From cb87dffceedc566825d5accaf5e0dd8fbf2547f2 Mon Sep 17 00:00:00 2001
From: minyanyi <109479933+minyanyi@users.noreply.github.com>
Date: Mon, 11 May 2026 17:13:53 +0800
Subject: [PATCH] Add optional disabled campaign penalty
---
.../Matcher/CreateCampaignContribution.php | 56 +++++++++++++++++++
.../CreateCampaignContribution.suggestion.tpl | 5 ++
.../CreateCampaignContributionTest.php | 56 +++++++++++++++++++
3 files changed, 117 insertions(+)
diff --git a/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.php b/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.php
index dc88f246..008b5ac1 100644
--- a/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.php
+++ b/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.php
@@ -78,6 +78,10 @@ public function __construct($config_name) {
// ...default for which is: only activities with campaigns
$config->activity_with_no_campaign_penalty = 1.00;
}
+ // penalty for disabled campaigns
+ if (!isset($config->disabled_campaign_penalty)) {
+ $config->disabled_campaign_penalty = 0.00;
+ }
// default status is 'in Progress'
if (!isset($config->active_recurring_contribution_status_ids)) {
$config->active_recurring_contribution_status_ids = ['In Progress'];
@@ -203,6 +207,7 @@ public function match(CRM_Banking_BAO_BankTransaction $btx, CRM_Banking_Matcher_
$activity_confidence = max($contacts_found[$contact_id], 0.0);
$this->logMessage("Found [{$contact_id}] with confidence {$activity_confidence} (including penalty of {$penalty})", 'debug');
$multiple_recurring_contributions_penalty_applied = $this->adjustRatingOfRecurringContributions($contact_id, $activity_confidence, $btx);
+ $disabled_campaign_penalty_applied = 0.0;
// also: add a penalty for activities without campaign (if configured this way)
if ($activity_with_no_campaign_penalty > 0.0) {
@@ -212,6 +217,12 @@ public function match(CRM_Banking_BAO_BankTransaction $btx, CRM_Banking_Matcher_
$no_campaign_penalty_applied = $activity_with_no_campaign_penalty;
}
}
+ if (!empty($activity['campaign_id'])) {
+ $disabled_campaign_penalty_applied = $this->adjustRatingOfDisabledCampaign(
+ $activity['campaign_id'],
+ $activity_confidence
+ );
+ }
// apply the general penalty
$activity_confidence = min($activity_confidence - $penalty, 1.0);
@@ -226,6 +237,7 @@ public function match(CRM_Banking_BAO_BankTransaction $btx, CRM_Banking_Matcher_
$suggestion->setParameter('activity_id', $activity_id);
$suggestion->setParameter('multiple_recurring_contributions_penalty_applied', $multiple_recurring_contributions_penalty_applied);
$suggestion->setParameter('no_campaign_penalty_applied', $no_campaign_penalty_applied);
+ $suggestion->setParameter('disabled_campaign_penalty_applied', $disabled_campaign_penalty_applied);
$suggestion->setParameter('time_after_activity', strtotime("{$btx->booking_date}") - strtotime($activity['activity_date_time']));
$suggestion->setProbability($activity_confidence);
if ($activity_confidence == 1.0) {
@@ -367,6 +379,48 @@ public function adjustRatingOfRecurringContributions($contact_id, &$contact_prob
}
}
+ /**
+ * This will reduce the probability of a campaign contribution if
+ * the referenced campaign is disabled.
+ *
+ * @param int|string|null $campaign_id
+ * Campaign ID.
+ * @param float $contact_probability
+ * The probability of the contact to be adjusted.
+ *
+ * @return float
+ * Penalty added to the contact's rating.
+ */
+ public function adjustRatingOfDisabledCampaign($campaign_id, &$contact_probability) {
+ $disabled_campaign_penalty = (float) ($this->_plugin_config->disabled_campaign_penalty ?? 0);
+ if ($disabled_campaign_penalty <= 0 || empty($campaign_id)) {
+ return 0.0;
+ }
+
+ static $campaign_is_active = [];
+ $campaign_id = (int) $campaign_id;
+
+ if (!array_key_exists($campaign_id, $campaign_is_active)) {
+ try {
+ $campaign = civicrm_api3('Campaign', 'getsingle', ['id' => $campaign_id]);
+ }
+ catch (Exception $ex) {
+ $this->logMessage("Campaign [{$campaign_id}] could not be loaded, disabled-campaign penalty skipped.", 'warn');
+ return 0.0;
+ }
+ $campaign_is_active[$campaign_id] = !empty($campaign['is_active']);
+ }
+
+ if ($campaign_is_active[$campaign_id]) {
+ $this->logMessage("Campaign [{$campaign_id}] is active, no disabled-campaign penalty applied.", 'debug');
+ return 0.0;
+ }
+
+ $contact_probability = max(0.0, $contact_probability - $disabled_campaign_penalty);
+ $this->logMessage("Campaign [{$campaign_id}] is disabled, suggestion will be reduced by a penalty of {$disabled_campaign_penalty}.", 'info');
+ return $disabled_campaign_penalty;
+ }
+
/**
* If the user has modified the input fields provided by the "visualize" html code,
* the new values will be passed here BEFORE execution
@@ -391,6 +445,7 @@ public function visualize_match(CRM_Banking_Matcher_Suggestion $match, $btx) {
$contact_id = $match->getParameter('contact_id');
$activity_id = $match->getParameter('activity_id');
$no_campaign_penalty_applied = $match->getParameter('no_campaign_penalty_applied');
+ $disabled_campaign_penalty_applied = $match->getParameter('disabled_campaign_penalty_applied');
$multiple_recurring_contributions_penalty_applied
= $match->getParameter('multiple_recurring_contributions_penalty_applied');
$contribution = $this->get_contribution_data($btx, $match, $contact_id);
@@ -440,6 +495,7 @@ public function visualize_match(CRM_Banking_Matcher_Suggestion $match, $btx) {
// penalties
$smarty_vars['no_campaign_penalty_applied'] = (int) (100.0 * $no_campaign_penalty_applied);
+ $smarty_vars['disabled_campaign_penalty_applied'] = (int) (100.0 * $disabled_campaign_penalty_applied);
$smarty_vars['multiple_recurring_contributions_penalty_applied']
= (int) (100.0 * $multiple_recurring_contributions_penalty_applied);
diff --git a/templates/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.suggestion.tpl b/templates/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.suggestion.tpl
index 1612d23f..a88587f7 100644
--- a/templates/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.suggestion.tpl
+++ b/templates/CRM/Banking/PluginImpl/Matcher/CreateCampaignContribution.suggestion.tpl
@@ -36,6 +36,11 @@
{ts 1=$no_campaign_penalty_applied}Caution: the activity found has no campaign, so the score of this suggestion has been reduced by %1%.{/ts}
{/if}
+ {if $disabled_campaign_penalty_applied}
+
+ {ts 1=$disabled_campaign_penalty_applied}Caution: the selected campaign is disabled, so the score of this suggestion has been reduced by %1%.{/ts}
+
+ {/if}
{ts 1=$activity_link}Based on activity '%1', the following contribution will be created:{/ts}