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