comment fixes
[civicrm-core.git] / CRM / Event / Form / Registration / Register.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
6a488035 29 * @package CRM
e7112fa7 30 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
31 */
32
33/**
3bdf1f3a 34 * This class generates form components for processing Event.
6a488035
TO
35 */
36class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
37
38 /**
66f9e52b 39 * The fields involved in this page.
6a488035
TO
40 */
41 public $_fields;
42
6a488035
TO
43 /**
44 * The status message that user view.
6a488035
TO
45 */
46 protected $_waitlistMsg = NULL;
47 protected $_requireApprovalMsg = NULL;
48
3bdf1f3a 49 /**
50 * Deprecated parameter that we hope to remove.
51 *
52 * @var bool
53 */
6a488035
TO
54 public $_quickConfig = NULL;
55
56 /**
3bdf1f3a 57 * Skip duplicate check.
58 *
59 * This can be set using hook_civicrm_buildForm() to override the registration dupe check.
6a488035
TO
60 * CRM-7604
61 */
62 public $_skipDupeRegistrationCheck = FALSE;
63
cc789d46 64 public $_paymentProcessorID;
6a488035 65
16d1c8e2 66 /**
3bdf1f3a 67 * Show fee block or not.
68 *
16d1c8e2 69 * @var boolean determines if fee block should be shown or hidden
70 */
71 public $_noFees;
72
cc789d46 73 /**
3bdf1f3a 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 *
cc789d46
EM
78 * @var array
79 */
80 public $_paymentFields = array();
81
6a488035 82 /**
66f9e52b 83 * Set variables up before form is built.
6a488035 84 */
00be9182 85 public function preProcess() {
6a488035 86 parent::preProcess();
7bf9cde2 87
6a488035
TO
88 //CRM-4320.
89 //here we can't use parent $this->_allowWaitlist as user might
cc789d46 90 //walk back and we might set this value in this postProcess.
6a488035 91 //(we set when spaces < group count and want to allow become part of waiting )
6a488035
TO
92 $eventFull = CRM_Event_BAO_Participant::eventFull($this->_eventId, FALSE, CRM_Utils_Array::value('has_waitlist', $this->_values['event']));
93
b6a469c5
CW
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
16d1c8e2 97 $this->_noFees = (($eventFull || $this->_requireApproval) && !$this->_allowConfirmation);
42e3a033
EM
98 $this->_paymentProcessors = $this->_noFees ? array() : $this->get('paymentProcessors');
99 $this->preProcessPaymentOptions();
b6a469c5 100
6a488035 101 $this->_allowWaitlist = FALSE;
8cc574cf 102 if ($eventFull && !$this->_allowConfirmation && !empty($this->_values['event']['has_waitlist'])) {
6a488035
TO
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 }
6a488035
TO
122 }
123
124 /**
70d1766d 125 * Set default values for the form.
6a488035 126 */
00be9182 127 public function setDefaultValues() {
2ab5ff1d 128 $this->_defaults = array();
5c280496 129 $contactID = $this->getContactID();
70d1766d 130 CRM_Core_Payment_Form::setDefaultValues($this, $contactID);
a28e436f 131
6a488035 132 if ($contactID) {
6a488035
TO
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 }
3feb567a
DL
154
155 if (!empty($fields)) {
156 CRM_Core_BAO_UFGroup::setProfileDefaults($contactID, $fields, $this->_defaults);
157 }
158
13ac605f
DG
159 // Set default payment processor as default payment_processor radio button value
160 if (!empty($this->_paymentProcessors)) {
161 foreach ($this->_paymentProcessors as $pid => $value) {
a7488080 162 if (!empty($value['is_default'])) {
e02d7e96 163 $this->_defaults['payment_processor_id'] = $pid;
13ac605f
DG
164 }
165 }
166 }
167
6a488035
TO
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
a7488080 171 if (!empty($this->_values['event']['is_pay_later']) &&
6a488035
TO
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],
353ffa53
TO
210 $discountKey - 1, $discountKey, TRUE
211 ));
6a488035
TO
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']) {
608e6658 219 $this->_defaults['participant_role']
220 = $this->_defaults['participant_role_id'] = $this->_values['event']['default_role_id'];
6a488035
TO
221 }
222 if ($this->_priceSetId && !empty($this->_feeBlock)) {
223 foreach ($this->_feeBlock as $key => $val) {
0dc0b759 224 if (empty($val['options'])) {
225 continue;
226 }
227 $optionFullIds = CRM_Utils_Array::value('option_full_ids', $val, array());
6a488035 228 foreach ($val['options'] as $keys => $values) {
8cc574cf 229 if ($values['is_default'] && empty($values['is_full'])) {
6a488035
TO
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 }
0dc0b759 239 $unsetSubmittedOptions[$val['id']] = $optionFullIds;
6a488035 240 }
0dc0b759 241 //reset values for all options those are full.
242 CRM_Event_Form_Registration::resetElementValue($unsetSubmittedOptions, $this);
6a488035
TO
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 /**
66f9e52b 277 * Build the form object.
3bdf1f3a 278 *
279 * @return void
6a488035
TO
280 */
281 public function buildQuickForm() {
4839c695
KJ
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
7d613bb7 287 if (!empty($this->_fields) && !empty($this->_values['custom_pre_id'])) {
4839c695
KJ
288 $profileAddressFields = array();
289 foreach ($this->_fields as $key => $value) {
bd14c83f 290 CRM_Core_BAO_UFField::assignAddressField($key, $profileAddressFields, array(
21dfd5f5 291 'uf_group_id' => $this->_values['custom_pre_id'],
bd14c83f
FG
292 ));
293 }
4839c695
KJ
294 $this->set('profileAddressFields', $profileAddressFields);
295 }
296
cc789d46 297 CRM_Core_Payment_ProcessorForm::buildQuickForm($this);
6a488035 298
5c280496 299 $contactID = $this->getContactID();
37326fa1
DG
300 if ($contactID) {
301 $this->assign('contact_id', $contactID);
f498a273 302 $this->assign('display_name', CRM_Contact_BAO_Contact::displayName($contactID));
37326fa1 303 }
6a488035 304
6a488035
TO
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")
0161a899 314 $additionalOptions = array(
d3e86119
TO
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',
6a488035
TO
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
8cc574cf 337 if ((!empty($this->_values['event']['is_multiple_registrations']) ||
6a488035
TO
338 $this->_priceSetId
339 ) &&
340 !$this->_allowConfirmation &&
353ffa53
TO
341 is_numeric($this->_availableRegistrations) && !empty($this->_values['event']['has_waitlist'])
342 ) {
6a488035
TO
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
6a488035
TO
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
596bff78 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
cf6a124f 381 $onlinePaymentProcessorEnabled = FALSE;
6a488035 382 if (!empty($this->_paymentProcessors)) {
596bff78 383 foreach ($this->_paymentProcessors as $key => $name) {
22e263ad 384 if ($name['billing_mode'] == 1) {
596bff78 385 $onlinePaymentProcessorEnabled = TRUE;
386 }
6a488035
TO
387 $pps[$key] = $name['name'];
388 }
389 }
aa288d3f 390 if ($this->getContactID() === 0 && !$this->_values['event']['is_multiple_registrations']) {
e1ce628e 391 //@todo we are blocking for multiple registrations because we haven't tested
596bff78 392 $this->addCidZeroOptions($onlinePaymentProcessorEnabled);
393 }
a7488080 394 if (!empty($this->_values['event']['is_pay_later']) &&
6a488035
TO
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) {
e02d7e96 402 $this->addRadio('payment_processor_id', ts('Payment Method'), $pps,
fdf1844b 403 NULL, "&nbsp;"
6a488035
TO
404 );
405 }
406 elseif (!empty($pps)) {
407 $ppKeys = array_keys($pps);
408 $currentPP = array_pop($ppKeys);
e02d7e96 409 $this->addElement('hidden', 'payment_processor_id', $currentPP);
6a488035
TO
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
5c280496 420 $userID = $this->getContactID();
6a488035
TO
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;
0db6c3e1
TO
467 }
468 else {
6a488035
TO
469 $allAreBillingModeProcessors = FALSE;
470 }
471
8cc574cf 472 if (!$allAreBillingModeProcessors || !empty($this->_values['event']['is_pay_later']) || $bypassPayment
6a488035
TO
473 ) {
474
475 //freeze button to avoid multiple calls.
476 $js = NULL;
477
a7488080 478 if (empty($this->_values['event']['is_monetary'])) {
6a488035
TO
479 $js = array('onclick' => "return submitOnce(this,'" . $this->_name . "','" . ts('Processing') . "');");
480 }
2a6da8d7 481
1909126f 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']
d6121d3e 486 && !$this->_values['event']['is_monetary']
1909126f 487 && !$this->_values['event']['is_confirm_enabled']
488 ) {
f212d37d 489 $buttonLabel = ts('Register');
0db6c3e1
TO
490 }
491 else {
f212d37d 492 $buttonLabel = ts('Continue');
1909126f 493 }
2a6da8d7 494
6a488035
TO
495 $this->addButtons(array(
496 array(
497 'type' => 'upload',
1909126f 498 'name' => $buttonLabel,
6a488035
TO
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);
86c0d461 508 $this->unsavedChangesWarn = TRUE;
6a488035
TO
509
510 // add pcp fields
511 if ($this->_pcpId) {
512 CRM_PCP_BAO_PCP::buildPcp($this->_pcpId, $this);
513 }
514 }
515
516 /**
100fef9d 517 * Build the radio/text form elements for the amount field
6a488035 518 *
d4dd1e85
TO
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.
6a488035
TO
525 *
526 * @return void
6a488035
TO
527 */
528 static public function buildAmount(&$form, $required = TRUE, $discountId = NULL) {
16d1c8e2 529 // build amount only when needed, skip incase of event full and waitlisting is enabled
530 // and few other conditions check preProcess()
a2a1e950 531 if (property_exists($form, '_noFees') && $form->_noFees) {
16d1c8e2 532 return;
533 }
534
6a488035 535 //if payment done, no need to build the fee block.
7bf9cde2 536 if (!empty($form->_paymentId)) {
b6e641a4 537 //fix to display line item in update mode.
6a488035
TO
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
a7488080 579 if (!empty($form->_priceSet['is_quick_config'])) {
6a488035
TO
580 $form->_quickConfig = $form->_priceSet['is_quick_config'];
581 }
582 $form->add('hidden', 'priceSetId', $form->_priceSetId);
583
c7b3d063 584 // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
ab8a593e 585 $adminFieldVisible = FALSE;
c7b3d063 586 if (CRM_Core_Permission::check('administer CiviCRM')) {
4eeb9a5b 587 $adminFieldVisible = TRUE;
c7b3d063
DG
588 }
589
6a488035 590 foreach ($form->_feeBlock as $field) {
d06f3157 591 // public AND admin visibility fields are included for back-office registration and back-office change selections
6a488035 592 if (CRM_Utils_Array::value('visibility', $field) == 'public' ||
4eeb9a5b 593 (CRM_Utils_Array::value('visibility', $field) == 'admin' && $adminFieldVisible == TRUE) ||
d06f3157
DG
594 $className == 'CRM_Event_Form_Participant' ||
595 $className == 'CRM_Event_Form_ParticipantFeeSelection'
6a488035
TO
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.
9da8dc8c 619 CRM_Price_BAO_PriceField::addQuickFormElement($form,
6a488035
TO
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
0cf587a7 665 /**
c490a46a 666 * @param CRM_Core_Form $form
0cf587a7 667 */
6a488035
TO
668 public static function formatFieldsForOptionFull(&$form) {
669 $priceSet = $form->get('priceSet');
670 $priceSetId = $form->get('priceSetId');
e9bb507e 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 }
6a488035
TO
677 if (!$priceSetId ||
678 !is_array($priceSet) ||
353ffa53
TO
679 empty($priceSet) || empty($priceSet['optionsMaxValueTotal'])
680 ) {
6a488035
TO
681 return;
682 }
683
684 $skipParticipants = $formattedPriceSetDefaults = array();
e03317f1 685 if (!empty($form->_allowConfirmation) && (isset($form->_pId) || isset($form->_additionalParticipantId))) {
6a488035
TO
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.
217d80ab 692 $formattedPriceSetDefaults = self::formatPriceSetParams($form, $pricesetDefaults);
6a488035
TO
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);
e9bb507e 706 $optionFullTotalAmount = 0;
0dc0b759 707 $currentParticipantNo = (int) substr($form->_name, 12);
6a488035
TO
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) {
353ffa53
TO
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);
6a488035
TO
719 $currentTotalCount = CRM_Utils_Array::value($optId, $currentOptionsCount, 0);
720
79b152ac 721 $totalCount = $currentTotalCount + $dbTotalCount;
6a488035
TO
722 $isFull = FALSE;
723 if ($maxValue &&
0dc0b759 724 (($totalCount >= $maxValue) &&
725 (empty($form->_lineItem[$currentParticipantNo][$optId]['price_field_id']) || $dbTotalCount >= $maxValue))
6a488035
TO
726 ) {
727 $isFull = TRUE;
728 $optionFullIds[$optId] = $optId;
e9bb507e 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 }
6a488035 739 }
6a488035
TO
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 &&
8dfe9fe3 744 !empty($form->_allowConfirmation) &&
6a488035
TO
745 !empty($formattedPriceSetDefaults)
746 ) {
217d80ab 747 if (empty($formattedPriceSetDefaults["price_{$field}"]) || empty($formattedPriceSetDefaults["price_{$fieldId}"][$optId])) {
6a488035
TO
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 }
e9bb507e 765 $form->assign('optionFullTotalAmount', $optionFullTotalAmount);
6a488035
TO
766 }
767
768 /**
66f9e52b 769 * Global form rule.
6a488035 770 *
d4dd1e85
TO
771 * @param array $fields
772 * The input form values.
773 * @param array $files
774 * The uploaded files if any.
2a6da8d7
EM
775 * @param $self
776 *
6a488035 777 *
72b3a70c
CW
778 * @return bool|array
779 * true if no errors, else array of errors
6a488035 780 */
00be9182 781 public static function formRule($fields, $files, $self) {
6a488035
TO
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) {
168e792f 787 self::checkRegistration($fields, $self);
6a488035
TO
788 }
789 //check for availability of registrations.
8cc574cf 790 if (!$self->_allowConfirmation && empty($fields['bypass_payment']) &&
6a488035
TO
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
8cc574cf 798 if ($self->_allowConfirmation && !empty($fields['additional_participants']) &&
6a488035
TO
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.
a7488080 806 if (!empty($fields['bypass_payment'])) {
6a488035 807 if (!is_numeric($self->_availableRegistrations) ||
8cc574cf 808 (empty($fields['priceSetId']) && CRM_Utils_Array::value('additional_participants', $fields) < $self->_availableRegistrations)
6a488035
TO
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
a7488080 814 if (!empty($fields['additional_participants']) &&
6a488035
TO
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
0dc0b759 821 if (!empty($fields['priceSetId']) &&
822 !$self->_requireApproval && !$self->_allowWaitlist
823 ) {
6a488035
TO
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;
a7488080 834 if (!empty($fields['additional_participants'])) {
6a488035
TO
835 $totalParticipants += $fields['additional_participants'];
836 }
837
a7488080 838 if (empty($fields['bypass_payment']) &&
6a488035
TO
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();
9da8dc8c 847 CRM_Price_BAO_PriceSet::processAmount($self->_values['fee'], $fields, $lineItem);
6a488035
TO
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
f48e6cf7 853 // @todo - can we remove the 'is_monetary' concept?
6a488035 854 if ($self->_values['event']['is_monetary']) {
e02d7e96
EM
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');
0d588131 858 }
6a488035 859
0d588131 860 $isZeroAmount = $skipPaymentValidation = FALSE;
a7488080 861 if (!empty($fields['priceSetId'])) {
6a488035
TO
862 if (CRM_Utils_Array::value('amount', $fields) == 0) {
863 $isZeroAmount = TRUE;
864 }
865 }
a7488080 866 elseif (!empty($fields['amount']) &&
6a488035
TO
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 }
a7488080 873 elseif (!empty($fields['amount']) &&
6a488035
TO
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
8cc574cf 881 if ($isZeroAmount && !($self->_forcePayement && !empty($fields['additional_participants']))) {
0d588131 882 $skipPaymentValidation = TRUE;
6a488035
TO
883 }
884
f48e6cf7 885 // also return if zero fees for valid members
886 if (!empty($fields['bypass_payment']) ||
0d588131 887 $skipPaymentValidation ||
6a488035
TO
888 (!$self->_allowConfirmation && ($self->_requireApproval || $self->_allowWaitlist))
889 ) {
890 return empty($errors) ? TRUE : $errors;
891 }
f48e6cf7 892 CRM_Core_Payment_Form::validatePaymentInstrument(
893 $fields['payment_processor_id'],
894 $fields,
895 $errors,
896 (!$self->_isBillingAddressRequiredForPayLater ? NULL : 'billing')
897 );
6a488035 898 }
6a488035 899
6a488035
TO
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'])) {
217d80ab 904 $errors[$greeting . '_custom'] = ts('Custom %1 is a required field if %1 is of type Customized.',
6a488035
TO
905 array(1 => ucwords(str_replace('_', ' ', $greeting)))
906 );
907 }
908 }
909 }
910 return empty($errors) ? TRUE : $errors;
911 }
912
913 /**
ec022878 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
6a488035 919 */
00be9182 920 public static function checkProfileComplete($fields, &$errors, $eventId) {
6a488035
TO
921 $email = '';
922 foreach ($fields as $fieldname => $fieldvalue) {
923 if (substr($fieldname, 0, 6) == 'email-' && $fieldvalue) {
924 $email = $fieldvalue;
925 }
926 }
927
8cc574cf 928 if (!$email && !(!empty($fields['first_name']) && !empty($fields['last_name']))) {
6a488035
TO
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 /**
66f9e52b 937 * Process the form submission.
6a488035
TO
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
8ae4d0d3 946 if ($this->_values['event']['is_pay_later']
e02d7e96 947 && (!array_key_exists('hidden_processor', $params) || $params['payment_processor_id'] == 0)
353ffa53 948 ) {
6a488035
TO
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 }
6a488035 964
168e792f
DL
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
a7488080 972 if (!empty($params['image_URL'])) {
6a488035
TO
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;
a7488080 988 if (!empty($params['additional_participants'])) {
6a488035
TO
989 $totalParticipants += $params['additional_participants'];
990 }
8cc574cf 991 if (!$this->_allowConfirmation && !empty($params['bypass_payment']) &&
6a488035
TO
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 }
a7488080 1012 if (empty($params['participant_role_id']) &&
6a488035
TO
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'])) {
16d1c8e2 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 }
6a488035
TO
1042 }
1043 else {
1044 $lineItem = array();
9da8dc8c 1045 CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem);
d91b8b33 1046 if ($params['tax_amount']) {
1047 $this->set('tax_amount', $params['tax_amount']);
1048 }
9d8d8fd0 1049 $submittedLineItems = $this->get('lineItem');
1050 if (!empty($submittedLineItems) && is_array($submittedLineItems)) {
0dc0b759 1051 $submittedLineItems[0] = $lineItem;
1052 }
1053 else {
1054 $submittedLineItems = array($lineItem);
1055 }
1056 $this->set('lineItem', $submittedLineItems);
6a488035
TO
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)) {
077017db 1068 $payment = $this->_paymentProcessor['object'];
ec022878 1069 $payment->setBaseReturnUrl('civicrm/event/register');
6a488035
TO
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;
6a488035
TO
1092 $params['invoiceID'] = $invoiceID;
1093 }
d0ebccea 1094 $this->_params = $this->get('params');
ec022878 1095 // Set the button so we know what
1096 $params['button'] = $this->controller->getButtonName();
d0ebccea 1097 if (!empty($this->_params) && is_array($this->_params)) {
0dc0b759 1098 $this->_params[0] = $params;
1099 }
1100 else {
1101 $this->_params = array();
1102 $this->_params[] = $params;
1103 }
6a488035 1104 $this->set('params', $this->_params);
f92fc7eb 1105 if ($this->_paymentProcessor &&
223190c8 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.
ec022878 1108 $this->_paymentProcessor['object']->supports('preApproval')
1109 && !$this->_allowWaitlist &&
1110 !$this->_requireApproval
f92fc7eb 1111 ) {
6a488035 1112
0f2b049e 1113 // The concept of contributeMode is deprecated - but still needs removal from the message templates.
ec022878 1114 $this->set('contributeMode', 'express');
6a488035 1115
ec022878 1116 // Send Event Name & Id in Params
1117 $params['eventName'] = $this->_values['event']['title'];
1118 $params['eventId'] = $this->_values['event']['id'];
6a488035 1119
ec022878 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;
6a488035 1135
ec022878 1136 $params['component'] = 'event';
223190c8 1137 $this->handlePreApproval($params);
6a488035 1138 }
f92fc7eb
CW
1139 elseif ($this->_paymentProcessor &&
1140 $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY
1141 ) {
0f2b049e 1142 // The concept of contributeMode is deprecated - but still needs removal from the message templates.
6a488035
TO
1143 $this->set('contributeMode', 'notify');
1144 }
13f230bc 1145 }
1146 else {
1147 $params['description'] = ts('Online Event Registration') . ' ' . $this->_values['event']['title'];
6a488035 1148
13f230bc 1149 $this->_params = array();
1150 $this->_params[] = $params;
1151 $this->set('params', $this->_params);
6a488035 1152
13f230bc 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);
6a488035
TO
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 }
6a488035 1167
0cf587a7 1168 /**
66f9e52b 1169 * Process Registration of free event.
d424ffde 1170 *
c490a46a 1171 * @param array $params
d424ffde 1172 * Form values.
100fef9d 1173 * @param int $contactID
0cf587a7 1174 */
6a488035
TO
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.
a7488080 1200 if (empty($value['is_primary'])) {
6a488035
TO
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 }
a7488080 1220 elseif (!empty($value['contact_id'])) {
6a488035
TO
1221 $contactID = $value['contact_id'];
1222 }
1223 else {
5c280496 1224 $contactID = $this->getContactID();
6a488035
TO
1225 }
1226
a9f7d48b 1227 CRM_Event_Form_Registration_Confirm::fixLocationFields($value, $fields, $this);
6a488035 1228 //for free event or additional participant, dont create billing email address.
a7488080 1229 if (empty($value['is_primary']) || !$this->_values['event']['is_monetary']) {
6a488035
TO
1230 unset($value["email-{$this->_bltID}"]);
1231 }
1232
a9f7d48b 1233 $contactID = CRM_Event_Form_Registration_Confirm::updateContactFields($contactID, $value, $fields, $this);
6a488035
TO
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
8cc574cf 1239 if (!$this->getContactID() && !empty($value['is_primary'])) {
6a488035
TO
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
b44e3f84 1266 // update status and send mail to cancelled additional participants, CRM-4320
6a488035
TO
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
ec022878 1299 //lets carry all participant params w/ values.
6a488035
TO
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 /**
66f9e52b 1347 * Method to check if the user is already registered for the event.
6a488035
TO
1348 * and if result found redirect to the event info page
1349 *
d4dd1e85
TO
1350 * @param array $fields
1351 * The input form values(anonymous user).
ec022878 1352 * @param CRM_Event_Form_Registration_Register $self
d4dd1e85
TO
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.
6a488035
TO
1360 *
1361 * @return void
6a488035 1362 */
00be9182 1363 public static function checkRegistration($fields, &$self, $isAdditional = FALSE, $returnContactId = FALSE, $useDedupeRules = FALSE) {
6a488035
TO
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) {
5c280496 1375 $contactID = $self->getContactID();
6a488035
TO
1376 }
1377
178073d6 1378 if (!$contactID && is_array($fields) && $fields) {
6a488035 1379
03390e26 1380 //CRM-14134 use Unsupervised rule for everyone
1381 $dedupeParams = CRM_Dedupe_Finder::formatParams($fields, 'Individual');
6a488035 1382
03390e26 1383 // disable permission based on cache since event registration is public page/feature.
1384 $dedupeParams['check_permission'] = FALSE;
6a488035 1385
03390e26 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']);
6a488035
TO
1389 }
1390 else {
03390e26 1391 $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, 'Individual', 'Unsupervised');
6a488035 1392 }
03390e26 1393 $contactID = CRM_Utils_Array::value(0, $ids);
1394
6a488035
TO
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 }
96025800 1451
6a488035 1452}