Merge pull request #18548 from civicrm/5.30
[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.
f7dbf5d9 277 $this->assign('isAmountzero', $this->_totalAmount <= 0);
6a488035 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)) {
9c1bc317 429 $additonalId = $record['participant_id'] ?? NULL;
6a488035
TO
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);
8ae4d0d3 442 if ($this->_allowWaitlist
443 || $this->_requireApproval
444 || (!empty($value['is_pay_later']) && !$this->_isBillingAddressRequiredForPayLater)
445 || empty($value['is_primary'])
446 ) {
e6a5c070 447 // This is confusing because unnecessary code around it has been removed. It is not
448 // clear why we do this / whether we should.
a7488080 449 if (!empty($value['is_pay_later'])) {
6a488035
TO
450 $this->_values['params']['is_pay_later'] = TRUE;
451 }
452 }
453
454 //Unset ContactID for additional participants and set RegisterBy Id.
a7488080 455 if (empty($value['is_primary'])) {
9c1bc317 456 $contactID = $value['contact_id'] ?? NULL;
6a488035
TO
457 $registerByID = $this->get('registerByID');
458 if ($registerByID) {
459 $value['registered_by_id'] = $registerByID;
460 }
461 }
462 else {
463 $value['amount'] = $this->_totalAmount;
464 }
465
a9f7d48b 466 $contactID = CRM_Event_Form_Registration_Confirm::updateContactFields($contactID, $value, $fields, $this);
6a488035
TO
467
468 // lets store the contactID in the session
469 // we dont store in userID in case the user is doing multiple
470 // transactions etc
471 // for things like tell a friend
8cc574cf 472 if (!$this->getContactID() && !empty($value['is_primary'])) {
18fe20eb 473 CRM_Core_Session::singleton()->set('transaction.userID', $contactID);
6a488035
TO
474 }
475
476 $value['description'] = ts('Online Event Registration') . ': ' . $this->_values['event']['title'];
477 $value['accountingCode'] = CRM_Utils_Array::value('accountingCode',
478 $this->_values['event']
479 );
480
752f450d 481 $pending = FALSE;
67c8322d
J
482 if ($this->_allowWaitlist || $this->_requireApproval) {
483 //get the participant statuses.
484 $waitingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Waiting'");
485 if ($this->_allowWaitlist) {
486 $value['participant_status_id'] = $value['participant_status'] = array_search('On waitlist', $waitingStatuses);
487 }
488 else {
489 $value['participant_status_id'] = $value['participant_status'] = array_search('Awaiting approval', $waitingStatuses);
490 }
491
6acc9d56 492 //there might be case user selected pay later and
67c8322d
J
493 //now becomes part of run time waiting list.
494 $value['is_pay_later'] = FALSE;
495 }
6acc9d56
MWMC
496 elseif ($this->_values['event']['is_monetary']) {
497 // required only if paid event
6a488035 498 if (is_array($this->_paymentProcessor)) {
077017db 499 $payment = $this->_paymentProcessor['object'];
6a488035 500 }
ec022878 501 if (!empty($this->_paymentProcessor) && $this->_paymentProcessor['object']->supports('preApproval')) {
502 $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
503 $value = array_merge($value, $preApprovalParams);
504 }
a3820d7d 505 $result = NULL;
6a488035 506
67c8322d 507 if (!empty($value['is_pay_later']) ||
6a488035 508 $value['amount'] == 0 ||
0f2b049e 509 // The concept of contributeMode is deprecated.
6a488035
TO
510 $this->_contributeMode == 'checkout' ||
511 $this->_contributeMode == 'notify'
512 ) {
513 if ($value['amount'] != 0) {
514 $pending = TRUE;
515 //get the participant statuses.
516 $pendingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Pending'");
0d8afee2 517 $status = !empty($value['is_pay_later']) ? 'Pending from pay later' : 'Pending from incomplete transaction';
6a488035
TO
518 $value['participant_status_id'] = $value['participant_status'] = array_search($status, $pendingStatuses);
519 }
520 }
a7488080 521 elseif (!empty($value['is_primary'])) {
6a488035 522 CRM_Core_Payment_Form::mapParams($this->_bltID, $value, $value, TRUE);
bd7b39e7
PJ
523 // payment email param can be empty for _bltID mapping
524 // thus provide mapping for it with a different email value
525 if (empty($value['email'])) {
526 $value['email'] = CRM_Utils_Array::valueByRegexKey('/^email-/', $value);
527 }
a3820d7d 528
529 if (is_object($payment)) {
530 // Not quite sure why we don't just user $value since it contains the data
531 // from result
532 // @todo ditch $result & retest.
533 list($result, $value) = $this->processPayment($payment, $value);
534 }
535 else {
a39a65ee 536 throw new CRM_Core_Exception($paymentObjError);
a3820d7d 537 }
6a488035
TO
538 }
539
6a488035
TO
540 $value['receive_date'] = $now;
541 if ($this->_allowConfirmation) {
542 $value['participant_register_date'] = $this->_values['participant']['register_date'];
543 }
544
f7dbf5d9 545 $createContrib = $value['amount'] != 0;
6a488035
TO
546 // force to create zero amount contribution, CRM-5095
547 if (!$createContrib && ($value['amount'] == 0)
548 && $this->_priceSetId && $this->_lineItem
549 ) {
550 $createContrib = TRUE;
551 }
552
8cc574cf 553 if ($createContrib && !empty($value['is_primary']) &&
6a488035
TO
554 !$this->_allowWaitlist && !$this->_requireApproval
555 ) {
556 // if paid event add a contribution record
557 //if primary participant contributing additional amount
558 //append (multiple participants) to its fee level. CRM-4196.
6a488035 559 if (count($params) > 1) {
7a0f6c65 560 $value['amount_level'] .= ts(' (multiple participants)') . CRM_Core_DAO::VALUE_SEPARATOR;
6a488035
TO
561 }
562
563 //passing contribution id is already registered.
44237a29 564 $contribution = $this->processContribution($this, $value, $result, $contactID, $pending, $this->_paymentProcessor);
6a488035
TO
565 $value['contributionID'] = $contribution->id;
566 $value['contributionTypeID'] = $contribution->financial_type_id;
567 $value['receive_date'] = $contribution->receive_date;
568 $value['trxn_id'] = $contribution->trxn_id;
569 $value['contributionID'] = $contribution->id;
570 $value['contributionTypeID'] = $contribution->financial_type_id;
571 }
572 $value['contactID'] = $contactID;
353ffa53 573 $value['eventID'] = $this->_eventId;
6a488035
TO
574 $value['item_name'] = $value['description'];
575 }
9a32a8fc
GC
576
577 if (!empty($value['contributionID'])) {
578 $this->_values['contributionId'] = $value['contributionID'];
579 }
6a488035
TO
580
581 //CRM-4453.
a7488080 582 if (!empty($value['is_primary'])) {
9c1bc317 583 $primaryCurrencyID = $value['currencyID'] ?? NULL;
6a488035 584 }
a7488080 585 if (empty($value['currencyID'])) {
6a488035
TO
586 $value['currencyID'] = $primaryCurrencyID;
587 }
588
1909126f 589 // CRM-11182 - Confirmation page might not be monetary
590 if ($this->_values['event']['is_monetary']) {
591 if (!$pending && !empty($value['is_primary']) &&
592 !$this->_allowWaitlist && !$this->_requireApproval
593 ) {
594 // transactionID & receive date required while building email template
bcdf9664
PN
595 $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $value));
596 $this->assign('receive_date', CRM_Utils_Date::mysqlToIso(CRM_Utils_Array::value('receive_date', $value)));
597 $this->set('receiveDate', CRM_Utils_Date::mysqlToIso(CRM_Utils_Array::value('receive_date', $value)));
1909126f 598 $this->set('trxnId', CRM_Utils_Array::value('trxn_id', $value));
599 }
6a488035 600 }
f55dc004 601
9c1bc317 602 $value['fee_amount'] = $value['amount'] ?? NULL;
6a488035
TO
603 $this->set('value', $value);
604
605 // handle register date CRM-4320
606 if ($this->_allowConfirmation) {
9c1bc317 607 $registerDate = $params['participant_register_date'] ?? NULL;
6a488035 608 }
a7488080 609 elseif (!empty($params['participant_register_date']) &&
bcffdf0c 610 is_array($params['participant_register_date'])
6a488035
TO
611 ) {
612 $registerDate = CRM_Utils_Date::format($params['participant_register_date']);
613 }
614 else {
615 $registerDate = date('YmdHis');
616 }
617 $this->assign('register_date', $registerDate);
618
d5ce773d 619 $this->confirmPostProcess($contactID, $contribution);
6a488035
TO
620 }
621
622 //handle if no additional participant.
623 if (!$registerByID) {
624 $registerByID = $this->get('registerByID');
625 }
626
627 $this->set('participantIDs', $this->_participantIDS);
628
629 // create line items, CRM-5313
630 if ($this->_priceSetId &&
631 !empty($this->_lineItem)
632 ) {
633 // take all processed participant ids.
634 $allParticipantIds = $this->_participantIDS;
635
636 // when participant re-walk wizard.
637 if ($this->_allowConfirmation &&
638 !empty($this->_additionalParticipantIds)
639 ) {
be2fb01f 640 $allParticipantIds = array_merge([$registerByID], $this->_additionalParticipantIds);
6a488035
TO
641 }
642
643 $entityTable = 'civicrm_participant';
79d001a2 644 $totalTaxAmount = 0;
be2fb01f 645 $dataArray = [];
6a488035 646 foreach ($this->_lineItem as $key => $value) {
e189cf22 647 if ($value == 'skip') {
648 continue;
649 }
650 if ($entityId = CRM_Utils_Array::value($key, $allParticipantIds)) {
6a488035
TO
651 // do cleanup line items if participant re-walking wizard.
652 if ($this->_allowConfirmation) {
653 CRM_Price_BAO_LineItem::deleteLineItems($entityId, $entityTable);
654 }
655 $lineItem[$this->_priceSetId] = $value;
656 CRM_Price_BAO_LineItem::processPriceSet($entityId, $lineItem, $contribution, $entityTable);
657 }
63743dd6 658 if (CRM_Invoicing_Utils::isInvoicingEnabled()) {
03b412ae
PB
659 foreach ($value as $line) {
660 if (isset($line['tax_amount']) && isset($line['tax_rate'])) {
661 $totalTaxAmount = $line['tax_amount'] + $totalTaxAmount;
662 if (isset($dataArray[$line['tax_rate']])) {
663 $dataArray[$line['tax_rate']] = $dataArray[$line['tax_rate']] + CRM_Utils_Array::value('tax_amount', $line);
664 }
665 else {
9c1bc317 666 $dataArray[$line['tax_rate']] = $line['tax_amount'] ?? NULL;
03b412ae 667 }
79d001a2
PB
668 }
669 }
670 }
6a488035 671 }
63743dd6 672 $this->assign('dataArray', $dataArray);
673 $this->assign('totalTaxAmount', $totalTaxAmount);
6a488035
TO
674 }
675
b44e3f84 676 //update status and send mail to cancelled additional participants, CRM-4320
6a488035
TO
677 if ($this->_allowConfirmation && is_array($cancelledIds) && !empty($cancelledIds)) {
678 $cancelledId = array_search('Cancelled',
679 CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Negative'")
680 );
681 CRM_Event_BAO_Participant::transitionParticipants($cancelledIds, $cancelledId);
682 }
683
684 $isTest = FALSE;
685 if ($this->_action & CRM_Core_Action::PREVIEW) {
686 $isTest = TRUE;
687 }
688
c0f73fab 689 $primaryParticipant = $this->get('primaryParticipant');
690
691 if (empty($primaryParticipant['participantID'])) {
692 CRM_Core_Error::deprecatedFunctionWarning('This line is not logically reachable.');
693 $primaryParticipant['participantID'] = $registerByID;
694 }
695 //otherwise send mail Confirmation/Receipt
696 $primaryContactId = $this->get('primaryContactId');
697
6a488035 698 // for Transfer checkout.
0f2b049e 699 // The concept of contributeMode is deprecated.
6a488035
TO
700 if (($this->_contributeMode == 'checkout' ||
701 $this->_contributeMode == 'notify'
8cc574cf 702 ) && empty($params[0]['is_pay_later']) &&
6a488035
TO
703 !$this->_allowWaitlist && !$this->_requireApproval &&
704 $this->_totalAmount > 0
705 ) {
706
6a488035
TO
707 //build an array of custom profile and assigning it to template
708 $customProfile = CRM_Event_BAO_Event::buildCustomProfile($registerByID, $this->_values, NULL, $isTest);
709 if (count($customProfile)) {
710 $this->assign('customProfile', $customProfile);
711 $this->set('customProfile', $customProfile);
712 }
713
714 // do a transfer only if a monetary payment greater than 0
715 if ($this->_values['event']['is_monetary'] && $primaryParticipant) {
716 if ($payment && is_object($payment)) {
03665663 717 //CRM 14512 provide line items of all participants to payment gateway
718 $primaryContactId = $this->get('primaryContactId');
fb3b1f9a 719
03665663 720 //build an array of cId/pId of participants
721 $additionalIDs = CRM_Event_BAO_Event::buildCustomProfile($registerByID, NULL, $primaryContactId, $isTest, TRUE);
722
723 //need to copy, since we are unsetting on the way.
724 $copyParticipantCountLines = $participantCount;
725
726 //lets carry all participant params w/ values.
727 foreach ($additionalIDs as $participantID => $contactId) {
03665663 728 $participantNum = $participantID;
729 if ($participantID == $registerByID) {
3bdf1f3a 730 // This is the is primary participant.
731 $participantNum = 0;
03665663 732 }
733 else {
734 if ($participantNum = array_search('participant', $copyParticipantCountLines)) {
735 //if no participant found break.
736 if ($participantNum === NULL) {
737 break;
738 }
6acc9d56 739 //unset current participant so we don't check them again
03665663 740 unset($copyParticipantCountLines[$participantNum]);
741 }
742 }
743 // get values of line items
744 if ($this->_amount) {
be2fb01f 745 $amount = [];
03665663 746 $amount[$participantNum]['label'] = preg_replace('/\ 1/', '', $params[$participantNum]['amount_level']);
747 $amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
748 $params[$participantNum]['amounts'] = $amount;
749 }
750
751 if (!empty($this->_lineItem)) {
353ffa53 752 $lineItems = $this->_lineItem;
be2fb01f 753 $lineItem = [];
03665663 754 if ($lineItemValue = CRM_Utils_Array::value($participantNum, $lineItems)) {
755 $lineItem[] = $lineItemValue;
756 }
757 $params[$participantNum]['lineItem'] = $lineItem;
758 }
759
760 //only add additional particpants and not the primary particpant as we already have that
761 //added to $primaryParticipant so that this change doesn't break or require changes to
762 //existing gateway implementations
763 $primaryParticipant['participants_info'][$participantID] = $params[$participantNum];
764 }
765
766 //get event custom field information
0b330e6d 767 $groupTree = CRM_Core_BAO_CustomGroup::getTree('Event', NULL, $this->_eventId, 0, $this->_values['event']['event_type_id']);
03665663 768 $primaryParticipant['eventCustomFields'] = $groupTree;
fb3b1f9a 769
6a488035
TO
770 // call postprocess hook before leaving
771 $this->postProcessHook();
55f9f634 772
773 $this->processPayment($payment, $primaryParticipant);
6a488035
TO
774 }
775 else {
a39a65ee 776 throw new CRM_Core_Exception($paymentObjError);
6a488035
TO
777 }
778 }
779 }
780 else {
6a488035
TO
781
782 //build an array of cId/pId of participants
783 $additionalIDs = CRM_Event_BAO_Event::buildCustomProfile($registerByID,
784 NULL, $primaryContactId, $isTest,
785 TRUE
786 );
6acc9d56 787 //let's send mails to all with meaningful text, CRM-4320.
6a488035
TO
788 $this->assign('isOnWaitlist', $this->_allowWaitlist);
789 $this->assign('isRequireApproval', $this->_requireApproval);
790
791 //need to copy, since we are unsetting on the way.
792 $copyParticipantCount = $participantCount;
793
6acc9d56 794 //let's carry all participant params w/ values.
6a488035
TO
795 foreach ($additionalIDs as $participantID => $contactId) {
796 $participantNum = NULL;
797 if ($participantID == $registerByID) {
798 $participantNum = 0;
799 }
800 else {
801 if ($participantNum = array_search('participant', $copyParticipantCount)) {
802 unset($copyParticipantCount[$participantNum]);
803 }
804 }
0479b4c8
TO
805 if ($participantNum === NULL) {
806 break;
807 }
6a488035
TO
808
809 //carry the participant submitted values.
810 $this->_values['params'][$participantID] = $params[$participantNum];
811 }
812
813 foreach ($additionalIDs as $participantID => $contactId) {
814 $participantNum = 0;
815 if ($participantID == $registerByID) {
816 //set as Primary Participant
817 $this->assign('isPrimary', 1);
818 //build an array of custom profile and assigning it to template.
819 $customProfile = CRM_Event_BAO_Event::buildCustomProfile($participantID, $this->_values, NULL, $isTest);
820
821 if (count($customProfile)) {
822 $this->assign('customProfile', $customProfile);
823 $this->set('customProfile', $customProfile);
824 }
825 $this->_values['params']['additionalParticipant'] = FALSE;
826 }
827 else {
828 //take the Additional participant number.
829 if ($participantNum = array_search('participant', $participantCount)) {
830 unset($participantCount[$participantNum]);
831 }
4abc4ee1 832 // Change $this->_values['participant'] to include additional participant values
be2fb01f
CW
833 $ids = $participantValues = [];
834 $participantParams = ['id' => $participantID];
4abc4ee1 835 CRM_Event_BAO_Participant::getValues($participantParams, $participantValues, $ids);
836 $this->_values['participant'] = $participantValues[$participantID];
837
6a488035
TO
838 $this->assign('isPrimary', 0);
839 $this->assign('customProfile', NULL);
840 //Additional Participant should get only it's payment information
1909126f 841 if (!empty($this->_amount)) {
be2fb01f 842 $amount = [];
6a488035
TO
843 $params = $this->get('params');
844 $amount[$participantNum]['label'] = preg_replace('/\ 1/', '', $params[$participantNum]['amount_level']);
845 $amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
846 $this->assign('amounts', $amount);
847 }
848 if ($this->_lineItem) {
353ffa53 849 $lineItems = $this->_lineItem;
be2fb01f 850 $lineItem = [];
6a488035
TO
851 if ($lineItemValue = CRM_Utils_Array::value($participantNum, $lineItems)) {
852 $lineItem[] = $lineItemValue;
853 }
63743dd6 854 if (CRM_Invoicing_Utils::isInvoicingEnabled()) {
75b065ce 855 $individual = $this->get('individual');
856 $dataArray[key($dataArray)] = $individual[$participantNum]['totalTaxAmt'];
857 $this->assign('dataArray', $dataArray);
858 $this->assign('totalAmount', $individual[$participantNum]['totalAmtWithTax']);
859 $this->assign('totalTaxAmount', $individual[$participantNum]['totalTaxAmt']);
be2fb01f 860 $this->assign('individual', [$individual[$participantNum]]);
75b065ce 861 }
6a488035
TO
862 $this->assign('lineItem', $lineItem);
863 }
864 $this->_values['params']['additionalParticipant'] = TRUE;
7d92d486 865 $this->assign('isAdditionalParticipant', $this->_values['params']['additionalParticipant']);
6a488035
TO
866 }
867
868 //pass these variables since these are run time calculated.
869 $this->_values['params']['isOnWaitlist'] = $this->_allowWaitlist;
870 $this->_values['params']['isRequireApproval'] = $this->_requireApproval;
871
872 //send mail to primary as well as additional participants.
6a488035
TO
873 CRM_Event_BAO_Event::sendMail($contactId, $this->_values, $participantID, $isTest);
874 }
875 }
876 }
6a488035
TO
877
878 /**
66f9e52b 879 * Process the contribution.
6a488035 880 *
c490a46a
CW
881 * @param CRM_Core_Form $form
882 * @param array $params
3bdf1f3a 883 * @param array $result
100fef9d 884 * @param int $contactID
dd244018 885 * @param bool $pending
6acc9d56 886 * @param array $paymentProcessor
dd244018 887 *
3bdf1f3a 888 * @return \CRM_Contribute_BAO_Contribution
bcffdf0c 889 *
6acc9d56 890 * @throws \CRM_Core_Exception
bcffdf0c 891 * @throws \CiviCRM_API3_Exception
6a488035 892 */
44237a29 893 protected function processContribution(
ddca8f33 894 &$form, $params, $result, $contactID,
7a0f6c65 895 $pending = FALSE,
632196ea 896 $paymentProcessor = NULL
6a488035 897 ) {
44237a29 898 // Note this used to be shared with the backoffice form & no longer is, some code may no longer be required.
6a488035
TO
899 $transaction = new CRM_Core_Transaction();
900
353ffa53 901 $now = date('YmdHis');
6a488035
TO
902 $receiptDate = NULL;
903
bf2c70af 904 if (!empty($form->_values['event']['is_email_confirm'])) {
6a488035
TO
905 $receiptDate = $now;
906 }
6a488035 907
a7f2d5fd 908 // CRM-20264: fetch CC type ID and number (last 4 digit) and assign it back to $params
909 CRM_Contribute_Form_AbstractEditPayment::formatCreditCardDetails($params);
910
be2fb01f 911 $contribParams = [
6a488035 912 'contact_id' => $contactID,
353ffa53 913 'financial_type_id' => !empty($form->_values['event']['financial_type_id']) ? $form->_values['event']['financial_type_id'] : $params['financial_type_id'],
6a488035
TO
914 'receive_date' => $now,
915 'total_amount' => $params['amount'],
d91b8b33 916 'tax_amount' => $params['tax_amount'],
6a488035
TO
917 'amount_level' => $params['amount_level'],
918 'invoice_id' => $params['invoiceID'],
919 'currency' => $params['currencyID'],
13bb29e4 920 'source' => !empty($params['participant_source']) ? $params['participant_source'] : $params['description'],
6a488035 921 'is_pay_later' => CRM_Utils_Array::value('is_pay_later', $params, 0),
6b409353
CW
922 'campaign_id' => $params['campaign_id'] ?? NULL,
923 'card_type_id' => $params['card_type_id'] ?? NULL,
924 'pan_truncation' => $params['pan_truncation'] ?? NULL,
be2fb01f 925 ];
6a488035 926
632196ea 927 if ($paymentProcessor) {
928 $contribParams['payment_instrument_id'] = $paymentProcessor['payment_instrument_id'];
dcc0e041 929 $contribParams['payment_processor'] = $paymentProcessor['id'];
6a488035
TO
930 }
931
932 if (!$pending && $result) {
be2fb01f 933 $contribParams += [
6b409353 934 'fee_amount' => $result['fee_amount'] ?? NULL,
6a488035
TO
935 'trxn_id' => $result['trxn_id'],
936 'receipt_date' => $receiptDate,
be2fb01f 937 ];
6a488035
TO
938 }
939
940 $allStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
941 $contribParams['contribution_status_id'] = array_search('Completed', $allStatuses);
942 if ($pending) {
943 $contribParams['contribution_status_id'] = array_search('Pending', $allStatuses);
944 }
945
946 $contribParams['is_test'] = 0;
947 if ($form->_action & CRM_Core_Action::PREVIEW || CRM_Utils_Array::value('mode', $params) == 'test') {
948 $contribParams['is_test'] = 1;
949 }
950
a7488080 951 if (!empty($contribParams['invoice_id'])) {
3c884887 952 $contribParams['id'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution',
6a488035
TO
953 $contribParams['invoice_id'],
954 'id',
955 'invoice_id'
956 );
957 }
958
a17bec97 959 if (Civi::settings()->get('deferred_revenue_enabled')) {
8cf6bd83
PN
960 $eventStartDate = CRM_Utils_Array::value(
961 'start_date',
962 CRM_Utils_Array::value(
963 'event',
964 $form->_values
965 )
966 );
a493ffb6 967 if (strtotime($eventStartDate) > strtotime(date('Ymt'))) {
8cf6bd83
PN
968 $contribParams['revenue_recognition_date'] = date('Ymd', strtotime($eventStartDate));
969 }
970 }
6a488035 971 //create an contribution address
0f2b049e 972 // The concept of contributeMode is deprecated. Elsewhere we use the function processBillingAddress() - although
973 // currently that is only inherited by back-office forms.
8cc574cf 974 if ($form->_contributeMode != 'notify' && empty($params['is_pay_later'])) {
6a488035
TO
975 $contribParams['address_id'] = CRM_Contribute_BAO_Contribution::createAddress($params, $form->_bltID);
976 }
977
6a488035 978 $contribParams['skipLineItem'] = 1;
3ae1b2f4 979 $contribParams['skipCleanMoney'] = 1;
6a488035 980 // create contribution record
66ea9833 981 $contribution = CRM_Contribute_BAO_Contribution::add($contribParams);
6a488035 982 // CRM-11124
362bd1b7 983 CRM_Event_BAO_Participant::createDiscountTrxn($form->_eventId, $contribParams, NULL, CRM_Price_BAO_PriceSet::parseFirstPriceSetValueIDFromParams($params));
6a488035
TO
984
985 // process soft credit / pcp pages
7a13735b 986 if (!empty($params['pcp_made_through_id'])) {
03b0e225 987 CRM_Contribute_BAO_ContributionSoft::formatSoftCreditParams($params, $form);
7a13735b 988 CRM_Contribute_BAO_ContributionSoft::processSoftContribution($params, $contribution);
989 }
6a488035
TO
990
991 $transaction->commit();
992
993 return $contribution;
994 }
995
996 /**
66f9e52b 997 * Fix the Location Fields.
6a488035 998 *
b7a83c2c
J
999 * @todo Reconcile with the contribution method formatParamsForPaymentProcessor
1000 * rather than adding different logic to check when to keep the billing
1001 * fields. There might be a difference in handling guest/multiple
1002 * participants though.
1003 *
c490a46a 1004 * @param array $params
3bdf1f3a 1005 * @param array $fields
c490a46a 1006 * @param CRM_Core_Form $form
6a488035 1007 */
4fb756af 1008 public static function fixLocationFields(&$params, &$fields, &$form) {
a9f7d48b
AS
1009 if (!empty($form->_fields)) {
1010 foreach ($form->_fields as $name => $dontCare) {
6a488035
TO
1011 $fields[$name] = 1;
1012 }
1013 }
1014
08318d90
J
1015 // If there's no 'first_name' in the profile then overwrite the names from
1016 // the billing fields (if they are set)
6a488035
TO
1017 if (is_array($fields)) {
1018 if (!array_key_exists('first_name', $fields)) {
be2fb01f 1019 $nameFields = ['first_name', 'middle_name', 'last_name'];
6a488035
TO
1020 foreach ($nameFields as $name) {
1021 $fields[$name] = 1;
1022 if (array_key_exists("billing_$name", $params)) {
1023 $params[$name] = $params["billing_{$name}"];
1024 $params['preserveDBName'] = TRUE;
1025 }
1026 }
1027 }
1028 }
1029
08318d90 1030 // Add the billing names to the billing address, if a billing name is set
5329bf02 1031 if (!empty($params['billing_first_name'])) {
2cfe2cf4 1032 $params["address_name-{$form->_bltID}"] = $params['billing_first_name'] . ' ' . CRM_Utils_Array::value('billing_middle_name', $params) . ' ' . CRM_Utils_Array::value('billing_last_name', $params);
a9f7d48b 1033 $fields["address_name-{$form->_bltID}"] = 1;
6a488035 1034 }
08318d90 1035
a9f7d48b 1036 $fields["email-{$form->_bltID}"] = 1;
6a488035
TO
1037 $fields['email-Primary'] = 1;
1038
1039 //if its pay later or additional participant set email address as primary.
8cc574cf 1040 if ((!empty($params['is_pay_later']) || empty($params['is_primary']) ||
a9f7d48b
AS
1041 !$form->_values['event']['is_monetary'] ||
1042 $form->_allowWaitlist ||
1043 $form->_requireApproval
353ffa53
TO
1044 ) && !empty($params["email-{$form->_bltID}"])
1045 ) {
a9f7d48b 1046 $params['email-Primary'] = $params["email-{$form->_bltID}"];
6a488035
TO
1047 }
1048 }
1049
1050 /**
66f9e52b 1051 * Update contact fields.
6a488035 1052 *
100fef9d 1053 * @param int $contactID
c490a46a 1054 * @param array $params
3bdf1f3a 1055 * @param array $fields
c490a46a 1056 * @param CRM_Core_Form $form
dd244018 1057 *
3bdf1f3a 1058 * @return int
6a488035 1059 */
4fb756af 1060 public static function updateContactFields($contactID, $params, $fields, &$form) {
6a488035
TO
1061 //add the contact to group, if add to group is selected for a
1062 //particular uf group
1063
1064 // get the add to groups
be2fb01f 1065 $addToGroups = [];
6a488035 1066
a9f7d48b
AS
1067 if (!empty($form->_fields)) {
1068 foreach ($form->_fields as $key => $value) {
a7488080 1069 if (!empty($value['add_to_group_id'])) {
6a488035
TO
1070 $addToGroups[$value['add_to_group_id']] = $value['add_to_group_id'];
1071 }
1072 }
1073 }
1074
1075 // check for profile double opt-in and get groups to be subscribed
1076 $subscribeGroupIds = CRM_Core_BAO_UFGroup::getDoubleOptInGroupIds($params, $contactID);
1077
1078 foreach ($addToGroups as $k) {
1079 if (array_key_exists($k, $subscribeGroupIds)) {
1080 unset($addToGroups[$k]);
1081 }
1082 }
1083
1084 // since we are directly adding contact to group lets unset it from mailing
1085 if (!empty($addToGroups)) {
1086 foreach ($addToGroups as $groupId) {
1087 if (isset($subscribeGroupIds[$groupId])) {
1088 unset($subscribeGroupIds[$groupId]);
1089 }
1090 }
1091 }
1092 if ($contactID) {
1093 $ctype = CRM_Core_DAO::getFieldValue(
1094 'CRM_Contact_DAO_Contact',
1095 $contactID,
1096 'contact_type'
1097 );
e1ce628e 1098
22e263ad 1099 if (array_key_exists('contact_id', $params) && empty($params['contact_id'])) {
e1ce628e 1100 // we unset this here because the downstream function ignores the contactID we give it
1101 // if it is set & it is difficult to understand the implications of 'fixing' this downstream
1102 // but if we are passing a contact id into this function it's reasonable to assume we don't
1103 // want it ignored
1104 unset($params['contact_id']);
1105 }
1106
6a488035
TO
1107 $contactID = CRM_Contact_BAO_Contact::createProfileContact(
1108 $params,
1109 $fields,
1110 $contactID,
1111 $addToGroups,
1112 NULL,
1113 $ctype,
1114 TRUE
1115 );
1116 }
1117 else {
1118
1119 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
1120 if (!isset($params[$greeting . '_id'])) {
1121 $params[$greeting . '_id'] = CRM_Contact_BAO_Contact_Utils::defaultGreeting('Individual', $greeting);
1122 }
1123 }
1124
1125 $contactID = CRM_Contact_BAO_Contact::createProfileContact($params,
1126 $fields,
1127 NULL,
1128 $addToGroups,
1129 NULL,
1130 NULL,
1131 TRUE
1132 );
a9f7d48b 1133 $form->set('contactID', $contactID);
6a488035
TO
1134 }
1135
1136 //get email primary first if exist
dd01a750
MWMC
1137 $subscriptionEmail = ['email' => CRM_Utils_Array::value('email-Primary', $params)];
1138 if (!$subscriptionEmail['email']) {
9c1bc317 1139 $subscriptionEmail['email'] = $params["email-{$form->_bltID}"] ?? NULL;
6a488035
TO
1140 }
1141 // subscribing contact to groups
dd01a750
MWMC
1142 if (!empty($subscribeGroupIds) && $subscriptionEmail['email']) {
1143 CRM_Mailing_Event_BAO_Subscribe::commonSubscribe($subscribeGroupIds, $subscriptionEmail, $contactID);
6a488035
TO
1144 }
1145
1146 return $contactID;
1147 }
5bdcb00b 1148
0cf587a7 1149 /**
301906ab 1150 * Assign Profiles to the template.
3bdf1f3a 1151 *
301906ab 1152 * @param CRM_Event_Form_Registration_Confirm $form
1153 *
1154 * @throws \Exception
0cf587a7 1155 */
301906ab 1156 public static function assignProfiles($form) {
5bdcb00b 1157 $participantParams = $form->_params;
be2fb01f 1158 $formattedValues = $profileFields = [];
353ffa53 1159 $count = 1;
5bdcb00b
PJ
1160 foreach ($participantParams as $participantNum => $participantValue) {
1161 if ($participantNum) {
0479b4c8
TO
1162 $prefix1 = 'additional';
1163 $prefix2 = 'additional_';
0db6c3e1
TO
1164 }
1165 else {
0479b4c8
TO
1166 $prefix1 = '';
1167 $prefix2 = '';
5bdcb00b 1168 }
301906ab 1169 if ($participantValue !== 'skip') {
5bdcb00b
PJ
1170 //get the customPre profile info
1171 if (!empty($form->_values[$prefix2 . 'custom_pre_id'])) {
be2fb01f 1172 $values = $groupName = [];
5bdcb00b 1173 CRM_Event_BAO_Event::displayProfile($participantValue,
0479b4c8 1174 $form->_values[$prefix2 . 'custom_pre_id'],
5bdcb00b
PJ
1175 $groupName,
1176 $values,
1177 $profileFields
1178 );
1179
1180 if (count($values)) {
1181 $formattedValues[$count][$prefix1 . 'CustomPre'] = $values;
1182 }
9c1bc317 1183 $formattedValues[$count][$prefix1 . 'CustomPreGroupTitle'] = $groupName['groupTitle'] ?? NULL;
5bdcb00b
PJ
1184 }
1185 //get the customPost profile info
1186 if (!empty($form->_values[$prefix2 . 'custom_post_id'])) {
be2fb01f 1187 $values = $groupName = [];
5bdcb00b 1188 foreach ($form->_values[$prefix2 . 'custom_post_id'] as $gids) {
be2fb01f 1189 $val = [];
5bdcb00b
PJ
1190 CRM_Event_BAO_Event::displayProfile($participantValue,
1191 $gids,
1192 $group,
1193 $val,
1194 $profileFields
1195 );
1196 $values[$gids] = $val;
1197 $groupName[$gids] = $group;
1198 }
1199
1200 if (count($values)) {
1201 $formattedValues[$count][$prefix1 . 'CustomPost'] = $values;
1202 }
1203
1204 if (isset($formattedValues[$count][$prefix1 . 'CustomPre'])) {
1205 $formattedValues[$count][$prefix1 . 'CustomPost'] = array_diff_assoc($formattedValues[$count][$prefix1 . 'CustomPost'],
1206 $formattedValues[$count][$prefix1 . 'CustomPre']
1207 );
1208 }
1209
1210 $formattedValues[$count][$prefix1 . 'CustomPostGroupTitle'] = $groupName;
1211 }
1212 $count++;
1213 }
1214 $form->_fields = $profileFields;
1215 }
481a74f4 1216 if (!empty($formattedValues)) {
5bdcb00b 1217 $form->assign('primaryParticipantProfile', $formattedValues[1]);
0479b4c8 1218 $form->set('primaryParticipantProfile', $formattedValues[1]);
5bdcb00b
PJ
1219 if ($count > 2) {
1220 unset($formattedValues[1]);
1221 $form->assign('addParticipantProfile', $formattedValues);
0479b4c8 1222 $form->set('addParticipantProfile', $formattedValues);
5bdcb00b
PJ
1223 }
1224 }
1225 }
96025800 1226
632196ea 1227 /**
1228 * Submit in test mode.
1229 *
1230 * @param $params
1231 */
1232 public static function testSubmit($params) {
1233 $form = new CRM_Event_Form_Registration_Confirm();
1234 // This way the mocked up controller ignores the session stuff.
1235 $_SERVER['REQUEST_METHOD'] = 'GET';
1236 $_REQUEST['id'] = $form->_eventId = $params['id'];
1237 $form->controller = new CRM_Event_Controller_Registration();
1238 $form->_params = $params['params'];
3ae1b2f4 1239 // This happens in buildQuickForm so emulate here.
1240 $form->_amount = $form->_totalAmount = CRM_Utils_Rule::cleanMoney(CRM_Utils_Array::value('totalAmount', $params));
632196ea 1241 $form->set('params', $params['params']);
9c1bc317
CW
1242 $form->_values['custom_pre_id'] = $params['custom_pre_id'] ?? NULL;
1243 $form->_values['custom_post_id'] = $params['custom_post_id'] ?? NULL;
1244 $form->_values['event'] = $params['event'] ?? NULL;
632196ea 1245 $form->_contributeMode = $params['contributeMode'];
be2fb01f 1246 $eventParams = ['id' => $params['id']];
632196ea 1247 CRM_Event_BAO_Event::retrieve($eventParams, $form->_values['event']);
1248 $form->set('registerByID', $params['registerByID']);
5e40de84 1249 if (!empty($params['paymentProcessorObj'])) {
1250 $form->_paymentProcessor = $params['paymentProcessorObj'];
1251 }
632196ea 1252 $form->postProcess();
1253 }
1254
55f9f634 1255 /**
1256 * Process the payment, redirecting back to the page on error.
1257 *
bcffdf0c 1258 * @param \CRM_Core_Payment $payment
55f9f634 1259 * @param $value
1260 *
1261 * @return array
1262 */
1263 private function processPayment($payment, $value) {
1264 try {
1a093d07 1265 $params = $this->prepareParamsForPaymentProcessor($value);
1266 $result = $payment->doPayment($params, 'event');
be2fb01f 1267 return [$result, $value];
55f9f634 1268 }
1269 catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
22f9da80 1270 Civi::log()->error('Payment processor exception: ' . $e->getMessage());
55f9f634 1271 CRM_Core_Session::singleton()->setStatus($e->getMessage());
1272 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "id={$this->_eventId}"));
1273 }
be2fb01f 1274 return [];
55f9f634 1275 }
1276
3ae1b2f4 1277 /**
1278 * Clean money fields from the form.
1279 *
1280 * @param array $params
1281 */
1282 protected function cleanMoneyFields(&$params) {
1283 foreach ($this->submittableMoneyFields as $moneyField) {
1284 foreach ($params as $index => $paramField) {
1285 if (isset($paramField[$moneyField])) {
1286 $params[$index][$moneyField] = CRM_Utils_Rule::cleanMoney($paramField[$moneyField]);
1287 }
1288 }
1289 }
1290 }
1291
6a488035 1292}