diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php
index 11abe29a3..abf3177aa 100644
--- a/core/lib/Thelia/Controller/Admin/CouponController.php
+++ b/core/lib/Thelia/Controller/Admin/CouponController.php
@@ -25,9 +25,7 @@ use Thelia\Core\Security\AccessManager;
use Thelia\Coupon\CouponFactory;
use Thelia\Coupon\CouponManager;
use Thelia\Condition\ConditionCollection;
-use Thelia\Coupon\Type\CouponAbstract;
use Thelia\Coupon\Type\CouponInterface;
-use Thelia\Coupon\Type\RemoveXPercent;
use Thelia\Form\CouponCreationForm;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Log\Tlog;
@@ -577,7 +575,7 @@ class CouponController extends BaseAdminController
$condition['serviceId'] = $availableCoupon->getServiceId();
$condition['name'] = $availableCoupon->getName();
$condition['toolTip'] = $availableCoupon->getToolTip();
- // $condition['inputName'] = $availableCoupon->getInputName();
+
$cleanedCoupons[] = $condition;
}
@@ -676,35 +674,6 @@ class CouponController extends BaseAdminController
}
- /**
- * Add percentage logic if found in the Coupon post data
- *
- * @param array $effects Effect parameters to populate
- * @param array $extendedInputNames Extended Inputs to manage
- *
- * @return array Populated effect with percentage
- */
- protected function addExtendedLogic(array $effects, array $extendedInputNames)
- {
- /** @var Request $request */
- $request = $this->container->get('request');
- $postData = $request->request;
- // Validate quantity input
-
- if ($postData->has(RemoveXPercent::INPUT_EXTENDED__NAME)) {
- $extentedPostData = $postData->get(RemoveXPercent::INPUT_EXTENDED__NAME);
-
- foreach ($extendedInputNames as $extendedInputName) {
- if (isset($extentedPostData[$extendedInputName])) {
- $inputValue = $extentedPostData[$extendedInputName];
- $effects[$extendedInputName] = $inputValue;
- }
- }
- }
-
- return $effects;
- }
-
/**
* Feed the Coupon Create or Update event with the User inputs
*
@@ -718,16 +687,15 @@ class CouponController extends BaseAdminController
// Get the form field values
$data = $form->getData();
$serviceId = $data['type'];
- /** @var CouponInterface $couponManager */
- $couponManager = $this->container->get($serviceId);
- $effects = [CouponAbstract::INPUT_AMOUNT_NAME => $data[CouponAbstract::INPUT_AMOUNT_NAME]];
- $effects = $this->addExtendedLogic($effects, $couponManager->getExtendedInputs());
+
+ /** @var CouponInterface $coupon */
+ $coupon = $this->container->get($serviceId);
$couponEvent = new CouponCreateOrUpdateEvent(
$data['code'],
$serviceId,
$data['title'],
- $effects,
+ $coupon->getEffects($data),
$data['shortDescription'],
$data['description'],
$data['isEnabled'],
diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php
index 755dbe9f7..ae2312aae 100644
--- a/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php
+++ b/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php
@@ -327,10 +327,9 @@ class CouponCreateOrUpdateEvent extends ActionEvent
*/
public function setEffects(array $effects)
{
- if (null === $effects['amount']) {
- throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect ready to be serialized array');
- }
- $this->amount = $effects['amount'];
+ // Amount is now optionnal.
+ $this->amount = isset($effects['amount']) ? $effects['amount'] : 0;
+
$this->effects = $effects;
}
diff --git a/core/lib/Thelia/Coupon/Type/CouponAbstract.php b/core/lib/Thelia/Coupon/Type/CouponAbstract.php
index 424de8323..d04c29b89 100644
--- a/core/lib/Thelia/Coupon/Type/CouponAbstract.php
+++ b/core/lib/Thelia/Coupon/Type/CouponAbstract.php
@@ -17,6 +17,7 @@ use Thelia\Condition\ConditionEvaluator;
use Thelia\Condition\ConditionOrganizerInterface;
use Thelia\Core\Translation\Translator;
use Thelia\Coupon\FacadeInterface;
+use Thelia\Form\CouponCreationForm;
use Thelia\Model\CouponCountry;
use Thelia\Model\CouponModule;
@@ -29,12 +30,21 @@ use Thelia\Model\CouponModule;
*/
abstract class CouponAbstract implements CouponInterface
{
- const INPUT_EXTENDED__NAME = 'thelia_coupon_creation_extended';
+ /**
+ * The dataset name for all coupon specific input fields, that do not appear in the CouPonCreationForm form.
+ *
+ * In the input form, these fields have to be created like:
+ *
+ * thelia_coupon_specific[my_field, thelia_coupon_creation_extended[my_other_field]
+ *
+ * use the makeCouponField() method to do that safely.
+ */
+ const COUPON_DATASET_NAME = 'coupon_specific';
- const INPUT_AMOUNT_NAME = 'amount';
-
- /** @var array Extended Inputs to manage */
- protected $extendedInputs = array();
+ /**
+ * A standard 'amount' filed name, thant can be used in coupons which extends this class
+ */
+ const AMOUNT_FIELD_NAME = 'amount';
/** @var FacadeInterface Provide necessary value from Thelia */
protected $facade = null;
@@ -161,7 +171,8 @@ abstract class CouponAbstract implements CouponInterface
$this->facade = $facade;
$this->effects = $effects;
- $this->amount = $effects[self::INPUT_AMOUNT_NAME];
+ // Amount is now optional.
+ $this->amount = isset($effects[self::AMOUNT_FIELD_NAME]) ? $effects[self::AMOUNT_FIELD_NAME] : 0;
$this->freeShippingForCountries = $freeShippingForCountries;
$this->freeShippingForModules = $freeShippingForModules;
@@ -383,6 +394,18 @@ abstract class CouponAbstract implements CouponInterface
return $this->conditionEvaluator->isMatching($this->conditions);
}
+ /**
+ * This is the field label than will be displayed in the form.
+ * This method should be overridden to be useful.
+ *
+ * For backward compatibility only.
+ *
+ * @return string
+ */
+ public function getInputName() {
+ return "Please override getInputName() method";
+ }
+
/**
* Draw the input displayed in the BackOffice
* allowing Admin to set its Coupon effect
@@ -394,19 +417,86 @@ abstract class CouponAbstract implements CouponInterface
{
return $this->facade->getParser()->render('coupon/type-fragments/remove-x.html', [
'label' => $this->getInputName(),
- 'fieldName' => self::INPUT_AMOUNT_NAME,
+ 'fieldId' => self::AMOUNT_FIELD_NAME,
+ 'fieldName' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME),
'value' => $this->amount
]);
}
/**
- * Get all extended inputs name to manage
+ * This methods checks a field value. If the field has a correct value, this value is returned
+ * Otherwise, an InvalidArgumentException describing the problem should be thrown.
*
+ * This method should be ovveriden to be useful.
+ *
+ * @param $fieldName
+ * @param $fieldValue
* @return mixed
+ * @throws \InvalidArgumentException if the field valiue is not valid.
*/
- public function getExtendedInputs()
- {
- return $this->extendedInputs;
+ protected function checkCouponFieldValue($fieldName, $fieldValue) {
+ return $fieldValue;
}
+ /**
+ * A helper to get the value of a standard field name
+ *
+ * @param string $fieldName the field name
+ * @param array $data the input form data (e.g. $form->getData())
+ * @param mixed $defaultValue the default value if the field is not found.
+ *
+ * @return mixed the input value, or the default one
+ *
+ * @throws \InvalidArgumentException if the field is not found, and no default value has been defined.
+ */
+ protected function getCouponFieldValue($fieldName, $data, $defaultValue = null) {
+ if (isset($data[self::COUPON_DATASET_NAME][$fieldName])) {
+
+ return $this->checkCouponFieldValue(
+ $fieldName,
+ $data[self::COUPON_DATASET_NAME][$fieldName]
+ );
+ }
+ else if (null !== $defaultValue) {
+ return $defaultValue;
+ }
+ else {
+ throw new \InvalidArgumentException(sprintf("The coupon field name %s was not found in the coupon form", $fieldName));
+ }
+ }
+
+ /**
+ * A helper to create an standard field name that will be used in the coupon form
+ *
+ * @param string $fieldName the field name
+ * @return string the complete name, ready to be used in a form.
+ */
+ protected function makeCouponFieldName($fieldName) {
+ return sprintf("%s[%s][%s]", CouponCreationForm::COUPON_CREATION_FORM_NAME, self::COUPON_DATASET_NAME, $fieldName);
+ }
+
+ /**
+ * Return a list of the fields name for this coupon.
+ *
+ * @return array
+ */
+ protected function getFieldList() {
+ return [self::AMOUNT_FIELD_NAME];
+ }
+
+ /**
+ * Create the effect array from the list of fields
+ *
+ * @param array $data the input form data (e.g. $form->getData())
+ * @return array a filedName => fieldValue array
+ */
+ public function getEffects($data) {
+ $effects = [];
+
+ foreach($this->getFieldList() as $fieldName) {
+ $effects[$fieldName] = $this->getCouponFieldValue($fieldName, $data);
+ }
+
+ return $effects;
+ }
}
diff --git a/core/lib/Thelia/Coupon/Type/CouponInterface.php b/core/lib/Thelia/Coupon/Type/CouponInterface.php
index 69eca002a..f9acc973d 100644
--- a/core/lib/Thelia/Coupon/Type/CouponInterface.php
+++ b/core/lib/Thelia/Coupon/Type/CouponInterface.php
@@ -15,6 +15,7 @@ namespace Thelia\Coupon\Type;
use Propel\Runtime\Collection\ObjectCollection;
use Thelia\Condition\ConditionCollection;
use Thelia\Coupon\FacadeInterface;
+use Thelia\Form\CouponCreationForm;
/**
* Represents a Coupon ready to be processed in a Checkout process
@@ -220,13 +221,6 @@ interface CouponInterface
*/
public function drawBackOfficeInputs();
- /**
- * Get all extended inputs name to manage
- *
- * @return mixed
- */
- public function getExtendedInputs();
-
/**
* @return ObjectCollection list of country IDs for which shipping is free. All if empty
*/
@@ -236,4 +230,14 @@ interface CouponInterface
* @return ObjectCollection list of module IDs for which shipping is free. All if empty
*/
public function getFreeShippingForModules();
+
+ /**
+ * Create the effect array from the list of fields
+ *
+ * @param array $data the input form data (e.g. $form->getData())
+ *
+ * @return array a filedName => fieldValue array
+ */
+ public function getEffects($data);
+
}
diff --git a/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php b/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php
index 2372dbfb4..9994219e2 100644
--- a/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php
+++ b/core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php
@@ -12,6 +12,9 @@
namespace Thelia\Coupon\Type;
+use Thelia\Core\Translation\Translator;
+use Thelia\Coupon\FacadeInterface;
+
/**
* Allow to remove an amount from the checkout total
*
@@ -26,6 +29,44 @@ class RemoveAmountOnCategories extends CouponAbstract
/** @var string Service Id */
protected $serviceId = 'thelia.coupon.type.remove_amount_on_categories';
+ var $category_list = array();
+
+ /**
+ * @inheritdoc
+ */
+ public function set(
+ FacadeInterface $facade,
+ $code,
+ $title,
+ $shortDescription,
+ $description,
+ array $effects,
+ $isCumulative,
+ $isRemovingPostage,
+ $isAvailableOnSpecialOffers,
+ $isEnabled,
+ $maxUsage,
+ \DateTime $expirationDate,
+ $freeShippingForCountries,
+ $freeShippingForModules,
+ $perCustomerUsageCount
+ )
+ {
+ parent::set(
+ $facade, $code, $title, $shortDescription, $description, $effects,
+ $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
+ $freeShippingForCountries,
+ $freeShippingForModules,
+ $perCustomerUsageCount
+ );
+
+ $this->category_list = isset($effects[self::CATEGORIES_LIST]) ? $effects[self::CATEGORIES_LIST] : array();
+
+ if (! is_array($this->category_list)) $this->category_list = array($this->category_list);
+
+ return $this;
+ }
+
/**
* Get I18n name
*
@@ -64,18 +105,64 @@ class RemoveAmountOnCategories extends CouponAbstract
*/
public function exec()
{
+ // TODO !!!
return $this->amount;
}
public function drawBackOfficeInputs()
{
return $this->facade->getParser()->render('coupon/type-fragments/remove-amount-on-categories.html', [
- 'amount_field_name' => self::INPUT_AMOUNT_NAME,
- 'amount_value' => $this->amount,
- 'categories_field_name' => self::CATEGORIES_LIST,
- 'categories_values' => isset($this->values[self::CATEGORIES_LIST]) ? $this->values[self::CATEGORIES_LIST] : array()
+ // The standard "Amount" field
+ 'amount_field_name' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME),
+ 'amount_value' => $this->amount,
- ]);
+ // The categories list field
+ 'categories_field_id' => self::CATEGORIES_LIST,
+ 'categories_field_name' => $this->makeCouponFieldName(self::CATEGORIES_LIST),
+
+ // The selected categories
+ 'categories_values' => $this->category_list
+ ]);
}
+
+ /**
+ * Return a list of the fields name for this coupon.
+ *
+ * @return array
+ */
+ protected function getFieldList() {
+ return [self::AMOUNT_FIELD_NAME, self::CATEGORIES_LIST];
+ }
+
+
+ /**
+ * @inheritdoc
+ */
+ protected function checkCouponFieldValue($fieldName, $fieldValue)
+ {
+ if ($fieldName === self::AMOUNT_FIELD_NAME) {
+
+ if (floatval($fieldValue) < 0) {
+ throw new \InvalidArgumentException(
+ Translator::getInstance()->trans(
+ 'Value %val for Discount Amount is invalid. Please enter a positive value.',
+ [ '%val' => $fieldValue]
+ )
+ );
+ }
+ }
+ else if ($fieldName === self::CATEGORIES_LIST) {
+ if (empty($fieldValue)) {
+ throw new \InvalidArgumentException(
+ Translator::getInstance()->trans(
+ 'Please select at least one category'
+ )
+ );
+ }
+ }
+
+ return $fieldValue;
+ }
+
}
diff --git a/core/lib/Thelia/Coupon/Type/RemoveXAmount.php b/core/lib/Thelia/Coupon/Type/RemoveXAmount.php
index c644706a2..fe5322e22 100644
--- a/core/lib/Thelia/Coupon/Type/RemoveXAmount.php
+++ b/core/lib/Thelia/Coupon/Type/RemoveXAmount.php
@@ -12,6 +12,8 @@
namespace Thelia\Coupon\Type;
+use Thelia\Core\Translation\Translator;
+
/**
* Allow to remove an amount from the checkout total
*
@@ -36,18 +38,6 @@ class RemoveXAmount extends CouponAbstract
->trans('Fixed Amount Discount', array(), 'coupon');
}
- /**
- * Get I18n amount input name
- *
- * @return string
- */
- public function getInputName()
- {
- return $this->facade
- ->getTranslator()
- ->trans('Discount amount', array(), 'coupon');
- }
-
/**
* Get I18n tooltip
*
@@ -69,9 +59,38 @@ class RemoveXAmount extends CouponAbstract
public function drawBackOfficeInputs()
{
return $this->facade->getParser()->render('coupon/type-fragments/remove-x-amount.html', [
- 'label' => $this->getInputName(),
- 'fieldName' => self::INPUT_AMOUNT_NAME,
+ 'fieldName' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME),
'value' => $this->amount
]);
}
-}
+
+ /**
+ * Return a list of the fields name for this coupon.
+ *
+ * @return array
+ */
+ protected function getFieldList() {
+ return [self::AMOUNT_FIELD_NAME];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ protected function checkCouponFieldValue($fieldName, $fieldValue)
+ {
+ if ($fieldName === self::AMOUNT_FIELD_NAME) {
+
+ if (floatval($fieldValue) < 0) {
+ throw new \InvalidArgumentException(
+ Translator::getInstance()->trans(
+ 'Value %val for Disount Amount is invalid. Please enter a positive value.',
+ [ '%val' => $fieldValue]
+ )
+ );
+ }
+ }
+
+ return $fieldValue;
+ }
+
+}
\ No newline at end of file
diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercent.php b/core/lib/Thelia/Coupon/Type/RemoveXPercent.php
index e5a98c5fb..06c73981a 100644
--- a/core/lib/Thelia/Coupon/Type/RemoveXPercent.php
+++ b/core/lib/Thelia/Coupon/Type/RemoveXPercent.php
@@ -12,6 +12,7 @@
namespace Thelia\Coupon\Type;
+use Thelia\Core\Translation\Translator;
use Thelia\Coupon\FacadeInterface;
/**
@@ -29,11 +30,6 @@ class RemoveXPercent extends CouponAbstract
/** @var float Percentage removed from the Cart */
protected $percentage = 0;
- /** @var array Extended Inputs to manage */
- protected $extendedInputs = array(
- self::INPUT_PERCENTAGE_NAME
- );
-
/**
* @inheritdoc
*/
@@ -87,6 +83,26 @@ class RemoveXPercent extends CouponAbstract
return round($this->facade->getCartTotalTaxPrice() * $this->percentage/100, 2);
}
+ /**
+ * @inheritdoc
+ */
+ protected function checkCouponFieldValue($fieldName, $fieldValue)
+ {
+ if ($fieldName === self::INPUT_PERCENTAGE_NAME) {
+
+ if (floatval($fieldValue) <= 0) {
+ throw new \InvalidArgumentException(
+ Translator::getInstance()->trans(
+ 'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.',
+ [ '%val' => $fieldValue]
+ )
+ );
+ }
+ }
+
+ return $fieldValue;
+ }
+
/**
* Get I18n name
*
@@ -99,18 +115,6 @@ class RemoveXPercent extends CouponAbstract
->trans('Remove X percent to total cart', array(), 'coupon');
}
- /**
- * Get I18n amount input name
- *
- * @return string
- */
- public function getInputName()
- {
- return $this->facade
- ->getTranslator()
- ->trans('Percent Discount', array(), 'coupon');
- }
-
/**
* Get I18n tooltip
*
@@ -138,11 +142,17 @@ class RemoveXPercent extends CouponAbstract
public function drawBackOfficeInputs()
{
return $this->facade->getParser()->render('coupon/type-fragments/remove-x-percent.html', [
- 'label' => $this->getInputName(),
- 'typeKey' => self::INPUT_AMOUNT_NAME,
- 'fieldId' => self::INPUT_PERCENTAGE_NAME,
- 'fieldName' => self::INPUT_EXTENDED__NAME,
+ 'fieldName' => $this->makeCouponFieldName(self::INPUT_PERCENTAGE_NAME),
'value' => $this->percentage
]);
}
+
+ /**
+ * Return a list of the fields name for this coupon.
+ *
+ * @return array
+ */
+ protected function getFieldList() {
+ return [self::INPUT_PERCENTAGE_NAME];
+ }
}
diff --git a/core/lib/Thelia/Form/CouponCreationForm.php b/core/lib/Thelia/Form/CouponCreationForm.php
index 688e8a6ba..acb16ce70 100644
--- a/core/lib/Thelia/Form/CouponCreationForm.php
+++ b/core/lib/Thelia/Form/CouponCreationForm.php
@@ -33,6 +33,8 @@ use Thelia\Module\BaseModule;
*/
class CouponCreationForm extends BaseForm
{
+ const COUPON_CREATION_FORM_NAME = 'thelia_coupon_creation';
+
/**
* Build Coupon form
*
@@ -110,14 +112,6 @@ class CouponCreationForm extends BaseForm
)
)
)
- ->add(
- 'amount',
- 'money',
- array(
- 'constraints' => array(
- new NotBlank()
- ))
- )
->add(
'isEnabled',
'text',
@@ -198,7 +192,12 @@ class CouponCreationForm extends BaseForm
new NotBlank()
)
)
- );
+ )
+ ->add('coupon_specific', 'collection', array(
+ 'allow_add' => true,
+ 'allow_delete' => true,
+ ))
+ ;
}
/**
@@ -226,6 +225,6 @@ class CouponCreationForm extends BaseForm
*/
public function getName()
{
- return 'thelia_coupon_creation';
+ return self::COUPON_CREATION_FORM_NAME;
}
}
diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php
index 45f701876..921078eda 100644
--- a/core/lib/Thelia/Model/Coupon.php
+++ b/core/lib/Thelia/Model/Coupon.php
@@ -184,7 +184,8 @@ class Coupon extends BaseCoupon
*/
public function getAmount()
{
- $amount = $this->getEffects()['amount'];
+ // Amount is now optional
+ $amount = isset($this->getEffects()['amount']) ? $this->getEffects()['amount'] : 0;
return floatval($amount);
}
@@ -199,10 +200,6 @@ class Coupon extends BaseCoupon
{
$effects = $this->unserializeEffects($this->getSerializedEffects());
- if (null === $effects['amount']) {
- throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect coming from database');
- }
-
return $effects;
}
@@ -210,18 +207,12 @@ class Coupon extends BaseCoupon
* Get the Coupon effects
*
* @param array $effects Effect ready to be serialized
- * Needs at least the key 'amount'
- * with the amount removed from the cart
*
* @throws Exception\InvalidArgumentException
* @return $this
*/
public function setEffects(array $effects)
{
- if (null === $effects['amount']) {
- throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect ready to be serialized array');
- }
-
$this->setSerializedEffects($this->serializeEffects($effects));
return $this;
diff --git a/templates/backOffice/default/coupon/form.html b/templates/backOffice/default/coupon/form.html
index 19ed9254e..bdb8b7226 100644
--- a/templates/backOffice/default/coupon/form.html
+++ b/templates/backOffice/default/coupon/form.html
@@ -181,9 +181,7 @@
{/form_field}
- {form_field form=$form field='amount'}
{$couponInputsHtml nofilter}
- {/form_field}
diff --git a/templates/backOffice/default/coupon/type-fragments/remove-amount-on-categories.html b/templates/backOffice/default/coupon/type-fragments/remove-amount-on-categories.html
index b14a171a5..396a1ef01 100644
--- a/templates/backOffice/default/coupon/type-fragments/remove-amount-on-categories.html
+++ b/templates/backOffice/default/coupon/type-fragments/remove-amount-on-categories.html
@@ -1,7 +1,11 @@
-