CRM-5039 - Sold out price options modifications
authoratif-shaikh <shaikh388@gmail.com>
Wed, 28 Jan 2015 14:34:48 +0000 (20:04 +0530)
committeratif-shaikh <shaikh388@gmail.com>
Thu, 12 Feb 2015 07:28:57 +0000 (12:58 +0530)
----------------------------------------
* 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
CRM/Event/Form/Registration/AdditionalParticipant.php
CRM/Event/Form/Registration/Confirm.php
CRM/Event/Form/Registration/Register.php
CRM/Price/BAO/PriceField.php

index 501c6df387a98be623fefb188c08119da8e4b066..f35474ef1b28942607846b940b425db188097587 100644 (file)
@@ -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()}<tt>(x)</tt>";
+            $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;
   }
 
index f872c23d1db8a17cf354fc1fcfd0fdd35ec1e768..0c7287047adc57ad497acb7a406adb308af35796 100644 (file)
@@ -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;
-      }
-    }
-  }
-
 }
index b4f2c02ef385b3e1ea39ad908a01547ea07db2dd..b3f79dd9e603eb15a491c8765e5a99c12f961154 100644 (file)
@@ -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("<br/>", $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;
   }
 
   /**
index cc63b7954775c66ec8b8a18246c5e4d2f52c91e5..da41970f232744293e6dc666d4306f89d2f87f06 100644 (file)
@@ -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 &&
index ee0f698374694f5ed3caa5deb6f33dc289d2ea72..709e5546f69bf715e8d06efbac30f6a6985ef1c0 100644 (file)
@@ -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 . '&nbsp;<span class="sold-out-option">' . ts('Sold out') . '</span>');
         }
@@ -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