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