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