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