Merge pull request #16731 from eileenmcnaughton/regress
[civicrm-core.git] / CRM / Event / Form / Registration / Confirm.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
6a488035 13 * @package CRM
ca5cec67 14 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
15 */
16
17/**
3bdf1f3a 18 * This class generates form components for processing Event.
6a488035
TO
19 */
20class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration {
21
22 /**
66f9e52b 23 * The values for the contribution db object.
6a488035
TO
24 *
25 * @var array
6a488035
TO
26 */
27 public $_values;
28
29 /**
66f9e52b 30 * The total amount.
6a488035
TO
31 *
32 * @var float
6a488035
TO
33 */
34 public $_totalAmount;
35
423616fa
CW
36 public $submitOnce = TRUE;
37
3ae1b2f4 38 /**
39 * Monetary fields that may be submitted.
40 *
41 * These should get a standardised format in the beginPostProcess function.
42 *
43 * These fields are common to many forms. Some may override this.
90b461f1 44 * @var array
3ae1b2f4 45 */
46 protected $submittableMoneyFields = ['total_amount', 'net_amount', 'non_deductible_amount', 'fee_amount', 'tax_amount', 'amount'];
47
6a488035 48 /**
66f9e52b 49 * Set variables up before form is built.
6a488035 50 */
00be9182 51 public function preProcess() {
6a488035
TO
52 parent::preProcess();
53
54 // lineItem isn't set until Register postProcess
55 $this->_lineItem = $this->get('lineItem');
56
57 $this->_params = $this->get('params');
d91b8b33 58 $this->_params[0]['tax_amount'] = $this->get('tax_amount');
6a488035
TO
59
60 $this->_params[0]['is_pay_later'] = $this->get('is_pay_later');
61 $this->assign('is_pay_later', $this->_params[0]['is_pay_later']);
62 if ($this->_params[0]['is_pay_later']) {
63 $this->assign('pay_later_receipt', $this->_values['event']['pay_later_receipt']);
64 }
65
66 CRM_Utils_Hook::eventDiscount($this, $this->_params);
67
8cc574cf 68 if (!empty($this->_params[0]['discount']) && !empty($this->_params[0]['discount']['applied'])) {
6a488035
TO
69 $this->set('hookDiscount', $this->_params[0]['discount']);
70 $this->assign('hookDiscount', $this->_params[0]['discount']);
71 }
72
1a093d07 73 $this->preProcessExpress();
6a488035
TO
74
75 if ($this->_values['event']['is_monetary']) {
76 $this->_params[0]['invoiceID'] = $this->get('invoiceID');
77 }
78 $this->assign('defaultRole', FALSE);
79 if (CRM_Utils_Array::value('defaultRole', $this->_params[0]) == 1) {
80 $this->assign('defaultRole', TRUE);
81 }
82
a7488080 83 if (empty($this->_params[0]['participant_role_id']) &&
6a488035
TO
84 $this->_values['event']['default_role_id']
85 ) {
86 $this->_params[0]['participant_role_id'] = $this->_values['event']['default_role_id'];
87 }
88
89 if (isset($this->_values['event']['confirm_title'])) {
90 CRM_Utils_System::setTitle($this->_values['event']['confirm_title']);
91 }
92
f12392c8 93 // Personal campaign page
6a488035
TO
94 if ($this->_pcpId) {
95 $params = CRM_Contribute_Form_Contribution_Confirm::processPcp($this, $this->_params[0]);
96 $this->_params[0] = $params;
97 }
98
99 $this->set('params', $this->_params);
100 }
101
532279dd
MWMC
102 /**
103 * Pre process function for Paypal Express confirm.
104 * @todo this is just a step in refactor as payment processor specific code does not belong in generic forms
105 *
106 * @return bool
107 * @throws \CRM_Core_Exception
108 */
109 private function preProcessExpress() {
110 if ($this->_contributeMode !== 'express') {
111 return FALSE;
112 }
113 $params = [];
114 // rfp == redirect from paypal
115 // @fixme rfp is probably not required - the getPreApprovalDetails should deal with any payment-processor specific 'stuff'
116 $rfp = CRM_Utils_Request::retrieve('rfp', 'Boolean', CRM_Core_DAO::$_nullObject, FALSE, NULL, 'GET');
117
118 //we lost rfp in case of additional participant. So set it explicitly.
119 if ($rfp || CRM_Utils_Array::value('additional_participants', $this->_params[0], FALSE)) {
120 if (!empty($this->_paymentProcessor) && $this->_paymentProcessor['object']->supports('preApproval')) {
121 $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
122 $params = array_merge($this->_params, $preApprovalParams);
123 }
124 CRM_Core_Payment_Form::mapParams($this->_bltID, $params, $params, FALSE);
125
126 // set a few other parameters that are not really specific to this method because we don't know what
127 // will break if we change this.
128 $params['amount'] = $this->_params[0]['amount'];
129 if (!empty($this->_params[0]['discount'])) {
130 $params['discount'] = $this->_params[0]['discount'];
131 $params['discountAmount'] = $this->_params[0]['discountAmount'];
132 $params['discountMessage'] = $this->_params[0]['discountMessage'];
133 }
134
135 $params['amount_level'] = $this->_params[0]['amount_level'];
136 $params['currencyID'] = $this->_params[0]['currencyID'];
137
138 // also merge all the other values from the profile fields
139 $values = $this->controller->exportValues('Register');
140 $skipFields = [
141 'amount',
142 "street_address-{$this->_bltID}",
143 "city-{$this->_bltID}",
144 "state_province_id-{$this->_bltID}",
145 "postal_code-{$this->_bltID}",
146 "country_id-{$this->_bltID}",
147 ];
148
149 foreach ($values as $name => $value) {
150 // skip amount field
151 if (!in_array($name, $skipFields)) {
152 $params[$name] = $value;
153 }
154 if (substr($name, 0, 6) == 'price_') {
155 $params[$name] = $this->_params[0][$name];
156 }
157 }
158 $this->set('getExpressCheckoutDetails', $params);
159 }
160 $this->_params[0] = array_merge($this->_params[0], $params);
161 $this->_params[0]['is_primary'] = 1;
162 return TRUE;
163 }
164
6a488035 165 /**
3bdf1f3a 166 * Overwrite action, since we are only showing elements in frozen mode no help display needed.
6a488035
TO
167 *
168 * @return int
6a488035 169 */
00be9182 170 public function getAction() {
6a488035
TO
171 if ($this->_action & CRM_Core_Action::PREVIEW) {
172 return CRM_Core_Action::VIEW | CRM_Core_Action::PREVIEW;
173 }
174 else {
175 return CRM_Core_Action::VIEW;
176 }
177 }
178
179 /**
66f9e52b 180 * Build the form object.
6a488035
TO
181 */
182 public function buildQuickForm() {
183 $this->assignToTemplate();
1909126f 184
185 if ($this->_values['event']['is_monetary'] &&
ef27a9b6
AS
186 ($this->_params[0]['amount'] || $this->_params[0]['amount'] == 0) &&
187 !$this->_requireApproval
1909126f 188 ) {
be2fb01f 189 $this->_amount = [];
6a488035 190
79d001a2 191 $taxAmount = 0;
6a488035 192 foreach ($this->_params as $k => $v) {
7bde3600 193 if ($v == 'skip') {
194 continue;
195 }
75b065ce 196 $individualTaxAmount = 0;
79d001a2
PB
197 //display tax amount on confirmation page
198 $taxAmount += $v['tax_amount'];
6a488035 199 if (is_array($v)) {
60345ce2 200 $this->cleanMoneyFields($v);
be2fb01f 201 foreach ([
90b461f1
SL
202 'first_name',
203 'last_name',
204 ] as $name) {
6a488035
TO
205 if (isset($v['billing_' . $name]) &&
206 !isset($v[$name])
207 ) {
208 $v[$name] = $v['billing_' . $name];
209 }
210 }
211
8cc574cf 212 if (!empty($v['first_name']) && !empty($v['last_name'])) {
6a488035
TO
213 $append = $v['first_name'] . ' ' . $v['last_name'];
214 }
215 else {
216 //use an email if we have one
217 foreach ($v as $v_key => $v_val) {
218 if (substr($v_key, 0, 6) == 'email-') {
219 $append = $v[$v_key];
220 }
221 }
222 }
223
224 $this->_amount[$k]['amount'] = $v['amount'];
a7488080 225 if (!empty($v['discountAmount'])) {
6a488035
TO
226 $this->_amount[$k]['amount'] -= $v['discountAmount'];
227 }
228
229 $this->_amount[$k]['label'] = preg_replace('/\ 1/', '', $v['amount_level']) . ' - ' . $append;
230 $this->_part[$k]['info'] = CRM_Utils_Array::value('first_name', $v) . ' ' . CRM_Utils_Array::value('last_name', $v);
a7488080 231 if (empty($v['first_name'])) {
6a488035
TO
232 $this->_part[$k]['info'] = $append;
233 }
75b065ce 234
235 /*CRM-16320 */
236 $individual[$k]['totalAmtWithTax'] = $this->_amount[$k]['amount'];
237 $individual[$k]['totalTaxAmt'] = $individualTaxAmount + $v['tax_amount'];
6a488035 238 $this->_totalAmount = $this->_totalAmount + $this->_amount[$k]['amount'];
a7488080 239 if (!empty($v['is_primary'])) {
6a488035
TO
240 $this->set('primaryParticipantAmount', $this->_amount[$k]['amount']);
241 }
242 }
243 }
244
63743dd6 245 if (CRM_Invoicing_Utils::isInvoicingEnabled()) {
03b412ae 246 $this->assign('totalTaxAmount', $taxAmount);
63743dd6 247 $this->assign('taxTerm', CRM_Invoicing_Utils::getTaxTerm());
75b065ce 248 $this->assign('individual', $individual);
249 $this->set('individual', $individual);
03b412ae 250 }
75b065ce 251
6a488035
TO
252 $this->assign('part', $this->_part);
253 $this->set('part', $this->_part);
254 $this->assign('amounts', $this->_amount);
255 $this->assign('totalAmount', $this->_totalAmount);
256 $this->set('totalAmount', $this->_totalAmount);
257 }
258
9da8dc8c 259 if ($this->_priceSetId && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) {
be2fb01f 260 $lineItemForTemplate = [];
26fe6f4c 261 if (!empty($this->_lineItem) && is_array($this->_lineItem)) {
262 foreach ($this->_lineItem as $key => $value) {
263 if (!empty($value)) {
264 $lineItemForTemplate[$key] = $value;
265 }
03b412ae 266 }
6a488035
TO
267 }
268 if (!empty($lineItemForTemplate)) {
1dacd56e 269 $this->assignLineItemsToTemplate($lineItemForTemplate);
6a488035
TO
270 }
271 }
272
273 //display additional participants profile.
5bdcb00b 274 self::assignProfiles($this);
6a488035
TO
275
276 //consider total amount.
277 $this->assign('isAmountzero', ($this->_totalAmount <= 0) ? TRUE : FALSE);
278
229159bf 279 $contribButton = ts('Continue');
be2fb01f 280 $this->addButtons([
90b461f1
SL
281 [
282 'type' => 'back',
283 'name' => ts('Go Back'),
284 ],
285 [
286 'type' => 'next',
287 'name' => $contribButton,
288 'isDefault' => TRUE,
90b461f1
SL
289 ],
290 ]);
6a488035 291
be2fb01f
CW
292 $defaults = [];
293 $fields = [];
6a488035
TO
294 if (!empty($this->_fields)) {
295 foreach ($this->_fields as $name => $dontCare) {
296 $fields[$name] = 1;
297 }
298 }
299 $fields["billing_state_province-{$this->_bltID}"] = $fields["billing_country-{$this->_bltID}"] = $fields["email-{$this->_bltID}"] = 1;
300 foreach ($fields as $name => $dontCare) {
301 if (isset($this->_params[0][$name])) {
302 $defaults[$name] = $this->_params[0][$name];
303 if (substr($name, 0, 7) == 'custom_') {
304 $timeField = "{$name}_time";
305 if (isset($this->_params[0][$timeField])) {
306 $defaults[$timeField] = $this->_params[0][$timeField];
307 }
308 if (isset($this->_params[0]["{$name}_id"])) {
309 $defaults["{$name}_id"] = $this->_params[0]["{$name}_id"];
310 }
311 }
312 elseif (in_array($name, CRM_Contact_BAO_Contact::$_greetingTypes)
313 && !empty($this->_params[0][$name . '_custom'])
314 ) {
315 $defaults[$name . '_custom'] = $this->_params[0][$name . '_custom'];
316 }
317 }
318 }
319
6a488035
TO
320 $this->setDefaults($defaults);
321 $this->freeze();
322
323 //lets give meaningful status message, CRM-4320.
324 $this->assign('isOnWaitlist', $this->_allowWaitlist);
325 $this->assign('isRequireApproval', $this->_requireApproval);
326
327 // Assign Participant Count to Lineitem Table
9da8dc8c 328 $this->assign('pricesetFieldsCount', CRM_Price_BAO_PriceSet::getPricesetCount($this->_priceSetId));
be2fb01f 329 $this->addFormRule(['CRM_Event_Form_Registration_Confirm', 'formRule'], $this);
6a488035
TO
330 }
331
ca87146b 332 /**
3bdf1f3a 333 * Apply form rule.
334 *
335 * @param array $fields
336 * @param array $files
337 * @param CRM_Core_Form $self
ca87146b
EM
338 *
339 * @return array|bool
340 */
00be9182 341 public static function formRule($fields, $files, $self) {
be2fb01f 342 $errors = [];
79b152ac 343 $eventFull = CRM_Event_BAO_Participant::eventFull($self->_eventId, FALSE, CRM_Utils_Array::value('has_waitlist', $self->_values['event']));
344 if ($eventFull && empty($self->_allowConfirmation)) {
345 if (empty($self->_allowWaitlist)) {
0479b4c8 346 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "reset=1&id={$self->_eventId}", FALSE, NULL, FALSE, TRUE));
79b152ac 347 }
348 }
349 $self->_feeBlock = $self->_values['fee'];
350 CRM_Event_Form_Registration_Register::formatFieldsForOptionFull($self);
351
0dc0b759 352 if (!empty($self->_priceSetId) &&
353 !$self->_requireApproval && !$self->_allowWaitlist
354 ) {
79b152ac 355 $priceSetErrors = self::validatePriceSet($self, $self->_params);
0dc0b759 356 if (!empty($priceSetErrors)) {
2ae4d103 357 CRM_Core_Session::setStatus(ts('You have been returned to the start of the registration process and any sold out events have been removed from your selections. You will not be able to continue until you review your booking and select different events if you wish.'), ts('Unfortunately some of your options have now sold out for one or more participants.'), 'error');
0dc0b759 358 CRM_Core_Session::setStatus(ts('Please note that the options which are marked or selected are sold out for participant being viewed.'), ts('Sold out:'), 'error');
359 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "_qf_Register_display=true&qfKey={$fields['qfKey']}"));
360 }
79b152ac 361 }
362
0dc0b759 363 return empty($priceSetErrors) ? TRUE : $priceSetErrors;
79b152ac 364 }
353ffa53 365
6a488035 366 /**
66f9e52b 367 * Process the form submission.
bdcbbfea 368 *
369 * @throws \CiviCRM_API3_Exception
370 * @throws \CRM_Core_Exception
6a488035
TO
371 */
372 public function postProcess() {
353ffa53 373 $now = date('YmdHis');
af72b8c7 374
6a488035 375 $this->_params = $this->get('params');
3ae1b2f4 376 $this->cleanMoneyFields($this->_params);
377
a7488080 378 if (!empty($this->_params[0]['contact_id'])) {
e1ce628e 379 // unclear when this would be set & whether it could be checked in getContactID.
380 // perhaps it relates to when cid is in the url
381 //@todo someone who knows add comments on the various contactIDs in this form
6a488035
TO
382 $contactID = $this->_params[0]['contact_id'];
383 }
384 else {
5c280496 385 $contactID = $this->getContactID();
6a488035
TO
386 }
387
388 // if a discount has been applied, lets now deduct it from the amount
389 // and fix the fee level
8cc574cf 390 if (!empty($this->_params[0]['discount']) && !empty($this->_params[0]['discount']['applied'])) {
6a488035 391 foreach ($this->_params as $k => $v) {
8cc574cf 392 if (CRM_Utils_Array::value('amount', $this->_params[$k]) > 0 && !empty($this->_params[$k]['discountAmount'])) {
6a488035
TO
393 $this->_params[$k]['amount'] -= $this->_params[$k]['discountAmount'];
394 $this->_params[$k]['amount_level'] .= CRM_Utils_Array::value('discountMessage', $this->_params[$k]);
395 }
396 }
397 $this->set('params', $this->_params);
398 }
399
400 // CRM-4320, lets build array of cancelled additional participant ids
401 // those are drop or skip by primary at the time of confirmation.
402 // get all in and then unset those we want to process.
403 $cancelledIds = $this->_additionalParticipantIds;
404
405 $params = $this->_params;
1909126f 406 if ($this->_values['event']['is_monetary']) {
407 $this->set('finalAmount', $this->_amount);
408 }
be2fb01f 409 $participantCount = [];
bcffdf0c 410 $totalTaxAmount = 0;
6a488035
TO
411
412 //unset the skip participant from params.
413 //build the $participantCount array.
414 //maintain record for all participants.
415 foreach ($params as $participantNum => $record) {
416 if ($record == 'skip') {
417 unset($params[$participantNum]);
418 $participantCount[$participantNum] = 'skip';
419 }
420 elseif ($participantNum) {
421 $participantCount[$participantNum] = 'participant';
422 }
b6c8057d 423 $totalTaxAmount += CRM_Utils_Array::value('tax_amount', $record, 0);
de6c59ca 424 if (!empty($record['is_primary'])) {
b6c8057d
PN
425 $taxAmount = &$params[$participantNum]['tax_amount'];
426 }
6a488035
TO
427 //lets get additional participant id to cancel.
428 if ($this->_allowConfirmation && is_array($cancelledIds)) {
429 $additonalId = CRM_Utils_Array::value('participant_id', $record);
430 if ($additonalId && $key = array_search($additonalId, $cancelledIds)) {
431 unset($cancelledIds[$key]);
432 }
433 }
434 }
b6c8057d 435 $taxAmount = $totalTaxAmount;
6a488035
TO
436 $payment = $registerByID = $primaryCurrencyID = $contribution = NULL;
437 $paymentObjError = ts('The system did not record payment details for this payment and so could not process the transaction. Please report this error to the site administrator.');
438
be2fb01f 439 $fields = [];
6a488035 440 foreach ($params as $key => $value) {
a9f7d48b 441 CRM_Event_Form_Registration_Confirm::fixLocationFields($value, $fields, $this);
6a488035
TO
442 //unset the billing parameters if it is pay later mode
443 //to avoid creation of billing location
0b05b9a9 444 // @todo - the reasoning for this is unclear - elsewhere we check what fields are provided by
445 // the form & if billing fields exist we create the address, relying on the form to collect
446 // only information we intend to store.
8ae4d0d3 447 if ($this->_allowWaitlist
448 || $this->_requireApproval
449 || (!empty($value['is_pay_later']) && !$this->_isBillingAddressRequiredForPayLater)
450 || empty($value['is_primary'])
451 ) {
be2fb01f 452 $billingFields = [
6a488035
TO
453 "email-{$this->_bltID}",
454 'billing_first_name',
455 'billing_middle_name',
456 'billing_last_name',
457 "billing_street_address-{$this->_bltID}",
458 "billing_city-{$this->_bltID}",
459 "billing_state_province-{$this->_bltID}",
460 "billing_state_province_id-{$this->_bltID}",
461 "billing_postal_code-{$this->_bltID}",
462 "billing_country-{$this->_bltID}",
463 "billing_country_id-{$this->_bltID}",
464 "address_name-{$this->_bltID}",
be2fb01f 465 ];
6a488035
TO
466 foreach ($billingFields as $field) {
467 unset($value[$field]);
468 }
a7488080 469 if (!empty($value['is_pay_later'])) {
6a488035
TO
470 $this->_values['params']['is_pay_later'] = TRUE;
471 }
472 }
473
474 //Unset ContactID for additional participants and set RegisterBy Id.
a7488080 475 if (empty($value['is_primary'])) {
6a488035
TO
476 $contactID = CRM_Utils_Array::value('contact_id', $value);
477 $registerByID = $this->get('registerByID');
478 if ($registerByID) {
479 $value['registered_by_id'] = $registerByID;
480 }
481 }
482 else {
483 $value['amount'] = $this->_totalAmount;
484 }
485
a9f7d48b 486 $contactID = CRM_Event_Form_Registration_Confirm::updateContactFields($contactID, $value, $fields, $this);
6a488035
TO
487
488 // lets store the contactID in the session
489 // we dont store in userID in case the user is doing multiple
490 // transactions etc
491 // for things like tell a friend
8cc574cf 492 if (!$this->getContactID() && !empty($value['is_primary'])) {
18fe20eb 493 CRM_Core_Session::singleton()->set('transaction.userID', $contactID);
6a488035
TO
494 }
495
496 $value['description'] = ts('Online Event Registration') . ': ' . $this->_values['event']['title'];
497 $value['accountingCode'] = CRM_Utils_Array::value('accountingCode',
498 $this->_values['event']
499 );
500
752f450d 501 $pending = FALSE;
67c8322d
J
502 if ($this->_allowWaitlist || $this->_requireApproval) {
503 //get the participant statuses.
504 $waitingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Waiting'");
505 if ($this->_allowWaitlist) {
506 $value['participant_status_id'] = $value['participant_status'] = array_search('On waitlist', $waitingStatuses);
507 }
508 else {
509 $value['participant_status_id'] = $value['participant_status'] = array_search('Awaiting approval', $waitingStatuses);
510 }
511
6acc9d56 512 //there might be case user selected pay later and
67c8322d
J
513 //now becomes part of run time waiting list.
514 $value['is_pay_later'] = FALSE;
515 }
6acc9d56
MWMC
516 elseif ($this->_values['event']['is_monetary']) {
517 // required only if paid event
6a488035 518 if (is_array($this->_paymentProcessor)) {
077017db 519 $payment = $this->_paymentProcessor['object'];
6a488035 520 }
ec022878 521 if (!empty($this->_paymentProcessor) && $this->_paymentProcessor['object']->supports('preApproval')) {
522 $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
523 $value = array_merge($value, $preApprovalParams);
524 }
a3820d7d 525 $result = NULL;
6a488035 526
67c8322d 527 if (!empty($value['is_pay_later']) ||
6a488035 528 $value['amount'] == 0 ||
0f2b049e 529 // The concept of contributeMode is deprecated.
6a488035
TO
530 $this->_contributeMode == 'checkout' ||
531 $this->_contributeMode == 'notify'
532 ) {
533 if ($value['amount'] != 0) {
534 $pending = TRUE;
535 //get the participant statuses.
536 $pendingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Pending'");
0d8afee2 537 $status = !empty($value['is_pay_later']) ? 'Pending from pay later' : 'Pending from incomplete transaction';
6a488035
TO
538 $value['participant_status_id'] = $value['participant_status'] = array_search($status, $pendingStatuses);
539 }
540 }
a7488080 541 elseif (!empty($value['is_primary'])) {
6a488035 542 CRM_Core_Payment_Form::mapParams($this->_bltID, $value, $value, TRUE);
bd7b39e7
PJ
543 // payment email param can be empty for _bltID mapping
544 // thus provide mapping for it with a different email value
545 if (empty($value['email'])) {
546 $value['email'] = CRM_Utils_Array::valueByRegexKey('/^email-/', $value);
547 }
a3820d7d 548
549 if (is_object($payment)) {
550 // Not quite sure why we don't just user $value since it contains the data
551 // from result
552 // @todo ditch $result & retest.
553 list($result, $value) = $this->processPayment($payment, $value);
554 }
555 else {
a39a65ee 556 throw new CRM_Core_Exception($paymentObjError);
a3820d7d 557 }
6a488035
TO
558 }
559
6a488035
TO
560 $value['receive_date'] = $now;
561 if ($this->_allowConfirmation) {
562 $value['participant_register_date'] = $this->_values['participant']['register_date'];
563 }
564
565 $createContrib = ($value['amount'] != 0) ? TRUE : FALSE;
566 // force to create zero amount contribution, CRM-5095
567 if (!$createContrib && ($value['amount'] == 0)
568 && $this->_priceSetId && $this->_lineItem
569 ) {
570 $createContrib = TRUE;
571 }
572
8cc574cf 573 if ($createContrib && !empty($value['is_primary']) &&
6a488035
TO
574 !$this->_allowWaitlist && !$this->_requireApproval
575 ) {
576 // if paid event add a contribution record
577 //if primary participant contributing additional amount
578 //append (multiple participants) to its fee level. CRM-4196.
6a488035 579 if (count($params) > 1) {
7a0f6c65 580 $value['amount_level'] .= ts(' (multiple participants)') . CRM_Core_DAO::VALUE_SEPARATOR;
6a488035
TO
581 }
582
583 //passing contribution id is already registered.
44237a29 584 $contribution = $this->processContribution($this, $value, $result, $contactID, $pending, $this->_paymentProcessor);
6a488035
TO
585 $value['contributionID'] = $contribution->id;
586 $value['contributionTypeID'] = $contribution->financial_type_id;
587 $value['receive_date'] = $contribution->receive_date;
588 $value['trxn_id'] = $contribution->trxn_id;
589 $value['contributionID'] = $contribution->id;
590 $value['contributionTypeID'] = $contribution->financial_type_id;
591 }
592 $value['contactID'] = $contactID;
353ffa53 593 $value['eventID'] = $this->_eventId;
6a488035
TO
594 $value['item_name'] = $value['description'];
595 }
9a32a8fc
GC
596
597 if (!empty($value['contributionID'])) {
598 $this->_values['contributionId'] = $value['contributionID'];
599 }
6a488035
TO
600
601 //CRM-4453.
a7488080 602 if (!empty($value['is_primary'])) {
6a488035
TO
603 $primaryCurrencyID = CRM_Utils_Array::value('currencyID', $value);
604 }
a7488080 605 if (empty($value['currencyID'])) {
6a488035
TO
606 $value['currencyID'] = $primaryCurrencyID;
607 }
608
1909126f 609 // CRM-11182 - Confirmation page might not be monetary
610 if ($this->_values['event']['is_monetary']) {
611 if (!$pending && !empty($value['is_primary']) &&
612 !$this->_allowWaitlist && !$this->_requireApproval
613 ) {
614 // transactionID & receive date required while building email template
bcdf9664
PN
615 $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $value));
616 $this->assign('receive_date', CRM_Utils_Date::mysqlToIso(CRM_Utils_Array::value('receive_date', $value)));
617 $this->set('receiveDate', CRM_Utils_Date::mysqlToIso(CRM_Utils_Array::value('receive_date', $value)));
1909126f 618 $this->set('trxnId', CRM_Utils_Array::value('trxn_id', $value));
619 }
6a488035 620 }
f55dc004 621
ffcec972 622 $value['fee_amount'] = CRM_Utils_Array::value('amount', $value);
6a488035
TO
623 $this->set('value', $value);
624
625 // handle register date CRM-4320
626 if ($this->_allowConfirmation) {
481a74f4 627 $registerDate = CRM_Utils_Array::value('participant_register_date', $params);
6a488035 628 }
a7488080 629 elseif (!empty($params['participant_register_date']) &&
bcffdf0c 630 is_array($params['participant_register_date'])
6a488035
TO
631 ) {
632 $registerDate = CRM_Utils_Date::format($params['participant_register_date']);
633 }
634 else {
635 $registerDate = date('YmdHis');
636 }
637 $this->assign('register_date', $registerDate);
638
d5ce773d 639 $this->confirmPostProcess($contactID, $contribution);
6a488035
TO
640 }
641
642 //handle if no additional participant.
643 if (!$registerByID) {
644 $registerByID = $this->get('registerByID');
645 }
646
647 $this->set('participantIDs', $this->_participantIDS);
648
649 // create line items, CRM-5313
650 if ($this->_priceSetId &&
651 !empty($this->_lineItem)
652 ) {
653 // take all processed participant ids.
654 $allParticipantIds = $this->_participantIDS;
655
656 // when participant re-walk wizard.
657 if ($this->_allowConfirmation &&
658 !empty($this->_additionalParticipantIds)
659 ) {
be2fb01f 660 $allParticipantIds = array_merge([$registerByID], $this->_additionalParticipantIds);
6a488035
TO
661 }
662
663 $entityTable = 'civicrm_participant';
79d001a2 664 $totalTaxAmount = 0;
be2fb01f 665 $dataArray = [];
6a488035 666 foreach ($this->_lineItem as $key => $value) {
e189cf22 667 if ($value == 'skip') {
668 continue;
669 }
670 if ($entityId = CRM_Utils_Array::value($key, $allParticipantIds)) {
6a488035
TO
671 // do cleanup line items if participant re-walking wizard.
672 if ($this->_allowConfirmation) {
673 CRM_Price_BAO_LineItem::deleteLineItems($entityId, $entityTable);
674 }
675 $lineItem[$this->_priceSetId] = $value;
676 CRM_Price_BAO_LineItem::processPriceSet($entityId, $lineItem, $contribution, $entityTable);
677 }
63743dd6 678 if (CRM_Invoicing_Utils::isInvoicingEnabled()) {
03b412ae
PB
679 foreach ($value as $line) {
680 if (isset($line['tax_amount']) && isset($line['tax_rate'])) {
681 $totalTaxAmount = $line['tax_amount'] + $totalTaxAmount;
682 if (isset($dataArray[$line['tax_rate']])) {
683 $dataArray[$line['tax_rate']] = $dataArray[$line['tax_rate']] + CRM_Utils_Array::value('tax_amount', $line);
684 }
685 else {
686 $dataArray[$line['tax_rate']] = CRM_Utils_Array::value('tax_amount', $line);
687 }
79d001a2
PB
688 }
689 }
690 }
6a488035 691 }
63743dd6 692 $this->assign('dataArray', $dataArray);
693 $this->assign('totalTaxAmount', $totalTaxAmount);
6a488035
TO
694 }
695
b44e3f84 696 //update status and send mail to cancelled additional participants, CRM-4320
6a488035
TO
697 if ($this->_allowConfirmation && is_array($cancelledIds) && !empty($cancelledIds)) {
698 $cancelledId = array_search('Cancelled',
699 CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Negative'")
700 );
701 CRM_Event_BAO_Participant::transitionParticipants($cancelledIds, $cancelledId);
702 }
703
704 $isTest = FALSE;
705 if ($this->_action & CRM_Core_Action::PREVIEW) {
706 $isTest = TRUE;
707 }
708
c0f73fab 709 $primaryParticipant = $this->get('primaryParticipant');
710
711 if (empty($primaryParticipant['participantID'])) {
712 CRM_Core_Error::deprecatedFunctionWarning('This line is not logically reachable.');
713 $primaryParticipant['participantID'] = $registerByID;
714 }
715 //otherwise send mail Confirmation/Receipt
716 $primaryContactId = $this->get('primaryContactId');
717
6a488035 718 // for Transfer checkout.
0f2b049e 719 // The concept of contributeMode is deprecated.
6a488035
TO
720 if (($this->_contributeMode == 'checkout' ||
721 $this->_contributeMode == 'notify'
8cc574cf 722 ) && empty($params[0]['is_pay_later']) &&
6a488035
TO
723 !$this->_allowWaitlist && !$this->_requireApproval &&
724 $this->_totalAmount > 0
725 ) {
726
6a488035
TO
727 //build an array of custom profile and assigning it to template
728 $customProfile = CRM_Event_BAO_Event::buildCustomProfile($registerByID, $this->_values, NULL, $isTest);
729 if (count($customProfile)) {
730 $this->assign('customProfile', $customProfile);
731 $this->set('customProfile', $customProfile);
732 }
733
734 // do a transfer only if a monetary payment greater than 0
735 if ($this->_values['event']['is_monetary'] && $primaryParticipant) {
736 if ($payment && is_object($payment)) {
03665663 737 //CRM 14512 provide line items of all participants to payment gateway
738 $primaryContactId = $this->get('primaryContactId');
fb3b1f9a 739
03665663 740 //build an array of cId/pId of participants
741 $additionalIDs = CRM_Event_BAO_Event::buildCustomProfile($registerByID, NULL, $primaryContactId, $isTest, TRUE);
742
743 //need to copy, since we are unsetting on the way.
744 $copyParticipantCountLines = $participantCount;
745
746 //lets carry all participant params w/ values.
747 foreach ($additionalIDs as $participantID => $contactId) {
03665663 748 $participantNum = $participantID;
749 if ($participantID == $registerByID) {
3bdf1f3a 750 // This is the is primary participant.
751 $participantNum = 0;
03665663 752 }
753 else {
754 if ($participantNum = array_search('participant', $copyParticipantCountLines)) {
755 //if no participant found break.
756 if ($participantNum === NULL) {
757 break;
758 }
6acc9d56 759 //unset current participant so we don't check them again
03665663 760 unset($copyParticipantCountLines[$participantNum]);
761 }
762 }
763 // get values of line items
764 if ($this->_amount) {
be2fb01f 765 $amount = [];
03665663 766 $amount[$participantNum]['label'] = preg_replace('/\ 1/', '', $params[$participantNum]['amount_level']);
767 $amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
768 $params[$participantNum]['amounts'] = $amount;
769 }
770
771 if (!empty($this->_lineItem)) {
353ffa53 772 $lineItems = $this->_lineItem;
be2fb01f 773 $lineItem = [];
03665663 774 if ($lineItemValue = CRM_Utils_Array::value($participantNum, $lineItems)) {
775 $lineItem[] = $lineItemValue;
776 }
777 $params[$participantNum]['lineItem'] = $lineItem;
778 }
779
780 //only add additional particpants and not the primary particpant as we already have that
781 //added to $primaryParticipant so that this change doesn't break or require changes to
782 //existing gateway implementations
783 $primaryParticipant['participants_info'][$participantID] = $params[$participantNum];
784 }
785
786 //get event custom field information
0b330e6d 787 $groupTree = CRM_Core_BAO_CustomGroup::getTree('Event', NULL, $this->_eventId, 0, $this->_values['event']['event_type_id']);
03665663 788 $primaryParticipant['eventCustomFields'] = $groupTree;
fb3b1f9a 789
6a488035
TO
790 // call postprocess hook before leaving
791 $this->postProcessHook();
55f9f634 792
793 $this->processPayment($payment, $primaryParticipant);
6a488035
TO
794 }
795 else {
a39a65ee 796 throw new CRM_Core_Exception($paymentObjError);
6a488035
TO
797 }
798 }
799 }
800 else {
6a488035
TO
801
802 //build an array of cId/pId of participants
803 $additionalIDs = CRM_Event_BAO_Event::buildCustomProfile($registerByID,
804 NULL, $primaryContactId, $isTest,
805 TRUE
806 );
6acc9d56 807 //let's send mails to all with meaningful text, CRM-4320.
6a488035
TO
808 $this->assign('isOnWaitlist', $this->_allowWaitlist);
809 $this->assign('isRequireApproval', $this->_requireApproval);
810
811 //need to copy, since we are unsetting on the way.
812 $copyParticipantCount = $participantCount;
813
6acc9d56 814 //let's carry all participant params w/ values.
6a488035
TO
815 foreach ($additionalIDs as $participantID => $contactId) {
816 $participantNum = NULL;
817 if ($participantID == $registerByID) {
818 $participantNum = 0;
819 }
820 else {
821 if ($participantNum = array_search('participant', $copyParticipantCount)) {
822 unset($copyParticipantCount[$participantNum]);
823 }
824 }
0479b4c8
TO
825 if ($participantNum === NULL) {
826 break;
827 }
6a488035
TO
828
829 //carry the participant submitted values.
830 $this->_values['params'][$participantID] = $params[$participantNum];
831 }
832
833 foreach ($additionalIDs as $participantID => $contactId) {
834 $participantNum = 0;
835 if ($participantID == $registerByID) {
836 //set as Primary Participant
837 $this->assign('isPrimary', 1);
838 //build an array of custom profile and assigning it to template.
839 $customProfile = CRM_Event_BAO_Event::buildCustomProfile($participantID, $this->_values, NULL, $isTest);
840
841 if (count($customProfile)) {
842 $this->assign('customProfile', $customProfile);
843 $this->set('customProfile', $customProfile);
844 }
845 $this->_values['params']['additionalParticipant'] = FALSE;
846 }
847 else {
848 //take the Additional participant number.
849 if ($participantNum = array_search('participant', $participantCount)) {
850 unset($participantCount[$participantNum]);
851 }
4abc4ee1 852 // Change $this->_values['participant'] to include additional participant values
be2fb01f
CW
853 $ids = $participantValues = [];
854 $participantParams = ['id' => $participantID];
4abc4ee1 855 CRM_Event_BAO_Participant::getValues($participantParams, $participantValues, $ids);
856 $this->_values['participant'] = $participantValues[$participantID];
857
6a488035
TO
858 $this->assign('isPrimary', 0);
859 $this->assign('customProfile', NULL);
860 //Additional Participant should get only it's payment information
1909126f 861 if (!empty($this->_amount)) {
be2fb01f 862 $amount = [];
6a488035
TO
863 $params = $this->get('params');
864 $amount[$participantNum]['label'] = preg_replace('/\ 1/', '', $params[$participantNum]['amount_level']);
865 $amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
866 $this->assign('amounts', $amount);
867 }
868 if ($this->_lineItem) {
353ffa53 869 $lineItems = $this->_lineItem;
be2fb01f 870 $lineItem = [];
6a488035
TO
871 if ($lineItemValue = CRM_Utils_Array::value($participantNum, $lineItems)) {
872 $lineItem[] = $lineItemValue;
873 }
63743dd6 874 if (CRM_Invoicing_Utils::isInvoicingEnabled()) {
75b065ce 875 $individual = $this->get('individual');
876 $dataArray[key($dataArray)] = $individual[$participantNum]['totalTaxAmt'];
877 $this->assign('dataArray', $dataArray);
878 $this->assign('totalAmount', $individual[$participantNum]['totalAmtWithTax']);
879 $this->assign('totalTaxAmount', $individual[$participantNum]['totalTaxAmt']);
be2fb01f 880 $this->assign('individual', [$individual[$participantNum]]);
75b065ce 881 }
6a488035
TO
882 $this->assign('lineItem', $lineItem);
883 }
884 $this->_values['params']['additionalParticipant'] = TRUE;
7d92d486 885 $this->assign('isAdditionalParticipant', $this->_values['params']['additionalParticipant']);
6a488035
TO
886 }
887
888 //pass these variables since these are run time calculated.
889 $this->_values['params']['isOnWaitlist'] = $this->_allowWaitlist;
890 $this->_values['params']['isRequireApproval'] = $this->_requireApproval;
891
892 //send mail to primary as well as additional participants.
6a488035
TO
893 CRM_Event_BAO_Event::sendMail($contactId, $this->_values, $participantID, $isTest);
894 }
895 }
896 }
6a488035
TO
897
898 /**
66f9e52b 899 * Process the contribution.
6a488035 900 *
c490a46a
CW
901 * @param CRM_Core_Form $form
902 * @param array $params
3bdf1f3a 903 * @param array $result
100fef9d 904 * @param int $contactID
dd244018 905 * @param bool $pending
6acc9d56 906 * @param array $paymentProcessor
dd244018 907 *
3bdf1f3a 908 * @return \CRM_Contribute_BAO_Contribution
bcffdf0c 909 *
6acc9d56 910 * @throws \CRM_Core_Exception
bcffdf0c 911 * @throws \CiviCRM_API3_Exception
6a488035 912 */
44237a29 913 protected function processContribution(
ddca8f33 914 &$form, $params, $result, $contactID,
7a0f6c65 915 $pending = FALSE,
632196ea 916 $paymentProcessor = NULL
6a488035 917 ) {
44237a29 918 // Note this used to be shared with the backoffice form & no longer is, some code may no longer be required.
6a488035
TO
919 $transaction = new CRM_Core_Transaction();
920
353ffa53 921 $now = date('YmdHis');
6a488035
TO
922 $receiptDate = NULL;
923
bf2c70af 924 if (!empty($form->_values['event']['is_email_confirm'])) {
6a488035
TO
925 $receiptDate = $now;
926 }
6a488035 927
a7f2d5fd 928 // CRM-20264: fetch CC type ID and number (last 4 digit) and assign it back to $params
929 CRM_Contribute_Form_AbstractEditPayment::formatCreditCardDetails($params);
930
be2fb01f 931 $contribParams = [
6a488035 932 'contact_id' => $contactID,
353ffa53 933 'financial_type_id' => !empty($form->_values['event']['financial_type_id']) ? $form->_values['event']['financial_type_id'] : $params['financial_type_id'],
6a488035
TO
934 'receive_date' => $now,
935 'total_amount' => $params['amount'],
d91b8b33 936 'tax_amount' => $params['tax_amount'],
6a488035
TO
937 'amount_level' => $params['amount_level'],
938 'invoice_id' => $params['invoiceID'],
939 'currency' => $params['currencyID'],
13bb29e4 940 'source' => !empty($params['participant_source']) ? $params['participant_source'] : $params['description'],
6a488035 941 'is_pay_later' => CRM_Utils_Array::value('is_pay_later', $params, 0),
6b409353
CW
942 'campaign_id' => $params['campaign_id'] ?? NULL,
943 'card_type_id' => $params['card_type_id'] ?? NULL,
944 'pan_truncation' => $params['pan_truncation'] ?? NULL,
be2fb01f 945 ];
6a488035 946
632196ea 947 if ($paymentProcessor) {
948 $contribParams['payment_instrument_id'] = $paymentProcessor['payment_instrument_id'];
dcc0e041 949 $contribParams['payment_processor'] = $paymentProcessor['id'];
6a488035
TO
950 }
951
952 if (!$pending && $result) {
be2fb01f 953 $contribParams += [
6b409353 954 'fee_amount' => $result['fee_amount'] ?? NULL,
6a488035
TO
955 'trxn_id' => $result['trxn_id'],
956 'receipt_date' => $receiptDate,
be2fb01f 957 ];
6a488035
TO
958 }
959
960 $allStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
961 $contribParams['contribution_status_id'] = array_search('Completed', $allStatuses);
962 if ($pending) {
963 $contribParams['contribution_status_id'] = array_search('Pending', $allStatuses);
964 }
965
966 $contribParams['is_test'] = 0;
967 if ($form->_action & CRM_Core_Action::PREVIEW || CRM_Utils_Array::value('mode', $params) == 'test') {
968 $contribParams['is_test'] = 1;
969 }
970
a7488080 971 if (!empty($contribParams['invoice_id'])) {
3c884887 972 $contribParams['id'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution',
6a488035
TO
973 $contribParams['invoice_id'],
974 'id',
975 'invoice_id'
976 );
977 }
978
a17bec97 979 if (Civi::settings()->get('deferred_revenue_enabled')) {
8cf6bd83
PN
980 $eventStartDate = CRM_Utils_Array::value(
981 'start_date',
982 CRM_Utils_Array::value(
983 'event',
984 $form->_values
985 )
986 );
a493ffb6 987 if (strtotime($eventStartDate) > strtotime(date('Ymt'))) {
8cf6bd83
PN
988 $contribParams['revenue_recognition_date'] = date('Ymd', strtotime($eventStartDate));
989 }
990 }
6a488035 991 //create an contribution address
0f2b049e 992 // The concept of contributeMode is deprecated. Elsewhere we use the function processBillingAddress() - although
993 // currently that is only inherited by back-office forms.
8cc574cf 994 if ($form->_contributeMode != 'notify' && empty($params['is_pay_later'])) {
6a488035
TO
995 $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $form->_bltID);
996 }
997
6a488035 998 $contribParams['skipLineItem'] = 1;
3ae1b2f4 999 $contribParams['skipCleanMoney'] = 1;
6a488035 1000 // create contribution record
66ea9833 1001 $contribution = CRM_Contribute_BAO_Contribution::add($contribParams);
6a488035 1002 // CRM-11124
362bd1b7 1003 CRM_Event_BAO_Participant::createDiscountTrxn($form->_eventId, $contribParams, NULL, CRM_Price_BAO_PriceSet::parseFirstPriceSetValueIDFromParams($params));
6a488035
TO
1004
1005 // process soft credit / pcp pages
7a13735b 1006 if (!empty($params['pcp_made_through_id'])) {
03b0e225 1007 CRM_Contribute_BAO_ContributionSoft::formatSoftCreditParams($params, $form);
7a13735b 1008 CRM_Contribute_BAO_ContributionSoft::processSoftContribution($params, $contribution);
1009 }
6a488035
TO
1010
1011 $transaction->commit();
1012
1013 return $contribution;
1014 }
1015
1016 /**
66f9e52b 1017 * Fix the Location Fields.
6a488035 1018 *
b7a83c2c
J
1019 * @todo Reconcile with the contribution method formatParamsForPaymentProcessor
1020 * rather than adding different logic to check when to keep the billing
1021 * fields. There might be a difference in handling guest/multiple
1022 * participants though.
1023 *
c490a46a 1024 * @param array $params
3bdf1f3a 1025 * @param array $fields
c490a46a 1026 * @param CRM_Core_Form $form
6a488035 1027 */
4fb756af 1028 public static function fixLocationFields(&$params, &$fields, &$form) {
a9f7d48b
AS
1029 if (!empty($form->_fields)) {
1030 foreach ($form->_fields as $name => $dontCare) {
6a488035
TO
1031 $fields[$name] = 1;
1032 }
1033 }
1034
08318d90
J
1035 // If there's no 'first_name' in the profile then overwrite the names from
1036 // the billing fields (if they are set)
6a488035
TO
1037 if (is_array($fields)) {
1038 if (!array_key_exists('first_name', $fields)) {
be2fb01f 1039 $nameFields = ['first_name', 'middle_name', 'last_name'];
6a488035
TO
1040 foreach ($nameFields as $name) {
1041 $fields[$name] = 1;
1042 if (array_key_exists("billing_$name", $params)) {
1043 $params[$name] = $params["billing_{$name}"];
1044 $params['preserveDBName'] = TRUE;
1045 }
1046 }
1047 }
1048 }
1049
08318d90 1050 // Add the billing names to the billing address, if a billing name is set
5329bf02 1051 if (!empty($params['billing_first_name'])) {
a9f7d48b
AS
1052 $params["address_name-{$form->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $params) . ' ' . CRM_Utils_Array::value('billing_last_name', $params);
1053 $fields["address_name-{$form->_bltID}"] = 1;
6a488035 1054 }
08318d90 1055
a9f7d48b 1056 $fields["email-{$form->_bltID}"] = 1;
6a488035
TO
1057 $fields['email-Primary'] = 1;
1058
1059 //if its pay later or additional participant set email address as primary.
8cc574cf 1060 if ((!empty($params['is_pay_later']) || empty($params['is_primary']) ||
a9f7d48b
AS
1061 !$form->_values['event']['is_monetary'] ||
1062 $form->_allowWaitlist ||
1063 $form->_requireApproval
353ffa53
TO
1064 ) && !empty($params["email-{$form->_bltID}"])
1065 ) {
a9f7d48b 1066 $params['email-Primary'] = $params["email-{$form->_bltID}"];
6a488035
TO
1067 }
1068 }
1069
1070 /**
66f9e52b 1071 * Update contact fields.
6a488035 1072 *
100fef9d 1073 * @param int $contactID
c490a46a 1074 * @param array $params
3bdf1f3a 1075 * @param array $fields
c490a46a 1076 * @param CRM_Core_Form $form
dd244018 1077 *
3bdf1f3a 1078 * @return int
6a488035 1079 */
4fb756af 1080 public static function updateContactFields($contactID, $params, $fields, &$form) {
6a488035
TO
1081 //add the contact to group, if add to group is selected for a
1082 //particular uf group
1083
1084 // get the add to groups
be2fb01f 1085 $addToGroups = [];
6a488035 1086
a9f7d48b
AS
1087 if (!empty($form->_fields)) {
1088 foreach ($form->_fields as $key => $value) {
a7488080 1089 if (!empty($value['add_to_group_id'])) {
6a488035
TO
1090 $addToGroups[$value['add_to_group_id']] = $value['add_to_group_id'];
1091 }
1092 }
1093 }
1094
1095 // check for profile double opt-in and get groups to be subscribed
1096 $subscribeGroupIds = CRM_Core_BAO_UFGroup::getDoubleOptInGroupIds($params, $contactID);
1097
1098 foreach ($addToGroups as $k) {
1099 if (array_key_exists($k, $subscribeGroupIds)) {
1100 unset($addToGroups[$k]);
1101 }
1102 }
1103
1104 // since we are directly adding contact to group lets unset it from mailing
1105 if (!empty($addToGroups)) {
1106 foreach ($addToGroups as $groupId) {
1107 if (isset($subscribeGroupIds[$groupId])) {
1108 unset($subscribeGroupIds[$groupId]);
1109 }
1110 }
1111 }
1112 if ($contactID) {
1113 $ctype = CRM_Core_DAO::getFieldValue(
1114 'CRM_Contact_DAO_Contact',
1115 $contactID,
1116 'contact_type'
1117 );
e1ce628e 1118
22e263ad 1119 if (array_key_exists('contact_id', $params) && empty($params['contact_id'])) {
e1ce628e 1120 // we unset this here because the downstream function ignores the contactID we give it
1121 // if it is set & it is difficult to understand the implications of 'fixing' this downstream
1122 // but if we are passing a contact id into this function it's reasonable to assume we don't
1123 // want it ignored
1124 unset($params['contact_id']);
1125 }
1126
6a488035
TO
1127 $contactID = CRM_Contact_BAO_Contact::createProfileContact(
1128 $params,
1129 $fields,
1130 $contactID,
1131 $addToGroups,
1132 NULL,
1133 $ctype,
1134 TRUE
1135 );
1136 }
1137 else {
1138
1139 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
1140 if (!isset($params[$greeting . '_id'])) {
1141 $params[$greeting . '_id'] = CRM_Contact_BAO_Contact_Utils::defaultGreeting('Individual', $greeting);
1142 }
1143 }
1144
1145 $contactID = CRM_Contact_BAO_Contact::createProfileContact($params,
1146 $fields,
1147 NULL,
1148 $addToGroups,
1149 NULL,
1150 NULL,
1151 TRUE
1152 );
a9f7d48b 1153 $form->set('contactID', $contactID);
6a488035
TO
1154 }
1155
1156 //get email primary first if exist
dd01a750
MWMC
1157 $subscriptionEmail = ['email' => CRM_Utils_Array::value('email-Primary', $params)];
1158 if (!$subscriptionEmail['email']) {
1159 $subscriptionEmail['email'] = CRM_Utils_Array::value("email-{$form->_bltID}", $params);
6a488035
TO
1160 }
1161 // subscribing contact to groups
dd01a750
MWMC
1162 if (!empty($subscribeGroupIds) && $subscriptionEmail['email']) {
1163 CRM_Mailing_Event_BAO_Subscribe::commonSubscribe($subscribeGroupIds, $subscriptionEmail, $contactID);
6a488035
TO
1164 }
1165
1166 return $contactID;
1167 }
5bdcb00b 1168
0cf587a7 1169 /**
301906ab 1170 * Assign Profiles to the template.
3bdf1f3a 1171 *
301906ab 1172 * @param CRM_Event_Form_Registration_Confirm $form
1173 *
1174 * @throws \Exception
0cf587a7 1175 */
301906ab 1176 public static function assignProfiles($form) {
5bdcb00b 1177 $participantParams = $form->_params;
be2fb01f 1178 $formattedValues = $profileFields = [];
353ffa53 1179 $count = 1;
5bdcb00b
PJ
1180 foreach ($participantParams as $participantNum => $participantValue) {
1181 if ($participantNum) {
0479b4c8
TO
1182 $prefix1 = 'additional';
1183 $prefix2 = 'additional_';
0db6c3e1
TO
1184 }
1185 else {
0479b4c8
TO
1186 $prefix1 = '';
1187 $prefix2 = '';
5bdcb00b 1188 }
301906ab 1189 if ($participantValue !== 'skip') {
5bdcb00b
PJ
1190 //get the customPre profile info
1191 if (!empty($form->_values[$prefix2 . 'custom_pre_id'])) {
be2fb01f 1192 $values = $groupName = [];
5bdcb00b 1193 CRM_Event_BAO_Event::displayProfile($participantValue,
0479b4c8 1194 $form->_values[$prefix2 . 'custom_pre_id'],
5bdcb00b
PJ
1195 $groupName,
1196 $values,
1197 $profileFields
1198 );
1199
1200 if (count($values)) {
1201 $formattedValues[$count][$prefix1 . 'CustomPre'] = $values;
1202 }
1203 $formattedValues[$count][$prefix1 . 'CustomPreGroupTitle'] = CRM_Utils_Array::value('groupTitle', $groupName);
1204 }
1205 //get the customPost profile info
1206 if (!empty($form->_values[$prefix2 . 'custom_post_id'])) {
be2fb01f 1207 $values = $groupName = [];
5bdcb00b 1208 foreach ($form->_values[$prefix2 . 'custom_post_id'] as $gids) {
be2fb01f 1209 $val = [];
5bdcb00b
PJ
1210 CRM_Event_BAO_Event::displayProfile($participantValue,
1211 $gids,
1212 $group,
1213 $val,
1214 $profileFields
1215 );
1216 $values[$gids] = $val;
1217 $groupName[$gids] = $group;
1218 }
1219
1220 if (count($values)) {
1221 $formattedValues[$count][$prefix1 . 'CustomPost'] = $values;
1222 }
1223
1224 if (isset($formattedValues[$count][$prefix1 . 'CustomPre'])) {
1225 $formattedValues[$count][$prefix1 . 'CustomPost'] = array_diff_assoc($formattedValues[$count][$prefix1 . 'CustomPost'],
1226 $formattedValues[$count][$prefix1 . 'CustomPre']
1227 );
1228 }
1229
1230 $formattedValues[$count][$prefix1 . 'CustomPostGroupTitle'] = $groupName;
1231 }
1232 $count++;
1233 }
1234 $form->_fields = $profileFields;
1235 }
481a74f4 1236 if (!empty($formattedValues)) {
5bdcb00b 1237 $form->assign('primaryParticipantProfile', $formattedValues[1]);
0479b4c8 1238 $form->set('primaryParticipantProfile', $formattedValues[1]);
5bdcb00b
PJ
1239 if ($count > 2) {
1240 unset($formattedValues[1]);
1241 $form->assign('addParticipantProfile', $formattedValues);
0479b4c8 1242 $form->set('addParticipantProfile', $formattedValues);
5bdcb00b
PJ
1243 }
1244 }
1245 }
96025800 1246
632196ea 1247 /**
1248 * Submit in test mode.
1249 *
1250 * @param $params
1251 */
1252 public static function testSubmit($params) {
1253 $form = new CRM_Event_Form_Registration_Confirm();
1254 // This way the mocked up controller ignores the session stuff.
1255 $_SERVER['REQUEST_METHOD'] = 'GET';
1256 $_REQUEST['id'] = $form->_eventId = $params['id'];
1257 $form->controller = new CRM_Event_Controller_Registration();
1258 $form->_params = $params['params'];
3ae1b2f4 1259 // This happens in buildQuickForm so emulate here.
1260 $form->_amount = $form->_totalAmount = CRM_Utils_Rule::cleanMoney(CRM_Utils_Array::value('totalAmount', $params));
632196ea 1261 $form->set('params', $params['params']);
eba56939
BS
1262 $form->_values['custom_pre_id'] = CRM_Utils_Array::value('custom_pre_id', $params);
1263 $form->_values['custom_post_id'] = CRM_Utils_Array::value('custom_post_id', $params);
6704d983 1264 $form->_values['event'] = CRM_Utils_Array::value('event', $params);
632196ea 1265 $form->_contributeMode = $params['contributeMode'];
be2fb01f 1266 $eventParams = ['id' => $params['id']];
632196ea 1267 CRM_Event_BAO_Event::retrieve($eventParams, $form->_values['event']);
1268 $form->set('registerByID', $params['registerByID']);
5e40de84 1269 if (!empty($params['paymentProcessorObj'])) {
1270 $form->_paymentProcessor = $params['paymentProcessorObj'];
1271 }
632196ea 1272 $form->postProcess();
1273 }
1274
55f9f634 1275 /**
1276 * Process the payment, redirecting back to the page on error.
1277 *
bcffdf0c 1278 * @param \CRM_Core_Payment $payment
55f9f634 1279 * @param $value
1280 *
1281 * @return array
1282 */
1283 private function processPayment($payment, $value) {
1284 try {
1a093d07 1285 $params = $this->prepareParamsForPaymentProcessor($value);
1286 $result = $payment->doPayment($params, 'event');
be2fb01f 1287 return [$result, $value];
55f9f634 1288 }
1289 catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
22f9da80 1290 Civi::log()->error('Payment processor exception: ' . $e->getMessage());
55f9f634 1291 CRM_Core_Session::singleton()->setStatus($e->getMessage());
1292 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "id={$this->_eventId}"));
1293 }
be2fb01f 1294 return [];
55f9f634 1295 }
1296
3ae1b2f4 1297 /**
1298 * Clean money fields from the form.
1299 *
1300 * @param array $params
1301 */
1302 protected function cleanMoneyFields(&$params) {
1303 foreach ($this->submittableMoneyFields as $moneyField) {
1304 foreach ($params as $index => $paramField) {
1305 if (isset($paramField[$moneyField])) {
1306 $params[$index][$moneyField] = CRM_Utils_Rule::cleanMoney($paramField[$moneyField]);
1307 }
1308 }
1309 }
1310 }
1311
6a488035 1312}