Commit 3a95a722 authored by mattwire's avatar mattwire
Browse files

Update and refactor how we create/update declarations

parent 4c20b821
This diff is collapsed.
<?php
/*--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+-------------------------------------------------------------------*/
use CRM_Civigiftaid_ExtensionUtil as E;
/**
* Form controller class
*
* @see http://wiki.civicrm.org/confluence/display/CRMDOC43/QuickForm+Reference
*/
class CRM_Civigiftaid_Form_Settings extends CRM_Core_Form {
function buildQuickForm() {
parent::buildQuickForm();
$className = E::CLASS_PREFIX . '_Settings';
CRM_Utils_System::setTitle($className::TITLE . ' - ' . E::ts('Settings'));
$className = E::CLASS_PREFIX . '_Form_SettingsCustom';
if (method_exists($className, 'buildQuickFormPre')) {
$className::buildQuickFormPre($this);
}
$settings = $this->getFormSettings();
foreach ($settings as $name => $setting) {
if (isset($setting['html_type'])) {
Switch (strtolower($setting['html_type'])) {
case 'text':
$this->addElement('text', $name, ts($setting['description']), $setting['html_attributes'], []);
break;
case 'checkbox':
$this->addElement('checkbox', $name, ts($setting['description']), '', '');
break;
case 'datepicker':
foreach ($setting['html_extra'] as $key => $value) {
if ($key == 'minDate') {
$minDate = new DateTime('now');
$minDate->modify($value);
$setting['html_extra'][$key] = $minDate->format('Y-m-d');
}
}
$this->add('datepicker', $name, ts($setting['description']), $setting['html_attributes'], FALSE, $setting['html_extra']);
break;
case 'select2':
$className = E::CLASS_PREFIX . '_Form_SettingsCustom';
if (method_exists($className, 'addSelect2Element')) {
$className::addSelect2Element($this, $name, $setting);
}
break;
case 'select':
$className = E::CLASS_PREFIX . '_Form_SettingsCustom';
if (method_exists($className, 'addSelectElement')) {
$className::addSelectElement($this, $name, $setting);
}
break;
case 'hidden':
$hidden = TRUE;
}
if (isset($hidden)) {
continue;
}
$adminGroup = isset($setting['admin_group']) ? $setting['admin_group'] : 'default';
$elementGroups[$adminGroup]['elementNames'][] = $name;
// Title and description may not be defined on all elements (they only need to be on one)
if (!empty($setting['admin_grouptitle'])) {
$elementGroups[$setting['admin_group']]['title'] = $setting['admin_grouptitle'];
}
if (!empty($setting['admin_groupdescription'])) {
$elementGroups[$setting['admin_group']]['description'] = $setting['admin_groupdescription'];
}
}
}
$this->addButtons([
[
'type' => 'submit',
'name' => ts('Submit'),
'isDefault' => TRUE,
],
[
'type' => 'cancel',
'name' => ts('Cancel'),
]
]);
// export form elements
$this->assign('elementGroups', $elementGroups);
}
function postProcess() {
$className = E::CLASS_PREFIX . '_Settings';
$changed = $this->_submitValues;
$settings = $this->getFormSettings(TRUE);
foreach ($settings as &$setting) {
if ($setting['html_type'] == 'Checkbox') {
$setting = false;
}
else {
$setting = NULL;
}
}
// Make sure we have all settings elements set (boolean settings will be unset by default and wouldn't be saved)
$settingsToSave = array_merge($settings, array_intersect_key($changed, $settings));
$className::save($settingsToSave);
parent::postProcess();
CRM_Core_Session::singleton()->setStatus('Configuration Updated', $className::TITLE, 'success');
}
/**
* Get the settings we are going to allow to be set on this form.
*
* @return array
*/
function getFormSettings($metadata=TRUE) {
$className = E::CLASS_PREFIX . '_Settings';
$unprefixedSettings = [];
$settings = civicrm_api3('setting', 'getfields', ['filters' => $className::getFilter()]);
if (!empty($settings['values'])) {
foreach ($settings['values'] as $name => $values) {
if ($metadata) {
$unprefixedSettings[$className::getName($name, FALSE)] = $values;
}
else {
$unprefixedSettings[$className::getName($name, FALSE)] = NULL;
}
}
}
return $unprefixedSettings;
}
/**
* Set defaults for form.
*
* @see CRM_Core_Form::setDefaultValues()
*/
function setDefaultValues() {
$className = E::CLASS_PREFIX . '_Settings';
$settings = $this->getFormSettings(FALSE);
$defaults = [];
$existing = $className::get(array_keys($settings));
if ($existing) {
foreach ($existing as $name => $value) {
$defaults[$name] = $value;
}
}
return $defaults;
}
}
<?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_ExtensionUtil as E;
/**
* Form controller class
*
* @see http://wiki.civicrm.org/confluence/display/CRMDOC43/QuickForm+Reference
*/
class CRM_Civigiftaid_Form_Settings extends CRM_Core_Form {
function buildQuickForm() {
parent::buildQuickForm();
$className = E::CLASS_PREFIX . '_Settings';
CRM_Utils_System::setTitle($className::TITLE . ' - ' . E::ts('Settings'));
$className = E::CLASS_PREFIX . '_Form_SettingsCustom';
if (method_exists($className, 'buildQuickFormPre')) {
$className::buildQuickFormPre($this);
}
$settings = $this->getFormSettings();
foreach ($settings as $name => $setting) {
if (isset($setting['html_type'])) {
Switch (strtolower($setting['html_type'])) {
case 'text':
$this->addElement('text', $name, ts($setting['description']), $setting['html_attributes'], []);
break;
case 'checkbox':
$this->addElement('checkbox', $name, ts($setting['description']), '', '');
break;
case 'datepicker':
foreach ($setting['html_extra'] as $key => $value) {
if ($key == 'minDate') {
$minDate = new DateTime('now');
$minDate->modify($value);
$setting['html_extra'][$key] = $minDate->format('Y-m-d');
}
}
$this->add('datepicker', $name, ts($setting['description']), $setting['html_attributes'], FALSE, $setting['html_extra']);
break;
case 'select2':
$className = E::CLASS_PREFIX . '_Form_SettingsCustom';
if (method_exists($className, 'addSelect2Element')) {
$className::addSelect2Element($this, $name, $setting);
}
break;
case 'select':
$className = E::CLASS_PREFIX . '_Form_SettingsCustom';
if (method_exists($className, 'addSelectElement')) {
$className::addSelectElement($this, $name, $setting);
}
break;
case 'hidden':
$hidden = TRUE;
}
if (isset($hidden)) {
continue;
}
$adminGroup = isset($setting['admin_group']) ? $setting['admin_group'] : 'default';
$elementGroups[$adminGroup]['elementNames'][] = $name;
// Title and description may not be defined on all elements (they only need to be on one)
if (!empty($setting['admin_grouptitle'])) {
$elementGroups[$setting['admin_group']]['title'] = $setting['admin_grouptitle'];
}
if (!empty($setting['admin_groupdescription'])) {
$elementGroups[$setting['admin_group']]['description'] = $setting['admin_groupdescription'];
}
}
}
$this->addButtons([
[
'type' => 'submit',
'name' => ts('Submit'),
'isDefault' => TRUE,
],
[
'type' => 'cancel',
'name' => ts('Cancel'),
]
]);
// export form elements
$this->assign('elementGroups', $elementGroups);
}
function postProcess() {
$className = E::CLASS_PREFIX . '_Settings';
$changed = $this->_submitValues;
$settings = $this->getFormSettings(TRUE);
foreach ($settings as &$setting) {
if ($setting['html_type'] == 'Checkbox') {
$setting = false;
}
else {
$setting = NULL;
}
}
// Make sure we have all settings elements set (boolean settings will be unset by default and wouldn't be saved)
$settingsToSave = array_merge($settings, array_intersect_key($changed, $settings));
$className::save($settingsToSave);
parent::postProcess();
CRM_Core_Session::singleton()->setStatus('Configuration Updated', $className::TITLE, 'success');
}
/**
* Get the settings we are going to allow to be set on this form.
*
* @return array
*/
function getFormSettings($metadata=TRUE) {
$className = E::CLASS_PREFIX . '_Settings';
$unprefixedSettings = [];
$settings = civicrm_api3('setting', 'getfields', ['filters' => $className::getFilter()]);
if (!empty($settings['values'])) {
foreach ($settings['values'] as $name => $values) {
if ($metadata) {
$unprefixedSettings[$className::getName($name, FALSE)] = $values;
}
else {
$unprefixedSettings[$className::getName($name, FALSE)] = NULL;
}
}
}
return $unprefixedSettings;
}
/**
* Set defaults for form.
*
* @see CRM_Core_Form::setDefaultValues()
*/
function setDefaultValues() {
$className = E::CLASS_PREFIX . '_Settings';
$settings = $this->getFormSettings(FALSE);
$defaults = [];
$existing = $className::get(array_keys($settings));
if ($existing) {
foreach ($existing as $name => $value) {
$defaults[$name] = $value;
}
}
return $defaults;
}
}
......@@ -9,7 +9,6 @@
+--------------------------------------------------------------------+
*/
use CRM_Civigiftaid_Utils_GiftAid as GiftAidUtil;
use CRM_Civigiftaid_ExtensionUtil as E;
/**
......@@ -30,7 +29,7 @@ class CRM_Civigiftaid_SetContributionGiftAidEligibility {
if (($event->entity !== 'Contribution') || !in_array($event->action, ['create', 'edit'])) {
return;
}
self::setGiftAidEligibilityStatus($event->id);
self::setGiftAidEligibilityStatus($event->id, $event->action);
}
/**
......@@ -45,11 +44,13 @@ class CRM_Civigiftaid_SetContributionGiftAidEligibility {
*
* @param int $contributionID
* Contribution Id.
* @param string $action
* The action - eg. create/edit
*
* @throws \CRM_Extension_Exception
* @throws \CiviCRM_API3_Exception
*/
private static function setGiftAidEligibilityStatus($contributionID) {
private static function setGiftAidEligibilityStatus($contributionID, $action) {
$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', [
......@@ -57,8 +58,9 @@ class CRM_Civigiftaid_SetContributionGiftAidEligibility {
'return' => [
'financial_type_id',
'contact_id',
'contribution_recur_id',
$contributionEligibleGiftAidFieldName,
$contributionBatchNameFieldName
$contributionBatchNameFieldName,
]
]);
......@@ -77,14 +79,20 @@ class CRM_Civigiftaid_SetContributionGiftAidEligibility {
}
$contributionContact = $contribution['contact_id'];
if (!GiftAidUtil::getDeclaration($contributionContact) && $eligibility === 1) {
if (!CRM_Civigiftaid_Declaration::getDeclaration($contributionContact) && $eligibility === 1) {
CRM_Core_Session::setStatus(self::getMissingGiftAidDeclarationMessage($contributionContact), E::ts('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]);
if (!empty($contribution['contribution_recur_id']) && ($action === 'create')) {
// As it is a copy of a contribution we need to clear the batch name field
CRM_Civigiftaid_Utils_Contribution::updateGiftAidFields($contributionID, $eligibility, '', TRUE);
}
else {
// This will not touch the contribution if it is part of a batch
CRM_Civigiftaid_Utils_Contribution::updateGiftAidFields($contributionID, $eligibility, $contribution[$contributionBatchNameFieldName]);
}
}
/**
......
......@@ -65,7 +65,7 @@ class CRM_Civigiftaid_Utils_Contribution {
}
// check if contribution is valid for gift aid
if (CRM_Civigiftaid_Utils_GiftAid::isEligibleForGiftAid($contribution)
if (self::isEligibleForGiftAid($contribution)
&& ($contribution['contribution_status_id'] == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'))
) {
civicrm_api3('EntityBatch', 'create', [
......@@ -103,6 +103,7 @@ class CRM_Civigiftaid_Utils_Contribution {
* @param int $contributionID
* @param int $eligibleForGiftAid - if this is NULL if will NOT be set, otherwise set it to eg CRM_Civigiftaid_Utils_GiftAid::DECLARATION_IS_YES
* @param string $batchName - if this is set to NULL it will NOT be changed
* @param bool $addToBatch - You must set this to TRUE to modify the batchName
*
* @throws \CRM_Extension_Exception
* @throws \CiviCRM_API3_Exception
......@@ -379,7 +380,7 @@ class CRM_Civigiftaid_Utils_Contribution {
if (!empty($contribution[CRM_Civigiftaid_Utils::getCustomByName('batch_name', $groupID)])) {
$contributionsAlreadyAdded[] = $contribution['id'];
}
elseif (CRM_Civigiftaid_Utils_GiftAid::isEligibleForGiftAid($contribution)
elseif (self::isEligibleForGiftAid($contribution)
&& ($contribution['contribution_status_id'] == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'))
) {
$contributionsAdded[] = $contribution['id'];
......@@ -571,4 +572,192 @@ class CRM_Civigiftaid_Utils_Contribution {
return self::getContribAmtForEnabledFinanceTypes($contributionID);
}
/**
* @param array $contribution
*
* @return bool
* @throws \CiviCRM_API3_Exception
*/
public static function isEligibleForGiftAid($contribution) {
$isContributionEligible = self::isContributionEligible($contribution);
// hook can alter the eligibility if needed
CRM_Civigiftaid_Utils_Hook::giftAidEligible($isContributionEligible, $contribution['contact_id'], $contribution['receive_date'], $contribution['id']);
return $isContributionEligible;
}
/**
* @param array $declarations
* @param int $limit
*
* @return array
* @throws \CiviCRM_API3_Exception
*/
public static function getContributionsByDeclarations($declarations = [], $limit = 100) {
$contributionsToSubmit = [];
foreach ($declarations as $declaration) {
$dateRange = [];
$contactId = $declaration['entity_id'];
$startDate = $declaration['start_date'];
$dateRange[0] = self::dateFourYearsAgo($startDate);
$dateRange[1] = $startDate;
$contributions = self::getContributionsByDateRange($contactId, $dateRange);
$contributionsToSubmit = array_merge($contributions, $contributionsToSubmit);
if (count($contributionsToSubmit) >= $limit) {
$contributionsToSubmit = array_slice($contributionsToSubmit, 0, $limit);
break;
}
}
return $contributionsToSubmit;
}
/**
* @param int $contactId
* @param string $dateRange
*
* @return mixed
* @throws \CiviCRM_API3_Exception
*/
public static function getContributionsByDateRange($contactId, $dateRange) {
if ((bool) CRM_Civigiftaid_Settings::getValue('globally_enabled')) {
$result = civicrm_api3('Contribution', 'get', [
'sequential' => 1,
'return' => "financial_type_id,id",
'contact_id' => $contactId,
'id' => ['NOT IN' => self::submittedContributions()],
'receive_date' => ['BETWEEN' => $dateRange],
]);
}
else {
if ($financialTypes = (array) CRM_Civigiftaid_Settings::getValue('financial_types_enabled')) {
$result = civicrm_api3('Contribution', 'get', [
'sequential' => 1,
'return' => "financial_type_id,id",
'contact_id' => $contactId,
'financial_type_id' => $financialTypes,
'id' => ['NOT IN' => self::submittedContributions()],
'receive_date' => ['BETWEEN' => $dateRange],
]);
}
}
return $result['values'];
}
/**
* @return array
*/
public static function submittedContributions() {
$submittedContributions = [];
$sql = "
SELECT entity_id
FROM civicrm_value_gift_aid_submission";
$dao = CRM_Core_DAO::executeQuery($sql);
foreach ($dao->fetchAll() as $row) {
$submittedContributions[] = $row['entity_id'];
}
return $submittedContributions;
}
/**
* Check if Eligibility criteria for Contribution is met.
*
* @param array $contribution
*
* @return bool
* @throws \CiviCRM_API3_Exception
*/
public static function isContributionEligible($contribution) {
$declarations = CRM_Civigiftaid_Declaration::getAllDeclarations($contribution['contact_id']);
if (empty($declarations)) {
return FALSE;
}
$eligibleAmount = $contribution[CRM_Civigiftaid_Utils::getCustomByName('Amount', 'Gift_Aid')];
if (!empty($eligibleAmount) && ($eligibleAmount == 0)) {
// Contribution has 0 eligible amount.
return FALSE;
}
$isEligible = $contribution[CRM_Civigiftaid_Utils::getCustomByName('Eligible_for_Gift_Aid', 'Gift_Aid')];
if (!empty($isEligible) && ($isEligible == 0)) {
// Contribution marked as not eligible
return FALSE;
};
// If it is not set ('') it's not the same as DECLARATION_IS_NO
if (!empty($contributionEligible) && ($contributionEligible == CRM_Civigiftaid_Declaration::DECLARATION_IS_NO)) {
return FALSE;
}
foreach ($declarations as $declaration) {
if ($declaration['eligible_for_gift_aid'] == CRM_Civigiftaid_Declaration::DECLARATION_IS_PAST_4_YEARS) {
$declaration['start_date'] = self::dateFourYearsAgo($declaration['start_date']);
}
// Convert dates to timestamps.
$startDateTS = strtotime(date('Ymd 00:00:00', strtotime($declaration['start_date'])));
$endDateTS = !empty($declaration['end_date']) ? strtotime(date('Ymd 00:00:00', strtotime($declaration['end_date']))) : NULL;
$contributionDateTS = strtotime($contribution['receive_date']);
/**
* Check between which date the contribution's receive date falls.
*/
if (!empty($endDateTS)) {
$contributionDeclarationDateMatchFound =
($contributionDateTS >= $startDateTS) && ($contributionDateTS < $endDateTS);
}
else {
$contributionDeclarationDateMatchFound = ($contributionDateTS >= $startDateTS);
}
if ($contributionDeclarationDateMatchFound == TRUE) {
return ((bool) $declaration['eligible_for_gift_aid']);
}
}
return FALSE;
}
/**
* @param array $params
*/
public static function setSubmission($params) {
$sql = "SELECT * FROM civicrm_value_gift_aid_submission where entity_id = %1";
$sqlParams = [1 => [$params['entity_id'], 'Integer']];
$dao = CRM_Core_DAO::executeQuery($sql, $sqlParams);
$count = count($dao->fetchAll());
if ($count == 0) {
// Insert
$sql = "
INSERT INTO civicrm_value_gift_aid_submission (entity_id, eligible_for_gift_aid, amount, gift_aid_amount, batch_name)
VALUES (%1, %2, NULL, NULL, NULL)";
}
else {
// Update
$sql = "
UPDATE civicrm_value_gift_aid_submission
SET eligible_for_gift_aid = %2
WHERE entity_id = %1";
}
$queryParams = [
1 => [$params['entity_id'], 'Integer'],