Commit da2659ad authored by mattwire's avatar mattwire
Browse files

Release 3.3.4 - fix setting 'eligible for gift aid' on contribution

parent 8c5e882d
<?php
/*
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC. All rights reserved. |
| |
| This work is published under the GNU AGPLv3 license with some |
| permitted exceptions and without any warranty. For full license |
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
use CRM_Civigiftaid_Utils_GiftAid as GiftAidUtil;
use CRM_Civigiftaid_ExtensionUtil as E;
/**
* Class CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility.
*/
class CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility {
class CRM_Civigiftaid_SetContributionGiftAidEligibility {
/**
* Set the gift aid eligibility for a contribution.
* Set the gift aid eligibility for a contribution if it has an eligible financial type.
*
* @param string $op
* The operation being performed.
* @param string $objectName
* Object name.
* @param mixed $objectId
* Object ID.
* @param object $objectRef
* Object reference.
* @param \Civi\Core\Event\GenericHookEvent $event
* @param $hook
*
* @throws \CRM_Extension_Exception
* @throws \CiviCRM_API3_Exception
*/
public function run($op, $objectName, $objectId, &$objectRef) {
if (!$this->shouldRun($op, $objectName)) {
public static function run($event, $hook) {
if (($event->entity !== 'Contribution') || !in_array($event->action, ['create', 'edit'])) {
return;
}
$this->setGiftAidEligibilityStatus($objectId);
self::setGiftAidEligibilityStatus($event->id);
}
/**
......@@ -39,42 +43,48 @@ class CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility {
* This function checks if the contribution is eligible and automatically sets
* the status to yes, else, it sets it to No.
*
* @param int $contributionId
* @param int $contributionID
* Contribution Id.
*
* @throws \CRM_Extension_Exception
* @throws \CiviCRM_API3_Exception
*/
private function setGiftAidEligibilityStatus($contributionId) {
$currentPath = CRM_Utils_System::currentPath();
if (!in_array($currentPath, $this->getRequiredPaths())) {
return;
}
$eligibilityFieldId = $this->getEligibilityFieldId();
$eligibilityField = 'custom_' . $eligibilityFieldId;
private static function setGiftAidEligibilityStatus($contributionID) {
$contributionEligibleGiftAidFieldName = CRM_Civigiftaid_Utils::getCustomByName('Eligible_For_Gift_Aid', 'Gift_Aid');
$contributionBatchNameFieldName = CRM_Civigiftaid_Utils::getCustomByName('batch_name', 'Gift_Aid');
$contribution = civicrm_api3('Contribution', 'getsingle', [
'return' => ['financial_type_id', 'contact_id'],
'id' => $contributionId,
'id' => $contributionID,
'return' => [
'financial_type_id',
'contact_id',
$contributionEligibleGiftAidFieldName,
$contributionBatchNameFieldName
]
]);
$allFinancialTypesEnabled = (bool) CRM_Civigiftaid_Settings::getValue('globally_enabled');
if ($allFinancialTypesEnabled || $this->financialTypeIsEligible($contribution['financial_type_id'])) {
$eligibility = GiftAidUtil::DECLARATION_IS_YES;
if (isset($contribution[$contributionEligibleGiftAidFieldName]) && ($contribution[$contributionEligibleGiftAidFieldName] !== '')) {
$eligibility = (int) $contribution[$contributionEligibleGiftAidFieldName];
}
else {
$eligibility = GiftAidUtil::DECLARATION_IS_NO;
// If the "Eligible for gift-aid" field is already set don't try to set it.
if (!isset($eligibility)) {
// We need to set the Eligible for gift-aid field.
$allFinancialTypesEnabled = (bool) CRM_Civigiftaid_Settings::getValue('globally_enabled');
if ($allFinancialTypesEnabled || self::financialTypeIsEligible($contribution['financial_type_id'])) {
$eligibility = 1;
}
else {
$eligibility = 0;
}
$contributionContact = $contribution['contact_id'];
if (!GiftAidUtil::getDeclaration($contributionContact) && $eligibility === 1) {
CRM_Core_Session::setStatus(self::getMissingGiftAidDeclarationMessage($contributionContact), E::ts('Gift Aid Declaration'), 'success');
}
}
civicrm_api3('Contribution', 'create', [
$eligibilityField => $eligibility,
'id' => $contributionId,
]);
$contributionContact = $contribution['contact_id'];
if (!GiftAidUtil::getDeclaration($contributionContact) && $eligibility == GiftAidUtil::DECLARATION_IS_YES) {
CRM_Core_Session::setStatus(ts($this->getMissingGiftAidDeclarationMessage($contributionContact)), 'Gift Aid Declaration', 'success');
}
// Now update the giftaid fields on the contribution and (re-)do calculations for amounts.
// This will not touch the contribution if it is part of a batch
CRM_Civigiftaid_Utils_Contribution::updateGiftAidFields($contributionID, $eligibility, $contribution[$contributionBatchNameFieldName]);
}
/**
......@@ -87,15 +97,14 @@ class CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility {
* @return string
*
*/
private function getMissingGiftAidDeclarationMessage($contactId) {
$message = "This contribution has been automatically marked as Eligible for Gift Aid.
This is because the administrator has indicated that it's financial type is Eligible for Gift Aid.
However this contact does not have a valid Gift Aid Declaration. You can add one of these %s .";
$giftAidDeclarationGroupId = $this->getGiftAidDeclarationGroupId();
private static function getMissingGiftAidDeclarationMessage($contactId) {
$giftAidDeclarationGroupId = self::getGiftAidDeclarationGroupId();
$selectedTab = 'custom_' . $giftAidDeclarationGroupId;
$link = "<a href='/civicrm/contact/view/?reset=1&gid={$giftAidDeclarationGroupId}&cid={$contactId}&selectedChild={$selectedTab}'> Here </a>";
$link = "<a href='/civicrm/contact/view/?reset=1&gid={$giftAidDeclarationGroupId}&cid={$contactId}&selectedChild={$selectedTab}'>" . E::ts('here') . "</a>";
return sprintf($message, $link);
return E::ts("This contribution has been automatically marked as Eligible for Gift Aid.
This is because the administrator has indicated that it's financial type is Eligible for Gift Aid.
However this contact does not have a valid Gift Aid Declaration. You can add one of these %1.", [1 => $link]);
}
/**
......@@ -104,7 +113,7 @@ class CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility {
* @return int
* Custom group Id.
*/
private function getGiftAidDeclarationGroupId() {
private static function getGiftAidDeclarationGroupId() {
try {
$customGroup = civicrm_api3('CustomGroup', 'getsingle', [
'return' => ['id'],
......@@ -119,67 +128,15 @@ class CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility {
/**
* Checks if the contribution financial type is eligible for gift aid.
*
* @param mixed $financialType
* @param int $financialType
* Financial type.
*
* @return bool
* Whether eligible or not.
*/
private function financialTypeIsEligible($financialType) {
$eligibleFinancialTypes = (array) CRM_Civigiftaid_Settings::getValue('financial_types_enabled');
private static function financialTypeIsEligible($financialType) {
$eligibleFinancialTypes = explode(',', CRM_Civigiftaid_Settings::getValue('financial_types_enabled'));
return in_array($financialType, $eligibleFinancialTypes);
}
/**
* Returns the eligibility custom field Id.
*
* @return int
* Eligibility field Id.
*/
private function getEligibilityFieldId() {
try {
$customField = civicrm_api3('CustomField', 'getsingle', [
'return' => ['id'],
'name' => 'eligible_for_gift_aid',
'custom_group_id' => 'Gift_Aid',
]);
return $customField['id'];
}
catch (Exception $e) {}
}
/**
* Returns paths/Urls where that needs this functionality implemented.
*
* @return array
* Required paths.
*/
private function getRequiredPaths() {
return [
'civicrm/member/add', // Add membership page
'civicrm/contact/view/membership', // Add membership from contact view page
'civicrm/participant/add', // Register event participant page
'civicrm/contact/view/participant' //Add participant from contact view page
];
}
/**
* Determines if the hook should run or not.
*
* @param string $op
* The operation being performed.
* @param string $objectName
* Object name.
*
* @return bool
* returns a boolean to determine if hook will run or not.
*/
private function shouldRun($op, $objectName) {
return $op == 'create' && $objectName == 'Contribution';
}
}
......@@ -49,17 +49,13 @@ class CRM_Civigiftaid_Settings {
/**
* Read setting that has prefix in database and return single value
* @param $name
*
* @param string $name
*
* @return mixed
*/
public static function getValue($name) {
$className = E::CLASS_PREFIX . '_Settings';
$settings = civicrm_api3('setting', 'get', ['return' => $className::getName($name,true)]);
$domainID = CRM_Core_Config::domainID();
if (isset($settings['values'][$domainID][$className::getName($name,true)])) {
return $settings['values'][$domainID][$className::getName($name, true)];
}
return '';
return \Civi::settings()->get(E::SHORT_NAME . "_{$name}");
}
/**
......
......@@ -18,12 +18,11 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
public function install() {
$this->setOptionGroups();
$this->enableOptionGroups(1);
self::migrateOneToTwo($this);
$this->setCustomFields();
$this->upgrade_3000();
$this->upgrade_3101();
$this->upgrade_3103();
$this->upgrade_3104();
$this->upgrade_3105();
}
/**
......@@ -144,7 +143,16 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
}
public function upgrade_3105() {
$this->log('Set contribution "Eligible Amount" custom field label');
return TRUE;
}
public function upgrade_3106() {
$this->log('Updating custom fields');
$this->setCustomFields();
return TRUE;
}
private function setCustomFields() {
$amountCustomField = civicrm_api3('CustomField', 'getsingle', [
'custom_group_id' => "Gift_Aid",
'name' => "Amount",
......@@ -152,7 +160,46 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
if ($amountCustomField['label'] !== 'Eligible Amount') {
civicrm_api3('CustomField', 'create', ['id' => $amountCustomField['id'], 'label' => 'Eligible Amount']);
}
return TRUE;
$customFields = $this->getCustomFields();
foreach ($customFields as $customField) {
try {
$existingField = civicrm_api3('CustomField', 'getsingle', [
'custom_group_id' => $customField['custom_group_id'],
'name' => $customField['name']
]);
if (!empty($customField['option_group_id'])) {
$customField['option_group_id'] = civicrm_api3('OptionGroup', 'getvalue', ['name' => $customField['option_group_id'], 'return' => 'id']);
}
}
catch (Exception $e) {
continue;
}
$customField = array_merge($customField, ['id' => $existingField['id']]);
civicrm_api3('CustomField', 'create', $customField);
}
}
private function getCustomFields() {
$optionGroups = $this->getOptionGroups();
$customFields = [
'Eligible_for_Gift_Aid' => [
'custom_group_id' => 'Gift_Aid',
'name' => 'Eligible_for_Gift_Aid',
'label' => 'Eligible for Gift Aid?',
'data_type' => 'Int',
'html_type' => 'Radio',
'is_searchable' => '1',
'is_search_range' => '0',
'weight' => '1',
'help_pre' => '\'Eligible for Gift Aid\' will be set automatically based on the financial type of the contribution if you do not select Yes or No',
'is_active' => '1',
'column_name' => 'eligible_for_gift_aid',
'option_group_id' => 'uk_taxpayer_options',
'in_selector' => '0'
]
];
return $customFields;
}
private function getOptionGroups() {
......@@ -202,6 +249,7 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
'name' => 'eligible_for_giftaid',
'is_default' => 0,
'weight' => 2,
'is_reserved' => 1,
],
[
'option_group_id' => $optionGroups['eligibility_declaration_options']['id'],
......@@ -210,6 +258,7 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
'name' => 'not_eligible_for_giftaid',
'is_default' => 0,
'weight' => 3,
'is_reserved' => 1,
],
[
'option_group_id' => $optionGroups['eligibility_declaration_options']['id'],
......@@ -218,6 +267,7 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
'name' => 'past_four_years',
'is_default' => 0,
'weight' => 1,
'is_reserved' => 1,
],
[
'option_group_id' => $optionGroups['uk_taxpayer_options']['id'],
......@@ -225,6 +275,7 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
'value' => 1,
'name' => 'yes_uk_taxpayer',
'is_default' => 0,
'is_reserved' => 1,
],
[
'option_group_id' => $optionGroups['uk_taxpayer_options']['id'],
......@@ -232,6 +283,7 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
'value' => 0,
'name' => 'not_uk_taxpayer',
'is_default' => 0,
'is_reserved' => 1,
],
[
'option_group_id' => $optionGroups['uk_taxpayer_options']['id'],
......@@ -240,6 +292,7 @@ class CRM_Civigiftaid_Upgrader extends CRM_Civigiftaid_Upgrader_Base {
'name' => 'uk_taxpayer_past_four_years',
'is_active' => 0,
'is_default' => 0,
'is_reserved' => 1,
],
[
......
......@@ -69,7 +69,7 @@ class CRM_Civigiftaid_Utils_Contribution {
'entity_table' => 'civicrm_contribution',
]);
self::updateGiftAidFields($contribution['id'], NULL, $batchName);
self::updateGiftAidFields($contribution['id'], NULL, $batchName, $addToBatch = TRUE);
$contributionsAdded[] = $contribution['id'];
}
......@@ -102,29 +102,35 @@ class CRM_Civigiftaid_Utils_Contribution {
* @throws \CRM_Extension_Exception
* @throws \CiviCRM_API3_Exception
*/
public static function updateGiftAidFields($contributionID, $eligibleForGiftAid = NULL, $batchName = '') {
$totalAmount = (float) civicrm_api3('Contribution', 'getvalue', [
'return' => "total_amount",
'id' => $contributionID,
]);
$giftAidableContribAmt = self::getGiftAidableContribAmt($totalAmount, $contributionID);
$giftAidAmount = self::calculateGiftAidAmt($giftAidableContribAmt, self::getBasicRateTax());
public static function updateGiftAidFields($contributionID, $eligibleForGiftAid = NULL, $batchName = '', $addToBatch = FALSE) {
if (!empty($batchName) && !$addToBatch) {
// Don't touch this contribution - it's already part of a batch
return;
}
$groupID = civicrm_api3('CustomGroup', 'getvalue', [
'return' => "id",
'name' => "gift_aid",
]);
$contributionParams = [
'entity_id' => $contributionID,
CRM_Civigiftaid_Utils::getCustomByName('gift_aid_amount', $groupID) => $giftAidAmount,
CRM_Civigiftaid_Utils::getCustomByName('amount', $groupID) => $giftAidableContribAmt,
];
if ($batchName !== NULL) {
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('batch_name', $groupID)] = $batchName;
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('batch_name', 'Gift_Aid')] = $batchName;
}
if ($eligibleForGiftAid) {
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('Eligible_for_Gift_Aid', $groupID)] = 1;
if (isset($eligibleForGiftAid)) {
$eligibleForGiftAid = (int) $eligibleForGiftAid;
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('Eligible_for_Gift_Aid', 'Gift_Aid')] = (int) $eligibleForGiftAid;
if ($eligibleForGiftAid === 0) {
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('gift_aid_amount', 'Gift_Aid')] = NULL;
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('amount', 'Gift_Aid')] = NULL;
}
else {
// Eligible - calculate gift aid amounts
$totalAmount = (float) civicrm_api3('Contribution', 'getvalue', [
'return' => "total_amount",
'id' => $contributionID,
]);
$giftAidableContribAmt = self::getGiftAidableContribAmt($totalAmount, $contributionID);
$giftAidAmount = self::calculateGiftAidAmt($giftAidableContribAmt, self::getBasicRateTax());
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('gift_aid_amount', 'Gift_Aid')] = $giftAidAmount;
$contributionParams[CRM_Civigiftaid_Utils::getCustomByName('amount', 'Gift_Aid')] = $giftAidableContribAmt;
}
}
$contributionParams['entity_id'] = $contributionID;
// We use CustomValue.create instead of Contribution.create because Contribution.create is way too slow
civicrm_api3('CustomValue', 'create', $contributionParams);
}
......
......@@ -11,6 +11,12 @@ define('CIVICRM_GIFTAID_REMOVE_TASKID', 1436);
*/
function civigiftaid_civicrm_config(&$config) {
_civigiftaid_civix_civicrm_config($config);
if (isset(Civi::$statics[__FUNCTION__])) { return; }
Civi::$statics[__FUNCTION__] = 1;
// Add listeners for CiviCRM hooks that might need altering by other scripts
Civi::dispatcher()->addListener('hook_civicrm_post', 'CRM_Civigiftaid_SetContributionGiftAidEligibility::run');
}
/**
......@@ -240,13 +246,6 @@ function civigiftaid_update_declaration_amount($contributionID, $op) {
* @throws \CiviCRM_API3_Exception
*/
function civigiftaid_civicrm_post($op, $objectName, $objectId, &$objectRef) {
$hooks = [
new CRM_Civigiftaid_Hook_Post_SetContributionGiftAidEligibility(),
];
foreach ($hooks as $hook) {
$hook->run($op, $objectName, $objectId, $objectRef);
}
switch ($objectName) {
case 'Contribution':
if ($op == 'edit' || $op == 'create') {
......
# Contributions and eligibility
Contributions have the following Gift Aid fields.
#### Eligible for Gift Aid?
If the value is set on the form (eg. via Add contribution) then that value will be used.
Otherwise it is set automatically based on the enabled financial types.
This means it will always get set to Yes or No but can be optionally overridden via the UI.
#### Eligible Amount
This is the amount of the contribution that is eligible for gift-aid.
If there are no financial types that are eligible for the contribution the eligible amount will be 0.
#### Gift Aid Amount
This is the actual gift aid amount of the eligible amount.
#### Batch Name
This is set automatically when the contribution is added to a batch.
......@@ -6,8 +6,8 @@ The extension is licensed under [AGPL-3.0](LICENSE.txt).
## Requirements
* PHP v7.x
* CiviCRM 5.13+
* PHP v7.2+
* CiviCRM 5.24+
## Installation
......
## Release 3.3.4
* Fix issues with setting "Eligible for gift aid" on contributions.
* Added [documentation](../contributions.md) to explain how the gift aid fields on contributions work.
## Release 3.3.3
* Include first donation in the batch
......
......@@ -16,8 +16,8 @@
<author>MJW Consulting, Erawat Chamanont, Jamie Novick, Guanhuan Chen, Robin Mitra</author>
<email>mjw@mjwconsult.co.uk, jamie@compucorp.co.uk, guanhuan@compucorp.co.uk</email>
</maintainer>
<releaseDate>2020-04-07</releaseDate>
<version>3.3.3</version>
<releaseDate>2020-04-15</releaseDate>
<version>3.3.4</version>
<develStage>beta</develStage>
<compatibility>
<ver>5.19</ver>
......
site_name: Smart Debit (Direct Debit provider in the UK)
repo_url: https://github.com/mattwire/org.civicrm.smartdebit
theme: material
site_name: UK Gift Aid
repo_url: https://github.com/mattwire/uk.co.compucorp.civicrm.giftaid
theme:
name: material
markdown_extensions:
- attr_list
- admonition
- def_list
- codehilite
- toc(permalink=true)
- toc:
permalink: true
- pymdownx.superfences
- pymdownx.inlinehilite
- pymdownx.tilde
- pymdownx.betterem
- pymdownx.mark
pages:
nav:
- Release Notes: release/release_notes.md
- Introduction: index.md
- Setup and Configuration: setup.md
- The Gift Aid Declaration: declaration.md
- Contributions and Eligibility: contributions.md
- Creating and managing your batch: batches.md
- Submission to HMRC: submission.md
- Managing the basic rate of Tax: tax.md
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment