Merge pull request #13967 from eileenmcnaughton/activity_token
[civicrm-core.git] / CRM / Contribute / Form / UpdateSubscription.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
6b83d5bd 6 | Copyright CiviCRM LLC (c) 2004-2019 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
6a488035 29 * @package CRM
6b83d5bd 30 * @copyright CiviCRM LLC (c) 2004-2019
6a488035
TO
31 */
32
33/**
c0f62075 34 * This class generates form components generic to recurring contributions.
6a488035
TO
35 *
36 * It delegates the work to lower level subclasses and integrates the changes
37 * back in. It also uses a lot of functionality with the CRM API's, so any change
38 * made here could potentially affect the API etc. Be careful, be aware, use unit tests.
6a488035 39 */
ca809bb6 40class CRM_Contribute_Form_UpdateSubscription extends CRM_Contribute_Form_ContributionRecur {
6a488035 41
6a488035
TO
42 protected $_subscriptionDetails = NULL;
43
44 protected $_selfService = FALSE;
45
46 public $_paymentProcessor = NULL;
47
48 public $_paymentProcessorObj = NULL;
49
0c6c47a5 50 /**
51 * Fields that affect the schedule and are defined as editable by the processor.
52 *
53 * @var array
54 */
55 protected $editableScheduleFields = array();
56
6a488035 57 /**
fe482240 58 * The id of the contact associated with this recurring contribution.
6a488035
TO
59 *
60 * @var int
6a488035 61 */
430ae6dd
TO
62 public $_contactID;
63
c0f62075 64 /**
65 * Pre-processing for the form.
66 *
67 * @throws \Exception
68 */
00be9182 69 public function preProcess() {
6a488035 70
1f17c8ef 71 parent::preProcess();
a0d322b1
KW
72 $this->setAction(CRM_Core_Action::UPDATE);
73
0c6c47a5 74 if ($this->contributionRecurID) {
b3e340d9 75 try {
cd3ad80e 76 $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorForRecurringContribution($this->contributionRecurID);
b3e340d9 77 }
78 catch (CRM_Core_Exception $e) {
0c6c47a5 79 CRM_Core_Error::statusBounce(ts('There is no valid processor for this subscription so it cannot be edited.'));
80 }
85b68a11
CR
81 catch (CiviCRM_API3_Exception $e) {
82 CRM_Core_Error::statusBounce(ts('There is no valid processor for this subscription so it cannot be edited.'));
83 }
0c6c47a5 84 $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->contributionRecurID);
6a488035
TO
85 }
86
6a488035
TO
87 if ($this->_coid) {
88 $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'info');
cd3ad80e 89 // @todo test & replace with $this->_paymentProcessorObj = Civi\Payment\System::singleton()->getById($this->_paymentProcessor['id']);
6a488035
TO
90 $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'obj');
91 $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->_coid, 'contribution');
0c6c47a5 92 $this->contributionRecurID = $this->_subscriptionDetails->recur_id;
6a488035 93 }
0c6c47a5 94 elseif ($this->contributionRecurID) {
95 $this->_coid = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->contributionRecurID, 'id', 'contribution_recur_id');
8de2c073 96 }
6a488035 97
1273d77c 98 if (!$this->contributionRecurID || !$this->_subscriptionDetails) {
7bcd892a 99 CRM_Core_Error::statusBounce(ts('Required information missing.'));
6a488035
TO
100 }
101
102 if ($this->_subscriptionDetails->membership_id && $this->_subscriptionDetails->auto_renew) {
14b61354
MW
103 // Add Membership details to form
104 $membership = civicrm_api3('Membership', 'get', array(
105 'contribution_recur_id' => $this->contributionRecurID,
106 ));
107 if (!empty($membership['count'])) {
108 $membershipDetails = reset($membership['values']);
109 $values['membership_id'] = $membershipDetails['id'];
110 $values['membership_name'] = $membershipDetails['membership_name'];
111 }
112 $this->assign('recurMembership', $values);
113 $this->assign('contactId', $this->_subscriptionDetails->contact_id);
6a488035
TO
114 }
115
116 if (!CRM_Core_Permission::check('edit contributions')) {
a21270c0 117 if ($this->_subscriptionDetails->contact_id != $this->getContactID()) {
7bcd892a 118 CRM_Core_Error::statusBounce(ts('You do not have permission to update subscription.'));
6a488035
TO
119 }
120 $this->_selfService = TRUE;
121 }
122 $this->assign('self_service', $this->_selfService);
123
0c6c47a5 124 $this->editableScheduleFields = $this->_paymentProcessorObj->getEditableRecurringScheduleFields();
125
126 $changeHelpText = $this->_paymentProcessorObj->getRecurringScheduleUpdateHelpText();
127 if (!in_array('amount', $this->editableScheduleFields)) {
128 // Not sure if this is good behaviour - maintaining this existing behaviour for now.
129 CRM_Core_Session::setStatus($changeHelpText, ts('Warning'), 'alert');
130 }
131 else {
132 $this->assign('changeHelpText', $changeHelpText);
133 }
134 $alreadyHardCodedFields = array('amount', 'installments');
135 foreach ($this->editableScheduleFields as $editableScheduleField) {
136 if (!in_array($editableScheduleField, $alreadyHardCodedFields)) {
9139737b 137 $this->addField($editableScheduleField, array('entity' => 'ContributionRecur'), FALSE, FALSE);
0c6c47a5 138 }
6a488035
TO
139 }
140
0699333e
MW
141 // when custom data is included in this page
142 if (!empty($_POST['hidden_custom'])) {
143 CRM_Custom_Form_CustomData::preProcess($this, NULL, NULL, 1, 'ContributionRecur', $this->contributionRecurID);
144 CRM_Custom_Form_CustomData::buildQuickForm($this);
145 CRM_Custom_Form_CustomData::setDefaultValues($this);
146 }
147
0c6c47a5 148 $this->assign('editableScheduleFields', array_diff($this->editableScheduleFields, $alreadyHardCodedFields));
6a488035
TO
149
150 if ($this->_subscriptionDetails->contact_id) {
151 list($this->_donorDisplayName, $this->_donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($this->_subscriptionDetails->contact_id);
152 }
153
154 CRM_Utils_System::setTitle(ts('Update Recurring Contribution'));
155
0c6c47a5 156 // Handle context redirection.
6a488035
TO
157 CRM_Contribute_BAO_ContributionRecur::setSubscriptionContext();
158 }
159
160 /**
347e061b 161 * Set default values for the form.
6a488035 162 *
347e061b 163 * Note that in edit/view mode the default values are retrieved from the database.
6a488035 164 */
00be9182 165 public function setDefaultValues() {
6a488035
TO
166 $this->_defaults = array();
167 $this->_defaults['amount'] = $this->_subscriptionDetails->amount;
168 $this->_defaults['installments'] = $this->_subscriptionDetails->installments;
7083dc2a 169 $this->_defaults['campaign_id'] = $this->_subscriptionDetails->campaign_id;
467fe956 170 $this->_defaults['financial_type_id'] = $this->_subscriptionDetails->financial_type_id;
6a488035 171 $this->_defaults['is_notify'] = 1;
0c6c47a5 172 foreach ($this->editableScheduleFields as $field) {
0699333e 173 $this->_defaults[$field] = isset($this->_subscriptionDetails->$field) ? $this->_subscriptionDetails->$field : NULL;
0c6c47a5 174 }
6a488035
TO
175
176 return $this->_defaults;
177 }
178
179 /**
fe482240 180 * Actually build the components of the form.
6a488035
TO
181 */
182 public function buildQuickForm() {
8de2c073 183 // CRM-16398: If current recurring contribution got > 1 lineitems then make amount field readonly
184 $amtAttr = array('size' => 20);
185 $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($this->_coid);
186 if (count($lineItems) > 1) {
187 $amtAttr += array('readonly' => TRUE);
188 }
189 $this->addMoney('amount', ts('Recurring Contribution Amount'), TRUE, $amtAttr,
190 TRUE, 'currency', $this->_subscriptionDetails->currency, TRUE
6a488035
TO
191 );
192
467fe956 193 $this->add('text', 'installments', ts('Number of Installments'), array('size' => 20), FALSE);
6a488035
TO
194
195 if ($this->_donorEmail) {
196 $this->add('checkbox', 'is_notify', ts('Notify Contributor?'));
197 }
198
7083dc2a 199 if (CRM_Core_Permission::check('edit contributions')) {
edb227cd 200 CRM_Campaign_BAO_Campaign::addCampaign($this, $this->_subscriptionDetails->campaign_id);
467fe956 201 }
202
0c6c47a5 203 if (CRM_Contribute_BAO_ContributionRecur::supportsFinancialTypeChange($this->contributionRecurID)) {
0d93f90b 204 $this->addEntityRef('financial_type_id', ts('Financial Type'), array('entity' => 'FinancialType'), !$this->_selfService);
7083dc2a 205 }
206
0699333e
MW
207 // Add custom data
208 $this->assign('customDataType', 'ContributionRecur');
209 $this->assign('entityID', $this->contributionRecurID);
210
6a488035 211 $type = 'next';
481a74f4 212 if ($this->_selfService) {
6a488035
TO
213 $type = 'submit';
214 }
215
216 // define the buttons
217 $this->addButtons(array(
218 array(
219 'type' => $type,
220 'name' => ts('Save'),
221 'isDefault' => TRUE,
222 ),
223 array(
224 'type' => 'cancel',
225 'name' => ts('Cancel'),
226 ),
227 )
228 );
229 }
230
231 /**
347e061b 232 * Called after the user submits the form.
6a488035
TO
233 */
234 public function postProcess() {
235 // store the submitted values in an array
236 $params = $this->exportValues();
237
238 if ($this->_selfService && $this->_donorEmail) {
239 // for self service force notify
240 $params['is_notify'] = 1;
241 }
242
243 // if this is an update of an existing recurring contribution, pass the ID
244 $params['id'] = $this->_subscriptionDetails->recur_id;
245 $message = '';
246
247 $params['subscriptionId'] = $this->_subscriptionDetails->subscription_id;
4eeb9a5b 248 $updateSubscription = TRUE;
b690491e 249 if ($this->_paymentProcessorObj->supports('changeSubscriptionAmount')) {
353ffa53 250 $updateSubscription = $this->_paymentProcessorObj->changeSubscriptionAmount($message, $params);
6a488035
TO
251 }
252 if (is_a($updateSubscription, 'CRM_Core_Error')) {
353ffa53
TO
253 CRM_Core_Error::displaySessionError($updateSubscription);
254 $status = ts('Could not update the Recurring contribution details');
255 $msgTitle = ts('Update Error');
256 $msgType = 'error';
6a488035
TO
257 }
258 elseif ($updateSubscription) {
0699333e
MW
259 // Handle custom data
260 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, $this->contributionRecurID, 'ContributionRecur');
353ffa53 261 // save the changes
0699333e 262 CRM_Contribute_BAO_ContributionRecur::add($params);
353ffa53
TO
263 $status = ts('Recurring contribution has been updated to: %1, every %2 %3(s) for %4 installments.',
264 array(
265 1 => CRM_Utils_Money::format($params['amount'], $this->_subscriptionDetails->currency),
266 2 => $this->_subscriptionDetails->frequency_interval,
267 3 => $this->_subscriptionDetails->frequency_unit,
268 4 => $params['installments'],
269 )
270 );
271
272 $msgTitle = ts('Update Success');
273 $msgType = 'success';
c6c91efc 274 $msg = ts('Recurring Contribution Updated');
353ffa53
TO
275 $contactID = $this->_subscriptionDetails->contact_id;
276
277 if ($this->_subscriptionDetails->amount != $params['amount']) {
278 $message .= "<br /> " . ts("Recurring contribution amount has been updated from %1 to %2 for this subscription.",
279 array(
280 1 => CRM_Utils_Money::format($this->_subscriptionDetails->amount, $this->_subscriptionDetails->currency),
281 2 => CRM_Utils_Money::format($params['amount'], $this->_subscriptionDetails->currency),
282 )) . ' ';
c6c91efc 283 if ($this->_subscriptionDetails->amount < $params['amount']) {
284 $msg = ts('Recurring Contribution Updated - increased installment amount');
285 }
286 else {
287 $msg = ts('Recurring Contribution Updated - decreased installment amount');
288 }
353ffa53 289 }
6a488035 290
353ffa53
TO
291 if ($this->_subscriptionDetails->installments != $params['installments']) {
292 $message .= "<br /> " . ts("Recurring contribution installments have been updated from %1 to %2 for this subscription.", array(
293 1 => $this->_subscriptionDetails->installments,
317fceb4 294 2 => $params['installments'],
353ffa53
TO
295 )) . ' ';
296 }
6a488035 297
353ffa53
TO
298 $activityParams = array(
299 'source_contact_id' => $contactID,
12853dec 300 'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Update Recurring Contribution'),
c6c91efc 301 'subject' => $msg,
353ffa53
TO
302 'details' => $message,
303 'activity_date_time' => date('YmdHis'),
12853dec 304 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed'),
353ffa53 305 );
12853dec 306
353ffa53
TO
307 $session = CRM_Core_Session::singleton();
308 $cid = $session->get('userID');
6a488035 309
353ffa53
TO
310 if ($cid) {
311 $activityParams['target_contact_id'][] = $activityParams['source_contact_id'];
312 $activityParams['source_contact_id'] = $cid;
313 }
314 CRM_Activity_BAO_Activity::create($activityParams);
315
316 if (!empty($params['is_notify'])) {
317 // send notification
318 if ($this->_subscriptionDetails->contribution_page_id) {
319 CRM_Core_DAO::commonRetrieveAll('CRM_Contribute_DAO_ContributionPage', 'id',
320 $this->_subscriptionDetails->contribution_page_id, $value, array(
321 'title',
322 'receipt_from_name',
323 'receipt_from_email',
324 )
6a488035 325 );
353ffa53
TO
326 $receiptFrom = '"' . CRM_Utils_Array::value('receipt_from_name', $value[$this->_subscriptionDetails->contribution_page_id]) . '" <' . $value[$this->_subscriptionDetails->contribution_page_id]['receipt_from_email'] . '>';
327 }
328 else {
329 $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
330 $receiptFrom = "$domainValues[0] <$domainValues[1]>";
6a488035 331 }
353ffa53
TO
332
333 list($donorDisplayName, $donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($contactID);
334
335 $tplParams = array(
336 'recur_frequency_interval' => $this->_subscriptionDetails->frequency_interval,
337 'recur_frequency_unit' => $this->_subscriptionDetails->frequency_unit,
338 'amount' => CRM_Utils_Money::format($params['amount']),
339 'installments' => $params['installments'],
340 );
341
342 $tplParams['contact'] = array('display_name' => $donorDisplayName);
343 $tplParams['receipt_from_email'] = $receiptFrom;
344
345 $sendTemplateParams = array(
346 'groupName' => 'msg_tpl_workflow_contribution',
347 'valueName' => 'contribution_recurring_edit',
348 'contactId' => $contactID,
349 'tplParams' => $tplParams,
350 'isTest' => $this->_subscriptionDetails->is_test,
351 'PDFFilename' => 'receipt.pdf',
352 'from' => $receiptFrom,
353 'toName' => $donorDisplayName,
354 'toEmail' => $donorEmail,
355 );
356 list($sent) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
6a488035 357 }
353ffa53 358 }
6a488035
TO
359
360 $session = CRM_Core_Session::singleton();
353ffa53 361 $userID = $session->get('userID');
481a74f4 362 if ($userID && $status) {
6a488035 363 CRM_Core_Session::setStatus($status, $msgTitle, $msgType);
0db6c3e1 364 }
4c9b6178 365 elseif (!$userID) {
317fceb4 366 if ($status) {
6a488035 367 CRM_Utils_System::setUFMessage($status);
317fceb4 368 }
6a488035
TO
369 // keep result as 1, since we not displaying anything on the redirected page anyway
370 return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/subscriptionstatus',
353ffa53 371 "reset=1&task=update&result=1"));
6a488035
TO
372 }
373 }
96025800 374
6a488035 375}