diff --git a/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php b/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php index 26c5b1974..0ac2e3964 100644 --- a/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php +++ b/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php @@ -1,5 +1,8 @@ generateLineItems(); + $priceField = $this->getDefaultPriceSetFields(); + \Civi::cache('short')->set('sales_order_line_items', $lineItems); + + $submittedValues = []; + foreach ($lineItems as $index => &$lineItem) { + $submittedValues[] = $priceField[$index]['id']; + } + $form->assign('lineItemSubmitted', json_encode($submittedValues)); CRM_Core_Resources::singleton() ->addScriptFile(E::LONG_NAME, 'js/sales-order-contribution.js') @@ -61,4 +72,25 @@ public function shouldRun(CRM_Core_Form $form, string $formName, ?int $salesOrde && !empty($salesOrderId); } + /** + * Returns default contribution price set fields. + * + * @return array + * Array of price fields + */ + private function getDefaultPriceSetFields(): array { + $priceSet = PriceSet::get(FALSE) + ->addWhere('name', '=', 'default_contribution_amount') + ->addWhere('is_quick_config', '=', 1) + ->execute() + ->first(); + + return PriceField::get(FALSE) + ->addWhere('price_set_id', '=', $priceSet['id']) + ->addChain('price_field_value', PriceFieldValue::get(FALSE) + ->addWhere('price_field_id', '=', '$id') + )->execute() + ->getArrayCopy(); + } + } diff --git a/CRM/Civicase/Hook/alterContent/AddSalesOrderLineToContribution.php b/CRM/Civicase/Hook/alterContent/AddSalesOrderLineToContribution.php new file mode 100644 index 000000000..6bc13bef3 --- /dev/null +++ b/CRM/Civicase/Hook/alterContent/AddSalesOrderLineToContribution.php @@ -0,0 +1,125 @@ +salesOrderLineItems = \Civi::cache('short')->get('sales_order_line_items'); + } + + /** + * Add sales order line items to the contribution. + */ + public function run() { + if (!$this->shouldRun()) { + return; + } + + $this->addLineItems(); + } + + /** + * Adds sales order line items to the contribution. + * + * This method retrieves the sales order line items from the cache, and then + * updates the corresponding input fields in the contribution + * page's HTML content. + */ + public function addLineItems() { + $dom = new DomDocument(); + $dom->loadHTML($this->content); + + $table = $dom->getElementById('info'); + + // Delete the first row (index 0) + if ($table) { + $firstRow = $table->getElementsByTagName('tr')->item(0); + if ($firstRow) { + $table->removeChild($firstRow); + } + } + + $rows = $table->getElementsByTagName('tr'); + // Set the values in the DOM. + foreach ($this->salesOrderLineItems as $index => $item) { + if ($index < $rows->length) { + // Get the current row. + $row = $rows->item($index); + + // Remove 'hiddenElement' class if it exists. + $row->setAttribute('class', str_replace('hiddenElement', '', $row->getAttribute('class'))); + + // Set the values from the line item array. + $inputs = $row->getElementsByTagName('input'); + $selects = $row->getElementsByTagName('select'); + + foreach ($inputs as $input) { + $name = $input->getAttribute('name'); + + if (strpos($name, 'qty') !== FALSE) { + $input->setAttribute('value', $item['qty']); + } + elseif (strpos($name, 'tax_amount') !== FALSE) { + $input->setAttribute('value', $item['tax_amount']); + } + elseif (strpos($name, 'line_total') !== FALSE) { + $input->setAttribute('value', $item['line_total']); + } + elseif (strpos($name, 'unit_price') !== FALSE) { + $input->setAttribute('value', $item['unit_price']); + } + elseif (strpos($name, 'label') !== FALSE) { + $input->setAttribute('value', $item['label']); + } + } + + foreach ($selects as $select) { + $name = $select->getAttribute('name'); + + if (strpos($name, 'financial_type_id') !== FALSE) { + foreach ($select->getElementsByTagName('option') as $option) { + if ($option->getAttribute('value') == $item['financial_type_id']) { + $option->setAttribute('selected', 'selected'); + break; + } + } + } + } + } + } + + \Civi::cache('short')->delete('sales_order_line_items'); + + $this->content = $dom->saveHTML(); + } + + /** + * Determines whether the hook should run. + * + * @return bool + * TRUE if the hook should run, FALSE otherwise. + */ + public function shouldRun() { + return $this->tplName === "CRM/Contribute/Page/Tab.tpl" && $this->context == "page" && !empty($this->salesOrderLineItems); + } + +} diff --git a/CRM/Civicase/Service/CaseSalesOrderLineItemsGenerator.php b/CRM/Civicase/Service/CaseSalesOrderLineItemsGenerator.php index 63379b52d..70248d17c 100644 --- a/CRM/Civicase/Service/CaseSalesOrderLineItemsGenerator.php +++ b/CRM/Civicase/Service/CaseSalesOrderLineItemsGenerator.php @@ -147,7 +147,7 @@ private function lineItemToContributionLineItem(array $item) { 'entity_table' => 'civicrm_contribution', 'financial_type_id' => $item['financial_type_id'], 'line_total' => round($item['total'], 2), - 'unit_price' => round($item['unit_price'], 2), + 'unit_price' => $item['unit_price'], ]; } diff --git a/CRM/Civicase/Service/CaseSalesOrderOpportunityCalculator.php b/CRM/Civicase/Service/CaseSalesOrderOpportunityCalculator.php index 47c157b16..18859fc4a 100644 --- a/CRM/Civicase/Service/CaseSalesOrderOpportunityCalculator.php +++ b/CRM/Civicase/Service/CaseSalesOrderOpportunityCalculator.php @@ -172,7 +172,10 @@ private function calculateOpportunityFinancialAmount($contributions) { private function getContributions($caseId) { $contributions = Contribution::get(FALSE) ->addSelect('*', 'Opportunity_Details.Quotation') - ->addWhere('Opportunity_Details.Case_Opportunity', '=', $caseId); + ->addWhere('Opportunity_Details.Case_Opportunity', '=', $caseId) + ->addJoin('CaseSalesOrder AS case_sales_order', 'INNER', + ['Opportunity_Details.Quotation', '=', 'case_sales_order.id'] + ); if ($this->deletingContributionId !== NULL) { $contributions->addWhere('id', '!=', $this->deletingContributionId); diff --git a/civicase.php b/civicase.php index d5162fc25..ed8217d19 100644 --- a/civicase.php +++ b/civicase.php @@ -632,3 +632,16 @@ function civicase_civicrm_searchTasks(string $objectName, array &$tasks) { } } } + +/** + * Implements hook_civicrm_alterContent(). + */ +function civicase_civicrm_alterContent(&$content, $context, $tplName, &$object) { + $hooks = [ + new CRM_Civicase_Hook_alterContent_AddSalesOrderLineToContribution($content, $context, $tplName), + ]; + + foreach ($hooks as $hook) { + $hook->run(); + } +} diff --git a/js/contribution-entityref-field.js b/js/contribution-entityref-field.js index 8d0922353..0b483527a 100644 --- a/js/contribution-entityref-field.js +++ b/js/contribution-entityref-field.js @@ -24,6 +24,18 @@ if (field.value) { $(`[name^=${field.name}_]`).val(field.value).trigger('change'); } + + $(`[name^=${field.name}_]`).on('change', field, function (event) { + const f = event.data; + + $(`[name^=${f.name}_]`) + .attr('placeholder', f.placeholder) + .attr('disabled', false) + .crmEntityRef({ + entity: f.entity, + create: false + }); + }); }); }); }); diff --git a/js/sales-order-contribution.js b/js/sales-order-contribution.js index 5de753872..02c2245de 100644 --- a/js/sales-order-contribution.js +++ b/js/sales-order-contribution.js @@ -7,7 +7,7 @@ }); }; - $(document).one('crmLoad', function () { + $(document).one('crmLoad', async function () { const params = CRM.vars['uk.co.compucorp.civicase']; const salesOrderId = params.sales_order; const salesOrderStatusId = params.sales_order_status_id; @@ -16,7 +16,6 @@ const lineItems = JSON.parse(params.line_items); const caseCustomField = params.case_custom_field; const quotationCustomField = params.quotation_custom_field; - let count = 0; const apiRequest = {}; apiRequest.caseSalesOrders = ['CaseSalesOrder', 'get', { @@ -29,56 +28,33 @@ }]; if (Array.isArray(lineItems)) { + CRM.$.blockUI(); + CRM.$('form#Contribution').css('visibility', 'hidden'); + await new Promise(resolve => setTimeout(resolve, 1000)); CRM.api4(apiRequest).then(function (batch) { const caseSalesOrder = batch.caseSalesOrders[0]; - lineItems.forEach(lineItem => { - addLineItem(lineItem.qty, lineItem.unit_price, lineItem.label, lineItem.financial_type_id, lineItem.tax_amount); - }); - - $('#total_amount').val(0); - $('#lineitem-add-block').show().removeClass('hiddenElement'); $('#contribution_status_id').val(batch.optionValues[0].value); $('#source').val(`Quotation ${caseSalesOrder.id}`).trigger('change'); $('#contact_id').select2('val', caseSalesOrder.client_id).trigger('change'); - $('input[id="total_amount"]', 'form.CRM_Contribute_Form_Contribution').trigger('change'); $(``).insertBefore('#source'); $(``).insertBefore('#source'); $(``).insertBefore('#source'); $(``).insertBefore('#source'); - $('#totalAmount, #totalAmountORaddLineitem, #totalAmountORPriceSet, #price_set_id, #choose-manual').hide(); + $(' #totalAmountORaddLineitem, #totalAmountORPriceSet, #price_set_id, #choose-manual').hide(); + if ($('#customData')) { + CRM.$(`[name^=${caseCustomField}_]`).val(caseSalesOrder.case_id).trigger('change'); + CRM.$(`[name^=${quotationCustomField}_]`).val(caseSalesOrder.id).trigger('change'); + } waitForElement($, '#customData', function ($, elem) { - $(`[name^=${caseCustomField}_]`).val(caseSalesOrder.case_id).trigger('change'); - $(`[name^=${quotationCustomField}_]`).val(caseSalesOrder.id).trigger('change'); + CRM.$(`[name^=${caseCustomField}_]`).val(caseSalesOrder.case_id).trigger('change'); + CRM.$(`[name^=${quotationCustomField}_]`).val(caseSalesOrder.id).trigger('change'); }); + }).finally(() => { + CRM.$.unblockUI(); + CRM.$('form#Contribution').css('visibility', 'visible'); }); } - - /** - * @param {number} quantity Item quantity - * @param {number} unitPrice Item unit price - * @param {string} description Item description - * @param {number} financialTypeId Item financial type - * @param {number|object} taxAmount Item tax amount - */ - function addLineItem (quantity, unitPrice, description, financialTypeId, taxAmount) { - const row = $($(`tr#add-item-row-${count}`)); - row.show().removeClass('hiddenElement'); - quantity = +parseFloat(quantity).toFixed(10); // limit to 10 decimal places - - $('input[id^="item_label"]', row).val(ts(description)); - $('select[id^="item_financial_type_id"]', row).select2('val', financialTypeId); - $('input[id^="item_qty"]', row).val(quantity); - - const total = quantity * parseFloat(unitPrice); - - $('input[id^="item_unit_price"]', row).val(unitPrice); - $('input[id^="item_line_total"]', row).val(CRM.formatMoney(total, true)); - - $('input[id^="item_tax_amount"]', row).val(taxAmount); - - count++; - } }); })(CRM.$, CRM._); diff --git a/templates/CRM/Civicase/Form/CaseSalesOrderContributionCreate.tpl b/templates/CRM/Civicase/Form/CaseSalesOrderContributionCreate.tpl index d575b8bae..5bd651fa7 100644 --- a/templates/CRM/Civicase/Form/CaseSalesOrderContributionCreate.tpl +++ b/templates/CRM/Civicase/Form/CaseSalesOrderContributionCreate.tpl @@ -61,3 +61,12 @@ }); {/literal} + +{literal} + + +{/literal} \ No newline at end of file