From c0eb1a92fb89bf2aca40ffa921c9d7565116dd61 Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Tue, 14 May 2024 13:04:44 +0100 Subject: [PATCH 01/18] BTHAMM-15: Add custom delay before updating line item total --- js/sales-order-contribution.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/js/sales-order-contribution.js b/js/sales-order-contribution.js index 5de753872..4fe8418fd 100644 --- a/js/sales-order-contribution.js +++ b/js/sales-order-contribution.js @@ -1,13 +1,15 @@ (function ($, _) { const waitForElement = function ($, elementPath, callBack) { - (new window.MutationObserver(function () { - callBack($, $(elementPath)); - })).observe(document.querySelector(elementPath), { - attributes: true - }); + window.setTimeout(function () { + if ($(elementPath).length) { + callBack($, $(elementPath)); + } else { + window.waitForElement($, elementPath, callBack); + } + }, 500); }; - $(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; @@ -29,6 +31,9 @@ }]; if (Array.isArray(lineItems)) { + CRM.$.blockUI(); + CRM.$('form#Contribution').css('visibility', 'hidden'); + await new Promise(resolve => setTimeout(resolve, 2000)); CRM.api4(apiRequest).then(function (batch) { const caseSalesOrder = batch.caseSalesOrders[0]; @@ -37,7 +42,6 @@ }); $('#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'); @@ -52,6 +56,9 @@ $(`[name^=${caseCustomField}_]`).val(caseSalesOrder.case_id).trigger('change'); $(`[name^=${quotationCustomField}_]`).val(caseSalesOrder.id).trigger('change'); }); + }).finally(() => { + CRM.$.unblockUI(); + CRM.$('form#Contribution').css('visibility', 'visible'); }); } @@ -73,10 +80,9 @@ 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); + $('input[id^="item_unit_price"]', row).val(unitPrice).trigger('change'); count++; } From fbbac39d08db3b73f25832e0c172dc669a2e47ed Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Mon, 27 May 2024 06:38:12 +0100 Subject: [PATCH 02/18] BTHAMM-15: Resolve incorrect total due to round off --- CRM/Civicase/Service/CaseSalesOrderLineItemsGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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'], ]; } From e10157d5b2c8214108ee25b1d8d0c33cbcc74402 Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Mon, 27 May 2024 06:52:36 +0100 Subject: [PATCH 03/18] BTHAMM-15: Add delay between lineitem population --- js/sales-order-contribution.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/js/sales-order-contribution.js b/js/sales-order-contribution.js index 4fe8418fd..9167ae2f3 100644 --- a/js/sales-order-contribution.js +++ b/js/sales-order-contribution.js @@ -33,24 +33,26 @@ if (Array.isArray(lineItems)) { CRM.$.blockUI(); CRM.$('form#Contribution').css('visibility', 'hidden'); - await new Promise(resolve => setTimeout(resolve, 2000)); + 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); + setTimeout( + () => addLineItem(lineItem.qty, lineItem.unit_price, lineItem.label, lineItem.financial_type_id, lineItem.tax_amount), + 2000 + ); }); - $('#total_amount').val(0); + $('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'); - $('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(); waitForElement($, '#customData', function ($, elem) { $(`[name^=${caseCustomField}_]`).val(caseSalesOrder.case_id).trigger('change'); From 0a82f7530784c09e91ee22ba66e9d743207f4104 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Mon, 15 Jul 2024 15:35:51 +0500 Subject: [PATCH 04/18] COMCL-603: Update case type entity name as that has been updated in civicrm core --- civicase.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/civicase.php b/civicase.php index d5162fc25..9ef585afc 100644 --- a/civicase.php +++ b/civicase.php @@ -542,7 +542,9 @@ function civicase_civicrm_alterAngular(Manager $angular) { * Entity types array. */ function _civicase_add_case_category_case_type_entity(array &$entityTypes) { - $entityTypes['CRM_Case_DAO_CaseType']['fields_callback'][] = function ($class, &$fields) { + $caseTypeEntityName = isset($entityTypes['CRM_Case_DAO_CaseType']) ? 'CRM_Case_DAO_CaseType' : 'CaseType'; + + $entityTypes[$caseTypeEntityName]['fields_callback'][] = function ($class, &$fields) { $fields['case_type_category'] = [ 'name' => 'case_type_category', 'type' => CRM_Utils_Type::T_INT, From 79f00f6cfc5dd0de9bfb6136884a295f035c2635 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Thu, 18 Jul 2024 11:13:35 +0500 Subject: [PATCH 05/18] COMCL-603: Correct visual bundle assets path --- ang/civicase-base.ang.php | 6 +++--- ang/civicase.ang.php | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ang/civicase-base.ang.php b/ang/civicase-base.ang.php index 6c9873f0a..9e1549d19 100644 --- a/ang/civicase-base.ang.php +++ b/ang/civicase-base.ang.php @@ -9,11 +9,11 @@ */ use Civi\CCase\Utils as Utils; -use CRM_Civicase_Helper_OptionValues as OptionValuesHelper; +use CRM_Civicase_Helper_CaseUrl as CaseUrlHelper; use CRM_Civicase_Helper_GlobRecursive as GlobRecursive; use CRM_Civicase_Helper_NewCaseWebform as NewCaseWebform; +use CRM_Civicase_Helper_OptionValues as OptionValuesHelper; use CRM_Civicase_Service_CaseCategoryCustomFieldsSetting as CaseCategoryCustomFieldsSetting; -use CRM_Civicase_Helper_CaseUrl as CaseUrlHelper; [$caseCategoryId, $caseCategoryName] = CaseUrlHelper::getCategoryParamsFromUrl(); @@ -110,7 +110,7 @@ function expose_settings(array &$options, array $defaults) { function get_base_js_files() { return array_merge( [ - 'assetBuilder://visual-bundle.js', + Civi::service('asset_builder')->getUrl('visual-bundle.js'), 'ang/civicase-base.js', ], GlobRecursive::getRelativeToExtension( diff --git a/ang/civicase.ang.php b/ang/civicase.ang.php index 2d3188100..8fc912eec 100644 --- a/ang/civicase.ang.php +++ b/ang/civicase.ang.php @@ -8,12 +8,12 @@ * http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_angularModules. */ +use CRM_Civicase_Helper_CaseCategory as CaseCategoryHelper; +use CRM_Civicase_Helper_CaseUrl as CaseUrlHelper; use CRM_Civicase_Helper_GlobRecursive as GlobRecursive; -use CRM_Civicase_Service_CaseCategoryPermission as CaseCategoryPermission; use CRM_Civicase_Helper_NewCaseWebform as NewCaseWebform; -use CRM_Civicase_Helper_CaseCategory as CaseCategoryHelper; use CRM_Civicase_Hook_Permissions_ExportCasesAndReports as ExportCasesAndReports; -use CRM_Civicase_Helper_CaseUrl as CaseUrlHelper; +use CRM_Civicase_Service_CaseCategoryPermission as CaseCategoryPermission; load_resources(); [$caseCategoryId, $caseCategoryName] = CaseUrlHelper::getCategoryParamsFromUrl(); @@ -96,7 +96,7 @@ function get_js_files() { [ // At the moment, it's safe to include this multiple times. // deduped by resource manager. - 'assetBuilder://visual-bundle.js', + Civi::service('asset_builder')->getUrl('visual-bundle.js'), 'ang/civicase.js', ], GlobRecursive::getRelativeToExtension( @@ -255,7 +255,7 @@ function set_contact_tasks(&$options) { 'css' => [ // At the moment, it's safe to include this multiple times. // deduped by resource manager. - 'assetBuilder://visual-bundle.css', + Civi::service('asset_builder')->getUrl('visual-bundle.css'), 'css/*.css', ], 'partials' => [ From fac25b6ba4db7871d33d941c00dda4457d7f452b Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Thu, 25 Jul 2024 17:25:17 +0500 Subject: [PATCH 06/18] COMCL-644: Fix contribution settings page --- .../BuildForm/AddQuotationsNotesToContributionSettings.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CRM/Civicase/Hook/BuildForm/AddQuotationsNotesToContributionSettings.php b/CRM/Civicase/Hook/BuildForm/AddQuotationsNotesToContributionSettings.php index f7d243b98..c9127a6dd 100644 --- a/CRM/Civicase/Hook/BuildForm/AddQuotationsNotesToContributionSettings.php +++ b/CRM/Civicase/Hook/BuildForm/AddQuotationsNotesToContributionSettings.php @@ -49,11 +49,13 @@ public function addQuotationsNoteField(CRM_Core_Form &$form) { 'weight' => 5, 'description' => ts('Enter note or message to be displyaed on quotations'), 'attributes' => ['rows' => 2, 'cols' => 40], + 'name' => $fieldName, + 'quick_form_type' => 'Element', ], ]; $form->add('wysiwyg', $fieldName, $field[$fieldName]['title'], $field[$fieldName]['attributes']); - $form->assign('htmlFields', array_merge($form->get_template_vars('htmlFields'), $field)); + $form->assign('fields', array_values(array_merge($form->getTemplateVars('fields'), $field))); $value = Civi::settings()->get($fieldName) ?? NULL; $form->setDefaults(array_merge($form->_defaultValues, [$fieldName => $value])); From e23cc9f32d6722174c73495d1fba95c1f00d0b6e Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Thu, 1 Aug 2024 12:52:54 +0500 Subject: [PATCH 07/18] COMCL-620: Fix add case button issue --- ang/civicase.ang.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ang/civicase.ang.php b/ang/civicase.ang.php index 8fc912eec..c4ca659c8 100644 --- a/ang/civicase.ang.php +++ b/ang/civicase.ang.php @@ -64,11 +64,6 @@ */ function load_resources() { Civi::resources() - ->addPermissions([ - 'administer CiviCase', 'administer CiviCRM', - 'access all cases and activities', 'add cases', 'basic case information', - 'access CiviCRM', 'access my cases and activities', - ]) ->addScriptFile('org.civicrm.shoreditch', 'base/js/affix.js', 1000, 'html-header') ->addSetting([ 'config' => [ @@ -264,4 +259,13 @@ function set_contact_tasks(&$options) { 'settings' => $options, 'requires' => $requires, 'basePages' => [], + 'permissions' => [ + 'administer CiviCase', + 'administer CiviCRM', + 'access all cases and activities', + 'add cases', + 'basic case information', + 'access CiviCRM', + 'access my cases and activities', + ], ]; From 3a82313815a311c0bb9cfdf69a8e447887b68888 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Fri, 2 Aug 2024 14:53:37 +0500 Subject: [PATCH 08/18] COMCL-649: Fix custom group page --- .../Hook/BuildForm/AddStyleFieldToCaseCustomGroups.php | 8 +++++--- js/custom-group-form.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CRM/Civicase/Hook/BuildForm/AddStyleFieldToCaseCustomGroups.php b/CRM/Civicase/Hook/BuildForm/AddStyleFieldToCaseCustomGroups.php index dc44a29a3..7670bc5e7 100644 --- a/CRM/Civicase/Hook/BuildForm/AddStyleFieldToCaseCustomGroups.php +++ b/CRM/Civicase/Hook/BuildForm/AddStyleFieldToCaseCustomGroups.php @@ -28,15 +28,17 @@ public function run($form, $formName) { return; } - $contactTypes = json_decode($form->get_template_vars('contactTypes')); + $multipleTypes = $form->get_template_vars('allowMultiple'); $caseEntityNames = CaseType::buildOptions('case_type_category', 'validate'); // This is the generic entity for all cases. $caseEntityNames[] = 'Case'; - $contactTypes = array_merge($contactTypes, $caseEntityNames); + foreach ($caseEntityNames as $caseEntityName) { + $multipleTypes[$caseEntityName] = TRUE; + } - $form->assign('contactTypes', json_encode($contactTypes)); + $form->assign('allowMultiple', $multipleTypes); CRM_Core_Resources::singleton()->addSetting([ 'caseEntityNames' => $caseEntityNames, ]); diff --git a/js/custom-group-form.js b/js/custom-group-form.js index d659ae5e7..7cb2726f6 100644 --- a/js/custom-group-form.js +++ b/js/custom-group-form.js @@ -1,8 +1,8 @@ (function ($, _, caseEntityNames) { $(document).on('crmLoad', function () { - var $multipleRecordsCheckboxRow = $('#is_multiple_row'); + var $multipleRecordsCheckboxRow = $('tr.field-is_multiple'); var $styleSelectTabWithTableOption = $('select[name="style"] option[value="Tab with table"]'); - var $extendSelect = $('#extends_0'); + var $extendSelect = $('#extends'); (function init () { hideShowElementsNotRelevantWhenExtendingCases(); From d3b6056ce7535dab46fb1ef36e2d8cd12b3c3252 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Fri, 2 Aug 2024 16:46:42 +0500 Subject: [PATCH 09/18] COMCL-674: Fix new contribution page layout --- js/contribution-entityref-field.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/contribution-entityref-field.js b/js/contribution-entityref-field.js index 8d0922353..11731408e 100644 --- a/js/contribution-entityref-field.js +++ b/js/contribution-entityref-field.js @@ -11,7 +11,7 @@ const entityRefCustomFields = Object.values(CRM.vars.civicase.entityRefCustomFields ?? {}); /* eslint-disable no-undef */ - waitForElement($, '#customData', function ($, elem) { + waitForElement($, '#customData_Contribution', function ($, elem) { entityRefCustomFields.forEach(field => { $(`[name^=${field.name}_]`) .attr('placeholder', field.placeholder) From 09de83627c9bad893167cc559ee199a8918b817e Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Mon, 5 Aug 2024 23:48:01 +0100 Subject: [PATCH 10/18] COMCL-640: Ensure submit buttons will validate the form properly --- civicase.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/civicase.php b/civicase.php index 9ef585afc..2936d58c9 100644 --- a/civicase.php +++ b/civicase.php @@ -634,3 +634,16 @@ function civicase_civicrm_searchTasks(string $objectName, array &$tasks) { } } } + +/** + * Implements hook_civicrm_alterContent(). + */ +function civicase_civicrm_alterContent(&$content, $context, $tplName, &$object) { + if ($context == "form") { + if ($tplName == "CRM/Activity/Form/Activity.tpl") { + // See: templates/CRM/Core/Form/RecurringEntity.tpl#209 + // Ensure submit buttons will validate the form properly. + $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); + } + } +} From 9837098a40d9e4fb2a10c6b9b772d4b8058a2698 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Thu, 8 Aug 2024 13:40:38 +0500 Subject: [PATCH 11/18] COMCL-706: Fix menu styles --- .../quotations/directives/quotations-list.directive.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ang/civicase-features/quotations/directives/quotations-list.directive.html b/ang/civicase-features/quotations/directives/quotations-list.directive.html index e8327d827..9750a85f9 100644 --- a/ang/civicase-features/quotations/directives/quotations-list.directive.html +++ b/ang/civicase-features/quotations/directives/quotations-list.directive.html @@ -14,7 +14,7 @@

{{ ts('Manage Quotations') }}

- + @@ -35,7 +35,6 @@

{{ ts('Manage Quotations') }}

margin: 0em 1em; } #bootstrap-theme.civicase__container .quotation__list ul.dropdown-menu { - right: 0; left: auto; } From 270a3029f86b9366da1cc27f8f54e63e46bf3d5f Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Tue, 13 Aug 2024 14:29:54 +0500 Subject: [PATCH 12/18] COMCL-716: Fix other relationship tab on case details page --- api/v3/Case/Getrelations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v3/Case/Getrelations.php b/api/v3/Case/Getrelations.php index a774c5514..0f4ebd2ce 100644 --- a/api/v3/Case/Getrelations.php +++ b/api/v3/Case/Getrelations.php @@ -53,7 +53,7 @@ function civicrm_api3_case_getrelations(array $params) { $relationships = Relationship::get(FALSE) ->addSelect('relationship_type_id', 'contact_id_a', 'contact_id_b') - ->addWhere('relationship_type.is_active', '=', TRUE) + ->addWhere('relationship_type_id.is_active', '=', TRUE) ->addWhere('is_active', '=', TRUE) ->addWhere('case_id', 'IS NULL'); From 4cbde12f92a11d0f0d1c88ddfb66aabf37e1d6b5 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Wed, 14 Aug 2024 12:33:34 +0500 Subject: [PATCH 13/18] COMCL-701: Fix auto filling of owner id field on create quotation form --- ang/civicase/contact/services/contact.service.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ang/civicase/contact/services/contact.service.js b/ang/civicase/contact/services/contact.service.js index 13313e1d1..4b7e95e65 100644 --- a/ang/civicase/contact/services/contact.service.js +++ b/ang/civicase/contact/services/contact.service.js @@ -9,8 +9,9 @@ */ this.getCurrentContactID = function () { var url = new URL(window.location.href); + var userIdFromConfig = CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid; - return url.searchParams.get('cid') !== null ? url.searchParams.get('cid') : CRM.config.user_contact_id; + return url.searchParams.get('cid') !== null ? url.searchParams.get('cid') : userIdFromConfig; }; }); })(angular, CRM.$, CRM._, CRM); From 7a594fae4d248c4f06581cbe43bb0fef9e504002 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Wed, 14 Aug 2024 13:22:54 +0500 Subject: [PATCH 14/18] COMCL-704: Fix quotation template --- CRM/Civicase/Upgrader/Steps/Step0020.php | 32 +++++++++++++++++++ .../MessageTemplate/QuotationInvoice.tpl | 14 ++++---- 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 CRM/Civicase/Upgrader/Steps/Step0020.php diff --git a/CRM/Civicase/Upgrader/Steps/Step0020.php b/CRM/Civicase/Upgrader/Steps/Step0020.php new file mode 100644 index 000000000..9cd7f747b --- /dev/null +++ b/CRM/Civicase/Upgrader/Steps/Step0020.php @@ -0,0 +1,32 @@ +create(); + } + catch (\Throwable $th) { + \Civi::log()->error('Error upgrading Civicase', [ + 'context' => [ + 'backtrace' => $th->getTraceAsString(), + 'message' => $th->getMessage(), + ], + ]); + } + + return TRUE; + } + +} diff --git a/templates/CRM/Civicase/MessageTemplate/QuotationInvoice.tpl b/templates/CRM/Civicase/MessageTemplate/QuotationInvoice.tpl index 4e4918993..ee542a97d 100644 --- a/templates/CRM/Civicase/MessageTemplate/QuotationInvoice.tpl +++ b/templates/CRM/Civicase/MessageTemplate/QuotationInvoice.tpl @@ -24,8 +24,8 @@ - {if $sales_order.clientAddress.street_address }{$sales_order.clientAddress.street_address}{/if} - {if $sales_order.clientAddress.supplemental_address_1 }{$sales_order.clientAddress.supplemental_address_1}{/if} + {if !empty($sales_order.clientAddress.street_address) }{$sales_order.clientAddress.street_address}{/if} + {if !empty($sales_order.clientAddress.supplemental_address_1) }{$sales_order.clientAddress.supplemental_address_1}{/if} {$sales_order.quotation_date|crmDate} @@ -35,8 +35,8 @@ - {if $sales_order.clientAddress.supplemental_address_2 }{$sales_order.clientAddress.supplemental_address_2 }{/if} - {if $sales_order.clientAddress.state }{$sales_order.clientAddress.state}{/if} + {if !empty($sales_order.clientAddress.supplemental_address_2) }{$sales_order.clientAddress.supplemental_address_2 }{/if} + {if !empty($sales_order.clientAddress.state) }{$sales_order.clientAddress.state}{/if} Quote Number @@ -46,8 +46,8 @@ - {if $sales_order.clientAddress.city }{$sales_order.clientAddress.city }{/if} - {if $sales_order.clientAddress.postal_code }{$sales_order.clientAddress.postal_code}{/if} + {if !empty($sales_order.clientAddress.city) }{$sales_order.clientAddress.city }{/if} + {if !empty($sales_order.clientAddress.postal_code) }{$sales_order.clientAddress.postal_code}{/if} {$sales_order.id} @@ -57,7 +57,7 @@ - {if $sales_order.clientAddress.country }{$sales_order.clientAddress.country}{/if} + {if !empty($sales_order.clientAddress.country) }{$sales_order.clientAddress.country}{/if} From ba11f060111264e0d202260c2098f2eafa477370 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Wed, 14 Aug 2024 16:26:21 +0500 Subject: [PATCH 15/18] COMCL-709: Fix case search on dashboard --- .../case/search/directives/search.directive.js | 13 +++++++++---- .../dashboard/directives/dashboard.directive.js | 8 +++++--- .../case/search/directives/search.directive.spec.js | 8 ++++---- .../directives/dashboard.directive.spec.js | 8 ++++---- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ang/civicase/case/search/directives/search.directive.js b/ang/civicase/case/search/directives/search.directive.js index c7adf5e99..369a1b710 100644 --- a/ang/civicase/case/search/directives/search.directive.js +++ b/ang/civicase/case/search/directives/search.directive.js @@ -180,8 +180,10 @@ * @returns {boolean} if the current logged in user is a case manager */ function caseManagerIsMe () { + var userIdFromConfig = CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid; + return !!$scope.filters.case_manager && $scope.filters.case_manager.length === 1 && - parseInt($scope.filters.case_manager[0], 10) === CRM.config.user_contact_id; + parseInt($scope.filters.case_manager[0], 10) === userIdFromConfig; } /** @@ -371,7 +373,8 @@ function isFilterEqualToLoggedInUser (filterName) { var filterValue = $scope.filters[filterName]; var isEqualToUserContactId = filterValue === 'user_contact_id'; - var isSelectingLoggedInUser = _.isEqual(filterValue, [CRM.config.user_contact_id]); + var userIdFromConfig = CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid; + var isSelectingLoggedInUser = _.isEqual(filterValue, [userIdFromConfig]); return isEqualToUserContactId || isSelectingLoggedInUser; } @@ -396,13 +399,15 @@ * Watcher for relationshipType filter */ function relationshipTypeWatcher () { + var userIdFromConfig = CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid; + if ($scope.relationshipType) { $scope.relationshipType[0] === 'is_case_manager' - ? $scope.filters.case_manager = [CRM.config.user_contact_id] + ? $scope.filters.case_manager = [userIdFromConfig] : delete ($scope.filters.case_manager); if ($scope.relationshipType[0] === 'is_involved') { - $scope.filters.contact_involved = [CRM.config.user_contact_id]; + $scope.filters.contact_involved = [userIdFromConfig]; $scope.filters.has_activities_for_involved_contact = includeActivitiesForInvolvedContact ? 1 : 0; } else { diff --git a/ang/civicase/dashboard/directives/dashboard.directive.js b/ang/civicase/dashboard/directives/dashboard.directive.js index 7c1204b0b..2e5f7b9a0 100644 --- a/ang/civicase/dashboard/directives/dashboard.directive.js +++ b/ang/civicase/dashboard/directives/dashboard.directive.js @@ -53,7 +53,7 @@ */ $scope.linkToManageCase = function (type, status) { var cf = { case_type_category: $scope.currentCaseCategory }; - var userContactId = [CRM.config.user_contact_id]; + var userContactId = [CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid]; if (type) { cf.case_type_id = [type]; @@ -106,12 +106,14 @@ * @param {string} newValue the new relationship value. */ function caseRelationshipTypeWatcher (newValue) { + var userIdFromConfig = CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid; + newValue === 'is_case_manager' - ? $scope.activityFilters.case_filter.case_manager = CRM.config.user_contact_id + ? $scope.activityFilters.case_filter.case_manager = userIdFromConfig : delete ($scope.activityFilters.case_filter.case_manager); if (newValue === 'is_involved') { - $scope.activityFilters.case_filter.contact_involved = { IN: [CRM.config.user_contact_id] }; + $scope.activityFilters.case_filter.contact_involved = { IN: [userIdFromConfig] }; $scope.activityFilters.case_filter.has_activities_for_involved_contact = includeActivitiesForInvolvedContact ? 1 : 0; } else { diff --git a/ang/test/civicase/case/search/directives/search.directive.spec.js b/ang/test/civicase/case/search/directives/search.directive.spec.js index 21045f97d..74f15c11d 100644 --- a/ang/test/civicase/case/search/directives/search.directive.spec.js +++ b/ang/test/civicase/case/search/directives/search.directive.spec.js @@ -162,7 +162,7 @@ }); it('sets the case manager filter equal to my id', () => { - expect($scope.filters.case_manager).toEqual([CRM.config.user_contact_id]); + expect($scope.filters.case_manager).toEqual([CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid]); }); }); @@ -173,7 +173,7 @@ }); it('sets the contact id filter equal to my id', function () { - expect($scope.filters.contact_involved).toEqual([CRM.config.user_contact_id]); + expect($scope.filters.contact_involved).toEqual([CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid]); }); it('filters by case activities related to the involved contact', () => { @@ -304,7 +304,7 @@ }); it('sets the case manager filter equal to the current logged in user id', () => { - expect($scope.filters.case_manager).toEqual([CRM.config.user_contact_id]); + expect($scope.filters.case_manager).toEqual([CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid]); }); }); @@ -324,7 +324,7 @@ }); it('sets the contact involved filter equal to the current logged in user id', () => { - expect($scope.filters.contact_involved).toEqual([CRM.config.user_contact_id]); + expect($scope.filters.contact_involved).toEqual([CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid]); }); }); }); diff --git a/ang/test/civicase/dashboard/directives/dashboard.directive.spec.js b/ang/test/civicase/dashboard/directives/dashboard.directive.spec.js index 7766cfd0a..646358924 100644 --- a/ang/test/civicase/dashboard/directives/dashboard.directive.spec.js +++ b/ang/test/civicase/dashboard/directives/dashboard.directive.spec.js @@ -64,7 +64,7 @@ it('filters the cases and activties where the user is the manager', function () { expect($scope.activityFilters.case_filter).toEqual(jasmine.objectContaining({ - case_manager: CRM.config.user_contact_id + case_manager: CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid })); }); }); @@ -78,7 +78,7 @@ it('filters the cases and activties where the user is involved', function () { expect($scope.activityFilters.case_filter).toEqual(jasmine.objectContaining({ - contact_involved: { IN: [CRM.config.user_contact_id] } + contact_involved: { IN: [CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid] } })); }); @@ -129,7 +129,7 @@ case_type_category: '1', case_type_id: ['type'], status_id: ['status'], - case_manager: [CRM.config.user_contact_id] + case_manager: [CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid] }) })); }); @@ -150,7 +150,7 @@ case_type_category: '1', case_type_id: ['type'], status_id: ['status'], - contact_involved: [CRM.config.user_contact_id] + contact_involved: [CRM.config.user_contact_id ? CRM.config.user_contact_id : CRM.config.cid] }) })); }); From 1edecbfdfb3e7be1c161beba357c53256c6ef992 Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Fri, 16 Aug 2024 08:20:00 +0100 Subject: [PATCH 16/18] BTHAMM-31: Set sales order line items from backend --- .../AddSalesOrderLineItemsToContribution.php | 32 +++++ .../AddSalesOrderLineToContribution.php | 125 ++++++++++++++++++ civicase.php | 8 ++ js/sales-order-contribution.js | 46 +------ 4 files changed, 170 insertions(+), 41 deletions(-) create mode 100644 CRM/Civicase/Hook/alterContent/AddSalesOrderLineToContribution.php 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/civicase.php b/civicase.php index 2936d58c9..b2e8c81cb 100644 --- a/civicase.php +++ b/civicase.php @@ -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(); + } } diff --git a/js/sales-order-contribution.js b/js/sales-order-contribution.js index 9167ae2f3..c423d2def 100644 --- a/js/sales-order-contribution.js +++ b/js/sales-order-contribution.js @@ -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 () { @@ -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', { @@ -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'); @@ -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._); From e1b8ca8998acb87eb07554f5e64e5c9716eb6407 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Fri, 16 Aug 2024 16:23:42 +0500 Subject: [PATCH 17/18] COMCL-707: Fix case category Terms --- .../PageRun/AddCaseTypeCategoryToCache.php | 33 +++++++++++++++++++ ang/civicase.ang.php | 2 -- civicase.php | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 CRM/Civicase/Hook/PageRun/AddCaseTypeCategoryToCache.php diff --git a/CRM/Civicase/Hook/PageRun/AddCaseTypeCategoryToCache.php b/CRM/Civicase/Hook/PageRun/AddCaseTypeCategoryToCache.php new file mode 100644 index 000000000..c70c1d8e2 --- /dev/null +++ b/CRM/Civicase/Hook/PageRun/AddCaseTypeCategoryToCache.php @@ -0,0 +1,33 @@ +addCaseTypeCategoryToCache(); + } + + /** + * Add case type category to cache. + */ + private function addCaseTypeCategoryToCache(): void { + if (CRM_Utils_System::currentPath() === 'civicrm/case/a') { + $caseCategoryInfo = CaseUrlHelper::getCategoryParamsFromUrl(); + \Civi::cache('metadata')->set('current_case_category', $caseCategoryInfo[1]); + } + elseif (!in_array(CRM_Utils_System::currentPath(), ['civicrm/asset/builder', 'civicrm/user-menu'], TRUE)) { + \Civi::cache('metadata')->set('current_case_category', NULL); + } + } + +} diff --git a/ang/civicase.ang.php b/ang/civicase.ang.php index c4ca659c8..072a87549 100644 --- a/ang/civicase.ang.php +++ b/ang/civicase.ang.php @@ -26,8 +26,6 @@ if (!in_array($caseCategoryName, CaseCategoryHelper::getAccessibleCaseTypeCategories())) { throw new Exception('Access denied! You are not authorized to access this page.'); } - - CRM_Civicase_Hook_Helper_CaseTypeCategory::addWordReplacements($caseCategoryName); } } diff --git a/civicase.php b/civicase.php index 2936d58c9..155cb3486 100644 --- a/civicase.php +++ b/civicase.php @@ -415,6 +415,7 @@ function civicase_civicrm_pageRun(&$page) { new CRM_Civicase_Hook_PageRun_AddCaseAngularPageResources(), new CRM_Civicase_Hook_PageRun_AddContactPageSummaryResources(), new CRM_Civicase_Hook_PageRun_CaseCategoryCustomGroupListing(), + new CRM_Civicase_Hook_PageRun_AddCaseTypeCategoryToCache(), ]; foreach ($hooks as $hook) { From bae28d3f93b236972700a54806d4be5d47d27278 Mon Sep 17 00:00:00 2001 From: Muhammad Shahrukh <> Date: Fri, 16 Aug 2024 17:29:46 +0500 Subject: [PATCH 18/18] COMCL-714: Fix case activity report --- CRM/Civicase/XMLProcessor/Report.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CRM/Civicase/XMLProcessor/Report.php b/CRM/Civicase/XMLProcessor/Report.php index bdfbf3aae..4d63b0f30 100644 --- a/CRM/Civicase/XMLProcessor/Report.php +++ b/CRM/Civicase/XMLProcessor/Report.php @@ -67,6 +67,7 @@ public static function getCaseReport($clientID, $caseID, $activitySetName, $para $template->assign('caseId', $caseID); $template->assign('clientID', $clientID); $template->assign('activitySetName', $activitySetName); + $allActivityTypes = CRM_Case_PseudoConstant::caseActivityType(); if (!empty($params['is_redact'])) { $report->_isRedact = TRUE; @@ -96,10 +97,10 @@ public static function getCaseReport($clientID, $caseID, $activitySetName, $para if ($activitySetName && !empty($activitySetNames[$activitySetName])) { $timelineActivities = $report->getActivityTypes($xml, $activitySetName); - $activityTypes = !empty($timelineActivities) ? $timelineActivities : CRM_Case_XMLProcessor::allActivityTypes(); + $activityTypes = !empty($timelineActivities) ? $timelineActivities : $allActivityTypes; } else { - $activityTypes = CRM_Case_XMLProcessor::allActivityTypes(); + $activityTypes = $allActivityTypes; } if (!$activityTypes) {