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