Fixes and tidies

This commit is contained in:
Rich Lott / Artful Robot 2025-02-27 18:10:48 +00:00
parent e56be4ce31
commit 69d4c6b2e8
11 changed files with 191 additions and 40 deletions

View file

@ -125,7 +125,7 @@ class Processor {
$oldCategoryId = (int) ($lastChange[0] ?? 0); $oldCategoryId = (int) ($lastChange[0] ?? 0);
$newCategoryId = (int) ($lastChange[1] ?? 0); $newCategoryId = (int) ($lastChange[1] ?? 0);
$oldName = $this->categories[$oldCategoryId]['label'] ?? E::ts('(Unknown)'); $oldName = $this->categories[$oldCategoryId]['label'] ?? E::ts('(Unknown)');
$subject = "$oldName" . $this->categories[$newCategoryId]; $subject = "$oldName" . $this->categories[$newCategoryId]['label'];
// Create activity on the first contact // Create activity on the first contact
$a = Activity::create(FALSE) $a = Activity::create(FALSE)
->addValue('target_contact_id', $batch[0]) ->addValue('target_contact_id', $batch[0])
@ -139,18 +139,18 @@ class Processor {
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_activity_contact (contact_id, activity_id, record_type_id) CRM_Core_DAO::executeQuery("INSERT INTO civicrm_activity_contact (contact_id, activity_id, record_type_id)
SELECT id contact_id, $activityID activity_id, 3 record_type_id SELECT id contact_id, $activityID activity_id, 3 record_type_id
FROM civicrm_contact_category cc FROM civicrm_contact_category cc
WHERE cc.category = $oldCategoryId WHERE cc.category_definition_id = $oldCategoryId
AND cc.next_category = $newCategoryId AND cc.next_category = $newCategoryId
AND contact_id <> $batch[0] AND cc.id <> $batch[0]
")->free(); ")->free();
Civi::log()->debug(count($batch) . " changes: $subject"); Civi::log()->debug(count($batch) . " changes: $subject");
}; };
while ($changes->fetch()) { while ($changes->fetch()) {
$n++; $n++;
if ($lastChange[0] !== $changes->category || $lastChange[1] !== $changes->next_category) { if ($lastChange[0] !== $changes->category_definition_id || $lastChange[1] !== $changes->next_category) {
$writeBatch(); $writeBatch();
$lastChange = [$changes->category, $changes->next_category]; $lastChange = [$changes->category_definition_id, $changes->next_category];
$batch = []; $batch = [];
} }
$batch[] = $changes->id; $batch[] = $changes->id;
@ -195,7 +195,7 @@ class Processor {
// Q: is it quicker to do a WHERE NOT EXISTS? A: nope. // Q: is it quicker to do a WHERE NOT EXISTS? A: nope.
CRM_Core_DAO::executeQuery(<<<SQL CRM_Core_DAO::executeQuery(<<<SQL
INSERT INTO civicrm_contact_category INSERT INTO civicrm_contact_category
SELECT id, id contact_id, NULL as category_definition_id, 0 next_category SELECT id, NULL as category_definition_id, 0 next_category
FROM civicrm_contact FROM civicrm_contact
WHERE NOT EXISTS (SELECT id FROM civicrm_contact_category WHERE id = civicrm_contact.id) WHERE NOT EXISTS (SELECT id FROM civicrm_contact_category WHERE id = civicrm_contact.id)
SQL)->free(); SQL)->free();

View file

@ -1,3 +0,0 @@
<div af-fieldset="">
<crm-search-display-list search-name="Category_for_contact" display-name="Category_for_contact_List_1" filters="{'contact_id': options.contact_id}"></crm-search-display-list>
</div>

View file

@ -1,13 +0,0 @@
{
"type": "search",
"title": "Category",
"placement": [
"contact_summary_block"
],
"icon": "fa-list-alt",
"server_route": "",
"permission": [
"access CiviCRM"
],
"permission_operator": "AND"
}

View file

@ -0,0 +1,3 @@
<div af-fieldset="">
<crm-search-display-table search-name="SavedSearch_Contact_Category_Counts" display-name="Category_counts"></crm-search-display-table>
</div>

View file

@ -0,0 +1,33 @@
{
"type": "search",
"title": "Contact Category Counts",
"placement": [
"dashboard_dashlet"
],
"icon": "fa-tags",
"server_route": "civicrm/reports/contact-category-counts",
"permission": [
"access CiviCRM"
],
"permission_operator": "AND",
"navigation": {
"parent": "Reports",
"label": "Contact Category Counts",
"weight": 0
},
"modified_date": "2025-02-27 17:32:42",
"requires": null,
"entity_type": null,
"join_entity": null,
"description": null,
"summary_contact_type": null,
"summary_weight": null,
"is_public": false,
"redirect": null,
"submit_enabled": true,
"submit_limit": null,
"create_submission": null,
"manual_processing": null,
"allow_verification_by_email": null,
"email_confirmation_template_id": null
}

View file

@ -27,6 +27,10 @@
ctrl.categoryToEdit = null; ctrl.categoryToEdit = null;
ctrl.categoryDefinitions = null; ctrl.categoryDefinitions = null;
ctrl.categoryDefinitions = await crmApi4("ContactCategoryDefinition", 'get', { orderBy: { execution_order: 'ASC' }, withLabels: true }); ctrl.categoryDefinitions = await crmApi4("ContactCategoryDefinition", 'get', { orderBy: { execution_order: 'ASC' }, withLabels: true });
if (ctrl.categoryDefinitions.count === 0) {
// First time.
ctrl.categoryDefinitions = [];
}
// Ensure we have the minimum of what we need. // Ensure we have the minimum of what we need.
if (!ctrl.categoryDefinitions.find(c => c.search_type === 'default')) { if (!ctrl.categoryDefinitions.find(c => c.search_type === 'default')) {
// There's no default one. // There's no default one.
@ -80,7 +84,7 @@
// Create a blank // Create a blank
ctrl.categoryToEdit = { ctrl.categoryToEdit = {
id: 0, id: 0,
execution_order: ctrl.categoryDefinitions.length, execution_order: -1,
label: '', label: '',
search_type: 'search', search_type: 'search',
search_data: { saved_search_id: null }, search_data: { saved_search_id: null },
@ -139,8 +143,14 @@
edited.search_data = {saved_search_id}; edited.search_data = {saved_search_id};
} }
const idx = edited.execution_order; if (edited.execution_order === -1) {
ctrl.categoryDefinitions[idx] = edited; // This is a new category, we need to insert it before the default one.
const newIdx = ctrl.categoryDefinitions.length - 1;
ctrl.categoryDefinitions.splice(newIdx, 0, edited);
}
else {
ctrl.categoryDefinitions[edited.execution_order] = edited;
}
ctrl.categoryToEdit = null; ctrl.categoryToEdit = null;
updateOrders(); updateOrders();
ctrl.dirty = 'dirty'; ctrl.dirty = 'dirty';

View file

@ -17,9 +17,7 @@ return [
'style' => 'Inline', 'style' => 'Inline',
'help_pre' => E::ts(''), 'help_pre' => E::ts(''),
'help_post' => E::ts(''), 'help_post' => E::ts(''),
'weight' => 18,
'collapse_adv_display' => TRUE, 'collapse_adv_display' => TRUE,
'created_date' => '2025-02-20 13:59:06',
'is_public' => FALSE, 'is_public' => FALSE,
'icon' => '', 'icon' => '',
], ],
@ -35,7 +33,7 @@ return [
'version' => 4, 'version' => 4,
'values' => [ 'values' => [
'custom_group_id.name' => 'Category_changes', 'custom_group_id.name' => 'Category_changes',
'name' => 'Previous_Category', 'name' => 'previous_category_id',
'label' => E::ts('Previous Category'), 'label' => E::ts('Previous Category'),
'data_type' => 'EntityReference', 'data_type' => 'EntityReference',
'html_type' => 'Autocomplete-Select', 'html_type' => 'Autocomplete-Select',
@ -44,7 +42,7 @@ return [
'text_length' => 255, 'text_length' => 255,
'note_columns' => 60, 'note_columns' => 60,
'note_rows' => 4, 'note_rows' => 4,
'column_name' => 'previous_category_117', 'column_name' => 'previous_category_id',
'fk_entity' => 'ContactCategoryDefinition', 'fk_entity' => 'ContactCategoryDefinition',
], ],
'match' => [ 'match' => [
@ -62,7 +60,7 @@ return [
'version' => 4, 'version' => 4,
'values' => [ 'values' => [
'custom_group_id.name' => 'Category_changes', 'custom_group_id.name' => 'Category_changes',
'name' => 'New_Category', 'name' => 'new_category_id',
'label' => E::ts('New Category'), 'label' => E::ts('New Category'),
'data_type' => 'EntityReference', 'data_type' => 'EntityReference',
'html_type' => 'Autocomplete-Select', 'html_type' => 'Autocomplete-Select',
@ -71,7 +69,7 @@ return [
'text_length' => 255, 'text_length' => 255,
'note_columns' => 60, 'note_columns' => 60,
'note_rows' => 4, 'note_rows' => 4,
'column_name' => 'new_category_118', 'column_name' => 'new_category_id',
'fk_entity' => 'ContactCategoryDefinition', 'fk_entity' => 'ContactCategoryDefinition',
], ],
'match' => [ 'match' => [

View file

@ -0,0 +1,26 @@
<?php
use CRM_Contactcats_ExtensionUtil as E;
return [
[
'name' => 'OptionValue_Changed_category',
'entity' => 'OptionValue',
'cleanup' => 'unused',
'update' => 'unmodified',
'params' => [
'version' => 4,
'values' => [
'option_group_id.name' => 'activity_type',
'label' => E::ts('Changed category'),
'name' => 'changed_contact_category',
'description' => E::ts('<p>This activity is automatically added when a contact is moved from one category to another.</p>'),
'icon' => 'fa-tags',
],
'match' => [
// Should this be option_group_id.name?
'option_group_id',
'name',
],
],
],
];

View file

@ -0,0 +1,104 @@
<?php
use CRM_Contactcats_ExtensionUtil as E;
return [
[
'name' => 'SavedSearch_SavedSearch_Contact_Category_Counts',
'entity' => 'SavedSearch',
'cleanup' => 'unused',
'update' => 'unmodified',
'params' => [
'version' => 4,
'values' => [
'name' => 'SavedSearch_Contact_Category_Counts',
'label' => E::ts('Category Counts query'),
'api_entity' => 'ContactCategoryDefinition',
'api_params' => [
'version' => 4,
'select' => [
'id',
'label',
'color',
'icon',
'COUNT(ContactCategoryDefinition_ContactCategory_category_definition_id_01.id) AS COUNT_ContactCategoryDefinition_ContactCategory_category_definition_id_01_id',
],
'orderBy' => [],
'where' => [],
'groupBy' => ['id'],
'join' => [
[
'ContactCategory AS ContactCategoryDefinition_ContactCategory_category_definition_id_01',
'LEFT',
[
'id',
'=',
'ContactCategoryDefinition_ContactCategory_category_definition_id_01.category_definition_id',
],
],
],
'having' => [],
],
],
'match' => ['name'],
],
],
[
'name' => 'SavedSearch_SavedSearch_Contact_Category_Counts_SearchDisplay_Category_counts',
'entity' => 'SearchDisplay',
'cleanup' => 'unused',
'update' => 'unmodified',
'params' => [
'version' => 4,
'values' => [
'name' => 'Category_counts',
'label' => E::ts('Category counts'),
'saved_search_id.name' => 'SavedSearch_Contact_Category_Counts',
'type' => 'table',
'settings' => [
'description' => E::ts('Shows a list of all categories and how many contacts are in each one.'),
'sort' => [
['label', 'ASC'],
],
'limit' => 50,
'pager' => FALSE,
'placeholder' => 0,
'columns' => [
[
'type' => 'field',
'key' => 'label',
'dataType' => 'String',
'label' => E::ts('Category'),
'sortable' => TRUE,
'rewrite' => '',
'icons' => [
[
'field' => 'icon',
'side' => 'left',
],
[
'field' => 'icon',
'side' => 'left',
],
],
'cssRules' => [],
],
[
'type' => 'field',
'key' => 'COUNT_ContactCategoryDefinition_ContactCategory_category_definition_id_01_id',
'dataType' => 'Integer',
'label' => E::ts('Count'),
'sortable' => TRUE,
'alignment' => 'text-right',
],
],
'actions' => FALSE,
'classes' => ['table', 'table-striped'],
],
],
'match' => [
'saved_search_id',
'name',
],
],
],
];

View file

@ -27,13 +27,6 @@ return [
'description' => E::ts('Unique ID, corresponds to contact id'), 'description' => E::ts('Unique ID, corresponds to contact id'),
'primary_key' => TRUE, 'primary_key' => TRUE,
'auto_increment' => TRUE, 'auto_increment' => TRUE,
],
'contact_id' => [
'title' => E::ts('Contact ID'),
'sql_type' => 'int unsigned',
'input_type' => 'EntityRef',
'required' => TRUE,
'description' => E::ts('Same as id but for FormBuilder'),
'input_attrs' => [ 'input_attrs' => [
'label' => E::ts('Contact'), 'label' => E::ts('Contact'),
], ],
@ -64,7 +57,7 @@ return [
], ],
], ],
'next_category' => [ 'next_category' => [
'title' => E::ts('Next Category'), 'title' => E::ts('Next Category - internal use'),
'sql_type' => 'int unsigned', 'sql_type' => 'int unsigned',
'required' => TRUE, 'required' => TRUE,
'default' => 0, 'default' => 0,

View file

@ -66,7 +66,7 @@ return [
'icon' => [ 'icon' => [
'title' => E::ts('Icon'), 'title' => E::ts('Icon'),
'sql_type' => 'varchar(64)', 'sql_type' => 'varchar(64)',
'default' => '', 'default' => 'fa-circle-half-stroke',
'required' => TRUE, 'required' => TRUE,
'description' => E::ts('The name of a Font Awesome icon to use to represent this, e.g. fa-trophy'), 'description' => E::ts('The name of a Font Awesome icon to use to represent this, e.g. fa-trophy'),
], ],