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