[REF] calculate 'amount' on ContributionPage in a shared way in one scenario
[civicrm-core.git] / CRM / Contribute / Form / UpdateSubscription.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
f299f7db 6 | Copyright CiviCRM LLC (c) 2004-2020 |
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
f299f7db 30 * @copyright CiviCRM LLC (c) 2004-2020
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
6a488035
TO
44 public $_paymentProcessor = NULL;
45
46 public $_paymentProcessorObj = NULL;
47
0c6c47a5 48 /**
49 * Fields that affect the schedule and are defined as editable by the processor.
50 *
51 * @var array
52 */
be2fb01f 53 protected $editableScheduleFields = [];
0c6c47a5 54
6a488035 55 /**
fe482240 56 * The id of the contact associated with this recurring contribution.
6a488035
TO
57 *
58 * @var int
6a488035 59 */
430ae6dd
TO
60 public $_contactID;
61
c0f62075 62 /**
63 * Pre-processing for the form.
64 *
65 * @throws \Exception
66 */
00be9182 67 public function preProcess() {
6a488035 68
1f17c8ef 69 parent::preProcess();
a0d322b1
KW
70 $this->setAction(CRM_Core_Action::UPDATE);
71
6a488035
TO
72 if ($this->_coid) {
73 $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'info');
cd3ad80e 74 // @todo test & replace with $this->_paymentProcessorObj = Civi\Payment\System::singleton()->getById($this->_paymentProcessor['id']);
6a488035 75 $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'obj');
0c6c47a5 76 $this->contributionRecurID = $this->_subscriptionDetails->recur_id;
6a488035 77 }
0c6c47a5 78 elseif ($this->contributionRecurID) {
79 $this->_coid = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->contributionRecurID, 'id', 'contribution_recur_id');
8de2c073 80 }
6a488035 81
1273d77c 82 if (!$this->contributionRecurID || !$this->_subscriptionDetails) {
7bcd892a 83 CRM_Core_Error::statusBounce(ts('Required information missing.'));
6a488035
TO
84 }
85
86 if ($this->_subscriptionDetails->membership_id && $this->_subscriptionDetails->auto_renew) {
14b61354 87 // Add Membership details to form
be2fb01f 88 $membership = civicrm_api3('Membership', 'get', [
14b61354 89 'contribution_recur_id' => $this->contributionRecurID,
be2fb01f 90 ]);
14b61354
MW
91 if (!empty($membership['count'])) {
92 $membershipDetails = reset($membership['values']);
93 $values['membership_id'] = $membershipDetails['id'];
94 $values['membership_name'] = $membershipDetails['membership_name'];
95 }
96 $this->assign('recurMembership', $values);
97 $this->assign('contactId', $this->_subscriptionDetails->contact_id);
6a488035
TO
98 }
99
e0e281fc 100 $this->assign('self_service', $this->isSelfService());
6a488035 101
0c6c47a5 102 $this->editableScheduleFields = $this->_paymentProcessorObj->getEditableRecurringScheduleFields();
103
104 $changeHelpText = $this->_paymentProcessorObj->getRecurringScheduleUpdateHelpText();
105 if (!in_array('amount', $this->editableScheduleFields)) {
106 // Not sure if this is good behaviour - maintaining this existing behaviour for now.
107 CRM_Core_Session::setStatus($changeHelpText, ts('Warning'), 'alert');
108 }
109 else {
110 $this->assign('changeHelpText', $changeHelpText);
111 }
be2fb01f 112 $alreadyHardCodedFields = ['amount', 'installments'];
0c6c47a5 113 foreach ($this->editableScheduleFields as $editableScheduleField) {
114 if (!in_array($editableScheduleField, $alreadyHardCodedFields)) {
be2fb01f 115 $this->addField($editableScheduleField, ['entity' => 'ContributionRecur'], FALSE, FALSE);
0c6c47a5 116 }
6a488035
TO
117 }
118
0699333e 119 // when custom data is included in this page
e0e281fc 120 if (!empty($_POST['hidden_custom']) && !$this->isSelfService()) {
0699333e
MW
121 CRM_Custom_Form_CustomData::preProcess($this, NULL, NULL, 1, 'ContributionRecur', $this->contributionRecurID);
122 CRM_Custom_Form_CustomData::buildQuickForm($this);
123 CRM_Custom_Form_CustomData::setDefaultValues($this);
124 }
125
0c6c47a5 126 $this->assign('editableScheduleFields', array_diff($this->editableScheduleFields, $alreadyHardCodedFields));
6a488035
TO
127
128 if ($this->_subscriptionDetails->contact_id) {
129 list($this->_donorDisplayName, $this->_donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($this->_subscriptionDetails->contact_id);
130 }
131
132 CRM_Utils_System::setTitle(ts('Update Recurring Contribution'));
133
0c6c47a5 134 // Handle context redirection.
6a488035
TO
135 CRM_Contribute_BAO_ContributionRecur::setSubscriptionContext();
136 }
137
138 /**
347e061b 139 * Set default values for the form.
6a488035 140 *
347e061b 141 * Note that in edit/view mode the default values are retrieved from the database.
6a488035 142 */
00be9182 143 public function setDefaultValues() {
be2fb01f 144 $this->_defaults = [];
6a488035
TO
145 $this->_defaults['amount'] = $this->_subscriptionDetails->amount;
146 $this->_defaults['installments'] = $this->_subscriptionDetails->installments;
7083dc2a 147 $this->_defaults['campaign_id'] = $this->_subscriptionDetails->campaign_id;
467fe956 148 $this->_defaults['financial_type_id'] = $this->_subscriptionDetails->financial_type_id;
6a488035 149 $this->_defaults['is_notify'] = 1;
0c6c47a5 150 foreach ($this->editableScheduleFields as $field) {
0699333e 151 $this->_defaults[$field] = isset($this->_subscriptionDetails->$field) ? $this->_subscriptionDetails->$field : NULL;
0c6c47a5 152 }
6a488035
TO
153
154 return $this->_defaults;
155 }
156
157 /**
fe482240 158 * Actually build the components of the form.
6a488035
TO
159 */
160 public function buildQuickForm() {
8de2c073 161 // CRM-16398: If current recurring contribution got > 1 lineitems then make amount field readonly
be2fb01f 162 $amtAttr = ['size' => 20];
8de2c073 163 $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($this->_coid);
164 if (count($lineItems) > 1) {
be2fb01f 165 $amtAttr += ['readonly' => TRUE];
8de2c073 166 }
167 $this->addMoney('amount', ts('Recurring Contribution Amount'), TRUE, $amtAttr,
168 TRUE, 'currency', $this->_subscriptionDetails->currency, TRUE
6a488035
TO
169 );
170
be2fb01f 171 $this->add('text', 'installments', ts('Number of Installments'), ['size' => 20], FALSE);
6a488035
TO
172
173 if ($this->_donorEmail) {
174 $this->add('checkbox', 'is_notify', ts('Notify Contributor?'));
175 }
176
7083dc2a 177 if (CRM_Core_Permission::check('edit contributions')) {
edb227cd 178 CRM_Campaign_BAO_Campaign::addCampaign($this, $this->_subscriptionDetails->campaign_id);
467fe956 179 }
180
0c6c47a5 181 if (CRM_Contribute_BAO_ContributionRecur::supportsFinancialTypeChange($this->contributionRecurID)) {
e0e281fc 182 $this->addEntityRef('financial_type_id', ts('Financial Type'), ['entity' => 'FinancialType'], !$this->isSelfService());
7083dc2a 183 }
184
0699333e
MW
185 // Add custom data
186 $this->assign('customDataType', 'ContributionRecur');
187 $this->assign('entityID', $this->contributionRecurID);
188
6a488035 189 $type = 'next';
e0e281fc 190 if ($this->isSelfService()) {
6a488035
TO
191 $type = 'submit';
192 }
193
194 // define the buttons
be2fb01f 195 $this->addButtons([
1330f57a
SL
196 [
197 'type' => $type,
198 'name' => ts('Save'),
199 'isDefault' => TRUE,
200 ],
201 [
202 'type' => 'cancel',
203 'name' => ts('Cancel'),
204 ],
205 ]);
6a488035
TO
206 }
207
208 /**
347e061b 209 * Called after the user submits the form.
6a488035
TO
210 */
211 public function postProcess() {
212 // store the submitted values in an array
213 $params = $this->exportValues();
214
e0e281fc 215 if ($this->isSelfService() && $this->_donorEmail) {
6a488035
TO
216 // for self service force notify
217 $params['is_notify'] = 1;
218 }
219
220 // if this is an update of an existing recurring contribution, pass the ID
221 $params['id'] = $this->_subscriptionDetails->recur_id;
222 $message = '';
223
224 $params['subscriptionId'] = $this->_subscriptionDetails->subscription_id;
4eeb9a5b 225 $updateSubscription = TRUE;
b690491e 226 if ($this->_paymentProcessorObj->supports('changeSubscriptionAmount')) {
353ffa53 227 $updateSubscription = $this->_paymentProcessorObj->changeSubscriptionAmount($message, $params);
6a488035
TO
228 }
229 if (is_a($updateSubscription, 'CRM_Core_Error')) {
353ffa53
TO
230 CRM_Core_Error::displaySessionError($updateSubscription);
231 $status = ts('Could not update the Recurring contribution details');
232 $msgTitle = ts('Update Error');
233 $msgType = 'error';
6a488035
TO
234 }
235 elseif ($updateSubscription) {
0699333e
MW
236 // Handle custom data
237 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params, $this->contributionRecurID, 'ContributionRecur');
353ffa53 238 // save the changes
0699333e 239 CRM_Contribute_BAO_ContributionRecur::add($params);
353ffa53 240 $status = ts('Recurring contribution has been updated to: %1, every %2 %3(s) for %4 installments.',
be2fb01f 241 [
353ffa53
TO
242 1 => CRM_Utils_Money::format($params['amount'], $this->_subscriptionDetails->currency),
243 2 => $this->_subscriptionDetails->frequency_interval,
244 3 => $this->_subscriptionDetails->frequency_unit,
245 4 => $params['installments'],
be2fb01f 246 ]
353ffa53
TO
247 );
248
249 $msgTitle = ts('Update Success');
250 $msgType = 'success';
c6c91efc 251 $msg = ts('Recurring Contribution Updated');
353ffa53
TO
252 $contactID = $this->_subscriptionDetails->contact_id;
253
254 if ($this->_subscriptionDetails->amount != $params['amount']) {
255 $message .= "<br /> " . ts("Recurring contribution amount has been updated from %1 to %2 for this subscription.",
be2fb01f 256 [
353ffa53
TO
257 1 => CRM_Utils_Money::format($this->_subscriptionDetails->amount, $this->_subscriptionDetails->currency),
258 2 => CRM_Utils_Money::format($params['amount'], $this->_subscriptionDetails->currency),
be2fb01f 259 ]) . ' ';
c6c91efc 260 if ($this->_subscriptionDetails->amount < $params['amount']) {
261 $msg = ts('Recurring Contribution Updated - increased installment amount');
262 }
263 else {
264 $msg = ts('Recurring Contribution Updated - decreased installment amount');
265 }
353ffa53 266 }
6a488035 267
353ffa53 268 if ($this->_subscriptionDetails->installments != $params['installments']) {
be2fb01f 269 $message .= "<br /> " . ts("Recurring contribution installments have been updated from %1 to %2 for this subscription.", [
1330f57a
SL
270 1 => $this->_subscriptionDetails->installments,
271 2 => $params['installments'],
272 ]) . ' ';
353ffa53 273 }
6a488035 274
be2fb01f 275 $activityParams = [
353ffa53 276 'source_contact_id' => $contactID,
12853dec 277 'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Update Recurring Contribution'),
c6c91efc 278 'subject' => $msg,
353ffa53
TO
279 'details' => $message,
280 'activity_date_time' => date('YmdHis'),
12853dec 281 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_status_id', 'Completed'),
be2fb01f 282 ];
12853dec 283
353ffa53
TO
284 $session = CRM_Core_Session::singleton();
285 $cid = $session->get('userID');
6a488035 286
353ffa53
TO
287 if ($cid) {
288 $activityParams['target_contact_id'][] = $activityParams['source_contact_id'];
289 $activityParams['source_contact_id'] = $cid;
290 }
291 CRM_Activity_BAO_Activity::create($activityParams);
292
293 if (!empty($params['is_notify'])) {
294 // send notification
295 if ($this->_subscriptionDetails->contribution_page_id) {
296 CRM_Core_DAO::commonRetrieveAll('CRM_Contribute_DAO_ContributionPage', 'id',
be2fb01f 297 $this->_subscriptionDetails->contribution_page_id, $value, [
353ffa53
TO
298 'title',
299 'receipt_from_name',
300 'receipt_from_email',
be2fb01f 301 ]
6a488035 302 );
353ffa53
TO
303 $receiptFrom = '"' . CRM_Utils_Array::value('receipt_from_name', $value[$this->_subscriptionDetails->contribution_page_id]) . '" <' . $value[$this->_subscriptionDetails->contribution_page_id]['receipt_from_email'] . '>';
304 }
305 else {
306 $domainValues = CRM_Core_BAO_Domain::getNameAndEmail();
307 $receiptFrom = "$domainValues[0] <$domainValues[1]>";
6a488035 308 }
353ffa53
TO
309
310 list($donorDisplayName, $donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($contactID);
311
be2fb01f 312 $tplParams = [
353ffa53
TO
313 'recur_frequency_interval' => $this->_subscriptionDetails->frequency_interval,
314 'recur_frequency_unit' => $this->_subscriptionDetails->frequency_unit,
315 'amount' => CRM_Utils_Money::format($params['amount']),
316 'installments' => $params['installments'],
be2fb01f 317 ];
353ffa53 318
be2fb01f 319 $tplParams['contact'] = ['display_name' => $donorDisplayName];
353ffa53
TO
320 $tplParams['receipt_from_email'] = $receiptFrom;
321
be2fb01f 322 $sendTemplateParams = [
353ffa53
TO
323 'groupName' => 'msg_tpl_workflow_contribution',
324 'valueName' => 'contribution_recurring_edit',
325 'contactId' => $contactID,
326 'tplParams' => $tplParams,
327 'isTest' => $this->_subscriptionDetails->is_test,
328 'PDFFilename' => 'receipt.pdf',
329 'from' => $receiptFrom,
330 'toName' => $donorDisplayName,
331 'toEmail' => $donorEmail,
be2fb01f 332 ];
353ffa53 333 list($sent) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
6a488035 334 }
353ffa53 335 }
6a488035
TO
336
337 $session = CRM_Core_Session::singleton();
353ffa53 338 $userID = $session->get('userID');
481a74f4 339 if ($userID && $status) {
6a488035 340 CRM_Core_Session::setStatus($status, $msgTitle, $msgType);
0db6c3e1 341 }
4c9b6178 342 elseif (!$userID) {
317fceb4 343 if ($status) {
6a488035 344 CRM_Utils_System::setUFMessage($status);
317fceb4 345 }
6a488035
TO
346 // keep result as 1, since we not displaying anything on the redirected page anyway
347 return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contribute/subscriptionstatus',
353ffa53 348 "reset=1&task=update&result=1"));
6a488035
TO
349 }
350 }
96025800 351
6a488035 352}