Merge pull request #1515 from pdelbar/fixgencode
[civicrm-core.git] / CRM / Event / Form / Registration / Register.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.4 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
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 *
30 *
31 * @package CRM
32 * @copyright CiviCRM LLC (c) 2004-2013
33 * $Id$
34 *
35 */
36
37 /**
38 * This class generates form components for processing Event
39 *
40 */
41 class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
42
43 /**
44 * The fields involved in this page
45 *
46 */
47 public $_fields;
48
49 /**
50 * The defaults involved in this page
51 *
52 */
53 public $_defaults;
54
55 /**
56 * The status message that user view.
57 *
58 */
59 protected $_waitlistMsg = NULL;
60 protected $_requireApprovalMsg = NULL;
61
62 public $_quickConfig = NULL;
63
64 /**
65 * Allow deveopera to use hook_civicrm_buildForm()
66 * to override the registration dupe check
67 * CRM-7604
68 */
69 public $_skipDupeRegistrationCheck = FALSE;
70
71 public $_ppType;
72 public $_snippet;
73
74 /**
75 * Function to set variables up before form is built
76 *
77 * @return void
78 * @access public
79 */
80 function preProcess() {
81 parent::preProcess();
82
83 //CRM-4320.
84 //here we can't use parent $this->_allowWaitlist as user might
85 //walk back and we maight set this value in this postProcess.
86 //(we set when spaces < group count and want to allow become part of waiting )
87 $eventFull = CRM_Event_BAO_Participant::eventFull($this->_eventId, FALSE, CRM_Utils_Array::value('has_waitlist', $this->_values['event']));
88
89 // Get payment processors if appropriate for this event
90 // We hide the payment fields if the event is full or requires approval,
91 // and the current user has not yet been approved CRM-12279
92 $noFees = (($eventFull || $this->_requireApproval) && !$this->_allowConfirmation);
93 CRM_Contribute_Form_Contribution_Main::preProcessPaymentOptions($this, $noFees);
94 if ($this->_snippet) {
95 return;
96 }
97
98 $this->_allowWaitlist = FALSE;
99 if ($eventFull && !$this->_allowConfirmation &&
100 CRM_Utils_Array::value('has_waitlist', $this->_values['event'])
101 ) {
102 $this->_allowWaitlist = TRUE;
103 $this->_waitlistMsg = CRM_Utils_Array::value('waitlist_text', $this->_values['event']);
104 if (!$this->_waitlistMsg) {
105 $this->_waitlistMsg = ts('This event is currently full. However you can register now and get added to a waiting list. You will be notified if spaces become available.');
106 }
107 }
108 $this->set('allowWaitlist', $this->_allowWaitlist);
109
110 //To check if the user is already registered for the event(CRM-2426)
111 if (!$this->_skipDupeRegistrationCheck) {
112 self::checkRegistration(NULL, $this);
113 }
114
115 $this->assign('availableRegistrations', $this->_availableRegistrations);
116
117 // get the participant values from EventFees.php, CRM-4320
118 if ($this->_allowConfirmation) {
119 CRM_Event_Form_EventFees::preProcess($this);
120 }
121 }
122
123 /**
124 * This function sets the default values for the form. For edit/view mode
125 * the default values are retrieved from the database
126 * Adding discussion from CRM-11915 as code comments
127 * When multiple payment processors are configured for a event and user does any selection changes for them on online event registeration page :
128 * The 'Register' page gets loaded through ajax and following happens :
129 * the setDefaults function is called with the variable _ppType set with selected payment processor type,
130 * so in the 'if' condition checked whether the selected payment processor's billing mode is of 'billing form mode'. If its not, don't setDefaults for billing form and return instead.
131 *- For payment processors of billing mode 'Notify' - return from setDefaults before the code for billing profile population execution .
132 * (done this is because for payment processors with 'Notify' mode billing profile form doesn't get rendered on UI)
133 *
134 * @access public
135 *
136 * @return None
137 */
138 function setDefaultValues() {
139 if ($this->_ppType && $this->_snippet && !($this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_FORM)) {
140 // see function comment block for explanation of this
141 return;
142 }
143 $this->_defaults = array();
144 $contactID = $this->getContactID();
145 if ($contactID) {
146 //@todo CRM-11915 I observed that even when the billing block is not present the routine to retrieve the billing defaults is still called - which seems a bit redundant.
147 $billingDefaults = $this->getProfileDefaults('Billing', $contactID);
148 $this->_defaults = array_merge($this->_defaults, $billingDefaults);
149 }
150 $config = CRM_Core_Config::singleton();
151 // set default country from config if no country set
152 if (!CRM_Utils_Array::value("billing_country_id-{$this->_bltID}", $this->_defaults)) {
153 $this->_defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry;
154 }
155
156 if ($this->_snippet) {
157 // now fix all state country selectors
158 CRM_Core_BAO_Address::fixAllStateSelects($this, $this->_defaults);
159 return $this->_defaults;
160 }
161
162 if ($contactID) {
163 $options = array();
164 $fields = array();
165
166 if (!empty($this->_fields)) {
167 $removeCustomFieldTypes = array('Participant');
168 foreach ($this->_fields as $name => $dontCare) {
169 if (substr($name, 0, 7) == 'custom_') {
170 $id = substr($name, 7);
171 if (!$this->_allowConfirmation &&
172 !CRM_Core_BAO_CustomGroup::checkCustomField($id, $removeCustomFieldTypes)
173 ) {
174 continue;
175 }
176 // ignore component fields
177 }
178 elseif ((substr($name, 0, 12) == 'participant_')) {
179 continue;
180 }
181 $fields[$name] = 1;
182 }
183 }
184 }
185
186 if (!empty($fields)) {
187 CRM_Core_BAO_UFGroup::setProfileDefaults($contactID, $fields, $this->_defaults);
188 }
189
190 // now fix all state country selectors
191 CRM_Core_BAO_Address::fixAllStateSelects($this, $this->_defaults);
192
193 // Set default payment processor as default payment_processor radio button value
194 if (!empty($this->_paymentProcessors)) {
195 foreach ($this->_paymentProcessors as $pid => $value) {
196 if (CRM_Utils_Array::value('is_default', $value)) {
197 $this->_defaults['payment_processor'] = $pid;
198 }
199 }
200 }
201
202 //if event is monetary and pay later is enabled and payment
203 //processor is not available then freeze the pay later checkbox with
204 //default check
205 if (CRM_Utils_Array::value('is_pay_later', $this->_values['event']) &&
206 !is_array($this->_paymentProcessor)
207 ) {
208 $this->_defaults['is_pay_later'] = 1;
209 }
210
211 //set custom field defaults
212 if (!empty($this->_fields)) {
213 //load default campaign from page.
214 if (array_key_exists('participant_campaign_id', $this->_fields)) {
215 $this->_defaults['participant_campaign_id'] = CRM_Utils_Array::value('campaign_id',
216 $this->_values['event']
217 );
218 }
219
220 foreach ($this->_fields as $name => $field) {
221 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
222 // fix for CRM-1743
223 if (!isset($this->_defaults[$name])) {
224 CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID, $name, $this->_defaults,
225 NULL, CRM_Profile_Form::MODE_REGISTER
226 );
227 }
228 }
229 }
230 }
231
232 //fix for CRM-3088, default value for discount set.
233 $discountId = NULL;
234 if (!empty($this->_values['discount'])) {
235 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
236 if ($discountId) {
237 if (isset($this->_values['event']['default_discount_fee_id'])) {
238 $discountKey = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue',
239 $this->_values['event']['default_discount_fee_id'],
240 'weight', 'id'
241 );
242
243 $this->_defaults['amount'] = key(array_slice($this->_values['discount'][$discountId],
244 $discountKey - 1, $discountKey, TRUE
245 ));
246 }
247 }
248 }
249
250 // add this event's default participant role to defaults array
251 // (for cases where participant_role field is included in form via profile)
252 if ($this->_values['event']['default_role_id']) {
253 $this->_defaults['participant_role'] =
254 $this->_defaults['participant_role_id'] = $this->_values['event']['default_role_id'];
255 }
256 if ($this->_priceSetId && !empty($this->_feeBlock)) {
257 foreach ($this->_feeBlock as $key => $val) {
258 foreach ($val['options'] as $keys => $values) {
259 if ($values['is_default'] &&
260 !CRM_Utils_Array::value('is_full', $values)
261 ) {
262
263 if ($val['html_type'] == 'CheckBox') {
264 $this->_defaults["price_{$key}"][$keys] = 1;
265 }
266 else {
267 $this->_defaults["price_{$key}"] = $keys;
268 }
269 }
270 }
271 }
272 }
273
274 //set default participant fields, CRM-4320.
275 $hasAdditionalParticipants = FALSE;
276 if ($this->_allowConfirmation) {
277 $this->_contactId = $contactID;
278 $this->_discountId = $discountId;
279 $forcePayLater = CRM_Utils_Array::value('is_pay_later', $this->_defaults, FALSE);
280 $this->_defaults = array_merge($this->_defaults, CRM_Event_Form_EventFees::setDefaultValues($this));
281 $this->_defaults['is_pay_later'] = $forcePayLater;
282
283 if ($this->_additionalParticipantIds) {
284 $hasAdditionalParticipants = TRUE;
285 $this->_defaults['additional_participants'] = count($this->_additionalParticipantIds);
286 }
287 }
288 $this->assign('hasAdditionalParticipants', $hasAdditionalParticipants);
289
290 // //hack to simplify credit card entry for testing
291 // $this->_defaults['credit_card_type'] = 'Visa';
292 // $this->_defaults['credit_card_number'] = '4807731747657838';
293 // $this->_defaults['cvv2'] = '000';
294 // $this->_defaults['credit_card_exp_date'] = array( 'Y' => '2010', 'M' => '05' );
295
296 // to process Custom data that are appended to URL
297 $getDefaults = CRM_Core_BAO_CustomGroup::extractGetParams($this, "'Contact', 'Individual', 'Contribution', 'Participant'");
298 if (!empty($getDefaults)) {
299 $this->_defaults = array_merge($this->_defaults, $getDefaults);
300 }
301
302 return $this->_defaults;
303 }
304
305 /**
306 * Function to build the form
307 *
308 * @return None
309 * @access public
310 */
311 public function buildQuickForm() {
312 // build profiles first so that we can determine address fields etc
313 // and then show copy address checkbox
314 $this->buildCustom($this->_values['custom_pre_id'], 'customPre');
315 $this->buildCustom($this->_values['custom_post_id'], 'customPost');
316
317 if (!empty($this->_fields)) {
318 $profileAddressFields = array();
319 foreach ($this->_fields as $key => $value) {
320 CRM_Core_BAO_UFField::assignAddressField($key, $profileAddressFields);
321 }
322 $this->set('profileAddressFields', $profileAddressFields);
323 }
324
325 // Build payment processor form
326 if ($this->_ppType) {
327 CRM_Core_Payment_ProcessorForm::buildQuickForm($this);
328 // Return if we are in an ajax callback
329 if ($this->_snippet) {
330 return;
331 }
332 }
333
334 $contactID = $this->getContactID();
335 $this->assign('contact_id', $contactID);
336 $this->assign('display_name', CRM_Contact_BAO_Contact::displayName($contactID));
337
338 $this->add('hidden', 'scriptFee', NULL);
339 $this->add('hidden', 'scriptArray', NULL);
340
341 $bypassPayment = $allowGroupOnWaitlist = $isAdditionalParticipants = FALSE;
342 if ($this->_values['event']['is_multiple_registrations']) {
343 // don't allow to add additional during confirmation if not preregistered.
344 if (!$this->_allowConfirmation || $this->_additionalParticipantIds) {
345 // Hardcode maximum number of additional participants here for now. May need to make this configurable per event.
346 // Label is value + 1, since the code sees this is ADDITIONAL participants (in addition to "self")
347 $additionalOptions = array('' => ts('1'), 1 => ts('2'), 2 => ts('3'), 3 => ts('4'), 4 => ts('5'),
348 5 => ts('6'), 6 => ts('7'), 7 => ts('8'), 8 => ts('9'), 9 => ts('10'),
349 );
350 $element = $this->add('select', 'additional_participants',
351 ts('How many people are you registering?'),
352 $additionalOptions,
353 NULL,
354 array('onChange' => "allowParticipant()")
355 );
356 $isAdditionalParticipants = TRUE;
357 }
358 }
359
360 //hack to allow group to register w/ waiting
361 if ((CRM_Utils_Array::value('is_multiple_registrations', $this->_values['event']) ||
362 $this->_priceSetId
363 ) &&
364 !$this->_allowConfirmation &&
365 is_numeric($this->_availableRegistrations)
366 && CRM_Utils_Array::value('has_waitlist', $this->_values['event'])
367 ) {
368 $bypassPayment = TRUE;
369 //case might be group become as a part of waitlist.
370 //If not waitlist then they require admin approve.
371 $allowGroupOnWaitlist = TRUE;
372 $this->_waitlistMsg = ts("This event has only %1 space(s) left. If you continue and register more than %1 people (including yourself ), the whole group will be wait listed. Or, you can reduce the number of people you are registering to %1 to avoid being put on the waiting list.", array(1 => $this->_availableRegistrations));
373
374 if ($this->_requireApproval) {
375 $this->_requireApprovalMsg = CRM_Utils_Array::value('approval_req_text', $this->_values['event'],
376 ts('Registration for this event requires approval. Once your registration(s) have been reviewed, you will receive an email with a link to a web page where you can complete the registration process.')
377 );
378 }
379 }
380
381 //case where only approval needed - no waitlist.
382 if ($this->_requireApproval &&
383 !$this->_allowWaitlist && !$bypassPayment
384 ) {
385 $this->_requireApprovalMsg = CRM_Utils_Array::value('approval_req_text', $this->_values['event'],
386 ts('Registration for this event requires approval. Once your registration has been reviewed, you will receive an email with a link to a web page where you can complete the registration process.')
387 );
388 }
389
390 //lets display status to primary page only.
391 $this->assign('waitlistMsg', $this->_waitlistMsg);
392 $this->assign('requireApprovalMsg', $this->_requireApprovalMsg);
393 $this->assign('allowGroupOnWaitlist', $allowGroupOnWaitlist);
394 $this->assign('isAdditionalParticipants', $isAdditionalParticipants);
395
396 //lets get js on two different qf elements.
397 $showHidePayfieldName = NULL;
398 $showHidePaymentInformation = FALSE;
399 if ($this->_values['event']['is_monetary']) {
400 self::buildAmount($this);
401 }
402
403 $pps = array();
404 //@todo this processor adding fn is another one duplicated on contribute - a shared
405 // common class would make this sort of thing extractable
406 if (!empty($this->_paymentProcessors)) {
407 foreach ($this->_paymentProcessors as $key => $name) {
408 if($name['billing_mode'] == 1) {
409 $onlinePaymentProcessorEnabled = TRUE;
410 }
411 $pps[$key] = $name['name'];
412 }
413 }
414 if($this->getContactID() === '0' && !$this->_values['event']['is_multiple_registrations']) {
415 //@todo we are blocking for multiple registrations because we haven't tested
416 $this->addCidZeroOptions($onlinePaymentProcessorEnabled);
417 }
418 if (CRM_Utils_Array::value('is_pay_later', $this->_values['event']) &&
419 ($this->_allowConfirmation || (!$this->_requireApproval && !$this->_allowWaitlist))
420 ) {
421 $pps[0] = $this->_values['event']['pay_later_text'];
422 }
423
424 if ($this->_values['event']['is_monetary']) {
425 if (count($pps) > 1) {
426 $this->addRadio('payment_processor', ts('Payment Method'), $pps,
427 NULL, "&nbsp;"
428 );
429 }
430 elseif (!empty($pps)) {
431 $ppKeys = array_keys($pps);
432 $currentPP = array_pop($ppKeys);
433 $this->addElement('hidden', 'payment_processor', $currentPP);
434 }
435 }
436
437 //lets add some qf element to bypass payment validations, CRM-4320
438 if ($bypassPayment) {
439 $this->addElement('hidden', 'bypass_payment', NULL, array('id' => 'bypass_payment'));
440 }
441 $this->assign('bypassPayment', $bypassPayment);
442 $this->assign('showHidePaymentInformation', $showHidePaymentInformation);
443
444 $userID = $this->getContactID();
445
446 if (!$userID) {
447 $createCMSUser = FALSE;
448
449 if ($this->_values['custom_pre_id']) {
450 $profileID = $this->_values['custom_pre_id'];
451 $createCMSUser = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $profileID, 'is_cms_user');
452 }
453
454 if (!$createCMSUser &&
455 $this->_values['custom_post_id']
456 ) {
457 if (!is_array($this->_values['custom_post_id'])) {
458 $profileIDs = array($this->_values['custom_post_id']);
459 }
460 else {
461 $profileIDs = $this->_values['custom_post_id'];
462 }
463 foreach ($profileIDs as $pid) {
464 if (CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $pid, 'is_cms_user')) {
465 $profileID = $pid;
466 $createCMSUser = TRUE;
467 break;
468 }
469 }
470 }
471
472 if ($createCMSUser) {
473 CRM_Core_BAO_CMSUser::buildForm($this, $profileID, TRUE);
474 }
475 }
476
477 //we have to load confirm contribution button in template
478 //when multiple payment processor as the user
479 //can toggle with payment processor selection
480 $billingModePaymentProcessors = 0;
481 if (!CRM_Utils_System::isNull($this->_paymentProcessors)) {
482 foreach ($this->_paymentProcessors as $key => $values) {
483 if ($values['billing_mode'] == CRM_Core_Payment::BILLING_MODE_BUTTON) {
484 $billingModePaymentProcessors++;
485 }
486 }
487 }
488
489 if ($billingModePaymentProcessors && count($this->_paymentProcessors) == $billingModePaymentProcessors) {
490 $allAreBillingModeProcessors = TRUE;
491 } else {
492 $allAreBillingModeProcessors = FALSE;
493 }
494
495 if (!$allAreBillingModeProcessors ||
496 CRM_Utils_Array::value('is_pay_later', $this->_values['event']) || $bypassPayment
497 ) {
498
499 //freeze button to avoid multiple calls.
500 $js = NULL;
501
502 if (!CRM_Utils_Array::value('is_monetary', $this->_values['event'])) {
503 $js = array('onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');");
504 }
505 $this->addButtons(array(
506 array(
507 'type' => 'upload',
508 'name' => ts('Continue >>'),
509 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
510 'isDefault' => TRUE,
511 'js' => $js,
512 ),
513 )
514 );
515 }
516
517 $this->addFormRule(array('CRM_Event_Form_Registration_Register', 'formRule'), $this);
518
519 // add pcp fields
520 if ($this->_pcpId) {
521 CRM_PCP_BAO_PCP::buildPcp($this->_pcpId, $this);
522 }
523 }
524
525 /**
526 * build the radio/text form elements for the amount field
527 *
528 * @param object $form form object
529 * @param boolean $required true if you want to add formRule
530 * @param int $discountId discount id for the event
531 *
532 * @return void
533 * @access public
534 * @static
535 */
536 static public function buildAmount(&$form, $required = TRUE, $discountId = NULL) {
537 //if payment done, no need to build the fee block.
538 if (!empty($form->_paymentId)) {
539 //fix to diaplay line item in update mode.
540 $form->assign('priceSet', isset($form->_priceSet) ? $form->_priceSet : NULL);
541 return;
542 }
543
544 $feeFields = CRM_Utils_Array::value('fee', $form->_values);
545
546 if (is_array($feeFields)) {
547 $form->_feeBlock = &$form->_values['fee'];
548 }
549
550 //check for discount.
551 $discountedFee = CRM_Utils_Array::value('discount', $form->_values);
552 if (is_array($discountedFee) && !empty($discountedFee)) {
553 if (!$discountId) {
554 $form->_discountId = $discountId = CRM_Core_BAO_Discount::findSet($form->_eventId, 'civicrm_event');
555 }
556 if ($discountId) {
557 $form->_feeBlock = &$form->_values['discount'][$discountId];
558 }
559 }
560 if (!is_array($form->_feeBlock)) {
561 $form->_feeBlock = array();
562 }
563
564 //its time to call the hook.
565 CRM_Utils_Hook::buildAmount('event', $form, $form->_feeBlock);
566
567 //reset required if participant is skipped.
568 $button = substr($form->controller->getButtonName(), -4);
569 if ($required && $button == 'skip') {
570 $required = FALSE;
571 }
572
573 $className = CRM_Utils_System::getClassName($form);
574
575 //build the priceset fields.
576 if (isset($form->_priceSetId) && $form->_priceSetId) {
577
578 //format price set fields across option full.
579 self::formatFieldsForOptionFull($form);
580
581 if (CRM_Utils_Array::value('is_quick_config', $form->_priceSet)) {
582 $form->_quickConfig = $form->_priceSet['is_quick_config'];
583 }
584 $form->add('hidden', 'priceSetId', $form->_priceSetId);
585
586 foreach ($form->_feeBlock as $field) {
587 if (CRM_Utils_Array::value('visibility', $field) == 'public' ||
588 $className == 'CRM_Event_Form_Participant'
589 ) {
590 $fieldId = $field['id'];
591 $elementName = 'price_' . $fieldId;
592
593 $isRequire = CRM_Utils_Array::value('is_required', $field);
594 if ($button == 'skip') {
595 $isRequire = FALSE;
596 }
597
598 //user might modified w/ hook.
599 $options = CRM_Utils_Array::value('options', $field);
600 if (!is_array($options)) {
601 continue;
602 }
603
604 $optionFullIds = CRM_Utils_Array::value('option_full_ids', $field, array());
605
606 //soft suppress required rule when option is full.
607 if (!empty($optionFullIds) && (count($options) == count($optionFullIds))) {
608 $isRequire = FALSE;
609 }
610
611 //build the element.
612 CRM_Price_BAO_PriceField::addQuickFormElement($form,
613 $elementName,
614 $fieldId,
615 FALSE,
616 $isRequire,
617 NULL,
618 $options,
619 $optionFullIds
620 );
621 }
622 }
623 $form->assign('priceSet', $form->_priceSet);
624 }
625 else {
626 $eventFeeBlockValues = array();
627 foreach ($form->_feeBlock as $fee) {
628 if (is_array($fee)) {
629
630 //CRM-7632, CRM-6201
631 $totalAmountJs = NULL;
632 if ($className == 'CRM_Event_Form_Participant') {
633 $totalAmountJs = array('onClick' => "fillTotalAmount(" . $fee['value'] . ")");
634 }
635
636 $eventFeeBlockValues['amount_id_' . $fee['amount_id']] = $fee['value'];
637 $elements[] = &$form->createElement('radio', NULL, '',
638 CRM_Utils_Money::format($fee['value']) . ' ' .
639 $fee['label'],
640 $fee['amount_id'],
641 $totalAmountJs
642 );
643 }
644 }
645 $form->assign('eventFeeBlockValues', json_encode($eventFeeBlockValues));
646
647 $form->_defaults['amount'] = CRM_Utils_Array::value('default_fee_id', $form->_values['event']);
648 $element = &$form->addGroup($elements, 'amount', ts('Event Fee(s)'), '<br />');
649 if (isset($form->_online) && $form->_online) {
650 $element->freeze();
651 }
652 if ($required) {
653 $form->addRule('amount', ts('Fee Level is a required field.'), 'required');
654 }
655 }
656 }
657
658 public static function formatFieldsForOptionFull(&$form) {
659 $priceSet = $form->get('priceSet');
660 $priceSetId = $form->get('priceSetId');
661 if (!$priceSetId ||
662 !is_array($priceSet) ||
663 empty($priceSet) ||
664 !CRM_Utils_Array::value('optionsMaxValueTotal', $priceSet)
665 ) {
666 return;
667 }
668
669 $skipParticipants = $formattedPriceSetDefaults = array();
670 if ($form->_allowConfirmation && (isset($form->_pId) || isset($form->_additionalParticipantId))) {
671 $participantId = isset($form->_pId) ? $form->_pId : $form->_additionalParticipantId;
672 $pricesetDefaults = CRM_Event_Form_EventFees::setDefaultPriceSet($participantId,
673 $form->_eventId
674 );
675 // modify options full to respect the selected fields
676 // options on confirmation.
677 $formattedPriceSetDefaults = self::formatPriceSetParams($form, $pricesetDefaultOptions);
678
679 // to skip current registered participants fields option count on confirmation.
680 $skipParticipants[] = $form->_participantId;
681 if (!empty($form->_additionalParticipantIds)) {
682 $skipParticipants = array_merge($skipParticipants, $form->_additionalParticipantIds);
683 }
684 }
685
686 $className = CRM_Utils_System::getClassName($form);
687
688 //get the current price event price set options count.
689 $currentOptionsCount = self::getPriceSetOptionCount($form);
690 $recordedOptionsCount = CRM_Event_BAO_Participant::priceSetOptionsCount($form->_eventId, $skipParticipants);
691
692 foreach ($form->_feeBlock as & $field) {
693 $optionFullIds = array();
694 $fieldId = $field['id'];
695 if (!is_array($field['options'])) {
696 continue;
697 }
698 foreach ($field['options'] as & $option) {
699 $optId = $option['id'];
700 $count = CRM_Utils_Array::value('count', $option, 0);
701 $maxValue = CRM_Utils_Array::value('max_value', $option, 0);
702 $dbTotalCount = CRM_Utils_Array::value($optId, $recordedOptionsCount, 0);
703 $currentTotalCount = CRM_Utils_Array::value($optId, $currentOptionsCount, 0);
704
705 // Do not consider current count for select field,
706 // since we are not going to freeze the options.
707 if ($field['html_type'] == 'Select') {
708 $totalCount = $dbTotalCount;
709 }
710 else {
711 $totalCount = $currentTotalCount + $dbTotalCount;
712 }
713
714 $isFull = FALSE;
715 if ($maxValue &&
716 (($totalCount >= $maxValue) || ($totalCount + $count > $maxValue))
717 ) {
718 $isFull = TRUE;
719 $optionFullIds[$optId] = $optId;
720 }
721
722 //here option is not full,
723 //but we don't want to allow participant to increase
724 //seats at the time of re-walking registration.
725 if ($count &&
726 $form->_allowConfirmation &&
727 !empty($formattedPriceSetDefaults)
728 ) {
729 if (!CRM_Utils_Array::value("price_{$field}", $formattedPriceSetDefaults) ||
730 !CRM_Utils_Array::value($opId, $formattedPriceSetDefaults["price_{$fieldId}"])
731 ) {
732 $optionFullIds[$optId] = $optId;
733 $isFull = TRUE;
734 }
735 }
736 $option['is_full'] = $isFull;
737 $option['db_total_count'] = $dbTotalCount;
738 $option['total_option_count'] = $dbTotalCount + $currentTotalCount;
739 }
740
741 //ignore option full for offline registration.
742 if ($className == 'CRM_Event_Form_Participant') {
743 $optionFullIds = array();
744 }
745
746 //finally get option ids in.
747 $field['option_full_ids'] = $optionFullIds;
748 }
749 }
750
751 /**
752 * global form rule
753 *
754 * @param array $fields the input form values
755 * @param array $files the uploaded files if any
756 * @param array $options additional user data
757 *
758 * @return true if no errors, else array of errors
759 * @access public
760 * @static
761 */
762 static function formRule($fields, $files, $self) {
763 $errors = array();
764 //check that either an email or firstname+lastname is included in the form(CRM-9587)
765 self::checkProfileComplete($fields, $errors, $self->_eventId);
766 //To check if the user is already registered for the event(CRM-2426)
767 if (!$self->_skipDupeRegistrationCheck) {
768 self::checkRegistration($fields, $self);
769 }
770 //check for availability of registrations.
771 if (!$self->_allowConfirmation &&
772 !CRM_Utils_Array::value('bypass_payment', $fields) &&
773 is_numeric($self->_availableRegistrations) &&
774 CRM_Utils_Array::value('additional_participants', $fields) >= $self->_availableRegistrations
775 ) {
776 $errors['additional_participants'] = ts("There is only enough space left on this event for %1 participant(s).", array(1 => $self->_availableRegistrations));
777 }
778
779 // during confirmation don't allow to increase additional participants, CRM-4320
780 if ($self->_allowConfirmation &&
781 CRM_Utils_Array::value('additional_participants', $fields) &&
782 is_array($self->_additionalParticipantIds) &&
783 $fields['additional_participants'] > count($self->_additionalParticipantIds)
784 ) {
785 $errors['additional_participants'] = ts("Oops. It looks like you are trying to increase the number of additional people you are registering for. You can confirm registration for a maximum of %1 additional people.", array(1 => count($self->_additionalParticipantIds)));
786 }
787
788 //don't allow to register w/ waiting if enough spaces available.
789 if (CRM_Utils_Array::value('bypass_payment', $fields)) {
790 if (!is_numeric($self->_availableRegistrations) ||
791 (!CRM_Utils_Array::value('priceSetId', $fields) && CRM_Utils_Array::value('additional_participants', $fields) < $self->_availableRegistrations)
792 ) {
793 $errors['bypass_payment'] = ts("Oops. There are enough available spaces in this event. You can not add yourself to the waiting list.");
794 }
795 }
796
797 if (CRM_Utils_Array::value('additional_participants', $fields) &&
798 !CRM_Utils_Rule::positiveInteger($fields['additional_participants'])
799 ) {
800 $errors['additional_participants'] = ts('Please enter a whole number for Number of additional people.');
801 }
802
803 // priceset validations
804 if (CRM_Utils_Array::value('priceSetId', $fields)) {
805 //format params.
806 $formatted = self::formatPriceSetParams($self, $fields);
807 $ppParams = array($formatted);
808 $priceSetErrors = self::validatePriceSet($self, $ppParams);
809 $primaryParticipantCount = self::getParticipantCount($self, $ppParams);
810
811 //get price set fields errors in.
812 $errors = array_merge($errors, CRM_Utils_Array::value(0, $priceSetErrors, array()));
813
814 $totalParticipants = $primaryParticipantCount;
815 if (CRM_Utils_Array::value('additional_participants', $fields)) {
816 $totalParticipants += $fields['additional_participants'];
817 }
818
819 if (!CRM_Utils_Array::value('bypass_payment', $fields) &&
820 !$self->_allowConfirmation &&
821 is_numeric($self->_availableRegistrations) &&
822 $self->_availableRegistrations < $totalParticipants
823 ) {
824 $errors['_qf_default'] = ts("Only %1 Registrations available.", array(1 => $self->_availableRegistrations));
825 }
826
827 $lineItem = array();
828 CRM_Price_BAO_PriceSet::processAmount($self->_values['fee'], $fields, $lineItem);
829 if ($fields['amount'] < 0) {
830 $errors['_qf_default'] = ts('Event Fee(s) can not be less than zero. Please select the options accordingly');
831 }
832 }
833
834 if ($self->_values['event']['is_monetary']) {
835 if ($fields['amount'] > 0 && !isset($fields['payment_processor'])) {
836 $errors['payment_processor'] = ts('Please select a Payment Method');
837 }
838 if (is_array($self->_paymentProcessor)) {
839 $payment = CRM_Core_Payment::singleton($self->_mode, $self->_paymentProcessor, $this);
840 $error = $payment->checkConfig($self->_mode);
841 if ($error) {
842 $errors['_qf_default'] = $error;
843 }
844 }
845 // return if this is express mode
846 if ($self->_paymentProcessor &&
847 $self->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON
848 ) {
849 if (CRM_Utils_Array::value($self->_expressButtonName . '_x', $fields) ||
850 CRM_Utils_Array::value($self->_expressButtonName . '_y', $fields) ||
851 CRM_Utils_Array::value($self->_expressButtonName, $fields)
852 ) {
853 return empty($errors) ? TRUE : $errors;
854 }
855 }
856
857 $isZeroAmount = $skipPaymentValidation = FALSE;
858 if (CRM_Utils_Array::value('priceSetId', $fields)) {
859 if (CRM_Utils_Array::value('amount', $fields) == 0) {
860 $isZeroAmount = TRUE;
861 }
862 }
863 elseif (CRM_Utils_Array::value('amount', $fields) &&
864 (isset($self->_values['discount'][$fields['amount']])
865 && CRM_Utils_Array::value('value', $self->_values['discount'][$fields['amount']]) == 0
866 )
867 ) {
868 $isZeroAmount = TRUE;
869 }
870 elseif (CRM_Utils_Array::value('amount', $fields) &&
871 (isset($self->_values['fee'][$fields['amount']])
872 && CRM_Utils_Array::value('value', $self->_values['fee'][$fields['amount']]) == 0
873 )
874 ) {
875 $isZeroAmount = TRUE;
876 }
877
878 if ($isZeroAmount && !($self->_forcePayement && CRM_Utils_Array::value('additional_participants', $fields))) {
879 $skipPaymentValidation = TRUE;
880 }
881
882 // also return if paylater mode or zero fees for valid members
883 if (CRM_Utils_Array::value('is_pay_later', $fields) ||
884 CRM_Utils_Array::value('bypass_payment', $fields) ||
885 $skipPaymentValidation ||
886 (!$self->_allowConfirmation && ($self->_requireApproval || $self->_allowWaitlist))
887 ) {
888 return empty($errors) ? TRUE : $errors;
889 }
890 if (!empty($self->_paymentFields)) {
891 CRM_Core_Form::validateMandatoryFields($self->_paymentFields, $fields, $errors);
892 }
893 CRM_Core_Payment_Form::validateCreditCard($fields, $errors);
894 }
895
896 foreach (CRM_Contact_BAO_Contact::$_greetingTypes as $greeting) {
897 if ($greetingType = CRM_Utils_Array::value($greeting, $fields)) {
898 $customizedValue = CRM_Core_OptionGroup::getValue($greeting, 'Customized', 'name');
899 if ($customizedValue == $greetingType && empty($fields[$greeting . '_custom'])) {
900 $errors[$customizedGreeting] = ts('Custom %1 is a required field if %1 is of type Customized.',
901 array(1 => ucwords(str_replace('_', ' ', $greeting)))
902 );
903 }
904 }
905 }
906 return empty($errors) ? TRUE : $errors;
907 }
908
909 /**
910 * Check if profiles are complete when event registration occurs(CRM-9587)
911 *
912 */
913 static function checkProfileComplete($fields, &$errors, $eventId) {
914 $email = '';
915 foreach ($fields as $fieldname => $fieldvalue) {
916 if (substr($fieldname, 0, 6) == 'email-' && $fieldvalue) {
917 $email = $fieldvalue;
918 }
919 }
920
921 if (!$email && !(CRM_Utils_Array::value('first_name', $fields) &&
922 CRM_Utils_Array::value('last_name', $fields)
923 )) {
924 $defaults = $params = array('id' => $eventId);
925 CRM_Event_BAO_Event::retrieve($params, $defaults);
926 $message = ts("Mandatory fields (first name and last name, OR email address) are missing from this form.");
927 $errors['_qf_default'] = $message;
928 }
929 }
930
931 /**
932 * Function to process the form
933 *
934 * @access public
935 *
936 * @return None
937 */
938 public function postProcess() {
939 // get the submitted form values.
940 $params = $this->controller->exportValues($this->_name);
941
942 //set as Primary participant
943 $params['is_primary'] = 1;
944
945 if ($this->_values['event']['is_pay_later'] && !array_key_exists('hidden_processor', $params)) {
946 $params['is_pay_later'] = 1;
947 }
948 else {
949 $params['is_pay_later'] = 0;
950 }
951
952 $this->set('is_pay_later', $params['is_pay_later']);
953
954 // assign pay later stuff
955 $this->_params['is_pay_later'] = CRM_Utils_Array::value('is_pay_later', $params, FALSE);
956 $this->assign('is_pay_later', $params['is_pay_later']);
957 if ($params['is_pay_later']) {
958 $this->assign('pay_later_text', $this->_values['event']['pay_later_text']);
959 $this->assign('pay_later_receipt', $this->_values['event']['pay_later_receipt']);
960 }
961
962 if (!$this->_allowConfirmation) {
963 // check if the participant is already registered
964 if (!$this->_skipDupeRegistrationCheck) {
965 $params['contact_id'] = self::checkRegistration($params, $this, FALSE, TRUE, TRUE);
966 }
967 }
968
969 if (CRM_Utils_Array::value('image_URL', $params)) {
970 CRM_Contact_BAO_Contact::processImageParams($params);
971 }
972
973 //carry campaign to partcipants.
974 if (array_key_exists('participant_campaign_id', $params)) {
975 $params['campaign_id'] = $params['participant_campaign_id'];
976 }
977 else {
978 $params['campaign_id'] = CRM_Utils_Array::value('campaign_id', $this->_values['event']);
979 }
980
981 //hack to allow group to register w/ waiting
982 $primaryParticipantCount = self::getParticipantCount($this, $params);
983
984 $totalParticipants = $primaryParticipantCount;
985 if (CRM_Utils_Array::value('additional_participants', $params)) {
986 $totalParticipants += $params['additional_participants'];
987 }
988 if (!$this->_allowConfirmation &&
989 CRM_Utils_Array::value('bypass_payment', $params) &&
990 is_numeric($this->_availableRegistrations) &&
991 $totalParticipants > $this->_availableRegistrations
992 ) {
993 $this->_allowWaitlist = TRUE;
994 $this->set('allowWaitlist', TRUE);
995 }
996
997 //carry participant id if pre-registered.
998 if ($this->_allowConfirmation && $this->_participantId) {
999 $params['participant_id'] = $this->_participantId;
1000 }
1001
1002 $params['defaultRole'] = 1;
1003 if (array_key_exists('participant_role', $params)) {
1004 $params['participant_role_id'] = $params['participant_role'];
1005 }
1006
1007 if (array_key_exists('participant_role_id', $params)) {
1008 $params['defaultRole'] = 0;
1009 }
1010 if (!CRM_Utils_Array::value('participant_role_id', $params) &&
1011 $this->_values['event']['default_role_id']
1012 ) {
1013 $params['participant_role_id'] = $this->_values['event']['default_role_id'];
1014 }
1015
1016 $config = CRM_Core_Config::singleton();
1017 $params['currencyID'] = $config->defaultCurrency;
1018
1019 if ($this->_values['event']['is_monetary']) {
1020 // we first reset the confirm page so it accepts new values
1021 $this->controller->resetPage('Confirm');
1022
1023 //added for discount
1024 $discountId = CRM_Core_BAO_Discount::findSet($this->_eventId, 'civicrm_event');
1025
1026 if (!empty($this->_values['discount'][$discountId])) {
1027 $params['discount_id'] = $discountId;
1028 $params['amount_level'] = $this->_values['discount'][$discountId][$params['amount']]['label'];
1029
1030 $params['amount'] = $this->_values['discount'][$discountId][$params['amount']]['value'];
1031 }
1032 elseif (empty($params['priceSetId'])) {
1033 $params['amount_level'] = $this->_values['fee'][$params['amount']]['label'];
1034 $params['amount'] = $this->_values['fee'][$params['amount']]['value'];
1035 }
1036 else {
1037 $lineItem = array();
1038 CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem);
1039 $this->set('lineItem', array($lineItem));
1040 $this->set('lineItemParticipantsCount', array($primaryParticipantCount));
1041 }
1042
1043 $this->set('amount', $params['amount']);
1044 $this->set('amount_level', $params['amount_level']);
1045
1046 // generate and set an invoiceID for this transaction
1047 $invoiceID = md5(uniqid(rand(), TRUE));
1048 $this->set('invoiceID', $invoiceID);
1049
1050 if (is_array($this->_paymentProcessor)) {
1051 $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this);
1052 }
1053 // default mode is direct
1054 $this->set('contributeMode', 'direct');
1055
1056 if (isset($params["state_province_id-{$this->_bltID}"]) &&
1057 $params["state_province_id-{$this->_bltID}"]
1058 ) {
1059 $params["state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($params["state_province_id-{$this->_bltID}"]);
1060 }
1061
1062 if (isset($params["country_id-{$this->_bltID}"]) &&
1063 $params["country_id-{$this->_bltID}"]
1064 ) {
1065 $params["country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($params["country_id-{$this->_bltID}"]);
1066 }
1067 if (isset($params['credit_card_exp_date'])) {
1068 $params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($params);
1069 $params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($params);
1070 }
1071 if ($this->_values['event']['is_monetary']) {
1072 $params['ip_address'] = CRM_Utils_System::ipAddress();
1073 $params['currencyID'] = $config->defaultCurrency;
1074 $params['payment_action'] = 'Sale';
1075 $params['invoiceID'] = $invoiceID;
1076 }
1077
1078 $this->_params = array();
1079 $this->_params[] = $params;
1080 $this->set('params', $this->_params);
1081
1082 if ($this->_paymentProcessor &&
1083 $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON
1084 ) {
1085 //get the button name
1086 $buttonName = $this->controller->getButtonName();
1087 if (in_array($buttonName,
1088 array(
1089 $this->_expressButtonName,
1090 $this->_expressButtonName . '_x',
1091 $this->_expressButtonName . '_y',
1092 )
1093 ) &&
1094 !CRM_Utils_Array::value('is_pay_later', $params) &&
1095 !$this->_allowWaitlist &&
1096 !$this->_requireApproval
1097 ) {
1098 $this->set('contributeMode', 'express');
1099
1100 // Send Event Name & Id in Params
1101 $params['eventName'] = $this->_values['event']['title'];
1102 $params['eventId'] = $this->_values['event']['id'];
1103
1104 $params['cancelURL'] = CRM_Utils_System::url('civicrm/event/register',
1105 "_qf_Register_display=1&qfKey={$this->controller->_key}",
1106 TRUE, NULL, FALSE
1107 );
1108 if (CRM_Utils_Array::value('additional_participants', $params, FALSE)) {
1109 $urlArgs = "_qf_Participant_1_display=1&rfp=1&qfKey={$this->controller->_key}";
1110 }
1111 else {
1112 $urlArgs = "_qf_Confirm_display=1&rfp=1&qfKey={$this->controller->_key}";
1113 }
1114 $params['returnURL'] = CRM_Utils_System::url('civicrm/event/register',
1115 $urlArgs,
1116 TRUE, NULL, FALSE
1117 );
1118 $params['invoiceID'] = $invoiceID;
1119
1120 //default action is Sale
1121 $params['payment_action'] = 'Sale';
1122
1123 $token = $payment->setExpressCheckout($params);
1124 if (is_a($token, 'CRM_Core_Error')) {
1125 CRM_Core_Error::displaySessionError($token);
1126 CRM_Utils_System::redirect($params['cancelURL']);
1127 }
1128
1129 $this->set('token', $token);
1130
1131 $paymentURL = $this->_paymentProcessor['url_site'] . "/cgi-bin/webscr?cmd=_express-checkout&token=$token";
1132
1133 CRM_Utils_System::redirect($paymentURL);
1134 }
1135 }
1136 elseif ($this->_paymentProcessor &&
1137 $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY
1138 ) {
1139 $this->set('contributeMode', 'notify');
1140 }
1141 }
1142 else {
1143 $session = CRM_Core_Session::singleton();
1144 $params['description'] = ts('Online Event Registration') . ' ' . $this->_values['event']['title'];
1145
1146 $this->_params = array();
1147 $this->_params[] = $params;
1148 $this->set('params', $this->_params);
1149
1150 if (!CRM_Utils_Array::value('additional_participants', $params)) {
1151 self::processRegistration($this->_params);
1152 }
1153 }
1154
1155 // If registering > 1 participant, give status message
1156 if (CRM_Utils_Array::value('additional_participants', $params, FALSE)) {
1157 $statusMsg = ts('Registration information for participant 1 has been saved.');
1158 CRM_Core_Session::setStatus($statusMsg, ts('Saved'), 'success');
1159 }
1160 }
1161 //end of function
1162
1163 /*
1164 * Function to process Registration of free event
1165 *
1166 * @param array $param Form valuess
1167 * @param int contactID
1168 *
1169 * @return None
1170 * access public
1171 *
1172 */
1173 public function processRegistration($params, $contactID = NULL) {
1174 $session = CRM_Core_Session::singleton();
1175 $this->_participantInfo = array();
1176
1177 // CRM-4320, lets build array of cancelled additional participant ids
1178 // those are drop or skip by primary at the time of confirmation.
1179 // get all in and then unset those are confirmed.
1180 $cancelledIds = $this->_additionalParticipantIds;
1181
1182 $participantCount = array();
1183 foreach ($params as $participantNum => $record) {
1184 if ($record == 'skip') {
1185 $participantCount[$participantNum] = 'skip';
1186 }
1187 elseif ($participantNum) {
1188 $participantCount[$participantNum] = 'participant';
1189 }
1190 }
1191
1192 $registerByID = NULL;
1193 foreach ($params as $key => $value) {
1194 if ($value != 'skip') {
1195 $fields = NULL;
1196
1197 // setting register by Id and unset contactId.
1198 if (!CRM_Utils_Array::value('is_primary', $value)) {
1199 $contactID = NULL;
1200 $registerByID = $this->get('registerByID');
1201 if ($registerByID) {
1202 $value['registered_by_id'] = $registerByID;
1203 }
1204 // get an email if one exists for the participant
1205 $participantEmail = '';
1206 foreach (array_keys($value) as $valueName) {
1207 if (substr($valueName, 0, 6) == 'email-') {
1208 $participantEmail = $value[$valueName];
1209 }
1210 }
1211 if ($participantEmail) {
1212 $this->_participantInfo[] = $participantEmail;
1213 }
1214 else {
1215 $this->_participantInfo[] = $value['first_name'] . ' ' . $value['last_name'];
1216 }
1217 }
1218 elseif (CRM_Utils_Array::value('contact_id', $value)) {
1219 $contactID = $value['contact_id'];
1220 }
1221 else {
1222 $contactID = $this->getContactID();
1223 }
1224
1225 CRM_Event_Form_Registration_Confirm::fixLocationFields($value, $fields);
1226 //for free event or additional participant, dont create billing email address.
1227 if (!CRM_Utils_Array::value('is_primary', $value) || !$this->_values['event']['is_monetary']) {
1228 unset($value["email-{$this->_bltID}"]);
1229 }
1230
1231 $contactID = CRM_Event_Form_Registration_Confirm::updateContactFields($contactID, $value, $fields);
1232
1233 // lets store the contactID in the session
1234 // we dont store in userID in case the user is doing multiple
1235 // transactions etc
1236 // for things like tell a friend
1237 if (!$this->getContactID() && CRM_Utils_Array::value('is_primary', $value)) {
1238 $session->set('transaction.userID', $contactID);
1239 }
1240
1241 //lets get the status if require approval or waiting.
1242
1243 $waitingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Waiting'");
1244 if ($this->_allowWaitlist && !$this->_allowConfirmation) {
1245 $value['participant_status_id'] = $value['participant_status'] = array_search('On waitlist', $waitingStatuses);
1246 }
1247 elseif ($this->_requireApproval && !$this->_allowConfirmation) {
1248 $value['participant_status_id'] = $value['participant_status'] = array_search('Awaiting approval', $waitingStatuses);
1249 }
1250
1251 $this->set('value', $value);
1252 $this->confirmPostProcess($contactID, NULL, NULL);
1253
1254 //lets get additional participant id to cancel.
1255 if ($this->_allowConfirmation && is_array($cancelledIds)) {
1256 $additonalId = CRM_Utils_Array::value('participant_id', $value);
1257 if ($additonalId && $key = array_search($additonalId, $cancelledIds)) {
1258 unset($cancelledIds[$key]);
1259 }
1260 }
1261 }
1262 }
1263
1264 // update status and send mail to cancelled additonal participants, CRM-4320
1265 if ($this->_allowConfirmation && is_array($cancelledIds) && !empty($cancelledIds)) {
1266 $cancelledId = array_search('Cancelled',
1267 CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Negative'")
1268 );
1269 CRM_Event_BAO_Participant::transitionParticipants($cancelledIds, $cancelledId);
1270 }
1271
1272 //set information about additional participants if exists
1273 if (count($this->_participantInfo)) {
1274 $this->set('participantInfo', $this->_participantInfo);
1275 }
1276
1277 //send mail Confirmation/Receipt
1278 if ($this->_contributeMode != 'checkout' ||
1279 $this->_contributeMode != 'notify'
1280 ) {
1281 $isTest = FALSE;
1282 if ($this->_action & CRM_Core_Action::PREVIEW) {
1283 $isTest = TRUE;
1284 }
1285
1286 //handle if no additional participant.
1287 if (!$registerByID) {
1288 $registerByID = $this->get('registerByID');
1289 }
1290 $primaryContactId = $this->get('primaryContactId');
1291
1292 //build an array of custom profile and assigning it to template.
1293 $additionalIDs = CRM_Event_BAO_Event::buildCustomProfile($registerByID, NULL,
1294 $primaryContactId, $isTest, TRUE
1295 );
1296
1297 //lets carry all paticipant params w/ values.
1298 foreach ($additionalIDs as $participantID => $contactId) {
1299 $participantNum = NULL;
1300 if ($participantID == $registerByID) {
1301 $participantNum = 0;
1302 }
1303 else {
1304 if ($participantNum = array_search('participant', $participantCount)) {
1305 unset($participantCount[$participantNum]);
1306 }
1307 }
1308
1309 if ($participantNum === NULL) {
1310 break;
1311 }
1312
1313 //carry the participant submitted values.
1314 $this->_values['params'][$participantID] = $params[$participantNum];
1315 }
1316
1317 //lets send mails to all with meanigful text, CRM-4320.
1318 $this->assign('isOnWaitlist', $this->_allowWaitlist);
1319 $this->assign('isRequireApproval', $this->_requireApproval);
1320
1321 foreach ($additionalIDs as $participantID => $contactId) {
1322 if ($participantID == $registerByID) {
1323 //set as Primary Participant
1324 $this->assign('isPrimary', 1);
1325
1326 $customProfile = CRM_Event_BAO_Event::buildCustomProfile($participantID, $this->_values, NULL, $isTest);
1327
1328 if (count($customProfile)) {
1329 $this->assign('customProfile', $customProfile);
1330 $this->set('customProfile', $customProfile);
1331 }
1332 }
1333 else {
1334 $this->assign('isPrimary', 0);
1335 $this->assign('customProfile', NULL);
1336 }
1337
1338 //send Confirmation mail to Primary & additional Participants if exists
1339 CRM_Event_BAO_Event::sendMail($contactId, $this->_values, $participantID, $isTest);
1340 }
1341 }
1342 }
1343
1344 /**
1345 * Method to check if the user is already registered for the event
1346 * and if result found redirect to the event info page
1347 *
1348 * @param array $fields the input form values(anonymous user)
1349 * @param array $self event data
1350 * @param boolean $isAdditional treat isAdditional participants a bit differently
1351 * @param boolean $returnContactId just find and return the contactID match to use
1352 * @param boolean $useDedupeRules force usage of dedupe rules
1353 *
1354 * @return void
1355 * @access public
1356 */
1357 static function checkRegistration($fields, &$self, $isAdditional = FALSE, $returnContactId = FALSE, $useDedupeRules = FALSE) {
1358 // CRM-3907, skip check for preview registrations
1359 // CRM-4320 participant need to walk wizard
1360 if (!$returnContactId &&
1361 ($self->_mode == 'test' || $self->_allowConfirmation)
1362 ) {
1363 return FALSE;
1364 }
1365
1366 $contactID = NULL;
1367 $session = CRM_Core_Session::singleton();
1368 if (!$isAdditional) {
1369 $contactID = $self->getContactID();
1370 }
1371
1372 if (!$contactID && is_array($fields) && $fields) {
1373
1374 //CRM-6996
1375 //as we are allowing w/ same email address,
1376 //lets check w/ other contact params.
1377 if ($self->_values['event']['allow_same_participant_emails']) {
1378 $params = $fields;
1379 $level = ($isAdditional) ? 'Supervised' : 'Unsupervised';
1380
1381 $dedupeParams = CRM_Dedupe_Finder::formatParams($params, 'Individual');
1382
1383 // disable permission based on cache since event registration is public page/feature.
1384 $dedupeParams['check_permission'] = FALSE;
1385 $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual', $level);
1386 $contactID = CRM_Utils_Array::value(0, $ids);
1387 }
1388 else {
1389 foreach ($fields as $fieldname => $fieldvalue) {
1390 if (substr($fieldname, 0, 6) == 'email-') {
1391 $emailString = trim($fieldvalue);
1392 if (!empty($emailString)) {
1393 $match = CRM_Contact_BAO_Contact::matchContactOnEmail($emailString, 'Individual');
1394 if (!empty($match)) {
1395 $contactID = $match->contact_id;
1396 }
1397 }
1398 }
1399 }
1400 }
1401 }
1402
1403 if ($returnContactId) {
1404 // CRM-7377
1405 // return contactID if contact already exists
1406 return $contactID;
1407 }
1408
1409 if ($contactID) {
1410 $participant = new CRM_Event_BAO_Participant();
1411 $participant->contact_id = $contactID;
1412 $participant->event_id = $self->_values['event']['id'];
1413 if (!empty($fields['participant_role']) && is_numeric($fields['participant_role'])) {
1414 $participant->role_id = $fields['participant_role'];
1415 }
1416 else {
1417 $participant->role_id = $self->_values['event']['default_role_id'];
1418 }
1419 $participant->is_test = 0;
1420 $participant->find();
1421 $statusTypes = CRM_Event_PseudoConstant::participantStatus(NULL, 'is_counted = 1');
1422 while ($participant->fetch()) {
1423 if (array_key_exists($participant->status_id, $statusTypes)) {
1424 if (!$isAdditional && !$self->_values['event']['allow_same_participant_emails']) {
1425 $registerUrl = CRM_Utils_System::url('civicrm/event/register',
1426 "reset=1&id={$self->_values['event']['id']}&cid=0"
1427 );
1428 if ($self->_pcpId) {
1429 $registerUrl .= '&pcpId=' . $self->_pcpId;
1430 }
1431
1432 $status = ts("It looks like you are already registered for this event. If you want to change your registration, or you feel that you've gotten this message in error, please contact the site administrator.") . ' ' . ts('You can also <a href="%1">register another participant</a>.', array(1 => $registerUrl));
1433 $session->setStatus($status, ts('Oops.'), 'alert');
1434 $url = CRM_Utils_System::url('civicrm/event/info',
1435 "reset=1&id={$self->_values['event']['id']}&noFullMsg=true"
1436 );
1437 if ($self->_action & CRM_Core_Action::PREVIEW) {
1438 $url .= '&action=preview';
1439 }
1440
1441 if ($self->_pcpId) {
1442 $url .= '&pcpId=' . $self->_pcpId;
1443 }
1444
1445 CRM_Utils_System::redirect($url);
1446 }
1447
1448 if ($isAdditional) {
1449 $status = ts("It looks like this participant is already registered for this event. If you want to change your registration, or you feel that you've gotten this message in error, please contact the site administrator.");
1450 $session->setStatus($status, ts('Oops.'), 'alert');
1451 return $participant->id;
1452 }
1453 }
1454 }
1455 }
1456 }
1457 }
1458