Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BTHAMM-31: Set sales order line items from backend #1033

Merged
merged 1 commit into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<?php

use Civi\Api4\PriceField;
use Civi\Api4\PriceFieldValue;
use Civi\Api4\PriceSet;
use CRM_Civicase_ExtensionUtil as E;
use CRM_Civicase_Service_CaseSalesOrderLineItemsGenerator as salesOrderlineItemGenerator;

Expand Down Expand Up @@ -27,6 +30,14 @@ public function run(CRM_Core_Form &$form, $formName) {
}
$lineItemGenerator = new salesOrderlineItemGenerator($salesOrderId, $toBeInvoiced, $percentValue);
$lineItems = $lineItemGenerator->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')
Expand Down Expand Up @@ -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();
}

}
125 changes: 125 additions & 0 deletions CRM/Civicase/Hook/alterContent/AddSalesOrderLineToContribution.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

/**
* Adds sales order line items to the contribution.
*/
class CRM_Civicase_Hook_alterContent_AddSalesOrderLineToContribution {

/**
* Stores the sales order line items retrieved from the cache.
*
* @var array
*/
private $salesOrderLineItems;

/**
* Constructs the AddSalesOrderLindeToContribution class.
*
* @param string $content
* The content to be altered.
* @param array $context
* The context for the hook.
* @param string $tplName
* The name of the template.
*/
public function __construct(private &$content, private $context, private $tplName) {
$this->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);
}

}
8 changes: 8 additions & 0 deletions civicase.php
Original file line number Diff line number Diff line change
Expand Up @@ -646,4 +646,12 @@ function civicase_civicrm_alterContent(&$content, $context, $tplName, &$object)
$content = str_replace("#_qf_Activity_upload-top, #_qf_Activity_upload-bottom", "#_qf_Activity_upload-top, #_qf_Activity_upload-bottom, #_qf_Activity_submit-bottom, #_qf_Activity_submit-top, #_qf_Activity_refresh-top, #_qf_Activity_refresh-bottom", $content);
}
}

$hooks = [
new CRM_Civicase_Hook_alterContent_AddSalesOrderLineToContribution($content, $context, $tplName),
];

foreach ($hooks as $hook) {
$hook->run();
}
}
46 changes: 5 additions & 41 deletions js/sales-order-contribution.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
(function ($, _) {
const waitForElement = function ($, elementPath, callBack) {
window.setTimeout(function () {
if ($(elementPath).length) {
callBack($, $(elementPath));
} else {
window.waitForElement($, elementPath, callBack);
}
}, 500);
(new window.MutationObserver(function () {
callBack($, $(elementPath));
})).observe(document.querySelector(elementPath), {
attributes: true
});
};

$(document).one('crmLoad', async function () {
Expand All @@ -18,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', {
Expand All @@ -37,14 +34,6 @@
CRM.api4(apiRequest).then(function (batch) {
const caseSalesOrder = batch.caseSalesOrders[0];

lineItems.forEach(lineItem => {
setTimeout(
() => addLineItem(lineItem.qty, lineItem.unit_price, lineItem.label, lineItem.financial_type_id, lineItem.tax_amount),
2000
);
});

$('input[id="total_amount"]').trigger('change');
$('#contribution_status_id').val(batch.optionValues[0].value);
$('#source').val(`Quotation ${caseSalesOrder.id}`).trigger('change');
$('#contact_id').select2('val', caseSalesOrder.client_id).trigger('change');
Expand All @@ -63,30 +52,5 @@
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_line_total"]', row).val(CRM.formatMoney(total, true));
$('input[id^="item_tax_amount"]', row).val(taxAmount);
$('input[id^="item_unit_price"]', row).val(unitPrice).trigger('change');

count++;
}
});
})(CRM.$, CRM._);
Loading