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