diff --git a/core/lib/Thelia/Action/Coupon.php b/core/lib/Thelia/Action/Coupon.php index d50f72aa8..036502c68 100755 --- a/core/lib/Thelia/Action/Coupon.php +++ b/core/lib/Thelia/Action/Coupon.php @@ -23,10 +23,16 @@ namespace Thelia\Action; +use Symfony\Component\Config\Definition\Exception\Exception; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Constraint\ConstraintFactory; +use Thelia\Core\Event\Coupon\CouponConsumeEvent; use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Coupon\CouponFactory; +use Thelia\Coupon\CouponManager; +use Thelia\Coupon\Type\CouponInterface; use Thelia\Model\Coupon as CouponModel; /** @@ -45,7 +51,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface /** * Occurring when a Coupon is about to be created * - * @param CouponCreateOrUpdateEvent $event Event creation or update Event + * @param CouponCreateOrUpdateEvent $event Event creation or update Coupon */ public function create(CouponCreateOrUpdateEvent $event) { @@ -57,7 +63,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface /** * Occurring when a Coupon is about to be updated * - * @param CouponCreateOrUpdateEvent $event Event creation or update Event + * @param CouponCreateOrUpdateEvent $event Event creation or update Coupon */ public function update(CouponCreateOrUpdateEvent $event) { @@ -69,7 +75,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface /** * Occurring when a Coupon rule is about to be updated * - * @param CouponCreateOrUpdateEvent $event Event creation or update Event + * @param CouponCreateOrUpdateEvent $event Event creation or update Coupon Rule */ public function updateRule(CouponCreateOrUpdateEvent $event) { @@ -81,11 +87,43 @@ class Coupon extends BaseAction implements EventSubscriberInterface /** * Occurring when a Coupon rule is about to be consumed * - * @param CouponCreateOrUpdateEvent $event Event creation or update Event + * @param CouponConsumeEvent $event Event consuming Coupon */ - public function consume(CouponCreateOrUpdateEvent $event) + public function consume(CouponConsumeEvent $event) { - // @todo implements + $totalDiscount = 0; + + /** @var CouponFactory $couponFactory */ + $couponFactory = $this->container->get('thelia.coupon.factory'); + + /** @var CouponManager $couponManager */ + $couponManager = $this->container->get('thelia.coupon.manager'); + + /** @var CouponInterface $coupon */ + $coupon = $couponFactory->buildCouponFromCode($event->getCode()); + + $isValid = $coupon->isMatching(); + if ($isValid) { + /** @var Request $request */ + $request = $this->container->get('request'); + $consumedCoupons = $request->getSession()->getConsumedCoupons(); + + if (!isset($consumedCoupons) || !$consumedCoupons) { + $consumedCoupons = array(); + } + + // Prevent accumulation of the same Coupon on a Checkout + $consumedCoupons[$event->getCode()] = $event->getCode(); + + $request->getSession()->setConsumedCoupons($consumedCoupons); + + $totalDiscount = $couponManager->getDiscount(); + + // @todo modify Cart total discount + } + + $event->setIsValid($isValid); + $event->setDiscount($totalDiscount); } /** @@ -165,8 +203,6 @@ class Coupon extends BaseAction implements EventSubscriberInterface return array( TheliaEvents::COUPON_CREATE => array("create", 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_UPDATE => array("updateRule", 128) ); diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index 8098eb9d4..9735aca36 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -235,6 +235,8 @@ + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 5c9399e27..8812d8ad4 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -103,25 +103,27 @@ - + Thelia\Controller\Admin\CouponController::browseAction - + Thelia\Controller\Admin\CouponController::createAction - + Thelia\Controller\Admin\CouponController::updateAction - + Thelia\Controller\Admin\CouponController::readAction - + Thelia\Controller\Admin\CouponController::getRuleInputAction Thelia\Controller\Admin\CouponController::updateRulesAction - + + Thelia\Controller\Admin\CouponController::consumeAction + diff --git a/core/lib/Thelia/Constraint/ConstraintFactory.php b/core/lib/Thelia/Constraint/ConstraintFactory.php index e96509172..e13d1d2aa 100644 --- a/core/lib/Thelia/Constraint/ConstraintFactory.php +++ b/core/lib/Thelia/Constraint/ConstraintFactory.php @@ -25,6 +25,7 @@ namespace Thelia\Constraint; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Thelia\Constraint\Rule\AvailableForEveryoneManager; use Thelia\Constraint\Rule\AvailableForTotalAmountManager; use Thelia\Constraint\Rule\CouponRuleInterface; use Thelia\Constraint\Rule\SerializableRule; @@ -74,11 +75,22 @@ class ConstraintFactory */ public function serializeCouponRuleCollection(CouponRuleCollection $collection) { + if ($collection->isEmpty()) { + /** @var CouponRuleInterface $ruleNoCondition */ + $ruleNoCondition = $this->container->get( + 'thelia.constraint.rule.available_for_everyone' + ); + $collection->add($ruleNoCondition); + } $serializableRules = array(); $rules = $collection->getRules(); if ($rules !== null) { /** @var $rule CouponRuleInterface */ foreach ($rules as $rule) { + // Remove all rule if the "no condition" rule is found +// if ($rule->getServiceId() == 'thelia.constraint.rule.available_for_everyone') { +// return base64_encode(json_encode(array($rule->getSerializableRule()))); +// } $serializableRules[] = $rule->getSerializableRule(); } } diff --git a/core/lib/Thelia/Constraint/ConstraintValidator.php b/core/lib/Thelia/Constraint/ConstraintValidator.php index edacee317..325faed22 100644 --- a/core/lib/Thelia/Constraint/ConstraintValidator.php +++ b/core/lib/Thelia/Constraint/ConstraintValidator.php @@ -52,7 +52,7 @@ class ConstraintValidator * * @return bool */ - public function test(CouponRuleCollection $rules) + public function isMatching(CouponRuleCollection $rules) { $isMatching = true; /** @var CouponRuleInterface $rule */ diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php index 9f1bf23a0..30bc86ad6 100644 --- a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php +++ b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php @@ -25,7 +25,6 @@ namespace Thelia\Constraint\Rule; use Symfony\Component\Intl\Exception\NotImplementedException; use Symfony\Component\Translation\Translator; -use Thelia\Constraint\ConstraintValidator; use Thelia\Coupon\CouponAdapterInterface; use Thelia\Constraint\Validator\PriceParam; use Thelia\Constraint\Validator\RuleValidator; @@ -168,13 +167,12 @@ class AvailableForTotalAmountManager extends CouponRuleAbstract return false; } - $constrainValidator = new ConstraintValidator(); - $constraint1 =$constrainValidator->variableOpComparison( + $constraint1 = $this->constraintValidator->variableOpComparison( $this->adapter->getCartTotalPrice(), $this->operators[self::INPUT1], $this->values[self::INPUT1] ); - $constraint2 =$constrainValidator->variableOpComparison( + $constraint2 = $this->constraintValidator->variableOpComparison( $this->adapter->getCheckoutCurrency(), $this->operators[self::INPUT2], $this->values[self::INPUT2] diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php index 26c7a8aeb..572d39b1d 100644 --- a/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php +++ b/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php @@ -126,8 +126,7 @@ class AvailableForXArticlesManager extends CouponRuleAbstract */ public function isMatching() { - $constrainValidator = new ConstraintValidator(); - $constraint1 =$constrainValidator->variableOpComparison( + $constraint1 = $this->constraintValidator->variableOpComparison( $this->adapter->getNbArticlesInCart(), $this->operators[self::INPUT1], $this->values[self::INPUT1] diff --git a/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php b/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php index 1cab6c48b..942e48d1f 100644 --- a/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php +++ b/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php @@ -82,6 +82,7 @@ abstract class CouponRuleAbstract implements CouponRuleInterface { $this->adapter = $adapter; $this->translator = $adapter->getTranslator(); + $this->constraintValidator = $adapter->getConstraintValidator(); } // /** diff --git a/core/lib/Thelia/Constraint/Rule/Operators.php b/core/lib/Thelia/Constraint/Rule/Operators.php index 41640810c..2ed5c2909 100644 --- a/core/lib/Thelia/Constraint/Rule/Operators.php +++ b/core/lib/Thelia/Constraint/Rule/Operators.php @@ -133,21 +133,21 @@ abstract class Operators break; case self::INFERIOR_OR_EQUAL: $ret = $translator->trans( - 'inferior or equals to', + 'inferior or equal to', array(), 'constraint' ); break; case self::EQUAL: $ret = $translator->trans( - 'equals to', + 'equal to', array(), 'constraint' ); break; case self::SUPERIOR_OR_EQUAL: $ret = $translator->trans( - 'superior or equals to', + 'superior or equal to', array(), 'constraint' ); diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php index cd8521d7a..6803addfd 100755 --- a/core/lib/Thelia/Controller/Admin/CouponController.php +++ b/core/lib/Thelia/Controller/Admin/CouponController.php @@ -30,6 +30,7 @@ use Thelia\Constraint\ConstraintFactoryTest; use Thelia\Constraint\Rule\AvailableForTotalAmount; use Thelia\Constraint\Rule\CouponRuleInterface; use Thelia\Constraint\Validator\PriceParam; +use Thelia\Core\Event\Coupon\CouponConsumeEvent; use Thelia\Core\Event\Coupon\CouponCreateEvent; use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; use Thelia\Core\Event\Coupon\CouponEvent; @@ -39,6 +40,7 @@ use Thelia\Core\Security\Exception\AuthenticationException; use Thelia\Core\Security\Exception\AuthorizationException; use Thelia\Core\Translation\Translator; use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Coupon\CouponFactory; use Thelia\Coupon\CouponManager; use Thelia\Coupon\CouponRuleCollection; use Thelia\Coupon\Type\CouponInterface; @@ -72,7 +74,54 @@ class CouponController extends BaseAdminController { $this->checkAuth('ADMIN', 'admin.coupon.view'); - return $this->render('coupon-list'); + $args['urlReadCoupon'] = $this->getRoute( + 'admin.coupon.read', + array('couponId' => 'couponId'), + Router::ABSOLUTE_URL + ); + + $args['urlEditCoupon'] = $this->getRoute( + 'admin.coupon.update', + array('couponId' => 'couponId'), + Router::ABSOLUTE_URL + ); + + $args['urlCreateCoupon'] = $this->getRoute( + 'admin.coupon.create', + array(), + Router::ABSOLUTE_URL + ); + + return $this->render('coupon-list', $args); + } + + /** + * Manage Coupons read display + * + * @param int $couponId Coupon Id + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function readAction($couponId) + { + $this->checkAuth('ADMIN', 'admin.coupon.read'); + + // Database request repeated in the loop but cached + $search = CouponQuery::create(); + $coupon = $search->findOneById($couponId); + + if ($coupon === null) { + return $this->pageNotFound(); + } + + $args['couponId'] = $couponId; + $args['urlEditCoupon'] = $this->getRoute( + 'admin.coupon.update', + array('couponId' => $couponId), + Router::ABSOLUTE_URL + ); + + return $this->render('coupon-read', $args); } /** @@ -93,7 +142,7 @@ class CouponController extends BaseAdminController $i18n = new I18n(); /** @var Lang $lang */ - $lang = $this->getSession()->get('lang'); + $lang = $this->getSession()->getLang(); $eventToDispatch = TheliaEvents::COUPON_CREATE; if ($this->getRequest()->isMethod('POST')) { @@ -108,10 +157,12 @@ class CouponController extends BaseAdminController // If no input for expirationDate, now + 2 months $defaultDate = new \DateTime(); $args['defaultDate'] = $defaultDate->modify('+2 month') - ->format($lang->getDateFormat()); + ->format('Y-m-d'); } - $args['formAction'] = 'admin/coupon/create'; + $args['dateFormat'] = $this->getSession()->getLang()->getDateFormat(); + $args['availableCoupons'] = $this->getAvailableCoupons(); + $args['formAction'] = 'admin/coupon/create/'; return $this->render( 'coupon-create', @@ -135,7 +186,7 @@ class CouponController extends BaseAdminController } /** @var Coupon $coupon */ - $coupon = CouponQuery::create()->findOneById($couponId); + $coupon = CouponQuery::create()->findPk($couponId); if (!$coupon) { $this->pageNotFound(); } @@ -148,6 +199,7 @@ class CouponController extends BaseAdminController $lang = $this->getSession()->getLang(); $eventToDispatch = TheliaEvents::COUPON_UPDATE; + // Create if ($this->getRequest()->isMethod('POST')) { $this->validateCreateOrUpdateForm( $i18n, @@ -156,9 +208,9 @@ class CouponController extends BaseAdminController 'updated', 'update' ); - } else { - // Prepare the data that will hydrate the form + } else { // Update + // Prepare the data that will hydrate the form /** @var ConstraintFactory $constraintFactory */ $constraintFactory = $this->container->get('thelia.constraint.factory'); $rules = $constraintFactory->unserializeCouponRuleCollection( @@ -173,7 +225,7 @@ class CouponController extends BaseAdminController 'shortDescription' => $coupon->getShortDescription(), 'description' => $coupon->getDescription(), 'isEnabled' => ($coupon->getIsEnabled() == 1), - 'expirationDate' => $coupon->getExpirationDate($lang->getDateFormat()), + 'expirationDate' => $coupon->getExpirationDate('Y-m-d'), 'isAvailableOnSpecialOffers' => ($coupon->getIsAvailableOnSpecialOffers() == 1), 'isCumulative' => ($coupon->getIsCumulative() == 1), 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), @@ -202,7 +254,7 @@ class CouponController extends BaseAdminController // Pass it to the parser $this->getParserContext()->addForm($changeForm); } - + $args['couponCode'] = $coupon->getCode(); $args['availableCoupons'] = $this->getAvailableCoupons(); $args['availableRules'] = $this->getAvailableRules(); $args['urlAjaxGetRuleInput'] = $this->getRoute( @@ -222,123 +274,6 @@ class CouponController extends BaseAdminController return $this->render('coupon-update', $args); } - -// /** -// * 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 -// -// /** @var ConstraintFactory $constraintFactory */ -// $constraintFactory = $this->container->get('thelia.constraint.factory'); -// -// $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' => $constraintFactory->unserializeCouponRuleCollection($coupon->getSerializedRules()), -// '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() -// ); -// } -// -// $args['rules'] = $this->cleanRuleForTemplate($coupon->getRules()->getRules()); -// -// // 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 - * - * @param int $couponId Coupon Id - * - * @return \Symfony\Component\HttpFoundation\Response - */ - public function readAction($couponId) - { - $this->checkAuth('ADMIN', 'admin.coupon.read'); - - // Database request repeated in the loop but cached - $search = CouponQuery::create(); - $coupon = $search->findOneById($couponId); - - if ($coupon === null) { - return $this->pageNotFound(); - } - - return $this->render('coupon-read', array('couponId' => $couponId)); - } - /** * Manage Coupons read display * @@ -350,17 +285,7 @@ class CouponController extends BaseAdminController { $this->checkAuth('ADMIN', 'admin.coupon.read'); - if ($this->isDebug()) { - if (!$this->getRequest()->isXmlHttpRequest()) { - $this->redirect( - $this->getRoute( - 'admin', - array(), - Router::ABSOLUTE_URL - ) - ); - } - } + $this->checkXmlHttpRequest(); /** @var ConstraintFactory $constraintFactory */ $constraintFactory = $this->container->get('thelia.constraint.factory'); @@ -391,17 +316,7 @@ class CouponController extends BaseAdminController { $this->checkAuth('ADMIN', 'admin.coupon.read'); - if ($this->isDebug()) { - if (!$this->getRequest()->isXmlHttpRequest()) { - $this->redirect( - $this->getRoute( - 'admin', - array(), - Router::ABSOLUTE_URL - ) - ); - } - } + $this->checkXmlHttpRequest(); $search = CouponQuery::create(); /** @var Coupon $coupon */ @@ -475,6 +390,29 @@ class CouponController extends BaseAdminController ); } + /** + * Test Coupon consuming + * + * @param string $couponCode Coupon code + * + */ + public function consumeAction($couponCode) + { + // @todo remove (event dispatcher testing purpose) + $couponConsumeEvent = new CouponConsumeEvent($couponCode); + $eventToDispatch = TheliaEvents::COUPON_CONSUME; + + // Dispatch Event to the Action + $this->dispatch( + $eventToDispatch, + $couponConsumeEvent + ); + + var_dump('test', $couponConsumeEvent->getCode(), $couponConsumeEvent->getDiscount(), $couponConsumeEvent->getIsValid()); + + exit(); + } + /** * Build a Coupon from its form * @@ -535,7 +473,7 @@ class CouponController extends BaseAdminController /** * Validate the CreateOrUpdate form * - * @param string $i18n Local code (fr_FR) + * @param I18n $i18n Local code (fr_FR) * @param Lang $lang Local variables container * @param string $eventToDispatch Event which will activate actions * @param string $log created|edited @@ -543,7 +481,7 @@ class CouponController extends BaseAdminController * * @return $this */ - protected function validateCreateOrUpdateForm($i18n, $lang, $eventToDispatch, $log, $action) + protected function validateCreateOrUpdateForm(I18n $i18n, Lang $lang, $eventToDispatch, $log, $action) { // Create the form from the request $creationForm = new CouponCreationForm($this->getRequest()); @@ -563,7 +501,7 @@ class CouponController extends BaseAdminController $data['shortDescription'], $data['description'], $data['isEnabled'], - $i18n->getDateTimeFromForm($lang, $data['expirationDate']), + \DateTime::createFromFormat('Y-m-d', $data['expirationDate']), $data['isAvailableOnSpecialOffers'], $data['isCumulative'], $data['isRemovingPostage'], @@ -651,17 +589,17 @@ class CouponController extends BaseAdminController /** @var CouponManager $couponManager */ $couponManager = $this->container->get('thelia.coupon.manager'); $availableCoupons = $couponManager->getAvailableCoupons(); - $cleanedRules = array(); + $cleanedCoupons = array(); /** @var CouponInterface $availableCoupon */ foreach ($availableCoupons as $availableCoupon) { $rule = array(); $rule['serviceId'] = $availableCoupon->getServiceId(); $rule['name'] = $availableCoupon->getName(); $rule['toolTip'] = $availableCoupon->getToolTip(); - $cleanedRules[] = $rule; + $cleanedCoupons[] = $rule; } - return $cleanedRules; + return $cleanedCoupons; } /** diff --git a/core/lib/Thelia/Controller/BaseController.php b/core/lib/Thelia/Controller/BaseController.php index bd1e68422..19e62a400 100755 --- a/core/lib/Thelia/Controller/BaseController.php +++ b/core/lib/Thelia/Controller/BaseController.php @@ -127,7 +127,7 @@ class BaseController extends ContainerAware /** * Returns the session from the current request * - * @return \Symfony\Component\HttpFoundation\Session\SessionInterface + * @return \Thelia\Core\HttpFoundation\Session\Session */ protected function getSession() { diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponDisableEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponConsumeEvent.php similarity index 54% rename from core/lib/Thelia/Core/Event/Coupon/CouponDisableEvent.php rename to core/lib/Thelia/Core/Event/Coupon/CouponConsumeEvent.php index db8e14243..df5cef7a9 100644 --- a/core/lib/Thelia/Core/Event/Coupon/CouponDisableEvent.php +++ b/core/lib/Thelia/Core/Event/Coupon/CouponConsumeEvent.php @@ -22,6 +22,8 @@ /**********************************************************************************/ namespace Thelia\Core\Event\Coupon; +use Thelia\Core\Event\ActionEvent; +use Thelia\Coupon\CouponRuleCollection; use Thelia\Model\Coupon; /** @@ -29,75 +31,112 @@ use Thelia\Model\Coupon; * Date: 8/29/13 * Time: 3:45 PM * - * Occurring when a Coupon is disabled + * Occurring when a Coupon is consumed * * @package Coupon * @author Guillaume MOREL * */ -class CouponDisableEvent extends ActionEvent +class CouponConsumeEvent extends ActionEvent { - /** @var int Coupon id */ - protected $couponId; + /** @var string Coupon code */ + protected $code = null; - /** @var Coupon Coupon being disabled */ - protected $disabledCoupon; + /** @var float Total discount given by this coupon */ + protected $discount = 0; + + /** @var bool If Coupon is valid or if Customer meets coupon conditions */ + protected $isValid = null; /** * Constructor * - * @param int $id Coupon Id + * @param string $code Coupon code + * @param float $discount Total discount given by this coupon + * @param bool $isValid If Coupon is valid or + * if Customer meets coupon conditions */ - public function __construct($id) + function __construct($code, $discount = null, $isValid = null) { - $this->id = $id; + $this->code = $code; + $this->discount = $discount; + $this->isValid = $isValid; } /** - * Get Coupon id + * Set Coupon code * - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * Set Coupon id - * - * @param int $id Coupon id + * @param string $code Coupon code * * @return $this */ - public function setId($id) + public function setCode($code) { - $this->id = $id; + $this->code = $code; return $this; } /** - * Get Coupon being disabled + * Get Coupon code * - * @return Coupon + * @return string */ - public function getDisabledCoupon() + public function getCode() { - return $this->disabledCoupon; + return $this->code; } /** - * Set Coupon to be disabled + * Set total discount given by this coupon * - * @param Coupon $disabledCoupon Coupon to disable + * @param float $discount Total discount given by this coupon * * @return $this */ - public function setDisabledCoupon(Coupon $disabledCoupon) + public function setDiscount($discount) { - $this->disabledCoupon = $disabledCoupon; + $this->discount = $discount; return $this; } + + /** + * Get total discount given by this coupon + * + * @return float + */ + public function getDiscount() + { + return $this->discount; + } + + /** + * Set if Coupon is valid or if Customer meets coupon conditions + * + * @param boolean $isValid if Coupon is valid or + * if Customer meets coupon conditions + * + * @return $this + */ + public function setIsValid($isValid) + { + $this->isValid = $isValid; + + return $this; + } + + /** + * Get if Coupon is valid or if Customer meets coupon conditions + * + * @return boolean + */ + public function getIsValid() + { + return $this->isValid; + } + + + + } diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponEnableEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponEnableEvent.php deleted file mode 100644 index ab06953e5..000000000 --- a/core/lib/Thelia/Core/Event/Coupon/CouponEnableEvent.php +++ /dev/null @@ -1,103 +0,0 @@ -. */ -/* */ -/**********************************************************************************/ - -namespace Thelia\Core\Event\Coupon; -use Thelia\Model\Coupon; - -/** - * Created by JetBrains PhpStorm. - * Date: 8/29/13 - * Time: 3:45 PM - * - * Occurring when a Coupon is enabled - * - * @package Coupon - * @author Guillaume MOREL - * - */ -class CouponEnableEvent extends ActionEvent -{ - /** @var int Coupon id */ - protected $couponId; - - /** @var Coupon Coupon being enabled */ - protected $enabledCoupon; - - /** - * Constructor - * - * @param int $id Coupon Id - */ - public function __construct($id) - { - $this->id = $id; - } - - /** - * Get Coupon id - * - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * Set Coupon id - * - * @param int $id Coupon id - * - * @return $this - */ - public function setId($id) - { - $this->id = $id; - - return $this; - } - - /** - * Get Coupon being enabled - * - * @return Coupon - */ - public function getEnabledCoupon() - { - return $this->enabledCoupon; - } - - /** - * Set Coupon to be enabled - * - * @param Coupon $enabledCoupon Coupon to enabled - * - * @return $this - */ - public function setEnabledCoupon(Coupon $enabledCoupon) - { - $this->enabledCoupon = $enabledCoupon; - - return $this; - } -} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index de8ffa648..d02c6d4d1 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -258,36 +258,6 @@ final class TheliaEvents */ const AFTER_UPDATE_COUPON = "action.after_update_coupon"; - /** - * Sent when disabling a Coupon - */ - const COUPON_DISABLE = "action.disable_coupon"; - - /** - * Sent just before a successful disable of a new Coupon in the database. - */ - const BEFORE_DISABLE_COUPON = "action.before_disable_coupon"; - - /** - * Sent just after a successful disable of a new Coupon in the database. - */ - const AFTER_DISABLE_COUPON = "action.after_disable_coupon"; - - /** - * Sent when enabling a Coupon - */ - const COUPON_ENABLE = "action.enable_coupon"; - - /** - * Sent just before a successful enable of a new Coupon in the database. - */ - const BEFORE_ENABLE_COUPON = "action.before_enable_coupon"; - - /** - * Sent just after a successful enable of a new Coupon in the database. - */ - const AFTER_ENABLE_COUPON = "action.after_enable_coupon"; - /** * Sent when attempting to use a Coupon */ diff --git a/core/lib/Thelia/Core/HttpFoundation/Request.php b/core/lib/Thelia/Core/HttpFoundation/Request.php index e86ce8b65..8e77ad865 100755 --- a/core/lib/Thelia/Core/HttpFoundation/Request.php +++ b/core/lib/Thelia/Core/HttpFoundation/Request.php @@ -55,4 +55,15 @@ class Request extends BaseRequest return $uri . $additionalQs; } + + /** + * Gets the Session. + * + * @return \Thelia\Core\HttpFoundation\Session\Session The session + * @api + */ + public function getSession() + { + return parent::getSession(); + } } diff --git a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php index f2eaadc4d..bce8e712a 100755 --- a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php +++ b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php @@ -220,4 +220,29 @@ class Session extends BaseSession { return $this->get("thelia.delivery_id"); } + + + /** + * Set consumed coupons by the Customer + * + * @param array $couponsCode An array of Coupon code + * + * @return $this + */ + public function setConsumedCoupons(array $couponsCode) + { + $this->set('thelia.consumed_coupons', $couponsCode); + + return $this; + } + + /** + * Get Customer consumed coupons + * + * @return array $couponsCode An array of Coupon code + */ + public function getConsumedCoupons() + { + return $this->get('thelia.consumed_coupons'); + } } diff --git a/core/lib/Thelia/Core/Template/Loop/Coupon.php b/core/lib/Thelia/Core/Template/Loop/Coupon.php index 2fb49e8b9..4e8ca3e71 100755 --- a/core/lib/Thelia/Core/Template/Loop/Coupon.php +++ b/core/lib/Thelia/Core/Template/Loop/Coupon.php @@ -24,6 +24,7 @@ namespace Thelia\Core\Template\Loop; use Propel\Runtime\ActiveQuery\Criteria; +use Propel\Runtime\Util\PropelModelPager; use Thelia\Constraint\ConstraintFactory; use Thelia\Constraint\Rule\CouponRuleInterface; use Thelia\Core\HttpFoundation\Request; @@ -34,9 +35,11 @@ use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Loop\Argument\ArgumentCollection; use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Coupon\Type\CouponInterface; use Thelia\Model\CouponQuery; use Thelia\Model\Coupon as MCoupon; use Thelia\Type; +use Thelia\Type\BooleanOrBothType; /** * Created by JetBrains PhpStorm. @@ -52,17 +55,22 @@ use Thelia\Type; class Coupon extends BaseI18nLoop { /** + * Define all args used in your loop + * * @return ArgumentCollection */ protected function getArgDefinitions() { return new ArgumentCollection( - Argument::createIntListTypeArgument('id') + Argument::createIntListTypeArgument('id'), + Argument::createBooleanOrBothTypeArgument('is_enabled', 1) ); } /** - * @param $pagination + * Execute Loop + * + * @param PropelModelPager $pagination * * @return \Thelia\Core\Template\Element\LoopResult */ @@ -74,11 +82,16 @@ class Coupon extends BaseI18nLoop $locale = $this->configureI18nProcessing($search, array('TITLE', 'DESCRIPTION', 'SHORT_DESCRIPTION')); $id = $this->getId(); + $isEnabled = $this->getIsEnabled(); if (null !== $id) { $search->filterById($id, Criteria::IN); } + if ($isEnabled != BooleanOrBothType::ANY) { + $search->filterByIsEnabled($isEnabled ? 1 : 0); + } + // Perform search $coupons = $this->search($search, $pagination); @@ -98,9 +111,30 @@ class Coupon extends BaseI18nLoop $coupon->getSerializedRules() ); + /** @var CouponInterface $couponManager */ + $couponManager = $this->container->get($coupon->getType()); + $couponManager->set( + $this->container->get('thelia.adapter'), + $coupon->getCode(), + $coupon->getTitle(), + $coupon->getShortDescription(), + $coupon->getDescription(), + $coupon->getAmount(), + $coupon->getIsCumulative(), + $coupon->getIsRemovingPostage(), + $coupon->getIsAvailableOnSpecialOffers(), + $coupon->getIsEnabled(), + $coupon->getMaxUsage(), + $coupon->getExpirationDate() + ); + + $now = time(); + $datediff = $coupon->getExpirationDate()->getTimestamp() - $now; + $daysLeftBeforeExpiration = floor($datediff/(60*60*24)); + $cleanedRules = array(); /** @var CouponRuleInterface $rule */ - foreach ($rules->getRules() as $key => $rule) { + foreach ($rules->getRules() as $rule) { $cleanedRules[] = $rule->getToolTip(); } $loopResultRow->set("ID", $coupon->getId()) @@ -114,9 +148,13 @@ class Coupon extends BaseI18nLoop ->set("USAGE_LEFT", $coupon->getMaxUsage()) ->set("IS_CUMULATIVE", $coupon->getIsCumulative()) ->set("IS_REMOVING_POSTAGE", $coupon->getIsRemovingPostage()) + ->set("IS_AVAILABLE_ON_SPECIAL_OFFERS", $coupon->getIsAvailableOnSpecialOffers()) ->set("IS_ENABLED", $coupon->getIsEnabled()) ->set("AMOUNT", $coupon->getAmount()) - ->set("APPLICATION_CONDITIONS", $cleanedRules); + ->set("APPLICATION_CONDITIONS", $cleanedRules) + ->set("TOOLTIP", $couponManager->getToolTip()) + ->set("DAY_LEFT_BEFORE_EXPIRATION", $daysLeftBeforeExpiration) + ->set("SERVICE_ID", $couponManager->getServiceId()); $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Coupon/CouponAdapterInterface.php b/core/lib/Thelia/Coupon/CouponAdapterInterface.php index 134d061be..b2c168186 100644 --- a/core/lib/Thelia/Coupon/CouponAdapterInterface.php +++ b/core/lib/Thelia/Coupon/CouponAdapterInterface.php @@ -155,4 +155,18 @@ interface CouponAdapterInterface */ public function getMainCurrency(); + /** + * Return request + * + * @return Request + */ + public function getRequest(); + + /** + * Return Constraint Validator + * + * @return ConstraintValidator + */ + public function getConstraintValidator(); + } \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/CouponBaseAdapter.php b/core/lib/Thelia/Coupon/CouponBaseAdapter.php index 3e77a56be..f9fae8651 100644 --- a/core/lib/Thelia/Coupon/CouponBaseAdapter.php +++ b/core/lib/Thelia/Coupon/CouponBaseAdapter.php @@ -27,9 +27,14 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\TranslatorInterface; +use Thelia\Constraint\ConstraintValidator; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Security\SecurityContext; use Thelia\Coupon\Type\CouponInterface; use Thelia\Model\Coupon; use Thelia\Model\CouponQuery; +use Thelia\Cart\CartTrait; +use Thelia\Model\Currency; /** * Created by JetBrains PhpStorm. @@ -43,6 +48,10 @@ use Thelia\Model\CouponQuery; */ class CouponBaseAdapter implements CouponAdapterInterface { + use CartTrait { + CartTrait::getCart as getCartFromTrait; + } + /** @var ContainerInterface Service Container */ protected $container = null; @@ -66,7 +75,7 @@ class CouponBaseAdapter implements CouponAdapterInterface */ public function getCart() { - // TODO: Implement getCart() method. + return $this->getCartFromTrait($this->getRequest()); } /** @@ -86,7 +95,7 @@ class CouponBaseAdapter implements CouponAdapterInterface */ public function getCustomer() { - // TODO: Implement getCustomer() method. + return $this->container->get('thelia.securityContext')->getCustomerUser(); } /** @@ -122,11 +131,11 @@ class CouponBaseAdapter implements CouponAdapterInterface /** * Return the Checkout currency EUR|USD * - * @return string + * @return Currency */ public function getCheckoutCurrency() { - // TODO: Implement getCheckoutCurrency() method. + $this->getRequest()->getSession()->getCurrency(); } @@ -147,9 +156,14 @@ class CouponBaseAdapter implements CouponAdapterInterface */ public function getCurrentCoupons() { + // @todo implement +// $consumedCoupons = $this->getRequest()->getSession()->getConsumedCoupons(); + // @todo convert coupon code to coupon Interface + + $couponFactory = $this->container->get('thelia.coupon.factory'); - // @todo Get from Session + // @todo get from cart $couponCodes = array('XMAS', 'SPRINGBREAK'); $coupons = array(); @@ -208,7 +222,7 @@ class CouponBaseAdapter implements CouponAdapterInterface */ public function getContainer() { - // TODO: Implement getContainer() method. + return $this->container; } /** @@ -232,4 +246,24 @@ class CouponBaseAdapter implements CouponAdapterInterface { // TODO: Implement getMainCurrency() method. } + + /** + * Return request + * + * @return Request + */ + public function getRequest() + { + return $this->container->get('request'); + } + + /** + * Return Constraint Validator + * + * @return ConstraintValidator + */ + public function getConstraintValidator() + { + return $this->container->get('thelia.constraint.validator'); + } } diff --git a/core/lib/Thelia/Coupon/CouponManager.php b/core/lib/Thelia/Coupon/CouponManager.php index 93cdd21fe..d8575c3e6 100644 --- a/core/lib/Thelia/Coupon/CouponManager.php +++ b/core/lib/Thelia/Coupon/CouponManager.php @@ -183,6 +183,7 @@ class CouponManager $discount = 0.00; /** @var CouponInterface $coupon */ foreach ($coupons as $coupon) { + // @todo modify Cart with discount for each cart item $discount += $coupon->getDiscount($this->adapter); } diff --git a/core/lib/Thelia/Coupon/Type/CouponAbstract.php b/core/lib/Thelia/Coupon/Type/CouponAbstract.php index 647635024..45e1427f1 100644 --- a/core/lib/Thelia/Coupon/Type/CouponAbstract.php +++ b/core/lib/Thelia/Coupon/Type/CouponAbstract.php @@ -26,6 +26,7 @@ namespace Thelia\Coupon\Type; use Symfony\Component\Intl\Exception\NotImplementedException; use Thelia\Constraint\ConstraintManager; use Thelia\Constraint\ConstraintValidator; +use Thelia\Core\Translation\Translator; use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponRuleCollection; use Thelia\Coupon\RuleOrganizerInterface; @@ -44,9 +45,6 @@ use Thelia\Exception\InvalidRuleException; */ abstract class CouponAbstract implements CouponInterface { - /** @var string Service Id */ - protected $serviceId = null; - /** @var CouponAdapterInterface Provide necessary value from Thelia */ protected $adapter = null; @@ -62,9 +60,19 @@ abstract class CouponAbstract implements CouponInterface /** @var ConstraintValidator Constraint validator */ protected $constraintValidator = null; + + + /** @var string Service Id */ + protected $serviceId = null; + + /** @var float Amount that will be removed from the Checkout (Coupon Effect) */ + protected $amount = 0; + /** @var string Coupon code (ex: XMAS) */ protected $code = null; + + /** @var string Coupon title (ex: Coupon for XMAS) */ protected $title = null; @@ -74,6 +82,8 @@ abstract class CouponAbstract implements CouponInterface /** @var string Coupon description */ protected $description = null; + + /** @var bool if Coupon is enabled */ protected $isEnabled = false; @@ -86,9 +96,6 @@ abstract class CouponAbstract implements CouponInterface /** @var bool if Coupon is removing postage */ protected $isRemovingPostage = false; - /** @var float Amount that will be removed from the Checkout (Coupon Effect) */ - protected $amount = 0; - /** @var int Max time a Coupon can be used (-1 = unlimited) */ protected $maxUsage = -1; @@ -105,6 +112,7 @@ abstract class CouponAbstract implements CouponInterface { $this->adapter = $adapter; $this->translator = $adapter->getTranslator(); + $this->constraintValidator = $adapter->getConstraintValidator(); } /** @@ -220,17 +228,6 @@ abstract class CouponAbstract implements CouponInterface return $this; } - /** - * Check if the current Coupon is matching its conditions (Rules) - * Thelia variables are given by the CouponAdapterInterface - * - * @return bool - */ - public function isMatching() - { - return $this->constraintValidator->test($this->rules); - } - /** * Return Coupon expiration date * @@ -302,4 +299,16 @@ abstract class CouponAbstract implements CouponInterface } + /** + * Check if the current Coupon is matching its conditions (Rules) + * Thelia variables are given by the CouponAdapterInterface + * + * @return bool + */ + public function isMatching() + { + return $this->constraintValidator->isMatching($this->rules); + } + + } diff --git a/core/lib/Thelia/Coupon/Type/CouponInterface.php b/core/lib/Thelia/Coupon/Type/CouponInterface.php index f0426298f..be76c1878 100644 --- a/core/lib/Thelia/Coupon/Type/CouponInterface.php +++ b/core/lib/Thelia/Coupon/Type/CouponInterface.php @@ -39,6 +39,27 @@ use Thelia\Coupon\CouponRuleCollection; */ interface CouponInterface { + /** + * Get I18n name + * + * @return string + */ + public function getName(); + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip(); + + /** + * Get Coupon Manager service Id + * + * @return string + */ + public function getServiceId(); + /** * Set Coupon * @@ -114,18 +135,7 @@ interface CouponInterface */ public function isRemovingPostage(); - /** - * Return effects generated by the coupon - * A positive value - * - * Effects could also affect something else than the final Checkout price - * CouponAdapter $adapter could be use to directly pass a Session value - * some would wish to modify - * Hence affecting a wide variety of Thelia elements - * - * @return float Amount removed from the Total Checkout - */ - public function getDiscount(); + /** * Return condition to validate the Coupon or not @@ -134,14 +144,6 @@ interface CouponInterface */ public function getRules(); - /** - * Check if the current Coupon is matching its conditions (Rules) - * Thelia variables are given by the CouponAdapterInterface - * - * @return bool - */ - public function isMatching(); - /** * Replace the existing Rules by those given in parameter * If one Rule is badly implemented, no Rule will be added @@ -191,25 +193,26 @@ interface CouponInterface */ public function isExpired(); - /** - * Get I18n name - * - * @return string - */ - public function getName(); /** - * Get I18n tooltip + * Return effects generated by the coupon + * A positive value * - * @return string + * Effects could also affect something else than the final Checkout price + * CouponAdapter $adapter could be use to directly pass a Session value + * some would wish to modify + * Hence affecting a wide variety of Thelia elements + * + * @return float Amount removed from the Total Checkout */ - public function getToolTip(); + public function getDiscount(); /** - * Get Coupon Manager service Id + * Check if the current Coupon is matching its conditions (Rules) + * Thelia variables are given by the CouponAdapterInterface * - * @return string + * @return bool */ - public function getServiceId(); + public function isMatching(); } diff --git a/core/lib/Thelia/Form/CouponCreationForm.php b/core/lib/Thelia/Form/CouponCreationForm.php index d63a4284d..1625ab685 100755 --- a/core/lib/Thelia/Form/CouponCreationForm.php +++ b/core/lib/Thelia/Form/CouponCreationForm.php @@ -23,7 +23,11 @@ namespace Thelia\Form; +use Symfony\Component\Validator\Constraints\Date; +use Symfony\Component\Validator\Constraints\DateTime; +use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\NotEqualTo; /** * Created by JetBrains PhpStorm. @@ -68,7 +72,6 @@ class CouponCreationForm extends BaseForm 'shortDescription', 'text', array( - 'invalid_message' => 'test', 'constraints' => array( new NotBlank() ) @@ -78,7 +81,6 @@ class CouponCreationForm extends BaseForm 'description', 'textarea', array( - 'invalid_message' => 'test', 'constraints' => array( new NotBlank() ) @@ -88,16 +90,23 @@ class CouponCreationForm extends BaseForm 'effect', 'text', array( - 'invalid_message' => 'test', 'constraints' => array( - new NotBlank() + new NotBlank(), + new NotEqualTo( + array( + 'value' => -1 + ) + ) ) ) ) ->add( 'amount', 'money', - array() + array( + 'constraints' => array( + new NotBlank() + )) ) ->add( 'isEnabled', @@ -109,7 +118,8 @@ class CouponCreationForm extends BaseForm 'text', array( 'constraints' => array( - new NotBlank() + new NotBlank(), + new Date() ) ) ) @@ -133,7 +143,12 @@ class CouponCreationForm extends BaseForm 'text', array( 'constraints' => array( - new NotBlank() + new NotBlank(), + new GreaterThanOrEqual( + array( + 'value' => -1 + ) + ) ) ) ) diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php index 7a7ce1e4a..032de412a 100755 --- a/core/lib/Thelia/Model/Coupon.php +++ b/core/lib/Thelia/Model/Coupon.php @@ -76,7 +76,6 @@ class Coupon extends BaseCoupon ->setType($effect) ->setAmount($amount) ->setIsRemovingPostage($isRemovingPostage) - ->setType($amount) ->setIsEnabled($isEnabled) ->setExpirationDate($expirationDate) ->setIsAvailableOnSpecialOffers($isAvailableOnSpecialOffers) diff --git a/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php b/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php index 01e9dde69..17b6b49e1 100644 --- a/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php +++ b/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php @@ -79,7 +79,7 @@ class ConstraintValidatorTest extends \PHPUnit_Framework_TestCase $rules = new CouponRuleCollection(); $rules->add($rule1); - $isValid = $ConstraintValidator->test($rules); + $isValid = $ConstraintValidator->isMatching($rules); $expected = true; $actual =$isValid; @@ -113,7 +113,7 @@ class ConstraintValidatorTest extends \PHPUnit_Framework_TestCase $rules = new CouponRuleCollection(); $rules->add($rule1); - $isValid = $ConstraintValidator->test($rules); + $isValid = $ConstraintValidator->isMatching($rules); $expected = false; $actual =$isValid; @@ -160,7 +160,7 @@ class ConstraintValidatorTest extends \PHPUnit_Framework_TestCase $rules->add($rule1); $rules->add($rule2); - $isValid = $ConstraintValidator->test($rules); + $isValid = $ConstraintValidator->isMatching($rules); $expected = true; $actual =$isValid; @@ -207,7 +207,7 @@ class ConstraintValidatorTest extends \PHPUnit_Framework_TestCase $rules->add($rule1); $rules->add($rule2); - $isValid = $ConstraintValidator->test($rules); + $isValid = $ConstraintValidator->isMatching($rules); $expected = false; $actual =$isValid; diff --git a/install/insert.sql b/install/insert.sql index 1cc7c55e6..03fbc690c 100755 --- a/install/insert.sql +++ b/install/insert.sql @@ -1,6 +1,6 @@ INSERT INTO `lang`(`id`,`title`,`code`,`locale`,`url`,`date_format`,`time_format`,`datetime_format`,`decimal_separator`,`thousands_separator`,`decimals`,`by_default`,`created_at`,`updated_at`)VALUES -(1, 'Français', 'fr', 'fr_FR', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '1', NOW(), NOW()), -(2, 'English', 'en', 'en_US', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', '.', ' ', '2', '0', NOW(), NOW()), +(1, 'Français', 'fr', 'fr_FR', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '0', NOW(), NOW()), +(2, 'English', 'en', 'en_US', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', '.', ' ', '2', '1', NOW(), NOW()), (3, 'castellano', 'es', 'es_ES', '', 'm-d-Y', 'h:i:s', 'm-d-Y h:i:s', ',', '.', '2', '0', NOW(), NOW()), (4, 'Italiano', 'it', 'it_IT', '', 'd/m/Y', 'H:i:s', 'd/m/y H:i:s', ',', ' ', '2', '0', NOW(), NOW()); diff --git a/templates/admin/default/admin-layout.tpl b/templates/admin/default/admin-layout.tpl index b15c624f3..3b97c069b 100644 --- a/templates/admin/default/admin-layout.tpl +++ b/templates/admin/default/admin-layout.tpl @@ -146,7 +146,7 @@ {loop name="menu-auth-coupon" type="auth" roles="ADMIN" permissions="admin.coupon.view"}
  • - {intl l="Coupons"} + {intl l="Coupons"}
  • {/loop} diff --git a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js index bf3a56df0..97a3d67ed 100755 --- a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js +++ b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js @@ -1,474 +1,474 @@ -/* ========================================================= - * bootstrap-datepicker.js - * http://www.eyecon.ro/bootstrap-datepicker - * ========================================================= - * Copyright 2012 Stefan Petre - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= */ - -!function( $ ) { - - // Picker object - - var Datepicker = function(element, options){ - this.element = $(element); - this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); - this.picker = $(DPGlobal.template) - .appendTo('body') - .on({ - click: $.proxy(this.click, this)//, - //mousedown: $.proxy(this.mousedown, this) - }); - this.isInput = this.element.is('input'); - this.component = this.element.is('.date') ? this.element.find('.add-on') : false; - - if (this.isInput) { - this.element.on({ - focus: $.proxy(this.show, this), - //blur: $.proxy(this.hide, this), - keyup: $.proxy(this.update, this) - }); - } else { - if (this.component){ - this.component.on('click', $.proxy(this.show, this)); - } else { - this.element.on('click', $.proxy(this.show, this)); - } - } - - this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; - if (typeof this.minViewMode === 'string') { - switch (this.minViewMode) { - case 'months': - this.minViewMode = 1; - break; - case 'years': - this.minViewMode = 2; - break; - default: - this.minViewMode = 0; - break; - } - } - this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; - if (typeof this.viewMode === 'string') { - switch (this.viewMode) { - case 'months': - this.viewMode = 1; - break; - case 'years': - this.viewMode = 2; - break; - default: - this.viewMode = 0; - break; - } - } - this.startViewMode = this.viewMode; - this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; - this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; - this.onRender = options.onRender; - this.fillDow(); - this.fillMonths(); - this.update(); - this.showMode(); - }; - - Datepicker.prototype = { - constructor: Datepicker, - - show: function(e) { - this.picker.show(); - this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); - this.place(); - $(window).on('resize', $.proxy(this.place, this)); - if (e ) { - e.stopPropagation(); - e.preventDefault(); - } - if (!this.isInput) { - } - var that = this; - $(document).on('mousedown', function(ev){ - if ($(ev.target).closest('.datepicker').length == 0) { - that.hide(); - } - }); - this.element.trigger({ - type: 'show', - date: this.date - }); - }, - - hide: function(){ - this.picker.hide(); - $(window).off('resize', this.place); - this.viewMode = this.startViewMode; - this.showMode(); - if (!this.isInput) { - $(document).off('mousedown', this.hide); - } - //this.set(); - this.element.trigger({ - type: 'hide', - date: this.date - }); - }, - - set: function() { - var formated = DPGlobal.formatDate(this.date, this.format); - if (!this.isInput) { - if (this.component){ - this.element.find('input').prop('value', formated); - } - this.element.data('date', formated); - } else { - this.element.prop('value', formated); - } - }, - - setValue: function(newDate) { - if (typeof newDate === 'string') { - this.date = DPGlobal.parseDate(newDate, this.format); - } else { - this.date = new Date(newDate); - } - this.set(); - this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); - this.fill(); - }, - - place: function(){ - var offset = this.component ? this.component.offset() : this.element.offset(); - this.picker.css({ - top: offset.top + this.height, - left: offset.left - }); - }, - - update: function(newDate){ - this.date = DPGlobal.parseDate( - typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), - this.format - ); - this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); - this.fill(); - }, - - fillDow: function(){ - var dowCnt = this.weekStart; - var html = ''; - while (dowCnt < this.weekStart + 7) { - html += ''+DPGlobal.dates.daysMin[(dowCnt++)%7]+''; - } - html += ''; - this.picker.find('.datepicker-days thead').append(html); - }, - - fillMonths: function(){ - var html = ''; - var i = 0 - while (i < 12) { - html += ''+DPGlobal.dates.monthsShort[i++]+''; - } - this.picker.find('.datepicker-months td').append(html); - }, - - fill: function() { - var d = new Date(this.viewDate), - year = d.getFullYear(), - month = d.getMonth(), - currentDate = this.date.valueOf(); - this.picker.find('.datepicker-days th:eq(1)') - .text(DPGlobal.dates.months[month]+' '+year); - var prevMonth = new Date(year, month-1, 28,0,0,0,0), - day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); - prevMonth.setDate(day); - prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); - var nextMonth = new Date(prevMonth); - nextMonth.setDate(nextMonth.getDate() + 42); - nextMonth = nextMonth.valueOf(); - var html = []; - var clsName, - prevY, - prevM; - while(prevMonth.valueOf() < nextMonth) { - if (prevMonth.getDay() === this.weekStart) { - html.push(''); - } - clsName = this.onRender(prevMonth); - prevY = prevMonth.getFullYear(); - prevM = prevMonth.getMonth(); - if ((prevM < month && prevY === year) || prevY < year) { - clsName += ' old'; - } else if ((prevM > month && prevY === year) || prevY > year) { - clsName += ' new'; - } - if (prevMonth.valueOf() === currentDate) { - clsName += ' active'; - } - html.push(''+prevMonth.getDate() + ''); - if (prevMonth.getDay() === this.weekEnd) { - html.push(''); - } - prevMonth.setDate(prevMonth.getDate()+1); - } - this.picker.find('.datepicker-days tbody').empty().append(html.join('')); - var currentYear = this.date.getFullYear(); - - var months = this.picker.find('.datepicker-months') - .find('th:eq(1)') - .text(year) - .end() - .find('span').removeClass('active'); - if (currentYear === year) { - months.eq(this.date.getMonth()).addClass('active'); - } - - html = ''; - year = parseInt(year/10, 10) * 10; - var yearCont = this.picker.find('.datepicker-years') - .find('th:eq(1)') - .text(year + '-' + (year + 9)) - .end() - .find('td'); - year -= 1; - for (var i = -1; i < 11; i++) { - html += ''+year+''; - year += 1; - } - yearCont.html(html); - }, - - click: function(e) { - e.stopPropagation(); - e.preventDefault(); - var target = $(e.target).closest('span, td, th'); - if (target.length === 1) { - switch(target[0].nodeName.toLowerCase()) { - case 'th': - switch(target[0].className) { - case 'switch': - this.showMode(1); - break; - case 'prev': - case 'next': - this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( - this.viewDate, - this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + - DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) - ); - this.fill(); - this.set(); - break; - } - break; - case 'span': - if (target.is('.month')) { - var month = target.parent().find('span').index(target); - this.viewDate.setMonth(month); - } else { - var year = parseInt(target.text(), 10)||0; - this.viewDate.setFullYear(year); - } - if (this.viewMode !== 0) { - this.date = new Date(this.viewDate); - this.element.trigger({ - type: 'changeDate', - date: this.date, - viewMode: DPGlobal.modes[this.viewMode].clsName - }); - } - this.showMode(-1); - this.fill(); - this.set(); - break; - case 'td': - if (target.is('.day') && !target.is('.disabled')){ - var day = parseInt(target.text(), 10)||1; - var month = this.viewDate.getMonth(); - if (target.is('.old')) { - month -= 1; - } else if (target.is('.new')) { - month += 1; - } - var year = this.viewDate.getFullYear(); - this.date = new Date(year, month, day,0,0,0,0); - this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); - this.fill(); - this.set(); - this.element.trigger({ - type: 'changeDate', - date: this.date, - viewMode: DPGlobal.modes[this.viewMode].clsName - }); - } - break; - } - } - }, - - mousedown: function(e){ - e.stopPropagation(); - e.preventDefault(); - }, - - showMode: function(dir) { - if (dir) { - this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); - } - this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); - } - }; - - $.fn.datepicker = function ( option, val ) { - return this.each(function () { - var $this = $(this), - data = $this.data('datepicker'), - options = typeof option === 'object' && option; - if (!data) { - $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); - } - if (typeof option === 'string') data[option](val); - }); - }; - - $.fn.datepicker.defaults = { - onRender: function(date) { - return ''; - } - }; - $.fn.datepicker.Constructor = Datepicker; - - var DPGlobal = { - modes: [ - { - clsName: 'days', - navFnc: 'Month', - navStep: 1 - }, - { - clsName: 'months', - navFnc: 'FullYear', - navStep: 1 - }, - { - clsName: 'years', - navFnc: 'FullYear', - navStep: 10 - }], - dates:{ - days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], - daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], - daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], - months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] - }, - isLeapYear: function (year) { - return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) - }, - getDaysInMonth: function (year, month) { - return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] - }, - parseFormat: function(format){ - var separator = format.match(/[.\/\-\s].*?/), - parts = format.split(/\W+/); - if (!separator || !parts || parts.length === 0){ - throw new Error("Invalid date format."); - } - return {separator: separator, parts: parts}; - }, - parseDate: function(date, format) { - var parts = date.split(format.separator), - date = new Date(), - val; - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - if (parts.length === format.parts.length) { - var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); - for (var i=0, cnt = format.parts.length; i < cnt; i++) { - val = parseInt(parts[i], 10)||1; - switch(format.parts[i]) { - case 'dd': - case 'd': - day = val; - date.setDate(val); - break; - case 'mm': - case 'm': - month = val - 1; - date.setMonth(val - 1); - break; - case 'yy': - year = 2000 + val; - date.setFullYear(2000 + val); - break; - case 'yyyy': - year = val; - date.setFullYear(val); - break; - } - } - date = new Date(year, month, day, 0 ,0 ,0); - } - return date; - }, - formatDate: function(date, format){ - var val = { - d: date.getDate(), - m: date.getMonth() + 1, - yy: date.getFullYear().toString().substring(2), - yyyy: date.getFullYear() - }; - val.dd = (val.d < 10 ? '0' : '') + val.d; - val.mm = (val.m < 10 ? '0' : '') + val.m; - var date = []; - for (var i=0, cnt = format.parts.length; i < cnt; i++) { - date.push(val[format.parts[i]]); - } - return date.join(format.separator); - }, - headTemplate: ''+ - ''+ - '‹'+ - ''+ - '›'+ - ''+ - '', - contTemplate: '' - }; - DPGlobal.template = ''; - -}( window.jQuery ); \ No newline at end of file +///* ========================================================= +// * bootstrap-datepicker.js +// * http://www.eyecon.ro/bootstrap-datepicker +// * ========================================================= +// * Copyright 2012 Stefan Petre +// * +// * Licensed under the Apache License, Version 2.0 (the "License"); +// * you may not use this file except in compliance with the License. +// * You may obtain a copy of the License at +// * +// * http://www.apache.org/licenses/LICENSE-2.0 +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the License is distributed on an "AS IS" BASIS, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the License for the specific language governing permissions and +// * limitations under the License. +// * ========================================================= */ +// +//!function( $ ) { +// +// // Picker object +// +// var Datepicker = function(element, options){ +// this.element = $(element); +// this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); +// this.picker = $(DPGlobal.template) +// .appendTo('body') +// .on({ +// click: $.proxy(this.click, this)//, +// //mousedown: $.proxy(this.mousedown, this) +// }); +// this.isInput = this.element.is('input'); +// this.component = this.element.is('.date') ? this.element.find('.add-on') : false; +// +// if (this.isInput) { +// this.element.on({ +// focus: $.proxy(this.show, this), +// //blur: $.proxy(this.hide, this), +// keyup: $.proxy(this.update, this) +// }); +// } else { +// if (this.component){ +// this.component.on('click', $.proxy(this.show, this)); +// } else { +// this.element.on('click', $.proxy(this.show, this)); +// } +// } +// +// this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; +// if (typeof this.minViewMode === 'string') { +// switch (this.minViewMode) { +// case 'months': +// this.minViewMode = 1; +// break; +// case 'years': +// this.minViewMode = 2; +// break; +// default: +// this.minViewMode = 0; +// break; +// } +// } +// this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; +// if (typeof this.viewMode === 'string') { +// switch (this.viewMode) { +// case 'months': +// this.viewMode = 1; +// break; +// case 'years': +// this.viewMode = 2; +// break; +// default: +// this.viewMode = 0; +// break; +// } +// } +// this.startViewMode = this.viewMode; +// this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; +// this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; +// this.onRender = options.onRender; +// this.fillDow(); +// this.fillMonths(); +// this.update(); +// this.showMode(); +// }; +// +// Datepicker.prototype = { +// constructor: Datepicker, +// +// show: function(e) { +// this.picker.show(); +// this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); +// this.place(); +// $(window).on('resize', $.proxy(this.place, this)); +// if (e ) { +// e.stopPropagation(); +// e.preventDefault(); +// } +// if (!this.isInput) { +// } +// var that = this; +// $(document).on('mousedown', function(ev){ +// if ($(ev.target).closest('.datepicker').length == 0) { +// that.hide(); +// } +// }); +// this.element.trigger({ +// type: 'show', +// date: this.date +// }); +// }, +// +// hide: function(){ +// this.picker.hide(); +// $(window).off('resize', this.place); +// this.viewMode = this.startViewMode; +// this.showMode(); +// if (!this.isInput) { +// $(document).off('mousedown', this.hide); +// } +// //this.set(); +// this.element.trigger({ +// type: 'hide', +// date: this.date +// }); +// }, +// +// set: function() { +// var formated = DPGlobal.formatDate(this.date, this.format); +// if (!this.isInput) { +// if (this.component){ +// this.element.find('input').prop('value', formated); +// } +// this.element.data('date', formated); +// } else { +// this.element.prop('value', formated); +// } +// }, +// +// setValue: function(newDate) { +// if (typeof newDate === 'string') { +// this.date = DPGlobal.parseDate(newDate, this.format); +// } else { +// this.date = new Date(newDate); +// } +// this.set(); +// this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); +// this.fill(); +// }, +// +// place: function(){ +// var offset = this.component ? this.component.offset() : this.element.offset(); +// this.picker.css({ +// top: offset.top + this.height, +// left: offset.left +// }); +// }, +// +// update: function(newDate){ +// this.date = DPGlobal.parseDate( +// typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), +// this.format +// ); +// this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); +// this.fill(); +// }, +// +// fillDow: function(){ +// var dowCnt = this.weekStart; +// var html = ''; +// while (dowCnt < this.weekStart + 7) { +// html += ''+DPGlobal.dates.daysMin[(dowCnt++)%7]+''; +// } +// html += ''; +// this.picker.find('.datepicker-days thead').append(html); +// }, +// +// fillMonths: function(){ +// var html = ''; +// var i = 0 +// while (i < 12) { +// html += ''+DPGlobal.dates.monthsShort[i++]+''; +// } +// this.picker.find('.datepicker-months td').append(html); +// }, +// +// fill: function() { +// var d = new Date(this.viewDate), +// year = d.getFullYear(), +// month = d.getMonth(), +// currentDate = this.date.valueOf(); +// this.picker.find('.datepicker-days th:eq(1)') +// .text(DPGlobal.dates.months[month]+' '+year); +// var prevMonth = new Date(year, month-1, 28,0,0,0,0), +// day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); +// prevMonth.setDate(day); +// prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); +// var nextMonth = new Date(prevMonth); +// nextMonth.setDate(nextMonth.getDate() + 42); +// nextMonth = nextMonth.valueOf(); +// var html = []; +// var clsName, +// prevY, +// prevM; +// while(prevMonth.valueOf() < nextMonth) { +// if (prevMonth.getDay() === this.weekStart) { +// html.push(''); +// } +// clsName = this.onRender(prevMonth); +// prevY = prevMonth.getFullYear(); +// prevM = prevMonth.getMonth(); +// if ((prevM < month && prevY === year) || prevY < year) { +// clsName += ' old'; +// } else if ((prevM > month && prevY === year) || prevY > year) { +// clsName += ' new'; +// } +// if (prevMonth.valueOf() === currentDate) { +// clsName += ' active'; +// } +// html.push(''+prevMonth.getDate() + ''); +// if (prevMonth.getDay() === this.weekEnd) { +// html.push(''); +// } +// prevMonth.setDate(prevMonth.getDate()+1); +// } +// this.picker.find('.datepicker-days tbody').empty().append(html.join('')); +// var currentYear = this.date.getFullYear(); +// +// var months = this.picker.find('.datepicker-months') +// .find('th:eq(1)') +// .text(year) +// .end() +// .find('span').removeClass('active'); +// if (currentYear === year) { +// months.eq(this.date.getMonth()).addClass('active'); +// } +// +// html = ''; +// year = parseInt(year/10, 10) * 10; +// var yearCont = this.picker.find('.datepicker-years') +// .find('th:eq(1)') +// .text(year + '-' + (year + 9)) +// .end() +// .find('td'); +// year -= 1; +// for (var i = -1; i < 11; i++) { +// html += ''+year+''; +// year += 1; +// } +// yearCont.html(html); +// }, +// +// click: function(e) { +// e.stopPropagation(); +// e.preventDefault(); +// var target = $(e.target).closest('span, td, th'); +// if (target.length === 1) { +// switch(target[0].nodeName.toLowerCase()) { +// case 'th': +// switch(target[0].className) { +// case 'switch': +// this.showMode(1); +// break; +// case 'prev': +// case 'next': +// this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( +// this.viewDate, +// this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + +// DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) +// ); +// this.fill(); +// this.set(); +// break; +// } +// break; +// case 'span': +// if (target.is('.month')) { +// var month = target.parent().find('span').index(target); +// this.viewDate.setMonth(month); +// } else { +// var year = parseInt(target.text(), 10)||0; +// this.viewDate.setFullYear(year); +// } +// if (this.viewMode !== 0) { +// this.date = new Date(this.viewDate); +// this.element.trigger({ +// type: 'changeDate', +// date: this.date, +// viewMode: DPGlobal.modes[this.viewMode].clsName +// }); +// } +// this.showMode(-1); +// this.fill(); +// this.set(); +// break; +// case 'td': +// if (target.is('.day') && !target.is('.disabled')){ +// var day = parseInt(target.text(), 10)||1; +// var month = this.viewDate.getMonth(); +// if (target.is('.old')) { +// month -= 1; +// } else if (target.is('.new')) { +// month += 1; +// } +// var year = this.viewDate.getFullYear(); +// this.date = new Date(year, month, day,0,0,0,0); +// this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); +// this.fill(); +// this.set(); +// this.element.trigger({ +// type: 'changeDate', +// date: this.date, +// viewMode: DPGlobal.modes[this.viewMode].clsName +// }); +// } +// break; +// } +// } +// }, +// +// mousedown: function(e){ +// e.stopPropagation(); +// e.preventDefault(); +// }, +// +// showMode: function(dir) { +// if (dir) { +// this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); +// } +// this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); +// } +// }; +// +// $.fn.datepicker = function ( option, val ) { +// return this.each(function () { +// var $this = $(this), +// data = $this.data('datepicker'), +// options = typeof option === 'object' && option; +// if (!data) { +// $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); +// } +// if (typeof option === 'string') data[option](val); +// }); +// }; +// +// $.fn.datepicker.defaults = { +// onRender: function(date) { +// return ''; +// } +// }; +// $.fn.datepicker.Constructor = Datepicker; +// +// var DPGlobal = { +// modes: [ +// { +// clsName: 'days', +// navFnc: 'Month', +// navStep: 1 +// }, +// { +// clsName: 'months', +// navFnc: 'FullYear', +// navStep: 1 +// }, +// { +// clsName: 'years', +// navFnc: 'FullYear', +// navStep: 10 +// }], +// dates:{ +// days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], +// daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], +// daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], +// months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], +// monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] +// }, +// isLeapYear: function (year) { +// return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) +// }, +// getDaysInMonth: function (year, month) { +// return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] +// }, +// parseFormat: function(format){ +// var separator = format.match(/[.\/\-\s].*?/), +// parts = format.split(/\W+/); +// if (!separator || !parts || parts.length === 0){ +// throw new Error("Invalid date format."); +// } +// return {separator: separator, parts: parts}; +// }, +// parseDate: function(date, format) { +// var parts = date.split(format.separator), +// date = new Date(), +// val; +// date.setHours(0); +// date.setMinutes(0); +// date.setSeconds(0); +// date.setMilliseconds(0); +// if (parts.length === format.parts.length) { +// var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); +// for (var i=0, cnt = format.parts.length; i < cnt; i++) { +// val = parseInt(parts[i], 10)||1; +// switch(format.parts[i]) { +// case 'dd': +// case 'd': +// day = val; +// date.setDate(val); +// break; +// case 'mm': +// case 'm': +// month = val - 1; +// date.setMonth(val - 1); +// break; +// case 'yy': +// year = 2000 + val; +// date.setFullYear(2000 + val); +// break; +// case 'yyyy': +// year = val; +// date.setFullYear(val); +// break; +// } +// } +// date = new Date(year, month, day, 0 ,0 ,0); +// } +// return date; +// }, +// formatDate: function(date, format){ +// var val = { +// d: date.getDate(), +// m: date.getMonth() + 1, +// yy: date.getFullYear().toString().substring(2), +// yyyy: date.getFullYear() +// }; +// val.dd = (val.d < 10 ? '0' : '') + val.d; +// val.mm = (val.m < 10 ? '0' : '') + val.m; +// var date = []; +// for (var i=0, cnt = format.parts.length; i < cnt; i++) { +// date.push(val[format.parts[i]]); +// } +// return date.join(format.separator); +// }, +// headTemplate: ''+ +// ''+ +// '‹'+ +// ''+ +// '›'+ +// ''+ +// '', +// contTemplate: '' +// }; +// DPGlobal.template = ''; +// +//}( window.jQuery ); \ No newline at end of file diff --git a/templates/admin/default/assets/js/coupon.js b/templates/admin/default/assets/js/coupon.js index 5c52aa097..41e0c1430 100644 --- a/templates/admin/default/assets/js/coupon.js +++ b/templates/admin/default/assets/js/coupon.js @@ -22,17 +22,15 @@ $(function($){ }; // Add 1 Rule / or update the temporary Rules array then Save Rules via AJAX - couponManager.addRuleAjax = function(id) { - console.log('addRuleAjax '+ id); + couponManager.createOrUpdateRuleAjax = function() { + var id = couponManager.ruleToUpdateId; // If create if(!id) { - console.log('pushing'); couponManager.rulesToSave.push(couponManager.ruleToSave); } else { // else update - console.log('editing ' + id); couponManager.rulesToSave[id] = couponManager.ruleToSave; // reset edit mode to off - couponManager.ruleIdToUpdate = false; + couponManager.ruleToUpdateId = false; } // Save @@ -40,57 +38,54 @@ $(function($){ }; // Set rule inputs to allow editing - couponManager.updateRuleAjax = function(id) { - couponManager.ruleToUpdate = couponManager.rulesToSave[id]; - console.log('Set id to edit to ' + id); - couponManager.ruleIdToUpdate = id; - - // Deleting this rule, we will reset it - delete couponManager.rulesToSave[id]; + couponManager.updateRuleSelectAjax = function(id) { + couponManager.ruleToUpdateId = id; + couponManager.ruleToSave = couponManager.rulesToSave[id]; // Set the rule selector $("#category-rule option").filter(function() { - return $(this).val() == couponManager.ruleToUpdate.serviceId; + return $(this).val() == couponManager.ruleToSave.serviceId; }).prop('selected', true); // Force rule input refresh - couponManager.loadRuleInputs(couponManager.ruleToUpdate.serviceId, function() { + couponManager.loadRuleInputs(couponManager.ruleToSave.serviceId, function() { couponManager.fillInRuleInputs(); }); }; // Fill in rule inputs couponManager.fillInRuleInputs = function() { - console.log('fillInRuleInputs with'); - console.log(couponManager.ruleToUpdate); var operatorId = null; var valueId = null; var idName = null; - for (idName in couponManager.ruleToUpdate.operators) { + var id = couponManager.ruleToUpdateId; + if(id) { + couponManager.ruleToSave = couponManager.rulesToSave[id]; + } + + for (idName in couponManager.ruleToSave.operators) { // Setting idName operator select operatorId = idName + '-operator'; - $('#' + operatorId).val(couponManager.ruleToUpdate.operators[idName]); + $('#' + operatorId).val(couponManager.ruleToSave.operators[idName]); - valueId = idName + '-value'; // Setting idName value input - $('#' + valueId).val(couponManager.ruleToUpdate.values[idName]); - } - couponManager.ruleToSave = couponManager.ruleToUpdate; - - var id = couponManager.ruleIdToUpdate; - console.log('id to edit = ' + id); - if(id) { - console.log('setint rulesToSave[' + id + ']'); - console.log(couponManager.ruleToSave); - couponManager.rulesToSave[id] = couponManager.ruleToSave; + valueId = idName + '-value'; + $('#' + valueId).val(couponManager.ruleToSave.values[idName]); } }; // Save rules on click couponManager.onClickSaveRule = function() { $('#constraint-save-btn').on('click', function () { - couponManager.addRuleAjax(couponManager.ruleIdToUpdate); + if($('#category-rule').val() == 'thelia.constraint.rule.available_for_everyone') { + // @todo translate + modal + var r= confirm("Do you really want to set this coupon available to everyone ?"); + if (r == true) { + couponManager.createOrUpdateRuleAjax(); + } + } + }); }; couponManager.onClickSaveRule(); @@ -110,7 +105,7 @@ $(function($){ $('.constraint-update-btn').on('click', function (e) { e.preventDefault(); var $this = $(this); - couponManager.updateRuleAjax($this.attr('data-int')); + couponManager.updateRuleSelectAjax($this.attr('data-int')); // Hide row being updated $this.parent().parent().remove(); @@ -120,6 +115,8 @@ $(function($){ // Reload effect inputs when changing effect couponManager.onEffectChange = function() { + var optionSelected = $("option:selected", this); + $('#effectToolTip').html(optionSelected.attr("data-description")); $('#effect').on('change', function () { var optionSelected = $("option:selected", this); $('#effectToolTip').html(optionSelected.attr("data-description")); @@ -130,7 +127,7 @@ $(function($){ // Reload rule inputs when changing effect couponManager.onRuleChange = function() { $('#category-rule').on('change', function () { - couponManager.loadRuleInputs($(this).val(), function(ruleToSave) {}); + couponManager.loadRuleInputs($(this).val(), function() {}); }); }; couponManager.onRuleChange(); @@ -139,10 +136,37 @@ $(function($){ // var onInputsChange = function() // In AJAX response + // Set max usage to unlimited or not + couponManager.onUsageUnlimitedChange = function() { + if (!$('#max-usage').parent().hasClass('has-error')) { + $('#max-usage').hide().attr('value', '-1'); + $('#max-usage-label').hide(); + } + $('#is-unlimited').change(function(){ + var $this = $(this); + if ($this.is(':checked')) { + $('#max-usage').hide().attr('value', '-1'); + $('#max-usage-label').hide(); + } else { + $('#max-usage').show().val('').attr('value', ''); + $('#max-usage-label').show(); + } + }); + }; + couponManager.onUsageUnlimitedChange(); + }); // Rule to save var couponManager = {}; +// Rule to be saved couponManager.ruleToSave = {}; -couponManager.ruleIdToUpdate = false; \ No newline at end of file +couponManager.ruleToSave.serviceId = false; +couponManager.ruleToSave.operators = {}; +couponManager.ruleToSave.values = {}; +// Rules payload to save +couponManager.rulesToSave = []; +// Rule being updated id +couponManager.ruleToUpdateId = false; + diff --git a/templates/admin/default/assets/js/main.js b/templates/admin/default/assets/js/main.js index d472a22a9..094dfe623 100644 --- a/templates/admin/default/assets/js/main.js +++ b/templates/admin/default/assets/js/main.js @@ -40,34 +40,7 @@ }); }*/ - // -- Effect description - if($('[name=effect]').length){ - var $effectSelect = $('[name=effect]'), - $helpBlock = $effectSelect.next('.help-block'); - $effectSelect.change(function(){ - var description = $(this).find(":selected").data('description'); - $helpBlock.text(description); - }); - } - - // -- Max usage -- - if($('#is-unlimited').length){ - - if($('#is-unlimited').is(':checked')){ - $('#max-usage').hide().attr('value', '-1'); - } - - $('#is-unlimited').change(function(){ - if($('#is-unlimited').is(':checked')){ - $('#max-usage').hide().attr('value', '-1'); - } - else{ - $('#max-usage').show().val('').attr('value', ''); - } - }); - - } // -- Bootstrap tooltip -- if($('[rel="tooltip"]').length){ diff --git a/templates/admin/default/coupon-create.html b/templates/admin/default/coupon-create.html index e8fcb73f5..f8a0411e1 100755 --- a/templates/admin/default/coupon-create.html +++ b/templates/admin/default/coupon-create.html @@ -7,18 +7,19 @@ {form name="thelia.admin.coupon.creation"} {include file='coupon/form.html' formAction={url path={$formAction}} noRules=true} {/form} - {include file='includes/confirmation-modal.html'} @@ -33,9 +34,20 @@ {/javascripts} + {javascripts file='assets/js/json2.js'} + + {/javascripts} + + {javascripts file='assets/js/coupon.js'} + + {/javascripts} + + {**} + {**} + {/block} diff --git a/templates/admin/default/coupon-list.html b/templates/admin/default/coupon-list.html index e4a1d5e36..2eafde586 100755 --- a/templates/admin/default/coupon-list.html +++ b/templates/admin/default/coupon-list.html @@ -7,70 +7,50 @@
    - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + {loop type="coupon" name="list_coupon" is_enabled="1" backend_context="true"} + + + + + + + + {/loop}
    - List of enabled coupons + {intl l='Enabled coupons'}
    CodeTitleExpiration dateUsage leftActions{block name="coupon-label-code"}{intl l='Code'}{/block}{block name="coupon-label-title"}{intl l='Title'}{/block}{block name="coupon-label-expiration-date"}{intl l='Expiration date'}{/block}{block name="coupon-label-usage-left"}{intl l='Usage left'}{/block}{block name="coupon-label-action"}{/block}
    XMAS13Coupon for XMAS -30 €18/10/201349 - Edit - Disable -
    XMAS13Coupon for XMAS -30 €05/09/201320 - Edit - Disable -
    XMAS13Coupon for XMAS -30 €03/12/20139 - Edit - Disable -
    XMAS13Coupon for XMAS -30 €25/01/20134 - Edit - Disable -
    {block name="coupon-code"}{$CODE}{/block}{block name="coupon-title"}{$TITLE}{/block}{block name="coupon-expiration-date"}{$EXPIRATION_DATE}{/block}{block name="coupon-usage-left"}{$USAGE_LEFT}{/block} + {block name="coupon-action"} + + {intl l='Edit'} + + {/block} +
    @@ -80,58 +60,33 @@
    - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + {loop type="coupon" name="list_coupon" is_enabled="0" backend_context="true"} + + + + + + + + {/loop}
    - List of disabled coupons + {intl l='Disabled coupons'}
    CodeTitleExpiration dateUsage leftActions{block name="coupon-label-code"}{intl l='Code'}{/block}{block name="coupon-label-title"}{intl l='Title'}{/block}{block name="coupon-label-expiration-date"}{intl l='Expiration date'}{/block}{block name="coupon-label-usage-left"}{intl l='Usage left'}{/block}{block name="coupon-label-action"}{/block}
    XMAS13Coupon for XMAS -30 €18/10/201349 - Edit - Enabled -
    XMAS13Coupon for XMAS -20 €05/09/201349 - Edit - Enabled -
    XMAS13Coupon for XMAS -50 €03/12/201349 - Edit - Enabled -
    XMAS13Coupon for XMAS -5 €25/01/201349 - Edit - Enabled -
    {block name="coupon-code"}{$CODE}{/block}{block name="coupon-title"}{$TITLE}{/block}{block name="coupon-expiration-date"}{$EXPIRATION_DATE}{/block}{block name="coupon-usage-left"}{$USAGE_LEFT}{/block} + {block name="coupon-action"} + + {intl l='Edit'} + + {/block} +
    @@ -139,9 +94,6 @@
    -{include file='includes/confirmation-modal.html' id="disable" message="{intl l='Do you really want to disable this element ?'}"} -{include file='includes/confirmation-modal.html' id="enable" message="{intl l='Do you really want to enable this element ?'}"} - {/block} diff --git a/templates/admin/default/coupon-read.html b/templates/admin/default/coupon-read.html index d0a86ac72..4ae5e5c68 100755 --- a/templates/admin/default/coupon-read.html +++ b/templates/admin/default/coupon-read.html @@ -4,112 +4,146 @@ {block name="main-content"}
    - + {loop type="coupon" name="read_coupon" id={$couponId} backend_context="true"} - {loop type="coupon" name="read_coupon" id={$couponId} backend_context="true"} - + -
    -
    +
    +
    -
    - - {if !$IS_ENABLED}{intl l='This coupon is disabled, you can enable to the bottom of this form.'}{/if} -
    + {if !$IS_ENABLED} +
    + + {intl l='This coupon is disabled, you can enable to the bottom of this form.'} +
    + {/if} - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + +
    {intl l='Title'}{$TITLE}
    {intl l='Expiration date'}{$EXPIRATION_DATE}
    {intl l='Usage left'} - {if $USAGE_LEFT} - - {$USAGE_LEFT} - - {else} - - 0 - - {/if} -
    {$SHORT_DESCRIPTION}
    {$DESCRIPTION}
    - {if $IS_CUMULATIVE} - - {intl l="May be cumulative"} - - {else} - - {intl l="Can't be cumulative"} - - {/if} -
    - {if $IS_REMOVING_POSTAGE} - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - -
    {intl l='Title'}{$TITLE}
    + {if $IS_ENABLED} + + {intl l="Is enabled"} + + {else} + + {intl l="Is disabled"} + + {/if} +
    + {$TOOLTIP} +
    {intl l='Amount'}{$AMOUNT}
    {intl l='Expiration date'}{$EXPIRATION_DATE} ({$DAY_LEFT_BEFORE_EXPIRATION} {intl l="days left"})
    {intl l='Usage left'} + {if $USAGE_LEFT} + + {$USAGE_LEFT} + + {else} + + 0 + + {/if} +
    + {if $IS_CUMULATIVE} + + {intl l="May be cumulative"} + + {else} + + {intl l="Can't be cumulative"} + + {/if} +
    + {if $IS_REMOVING_POSTAGE} + {intl l="Will remove postage"} - {else} - + {else} + {intl l="Won't remove postage"} - {/if} -
    {intl l='Amount'}{$AMOUNT}
    {intl l='Application field'} -
      - {foreach from=$APPLICATION_CONDITIONS item=rule name=rulesForeach} - {if !$smarty.foreach.rulesForeach.first} -
    • {intl l='And'}
    • - {/if} -
    • {$rule nofilter}
    • - {/foreach} -
    -
    {intl l='Actions'} - {intl l='Edit'} - {intl l='Enabled'} -
    - {/loop} - - + {/if} +
    + {if $IS_AVAILABLE_ON_SPECIAL_OFFERS} + + {intl l="Will be available on special offers"} + + {else} + + {intl l="Won't be available on special offers"} + + {/if} +
    {intl l='Application field'} +
      + {foreach from=$APPLICATION_CONDITIONS item=rule name=rulesForeach} + {if !$smarty.foreach.rulesForeach.first} +
    • {intl l='And'}
    • + {/if} +
    • {$rule nofilter}
    • + {/foreach} +
    +
    {$SHORT_DESCRIPTION}
    {$DESCRIPTION}
    + + {intl l='Edit'} + +
    +
    +
    + {/loop}
    {include file='includes/confirmation-modal.html' id="enable" message="{intl l='Do you really want to enable this element ?'}"} diff --git a/templates/admin/default/coupon-update.html b/templates/admin/default/coupon-update.html index 16771539a..0902dae4c 100755 --- a/templates/admin/default/coupon-update.html +++ b/templates/admin/default/coupon-update.html @@ -7,19 +7,20 @@ {form name="thelia.admin.coupon.creation"} {include file='coupon/form.html' formAction={url path={$formAction}} form=$form noRules=false} {/form} -
    {/block} @@ -71,8 +72,6 @@ // Save Rules AJAX couponManager.saveRuleAjax = function() { $('#constraint-add-operators-values').html('
    '); - console.log('about to save'); - console.log(couponManager.rulesToSave); var $url = '{$urlAjaxUpdateRules}'; $.ajax({ type: "POST", @@ -88,6 +87,11 @@ }).done(function(data) { $('#constraint-list').html(data); $('#constraint-add-operators-values').html(''); + // Set the rule selector + $("#category-rule option").filter(function() { + return $(this).val() == 'thelia.constraint.rule.available_for_everyone'; + }).prop('selected', true); + couponManager.onClickUpdateRule(); couponManager.onClickDeleteRule(); }); @@ -109,13 +113,22 @@ } }).done(function(data) { $('#constraint-add-operators-values').html(data); - + couponManager.ruleToSave.serviceId = ruleId; + if (ruleId == -1) { + // Placeholder can't be saved + $('#constraint-save-btn').hide(); + } else { + $('#constraint-save-btn').show(); + } return callBack(); }); }; // Rules which will be saved couponManager.rulesToSave = couponManager.initRules(); + + $('#constraint-save-btn').hide(); + }); {/block} diff --git a/templates/admin/default/coupon/form.html b/templates/admin/default/coupon/form.html index 5d30d201d..a4ec8b14a 100644 --- a/templates/admin/default/coupon/form.html +++ b/templates/admin/default/coupon/form.html @@ -11,152 +11,155 @@ {/form_field} {form_field form=$form field='success_url'} - + {/form_field}
    -
    - - {form_field form=$form field='code'} + {form_field form=$form field='code'} +
    + {if $error}{$message}{/if} - {/form_field} -
    +
    + {/form_field} -
    - - {form_field form=$form field='title'} + {form_field form=$form field='title'} +
    + {if $error}{$message}{/if} - {/form_field} -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - -
    - {form_field form=$form field='expirationDate'} - - {if $error}{$message}{/if} - {/form_field} -
    -
    + {/form_field} -
    - - - {form_field form=$form field='maxUsage'} + {form_field form=$form field='isEnabled'} +
    + +
    + {/form_field} + + {form_field form=$form field='isAvailableOnSpecialOffers'} +
    + +
    + {/form_field} + + {form_field form=$form field='isCumulative'} +
    + +
    + {/form_field} + + {form_field form=$form field='isRemovingPostage'} +
    + +
    + {/form_field} + + {form_field form=$form field='expirationDate'} +
    + +
    + + {if $error}{$message}{/if} + +
    +
    + {/form_field} + + {form_field form=$form field='maxUsage'} +
    + + + {if $error}{$message}{/if} - {/form_field} -
    +
    + {/form_field}
    -
    - - {form_field form=$form field='effect'} + {form_field form=$form field='effect'} +
    + {if $error}{$message}{/if} - {/form_field} - {$availableCoupons.0.toolTip} -
    + {$availableCoupons.0.toolTip} +
    + {/form_field}
    -
    - - {form_field form=$form field='amount'} + {form_field form=$form field='amount'} +
    + {$value} + {if $error}{$message}{/if} - {/form_field} -
    -
    - +
    + {/form_field} + {*
    *} + {**} {*form_field form=$form field='category'*} - + {**} {*if $error}{$message}{/if}*} {*/form_field*} -
    + {*
    *}
    -
    - - {form_field form=$form field='shortDescription'} - + {form_field form=$form field='shortDescription'} +
    + + {if $error}{$message}{/if} - {/form_field} -
    +
    + {/form_field}
    -
    - - {form_field form=$form field='description'} + {form_field form=$form field='description'} +
    + {if $error}{$message}{/if} - {/form_field} -
    +
    + {/form_field} - +
    @@ -186,22 +189,23 @@
    - + {intl l='Save this rule'}
    - {foreach from=$input.availableOperators key=k item=availableOperator} + {foreach from=$input.availableOperators key=k item=availableOperator name=availableOperators} {/foreach} @@ -11,7 +11,7 @@
    {if $input.type == 'select'} @@ -72,12 +72,16 @@