3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2017 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
30 * @copyright CiviCRM LLC (c) 2004-2017
34 * This class generates form components for processing Event.
36 class CRM_Event_Form_Registration_Confirm
extends CRM_Event_Form_Registration
{
39 * The values for the contribution db object.
53 * Set variables up before form is built.
55 public function preProcess() {
58 // lineItem isn't set until Register postProcess
59 $this->_lineItem
= $this->get('lineItem');
61 $this->_params
= $this->get('params');
62 $this->_params
[0]['tax_amount'] = $this->get('tax_amount');
64 $this->_params
[0]['is_pay_later'] = $this->get('is_pay_later');
65 $this->assign('is_pay_later', $this->_params
[0]['is_pay_later']);
66 if ($this->_params
[0]['is_pay_later']) {
67 $this->assign('pay_later_receipt', $this->_values
['event']['pay_later_receipt']);
70 CRM_Utils_Hook
::eventDiscount($this, $this->_params
);
72 if (!empty($this->_params
[0]['discount']) && !empty($this->_params
[0]['discount']['applied'])) {
73 $this->set('hookDiscount', $this->_params
[0]['discount']);
74 $this->assign('hookDiscount', $this->_params
[0]['discount']);
77 // The concept of contributeMode is deprecated.
78 if ($this->_contributeMode
== 'express') {
80 // rfp == redirect from paypal
81 // rfp is probably not required - the getPreApprovalDetails should deal with any payment-processor specific 'stuff'
82 $rfp = CRM_Utils_Request
::retrieve('rfp', 'Boolean',
83 CRM_Core_DAO
::$_nullObject, FALSE, NULL, 'GET'
86 //we lost rfp in case of additional participant. So set it explicitly.
87 if ($rfp || CRM_Utils_Array
::value('additional_participants', $this->_params
[0], FALSE)) {
88 if (!empty($this->_paymentProcessor
) && $this->_paymentProcessor
['object']->supports('preApproval')) {
89 $preApprovalParams = $this->_paymentProcessor
['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
90 $params = array_merge($this->_params
, $preApprovalParams);
92 CRM_Core_Payment_Form
::mapParams($this->_bltID
, $params, $params, FALSE);
94 // set a few other parameters that are not really specific to this method because we don't know what
95 // will break if we change this.
96 $params['amount'] = $this->_params
[0]['amount'];
97 if (!empty($this->_params
[0]['discount'])) {
98 $params['discount'] = $this->_params
[0]['discount'];
99 $params['discountAmount'] = $this->_params
[0]['discountAmount'];
100 $params['discountMessage'] = $this->_params
[0]['discountMessage'];
103 $params['amount_level'] = $this->_params
[0]['amount_level'];
104 $params['currencyID'] = $this->_params
[0]['currencyID'];
106 // also merge all the other values from the profile fields
107 $values = $this->controller
->exportValues('Register');
110 "street_address-{$this->_bltID}",
111 "city-{$this->_bltID}",
112 "state_province_id-{$this->_bltID}",
113 "postal_code-{$this->_bltID}",
114 "country_id-{$this->_bltID}",
117 foreach ($values as $name => $value) {
119 if (!in_array($name, $skipFields)) {
120 $params[$name] = $value;
122 if (substr($name, 0, 6) == 'price_') {
123 $params[$name] = $this->_params
[0][$name];
126 $this->set('getExpressCheckoutDetails', $params);
128 $this->_params
[0] = array_merge($this->_params
[0], $params);
129 $this->_params
[0]['is_primary'] = 1;
132 //process only primary participant params.
133 $registerParams = $this->_params
[0];
134 if (isset($registerParams["billing_state_province_id-{$this->_bltID}"])
135 && $registerParams["billing_state_province_id-{$this->_bltID}"]
137 $registerParams["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant
::stateProvinceAbbreviation($registerParams["billing_state_province_id-{$this->_bltID}"]);
140 if (isset($registerParams["billing_country_id-{$this->_bltID}"]) && $registerParams["billing_country_id-{$this->_bltID}"]) {
141 $registerParams["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant
::countryIsoCode($registerParams["billing_country_id-{$this->_bltID}"]);
143 if (isset($registerParams['credit_card_exp_date'])) {
144 $registerParams['year'] = CRM_Core_Payment_Form
::getCreditCardExpirationYear($registerParams);
145 $registerParams['month'] = CRM_Core_Payment_Form
::getCreditCardExpirationMonth($registerParams);
147 if ($this->_values
['event']['is_monetary']) {
148 $registerParams['ip_address'] = CRM_Utils_System
::ipAddress();
149 $registerParams['currencyID'] = $this->_params
[0]['currencyID'];
151 //assign back primary participant params.
152 $this->_params
[0] = $registerParams;
155 if ($this->_values
['event']['is_monetary']) {
156 $this->_params
[0]['invoiceID'] = $this->get('invoiceID');
158 $this->assign('defaultRole', FALSE);
159 if (CRM_Utils_Array
::value('defaultRole', $this->_params
[0]) == 1) {
160 $this->assign('defaultRole', TRUE);
163 if (empty($this->_params
[0]['participant_role_id']) &&
164 $this->_values
['event']['default_role_id']
166 $this->_params
[0]['participant_role_id'] = $this->_values
['event']['default_role_id'];
169 if (isset($this->_values
['event']['confirm_title'])) {
170 CRM_Utils_System
::setTitle($this->_values
['event']['confirm_title']);
174 $params = CRM_Contribute_Form_Contribution_Confirm
::processPcp($this, $this->_params
[0]);
175 $this->_params
[0] = $params;
178 $this->set('params', $this->_params
);
182 * Overwrite action, since we are only showing elements in frozen mode no help display needed.
186 public function getAction() {
187 if ($this->_action
& CRM_Core_Action
::PREVIEW
) {
188 return CRM_Core_Action
::VIEW | CRM_Core_Action
::PREVIEW
;
191 return CRM_Core_Action
::VIEW
;
196 * Build the form object.
198 public function buildQuickForm() {
199 $this->assignToTemplate();
201 if ($this->_values
['event']['is_monetary'] &&
202 ($this->_params
[0]['amount'] ||
$this->_params
[0]['amount'] == 0)
204 $this->_amount
= array();
207 foreach ($this->_params
as $k => $v) {
211 $individualTaxAmount = 0;
212 //display tax amount on confirmation page
213 $taxAmount +
= $v['tax_amount'];
219 if (isset($v['billing_' . $name]) &&
222 $v[$name] = $v['billing_' . $name];
226 if (!empty($v['first_name']) && !empty($v['last_name'])) {
227 $append = $v['first_name'] . ' ' . $v['last_name'];
230 //use an email if we have one
231 foreach ($v as $v_key => $v_val) {
232 if (substr($v_key, 0, 6) == 'email-') {
233 $append = $v[$v_key];
238 $this->_amount
[$k]['amount'] = $v['amount'];
239 if (!empty($v['discountAmount'])) {
240 $this->_amount
[$k]['amount'] -= $v['discountAmount'];
243 $this->_amount
[$k]['label'] = preg_replace('/\ 1/', '', $v['amount_level']) . ' - ' . $append;
244 $this->_part
[$k]['info'] = CRM_Utils_Array
::value('first_name', $v) . ' ' . CRM_Utils_Array
::value('last_name', $v);
245 if (empty($v['first_name'])) {
246 $this->_part
[$k]['info'] = $append;
250 $individual[$k]['totalAmtWithTax'] = $this->_amount
[$k]['amount'];
251 $individual[$k]['totalTaxAmt'] = $individualTaxAmount +
$v['tax_amount'];
252 $this->_totalAmount
= $this->_totalAmount +
$this->_amount
[$k]['amount'];
253 if (!empty($v['is_primary'])) {
254 $this->set('primaryParticipantAmount', $this->_amount
[$k]['amount']);
259 $invoiceSettings = Civi
::settings()->get('contribution_invoice_settings');
260 $taxTerm = CRM_Utils_Array
::value('tax_term', $invoiceSettings);
261 $invoicing = CRM_Utils_Array
::value('invoicing', $invoiceSettings);
263 $this->assign('totalTaxAmount', $taxAmount);
264 $this->assign('taxTerm', $taxTerm);
265 $this->assign('individual', $individual);
266 $this->set('individual', $individual);
269 $this->assign('part', $this->_part
);
270 $this->set('part', $this->_part
);
271 $this->assign('amounts', $this->_amount
);
272 $this->assign('totalAmount', $this->_totalAmount
);
273 $this->set('totalAmount', $this->_totalAmount
);
276 if ($this->_priceSetId
&& !CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId
, 'is_quick_config')) {
277 $lineItemForTemplate = array();
278 $getTaxDetails = FALSE;
279 if (!empty($this->_lineItem
) && is_array($this->_lineItem
)) {
280 foreach ($this->_lineItem
as $key => $value) {
281 if (!empty($value)) {
282 $lineItemForTemplate[$key] = $value;
285 foreach ($value as $v) {
286 if (isset($v['tax_rate'])) {
287 $getTaxDetails = TRUE;
293 if (!empty($lineItemForTemplate)) {
294 $this->assign('lineItem', $lineItemForTemplate);
296 $this->assign('getTaxDetails', $getTaxDetails);
299 //display additional participants profile.
300 self
::assignProfiles($this);
302 //consider total amount.
303 $this->assign('isAmountzero', ($this->_totalAmount
<= 0) ?
TRUE : FALSE);
305 $contribButton = ts('Continue');
306 $this->addButtons(array(
309 'name' => ts('Go Back'),
313 'name' => $contribButton,
315 'js' => array('onclick' => "return submitOnce(this,'" . $this->_name
. "','" . ts('Processing') . "');"),
322 if (!empty($this->_fields
)) {
323 foreach ($this->_fields
as $name => $dontCare) {
327 $fields["billing_state_province-{$this->_bltID}"] = $fields["billing_country-{$this->_bltID}"] = $fields["email-{$this->_bltID}"] = 1;
328 foreach ($fields as $name => $dontCare) {
329 if (isset($this->_params
[0][$name])) {
330 $defaults[$name] = $this->_params
[0][$name];
331 if (substr($name, 0, 7) == 'custom_') {
332 $timeField = "{$name}_time";
333 if (isset($this->_params
[0][$timeField])) {
334 $defaults[$timeField] = $this->_params
[0][$timeField];
336 if (isset($this->_params
[0]["{$name}_id"])) {
337 $defaults["{$name}_id"] = $this->_params
[0]["{$name}_id"];
340 elseif (in_array($name, CRM_Contact_BAO_Contact
::$_greetingTypes)
341 && !empty($this->_params
[0][$name . '_custom'])
343 $defaults[$name . '_custom'] = $this->_params
[0][$name . '_custom'];
348 $this->setDefaults($defaults);
351 //lets give meaningful status message, CRM-4320.
352 $this->assign('isOnWaitlist', $this->_allowWaitlist
);
353 $this->assign('isRequireApproval', $this->_requireApproval
);
355 // Assign Participant Count to Lineitem Table
356 $this->assign('pricesetFieldsCount', CRM_Price_BAO_PriceSet
::getPricesetCount($this->_priceSetId
));
357 $this->addFormRule(array('CRM_Event_Form_Registration_Confirm', 'formRule'), $this);
363 * @param array $fields
364 * @param array $files
365 * @param CRM_Core_Form $self
369 public static function formRule($fields, $files, $self) {
371 $eventFull = CRM_Event_BAO_Participant
::eventFull($self->_eventId
, FALSE, CRM_Utils_Array
::value('has_waitlist', $self->_values
['event']));
372 if ($eventFull && empty($self->_allowConfirmation
)) {
373 if (empty($self->_allowWaitlist
)) {
374 CRM_Utils_System
::redirect(CRM_Utils_System
::url('civicrm/event/register', "reset=1&id={$self->_eventId}", FALSE, NULL, FALSE, TRUE));
377 $self->_feeBlock
= $self->_values
['fee'];
378 CRM_Event_Form_Registration_Register
::formatFieldsForOptionFull($self);
380 if (!empty($self->_priceSetId
) &&
381 !$self->_requireApproval
&& !$self->_allowWaitlist
383 $priceSetErrors = self
::validatePriceSet($self, $self->_params
);
384 if (!empty($priceSetErrors)) {
385 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');
386 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');
387 CRM_Utils_System
::redirect(CRM_Utils_System
::url('civicrm/event/register', "_qf_Register_display=true&qfKey={$fields['qfKey']}"));
391 return empty($priceSetErrors) ?
TRUE : $priceSetErrors;
395 * Process the form submission.
397 public function postProcess() {
398 $now = date('YmdHis');
400 $this->_params
= $this->get('params');
401 if (!empty($this->_params
[0]['contact_id'])) {
402 // unclear when this would be set & whether it could be checked in getContactID.
403 // perhaps it relates to when cid is in the url
404 //@todo someone who knows add comments on the various contactIDs in this form
405 $contactID = $this->_params
[0]['contact_id'];
408 $contactID = $this->getContactID();
411 // if a discount has been applied, lets now deduct it from the amount
412 // and fix the fee level
413 if (!empty($this->_params
[0]['discount']) && !empty($this->_params
[0]['discount']['applied'])) {
414 foreach ($this->_params
as $k => $v) {
415 if (CRM_Utils_Array
::value('amount', $this->_params
[$k]) > 0 && !empty($this->_params
[$k]['discountAmount'])) {
416 $this->_params
[$k]['amount'] -= $this->_params
[$k]['discountAmount'];
417 $this->_params
[$k]['amount_level'] .= CRM_Utils_Array
::value('discountMessage', $this->_params
[$k]);
420 $this->set('params', $this->_params
);
423 // CRM-4320, lets build array of cancelled additional participant ids
424 // those are drop or skip by primary at the time of confirmation.
425 // get all in and then unset those we want to process.
426 $cancelledIds = $this->_additionalParticipantIds
;
428 $params = $this->_params
;
429 if ($this->_values
['event']['is_monetary']) {
430 $this->set('finalAmount', $this->_amount
);
432 $participantCount = array();
433 $taxAmount = $totalTaxAmount = 0;
435 //unset the skip participant from params.
436 //build the $participantCount array.
437 //maintain record for all participants.
438 foreach ($params as $participantNum => $record) {
439 if ($record == 'skip') {
440 unset($params[$participantNum]);
441 $participantCount[$participantNum] = 'skip';
443 elseif ($participantNum) {
444 $participantCount[$participantNum] = 'participant';
446 $totalTaxAmount +
= CRM_Utils_Array
::value('tax_amount', $record, 0);
447 if (CRM_Utils_Array
::value('is_primary', $record)) {
448 $taxAmount = &$params[$participantNum]['tax_amount'];
450 //lets get additional participant id to cancel.
451 if ($this->_allowConfirmation
&& is_array($cancelledIds)) {
452 $additonalId = CRM_Utils_Array
::value('participant_id', $record);
453 if ($additonalId && $key = array_search($additonalId, $cancelledIds)) {
454 unset($cancelledIds[$key]);
458 $taxAmount = $totalTaxAmount;
459 $payment = $registerByID = $primaryCurrencyID = $contribution = NULL;
460 $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.');
462 $this->participantIDS
= array();
464 foreach ($params as $key => $value) {
465 CRM_Event_Form_Registration_Confirm
::fixLocationFields($value, $fields, $this);
466 //unset the billing parameters if it is pay later mode
467 //to avoid creation of billing location
468 // @todo - the reasoning for this is unclear - elsewhere we check what fields are provided by
469 // the form & if billing fields exist we create the address, relying on the form to collect
470 // only information we intend to store.
471 if ($this->_allowWaitlist
472 ||
$this->_requireApproval
473 ||
(!empty($value['is_pay_later']) && !$this->_isBillingAddressRequiredForPayLater
)
474 ||
empty($value['is_primary'])
476 $billingFields = array(
477 "email-{$this->_bltID}",
478 'billing_first_name',
479 'billing_middle_name',
481 "billing_street_address-{$this->_bltID}",
482 "billing_city-{$this->_bltID}",
483 "billing_state_province-{$this->_bltID}",
484 "billing_state_province_id-{$this->_bltID}",
485 "billing_postal_code-{$this->_bltID}",
486 "billing_country-{$this->_bltID}",
487 "billing_country_id-{$this->_bltID}",
488 "address_name-{$this->_bltID}",
490 foreach ($billingFields as $field) {
491 unset($value[$field]);
493 if (!empty($value['is_pay_later'])) {
494 $this->_values
['params']['is_pay_later'] = TRUE;
498 //Unset ContactID for additional participants and set RegisterBy Id.
499 if (empty($value['is_primary'])) {
500 $contactID = CRM_Utils_Array
::value('contact_id', $value);
501 $registerByID = $this->get('registerByID');
503 $value['registered_by_id'] = $registerByID;
507 $value['amount'] = $this->_totalAmount
;
510 $contactID = CRM_Event_Form_Registration_Confirm
::updateContactFields($contactID, $value, $fields, $this);
512 // lets store the contactID in the session
513 // we dont store in userID in case the user is doing multiple
515 // for things like tell a friend
516 if (!$this->getContactID() && !empty($value['is_primary'])) {
517 $session = CRM_Core_Session
::singleton();
518 $session->set('transaction.userID', $contactID);
521 $value['description'] = ts('Online Event Registration') . ': ' . $this->_values
['event']['title'];
522 $value['accountingCode'] = CRM_Utils_Array
::value('accountingCode',
523 $this->_values
['event']
527 if ($this->_allowWaitlist ||
$this->_requireApproval
) {
528 //get the participant statuses.
529 $waitingStatuses = CRM_Event_PseudoConstant
::participantStatus(NULL, "class = 'Waiting'");
530 if ($this->_allowWaitlist
) {
531 $value['participant_status_id'] = $value['participant_status'] = array_search('On waitlist', $waitingStatuses);
534 $value['participant_status_id'] = $value['participant_status'] = array_search('Awaiting approval', $waitingStatuses);
537 //there might be case user seleted pay later and
538 //now becomes part of run time waiting list.
539 $value['is_pay_later'] = FALSE;
542 // required only if paid event
543 if ($this->_values
['event']['is_monetary'] && !($this->_allowWaitlist ||
$this->_requireApproval
)) {
544 if (is_array($this->_paymentProcessor
)) {
545 $payment = $this->_paymentProcessor
['object'];
547 if (!empty($this->_paymentProcessor
) && $this->_paymentProcessor
['object']->supports('preApproval')) {
548 $preApprovalParams = $this->_paymentProcessor
['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
549 $value = array_merge($value, $preApprovalParams);
553 if (!empty($value['is_pay_later']) ||
554 $value['amount'] == 0 ||
555 // The concept of contributeMode is deprecated.
556 $this->_contributeMode
== 'checkout' ||
557 $this->_contributeMode
== 'notify'
559 if ($value['amount'] != 0) {
561 //get the participant statuses.
562 $pendingStatuses = CRM_Event_PseudoConstant
::participantStatus(NULL, "class = 'Pending'");
563 $status = !empty($value['is_pay_later']) ?
'Pending from pay later' : 'Pending from incomplete transaction';
564 $value['participant_status_id'] = $value['participant_status'] = array_search($status, $pendingStatuses);
567 elseif (!empty($value['is_primary'])) {
568 CRM_Core_Payment_Form
::mapParams($this->_bltID
, $value, $value, TRUE);
569 // payment email param can be empty for _bltID mapping
570 // thus provide mapping for it with a different email value
571 if (empty($value['email'])) {
572 $value['email'] = CRM_Utils_Array
::valueByRegexKey('/^email-/', $value);
575 if (is_object($payment)) {
576 // Not quite sure why we don't just user $value since it contains the data
578 // @todo ditch $result & retest.
579 list($result, $value) = $this->processPayment($payment, $value);
582 CRM_Core_Error
::fatal($paymentObjError);
586 $value['receive_date'] = $now;
587 if ($this->_allowConfirmation
) {
588 $value['participant_register_date'] = $this->_values
['participant']['register_date'];
591 $createContrib = ($value['amount'] != 0) ?
TRUE : FALSE;
592 // force to create zero amount contribution, CRM-5095
593 if (!$createContrib && ($value['amount'] == 0)
594 && $this->_priceSetId
&& $this->_lineItem
596 $createContrib = TRUE;
599 if ($createContrib && !empty($value['is_primary']) &&
600 !$this->_allowWaitlist
&& !$this->_requireApproval
602 // if paid event add a contribution record
603 //if primary participant contributing additional amount
604 //append (multiple participants) to its fee level. CRM-4196.
605 $isAdditionalAmount = FALSE;
606 if (count($params) > 1) {
607 $isAdditionalAmount = TRUE;
610 //passing contribution id is already registered.
611 $contribution = self
::processContribution($this, $value, $result, $contactID, $pending, $isAdditionalAmount, $this->_paymentProcessor
);
612 $value['contributionID'] = $contribution->id
;
613 $value['contributionTypeID'] = $contribution->financial_type_id
;
614 $value['receive_date'] = $contribution->receive_date
;
615 $value['trxn_id'] = $contribution->trxn_id
;
616 $value['contributionID'] = $contribution->id
;
617 $value['contributionTypeID'] = $contribution->financial_type_id
;
619 $value['contactID'] = $contactID;
620 $value['eventID'] = $this->_eventId
;
621 $value['item_name'] = $value['description'];
624 if (!empty($value['contributionID'])) {
625 $this->_values
['contributionId'] = $value['contributionID'];
629 if (!empty($value['is_primary'])) {
630 $primaryCurrencyID = CRM_Utils_Array
::value('currencyID', $value);
632 if (empty($value['currencyID'])) {
633 $value['currencyID'] = $primaryCurrencyID;
636 // CRM-11182 - Confirmation page might not be monetary
637 if ($this->_values
['event']['is_monetary']) {
638 if (!$pending && !empty($value['is_primary']) &&
639 !$this->_allowWaitlist
&& !$this->_requireApproval
641 // transactionID & receive date required while building email template
642 $this->assign('trxn_id', CRM_Utils_Array
::value('trxn_id', $value));
643 $this->assign('receive_date', CRM_Utils_Date
::mysqlToIso(CRM_Utils_Array
::value('receive_date', $value)));
644 $this->set('receiveDate', CRM_Utils_Date
::mysqlToIso(CRM_Utils_Array
::value('receive_date', $value)));
645 $this->set('trxnId', CRM_Utils_Array
::value('trxn_id', $value));
649 $value['fee_amount'] = CRM_Utils_Array
::value('amount', $value);
650 $this->set('value', $value);
652 // handle register date CRM-4320
653 if ($this->_allowConfirmation
) {
654 $registerDate = CRM_Utils_Array
::value('participant_register_date', $params);
656 elseif (!empty($params['participant_register_date']) &&
657 is_array($params['participant_register_date']) &&
658 !empty($params['participant_register_date'])
660 $registerDate = CRM_Utils_Date
::format($params['participant_register_date']);
663 $registerDate = date('YmdHis');
665 $this->assign('register_date', $registerDate);
667 $this->confirmPostProcess($contactID, $contribution, $payment);
670 //handle if no additional participant.
671 if (!$registerByID) {
672 $registerByID = $this->get('registerByID');
675 $this->set('participantIDs', $this->_participantIDS
);
677 // create line items, CRM-5313
678 if ($this->_priceSetId
&&
679 !empty($this->_lineItem
)
681 // take all processed participant ids.
682 $allParticipantIds = $this->_participantIDS
;
684 // when participant re-walk wizard.
685 if ($this->_allowConfirmation
&&
686 !empty($this->_additionalParticipantIds
)
688 $allParticipantIds = array_merge(array($registerByID), $this->_additionalParticipantIds
);
691 $entityTable = 'civicrm_participant';
692 $invoiceSettings = Civi
::settings()->get('contribution_invoice_settings');
693 $invoicing = CRM_Utils_Array
::value('invoicing', $invoiceSettings);
695 $dataArray = array();
696 foreach ($this->_lineItem
as $key => $value) {
697 if ($value == 'skip') {
700 if ($entityId = CRM_Utils_Array
::value($key, $allParticipantIds)) {
701 // do cleanup line items if participant re-walking wizard.
702 if ($this->_allowConfirmation
) {
703 CRM_Price_BAO_LineItem
::deleteLineItems($entityId, $entityTable);
705 $lineItem[$this->_priceSetId
] = $value;
706 CRM_Price_BAO_LineItem
::processPriceSet($entityId, $lineItem, $contribution, $entityTable);
709 foreach ($value as $line) {
710 if (isset($line['tax_amount']) && isset($line['tax_rate'])) {
711 $totalTaxAmount = $line['tax_amount'] +
$totalTaxAmount;
712 if (isset($dataArray[$line['tax_rate']])) {
713 $dataArray[$line['tax_rate']] = $dataArray[$line['tax_rate']] + CRM_Utils_Array
::value('tax_amount', $line);
716 $dataArray[$line['tax_rate']] = CRM_Utils_Array
::value('tax_amount', $line);
723 $this->assign('dataArray', $dataArray);
724 $this->assign('totalTaxAmount', $totalTaxAmount);
728 //update status and send mail to cancelled additional participants, CRM-4320
729 if ($this->_allowConfirmation
&& is_array($cancelledIds) && !empty($cancelledIds)) {
730 $cancelledId = array_search('Cancelled',
731 CRM_Event_PseudoConstant
::participantStatus(NULL, "class = 'Negative'")
733 CRM_Event_BAO_Participant
::transitionParticipants($cancelledIds, $cancelledId);
737 if ($this->_action
& CRM_Core_Action
::PREVIEW
) {
741 // for Transfer checkout.
742 // The concept of contributeMode is deprecated.
743 if (($this->_contributeMode
== 'checkout' ||
744 $this->_contributeMode
== 'notify'
745 ) && empty($params[0]['is_pay_later']) &&
746 !$this->_allowWaitlist
&& !$this->_requireApproval
&&
747 $this->_totalAmount
> 0
750 $primaryParticipant = $this->get('primaryParticipant');
752 if (empty($primaryParticipant['participantID'])) {
753 $primaryParticipant['participantID'] = $registerByID;
756 //build an array of custom profile and assigning it to template
757 $customProfile = CRM_Event_BAO_Event
::buildCustomProfile($registerByID, $this->_values
, NULL, $isTest);
758 if (count($customProfile)) {
759 $this->assign('customProfile', $customProfile);
760 $this->set('customProfile', $customProfile);
763 // do a transfer only if a monetary payment greater than 0
764 if ($this->_values
['event']['is_monetary'] && $primaryParticipant) {
765 if ($payment && is_object($payment)) {
766 //CRM 14512 provide line items of all participants to payment gateway
767 $primaryContactId = $this->get('primaryContactId');
769 //build an array of cId/pId of participants
770 $additionalIDs = CRM_Event_BAO_Event
::buildCustomProfile($registerByID, NULL, $primaryContactId, $isTest, TRUE);
772 //need to copy, since we are unsetting on the way.
773 $copyParticipantCountLines = $participantCount;
775 //lets carry all participant params w/ values.
776 foreach ($additionalIDs as $participantID => $contactId) {
777 $participantNum = NULL;
778 $participantNum = $participantID;
779 if ($participantID == $registerByID) {
780 // This is the is primary participant.
784 if ($participantNum = array_search('participant', $copyParticipantCountLines)) {
785 //if no participant found break.
786 if ($participantNum === NULL) {
789 //unset current particpant so we don't check them again
790 unset($copyParticipantCountLines[$participantNum]);
793 // get values of line items
794 if ($this->_amount
) {
796 $amount[$participantNum]['label'] = preg_replace('/\ 1/', '', $params[$participantNum]['amount_level']);
797 $amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
798 $params[$participantNum]['amounts'] = $amount;
801 if (!empty($this->_lineItem
)) {
802 $lineItems = $this->_lineItem
;
804 if ($lineItemValue = CRM_Utils_Array
::value($participantNum, $lineItems)) {
805 $lineItem[] = $lineItemValue;
807 $params[$participantNum]['lineItem'] = $lineItem;
810 //only add additional particpants and not the primary particpant as we already have that
811 //added to $primaryParticipant so that this change doesn't break or require changes to
812 //existing gateway implementations
813 $primaryParticipant['participants_info'][$participantID] = $params[$participantNum];
816 //get event custom field information
817 $groupTree = CRM_Core_BAO_CustomGroup
::getTree('Event', NULL, $this->_eventId
, 0, $this->_values
['event']['event_type_id']);
818 $primaryParticipant['eventCustomFields'] = $groupTree;
820 // call postprocess hook before leaving
821 $this->postProcessHook();
822 // this does not return
824 $this->processPayment($payment, $primaryParticipant);
827 CRM_Core_Error
::fatal($paymentObjError);
832 //otherwise send mail Confirmation/Receipt
833 $primaryContactId = $this->get('primaryContactId');
835 //build an array of cId/pId of participants
836 $additionalIDs = CRM_Event_BAO_Event
::buildCustomProfile($registerByID,
837 NULL, $primaryContactId, $isTest,
840 //lets send mails to all with meaningful text, CRM-4320.
841 $this->assign('isOnWaitlist', $this->_allowWaitlist
);
842 $this->assign('isRequireApproval', $this->_requireApproval
);
844 //need to copy, since we are unsetting on the way.
845 $copyParticipantCount = $participantCount;
847 //lets carry all paticipant params w/ values.
848 foreach ($additionalIDs as $participantID => $contactId) {
849 $participantNum = NULL;
850 if ($participantID == $registerByID) {
854 if ($participantNum = array_search('participant', $copyParticipantCount)) {
855 unset($copyParticipantCount[$participantNum]);
858 if ($participantNum === NULL) {
862 //carry the participant submitted values.
863 $this->_values
['params'][$participantID] = $params[$participantNum];
866 foreach ($additionalIDs as $participantID => $contactId) {
868 if ($participantID == $registerByID) {
869 //set as Primary Participant
870 $this->assign('isPrimary', 1);
871 //build an array of custom profile and assigning it to template.
872 $customProfile = CRM_Event_BAO_Event
::buildCustomProfile($participantID, $this->_values
, NULL, $isTest);
874 if (count($customProfile)) {
875 $this->assign('customProfile', $customProfile);
876 $this->set('customProfile', $customProfile);
878 $this->_values
['params']['additionalParticipant'] = FALSE;
881 //take the Additional participant number.
882 if ($participantNum = array_search('participant', $participantCount)) {
883 unset($participantCount[$participantNum]);
885 // Change $this->_values['participant'] to include additional participant values
886 $ids = $participantValues = array();
887 $participantParams = array('id' => $participantID);
888 CRM_Event_BAO_Participant
::getValues($participantParams, $participantValues, $ids);
889 $this->_values
['participant'] = $participantValues[$participantID];
891 $this->assign('isPrimary', 0);
892 $this->assign('customProfile', NULL);
893 //Additional Participant should get only it's payment information
894 if (!empty($this->_amount
)) {
896 $params = $this->get('params');
897 $amount[$participantNum]['label'] = preg_replace('/\ 1/', '', $params[$participantNum]['amount_level']);
898 $amount[$participantNum]['amount'] = $params[$participantNum]['amount'];
899 $this->assign('amounts', $amount);
901 if ($this->_lineItem
) {
902 $lineItems = $this->_lineItem
;
904 if ($lineItemValue = CRM_Utils_Array
::value($participantNum, $lineItems)) {
905 $lineItem[] = $lineItemValue;
908 $individual = $this->get('individual');
909 $dataArray[key($dataArray)] = $individual[$participantNum]['totalTaxAmt'];
910 $this->assign('dataArray', $dataArray);
911 $this->assign('totalAmount', $individual[$participantNum]['totalAmtWithTax']);
912 $this->assign('totalTaxAmount', $individual[$participantNum]['totalTaxAmt']);
913 $this->assign('individual', array($individual[$participantNum]));
915 $this->assign('lineItem', $lineItem);
917 $this->_values
['params']['additionalParticipant'] = TRUE;
918 $this->assign('isAdditionalParticipant', $this->_values
['params']['additionalParticipant']);
921 //pass these variables since these are run time calculated.
922 $this->_values
['params']['isOnWaitlist'] = $this->_allowWaitlist
;
923 $this->_values
['params']['isRequireApproval'] = $this->_requireApproval
;
925 //send mail to primary as well as additional participants.
926 $this->assign('contactID', $contactId);
927 $this->assign('participantID', $participantID);
928 CRM_Event_BAO_Event
::sendMail($contactId, $this->_values
, $participantID, $isTest);
934 * Process the contribution.
936 * @param CRM_Core_Form $form
937 * @param array $params
938 * @param array $result
939 * @param int $contactID
940 * @param bool $pending
941 * @param bool $isAdditionalAmount
943 * @return \CRM_Contribute_BAO_Contribution
945 public static function processContribution(
946 &$form, $params, $result, $contactID,
947 $pending = FALSE, $isAdditionalAmount = FALSE,
948 $paymentProcessor = NULL
950 $transaction = new CRM_Core_Transaction();
952 $now = date('YmdHis');
955 if (!empty($form->_values
['event']['is_email_confirm'])) {
959 if ($isAdditionalAmount) {
960 $params['amount_level'] = $params['amount_level'] . ts(' (multiple participants)') . CRM_Core_DAO
::VALUE_SEPARATOR
;
963 // CRM-20264: fetch CC type ID and number (last 4 digit) and assign it back to $params
964 CRM_Contribute_Form_AbstractEditPayment
::formatCreditCardDetails($params);
966 $contribParams = array(
967 'contact_id' => $contactID,
968 'financial_type_id' => !empty($form->_values
['event']['financial_type_id']) ?
$form->_values
['event']['financial_type_id'] : $params['financial_type_id'],
969 'receive_date' => $now,
970 'total_amount' => $params['amount'],
971 'tax_amount' => $params['tax_amount'],
972 'amount_level' => $params['amount_level'],
973 'invoice_id' => $params['invoiceID'],
974 'currency' => $params['currencyID'],
975 'source' => !empty($params['participant_source']) ?
$params['participant_source'] : $params['description'],
976 'is_pay_later' => CRM_Utils_Array
::value('is_pay_later', $params, 0),
977 'campaign_id' => CRM_Utils_Array
::value('campaign_id', $params),
978 'card_type_id' => CRM_Utils_Array
::value('card_type_id', $params),
979 'pan_truncation' => CRM_Utils_Array
::value('pan_truncation', $params),
982 if ($paymentProcessor) {
983 $contribParams['payment_instrument_id'] = $paymentProcessor['payment_instrument_id'];
984 $contribParams['payment_processor'] = $paymentProcessor['id'];
987 if (!$pending && $result) {
988 $contribParams +
= array(
989 'fee_amount' => CRM_Utils_Array
::value('fee_amount', $result),
990 'net_amount' => CRM_Utils_Array
::value('net_amount', $result, $params['amount']),
991 'trxn_id' => $result['trxn_id'],
992 'receipt_date' => $receiptDate,
996 $allStatuses = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
997 $contribParams['contribution_status_id'] = array_search('Completed', $allStatuses);
999 $contribParams['contribution_status_id'] = array_search('Pending', $allStatuses);
1002 $contribParams['is_test'] = 0;
1003 if ($form->_action
& CRM_Core_Action
::PREVIEW || CRM_Utils_Array
::value('mode', $params) == 'test') {
1004 $contribParams['is_test'] = 1;
1008 if (!empty($contribParams['invoice_id'])) {
1009 $contribID = CRM_Core_DAO
::getFieldValue('CRM_Contribute_DAO_Contribution',
1010 $contribParams['invoice_id'],
1018 $ids['contribution'] = $contribID;
1019 $contribParams['id'] = $contribID;
1022 if (CRM_Contribute_BAO_Contribution
::checkContributeSettings('deferred_revenue_enabled')) {
1023 $eventStartDate = CRM_Utils_Array
::value(
1025 CRM_Utils_Array
::value(
1030 if (strtotime($eventStartDate) > strtotime(date('Ymt'))) {
1031 $contribParams['revenue_recognition_date'] = date('Ymd', strtotime($eventStartDate));
1034 //create an contribution address
1035 // The concept of contributeMode is deprecated. Elsewhere we use the function processBillingAddress() - although
1036 // currently that is only inherited by back-office forms.
1037 if ($form->_contributeMode
!= 'notify' && empty($params['is_pay_later'])) {
1038 $contribParams['address_id'] = CRM_Contribute_BAO_Contribution
::createAddress($params, $form->_bltID
);
1041 $contribParams['skipLineItem'] = 1;
1042 // create contribution record
1043 $contribution = CRM_Contribute_BAO_Contribution
::add($contribParams);
1045 CRM_Event_BAO_Participant
::createDiscountTrxn($form->_eventId
, $contribParams, NULL, CRM_Price_BAO_PriceSet
::parseFirstPriceSetValueIDFromParams($params));
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);
1053 $transaction->commit();
1055 return $contribution;
1059 * Fix the Location Fields.
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.
1066 * @param array $params
1067 * @param array $fields
1068 * @param CRM_Core_Form $form
1070 public static function fixLocationFields(&$params, &$fields, &$form) {
1071 if (!empty($form->_fields
)) {
1072 foreach ($form->_fields
as $name => $dontCare) {
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 = array('first_name', 'middle_name', 'last_name');
1082 foreach ($nameFields as $name) {
1084 if (array_key_exists("billing_$name", $params)) {
1085 $params[$name] = $params["billing_{$name}"];
1086 $params['preserveDBName'] = TRUE;
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;
1098 $fields["email-{$form->_bltID}"] = 1;
1099 $fields['email-Primary'] = 1;
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}"])
1108 $params['email-Primary'] = $params["email-{$form->_bltID}"];
1113 * Update contact fields.
1115 * @param int $contactID
1116 * @param array $params
1117 * @param array $fields
1118 * @param CRM_Core_Form $form
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
1126 // get the add to groups
1127 $addToGroups = array();
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'];
1137 // check for profile double opt-in and get groups to be subscribed
1138 $subscribeGroupIds = CRM_Core_BAO_UFGroup
::getDoubleOptInGroupIds($params, $contactID);
1140 foreach ($addToGroups as $k) {
1141 if (array_key_exists($k, $subscribeGroupIds)) {
1142 unset($addToGroups[$k]);
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]);
1155 $ctype = CRM_Core_DAO
::getFieldValue(
1156 'CRM_Contact_DAO_Contact',
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
1166 unset($params['contact_id']);
1169 $contactID = CRM_Contact_BAO_Contact
::createProfileContact(
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);
1187 $contactID = CRM_Contact_BAO_Contact
::createProfileContact($params,
1195 $form->set('contactID', $contactID);
1198 //get email primary first if exist
1199 $subscribtionEmail = array('email' => CRM_Utils_Array
::value('email-Primary', $params));
1200 if (!$subscribtionEmail['email']) {
1201 $subscribtionEmail['email'] = CRM_Utils_Array
::value("email-{$form->_bltID}", $params);
1203 // subscribing contact to groups
1204 if (!empty($subscribeGroupIds) && $subscribtionEmail['email']) {
1205 CRM_Mailing_Event_BAO_Subscribe
::commonSubscribe($subscribeGroupIds, $subscribtionEmail, $contactID);
1214 * @param CRM_Core_Form $form
1216 public static function assignProfiles(&$form) {
1217 $participantParams = $form->_params
;
1218 $formattedValues = $profileFields = array();
1220 foreach ($participantParams as $participantNum => $participantValue) {
1221 if ($participantNum) {
1222 $prefix1 = 'additional';
1223 $prefix2 = 'additional_';
1229 if ($participantValue != 'skip') {
1230 //get the customPre profile info
1231 if (!empty($form->_values
[$prefix2 . 'custom_pre_id'])) {
1232 $values = $groupName = array();
1233 CRM_Event_BAO_Event
::displayProfile($participantValue,
1234 $form->_values
[$prefix2 . 'custom_pre_id'],
1240 if (count($values)) {
1241 $formattedValues[$count][$prefix1 . 'CustomPre'] = $values;
1243 $formattedValues[$count][$prefix1 . 'CustomPreGroupTitle'] = CRM_Utils_Array
::value('groupTitle', $groupName);
1245 //get the customPost profile info
1246 if (!empty($form->_values
[$prefix2 . 'custom_post_id'])) {
1247 $values = $groupName = array();
1248 foreach ($form->_values
[$prefix2 . 'custom_post_id'] as $gids) {
1250 CRM_Event_BAO_Event
::displayProfile($participantValue,
1256 $values[$gids] = $val;
1257 $groupName[$gids] = $group;
1260 if (count($values)) {
1261 $formattedValues[$count][$prefix1 . 'CustomPost'] = $values;
1264 if (isset($formattedValues[$count][$prefix1 . 'CustomPre'])) {
1265 $formattedValues[$count][$prefix1 . 'CustomPost'] = array_diff_assoc($formattedValues[$count][$prefix1 . 'CustomPost'],
1266 $formattedValues[$count][$prefix1 . 'CustomPre']
1270 $formattedValues[$count][$prefix1 . 'CustomPostGroupTitle'] = $groupName;
1274 $form->_fields
= $profileFields;
1276 if (!empty($formattedValues)) {
1277 $form->assign('primaryParticipantProfile', $formattedValues[1]);
1278 $form->set('primaryParticipantProfile', $formattedValues[1]);
1280 unset($formattedValues[1]);
1281 $form->assign('addParticipantProfile', $formattedValues);
1282 $form->set('addParticipantProfile', $formattedValues);
1288 * Submit in test mode.
1292 public static function testSubmit($params) {
1293 $form = new CRM_Event_Form_Registration_Confirm();
1294 // This way the mocked up controller ignores the session stuff.
1295 $_SERVER['REQUEST_METHOD'] = 'GET';
1296 $_REQUEST['id'] = $form->_eventId
= $params['id'];
1297 $form->controller
= new CRM_Event_Controller_Registration();
1298 $form->_params
= $params['params'];
1299 $form->_amount
= $form->_totalAmount
= CRM_Utils_Array
::value('totalAmount', $params);
1300 $form->set('params', $params['params']);
1301 $form->_values
['custom_pre_id'] = array();
1302 $form->_values
['custom_post_id'] = array();
1303 $form->_values
['event'] = CRM_Utils_Array
::value('event', $params);
1304 $form->_contributeMode
= $params['contributeMode'];
1305 $eventParams = array('id' => $params['id']);
1306 CRM_Event_BAO_Event
::retrieve($eventParams, $form->_values
['event']);
1307 $form->set('registerByID', $params['registerByID']);
1308 if (!empty($params['paymentProcessorObj'])) {
1309 $form->_paymentProcessor
= $params['paymentProcessorObj'];
1311 $form->postProcess();
1315 * Process the payment, redirecting back to the page on error.
1322 private function processPayment($payment, $value) {
1324 $result = $payment->doPayment($value, 'event');
1325 return array($result, $value);
1327 catch (\Civi\Payment\Exception\PaymentProcessorException
$e) {
1328 Civi
::log()->error('Payment processor exception: ' . $e->getMessage());
1329 CRM_Core_Session
::singleton()->setStatus($e->getMessage());
1330 CRM_Utils_System
::redirect(CRM_Utils_System
::url('civicrm/event/register', "id={$this->_eventId}"));