Skip to content

Commit dccd9f4

Browse files
Edzelopezcolemanw
authored andcommitted
CRM-18854 [needs-review] Added support for recurring contributions for online pledges (civicrm#8558)
* MISC-110 Added pledge start date for pledge block * MISC-110 Added pledge start date to online contribution form * MISC-110 Added recur record for pledge * MISC-110 Added changes suggested by Eileen * MISC-110 Added upgrade code for pledge_start_date * MISC-110 Added unit test for createRecur function * MISC-110 Removed use of form and set payment instrument id * MISC-110 Added webtest for Pledge Recurring contribution * MISC-110 Removed unfinished unit test * MISC-110 Resolved Jenkins errors * MISC-110 Added apiSuccess assertion * MISC-110 Added changes from UP-3 * MISC-113 Added UI for frontend and set defaults * MISC-113 Bug fixes and improvements * MISC-113 Added date fields for start date on online contribution form * MISC-113 Added fields in payment processor table * MISC-113 Added processing for start date * MISC-110 Added changes to set contribution receive date for future payments * MISC-110 Typo error fixes * MISC-110 Added future start date to payment processor MISC-113 Added JS for adjust recurring start date MISC-110 Added future start date values on install MISC-113 Added script on install and upgrade MISC-110 Added form rule for pledge start date MISC-110 Removed explicit create of recur record -- minor change -- minor change -- minor change MISC-113 Added unit test MISC-113 Removed old webtest MISC-113 Resolved jenkins errors MISC-110 Style changes MISC-113 Allowed NULL values for future start date MISC-110 Removed future_start_date field from payment processor MISC-110 Removed future_start_date field from data * MISC-113 Changed serialize to json_encode MISC-113 Jenkins style fixes * MISC-113 Bug fixes for start date * MISC-113 Added unit test for contribution page submit with pledge with future start date MISC-110 Bug fix * MISC-113 Added id = 0 instead of pay_later text * MISC-110 Refactored assignment of contributionRecurID Conflicts: CRM/Contribute/BAO/Contribution/Utils.php * MISC-113 Handled issue with membership recur payments * MISC-110 Added upgrade script to 4.7.10
1 parent 29ef094 commit dccd9f4

File tree

17 files changed

+559
-24
lines changed

17 files changed

+559
-24
lines changed

CRM/Contribute/BAO/Contribution/Utils.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,6 @@ public static function processConfirm(
120120
$paymentParams['contributionTypeID'] = $contributionTypeId;
121121
$paymentParams['item_name'] = $form->_params['description'];
122122

123-
if ($contribution && $form->_values['is_recur'] && $contribution->contribution_recur_id
124-
) {
125-
$form->_params['contributionRecurID'] = $contribution->contribution_recur_id;
126-
}
127-
128123
$paymentParams['qfKey'] = $form->controller->_key;
129124
if ($component == 'membership') {
130125
return array('contribution' => $contribution);

CRM/Contribute/Form/Contribution/Confirm.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,11 @@ public static function processFormContribution(
932932
$pledgeParams['frequency_day'] = 1;
933933
}
934934
$pledgeParams['create_date'] = $pledgeParams['start_date'] = $pledgeParams['scheduled_date'] = date("Ymd");
935+
$pledgeBlock = CRM_Pledge_BAO_PledgeBlock::getPledgeBlock($contribution->contribution_page_id);
936+
if (CRM_Utils_Array::value('start_date', $params) || !CRM_Utils_Array::value('is_pledge_start_date_visible', $pledgeBlock)) {
937+
$pledgeStartDate = CRM_Utils_Array::value('start_date', $params, NULL);
938+
$pledgeParams['start_date'] = $pledgeParams['scheduled_date'] = CRM_Pledge_BAO_Pledge::getPledgeStartDate($pledgeStartDate, $pledgeBlock);
939+
}
935940
$pledgeParams['status_id'] = $contribution->contribution_status_id;
936941
$pledgeParams['max_reminders'] = $form->_values['max_reminders'];
937942
$pledgeParams['initial_reminder_day'] = $form->_values['initial_reminder_day'];
@@ -1104,6 +1109,10 @@ public static function processRecurringContribution(&$form, &$params, $contactID
11041109
}
11051110
CRM_Utils_System::redirect(CRM_Utils_System::url($urlString, $urlParams));
11061111
}
1112+
// Only set contribution recur ID for contributions since offline membership recur payments are handled somewhere else.
1113+
if (!is_a($form, "CRM_Member_Form_Membership")) {
1114+
$form->_params['contributionRecurID'] = $recurring->id;
1115+
}
11071116

11081117
return $recurring->id;
11091118
}
@@ -1846,6 +1855,15 @@ public static function submit($params) {
18461855
// hack these in for test support.
18471856
$form->_fields['billing_first_name'] = 1;
18481857
$form->_fields['billing_last_name'] = 1;
1858+
// CRM-18854 - Set form values to allow pledge to be created for api test.
1859+
if (CRM_Utils_Array::value('pledge_block_id', $params)) {
1860+
$form->_values['pledge_block_id'] = $params['pledge_block_id'];
1861+
$pledgeBlock = CRM_Pledge_BAO_PledgeBlock::getPledgeBlock($params['id']);
1862+
$form->_values['max_reminders'] = $pledgeBlock['max_reminders'];
1863+
$form->_values['initial_reminder_day'] = $pledgeBlock['initial_reminder_day'];
1864+
$form->_values['additional_reminder_day'] = $pledgeBlock['additional_reminder_day'];
1865+
$form->_values['is_email_receipt'] = FALSE;
1866+
}
18491867
$priceSetID = $form->_params['priceSetId'] = $paramsProcessedForForm['price_set_id'];
18501868
$priceFields = CRM_Price_BAO_PriceSet::getSetDetail($priceSetID);
18511869
$priceSetFields = reset($priceFields);
@@ -1929,6 +1947,17 @@ protected function processFormSubmission($contactID) {
19291947
// fix currency ID
19301948
$this->_params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency;
19311949

1950+
// CRM-18854
1951+
if (CRM_Utils_Array::value('adjust_recur_start_date', $this->_values)) {
1952+
$pledgeBlock = CRM_Pledge_BAO_PledgeBlock::getPledgeBlock($this->_id);
1953+
if (CRM_Utils_Array::value('start_date', $this->_params) || !CRM_Utils_Array::value('is_pledge_start_date_visible', $pledgeBlock)) {
1954+
$pledgeStartDate = CRM_Utils_Array::value('start_date', $this->_params, NULL);
1955+
$this->_params['receive_date'] = CRM_Pledge_BAO_Pledge::getPledgeStartDate($pledgeStartDate, $pledgeBlock);
1956+
$recurParams = CRM_Pledge_BAO_Pledge::buildRecurParams($this->_params);
1957+
$this->_params = array_merge($this->_params, $recurParams);
1958+
}
1959+
}
1960+
19321961
//carry payment processor id.
19331962
if (CRM_Utils_Array::value('id', $this->_paymentProcessor)) {
19341963
$this->_params['payment_processor_id'] = $this->_paymentProcessor['id'];
@@ -2315,6 +2344,7 @@ protected function completeTransaction($result, $contributionID) {
23152344
'payment_processor_id' => $this->_paymentProcessor['id'],
23162345
'is_transactional' => FALSE,
23172346
'fee_amount' => CRM_Utils_Array::value('fee_amount', $result),
2347+
'receive_date' => CRM_Utils_Array::value('receive_date', $result),
23182348
)
23192349
);
23202350
}

CRM/Contribute/Form/ContributionPage.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,26 @@ public function setDefaultValues() {
293293
'max_reminders',
294294
'initial_reminder_day',
295295
'additional_reminder_day',
296+
'pledge_start_date',
297+
'is_pledge_start_date_visible',
298+
'is_pledge_start_date_editable',
296299
);
297300
foreach ($pledgeBlock as $key) {
298301
$defaults[$key] = CRM_Utils_Array::value($key, $pledgeBlockDefaults);
302+
if ($key == 'pledge_start_date' && CRM_Utils_Array::value($key, $pledgeBlockDefaults)) {
303+
$defaultPledgeDate = (array) json_decode($pledgeBlockDefaults['pledge_start_date']);
304+
$pledgeDateFields = array(
305+
'pledge_calendar_date' => 'calendar_date',
306+
'pledge_calendar_month' => 'calendar_month',
307+
);
308+
$defaults['pledge_default_toggle'] = key($defaultPledgeDate);
309+
foreach ($pledgeDateFields as $key => $value) {
310+
if (array_key_exists($value, $defaultPledgeDate)) {
311+
$defaults[$key] = reset($defaultPledgeDate);
312+
$this->assign($key, reset($defaultPledgeDate));
313+
}
314+
}
315+
}
299316
}
300317
if (!empty($pledgeBlockDefaults['pledge_frequency_unit'])) {
301318
$defaults['pledge_frequency_unit'] = array_fill_keys(explode(CRM_Core_DAO::VALUE_SEPARATOR,

CRM/Contribute/Form/ContributionPage/Amount.php

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,28 @@ public function buildQuickForm() {
8787

8888
$this->addElement('checkbox', 'is_monetary', ts('Execute real-time monetary transactions'));
8989

90-
$paymentProcessor = CRM_Core_PseudoConstant::paymentProcessor();
91-
$recurringPaymentProcessor = array();
92-
93-
if (!empty($paymentProcessor)) {
94-
$paymentProcessorIds = implode(',', array_keys($paymentProcessor));
95-
$query = "
96-
SELECT id
97-
FROM civicrm_payment_processor
98-
WHERE id IN ({$paymentProcessorIds})
99-
AND is_recur = 1";
100-
$dao = CRM_Core_DAO::executeQuery($query);
101-
while ($dao->fetch()) {
102-
$recurringPaymentProcessor[] = $dao->id;
90+
$paymentProcessors = CRM_Financial_BAO_PaymentProcessor::getAllPaymentProcessors('live');
91+
$recurringPaymentProcessor = $futurePaymentProcessor = $paymentProcessor = array();
92+
93+
if (!empty($paymentProcessors)) {
94+
foreach ($paymentProcessors as $id => $processor) {
95+
if ($id != 0) {
96+
$paymentProcessor[$id] = $processor['name'];
97+
}
98+
if (CRM_Utils_Array::value('is_recur', $processor)) {
99+
$recurringPaymentProcessor[] = $id;
100+
}
101+
if (CRM_Utils_Array::value('object', $processor) && $processor['object']->supports('FutureRecurStartDate')) {
102+
$futurePaymentProcessor[] = $id;
103+
}
103104
}
104105
}
105-
$this->assign('recurringPaymentProcessor', $recurringPaymentProcessor);
106+
if (count($recurringPaymentProcessor)) {
107+
$this->assign('recurringPaymentProcessor', $recurringPaymentProcessor);
108+
}
109+
if (count($futurePaymentProcessor)) {
110+
$this->assign('futurePaymentProcessor', $futurePaymentProcessor);
111+
}
106112
if (count($paymentProcessor)) {
107113
$this->assign('paymentProcessor', $paymentProcessor);
108114
}
@@ -168,6 +174,23 @@ public function buildQuickForm() {
168174
$this->addElement('text', 'initial_reminder_day', ts('Send payment reminder'), array('size' => 3));
169175
$this->addElement('text', 'max_reminders', ts('Send up to'), array('size' => 3));
170176
$this->addElement('text', 'additional_reminder_day', ts('Send additional reminders'), array('size' => 3));
177+
if (!empty($futurePaymentProcessor)) {
178+
// CRM-18854
179+
$this->addElement('checkbox', 'adjust_recur_start_date', ts('Adjust Recurring Start Date'), NULL,
180+
array('onclick' => "showHideByValue('adjust_recur_start_date',true,'recurDefaults','table-row','radio',false);")
181+
);
182+
$this->addDate('pledge_calendar_date', ts('Specific Calendar Date'));
183+
$month = CRM_Utils_Date::getCalendarDayOfMonth();
184+
$this->add('select', 'pledge_calendar_month', ts('Specific day of Month'), $month);
185+
$pledgeDefaults = array(
186+
'contribution_date' => ts('Day of Contribution'),
187+
'calendar_date' => ts('Specific Calendar Date'),
188+
'calendar_month' => ts('Specific day of Month'),
189+
);
190+
$this->addRadio('pledge_default_toggle', ts('Recurring Contribution Start Date Default'), $pledgeDefaults, array('allowClear' => FALSE), '<br/><br/>');
191+
$this->addElement('checkbox', 'is_pledge_start_date_visible', ts('Show Recurring Donation Start Date?'), NULL);
192+
$this->addElement('checkbox', 'is_pledge_start_date_editable', ts('Allow Edits to Recurring Donation Start date?'), NULL);
193+
}
171194
}
172195

173196
//add currency element.
@@ -320,6 +343,13 @@ public static function formRule($fields, $files, $self) {
320343
}
321344
}
322345

346+
// CRM-18854 Check if recurring start date is in the future.
347+
if (CRM_Utils_Array::value('pledge_calendar_date', $fields)) {
348+
if (date('Ymd') > date('Ymd', strtotime($fields['pledge_calendar_date']))) {
349+
$errors['pledge_calendar_date'] = ts('The recurring start date cannot be prior to the current date.');
350+
}
351+
}
352+
323353
//check for the amount label (mandatory)
324354
if (!empty($fields['amount_block_is_active']) && empty($fields['amount_label'])) {
325355
$errors['amount_label'] = ts('Please enter the contribution amount label.');
@@ -481,6 +511,38 @@ public function postProcess() {
481511
$params['is_recur_installments'] = CRM_Utils_Array::value('is_recur_installments', $params, FALSE);
482512
}
483513

514+
if (CRM_Utils_Array::value('adjust_recur_start_date', $params)) {
515+
$fieldValue = '';
516+
$pledgeDateFields = array(
517+
'calendar_date' => 'pledge_calendar_date',
518+
'calendar_month' => 'pledge_calendar_month',
519+
);
520+
if ($params['pledge_default_toggle'] == 'contribution_date') {
521+
$fieldValue = json_encode(array('contribution_date' => date('Ymd')));
522+
}
523+
else {
524+
foreach ($pledgeDateFields as $key => $pledgeDateField) {
525+
if (CRM_Utils_Array::value($pledgeDateField, $params) && $params['pledge_default_toggle'] == $key) {
526+
$fieldValue = json_encode(array($key => $params[$pledgeDateField]));
527+
break;
528+
}
529+
}
530+
}
531+
$params['pledge_start_date'] = $fieldValue;
532+
}
533+
else {
534+
$params['pledge_start_date'] = '';
535+
$params['adjust_recur_start_date'] = 0;
536+
$params['is_pledge_start_date_visible'] = 0;
537+
$params['is_pledge_start_date_editable'] = 0;
538+
}
539+
if (!CRM_Utils_Array::value('is_pledge_start_date_visible', $params)) {
540+
$params['is_pledge_start_date_visible'] = 0;
541+
}
542+
if (!CRM_Utils_Array::value('is_pledge_start_date_editable', $params)) {
543+
$params['is_pledge_start_date_editable'] = 0;
544+
}
545+
484546
if (array_key_exists('payment_processor', $params) &&
485547
!CRM_Utils_System::isNull($params['payment_processor'])
486548
) {
@@ -712,13 +774,19 @@ public function postProcess() {
712774
'max_reminders',
713775
'initial_reminder_day',
714776
'additional_reminder_day',
777+
'pledge_start_date',
778+
'is_pledge_start_date_visible',
779+
'is_pledge_start_date_editable',
715780
);
716781
foreach ($pledgeBlock as $key) {
717782
$pledgeBlockParams[$key] = CRM_Utils_Array::value($key, $params);
718783
}
719784
$pledgeBlockParams['is_pledge_interval'] = CRM_Utils_Array::value('is_pledge_interval',
720785
$params, FALSE
721786
);
787+
$pledgeBlockParams['pledge_start_date'] = CRM_Utils_Array::value('pledge_start_date',
788+
$params, FALSE
789+
);
722790
// create pledge block.
723791
CRM_Pledge_BAO_PledgeBlock::create($pledgeBlockParams);
724792
}

CRM/Pledge/BAO/Pledge.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,4 +1202,90 @@ protected static function getTransactionalStatus() {
12021202
return array_diff(array_flip($paymentStatus), self::getNonTransactionalStatus());
12031203
}
12041204

1205+
/**
1206+
* Create array for recur record for pledge.
1207+
* @return array
1208+
* params for recur record
1209+
*/
1210+
public static function buildRecurParams($params) {
1211+
$recurParams = array(
1212+
'is_recur' => TRUE,
1213+
'auto_renew' => TRUE,
1214+
'frequency_unit' => $params['pledge_frequency_unit'],
1215+
'frequency_interval' => $params['pledge_frequency_interval'],
1216+
'installments' => $params['pledge_installments'],
1217+
'start_date' => $params['receive_date'],
1218+
);
1219+
return $recurParams;
1220+
}
1221+
1222+
/**
1223+
* Get pledge start date.
1224+
*
1225+
* @return string
1226+
* start date
1227+
*/
1228+
public static function getPledgeStartDate($date, $pledgeBlock) {
1229+
$startDate = (array) json_decode($pledgeBlock['pledge_start_date']);
1230+
list($field, $value) = each($startDate);
1231+
if (!CRM_Utils_Array::value('is_pledge_start_date_visible', $pledgeBlock)) {
1232+
return date('Ymd', strtotime($value));
1233+
}
1234+
if (!CRM_Utils_Array::value('is_pledge_start_date_editable', $pledgeBlock)) {
1235+
return $date;
1236+
}
1237+
switch ($field) {
1238+
case 'contribution_date':
1239+
$date = date('Ymd');
1240+
break;
1241+
1242+
case 'calendar_date':
1243+
$date = date('Ymd', strtotime($date));
1244+
break;
1245+
1246+
case 'calendar_month':
1247+
$date = self::getPaymentDate($date);
1248+
$date = date('Ymd', strtotime($date));
1249+
break;
1250+
1251+
default:
1252+
break;
1253+
1254+
}
1255+
return $date;
1256+
}
1257+
1258+
/**
1259+
* Get first payment date for pledge.
1260+
*
1261+
*/
1262+
public static function getPaymentDate($day) {
1263+
if ($day == 31) {
1264+
// Find out if current month has 31 days, if not, set it to 30 (last day).
1265+
$t = date('t');
1266+
if ($t != $day) {
1267+
$day = $t;
1268+
}
1269+
}
1270+
$current = date('d');
1271+
switch (TRUE) {
1272+
case ($day == $current):
1273+
$date = date('m/d/Y');
1274+
break;
1275+
1276+
case ($day > $current):
1277+
$date = date('m/d/Y', mktime(0, 0, 0, date('m'), $day, date('Y')));
1278+
break;
1279+
1280+
case ($day < $current):
1281+
$date = date('m/d/Y', mktime(0, 0, 0, date('m', strtotime("+1 month")), $day, date('Y')));
1282+
break;
1283+
1284+
default:
1285+
break;
1286+
1287+
}
1288+
return $date;
1289+
}
1290+
12051291
}

CRM/Pledge/BAO/PledgeBlock.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ public static function buildPledgeBlock($form) {
202202
'scheduled_date',
203203
'scheduled_amount',
204204
'currency',
205+
'pledge_start_date',
205206
);
206207
CRM_Core_DAO::commonRetrieveAll('CRM_Pledge_DAO_PledgePayment', 'pledge_id',
207208
$form->_values['pledge_id'], $allPayments, $returnProperties
@@ -300,6 +301,50 @@ public static function buildPledgeBlock($form) {
300301
}
301302
}
302303
$form->addElement('select', 'pledge_frequency_unit', NULL, $freqUnits);
304+
// CRM-18854
305+
if (CRM_Utils_Array::value('is_pledge_start_date_visible', $pledgeBlock)) {
306+
if (CRM_Utils_Array::value('pledge_start_date', $pledgeBlock)) {
307+
$defaults = array();
308+
$date = (array) json_decode($pledgeBlock['pledge_start_date']);
309+
list($field, $value) = each($date);
310+
switch ($field) {
311+
case 'contribution_date':
312+
$form->addDate('start_date', ts('First installment payment'));
313+
$paymentDate = $value = date('d/m/Y');
314+
list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults($value);
315+
$form->assign('is_date', TRUE);
316+
break;
317+
318+
case 'calendar_date':
319+
$form->addDate('start_date', ts('First installment payment'));
320+
list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults($value);
321+
$form->assign('is_date', TRUE);
322+
$paymentDate = $value;
323+
break;
324+
325+
case 'calendar_month':
326+
$month = CRM_Utils_Date::getCalendarDayOfMonth();
327+
$form->add('select', 'start_date', ts('Day of month installments paid'), $month);
328+
$paymentDate = CRM_Pledge_BAO_Pledge::getPaymentDate($value);
329+
list($defaults['start_date'], $defaults['start_date_time']) = CRM_Utils_Date::setDateDefaults($paymentDate);
330+
break;
331+
332+
default:
333+
break;
334+
335+
}
336+
$form->setDefaults($defaults);
337+
$form->assign('start_date_display', $paymentDate);
338+
$form->assign('start_date_editable', FALSE);
339+
if (CRM_Utils_Array::value('is_pledge_start_date_editable', $pledgeBlock)) {
340+
$form->assign('start_date_editable', TRUE);
341+
if ($field == 'calendar_month') {
342+
$form->assign('is_date', FALSE);
343+
$form->setDefaults(array('start_date' => $value));
344+
}
345+
}
346+
}
347+
}
303348
}
304349
}
305350

0 commit comments

Comments
 (0)