From fd07624397e603f0c375ba5bbc4084dcc463ef1e Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Wed, 13 Sep 2023 15:52:00 +0100 Subject: [PATCH 1/5] BTHAB-184: Add Contribution opportunity details custom group --- ...up_Contribution_OpportunityDetails.mgd.php | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 managed/CustomGroup_Contribution_OpportunityDetails.mgd.php diff --git a/managed/CustomGroup_Contribution_OpportunityDetails.mgd.php b/managed/CustomGroup_Contribution_OpportunityDetails.mgd.php new file mode 100644 index 000000000..bb4ac2314 --- /dev/null +++ b/managed/CustomGroup_Contribution_OpportunityDetails.mgd.php @@ -0,0 +1,117 @@ + 'CustomGroup_Opportunity_Details', + 'entity' => 'CustomGroup', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'name' => 'Opportunity_Details', + 'title' => 'Opportunity Details', + 'extends' => 'Contribution', + 'extends_entity_column_value' => NULL, + 'style' => 'Inline', + 'collapse_display' => TRUE, + 'help_pre' => '

If using CiviProspect you can link this contribution to a prospect, quotation or both below.

', + 'help_post' => '', + 'weight' => 34, + 'is_active' => TRUE, + 'is_multiple' => FALSE, + 'min_multiple' => NULL, + 'max_multiple' => NULL, + 'collapse_adv_display' => TRUE, + 'created_date' => '2023-09-12 13:08:59', + 'is_reserved' => TRUE, + 'is_public' => FALSE, + 'icon' => '', + 'extends_entity_column_id' => NULL, + ], + ], + ], + [ + 'name' => 'CustomGroup_Opportunity_Details_CustomField_Case_Opportunity', + 'entity' => 'CustomField', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'custom_group_id.name' => 'Opportunity_Details', + 'name' => 'Case_Opportunity', + 'label' => 'Case/Opportunity', + 'data_type' => 'String', + 'html_type' => 'Text', + 'default_value' => NULL, + 'is_required' => FALSE, + 'is_searchable' => FALSE, + 'is_search_range' => FALSE, + 'help_pre' => NULL, + 'help_post' => NULL, + 'mask' => NULL, + 'attributes' => NULL, + 'javascript' => NULL, + 'is_active' => TRUE, + 'is_view' => FALSE, + 'options_per_line' => NULL, + 'text_length' => 255, + 'start_date_years' => NULL, + 'end_date_years' => NULL, + 'date_format' => NULL, + 'time_format' => NULL, + 'note_columns' => 60, + 'note_rows' => 4, + 'column_name' => 'case_opportunity_51', + 'serialize' => 0, + 'filter' => NULL, + 'in_selector' => FALSE, + ], + ], + ], + [ + 'name' => 'CustomGroup_Opportunity_Details_CustomField_Quotation', + 'entity' => 'CustomField', + 'cleanup' => 'always', + 'update' => 'unmodified', + 'params' => [ + 'version' => 4, + 'values' => [ + 'custom_group_id.name' => 'Opportunity_Details', + 'name' => 'Quotation', + 'label' => 'Quotation', + 'data_type' => 'String', + 'html_type' => 'Text', + 'default_value' => NULL, + 'is_required' => FALSE, + 'is_searchable' => FALSE, + 'is_search_range' => FALSE, + 'help_pre' => NULL, + 'help_post' => NULL, + 'mask' => NULL, + 'attributes' => NULL, + 'javascript' => NULL, + 'is_active' => TRUE, + 'is_view' => FALSE, + 'options_per_line' => NULL, + 'text_length' => 255, + 'start_date_years' => NULL, + 'end_date_years' => NULL, + 'date_format' => NULL, + 'time_format' => NULL, + 'note_columns' => 60, + 'note_rows' => 4, + 'column_name' => 'quotation_52', + 'serialize' => 0, + 'filter' => NULL, + 'in_selector' => FALSE, + ], + ], + ], +]; From 91c826eadcc04691663903bf2bc6f300f7a94e86 Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Wed, 13 Sep 2023 15:54:55 +0100 Subject: [PATCH 2/5] BTHAB-184: Convert oportunity deatils field to entity reference fields --- .../AddEntityReferenceToCustomField.php | 55 +++++++++++++++++++ civicase.php | 1 + js/contribution-entityref-field.js | 28 ++++++++++ 3 files changed, 84 insertions(+) create mode 100644 CRM/Civicase/Hook/BuildForm/AddEntityReferenceToCustomField.php create mode 100644 js/contribution-entityref-field.js diff --git a/CRM/Civicase/Hook/BuildForm/AddEntityReferenceToCustomField.php b/CRM/Civicase/Hook/BuildForm/AddEntityReferenceToCustomField.php new file mode 100644 index 000000000..0e2a9d1b5 --- /dev/null +++ b/CRM/Civicase/Hook/BuildForm/AddEntityReferenceToCustomField.php @@ -0,0 +1,55 @@ +shouldRun($formName)) { + return; + } + + $customFields[] = [ + 'name' => CRM_Core_BAO_CustomField::getCustomFieldID('Case_Opportunity', 'Opportunity_Details', TRUE), + 'entity' => 'Case', + 'placeholder' => '- Select Case/Opportunity -', + ]; + + $customFields[] = [ + 'name' => CRM_Core_BAO_CustomField::getCustomFieldID('Quotation', 'Opportunity_Details', TRUE), + 'entity' => 'CaseSalesOrder', + 'placeholder' => '- Select Quotation -', + ]; + + \Civi::resources()->add([ + 'scriptFile' => [E::LONG_NAME, 'js/contribution-entityref-field.js'], + 'region' => 'page-header', + ]); + \Civi::resources()->addVars('civicase', ['entityRefCustomFields' => $customFields]); + } + + /** + * Checks if the hook should run. + * + * @param string $formName + * Form Name. + * + * @return bool + * True if hook should run, otherwise false. + */ + public function shouldRun($formName) { + return $formName === "CRM_Contribute_Form_Contribution"; + } + +} diff --git a/civicase.php b/civicase.php index 9520a99da..89ac2b026 100644 --- a/civicase.php +++ b/civicase.php @@ -188,6 +188,7 @@ function civicase_civicrm_buildForm($formName, &$form) { new CRM_Civicase_Hook_BuildForm_AddCaseCategoryFeaturesField(), new CRM_Civicase_Hook_BuildForm_AddQuotationsNotesToContributionSettings(), new CRM_Civicase_Hook_BuildForm_AddSalesOrderLineItemsToContribution(), + new CRM_Civicase_Hook_BuildForm_AddEntityReferenceToCustomField(), ]; foreach ($hooks as $hook) { diff --git a/js/contribution-entityref-field.js b/js/contribution-entityref-field.js new file mode 100644 index 000000000..a1e236683 --- /dev/null +++ b/js/contribution-entityref-field.js @@ -0,0 +1,28 @@ +(function ($, _) { + window.waitForElement = function ($, elementPath, callBack) { + window.setTimeout(function () { + if ($(elementPath).length) { + callBack($, $(elementPath)); + } else { + window.waitForElement($, elementPath, callBack); + } + }, 500); + }; + + $(document).one('crmLoad', function () { + const entityRefCustomFields = CRM.vars.civicase.entityRefCustomFields ?? []; + + entityRefCustomFields.forEach(field => { + /* eslint-disable no-undef */ + waitForElement($, `[name^=${field.name}_]`, function ($, elem) { + $(`[name^=${field.name}_]`) + .attr('placeholder', field.placeholder) + .attr('disabled', false) + .crmEntityRef({ + entity: field.entity, + create: false + }); + }); + }); + }); +})(CRM.$, CRM._); From 131e15b3159efc19f99f7f9b9e95dda86d34fb6f Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Wed, 13 Sep 2023 15:55:26 +0100 Subject: [PATCH 3/5] BTHAB-184: Add case sales order getlist endpoint --- api/v3/CaseSalesOrder/Get.php | 44 ++++++++++++++++ api/v3/CaseSalesOrder/Getlist.php | 88 +++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 api/v3/CaseSalesOrder/Get.php create mode 100644 api/v3/CaseSalesOrder/Getlist.php diff --git a/api/v3/CaseSalesOrder/Get.php b/api/v3/CaseSalesOrder/Get.php new file mode 100644 index 000000000..f31813127 --- /dev/null +++ b/api/v3/CaseSalesOrder/Get.php @@ -0,0 +1,44 @@ + $field) { + $spec[$fieldname] = $field; + } +} diff --git a/api/v3/CaseSalesOrder/Getlist.php b/api/v3/CaseSalesOrder/Getlist.php new file mode 100644 index 000000000..b9464d1af --- /dev/null +++ b/api/v3/CaseSalesOrder/Getlist.php @@ -0,0 +1,88 @@ + 3, + 'entity' => 'CaseSalesOrder', + 'action' => 'getlist', + 'params' => $params, + ]; + + return civicrm_api3_generic_getList($apiRequest); +} + +/** + * Get case sales order list output. + * + * @param array $result + * API Result to format. + * @param array $request + * API Request. + * + * @return array + * API Result + * + * @see _civicrm_api3_generic_getlist_output + */ +function _civicrm_api3_case_sales_order_getlist_output($result, $request) { + $output = []; + if (!empty($result['values'])) { + foreach ($result['values'] as $row) { + $caseSalesOrder = CaseSalesOrder::get() + ->addSelect('contact.display_name', 'quotation_date') + ->addJoin('Contact AS contact', 'LEFT', ['contact.id', '=', 'client_id']) + ->addWhere('id', '=', $row['id']) + ->execute() + ->first(); + + $data = [ + 'id' => $row[$request['id_field']], + 'label' => "Client: {$caseSalesOrder['contact.display_name']}", + 'description' => [ + strip_tags($row['description']), + ], + ]; + $data['description'][] = "Quotation Date: " . CRM_Utils_Date::customFormat($caseSalesOrder['quotation_date']); + $output[] = $data; + } + } + return $output; +} From a9d26a62020481a25940b1e87b7241410a92fab1 Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Wed, 13 Sep 2023 15:56:54 +0100 Subject: [PATCH 4/5] BTHAB-184: Display linked invoices using opportunity details custom fields --- ang/afsearchQuotationInvoices.aff.html | 2 +- .../directives/quotations-list.directive.html | 6 +- .../SavedSearch_Civicase_Quotations.mgd.php | 93 +++++++++---------- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/ang/afsearchQuotationInvoices.aff.html b/ang/afsearchQuotationInvoices.aff.html index 818179830..44a6bc143 100644 --- a/ang/afsearchQuotationInvoices.aff.html +++ b/ang/afsearchQuotationInvoices.aff.html @@ -1,3 +1,3 @@
- +
diff --git a/ang/civicase-features/quotations/directives/quotations-list.directive.html b/ang/civicase-features/quotations/directives/quotations-list.directive.html index 495a03c7d..e8327d827 100644 --- a/ang/civicase-features/quotations/directives/quotations-list.directive.html +++ b/ang/civicase-features/quotations/directives/quotations-list.directive.html @@ -8,7 +8,7 @@

{{ ts('Manage Quotations') }}

{{:: ts('Create Quotation') }} -
+
@@ -34,4 +34,8 @@

{{ ts('Manage Quotations') }}

.af-field-range-sep { margin: 0em 1em; } + #bootstrap-theme.civicase__container .quotation__list ul.dropdown-menu { + right: 0; + left: auto; + } diff --git a/managed/SavedSearch_Civicase_Quotations.mgd.php b/managed/SavedSearch_Civicase_Quotations.mgd.php index f5275daee..d0d08f4c9 100644 --- a/managed/SavedSearch_Civicase_Quotations.mgd.php +++ b/managed/SavedSearch_Civicase_Quotations.mgd.php @@ -415,53 +415,51 @@ ], ], [ - 'name' => 'SavedSearch_Quotation_Invoices', + 'name' => 'SavedSearch_Quotation_Contributions', 'entity' => 'SavedSearch', 'cleanup' => 'unused', 'update' => 'unmodified', 'params' => [ 'version' => 4, 'values' => [ - 'name' => 'Quotation_Invoices', - 'label' => 'Quotation Invoices', + 'name' => 'Quotation_Contributions', + 'label' => 'Quotation Contributions', 'form_values' => NULL, 'search_custom_id' => NULL, - 'api_entity' => 'CaseSalesOrderContribution', + 'api_entity' => 'Contribution', 'api_params' => [ 'version' => 4, 'select' => [ - 'id', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.id', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.financial_type_id:label', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.total_amount', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.source', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.thankyou_date', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.contribution_status_id:label', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.receive_date', + 'total_amount', + 'financial_type_id:label', + 'source', + 'receive_date', + 'thankyou_date', + 'contribution_status_id:label', + 'Opportunity_Details.Case_Opportunity', ], 'orderBy' => [], - 'where' => [], - 'groupBy' => [], - 'join' => [ + 'where' => [ [ - 'Contribution AS CaseSalesOrderContribution_Contribution_contribution_id_01', - 'LEFT', - [ - 'contribution_id', - '=', - 'CaseSalesOrderContribution_Contribution_contribution_id_01.id', - ], + 'id', + 'IS NOT EMPTY', ], [ - 'CaseSalesOrder AS CaseSalesOrderContribution_CaseSalesOrder_case_sales_order_id_01', - 'LEFT', + 'OR', [ - 'case_sales_order_id', - '=', - 'CaseSalesOrderContribution_CaseSalesOrder_case_sales_order_id_01.id', + [ + 'Opportunity_Details.Case_Opportunity', + 'IS NOT EMPTY', + ], + [ + 'Opportunity_Details.Quotation', + 'IS NOT EMPTY', + ], ], ], ], + 'groupBy' => [], + 'join' => [], 'having' => [], ], 'expires_date' => NULL, @@ -471,19 +469,19 @@ ], ], [ - 'name' => 'SavedSearch_Quotation_Invoices_SearchDisplay_Quotation_Invoices', + 'name' => 'SavedSearch_Quotation_Contributions_SearchDisplay_Contributions_Table_1', 'entity' => 'SearchDisplay', 'cleanup' => 'unused', 'update' => 'unmodified', 'params' => [ 'version' => 4, 'values' => [ - 'name' => 'Quotation_Invoices', - 'label' => 'Quotation Invoices', - 'saved_search_id.name' => 'Quotation_Invoices', + 'name' => 'Contributions_Table_1', + 'label' => 'Contributions Table 1', + 'saved_search_id.name' => 'Quotation_Contributions', 'type' => 'table', 'settings' => [ - 'actions' => FALSE, + 'actions' => TRUE, 'limit' => 10, 'classes' => [ 'table', @@ -495,43 +493,43 @@ 'columns' => [ [ 'type' => 'field', - 'key' => 'CaseSalesOrderContribution_Contribution_contribution_id_01.total_amount', + 'key' => 'total_amount', 'dataType' => 'Money', 'label' => 'Amount', 'sortable' => TRUE, ], [ 'type' => 'field', - 'key' => 'CaseSalesOrderContribution_Contribution_contribution_id_01.financial_type_id:label', + 'key' => 'financial_type_id:label', 'dataType' => 'Integer', 'label' => 'Type', 'sortable' => TRUE, ], [ 'type' => 'field', - 'key' => 'CaseSalesOrderContribution_Contribution_contribution_id_01.source', + 'key' => 'source', 'dataType' => 'String', 'label' => 'Source', 'sortable' => TRUE, ], [ 'type' => 'field', - 'key' => 'CaseSalesOrderContribution_Contribution_contribution_id_01.receive_date', + 'key' => 'receive_date', 'dataType' => 'Timestamp', 'label' => 'Date', 'sortable' => TRUE, ], [ 'type' => 'field', - 'key' => 'CaseSalesOrderContribution_Contribution_contribution_id_01.thankyou_date', + 'key' => 'thankyou_date', 'dataType' => 'Timestamp', - 'label' => 'Thank-You Sent', + 'label' => 'Thank-you Sent', 'sortable' => TRUE, - 'rewrite' => '{if "[CaseSalesOrderContribution_Contribution_contribution_id_01.thankyou_date]"} Yes {else} No {/if}', + 'rewrite' => '{if "[thankyou_date]"} Yes {else} No {/if}', ], [ 'type' => 'field', - 'key' => 'CaseSalesOrderContribution_Contribution_contribution_id_01.contribution_status_id:label', + 'key' => 'contribution_status_id:label', 'dataType' => 'Integer', 'label' => 'Status', 'sortable' => TRUE, @@ -545,7 +543,7 @@ [ 'entity' => 'Contribution', 'action' => 'view', - 'join' => 'CaseSalesOrderContribution_Contribution_contribution_id_01', + 'join' => '', 'target' => 'crm-popup', 'icon' => 'fa-external-link', 'text' => 'View', @@ -556,7 +554,7 @@ [ 'entity' => 'Contribution', 'action' => 'update', - 'join' => 'CaseSalesOrderContribution_Contribution_contribution_id_01', + 'join' => '', 'target' => 'crm-popup', 'icon' => 'fa-pencil', 'text' => 'Edit', @@ -565,15 +563,15 @@ 'condition' => [], ], [ - 'path' => 'civicrm/contribute/invoice/email/?reset=1&id=[contribution_id]&select=email', - 'icon' => 'fa-paper-plane-o', - 'text' => 'Send By Email', - 'style' => 'default', - 'condition' => [], 'entity' => '', 'action' => '', 'join' => '', 'target' => 'crm-popup', + 'icon' => 'fa-paper-plane-o', + 'text' => 'Send By Email', + 'style' => 'default', + 'path' => 'civicrm/contribute/invoice/email/?reset=1&id=[id]&select=email', + 'condition' => [], ], ], 'type' => 'menu', @@ -588,7 +586,6 @@ ], ]; - $searchKitIsInstalled = 'installed' === CRM_Extension_System::singleton()->getManager()->getStatus('org.civicrm.search_kit'); if ($searchKitIsInstalled) { From f8c6e31a6260b21f11f56f983f4cebfd0ada9ec4 Mon Sep 17 00:00:00 2001 From: olayiwola-compucorp Date: Wed, 13 Sep 2023 16:22:28 +0100 Subject: [PATCH 5/5] BTHAB-184: Link sales order with contribution using opoortunity details fields --- .../AddSalesOrderLineItemsToContribution.php | 2 ++ .../ContributionCreateAction.php | 12 +++++++++++ js/sales-order-contribution.js | 20 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php b/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php index 50c5c8bbd..26c5b1974 100644 --- a/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php +++ b/CRM/Civicase/Hook/BuildForm/AddSalesOrderLineItemsToContribution.php @@ -36,6 +36,8 @@ public function run(CRM_Core_Form &$form, $formName) { 'to_be_invoiced' => $toBeInvoiced, 'percent_value' => $percentValue, 'line_items' => json_encode($lineItems), + 'quotation_custom_field' => CRM_Core_BAO_CustomField::getCustomFieldID('Quotation', 'Opportunity_Details', TRUE), + 'case_custom_field' => CRM_Core_BAO_CustomField::getCustomFieldID('Case_Opportunity', 'Opportunity_Details', TRUE), ]); } diff --git a/Civi/Api4/Action/CaseSalesOrder/ContributionCreateAction.php b/Civi/Api4/Action/CaseSalesOrder/ContributionCreateAction.php index d3d134586..38bffa9bd 100644 --- a/Civi/Api4/Action/CaseSalesOrder/ContributionCreateAction.php +++ b/Civi/Api4/Action/CaseSalesOrder/ContributionCreateAction.php @@ -4,6 +4,7 @@ use Civi\Api4\CaseSalesOrder; use Civi\Api4\CaseSalesOrderContribution as Api4CaseSalesOrderContribution; +use Civi\Api4\Contribution as Api4Contribution; use Civi\Api4\Generic\AbstractAction; use Civi\Api4\Generic\Result; use Civi\Api4\Generic\Traits\DAOActionTrait; @@ -178,6 +179,17 @@ private function linkCaseSalesOrderToContribution(int $salesOrderId, int $contri ->addValue('percent_value', $this->percentValue) ->addValue('contribution_id', $contributionId) ->execute(); + + $salesOrder = CaseSalesOrder::get() + ->addWhere('id', '=', $salesOrderId) + ->execute() + ->first(); + + Api4Contribution::update() + ->addValue('Opportunity_Details.Case_Opportunity', $salesOrder['case_id']) + ->addValue('Opportunity_Details.Quotation', $salesOrderId) + ->addWhere('id', '=', $contributionId) + ->execute(); } /** diff --git a/js/sales-order-contribution.js b/js/sales-order-contribution.js index 1a74e349f..889d15593 100644 --- a/js/sales-order-contribution.js +++ b/js/sales-order-contribution.js @@ -1,4 +1,14 @@ (function ($, _) { + const waitForElement = function ($, elementPath, callBack) { + window.setTimeout(function () { + if ($(elementPath).length) { + callBack($, $(elementPath)); + } else { + window.waitForElement($, elementPath, callBack); + } + }, 500); + }; + $(document).one('crmLoad', function () { const params = CRM.vars['uk.co.compucorp.civicase']; const salesOrderId = params.sales_order; @@ -6,6 +16,8 @@ const percentValue = params.percent_value; const toBeInvoiced = params.to_be_invoiced; const lineItems = JSON.parse(params.line_items); + const caseCustomField = params.case_custom_field; + const quotationCustomField = params.quotation_custom_field; let count = 0; const apiRequest = {}; @@ -37,6 +49,14 @@ $(``).insertBefore('#source'); $(``).insertBefore('#source'); $('#totalAmount, #totalAmountORaddLineitem, #totalAmountORPriceSet, #price_set_id, #choose-manual').hide(); + + waitForElement($, `[name^=${quotationCustomField}_]`, function ($, elem) { + $(`[name^=${quotationCustomField}_]`).val(caseSalesOrder.id).trigger('change'); + }); + + waitForElement($, `[name^=${caseCustomField}_]`, function ($, elem) { + $(`[name^=${caseCustomField}_]`).val(caseSalesOrder.case_id).trigger('change'); + }); }); }