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