From 0dc0b75958ea0a4a5a279449117b028e1985cb83 Mon Sep 17 00:00:00 2001 From: atif-shaikh Date: Wed, 28 Jan 2015 20:04:48 +0530 Subject: [PATCH] CRM-5039 - Sold out price options modifications ---------------------------------------- * CRM-5039: Events don't always limit registrations to "max participants" setting https://issues.civicrm.org/jira/browse/CRM-5039 --- CRM/Event/Form/Registration.php | 140 +++++++++++++++--- .../Registration/AdditionalParticipant.php | 129 ++-------------- CRM/Event/Form/Registration/Confirm.php | 19 ++- CRM/Event/Form/Registration/Register.php | 35 ++++- CRM/Price/BAO/PriceField.php | 6 +- 5 files changed, 174 insertions(+), 155 deletions(-) diff --git a/CRM/Event/Form/Registration.php b/CRM/Event/Form/Registration.php index 501c6df387..f35474ef1b 100644 --- a/CRM/Event/Form/Registration.php +++ b/CRM/Event/Form/Registration.php @@ -1193,6 +1193,119 @@ WHERE v.option_group_id = g.id return $fileName ? $fileName : parent::overrideExtraTemplateFileName(); } + /** + * Reset values for all options those are full. + * + */ + public static function resetElementValue($optionFullIds = array(), &$form) { + if (!is_array($optionFullIds) || + empty($optionFullIds) || + !$form->isSubmitted() + ) { + return; + } + + foreach ($optionFullIds as $fldId => $optIds) { + $name = "price_$fldId"; + if (!$form->elementExists($name)) { + continue; + } + + $element = $form->getElement($name); + $eleType = $element->getType(); + + $resetSubmitted = FALSE; + switch ($eleType) { + case 'text': + if ($element->getValue() && $element->isFrozen()) { + $label = "{$element->getLabel()}(x)"; + $element->setLabel($label); + $element->setPersistantFreeze(); + $resetSubmitted = TRUE; + } + break; + + case 'group': + if (is_array($element->_elements)) { + foreach ($element->_elements as $child) { + $childType = $child->getType(); + $methodName = 'getName'; + if ($childType) { + $methodName = 'getValue'; + } + if (in_array($child->{$methodName}(), $optIds) && $child->isFrozen()) { + $resetSubmitted = TRUE; + $child->setPersistantFreeze(); + } + } + } + break; + + case 'select': + if (in_array($element->getValue()[0], $optIds)) { + foreach ($element->_options as $option) { + if ($option['attr']['value'] === "crm_disabled_opt-{$element->getValue()[0]}") { + $placeholder = html_entity_decode($option['text']); + $element->updateAttributes(array('placeholder' => $placeholder)); + break; + } + } + $resetSubmitted = TRUE; + } + break; + } + + //finally unset values from submitted. + if ($resetSubmitted) { + self::resetSubmittedValue($name, $optIds, $form); + } + } + } + + /** + * @param string $elementName + * @param array $optionIds + */ + public static function resetSubmittedValue($elementName, $optionIds = array(), &$form) { + if (empty($elementName) || + !$form->elementExists($elementName) || + !$form->getSubmitValue($elementName) + ) { + return; + } + foreach (array( + 'constantValues', + 'submitValues', + 'defaultValues', + ) as $val) { + $values = $form->{"_$val"}; + if (!is_array($values) || empty($values)) { + continue; + } + $eleVal = CRM_Utils_Array::value($elementName, $values); + if (empty($eleVal)) { + continue; + } + if (is_array($eleVal)) { + $found = FALSE; + foreach ($eleVal as $keyId => $ignore) { + if (in_array($keyId, $optionIds)) { + $found = TRUE; + unset($values[$elementName][$keyId]); + } + } + if ($found && empty($values[$elementName][$keyId])) { + $values[$elementName][$keyId] = NULL; + } + } + else { + if (!empty($keyId)) { + $values[$elementName][$keyId] = NULL; + } + } + } + } + /** * Validate price set submitted params for price option limit, * as well as user should select at least one price field option. @@ -1292,9 +1405,14 @@ WHERE v.option_group_id = g.id $optionMaxValues[$priceFieldId][$optId] = $currentMaxValue + CRM_Utils_Array::value($optId, CRM_Utils_Array::value($priceFieldId, $optionMaxValues), 0); } - + $soldOutPnum[$optId] = $pNum; } } + + //validate for price field selection. + if (empty($fieldSelected[$pNum])) { + $errors[$pNum]['_qf_default'] = ts('Select at least one option from Event Fee(s).'); + } } //validate for option max value. @@ -1304,34 +1422,22 @@ WHERE v.option_group_id = g.id $optMax = $optionsMaxValueDetails[$fieldId]['options'][$optId]; $opDbCount = CRM_Utils_Array::value('db_total_count', $options[$optId], 0); $total += $opDbCount; - if ($optMax && $total > $optMax) { - $errors['soldOutOptions'][] = ts('Option %1 has sold out.', array(1 => $feeBlock[$fieldId]['options'][$optId]['label'])); + if ($optMax && ($total > $optMax)) { if ($opDbCount && ($opDbCount >= $optMax)) { - $errors[$currentParticipantNum]["price_{$fieldId}"] + $errors[$soldOutPnum[$optId]]["price_{$fieldId}"] = ts('Sorry, this option is currently sold out.'); } elseif (($optMax - $opDbCount) == 1) { - $errors[$currentParticipantNum]["price_{$fieldId}"] + $errors[$soldOutPnum[$optId]]["price_{$fieldId}"] = ts('Sorry, currently only a single seat is available for this option.', array(1 => ($optMax - $opDbCount))); } else { - $errors[$currentParticipantNum]["price_{$fieldId}"] + $errors[$soldOutPnum[$optId]]["price_{$fieldId}"] = ts('Sorry, currently only %1 seats are available for this option.', array(1 => ($optMax - $opDbCount))); } } } } - - //validate for price field selection. - foreach ($params as $pNum => $values) { - if (!is_array($values) || $values == 'skip') { - continue; - } - if (empty($fieldSelected[$pNum])) { - $errors[$pNum]['_qf_default'] = ts('Select at least one option from Event Fee(s).'); - } - } - return $errors; } diff --git a/CRM/Event/Form/Registration/AdditionalParticipant.php b/CRM/Event/Form/Registration/AdditionalParticipant.php index f872c23d1d..0c7287047a 100644 --- a/CRM/Event/Form/Registration/AdditionalParticipant.php +++ b/CRM/Event/Form/Registration/AdditionalParticipant.php @@ -147,9 +147,7 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R $defaults = array_merge($this->_defaults, $defaults); //reset values for all options those are full. - if (!empty($unsetSubmittedOptions) && empty($_POST)) { - $this->resetElementValue($unsetSubmittedOptions); - } + CRM_Event_Form_Registration::resetElementValue($unsetSubmittedOptions, $this); //load default campaign from page. if (array_key_exists('participant_campaign_id', $this->_fields)) { @@ -569,7 +567,7 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R $payment_processor_id = $self->params[0]['payment_processor_id']; CRM_Core_Payment_Form::validatePaymentInstrument($payment_processor_id, $self->_params[0], $errors, $self); - if ($errors) { + if (!empty($errors)) { return FALSE; } @@ -681,13 +679,13 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R $lineItem = array(); CRM_Price_BAO_PriceSet::processAmount($this->_values['fee'], $params, $lineItem); - //build the line item.. - if (array_key_exists($addParticipantNum, $this->_lineItem)) { - $this->_lineItem[$addParticipantNum] = $lineItem; - } - else { - $this->_lineItem[] = $lineItem; - } + //build line item array.. + //if requireApproval/waitlist is enabled we hide fees for primary participant + // (and not for additional participant which might be is a bug) + //lineItem are not correctly build for primary participant + //this results in redundancy since now lineItems for additional participant will be build against primary participantNum + //therefore lineItems must always be build against current participant No + $this->_lineItem[$addParticipantNum] = $lineItem; } } @@ -710,12 +708,7 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R } //build the params array. - if (array_key_exists($addParticipantNum, $this->_params)) { - $this->_params[$addParticipantNum] = $params; - } - else { - $this->_params[] = $params; - } + $this->_params[$addParticipantNum] = $params; } //finally set the params. @@ -774,106 +767,4 @@ class CRM_Event_Form_Registration_AdditionalParticipant extends CRM_Event_Form_R } return FALSE; } - - /** - * Reset values for all options those are full. - * - */ - public function resetElementValue($optionFullIds = array()) { - if (!is_array($optionFullIds) || - empty($optionFullIds) || - !$this->isSubmitted() - ) { - return; - } - - foreach ($optionFullIds as $fldId => $optIds) { - $name = "price_$fldId"; - if (!$this->elementExists($name)) { - continue; - } - - $element = $this->getElement($name); - $eleType = $element->getType(); - - $resetSubmitted = FALSE; - switch ($eleType) { - case 'text': - if ($element->isFrozen()) { - $element->setValue(''); - $resetSubmitted = TRUE; - } - break; - - case 'group': - if (is_array($element->_elements)) { - foreach ($element->_elements as $child) { - $childType = $child->getType(); - $methodName = 'getName'; - if ($childType) { - $methodName = 'getValue'; - } - if (in_array($child->{$methodName}(), $optIds) && $child->isFrozen()) { - $resetSubmitted = TRUE; - $child->updateAttributes(array('checked' => NULL)); - } - } - } - break; - - case 'select': - $resetSubmitted = TRUE; - $element->_values = array(); - break; - } - - //finally unset values from submitted. - if ($resetSubmitted) { - $this->resetSubmittedValue($name, $optIds); - } - } - } - - /** - * @param string $elementName - * @param array $optionIds - */ - public function resetSubmittedValue($elementName, $optionIds = array()) { - if (empty($elementName) || - !$this->elementExists($elementName) || - !$this->getSubmitValue($elementName) - ) { - return; - } - foreach (array( - 'constantValues', - 'submitValues', - 'defaultValues', - ) as $val) { - $values = &$this->{"_$val"}; - if (!is_array($values) || empty($values)) { - continue; - } - $eleVal = CRM_Utils_Array::value($elementName, $values); - if (empty($eleVal)) { - continue; - } - if (is_array($eleVal)) { - $found = FALSE; - foreach ($eleVal as $keyId => $ignore) { - if (in_array($keyId, $optionIds)) { - $found = TRUE; - unset($values[$elementName][$keyId]); - } - } - if ($found && empty($values[$elementName][$keyId])) { - $values[$elementName][$keyId] = NULL; - } - } - else { - $values[$elementName][$keyId] = NULL; - } - } - } - } diff --git a/CRM/Event/Form/Registration/Confirm.php b/CRM/Event/Form/Registration/Confirm.php index b4f2c02ef3..b3f79dd9e6 100644 --- a/CRM/Event/Form/Registration/Confirm.php +++ b/CRM/Event/Form/Registration/Confirm.php @@ -411,19 +411,18 @@ class CRM_Event_Form_Registration_Confirm extends CRM_Event_Form_Registration { $self->_feeBlock = $self->_values['fee']; CRM_Event_Form_Registration_Register::formatFieldsForOptionFull($self); - if (!empty($self->_priceSetId)) { + if (!empty($self->_priceSetId) && + !$self->_requireApproval && !$self->_allowWaitlist + ) { $priceSetErrors = self::validatePriceSet($self, $self->_params); - //get price set fields errors in. - $errors = array_merge($errors, CRM_Utils_Array::value(0, $priceSetErrors, array())); + if (!empty($priceSetErrors)) { + CRM_Core_Session::setStatus(ts('You have been returned to the start of the registration process and any sold out events have been removed from your selections. You will not be able to continue until you review your booking and select different events if you wish. The following events were sold out:'), ts('Unfortunately some of your options have now sold out for one or more participants.'), 'error'); + CRM_Core_Session::setStatus(ts('Please note that the options which are marked or selected are sold out for participant being viewed.'), ts('Sold out:'), 'error'); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "_qf_Register_display=true&qfKey={$fields['qfKey']}")); + } } - if (!empty($errors)) { - $soldOutOptions = implode("
", $priceSetErrors['soldOutOptions']); - CRM_Core_Session::setStatus(ts('You have been returned to the start of the registration process and any sold out events have been removed from your selections. You will not be able to continue until you review your booking and select different events if you wish. The following events were sold out:'), ts('Unfortunately some of your options have now sold out for one or more participants.'), 'error'); - CRM_Core_Session::setStatus(ts("{$soldOutOptions}"), ts('Sold out:'), 'error'); - CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "_qf_Register_display=true&qfKey=" . $fields['qfKey'])); - } - return empty($errors) ? TRUE : $errors; + return empty($priceSetErrors) ? TRUE : $priceSetErrors; } /** diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php index cc63b79547..da41970f23 100644 --- a/CRM/Event/Form/Registration/Register.php +++ b/CRM/Event/Form/Registration/Register.php @@ -260,6 +260,10 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { } if ($this->_priceSetId && !empty($this->_feeBlock)) { foreach ($this->_feeBlock as $key => $val) { + if (empty($val['options'])) { + continue; + } + $optionFullIds = CRM_Utils_Array::value('option_full_ids', $val, array()); foreach ($val['options'] as $keys => $values) { if ($values['is_default'] && empty($values['is_full'])) { @@ -271,7 +275,10 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { } } } + $unsetSubmittedOptions[$val['id']] = $optionFullIds; } + //reset values for all options those are full. + CRM_Event_Form_Registration::resetElementValue($unsetSubmittedOptions, $this); } //set default participant fields, CRM-4320. @@ -737,7 +744,7 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { $currentOptionsCount = self::getPriceSetOptionCount($form); $recordedOptionsCount = CRM_Event_BAO_Participant::priceSetOptionsCount($form->_eventId, $skipParticipants); $optionFullTotalAmount = 0; - + $currentParticipantNo = (int) substr($form->_name, 12); foreach ($form->_feeBlock as & $field) { $optionFullIds = array(); $fieldId = $field['id']; @@ -754,7 +761,8 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { $totalCount = $currentTotalCount + $dbTotalCount; $isFull = FALSE; if ($maxValue && - (($totalCount > $maxValue) || ($totalCount + $count > $maxValue)) + (($totalCount >= $maxValue) && + (empty($form->_lineItem[$currentParticipantNo][$optId]['price_field_id']) || $dbTotalCount >= $maxValue)) ) { $isFull = TRUE; $optionFullIds[$optId] = $optId; @@ -850,7 +858,9 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { } // priceset validations - if (!empty($fields['priceSetId'])) { + if (!empty($fields['priceSetId']) && + !$self->_requireApproval && !$self->_allowWaitlist + ) { //format params. $formatted = self::formatPriceSetParams($self, $fields); $ppParams = array($formatted); @@ -1081,7 +1091,14 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { if ($params['tax_amount']) { $this->set('tax_amount', $params['tax_amount']); } - $this->set('lineItem', array($lineItem)); + if (!empty($this->get('lineItem')) && is_array($this->get('lineItem'))) { + $submittedLineItems = $this->get('lineItem'); + $submittedLineItems[0] = $lineItem; + } + else { + $submittedLineItems = array($lineItem); + } + $this->set('lineItem', $submittedLineItems); $this->set('lineItemParticipantsCount', array($primaryParticipantCount)); } @@ -1120,8 +1137,14 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration { $params['invoiceID'] = $invoiceID; } - $this->_params = array(); - $this->_params[] = $params; + if (!empty($this->get('params')) && is_array($this->get('params'))) { + $this->_params = $this->get('params'); + $this->_params[0] = $params; + } + else { + $this->_params = array(); + $this->_params[] = $params; + } $this->set('params', $this->_params); if ($this->_paymentProcessor && diff --git a/CRM/Price/BAO/PriceField.php b/CRM/Price/BAO/PriceField.php index ee0f698374..709e5546f6 100644 --- a/CRM/Price/BAO/PriceField.php +++ b/CRM/Price/BAO/PriceField.php @@ -353,7 +353,7 @@ class CRM_Price_BAO_PriceField extends CRM_Price_DAO_PriceField { // CRM-6902 - Add "max" option for a price set field if (in_array($optionKey, $freezeOptions)) { - self::freezeIfEnabled($element, $freezeOptions); + self::freezeIfEnabled($element, $fieldOptions[$optionKey]); // CRM-14696 - Improve display for sold out price set options $element->setLabel($label . ' ' . ts('Sold out') . ''); } @@ -488,7 +488,6 @@ class CRM_Price_BAO_PriceField extends CRM_Price_DAO_PriceField { } } - $selectOption[$opt['id']] = $opt['label']; $priceVal[$opt['id']] = implode($seperator, array($opt[$valueFieldName] + $taxAmount, $count, $max_value)); if (!in_array($opt['id'], $freezeOptions)) { @@ -496,6 +495,7 @@ class CRM_Price_BAO_PriceField extends CRM_Price_DAO_PriceField { } // CRM-14696 - Improve display for sold out price set options else { + $opt['id'] = 'crm_disabled_opt-'.$opt['id']; $opt['label'] = $opt['label'] . ' (' . ts('Sold out') . ')'; } @@ -511,7 +511,7 @@ class CRM_Price_BAO_PriceField extends CRM_Price_DAO_PriceField { '' => ts('- select -'), ) + $selectOption, $useRequired && $field->is_required, - array('price' => json_encode($priceVal)) + array('price' => json_encode($priceVal), 'class' => 'crm-select2') ); // CRM-6902 - Add "max" option for a price set field -- 2.25.1