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