- Add Coupon, Rules, CouponManager, Adapter as Services
- Refactor Coupon to use these services
This commit is contained in:
gmorel
2013-09-05 20:07:17 +02:00
parent a9b0f53334
commit eea29cba06
20 changed files with 723 additions and 169 deletions

View File

@@ -68,6 +68,52 @@ class Coupon extends BaseAction implements EventSubscriberInterface
$this->createOrUpdate($coupon, $event); $this->createOrUpdate($coupon, $event);
} }
/**
* Occurring when a Coupon rule is about to be created
*
* @param CouponCreateOrUpdateEvent $event Event creation or update Event
*/
public function createRule(CouponCreateOrUpdateEvent $event)
{
$coupon = $event->getCoupon();
$this->createOrUpdate($coupon, $event);
}
/**
* Occurring when a Coupon rule is about to be updated
*
* @param CouponCreateOrUpdateEvent $event Event creation or update Event
*/
public function updateRule(CouponCreateOrUpdateEvent $event)
{
$coupon = $event->getCoupon();
$this->createOrUpdate($coupon, $event);
}
/**
* Occurring when a Coupon rule is about to be deleted
*
* @param CouponCreateOrUpdateEvent $event Event creation or update Event
*/
public function deleteRule(CouponCreateOrUpdateEvent $event)
{
$coupon = $event->getCoupon();
$this->createOrUpdate($coupon, $event);
}
/**
* Occurring when a Coupon rule is about to be consumed
*
* @param CouponCreateOrUpdateEvent $event Event creation or update Event
*/
public function consume(CouponCreateOrUpdateEvent $event)
{
// @todo implements
}
/** /**
* Call the Model and delegate the create or delete action * Call the Model and delegate the create or delete action
* Feed the Event with the updated model * Feed the Event with the updated model
@@ -123,6 +169,12 @@ class Coupon extends BaseAction implements EventSubscriberInterface
return array( return array(
TheliaEvents::COUPON_CREATE => array("create", 128), TheliaEvents::COUPON_CREATE => array("create", 128),
TheliaEvents::COUPON_UPDATE => array("update", 128), TheliaEvents::COUPON_UPDATE => array("update", 128),
TheliaEvents::COUPON_DISABLE => array("disable", 128),
TheliaEvents::COUPON_ENABLE => array("enable", 128),
TheliaEvents::COUPON_CONSUME => array("consume", 128),
TheliaEvents::COUPON_RULE_CREATE => array("createRule", 128),
TheliaEvents::COUPON_RULE_UPDATE => array("updateRule", 128),
TheliaEvents::COUPON_RULE_DELETE => array("deleteRule", 128)
); );
} }
} }

View File

@@ -198,6 +198,33 @@
<service id="service_container" synthetic="true" /> <service id="service_container" synthetic="true" />
<service id="kernel" synthetic="true" /> <service id="kernel" synthetic="true" />
<!-- Coupon module -->
<service id="thelia.adapter" class="Thelia\Coupon\CouponBaseAdapter">
<argument type="service" id="service_container" />
</service>
<service id="thelia.coupon.manager" class="Thelia\Coupon\CouponManager">
<argument type="service" id="thelia.adapter" />
</service>
<service id="thelia.constraint.rule.available_for_x_articles" class="Thelia\Constraint\Rule\AvailableForXArticles">
<argument type="service" id="thelia.translator" />
<tag name="thelia.coupon.addRule"/>
</service>
<service id="thelia.constraint.rule.available_for_total_amount" class="Thelia\Constraint\Rule\AvailableForTotalAmount">
<argument type="service" id="thelia.translator" />
<tag name="thelia.coupon.addRule"/>
</service>
<service id="thelia.coupon.type.remove_x_amount" class="Thelia\Coupon\Type\RemoveXAmount">
<argument type="service" id="thelia.translator" />
<tag name="thelia.coupon.addCoupon"/>
</service>
<service id="thelia.coupon.type.remove_x_percent" class="Thelia\Coupon\Type\RemoveXPercent">
<argument type="service" id="thelia.translator" />
<tag name="thelia.coupon.addCoupon"/>
</service>
</services> </services>
</config> </config>

View File

@@ -24,6 +24,7 @@
namespace Thelia\Constraint\Rule; namespace Thelia\Constraint\Rule;
use Symfony\Component\Intl\Exception\NotImplementedException; use Symfony\Component\Intl\Exception\NotImplementedException;
use Symfony\Component\Translation\Translator;
use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponAdapterInterface;
use Thelia\Constraint\Validator\PriceParam; use Thelia\Constraint\Validator\PriceParam;
use Thelia\Constraint\Validator\RuleValidator; use Thelia\Constraint\Validator\RuleValidator;
@@ -48,6 +49,9 @@ class AvailableForTotalAmount extends CouponRuleAbstract
/** Rule 1st parameter : price */ /** Rule 1st parameter : price */
CONST PARAM1_PRICE = 'price'; CONST PARAM1_PRICE = 'price';
/** Rule 1st parameter : currency */
CONST PARAM1_CURRENCY = 'currency';
/** @var array Available Operators (Operators::CONST) */ /** @var array Available Operators (Operators::CONST) */
protected $availableOperators = array( protected $availableOperators = array(
Operators::INFERIOR, Operators::INFERIOR,
@@ -55,7 +59,7 @@ class AvailableForTotalAmount extends CouponRuleAbstract
Operators::SUPERIOR, Operators::SUPERIOR,
); );
/** @var RuleValidator Price Validator */ /** @var PriceParam Price Validator */
protected $priceValidator = null; protected $priceValidator = null;
/** /**
@@ -185,9 +189,11 @@ class AvailableForTotalAmount extends CouponRuleAbstract
*/ */
public function getName() public function getName()
{ {
return $this->adapter return $this->adapter->get('thelia.translator')->trans(
->getTranslator() 'Cart total amount',
->trans('Cart total amount', null, 'constraint'); array(),
'constraint'
);
} }
/** /**
@@ -197,14 +203,14 @@ class AvailableForTotalAmount extends CouponRuleAbstract
*/ */
public function getToolTip() public function getToolTip()
{ {
/** @var Translator $translator */
$translator = $this->get('thelia.translator');
$i18nOperator = Operators::getI18n( $i18nOperator = Operators::getI18n(
$this->adapter, $this->priceValidator->getOperator() $translator, $this->priceValidator->getOperator()
); );
$toolTip = $this->adapter $toolTip = $translator->trans(
->getTranslator() 'If cart total amount is <strong>%operator%</strong> %amount% %currency%',
->trans(
'If cart total amount is %operator% %amount% %currency%',
array( array(
'%operator%' => $i18nOperator, '%operator%' => $i18nOperator,
'%amount%' => $this->priceValidator->getParam()->getPrice(), '%amount%' => $this->priceValidator->getParam()->getPrice(),
@@ -216,4 +222,54 @@ class AvailableForTotalAmount extends CouponRuleAbstract
return $toolTip; return $toolTip;
} }
/**
* Populate a Rule from a form admin
*
* @param array $operators Rule Operator set by the Admin
* @param array $values Rule Values set by the Admin
*
* @throws InvalidArgumentException
* @return $this
*/
public function populateFromForm(array $operators, array $values)
{
if ($values[self::PARAM1_PRICE] === null
|| $values[self::PARAM1_CURRENCY] === null
) {
throw new InvalidArgumentException(
'The Rule ' . get_class() . 'needs at least a quantity set (' . self::PARAM1_PRICE . ', ' . self::PARAM1_CURRENCY . ')'
);
}
$this->priceValidator = new PriceParam(
$this->adapter,
$values[self::PARAM1_PRICE],
$values[self::PARAM1_CURRENCY]
);
return $this;
}
/**
* Return a serializable Rule
*
* @return SerializableRule
*/
public function getSerializableRule()
{
$serializableRule = new SerializableRule();
$serializableRule->operators = array(
self::PARAM1_PRICE => $this->priceValidator->getOperator()
);
$serializableRule->values = array(
self::PARAM1_PRICE => $this->priceValidator->getPrice(),
self::PARAM1_CURRENCY => $this->priceValidator->getCurrency()
);
return $serializableRule;
}
} }

View File

@@ -23,6 +23,8 @@
namespace Thelia\Constraint\Rule; namespace Thelia\Constraint\Rule;
use InvalidArgumentException;
use Symfony\Component\Translation\Translator;
use Thelia\Constraint\Validator\QuantityParam; use Thelia\Constraint\Validator\QuantityParam;
use Thelia\Constraint\Validator\RuleValidator; use Thelia\Constraint\Validator\RuleValidator;
use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponAdapterInterface;
@@ -51,7 +53,7 @@ class AvailableForXArticles extends CouponRuleAbstract
Operators::SUPERIOR, Operators::SUPERIOR,
); );
/** @var RuleValidator Quantity Validator */ /** @var QuantityParam Quantity Validator */
protected $quantityValidator = null; protected $quantityValidator = null;
/** /**
@@ -64,7 +66,7 @@ class AvailableForXArticles extends CouponRuleAbstract
* *
* @throws InvalidRuleException * @throws InvalidRuleException
*/ */
public function __construct(CouponAdapterInterface $adapter, array $validators) public function __construct(CouponAdapterInterface $adapter, array $validators = null)
{ {
parent::__construct($adapter, $validators); parent::__construct($adapter, $validators);
@@ -160,7 +162,7 @@ class AvailableForXArticles extends CouponRuleAbstract
$quantityValidator = $this->quantityValidator; $quantityValidator = $this->quantityValidator;
try { try {
$quantityValidator->getParam()->compareTo($quantity); $quantityValidator->getParam()->compareTo($quantity);
} catch(\InvalidArgumentException $e) { } catch(InvalidArgumentException $e) {
throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY);
} }
@@ -174,9 +176,14 @@ class AvailableForXArticles extends CouponRuleAbstract
*/ */
public function getName() public function getName()
{ {
return $this->adapter /** @var Translator $translator */
->getTranslator() $translator = $this->adapter->get('thelia.translator');
->trans('Number of articles in cart', null, 'constraint');
return $translator->trans(
'Number of articles in cart',
array(),
'constraint'
);
} }
/** /**
@@ -186,14 +193,15 @@ class AvailableForXArticles extends CouponRuleAbstract
*/ */
public function getToolTip() public function getToolTip()
{ {
/** @var Translator $translator */
$translator = $this->adapter->get('thelia.translator');
$i18nOperator = Operators::getI18n( $i18nOperator = Operators::getI18n(
$this->adapter, $this->priceValidator->getOperator() $translator, $this->priceValidator->getOperator()
); );
$toolTip = $this->adapter $toolTip = $translator->trans(
->getTranslator() 'If cart products quantity is <strong>%operator%</strong> %quantity%',
->trans(
'If cart products quantity is %operator% %quantity%',
array( array(
'%operator%' => $i18nOperator, '%operator%' => $i18nOperator,
'%quantity%' => $this->quantityValidator->getParam()->getInteger(), '%quantity%' => $this->quantityValidator->getParam()->getInteger(),
@@ -204,4 +212,49 @@ class AvailableForXArticles extends CouponRuleAbstract
return $toolTip; return $toolTip;
} }
/**
* Populate a Rule from a form admin
*
* @param array $operators Rule Operator set by the Admin
* @param array $values Rule Values set by the Admin
*
* @throws InvalidArgumentException
* @return $this
*/
public function populateFromForm(array $operators, array $values)
{
if ($values[self::PARAM1_QUANTITY] === null) {
throw new InvalidArgumentException(
'The Rule ' . get_class() . 'needs at least a quantity set (' . self::PARAM1_QUANTITY. ')'
);
}
$this->quantityValidator = new QuantityParam(
$this->adapter,
$values[self::PARAM1_QUANTITY]
);
return $this;
}
/**
* Return a serializable Rule
*
* @return SerializableRule
*/
public function getSerializableRule()
{
$serializableRule = new SerializableRule();
$serializableRule->operators = array(
self::PARAM1_QUANTITY => $this->quantityValidator->getOperator()
);
$serializableRule->values = array(
self::PARAM1_QUANTITY => $this->quantityValidator->getInteger()
);
return $serializableRule;
}
} }

View File

@@ -23,6 +23,7 @@
namespace Thelia\Constraint\Rule; namespace Thelia\Constraint\Rule;
use Symfony\Component\Translation\Translator;
use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponAdapterInterface;
/** /**
@@ -81,4 +82,31 @@ interface CouponRuleInterface
*/ */
public function getToolTip(); public function getToolTip();
/**
* Get validators
*
* @return array
*/
public function getValidators();
/**
* Populate a Rule from a form admin
*
* @param array $operators Rule Operator set by the Admin
* @param array $values Rule Values set by the Admin
*
* @return bool
*/
public function populateFromForm(array$operators, array $values);
/**
* Return a serializable Rule
*
* @return SerializableRule
*/
public function getSerializableRule();
} }

View File

@@ -23,6 +23,7 @@
namespace Thelia\Constraint\Rule; namespace Thelia\Constraint\Rule;
use Symfony\Component\Translation\Translator;
use Thelia\Constraint\Validator\ComparableInterface; use Thelia\Constraint\Validator\ComparableInterface;
/** /**
@@ -110,56 +111,54 @@ abstract class Operators
/** /**
* Get operator translation * Get operator translation
* *
* @param CouponAdapterInterface $adapter Provide necessary value from Thelia * @param Translator $translator Provide necessary value from Thelia
* @param string $operator Operator const * @param string $operator Operator const
* *
* @return string * @return string
*/ */
public static function getI18n(CouponAdapterInterface $adapter, $operator) public static function getI18n(Translator $translator, $operator)
{ {
$translator = $adapter->getTranslator();
$ret = $operator; $ret = $operator;
switch ($operator) { switch ($operator) {
case self::INFERIOR: case self::INFERIOR:
$ret = $translator->trans( $ret = $translator->trans(
'inferior to', 'inferior to',
null, array(),
'constraint' 'constraint'
); );
break; break;
case self::INFERIOR_OR_EQUAL: case self::INFERIOR_OR_EQUAL:
$ret = $translator->trans( $ret = $translator->trans(
'inferior or equals to', 'inferior or equals to',
null, array(),
'constraint' 'constraint'
); );
break; break;
case self::EQUAL: case self::EQUAL:
$ret = $translator->trans( $ret = $translator->trans(
'equals to', 'equals to',
null, array(),
'constraint' 'constraint'
); );
break; break;
case self::SUPERIOR_OR_EQUAL: case self::SUPERIOR_OR_EQUAL:
$ret = $translator->trans( $ret = $translator->trans(
'superior or equals to', 'superior or equals to',
null, array(),
'constraint' 'constraint'
); );
break; break;
case self::SUPERIOR: case self::SUPERIOR:
$ret = $translator->trans( $ret = $translator->trans(
'superior to', 'superior to',
null, array(),
'constraint' 'constraint'
); );
break; break;
case self::DIFFERENT: case self::DIFFERENT:
$ret = $translator->trans( $ret = $translator->trans(
'different from', 'different from',
null, array(),
'constraint' 'constraint'
); );
break; break;

View File

@@ -21,18 +21,29 @@
/* */ /* */
/**********************************************************************************/ /**********************************************************************************/
namespace Thelia\Coupon\Type; namespace Thelia\Constraint\Rule;
/** /**
* Created by JetBrains PhpStorm. * Created by JetBrains PhpStorm.
* Date: 8/19/13 * Date: 8/19/13
* Time: 3:24 PM * Time: 3:24 PM
* *
* @package Coupon * A rule set by an admin ready to be serialized and stored in DataBase
*
* @package Constraint
* @author Guillaume MOREL <gmorel@openstudio.fr> * @author Guillaume MOREL <gmorel@openstudio.fr>
* *
*/ */
class RemoveXAmountForCategoryY extends RemoveXAmount class SerializableRule
{ {
/** @var string Rule Service id */
public $ruleClassName = null;
/** @var array Operators set by Admin for this Rule */
public $operators = array();
/** @var array Values set by Admin for this Rule */
public $values = array();
} }

View File

@@ -24,6 +24,9 @@
namespace Thelia\Controller\Admin; namespace Thelia\Controller\Admin;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Thelia\Constraint\Rule\AvailableForTotalAmount;
use Thelia\Constraint\Rule\CouponRuleInterface;
use Thelia\Constraint\Validator\PriceParam;
use Thelia\Core\Event\Coupon\CouponCreateEvent; use Thelia\Core\Event\Coupon\CouponCreateEvent;
use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent;
use Thelia\Core\Event\Coupon\CouponEvent; use Thelia\Core\Event\Coupon\CouponEvent;
@@ -31,6 +34,8 @@ use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\HttpFoundation\Session\Session; use Thelia\Core\HttpFoundation\Session\Session;
use Thelia\Core\Security\Exception\AuthenticationException; use Thelia\Core\Security\Exception\AuthenticationException;
use Thelia\Core\Security\Exception\AuthorizationException; use Thelia\Core\Security\Exception\AuthorizationException;
use Thelia\Core\Translation\Translator;
use Thelia\Coupon\CouponAdapterInterface;
use Thelia\Coupon\CouponRuleCollection; use Thelia\Coupon\CouponRuleCollection;
use Thelia\Form\CouponCreationForm; use Thelia\Form\CouponCreationForm;
use Thelia\Form\Exception\FormValidationException; use Thelia\Form\Exception\FormValidationException;
@@ -165,6 +170,21 @@ class CouponController extends BaseAdminController
'locale' => $coupon->getLocale(), 'locale' => $coupon->getLocale(),
); );
/** @var CouponAdapterInterface $adapter */
$adapter = $this->container->get('thelia.adapter');
/** @var Translator $translator */
$translator = $this->container->get('thelia.translator');
$args['rulesObject'] = array();
/** @var CouponRuleInterface $rule */
foreach ($coupon->getRules()->getRules() as $rule) {
$args['rulesObject'][] = array(
'name' => $rule->getName(),
'tooltip' => $rule->getToolTip(),
'validators' => $rule->getValidators()
);
}
// Setup the object form // Setup the object form
$changeForm = new CouponCreationForm($this->getRequest(), 'form', $data); $changeForm = new CouponCreationForm($this->getRequest(), 'form', $data);
@@ -180,6 +200,95 @@ class CouponController extends BaseAdminController
); );
} }
/**
* Manage Coupons Rule creation display
*
* @param int $couponId Coupon id
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function createRuleAction($couponId)
{
// Check current user authorization
$response = $this->checkAuth('admin.coupon.update');
if ($response !== null) {
return $response;
}
/** @var Coupon $coupon */
$coupon = CouponQuery::create()->findOneById($couponId);
if (!$coupon) {
$this->pageNotFound();
}
// Parameters given to the template
$args = array();
$i18n = new I18n();
/** @var Lang $lang */
$lang = $this->getSession()->get('lang');
$eventToDispatch = TheliaEvents::COUPON_RULE_CREATE;
if ($this->getRequest()->isMethod('POST')) {
$this->validateCreateOrUpdateForm(
$i18n,
$lang,
$eventToDispatch,
'updated',
'update'
);
} else {
// Prepare the data that will hydrate the form
$data = array(
'code' => $coupon->getCode(),
'title' => $coupon->getTitle(),
'amount' => $coupon->getAmount(),
'effect' => $coupon->getType(),
'shortDescription' => $coupon->getShortDescription(),
'description' => $coupon->getDescription(),
'isEnabled' => ($coupon->getIsEnabled() == 1),
'expirationDate' => $coupon->getExpirationDate($lang->getDateFormat()),
'isAvailableOnSpecialOffers' => ($coupon->getIsAvailableOnSpecialOffers() == 1),
'isCumulative' => ($coupon->getIsCumulative() == 1),
'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1),
'maxUsage' => $coupon->getMaxUsage(),
'rules' => new CouponRuleCollection(array()),
'locale' => $coupon->getLocale(),
);
/** @var CouponAdapterInterface $adapter */
$adapter = $this->container->get('thelia.adapter');
/** @var Translator $translator */
$translator = $this->container->get('thelia.translator');
$args['rulesObject'] = array();
/** @var CouponRuleInterface $rule */
foreach ($coupon->getRules()->getRules() as $rule) {
$args['rulesObject'][] = array(
'name' => $rule->getName($translator),
'tooltip' => $rule->getToolTip($translator),
'validators' => $rule->getValidators()
);
}
// Setup the object form
$changeForm = new CouponCreationForm($this->getRequest(), 'form', $data);
// Pass it to the parser
$this->getParserContext()->addForm($changeForm);
}
$args['formAction'] = 'admin/coupon/update/' . $couponId;
return $this->render(
'coupon-update',
$args
);
}
/** /**
* Manage Coupons read display * Manage Coupons read display
* *
@@ -345,4 +454,26 @@ class CouponController extends BaseAdminController
return $this; return $this;
} }
// /**
// * Validation Rule creation
// *
// * @param string $type Rule class type
// * @param string $operator Rule operator (<, >, =, etc)
// * @param array $values Rules values
// *
// * @return bool
// */
// protected function validateRulesCreation($type, $operator, $values)
// {
// /** @var CouponAdapterInterface $adapter */
// $adapter = $this->container->get('thelia.adapter');
// $validator = new PriceParam()
// try {
// $rule = new AvailableForTotalAmount($adapter, $validators);
// $rule = new $type($adapter, $validators);
// } catch (\Exception $e) {
// return false;
// }
// }
} }

View File

@@ -26,9 +26,11 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Scope; use Symfony\Component\DependencyInjection\Scope;
use Thelia\Core\DependencyInjection\Compiler\RegisterCouponPass;
use Thelia\Core\DependencyInjection\Compiler\RegisterListenersPass; use Thelia\Core\DependencyInjection\Compiler\RegisterListenersPass;
use Thelia\Core\DependencyInjection\Compiler\RegisterParserPluginPass; use Thelia\Core\DependencyInjection\Compiler\RegisterParserPluginPass;
use Thelia\Core\DependencyInjection\Compiler\RegisterRouterPass; use Thelia\Core\DependencyInjection\Compiler\RegisterRouterPass;
use Thelia\Core\DependencyInjection\Compiler\RegisterRulePass;
/** /**
* First Bundle use in Thelia * First Bundle use in Thelia
@@ -60,6 +62,8 @@ class TheliaBundle extends Bundle
->addCompilerPass(new RegisterListenersPass()) ->addCompilerPass(new RegisterListenersPass())
->addCompilerPass(new RegisterParserPluginPass()) ->addCompilerPass(new RegisterParserPluginPass())
->addCompilerPass(new RegisterRouterPass()) ->addCompilerPass(new RegisterRouterPass())
->addCompilerPass(new RegisterCouponPass())
->addCompilerPass(new RegisterRulePass())
; ;
} }

View File

@@ -0,0 +1,69 @@
<?php
/**********************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/**********************************************************************************/
namespace Thelia\Core\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Created by JetBrains PhpStorm.
* Date: 9/05/13
* Time: 3:24 PM
*
* Class RegisterListenersPass
* Source code come from Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass class
*
* @package Thelia\Core\DependencyInjection\Compiler
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class RegisterCouponPass implements CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*
* @param ContainerBuilder $container Container
*
* @api
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('thelia.coupon.manager')) {
return;
}
$couponManager = $container->getDefinition('thelia.coupon.manager');
$services = $container->findTaggedServiceIds("thelia.coupon.addCoupon");
foreach ($services as $id => $rule) {
$couponManager->addMethodCall(
'addAvailableCoupon',
array(
new Reference($id)
)
);
}
}
}

View File

@@ -21,43 +21,49 @@
/* */ /* */
/**********************************************************************************/ /**********************************************************************************/
namespace Thelia\Coupon; namespace Thelia\Core\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/** /**
* Created by JetBrains PhpStorm. * Created by JetBrains PhpStorm.
* Date: 8/19/13 * Date: 9/05/13
* Time: 3:24 PM * Time: 3:24 PM
* *
* Unit Test RemoveXAmountForCategoryY Class * Class RegisterListenersPass
* Source code come from Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass class
* *
* @package Coupon * @package Thelia\Core\DependencyInjection\Compiler
* @author Guillaume MOREL <gmorel@openstudio.fr> * @author Guillaume MOREL <gmorel@openstudio.fr>
* *
*/ */
class RemoveXAmountForCategoryYTest extends \PHPUnit_Framework_TestCase class RegisterRulePass implements CompilerPassInterface
{ {
/** /**
* Sets up the fixture, for example, opens a network connection. * You can modify the container here before it is dumped to PHP code.
* This method is called before a test is executed. *
* @param ContainerBuilder $container Container
*
* @api
*/ */
protected function setUp() public function process(ContainerBuilder $container)
{ {
if (!$container->hasDefinition('thelia.coupon.manager')) {
return;
} }
public function incompleteTest() $couponManager = $container->getDefinition('thelia.coupon.manager');
{ $services = $container->findTaggedServiceIds("thelia.coupon.addCoupon");
$this->markTestIncomplete(
'This test has not been implemented yet.' foreach ($services as $id => $rule) {
$couponManager->addMethodCall(
'addAvailableCoupon',
array(
new Reference($id)
)
); );
} }
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown()
{
} }
} }

View File

@@ -249,15 +249,67 @@ final class TheliaEvents
*/ */
const AFTER_ENABLE_COUPON = "action.after_enable_coupon"; const AFTER_ENABLE_COUPON = "action.after_enable_coupon";
/**
* Sent when attempting to use a Coupon
*/
const COUPON_CONSUME = "action.consume_coupon";
/** /**
* Sent just before an attempt to use a Coupon * Sent just before an attempt to use a Coupon
*/ */
const BEFORE_USE_COUPON = "action.before_use_coupon"; const BEFORE_CONSUME_COUPON = "action.before_consume_coupon";
/** /**
* Sent just after an attempt to use a Coupon * Sent just after an attempt to use a Coupon
*/ */
const AFTER_USE_COUPON = "action.after_use_coupon"; const AFTER_CONSUME_COUPON = "action.after_consume_coupon";
/**
* Sent when attempting to create Coupon Rule
*/
const COUPON_RULE_CREATE = "action.create_coupon_rule";
/**
* Sent just before an attempt to create a Coupon Rule
*/
const BEFORE_COUPON_RULE_CREATE = "action.before_create_coupon_rule";
/**
* Sent just after an attempt to create a Coupon Rule
*/
const AFTER_COUPON_RULE_CREATE = "action.after_create_coupon_rule";
/**
* Sent when attempting to update Coupon Rule
*/
const COUPON_RULE_UPDATE = "action.update_coupon_rule";
/**
* Sent just before an attempt to update a Coupon Rule
*/
const BEFORE_COUPON_RULE_UPDATE = "action.before_update_coupon_rule";
/**
* Sent just after an attempt to update a Coupon Rule
*/
const AFTER_COUPON_RULE_UPDATE = "action.after_update_coupon_rule";
/**
* Sent when attempting to delete Coupon Rule
*/
const COUPON_RULE_DELETE = "action.delete_coupon_rule";
/**
* Sent just before an attempt to delete a Coupon Rule
*/
const BEFORE_COUPON_RULE_DELETE = "action.before_delete_coupon_rule";
/**
* Sent just after an attempt to delete a Coupon Rule
*/
const AFTER_COUPON_RULE_DELETE = "action.after_delete_coupon_rule";
// -- Configuration management --------------------------------------------- // -- Configuration management ---------------------------------------------

View File

@@ -24,6 +24,8 @@
namespace Thelia\Coupon; namespace Thelia\Coupon;
use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Thelia\Coupon\Type\CouponInterface; use Thelia\Coupon\Type\CouponInterface;
use Thelia\Model\Coupon; use Thelia\Model\Coupon;
@@ -42,6 +44,13 @@ use Thelia\Model\Coupon;
interface CouponAdapterInterface interface CouponAdapterInterface
{ {
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
function __construct(ContainerInterface $container);
/** /**
* Return a Cart a CouponManager can process * Return a Cart a CouponManager can process
* *

View File

@@ -24,6 +24,8 @@
namespace Thelia\Coupon; namespace Thelia\Coupon;
use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Thelia\Coupon\Type\CouponInterface; use Thelia\Coupon\Type\CouponInterface;
use Thelia\Model\Coupon; use Thelia\Model\Coupon;
@@ -41,6 +43,22 @@ use Thelia\Model\CouponQuery;
*/ */
class CouponBaseAdapter implements CouponAdapterInterface class CouponBaseAdapter implements CouponAdapterInterface
{ {
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var Translator Service Translator */
protected $translator = null;
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/** /**
* Return a Cart a CouponManager can process * Return a Cart a CouponManager can process
* *
@@ -189,7 +207,7 @@ class CouponBaseAdapter implements CouponAdapterInterface
*/ */
public function getTranslator() public function getTranslator()
{ {
return $this->getContainer()->get('thelia.translator'); return $this->container->get('thelia.translator');
} }

View File

@@ -24,6 +24,7 @@
namespace Thelia\Coupon; namespace Thelia\Coupon;
use Symfony\Component\Translation\Exception\NotFoundResourceException; use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Thelia\Constraint\Rule\CouponRuleInterface;
use Thelia\Coupon\Type\CouponInterface; use Thelia\Coupon\Type\CouponInterface;
use Thelia\Exception\CouponExpiredException; use Thelia\Exception\CouponExpiredException;
use Thelia\Exception\InvalidRuleException; use Thelia\Exception\InvalidRuleException;
@@ -125,4 +126,27 @@ class CouponFactory
return $coupon; return $coupon;
} }
// /**
// * Build a Coupon Rule from form
// *
// * @param string $type Rule class name
// * @param string $operator Rule Operator (<, >, = )
// * @param array $values Values setting this Rule
// *
// * @return CouponRuleInterface Ready to use Rule or false
// */
// public function buildCouponRuleFromForm($ruleClassName, $operator, array $values)
// {
// /** @var CouponAdapterInterface $adapter */
// $adapter = $this->container->get('thelia.adapter');
// $validator = new PriceParam()
// try {
// $rule = new AvailableForTotalAmount($adapter, $validators);
// $rule = new $type($adapter, $validators);
// } catch (\Exception $e) {
// return false;
// }
// }
} }

View File

@@ -23,6 +23,8 @@
namespace Thelia\Coupon; namespace Thelia\Coupon;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Constraint\Rule\CouponRuleInterface;
use Thelia\Coupon\Type\CouponInterface; use Thelia\Coupon\Type\CouponInterface;
/** /**
@@ -39,21 +41,23 @@ use Thelia\Coupon\Type\CouponInterface;
class CouponManager class CouponManager
{ {
/** @var CouponAdapterInterface Provides necessary value from Thelia */ /** @var CouponAdapterInterface Provides necessary value from Thelia */
protected $adapter; protected $adapter = null;
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var array CouponInterface to process*/ /** @var array CouponInterface to process*/
protected $coupons = array(); protected $coupons = array();
/** /**
* Constructor * Constructor
* Gather Coupons from Adapter
* via $adapter->getCurrentCoupons();
* *
* @param CouponAdapterInterface $adapter Provide necessary value from Thelia * @param ContainerInterface $container Service container
*/ */
function __construct(CouponAdapterInterface $adapter) function __construct(ContainerInterface $container)
{ {
$this->adapter = $adapter; $this->container = $container;
$this->adapter = $container->get('thelia.adapter');
$this->coupons = $this->adapter->getCurrentCoupons(); $this->coupons = $this->adapter->getCurrentCoupons();
} }
@@ -178,4 +182,30 @@ class CouponManager
return $discount; return $discount;
} }
/**
* Build a CouponRuleInterface from data coming from a form
*
* @param string $ruleServiceId Rule service id you want to instantiate
* @param array $operators Rule Operator set by the Admin
* @param array $values Rule Values set by the Admin
*
* @return CouponRuleInterface
*/
public function buildRuleFromForm($ruleServiceId, array $operators, array $values)
{
$rule = false;
try {
if ($this->container->has($ruleServiceId)) {
/** @var CouponRuleInterface $rule */
$rule = $this->container->get($ruleServiceId);
$rule->populateFromForm($operators, $values);
}
} catch (\InvalidArgumentException $e) {
}
return $rule;
}
} }

View File

@@ -176,4 +176,5 @@ interface CouponInterface
* @return string * @return string
*/ */
public function getToolTip(); public function getToolTip();
} }

View File

@@ -495,6 +495,8 @@ function setI18n($faker, &$object)
*/ */
function generateCouponFixtures() function generateCouponFixtures()
{ {
$adapter = new \Thelia\Coupon\CouponBaseAdapter();
// Coupons // Coupons
$coupon1 = new Thelia\Model\Coupon(); $coupon1 = new Thelia\Model\Coupon();
$coupon1->setCode('XMAS'); $coupon1->setCode('XMAS');
@@ -516,31 +518,35 @@ Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesua
$date = new \DateTime(); $date = new \DateTime();
$coupon1->setExpirationDate($date->setTimestamp(strtotime("today + 2 months"))); $coupon1->setExpirationDate($date->setTimestamp(strtotime("today + 2 months")));
// $rule1 = new Thelia\Constraint\Rule\AvailableForTotalAmount( $rule1 = new Thelia\Constraint\Rule\AvailableForTotalAmount(
// array( $adapter,
// Thelia\Constraint\Rule\AvailableForTotalAmount::PARAM1_PRICE => new Thelia\Constraint\Validator\RuleValidator( array(
// Thelia\Constraint\Rule\Operators::SUPERIOR, Thelia\Constraint\Rule\AvailableForTotalAmount::PARAM1_PRICE => new Thelia\Constraint\Validator\RuleValidator(
// new Thelia\Constraint\Validator\PriceParam( Thelia\Constraint\Rule\Operators::SUPERIOR,
// 40.00, new Thelia\Constraint\Validator\PriceParam(
// 'EUR' $adapter,
// ) 40.00,
// ) 'EUR'
// ) )
// ); )
// $rule2 = new Thelia\Constraint\Rule\AvailableForTotalAmount( )
// array( );
// Thelia\Constraint\Rule\AvailableForTotalAmount::PARAM1_PRICE => new Thelia\Coupon\Parameter\RuleValidator( $rule2 = new Thelia\Constraint\Rule\AvailableForTotalAmount(
// Thelia\Constraint\Rule\Operators::INFERIOR, $adapter,
// new Thelia\Constraint\Parameter\PriceParam( array(
// 400.00, Thelia\Constraint\Rule\AvailableForTotalAmount::PARAM1_PRICE => new Thelia\Constraint\Validator\RuleValidator(
// 'EUR' Thelia\Constraint\Rule\Operators::INFERIOR,
// ) new Thelia\Constraint\Validator\PriceParam(
// ) $adapter,
// ) 400.00,
// ); 'EUR'
// $rules = new \Thelia\Coupon\CouponRuleCollection(array($rule1, $rule2)); )
)
)
);
$rules = new \Thelia\Coupon\CouponRuleCollection(array($rule1, $rule2));
// $coupon1->setSerializedRules(base64_encode(serialize($rules))); $coupon1->setSerializedRules(base64_encode(serialize($rules)));
$coupon1->setIsCumulative(1); $coupon1->setIsCumulative(1);
$coupon1->setIsRemovingPostage(0); $coupon1->setIsRemovingPostage(0);

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# @author Guillaume MOREL # @author Guillaume MOREL
# v0.1 # v0.2
echo -e "\033[47m\033[1;31m\n[WARN] This script will reset this Thelia2 install\n\033[0m" echo -e "\033[47m\033[1;31m\n[WARN] This script will reset this Thelia2 install\n\033[0m"
@@ -15,11 +15,10 @@ echo -e "\n\e[01;34m[INFO] Building Models file\e[00m\n"
echo -e "\n\e[01;34m[INFO] Building SQL CREATE file\e[00m\n" echo -e "\n\e[01;34m[INFO] Building SQL CREATE file\e[00m\n"
../../bin/propel sql:build -v --output-dir=../../install/ ../../bin/propel sql:build -v --output-dir=../../install/
echo -e "\n\e[01;34m[INFO] Reloaded Thelia2 database\e[00m\n"
echo -e "\n\e[01;34m[INFO] Reloaded Thelia2 database\e[00m\n" cd ../..
cd ../.. rm install/sqldb.map
rm install/sqldb.map php Thelia thelia:dev:reloadDB
php Thelia thelia:dev:reloadDB
echo -e "\n\e[01;34m[INFO] Installing fixtures\e[00m\n" echo -e "\n\e[01;34m[INFO] Installing fixtures\e[00m\n"
php install/faker.php php install/faker.php
@@ -27,5 +26,4 @@ php install/faker.php
echo -e "\n\e[01;34m[INFO] Adding admin\e[00m\n" echo -e "\n\e[01;34m[INFO] Adding admin\e[00m\n"
php Thelia thelia:create-admin --login_name thelia2 --password thelia2 --last_name thelia2 --first_name thelia2 php Thelia thelia:create-admin --login_name thelia2 --password thelia2 --last_name thelia2 --first_name thelia2
echo -e "\n\e[00;32m[SUCCESS] Reset done\e[00m\n" echo -e "\n\e[00;32m[SUCCESS] Reset done\e[00m\n"
fi

View File

@@ -18,17 +18,17 @@
<div class="control-group"> <div class="control-group">
<div class="col-md-4"> <div class="col-md-4">
<div class="form-group"> <div class="form-group">
<label for="code">Code :</label> <label for="code">{intl l='Code :'}</label>
{form_field form=$form field='code'} {form_field form=$form field='code'}
<input id="code" class="form-control" type="text" name="{$name}" value="{$value}" placeholder="code"> <input id="code" class="form-control" type="text" name="{$name}" value="{$value}" placeholder="{intl l='code'}">
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="title">Title :</label> <label for="title">{intl l='Title :'}</label>
{form_field form=$form field='title'} {form_field form=$form field='title'}
<input id="title" class="form-control" type="text" name="{$name}" value="{$value}" placeholder="title"> <input id="title" class="form-control" type="text" name="{$name}" value="{$value}" placeholder="{intl l='title'}">
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
</div> </div>
@@ -39,7 +39,7 @@
<input id="enabled" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} > <input id="enabled" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} >
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
Is enabled ? {intl l='Is enabled ?'}
</label> </label>
</div> </div>
@@ -49,7 +49,7 @@
<input id="available-on-special-offers" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} > <input id="available-on-special-offers" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} >
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
Is available on special offers ? {intl l='Is available on special offers ?'}
</label> </label>
</div> </div>
@@ -59,7 +59,7 @@
<input id="cumulative" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} > <input id="cumulative" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} >
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
Is cumulative ? {intl l='Is cumulative ?'}
</label> </label>
</div> </div>
@@ -69,12 +69,12 @@
<input id="renoving-postage" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} > <input id="renoving-postage" type="checkbox" name="{$name}" {if $value}value="1" checked{else}value="0"{/if} >
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
Is removing postage ? {intl l='Is removing postage ?'}
</label> </label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="expiration-date">Expiration date :</label> <label for="expiration-date">{intl l='Expiration date :'}</label>
<div class="input-append date" data-date="12/02/2012" data-date-format="dd/mm/yyyy"> <div class="input-append date" data-date="12/02/2012" data-date-format="dd/mm/yyyy">
{form_field form=$form field='expirationDate'} {form_field form=$form field='expirationDate'}
<input type="text" id="expiration-date" name="{$name}" value="{if $defaultDate}{$defaultDate}{else}{$value}{/if}"> <input type="text" id="expiration-date" name="{$name}" value="{if $defaultDate}{$defaultDate}{else}{$value}{/if}">
@@ -85,13 +85,13 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="max-usage">Max usage :</label> <label for="max-usage">{intl l='Max usage :'}</label>
<label for="is-unlimited" class="checkbox"> <label for="is-unlimited" class="checkbox">
<input id="is-unlimited" type="checkbox" name="is-unlimited" checked > <input id="is-unlimited" type="checkbox" name="is-unlimited" checked >
Is unlimited ? {intl l='Is unlimited ?'}
</label> </label>
{form_field form=$form field='maxUsage'} {form_field form=$form field='maxUsage'}
<input id="max-usage" type="text" class="form-control" name="{$name}" value="{$value}" placeholder="max usage"> <input id="max-usage" type="text" class="form-control" name="{$name}" value="{$value}" placeholder="{intl l='max usage'}">
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
</div> </div>
@@ -101,7 +101,7 @@
<div class="well clearfix"> <div class="well clearfix">
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="effect">Effect :</label> <label for="effect">{intl l='Effect :'}</label>
{form_field form=$form field='effect'} {form_field form=$form field='effect'}
<select name="{$name}" value="{$value}" id="effect" class="col-md-12 form-control"> <select name="{$name}" value="{$value}" id="effect" class="col-md-12 form-control">
<option value="1" data-description="More description n°1 about item">Remove x percents for category Y</option> <option value="1" data-description="More description n°1 about item">Remove x percents for category Y</option>
@@ -116,9 +116,9 @@
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group"> <div class="form-group">
<label for="amount">Amount :</label> <label for="amount">{intl l='Amount :'}</label>
{form_field form=$form field='amount'} {form_field form=$form field='amount'}
<input id="amount" type="text" class="form-control" name="{$name}" value="{$value}" placeholder="amount"> <input id="amount" type="text" class="form-control" name="{$name}" value="{$value}" placeholder="{intl l='14.50'}">
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
</div> </div>
@@ -137,9 +137,9 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="short-description">Short description :</label> <label for="short-description">{intl l='Short description :'}</label>
{form_field form=$form field='shortDescription'} {form_field form=$form field='shortDescription'}
<textarea id="short-description" name="{$name}" placeholder="short description" class="span12" rows="5">{$value nofilter}</textarea> <textarea id="short-description" name="{$name}" placeholder="{intl l='short description'}" class="span12" rows="5">{$value nofilter}</textarea>
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
</div> </div>
@@ -149,14 +149,14 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="form-group"> <div class="form-group">
<label for="description">Long description :</label> <label for="description">{intl l='Long description :'}</label>
{form_field form=$form field='description'} {form_field form=$form field='description'}
<textarea id="description" name="{$name}" placeholder="long description" class="form-control wysiwyg" rows="10">{$value nofilter}</textarea> <textarea id="description" name="{$name}" placeholder="{intl l='long description'}" class="form-control wysiwyg" rows="10">{$value nofilter}</textarea>
{if $error}{$message}{/if} {if $error}{$message}{/if}
{/form_field} {/form_field}
</div> </div>
<button type="submit" class="btn btn-default btn-primary">Save</button> <button type="submit" class="btn btn-default btn-primary">{intl l='Save'}</button>
</div> </div>
</div> </div>
@@ -166,47 +166,27 @@
<div class="col-md-12 general-block-decorator"> <div class="col-md-12 general-block-decorator">
<table class="table table-striped"> <table class="table table-striped">
<caption class="clearfix"> <caption class="clearfix">
Rules {intl l='Rules'}
<a class="btn btn-default btn-primary pull-right" title="Add a new rule"> <a class="btn btn-default btn-primary pull-right" title="{intl l='Add a new rule'}">
<span class="glyphicon glyphicon-plus-sign"></span> <span class="glyphicon glyphicon-plus-sign"></span>
</a> </a>
</caption> </caption>
<thead> <thead>
<tr> <tr>
<th>Conditions</th> <th>{intl l='Conditions'}</th>
<th>Operator</th> <th>{intl l='Actions'}</th>
<th>Value</th>
<th>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach from=$rulesObject item=rule}
<tr> <tr>
<td>Total Amount</td> <td>{$rule.tooltip}</td>
<td><span class="label">is superior or equals to</span></td>
<td>300 &euro;</td>
<td> <td>
<a href="#url" class="btn btn-default btn-primary btn-medium"><span class="glyphicon glyphicon-edit"></span> Edit</a> <a href="#url" class="btn btn-default btn-primary btn-medium"><span class="glyphicon glyphicon-edit"></span> {intl l='Edit'}</a>
<a href="#url" class="btn btn-default btn-danger btn-medium" data-toggle="confirm" data-target="#delete"><span class="glyphicon glyphicon-remove"></span> Delete</a> <a href="#url" class="btn btn-default btn-danger btn-medium" data-toggle="confirm" data-target="#delete"><span class="glyphicon glyphicon-remove"></span> {intl l='Delete'}</a>
</td>
</tr>
<tr>
<td><span class="label">AND</span> NbArticleFromCategory</td>
<td><span class="label">is equals to</span></td>
<td>12 - <a href="#" target="_blank">Chaussettes rouges</a></td>
<td>
<a href="#url" class="btn btn-default btn-primary btn-medium"><span class="glyphicon glyphicon-edit"></span> Edit</a>
<a href="#url" class="btn btn-default btn-danger btn-medium" data-toggle="confirm" data-target="#delete"><span class="glyphicon glyphicon-remove"></span> Delete</a>
</td>
</tr>
<tr>
<td><span class="label label-info">OR</span> Date</td>
<td><span class="label">is inferior or equals to</span></td>
<td>12/02/2014</td>
<td>
<a href="#url" class="btn btn-default btn-primary btn-medium"><span class="glyphicon glyphicon-edit"></span> Edit</a>
<a href="#url" class="btn btn-default btn-danger btn-medium" data-toggle="confirm" data-target="#delete"><span class="glyphicon glyphicon-remove"></span> Delete</a>
</td> </td>
</tr> </tr>
{/foreach}
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -216,17 +196,17 @@
<div class="col-md-12 general-block-decorator clearfix"> <div class="col-md-12 general-block-decorator clearfix">
<div class="form-group col-md-2"> <div class="form-group col-md-2">
<label for="type">Condition type :</label> <label for="type">{intl l='Condition type :'}</label>
<label class="radio"> <label class="radio">
<input type="radio" name="type" id="type" value="1" checked> And <input type="radio" name="type" id="type" value="1" checked> {intl l='And'}
</label> </label>
<label class="radio"> <label class="radio">
<input type="radio" name="type" value="2"> Or <input type="radio" name="type" value="2"> {intl l='Or'}
</label> </label>
</div> </div>
<div class="form-group col-md-4"> <div class="form-group col-md-4">
<label for="category-rule">Rule's category :</label> <label for="category-rule">{intl l='Rule\'s category :'}</label>
<select name="categoryRule" id="category-rule" class="form-control"> <select name="categoryRule" id="category-rule" class="form-control">
<option value="1" selected>Total amount</option> <option value="1" selected>Total amount</option>
<option value="2">Date</option> <option value="2">Date</option>
@@ -249,7 +229,7 @@
</div> </div>
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="operator">Operator :</label> <label for="operator">{intl l='Operator :'}</label>
<div class="row"> <div class="row">
<div class="col-lg-6"> <div class="col-lg-6">
<select name="operator" id="operator" class="form-control"> <select name="operator" id="operator" class="form-control">