diff --git a/core/lib/Thelia/Action/Coupon.php b/core/lib/Thelia/Action/Coupon.php index 8676eb16c..d50f72aa8 100755 --- a/core/lib/Thelia/Action/Coupon.php +++ b/core/lib/Thelia/Action/Coupon.php @@ -24,6 +24,7 @@ namespace Thelia\Action; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Constraint\ConstraintFactory; use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Model\Coupon as CouponModel; @@ -65,18 +66,6 @@ class Coupon extends BaseAction implements EventSubscriberInterface $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 * @@ -86,19 +75,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface { $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); + $this->createOrUpdateRule($coupon, $event); } /** @@ -127,6 +104,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface $event->getTitle(), $event->getAmount(), $event->getEffect(), + $event->isRemovingPostage(), $event->getShortDescription(), $event->getDescription(), $event->isEnabled(), @@ -134,7 +112,28 @@ class Coupon extends BaseAction implements EventSubscriberInterface $event->isAvailableOnSpecialOffers(), $event->isCumulative(), $event->getMaxUsage(), - $event->getRules(), + $event->getLocale() + ); + + $event->setCoupon($coupon); + } + + /** + * Call the Model and delegate the create or delete action + * Feed the Event with the updated model + * + * @param CouponModel $coupon Model to save + * @param CouponCreateOrUpdateEvent $event Event containing data + */ + protected function createOrUpdateRule(CouponModel $coupon, CouponCreateOrUpdateEvent $event) + { + $coupon->setDispatcher($this->getDispatcher()); + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + + $coupon->createOrUpdateRules( + $constraintFactory->serializeCouponRuleCollection($event->getRules()), $event->getLocale() ); @@ -169,8 +168,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface 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), - TheliaEvents::COUPON_RULE_DELETE => array("deleteRule", 128) + TheliaEvents::COUPON_RULE_UPDATE => array("updateRule", 128) ); } } diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 8eaeb2547..5e34aec39 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -44,6 +44,14 @@ + + + + Thelia\Controller\Admin\OrderController::indexAction + + + + diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php index 6ab746e6c..9f1bf23a0 100644 --- a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php +++ b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php @@ -73,70 +73,6 @@ class AvailableForTotalAmountManager extends CouponRuleAbstract ) ); -// /** @var RuleValidator Price Validator */ -// protected $priceValidator = null; - -// /** -// * Check if backoffice inputs are relevant or not -// * -// * @throws InvalidRuleOperatorException if Operator is not allowed -// * @throws InvalidRuleValueException if Value is not allowed -// * @return bool -// */ -// public function checkBackOfficeInput() -// { -// if (!isset($this->validators) -// || empty($this->validators) -// ||!isset($this->validators[self::PARAM1_PRICE]) -// ||!isset($this->validators[self::PARAM1_PRICE]) -// ) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_PRICE); -// } -// -// /** @var RuleValidator $ruleValidator */ -// $ruleValidator = $this->validators[self::PARAM1_PRICE]; -// /** @var PriceParam $price */ -// $price = $ruleValidator->getParam(); -// -// if (!$price instanceof PriceParam) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_PRICE); -// } -// -// $this->checkBackOfficeInputsOperators(); -// -// return $this->isPriceValid($price->getPrice(), $price->getCurrency()); -// } - -// /** -// * Check if Checkout inputs are relevant or not -// * -// * @throws InvalidRuleValueException if Value is not allowed -// * @return bool -// */ -// public function checkCheckoutInput() -// { -// $currency = $this->adapter->getCheckoutCurrency(); -// if (empty($currency)) { -// throw new InvalidRuleValueException( -// get_class(), self::PARAM1_CURRENCY -// ); -// } -// -// $price = $this->adapter->getCartTotalPrice(); -// if (empty($price)) { -// throw new InvalidRuleValueException( -// get_class(), self::PARAM1_PRICE -// ); -// } -// -// $this->paramsToValidate = array( -// self::PARAM1_PRICE => $this->adapter->getCartTotalPrice(), -// self::PARAM1_CURRENCY => $this->adapter->getCheckoutCurrency() -// ); -// -// return $this->isPriceValid($price, $currency); -// } - /** * Check validators relevancy and store them * @@ -249,49 +185,6 @@ class AvailableForTotalAmountManager extends CouponRuleAbstract return false; } -// /** -// * Check if a price is valid -// * -// * @param float $price Price to check -// * @param string $currency Price currency -// * -// * @throws InvalidRuleValueException if Value is not allowed -// * @return bool -// */ -// protected function isPriceValid($price, $currency) -// { -// $priceValidator = $this->priceValidator; -// -// /** @var PriceParam $param */ -// $param = $priceValidator->getParam(); -// if ($currency == $param->getCurrency()) { -// try { -// $priceValidator->getParam()->compareTo($price); -// } catch(\InvalidArgumentException $e) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_PRICE); -// } -// } else { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_CURRENCY); -// } -// -// return true; -// } - -// /** -// * Generate current Rule param to be validated from adapter -// * -// * @return $this -// */ -// protected function setParametersToValidate() -// { -// $this->paramsToValidate = array( -// self::PARAM1_PRICE => $this->adapter->getCartTotalPrice(), -// self::PARAM1_CURRENCY => $this->adapter->getCheckoutCurrency() -// ); -// -// return $this; -// } - /** * Get I18n name * @@ -377,41 +270,4 @@ class AvailableForTotalAmountManager extends CouponRuleAbstract ); } -// /** -// * 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 RuleValidator( -// $operators[self::PARAM1_PRICE], -// new PriceParam( -// $this->translator, -// $values[self::PARAM1_PRICE], -// $values[self::PARAM1_CURRENCY] -// ) -// ); -// -// $this->validators = array(self::PARAM1_PRICE => $this->priceValidator); -// -// return $this; -// } - - - - - } \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php index 20d7eddca..26c7a8aeb 100644 --- a/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php +++ b/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php @@ -63,77 +63,6 @@ class AvailableForXArticlesManager extends CouponRuleAbstract ) ); -// /** @var QuantityParam Quantity Validator */ -// protected $quantityValidator = null; - -// /** -// * Check if backoffice inputs are relevant or not -// * -// * @throws InvalidRuleOperatorException if Operator is not allowed -// * @throws InvalidRuleValueException if Value is not allowed -// * @return bool -// */ -// public function checkBackOfficeInput() -// { -// if (!isset($this->validators) -// || empty($this->validators) -// ||!isset($this->validators[self::PARAM1_QUANTITY]) -// ||!isset($this->validators[self::PARAM1_QUANTITY]) -// ) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); -// } -// -// /** @var RuleValidator $ruleValidator */ -// $ruleValidator = $this->validators[self::PARAM1_QUANTITY]; -// /** @var QuantityParam $quantity */ -// $quantity = $ruleValidator->getParam(); -// -// if (!$quantity instanceof QuantityParam) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); -// } -// -// $this->checkBackOfficeInputsOperators(); -// -// return $this->isQuantityValid($quantity->getInteger()); -// } - -// /** -// * Generate current Rule param to be validated from adapter -// * -// * @param CouponAdapterInterface $adapter allowing to gather -// * all necessary Thelia variables -// * -// * @return $this -// */ -// protected function setParametersToValidate() -// { -// $this->paramsToValidate = array( -// self::PARAM1_QUANTITY => $this->adapter->getNbArticlesInCart() -// ); -// -// return $this; -// } - -// /** -// * Check if Checkout inputs are relevant or not -// * -// * @throws \Thelia\Exception\InvalidRuleValueException -// * @return bool -// */ -// public function checkCheckoutInput() -// { -// if (!isset($this->paramsToValidate) -// || empty($this->paramsToValidate) -// ||!isset($this->paramsToValidate[self::PARAM1_QUANTITY]) -// ) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); -// } -// -// $price = $this->paramsToValidate[self::PARAM1_QUANTITY]; -// -// return $this->isQuantityValid($price); -// } - /** * Check validators relevancy and store them * @@ -174,7 +103,7 @@ class AvailableForXArticlesManager extends CouponRuleAbstract ); } - if (!is_int($quantityValue) || $quantityValue <= 0) { + if ((int) $quantityValue <= 0) { throw new \InvalidArgumentException( 'Value for quantity field is not legit' ); @@ -210,26 +139,6 @@ class AvailableForXArticlesManager extends CouponRuleAbstract return false; } -// /** -// * Check if a quantity is valid -// * -// * @param int $quantity Quantity to check -// * -// * @throws InvalidRuleValueException if Value is not allowed -// * @return bool -// */ -// protected function isQuantityValid($quantity) -// { -// $quantityValidator = $this->quantityValidator; -// try { -// $quantityValidator->getParam()->compareTo($quantity); -// } catch(InvalidArgumentException $e) { -// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); -// } -// -// return true; -// } - /** * Get I18n name * @@ -267,36 +176,6 @@ class AvailableForXArticlesManager extends CouponRuleAbstract 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 RuleValidator( -// $operators[self::PARAM1_QUANTITY], -// new QuantityParam( -// $this->adapter, -// $values[self::PARAM1_QUANTITY] -// ) -// ); -// -// $this->validators = array(self::PARAM1_QUANTITY => $this->quantityValidator); -// -// return $this; -// } - /** * Generate inputs ready to be drawn * diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php index a440b9ba6..cd8521d7a 100755 --- a/core/lib/Thelia/Controller/Admin/CouponController.php +++ b/core/lib/Thelia/Controller/Admin/CouponController.php @@ -26,12 +26,17 @@ namespace Thelia\Controller\Admin; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Router; use Thelia\Constraint\ConstraintFactory; +use Thelia\Constraint\ConstraintFactoryTest; 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\CouponCreateOrUpdateEvent; use Thelia\Core\Event\Coupon\CouponEvent; use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Core\Security\Exception\AuthenticationException; +use Thelia\Core\Security\Exception\AuthorizationException; use Thelia\Core\Translation\Translator; use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponManager; @@ -153,6 +158,13 @@ class CouponController extends BaseAdminController ); } else { // Prepare the data that will hydrate the form + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + $rules = $constraintFactory->unserializeCouponRuleCollection( + $coupon->getSerializedRules() + ); + $data = array( 'code' => $coupon->getCode(), 'title' => $coupon->getTitle(), @@ -166,18 +178,12 @@ class CouponController extends BaseAdminController 'isCumulative' => ($coupon->getIsCumulative() == 1), 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), 'maxUsage' => $coupon->getMaxUsage(), - 'rules' => new CouponRuleCollection(array()), + 'rules' => $rules, 'locale' => $coupon->getLocale(), ); $args['rulesObject'] = array(); - /** @var ConstraintFactory $constraintFactory */ - $constraintFactory = $this->container->get('thelia.constraint.factory'); - $rules = $constraintFactory->unserializeCouponRuleCollection( - $coupon->getSerializedRules() - ); - /** @var CouponRuleInterface $rule */ foreach ($rules->getRules() as $rule) { $args['rulesObject'][] = array( @@ -188,6 +194,8 @@ class CouponController extends BaseAdminController ); } + $args['rules'] = $this->cleanRuleForTemplate($rules); + // Setup the object form $changeForm = new CouponCreationForm($this->getRequest(), 'form', $data); @@ -211,99 +219,103 @@ class CouponController extends BaseAdminController $args['formAction'] = 'admin/coupon/update/' . $couponId; - return $this->render( - 'coupon-update', - $args - ); + 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 - $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() - ); - } +// /** +// * 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 +// ); +// } - // 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 @@ -367,6 +379,7 @@ class CouponController extends BaseAdminController ); } + /** * Manage Coupons read display * @@ -404,7 +417,6 @@ class CouponController extends BaseAdminController $constraintFactory = $this->container->get('thelia.constraint.factory'); $rulesReceived = json_decode($this->getRequest()->get('rules')); foreach ($rulesReceived as $ruleReceived) { - var_dump('building ', $ruleReceived->values); $rule = $constraintFactory->build( $ruleReceived->serviceId, (array) $ruleReceived->operators, @@ -433,6 +445,7 @@ class CouponController extends BaseAdminController $rules, $coupon->getLocale() ); + $couponEvent->setCoupon($coupon); $eventToDispatch = TheliaEvents::COUPON_RULE_UPDATE; // Dispatch Event to the Action @@ -688,4 +701,6 @@ class CouponController extends BaseAdminController // } // } + + } diff --git a/core/lib/Thelia/Controller/Admin/OrderController.php b/core/lib/Thelia/Controller/Admin/OrderController.php new file mode 100644 index 000000000..b7e2b00ce --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/OrderController.php @@ -0,0 +1,39 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + +/** + * Class OrderController + * @package Thelia\Controller\Admin + * @author Manuel Raynaud + */ +class OrderController extends BaseAdminController +{ + public function indexAction() + { + if (null !== $response = $this->checkAuth("admin.orders.view")) return $response; + return $this->render("orders", array("display_order" => 20)); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index c19d3a400..01a669522 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -294,21 +294,6 @@ final class TheliaEvents */ 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 --------------------------------------------- const CONFIG_CREATE = "action.createConfig"; @@ -358,4 +343,5 @@ final class TheliaEvents const BEFORE_DELETECURRENCY = "action.before_deleteCurrency"; const AFTER_DELETECURRENCY = "action.after_deleteCurrency"; + } diff --git a/core/lib/Thelia/Core/Thelia.php b/core/lib/Thelia/Core/Thelia.php index 402059ddd..eb560a484 100755 --- a/core/lib/Thelia/Core/Thelia.php +++ b/core/lib/Thelia/Core/Thelia.php @@ -83,7 +83,7 @@ class Thelia extends Kernel $con = Propel::getConnection(\Thelia\Model\Map\ProductTableMap::DATABASE_NAME); $con->setAttribute(ConnectionWrapper::PROPEL_ATTR_CACHE_PREPARES, true); if ($this->isDebug()) { - //$serviceContainer->setLogger('defaultLogger', \Thelia\Log\Tlog::getInstance()); + $serviceContainer->setLogger('defaultLogger', \Thelia\Log\Tlog::getInstance()); $con->useDebug(true); } } diff --git a/core/lib/Thelia/Exception/TaxEngineException.php b/core/lib/Thelia/Exception/TaxEngineException.php index d56862ab6..93f5b8237 100755 --- a/core/lib/Thelia/Exception/TaxEngineException.php +++ b/core/lib/Thelia/Exception/TaxEngineException.php @@ -27,9 +27,18 @@ class TaxEngineException extends \RuntimeException { const UNKNOWN_EXCEPTION = 0; + const BAD_RECORDED_TYPE = 101; + const BAD_RECORDED_REQUIREMENTS = 102; + + const TAX_TYPE_BAD_ABSTRACT_METHOD = 201; + const TAX_TYPE_REQUIREMENT_NOT_FOUND = 202; + const TAX_TYPE_BAD_REQUIREMENT_VALUE = 203; + const UNDEFINED_PRODUCT = 501; const UNDEFINED_COUNTRY = 502; const UNDEFINED_TAX_RULES_COLLECTION = 503; + const UNDEFINED_REQUIREMENTS = 504; + const UNDEFINED_REQUIREMENT_VALUE = 505; const BAD_AMOUNT_FORMAT = 601; diff --git a/core/lib/Thelia/Exception/TypeException.php b/core/lib/Thelia/Exception/TypeException.php new file mode 100755 index 000000000..442fffe3e --- /dev/null +++ b/core/lib/Thelia/Exception/TypeException.php @@ -0,0 +1,39 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Exception; + +class TypeException extends \RuntimeException +{ + const UNKNOWN_EXCEPTION = 0; + + const MODEL_NOT_FOUND = 404; + + public function __construct($message, $code = null, $previous = null) + { + if ($code === null) { + $code = self::UNKNOWN_EXCEPTION; + } + parent::__construct($message, $code, $previous); + } +} diff --git a/core/lib/Thelia/Model/Base/Tax.php b/core/lib/Thelia/Model/Base/Tax.php index ed4bb40f7..da674b5cf 100644 --- a/core/lib/Thelia/Model/Base/Tax.php +++ b/core/lib/Thelia/Model/Base/Tax.php @@ -66,10 +66,16 @@ abstract class Tax implements ActiveRecordInterface protected $id; /** - * The value for the rate field. - * @var double + * The value for the type field. + * @var string */ - protected $rate; + protected $type; + + /** + * The value for the serialized_requirements field. + * @var string + */ + protected $serialized_requirements; /** * The value for the created_at field. @@ -395,14 +401,25 @@ abstract class Tax implements ActiveRecordInterface } /** - * Get the [rate] column value. + * Get the [type] column value. * - * @return double + * @return string */ - public function getRate() + public function getType() { - return $this->rate; + return $this->type; + } + + /** + * Get the [serialized_requirements] column value. + * + * @return string + */ + public function getSerializedRequirements() + { + + return $this->serialized_requirements; } /** @@ -467,25 +484,46 @@ abstract class Tax implements ActiveRecordInterface } // setId() /** - * Set the value of [rate] column. + * Set the value of [type] column. * - * @param double $v new value + * @param string $v new value * @return \Thelia\Model\Tax The current object (for fluent API support) */ - public function setRate($v) + public function setType($v) { if ($v !== null) { - $v = (double) $v; + $v = (string) $v; } - if ($this->rate !== $v) { - $this->rate = $v; - $this->modifiedColumns[] = TaxTableMap::RATE; + if ($this->type !== $v) { + $this->type = $v; + $this->modifiedColumns[] = TaxTableMap::TYPE; } return $this; - } // setRate() + } // setType() + + /** + * Set the value of [serialized_requirements] column. + * + * @param string $v new value + * @return \Thelia\Model\Tax The current object (for fluent API support) + */ + public function setSerializedRequirements($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->serialized_requirements !== $v) { + $this->serialized_requirements = $v; + $this->modifiedColumns[] = TaxTableMap::SERIALIZED_REQUIREMENTS; + } + + + return $this; + } // setSerializedRequirements() /** * Sets the value of [created_at] column to a normalized version of the date/time value specified. @@ -569,16 +607,19 @@ abstract class Tax implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : TaxTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; $this->id = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxTableMap::translateFieldName('Rate', TableMap::TYPE_PHPNAME, $indexType)]; - $this->rate = (null !== $col) ? (double) $col : null; + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxTableMap::translateFieldName('Type', TableMap::TYPE_PHPNAME, $indexType)]; + $this->type = (null !== $col) ? (string) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxTableMap::translateFieldName('SerializedRequirements', TableMap::TYPE_PHPNAME, $indexType)]; + $this->serialized_requirements = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : TaxTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : TaxTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : TaxTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -591,7 +632,7 @@ abstract class Tax implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 4; // 4 = TaxTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 5; // 5 = TaxTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\Tax object", 0, $e); @@ -852,8 +893,11 @@ abstract class Tax implements ActiveRecordInterface if ($this->isColumnModified(TaxTableMap::ID)) { $modifiedColumns[':p' . $index++] = 'ID'; } - if ($this->isColumnModified(TaxTableMap::RATE)) { - $modifiedColumns[':p' . $index++] = 'RATE'; + if ($this->isColumnModified(TaxTableMap::TYPE)) { + $modifiedColumns[':p' . $index++] = 'TYPE'; + } + if ($this->isColumnModified(TaxTableMap::SERIALIZED_REQUIREMENTS)) { + $modifiedColumns[':p' . $index++] = 'SERIALIZED_REQUIREMENTS'; } if ($this->isColumnModified(TaxTableMap::CREATED_AT)) { $modifiedColumns[':p' . $index++] = 'CREATED_AT'; @@ -875,8 +919,11 @@ abstract class Tax implements ActiveRecordInterface case 'ID': $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); break; - case 'RATE': - $stmt->bindValue($identifier, $this->rate, PDO::PARAM_STR); + case 'TYPE': + $stmt->bindValue($identifier, $this->type, PDO::PARAM_STR); + break; + case 'SERIALIZED_REQUIREMENTS': + $stmt->bindValue($identifier, $this->serialized_requirements, PDO::PARAM_STR); break; case 'CREATED_AT': $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); @@ -950,12 +997,15 @@ abstract class Tax implements ActiveRecordInterface return $this->getId(); break; case 1: - return $this->getRate(); + return $this->getType(); break; case 2: - return $this->getCreatedAt(); + return $this->getSerializedRequirements(); break; case 3: + return $this->getCreatedAt(); + break; + case 4: return $this->getUpdatedAt(); break; default: @@ -988,9 +1038,10 @@ abstract class Tax implements ActiveRecordInterface $keys = TaxTableMap::getFieldNames($keyType); $result = array( $keys[0] => $this->getId(), - $keys[1] => $this->getRate(), - $keys[2] => $this->getCreatedAt(), - $keys[3] => $this->getUpdatedAt(), + $keys[1] => $this->getType(), + $keys[2] => $this->getSerializedRequirements(), + $keys[3] => $this->getCreatedAt(), + $keys[4] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -1043,12 +1094,15 @@ abstract class Tax implements ActiveRecordInterface $this->setId($value); break; case 1: - $this->setRate($value); + $this->setType($value); break; case 2: - $this->setCreatedAt($value); + $this->setSerializedRequirements($value); break; case 3: + $this->setCreatedAt($value); + break; + case 4: $this->setUpdatedAt($value); break; } // switch() @@ -1076,9 +1130,10 @@ abstract class Tax implements ActiveRecordInterface $keys = TaxTableMap::getFieldNames($keyType); if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); - if (array_key_exists($keys[1], $arr)) $this->setRate($arr[$keys[1]]); - if (array_key_exists($keys[2], $arr)) $this->setCreatedAt($arr[$keys[2]]); - if (array_key_exists($keys[3], $arr)) $this->setUpdatedAt($arr[$keys[3]]); + if (array_key_exists($keys[1], $arr)) $this->setType($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setSerializedRequirements($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setCreatedAt($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setUpdatedAt($arr[$keys[4]]); } /** @@ -1091,7 +1146,8 @@ abstract class Tax implements ActiveRecordInterface $criteria = new Criteria(TaxTableMap::DATABASE_NAME); if ($this->isColumnModified(TaxTableMap::ID)) $criteria->add(TaxTableMap::ID, $this->id); - if ($this->isColumnModified(TaxTableMap::RATE)) $criteria->add(TaxTableMap::RATE, $this->rate); + if ($this->isColumnModified(TaxTableMap::TYPE)) $criteria->add(TaxTableMap::TYPE, $this->type); + if ($this->isColumnModified(TaxTableMap::SERIALIZED_REQUIREMENTS)) $criteria->add(TaxTableMap::SERIALIZED_REQUIREMENTS, $this->serialized_requirements); if ($this->isColumnModified(TaxTableMap::CREATED_AT)) $criteria->add(TaxTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(TaxTableMap::UPDATED_AT)) $criteria->add(TaxTableMap::UPDATED_AT, $this->updated_at); @@ -1157,7 +1213,8 @@ abstract class Tax implements ActiveRecordInterface */ public function copyInto($copyObj, $deepCopy = false, $makeNew = true) { - $copyObj->setRate($this->getRate()); + $copyObj->setType($this->getType()); + $copyObj->setSerializedRequirements($this->getSerializedRequirements()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); @@ -1729,7 +1786,8 @@ abstract class Tax implements ActiveRecordInterface public function clear() { $this->id = null; - $this->rate = null; + $this->type = null; + $this->serialized_requirements = null; $this->created_at = null; $this->updated_at = null; $this->alreadyInSave = false; diff --git a/core/lib/Thelia/Model/Base/TaxQuery.php b/core/lib/Thelia/Model/Base/TaxQuery.php index 07316bf69..93da10f53 100644 --- a/core/lib/Thelia/Model/Base/TaxQuery.php +++ b/core/lib/Thelia/Model/Base/TaxQuery.php @@ -23,12 +23,14 @@ use Thelia\Model\Map\TaxTableMap; * * * @method ChildTaxQuery orderById($order = Criteria::ASC) Order by the id column - * @method ChildTaxQuery orderByRate($order = Criteria::ASC) Order by the rate column + * @method ChildTaxQuery orderByType($order = Criteria::ASC) Order by the type column + * @method ChildTaxQuery orderBySerializedRequirements($order = Criteria::ASC) Order by the serialized_requirements column * @method ChildTaxQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildTaxQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * * @method ChildTaxQuery groupById() Group by the id column - * @method ChildTaxQuery groupByRate() Group by the rate column + * @method ChildTaxQuery groupByType() Group by the type column + * @method ChildTaxQuery groupBySerializedRequirements() Group by the serialized_requirements column * @method ChildTaxQuery groupByCreatedAt() Group by the created_at column * @method ChildTaxQuery groupByUpdatedAt() Group by the updated_at column * @@ -48,12 +50,14 @@ use Thelia\Model\Map\TaxTableMap; * @method ChildTax findOneOrCreate(ConnectionInterface $con = null) Return the first ChildTax matching the query, or a new ChildTax object populated from the query conditions when no match is found * * @method ChildTax findOneById(int $id) Return the first ChildTax filtered by the id column - * @method ChildTax findOneByRate(double $rate) Return the first ChildTax filtered by the rate column + * @method ChildTax findOneByType(string $type) Return the first ChildTax filtered by the type column + * @method ChildTax findOneBySerializedRequirements(string $serialized_requirements) Return the first ChildTax filtered by the serialized_requirements column * @method ChildTax findOneByCreatedAt(string $created_at) Return the first ChildTax filtered by the created_at column * @method ChildTax findOneByUpdatedAt(string $updated_at) Return the first ChildTax filtered by the updated_at column * * @method array findById(int $id) Return ChildTax objects filtered by the id column - * @method array findByRate(double $rate) Return ChildTax objects filtered by the rate column + * @method array findByType(string $type) Return ChildTax objects filtered by the type column + * @method array findBySerializedRequirements(string $serialized_requirements) Return ChildTax objects filtered by the serialized_requirements column * @method array findByCreatedAt(string $created_at) Return ChildTax objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildTax objects filtered by the updated_at column * @@ -144,7 +148,7 @@ abstract class TaxQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, RATE, CREATED_AT, UPDATED_AT FROM tax WHERE ID = :p0'; + $sql = 'SELECT ID, TYPE, SERIALIZED_REQUIREMENTS, CREATED_AT, UPDATED_AT FROM tax WHERE ID = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -275,44 +279,61 @@ abstract class TaxQuery extends ModelCriteria } /** - * Filter the query on the rate column + * Filter the query on the type column * * Example usage: * - * $query->filterByRate(1234); // WHERE rate = 1234 - * $query->filterByRate(array(12, 34)); // WHERE rate IN (12, 34) - * $query->filterByRate(array('min' => 12)); // WHERE rate > 12 + * $query->filterByType('fooValue'); // WHERE type = 'fooValue' + * $query->filterByType('%fooValue%'); // WHERE type LIKE '%fooValue%' * * - * @param mixed $rate The value to use as filter. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. + * @param string $type The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * * @return ChildTaxQuery The current query, for fluid interface */ - public function filterByRate($rate = null, $comparison = null) + public function filterByType($type = null, $comparison = null) { - if (is_array($rate)) { - $useMinMax = false; - if (isset($rate['min'])) { - $this->addUsingAlias(TaxTableMap::RATE, $rate['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($rate['max'])) { - $this->addUsingAlias(TaxTableMap::RATE, $rate['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { + if (null === $comparison) { + if (is_array($type)) { $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $type)) { + $type = str_replace('*', '%', $type); + $comparison = Criteria::LIKE; } } - return $this->addUsingAlias(TaxTableMap::RATE, $rate, $comparison); + return $this->addUsingAlias(TaxTableMap::TYPE, $type, $comparison); + } + + /** + * Filter the query on the serialized_requirements column + * + * Example usage: + * + * $query->filterBySerializedRequirements('fooValue'); // WHERE serialized_requirements = 'fooValue' + * $query->filterBySerializedRequirements('%fooValue%'); // WHERE serialized_requirements LIKE '%fooValue%' + * + * + * @param string $serializedRequirements The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildTaxQuery The current query, for fluid interface + */ + public function filterBySerializedRequirements($serializedRequirements = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($serializedRequirements)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $serializedRequirements)) { + $serializedRequirements = str_replace('*', '%', $serializedRequirements); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(TaxTableMap::SERIALIZED_REQUIREMENTS, $serializedRequirements, $comparison); } /** diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php index f5788ff4f..7a7ce1e4a 100755 --- a/core/lib/Thelia/Model/Coupon.php +++ b/core/lib/Thelia/Model/Coupon.php @@ -49,24 +49,25 @@ class Coupon extends BaseCoupon /** - * Constructor + * Create or Update this Coupon * - * @param string $code Coupon Code - * @param string $title Coupon title - * @param float $amount Amount removed from the Total Checkout - * @param string $effect Coupon effect - * @param string $shortDescription Coupon short description - * @param string $description Coupon description - * @param boolean $isEnabled Enable/Disable - * @param \DateTime $expirationDate Coupon expiration date - * @param boolean $isAvailableOnSpecialOffers Is available on special offers - * @param boolean $isCumulative Is cumulative - * @param boolean $isRemovingPostage Is removing Postage - * @param int $maxUsage Coupon quantity - * @param CouponRuleCollection $rules CouponRuleInterface to add - * @param string $locale Coupon Language code ISO (ex: fr_FR) + * @param string $code Coupon Code + * @param string $title Coupon title + * @param float $amount Amount removed from the Total Checkout + * @param string $effect Coupon effect + * @param bool $isRemovingPostage Is removing Postage + * @param string $shortDescription Coupon short description + * @param string $description Coupon description + * @param boolean $isEnabled Enable/Disable + * @param \DateTime $expirationDate Coupon expiration date + * @param boolean $isAvailableOnSpecialOffers Is available on special offers + * @param boolean $isCumulative Is cumulative + * @param int $maxUsage Coupon quantity + * @param string $locale Coupon Language code ISO (ex: fr_FR) + * + * @throws \Exception */ - function createOrUpdate($code, $title, $amount, $effect, $shortDescription, $description, $isEnabled, $expirationDate, $isAvailableOnSpecialOffers, $isCumulative, $maxUsage, $rules, $locale = null) + function createOrUpdate($code, $title, $amount, $effect, $isRemovingPostage, $shortDescription, $description, $isEnabled, $expirationDate, $isAvailableOnSpecialOffers, $isCumulative, $maxUsage, $locale = null) { $this->setCode($code) ->setTitle($title) @@ -74,13 +75,13 @@ class Coupon extends BaseCoupon ->setDescription($description) ->setType($effect) ->setAmount($amount) + ->setIsRemovingPostage($isRemovingPostage) ->setType($amount) ->setIsEnabled($isEnabled) ->setExpirationDate($expirationDate) ->setIsAvailableOnSpecialOffers($isAvailableOnSpecialOffers) ->setIsCumulative($isCumulative) - ->setMaxUsage($maxUsage) - ->setRules($rules); + ->setMaxUsage($maxUsage); // Set object language (i18n) if (!is_null($locale)) { @@ -99,33 +100,34 @@ class Coupon extends BaseCoupon } } -// /** -// * Set the value of [serialized_rules] column. -// * Convert a CouponRuleCollection into a serialized array of SerializableRule -// * -// * @param CouponRuleCollection $rules A set of Rules -// * -// * @return \Thelia\Model\Coupon The current object (for fluent API support) -// */ -// public function setRules(CouponRuleCollection $rules) -// { -// $serializedRules = null; -// if ($rules !== null) { -// /** @var $rule CouponRuleInterface */ -// foreach ($rules->getRules() as $rule) { -// $serializedRules[] = $rule->getSerializableRule(); -// } -// -// $serializedRules = (string) base64_encode(serialize($serializedRules)); -// } -// -// if ($this->serialized_rules !== $serializedRules) { -// $this->serialized_rules = $serializedRules; -// $this->modifiedColumns[] = CouponTableMap::SERIALIZED_RULES; -// } -// -// return $this; -// } + /** + * Create or Update this coupon rule + * + * @param string $serializableRules Serialized rules ready to be saved + * @param string $locale Coupon Language code ISO (ex: fr_FR) + * + * @throws \Exception + */ + function createOrUpdateRules($serializableRules, $locale) + { + $this->setSerializedRules($serializableRules); + + // Set object language (i18n) + if (!is_null($locale)) { + $this->setLocale($locale); + } + + $con = Propel::getWriteConnection(CouponTableMap::DATABASE_NAME); + $con->beginTransaction(); + try { + $this->save($con); + $con->commit(); + + } catch(\Exception $e) { + $con->rollback(); + throw $e; + } + } diff --git a/core/lib/Thelia/Model/Map/TaxTableMap.php b/core/lib/Thelia/Model/Map/TaxTableMap.php index 11e5047ce..6ca89ae85 100644 --- a/core/lib/Thelia/Model/Map/TaxTableMap.php +++ b/core/lib/Thelia/Model/Map/TaxTableMap.php @@ -57,7 +57,7 @@ class TaxTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 4; + const NUM_COLUMNS = 5; /** * The number of lazy-loaded columns @@ -67,7 +67,7 @@ class TaxTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 4; + const NUM_HYDRATE_COLUMNS = 5; /** * the column name for the ID field @@ -75,9 +75,14 @@ class TaxTableMap extends TableMap const ID = 'tax.ID'; /** - * the column name for the RATE field + * the column name for the TYPE field */ - const RATE = 'tax.RATE'; + const TYPE = 'tax.TYPE'; + + /** + * the column name for the SERIALIZED_REQUIREMENTS field + */ + const SERIALIZED_REQUIREMENTS = 'tax.SERIALIZED_REQUIREMENTS'; /** * the column name for the CREATED_AT field @@ -110,12 +115,12 @@ class TaxTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'Rate', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'rate', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(TaxTableMap::ID, TaxTableMap::RATE, TaxTableMap::CREATED_AT, TaxTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'RATE', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'rate', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, ) + self::TYPE_PHPNAME => array('Id', 'Type', 'SerializedRequirements', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('id', 'type', 'serializedRequirements', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(TaxTableMap::ID, TaxTableMap::TYPE, TaxTableMap::SERIALIZED_REQUIREMENTS, TaxTableMap::CREATED_AT, TaxTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('ID', 'TYPE', 'SERIALIZED_REQUIREMENTS', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('id', 'type', 'serialized_requirements', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, ) ); /** @@ -125,12 +130,12 @@ class TaxTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'Rate' => 1, 'CreatedAt' => 2, 'UpdatedAt' => 3, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'rate' => 1, 'createdAt' => 2, 'updatedAt' => 3, ), - self::TYPE_COLNAME => array(TaxTableMap::ID => 0, TaxTableMap::RATE => 1, TaxTableMap::CREATED_AT => 2, TaxTableMap::UPDATED_AT => 3, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'RATE' => 1, 'CREATED_AT' => 2, 'UPDATED_AT' => 3, ), - self::TYPE_FIELDNAME => array('id' => 0, 'rate' => 1, 'created_at' => 2, 'updated_at' => 3, ), - self::TYPE_NUM => array(0, 1, 2, 3, ) + self::TYPE_PHPNAME => array('Id' => 0, 'Type' => 1, 'SerializedRequirements' => 2, 'CreatedAt' => 3, 'UpdatedAt' => 4, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'type' => 1, 'serializedRequirements' => 2, 'createdAt' => 3, 'updatedAt' => 4, ), + self::TYPE_COLNAME => array(TaxTableMap::ID => 0, TaxTableMap::TYPE => 1, TaxTableMap::SERIALIZED_REQUIREMENTS => 2, TaxTableMap::CREATED_AT => 3, TaxTableMap::UPDATED_AT => 4, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'TYPE' => 1, 'SERIALIZED_REQUIREMENTS' => 2, 'CREATED_AT' => 3, 'UPDATED_AT' => 4, ), + self::TYPE_FIELDNAME => array('id' => 0, 'type' => 1, 'serialized_requirements' => 2, 'created_at' => 3, 'updated_at' => 4, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, ) ); /** @@ -150,7 +155,8 @@ class TaxTableMap extends TableMap $this->setUseIdGenerator(true); // columns $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null); - $this->addColumn('RATE', 'Rate', 'FLOAT', true, null, null); + $this->addColumn('TYPE', 'Type', 'VARCHAR', true, 255, null); + $this->addColumn('SERIALIZED_REQUIREMENTS', 'SerializedRequirements', 'LONGVARCHAR', true, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); } // initialize() @@ -327,12 +333,14 @@ class TaxTableMap extends TableMap { if (null === $alias) { $criteria->addSelectColumn(TaxTableMap::ID); - $criteria->addSelectColumn(TaxTableMap::RATE); + $criteria->addSelectColumn(TaxTableMap::TYPE); + $criteria->addSelectColumn(TaxTableMap::SERIALIZED_REQUIREMENTS); $criteria->addSelectColumn(TaxTableMap::CREATED_AT); $criteria->addSelectColumn(TaxTableMap::UPDATED_AT); } else { $criteria->addSelectColumn($alias . '.ID'); - $criteria->addSelectColumn($alias . '.RATE'); + $criteria->addSelectColumn($alias . '.TYPE'); + $criteria->addSelectColumn($alias . '.SERIALIZED_REQUIREMENTS'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); } diff --git a/core/lib/Thelia/Model/Tax.php b/core/lib/Thelia/Model/Tax.php index 21efbae6a..738f16508 100755 --- a/core/lib/Thelia/Model/Tax.php +++ b/core/lib/Thelia/Model/Tax.php @@ -4,6 +4,7 @@ namespace Thelia\Model; use Thelia\Exception\TaxEngineException; use Thelia\Model\Base\Tax as BaseTax; +use Thelia\TaxEngine\TaxType\BaseTaxType; class Tax extends BaseTax { @@ -33,14 +34,37 @@ class Tax extends BaseTax return $taxRuleCountryPosition; } - public function getTaxRuleRateSum() + public function getTypeInstance() { - try { - $taxRuleRateSum = $this->getVirtualColumn(TaxRuleQuery::ALIAS_FOR_TAX_RATE_SUM); - } catch(PropelException $e) { - throw new PropelException("Virtual column `" . TaxRuleQuery::ALIAS_FOR_TAX_RATE_SUM . "` does not exist in Tax::getTaxRuleRateSum"); + $class = '\\Thelia\\TaxEngine\\TaxType\\' . $this->getType(); + + /* test type */ + if(!class_exists($class)) { + throw new TaxEngineException('Recorded type does not exists', TaxEngineException::BAD_RECORDED_TYPE); } - return $taxRuleRateSum; + $instance = new $class; + + if(!$instance instanceof BaseTaxType) { + throw new TaxEngineException('Recorded type does not extends BaseTaxType', TaxEngineException::BAD_RECORDED_TYPE); + } + + return $instance; + } + + public function setRequirements($requirements) + { + parent::setSerializedRequirements(base64_encode(json_encode($requirements))); + } + + public function getRequirements() + { + $requirements = json_decode(base64_decode(parent::getSerializedRequirements()), true); + + if(json_last_error() != JSON_ERROR_NONE || !is_array($requirements)) { + throw new TaxEngineException('BAD RECORDED REQUIREMENTS', TaxEngineException::BAD_RECORDED_REQUIREMENTS); + } + + return $requirements; } } diff --git a/core/lib/Thelia/Model/TaxRuleQuery.php b/core/lib/Thelia/Model/TaxRuleQuery.php index f9c6cf1e5..d5ce47546 100755 --- a/core/lib/Thelia/Model/TaxRuleQuery.php +++ b/core/lib/Thelia/Model/TaxRuleQuery.php @@ -20,21 +20,18 @@ use Thelia\Model\Map\TaxTableMap; class TaxRuleQuery extends BaseTaxRuleQuery { const ALIAS_FOR_TAX_RULE_COUNTRY_POSITION = 'taxRuleCountryPosition'; - const ALIAS_FOR_TAX_RATE_SUM = 'taxRateSum'; - public function getTaxCalculatorGroupedCollection(Product $product, Country $country) + public function getTaxCalculatorCollection(Product $product, Country $country) { $search = TaxQuery::create() ->filterByTaxRuleCountry( TaxRuleCountryQuery::create() ->filterByCountry($country, Criteria::EQUAL) ->filterByTaxRuleId($product->getTaxRuleId()) - ->groupByPosition() ->orderByPosition() ->find() ) ->withColumn(TaxRuleCountryTableMap::POSITION, self::ALIAS_FOR_TAX_RULE_COUNTRY_POSITION) - ->withColumn('ROUND(SUM(' . TaxTableMap::RATE . '), 2)', self::ALIAS_FOR_TAX_RATE_SUM) ; return $search->find(); diff --git a/core/lib/Thelia/TaxEngine/Calculator.php b/core/lib/Thelia/TaxEngine/Calculator.php index 66c4fcbbf..2708e88c6 100755 --- a/core/lib/Thelia/TaxEngine/Calculator.php +++ b/core/lib/Thelia/TaxEngine/Calculator.php @@ -34,9 +34,12 @@ use Thelia\Model\TaxRuleQuery; */ class Calculator { + /** + * @var TaxRuleQuery + */ protected $taxRuleQuery = null; - protected $taxRulesGroupedCollection = null; + protected $taxRulesCollection = null; protected $product = null; protected $country = null; @@ -50,7 +53,7 @@ class Calculator { $this->product = null; $this->country = null; - $this->taxRulesGroupedCollection = null; + $this->taxRulesCollection = null; if($product->getId() === null) { throw new TaxEngineException('Product id is empty in Calculator::load', TaxEngineException::UNDEFINED_PRODUCT); @@ -62,34 +65,38 @@ class Calculator $this->product = $product; $this->country = $country; - $this->taxRulesGroupedCollection = $this->taxRuleQuery->getTaxCalculatorGroupedCollection($product, $country); + $this->taxRulesCollection = $this->taxRuleQuery->getTaxCalculatorCollection($product, $country); return $this; } - public function getTaxAmount($amount) + public function getTaxAmount($untaxedPrice) { - if(null === $this->taxRulesGroupedCollection) { + if(null === $this->taxRulesCollection) { throw new TaxEngineException('Tax rules collection is empty in Calculator::getTaxAmount', TaxEngineException::UNDEFINED_TAX_RULES_COLLECTION); } - if(false === filter_var($amount, FILTER_VALIDATE_FLOAT)) { + if(false === filter_var($untaxedPrice, FILTER_VALIDATE_FLOAT)) { throw new TaxEngineException('BAD AMOUNT FORMAT', TaxEngineException::BAD_AMOUNT_FORMAT); } $totalTaxAmount = 0; - foreach($this->taxRulesGroupedCollection as $taxRule) { - $rateSum = $taxRule->getTaxRuleRateSum(); - $taxAmount = $amount * $rateSum * 0.01; + foreach($this->taxRulesCollection as $taxRule) { + $taxType = $taxRule->getTypeInstance(); + + $taxType->loadRequirements($taxRule->getRequirements()); + + $taxAmount = $taxType->calculate($untaxedPrice); + $totalTaxAmount += $taxAmount; - $amount += $taxAmount; + $untaxedPrice += $taxAmount; } return $totalTaxAmount; } - public function getTaxedPrice($amount) + public function getTaxedPrice($untaxedPrice) { - return $amount + $this->getTaxAmount($amount); + return $untaxedPrice + $this->getTaxAmount($untaxedPrice); } } diff --git a/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php new file mode 100755 index 000000000..7f487bf64 --- /dev/null +++ b/core/lib/Thelia/TaxEngine/TaxType/BaseTaxType.php @@ -0,0 +1,78 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\TaxEngine\TaxType; + +use Thelia\Exception\TaxEngineException; +use Thelia\Type\TypeInterface; + +/** + * + * @author Etienne Roudeix + * + */ +abstract class BaseTaxType +{ + protected $requirements = null; + + public abstract function calculate($untaxedPrice); + + public abstract function getRequirementsList(); + + public function loadRequirements($requirementsValues) + { + $this->requirements = $this->getRequirementsList(); + + if(!is_array($this->requirements)) { + throw new TaxEngineException('getRequirementsList must return an array', TaxEngineException::TAX_TYPE_BAD_ABSTRACT_METHOD); + } + + foreach($this->requirements as $requirement => $requirementType) { + if(!$requirementType instanceof TypeInterface) { + throw new TaxEngineException('getRequirementsList must return an array of TypeInterface', TaxEngineException::TAX_TYPE_BAD_ABSTRACT_METHOD); + } + + if(!array_key_exists($requirement, $requirementsValues)) { + throw new TaxEngineException('Cannot load requirements : requirement value for `' . $requirement . '` not found', TaxEngineException::TAX_TYPE_REQUIREMENT_NOT_FOUND); + } + + if(!$requirementType->isValid($requirementsValues[$requirement])) { + throw new TaxEngineException('Requirement value for `' . $requirement . '` does not match required type', TaxEngineException::TAX_TYPE_BAD_REQUIREMENT_VALUE); + } + + $this->requirements[$requirement] = $requirementsValues[$requirement]; + } + } + + public function getRequirement($key) + { + if($this->requirements === null) { + throw new TaxEngineException('Requirements are empty in BaseTaxType::getRequirement', TaxEngineException::UNDEFINED_REQUIREMENTS); + } + + if(!array_key_exists($key, $this->requirements)) { + throw new TaxEngineException('Requirement value for `' . $key . '` does not exists in BaseTaxType::$requirements', TaxEngineException::UNDEFINED_REQUIREMENT_VALUE); + } + + return $this->requirements[$key]; + } +} diff --git a/core/lib/Thelia/TaxEngine/TaxType/FeatureSlicePercentTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/FeatureSlicePercentTaxType.php new file mode 100755 index 000000000..4485f1e21 --- /dev/null +++ b/core/lib/Thelia/TaxEngine/TaxType/FeatureSlicePercentTaxType.php @@ -0,0 +1,47 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\TaxEngine\TaxType; + +use Thelia\Type\FloatToFloatArrayType; +use Thelia\Type\ModelType; + +/** + * + * @author Etienne Roudeix + * + */ +class featureSlicePercentTaxType extends BaseTaxType +{ + public function calculate($untaxedPrice) + { + + } + + public function getRequirementsList() + { + return array( + 'featureId' => new ModelType('Currency'), + 'slices' => new FloatToFloatArrayType(), + ); + } +} diff --git a/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php b/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php new file mode 100755 index 000000000..1d7152fcf --- /dev/null +++ b/core/lib/Thelia/TaxEngine/TaxType/PricePercentTaxType.php @@ -0,0 +1,45 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\TaxEngine\TaxType; + +use Thelia\Type\FloatType; + +/** + * + * @author Etienne Roudeix + * + */ +class PricePercentTaxType extends BaseTaxType +{ + public function calculate($untaxedPrice) + { + return $untaxedPrice * $this->getRequirement("percent") * 0.01; + } + + public function getRequirementsList() + { + return array( + 'percent' => new FloatType(), + ); + } +} diff --git a/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php b/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php index fac6ca643..719d90835 100755 --- a/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php +++ b/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php @@ -83,9 +83,9 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase $calculator = new Calculator(); - $taxRuleQuery = $this->getMock('\Thelia\Model\TaxRuleQuery', array('getTaxCalculatorGroupedCollection')); + $taxRuleQuery = $this->getMock('\Thelia\Model\TaxRuleQuery', array('getTaxCalculatorCollection')); $taxRuleQuery->expects($this->once()) - ->method('getTaxCalculatorGroupedCollection') + ->method('getTaxCalculatorCollection') ->with($productQuery, $countryQuery) ->will($this->returnValue('foo')); @@ -104,7 +104,7 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase ); $this->assertEquals( 'foo', - $this->getProperty('taxRulesGroupedCollection')->getValue($calculator) + $this->getProperty('taxRulesCollection')->getValue($calculator) ); } @@ -124,35 +124,37 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase */ public function testGetTaxAmountBadAmount() { - $taxRulesGroupedCollection = new ObjectCollection(); + $taxRulesCollection = new ObjectCollection(); $calculator = new Calculator(); - $rewritingUrlQuery = $this->getProperty('taxRulesGroupedCollection'); - $rewritingUrlQuery->setValue($calculator, $taxRulesGroupedCollection); + $rewritingUrlQuery = $this->getProperty('taxRulesCollection'); + $rewritingUrlQuery->setValue($calculator, $taxRulesCollection); $calculator->getTaxAmount('foo'); } public function testGetTaxAmountAndGetTaxedPrice() { - $taxRulesGroupedCollection = new ObjectCollection(); - $taxRulesGroupedCollection->setModel('\Thelia\Model\Tax'); + $taxRulesCollection = new ObjectCollection(); + $taxRulesCollection->setModel('\Thelia\Model\Tax'); $tax = new Tax(); - $tax->setVirtualColumn('taxRateSum', 10); + $tax->setType('PricePercentTaxType') + ->setRequirements(array('percent' => 10)); - $taxRulesGroupedCollection->append($tax); + $taxRulesCollection->append($tax); $tax = new Tax(); - $tax->setVirtualColumn('taxRateSum', 8); + $tax->setType('PricePercentTaxType') + ->setRequirements(array('percent' => 8)); - $taxRulesGroupedCollection->append($tax); + $taxRulesCollection->append($tax); $calculator = new Calculator(); - $rewritingUrlQuery = $this->getProperty('taxRulesGroupedCollection'); - $rewritingUrlQuery->setValue($calculator, $taxRulesGroupedCollection); + $rewritingUrlQuery = $this->getProperty('taxRulesCollection'); + $rewritingUrlQuery->setValue($calculator, $taxRulesCollection); $taxAmount = $calculator->getTaxAmount(500); $taxedPrice = $calculator->getTaxedPrice(500); diff --git a/core/lib/Thelia/Type/FloatToFloatArrayType.php b/core/lib/Thelia/Type/FloatToFloatArrayType.php new file mode 100755 index 000000000..5a70dba91 --- /dev/null +++ b/core/lib/Thelia/Type/FloatToFloatArrayType.php @@ -0,0 +1,56 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class FloatToFloatArrayType implements TypeInterface +{ + public function getType() + { + return 'Float key to float value array type'; + } + + public function isValid($value) + { + if(!is_array($value)) + return false; + + foreach($value as $key => $value) { + if( filter_var($key, FILTER_VALIDATE_FLOAT) === false || filter_var($value, FILTER_VALIDATE_FLOAT) === false ) { + return false; + } + } + + return true; + } + + public function getFormattedValue($value) + { + return $this->isValid($value) ? $value : null; + } +} diff --git a/core/lib/Thelia/Type/ModelType.php b/core/lib/Thelia/Type/ModelType.php new file mode 100755 index 000000000..38df857e4 --- /dev/null +++ b/core/lib/Thelia/Type/ModelType.php @@ -0,0 +1,66 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +use Propel\Runtime\ActiveRecord\ActiveRecordInterface; +use Thelia\Exception\TypeException; + +/** + * + * @author Etienne Roudeix + * + */ +class ModelType implements TypeInterface +{ + protected $expectedModelActiveRecord = null; + + /** + * @param $expectedModelActiveRecord + * @throws TypeException + */ + public function __construct($expectedModelActiveRecord) + { + $class = '\\Thelia\\Model\\' . $expectedModelActiveRecord; + + if(!(class_exists($class) && new $class instanceof ActiveRecordInterface)) { + throw new TypeException('MODEL NOT FOUND', TypeException::MODEL_NOT_FOUND); + } + + $this->expectedModelActiveRecord = $class; + } + + public function getType() + { + return 'Model type'; + } + + public function isValid($value) + { + return $value instanceof $this->expectedModelActiveRecord; + } + + public function getFormattedValue($value) + { + return $this->isValid($value) ? $value : null; + } +} diff --git a/install/insert.sql b/install/insert.sql index 4ef9de276..253b6cb30 100755 --- a/install/insert.sql +++ b/install/insert.sql @@ -17,9 +17,10 @@ INSERT INTO `config` (`name`, `value`, `secured`, `hidden`, `created_at`, `updat ('image_cache_dir_from_web_root', 'cache/images', 0, 0, NOW(), NOW()), ('currency_rate_update_url', 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml', 0, 0, NOW(), NOW()), ('page_not_found_view', '404.html', 0, 0, NOW(), NOW()), -('use_tax_free_amounts', '1', 0, 0, NOW(), NOW()); +('use_tax_free_amounts', 0, 1, 0, NOW(), NOW()), ('process_assets', '1', 0, 0, NOW(), NOW()); + INSERT INTO `module` (`id`, `code`, `type`, `activate`, `position`, `full_namespace`, `created_at`, `updated_at`) VALUES (1, 'DebugBar', 1, 1, 1, 'DebugBar\\DebugBar', NOW(), NOW()); @@ -1112,9 +1113,9 @@ INSERT INTO `country_i18n` (`id`, `locale`, `title`, `description`, `chapo`, `po (268, 'es_ES', 'USA - Alabama', '', '', ''), (268, 'fr_FR', 'USA - Alabama', '', '', ''); -INSERT INTO `tax` (`id`, `rate`, `created_at`, `updated_at`) +INSERT INTO `tax` (`id`, `type`, `serialized_requirements`, `created_at`, `updated_at`) VALUES - (1, '19.6', NOW(), NOW()); + (1, 'PricePercentTaxType', 'eyJwZXJjZW50IjoxOS42fQ==', NOW(), NOW()); INSERT INTO `tax_i18n` (`id`, `locale`, `title`) VALUES diff --git a/install/thelia.sql b/install/thelia.sql index 0346ffba8..e4e5fb6b7 100755 --- a/install/thelia.sql +++ b/install/thelia.sql @@ -111,7 +111,8 @@ DROP TABLE IF EXISTS `tax`; CREATE TABLE `tax` ( `id` INTEGER NOT NULL AUTO_INCREMENT, - `rate` FLOAT NOT NULL, + `type` VARCHAR(255) NOT NULL, + `serialized_requirements` TEXT NOT NULL, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) diff --git a/local/config/schema.xml b/local/config/schema.xml index afb7b2c41..7590da1e4 100755 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -86,7 +86,8 @@ - + + diff --git a/run_casperjs.sh b/run_casperjs.sh new file mode 100755 index 000000000..88636a9d1 --- /dev/null +++ b/run_casperjs.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# @author Guillaume MOREL + +echo "Force dropping database. All data will be lost." + +cd local/config/ + +echo -e "\n\e[01;34m[INFO] Building Models file\e[00m\n" +../../bin/propel build -v --output-dir=../../core/lib/ + +echo -e "\n\e[01;34m[INFO] Building SQL CREATE file\e[00m\n" +../../bin/propel sql:build -v --output-dir=../../install/ + +echo -e "\n\e[01;34m[INFO] Reloaded Thelia2 database\e[00m\n" +cd ../.. +rm install/sqldb.map +php Thelia thelia:dev:reloadDB + +echo -e "\n\e[01;34m[INFO] Installing fixtures\e[00m\n" +php install/faker.php + +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 + +casperjs test ./tests/functionnal/casperjs/exe --pre=./tests/functionnal/casperjs/conf/local.js --direct diff --git a/templates/admin/default/assets/img/ajax-loader.gif b/templates/admin/default/assets/img/ajax-loader.gif index 1321dd374..948fa9bdb 100644 Binary files a/templates/admin/default/assets/img/ajax-loader.gif and b/templates/admin/default/assets/img/ajax-loader.gif differ diff --git a/templates/admin/default/assets/js/coupon.js b/templates/admin/default/assets/js/coupon.js new file mode 100644 index 000000000..5c52aa097 --- /dev/null +++ b/templates/admin/default/assets/js/coupon.js @@ -0,0 +1,148 @@ +$(function($){ + + // Clean array from deleteValue (undefined) keys + Array.prototype.clean = function(deleteValue) { + for (var i = 0; i < this.length; i++) { + if (this[i] == deleteValue) { + this.splice(i, 1); + i--; + } + } + return this; + }; + + // Remove 1 Rule then Save Rules AJAX + couponManager.removeRuleAjax = function(id) { + // Delete rule in temporary array + delete couponManager.rulesToSave[id]; + couponManager.rulesToSave.clean(undefined); + + // Save + couponManager.saveRuleAjax(); + }; + + // Add 1 Rule / or update the temporary Rules array then Save Rules via AJAX + couponManager.addRuleAjax = function(id) { + console.log('addRuleAjax '+ id); + // 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; + } + + // Save + couponManager.saveRuleAjax(); + }; + + // 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]; + + // Set the rule selector + $("#category-rule option").filter(function() { + return $(this).val() == couponManager.ruleToUpdate.serviceId; + }).prop('selected', true); + + // Force rule input refresh + couponManager.loadRuleInputs(couponManager.ruleToUpdate.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) { + // Setting idName operator select + operatorId = idName + '-operator'; + $('#' + operatorId).val(couponManager.ruleToUpdate.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; + } + }; + + // Save rules on click + couponManager.onClickSaveRule = function() { + $('#constraint-save-btn').on('click', function () { + couponManager.addRuleAjax(couponManager.ruleIdToUpdate); + }); + }; + couponManager.onClickSaveRule(); + + // Remove rule on click + couponManager.onClickDeleteRule = function() { + $('.constraint-delete-btn').on('click', function (e) { + e.preventDefault(); + var $this = $(this); + couponManager.removeRuleAjax($this.attr('data-int')); + }); + }; + couponManager.onClickDeleteRule(); + + // Update rule on click + couponManager.onClickUpdateRule = function() { + $('.constraint-update-btn').on('click', function (e) { + e.preventDefault(); + var $this = $(this); + couponManager.updateRuleAjax($this.attr('data-int')); + + // Hide row being updated + $this.parent().parent().remove(); + }); + }; + couponManager.onClickUpdateRule(); + + // Reload effect inputs when changing effect + couponManager.onEffectChange = function() { + $('#effect').on('change', function () { + var optionSelected = $("option:selected", this); + $('#effectToolTip').html(optionSelected.attr("data-description")); + }); + }; + couponManager.onEffectChange(); + + // Reload rule inputs when changing effect + couponManager.onRuleChange = function() { + $('#category-rule').on('change', function () { + couponManager.loadRuleInputs($(this).val(), function(ruleToSave) {}); + }); + }; + couponManager.onRuleChange(); + + // Fill in ready to be saved rule array + // var onInputsChange = function() + // In AJAX response + +}); + +// Rule to save + +var couponManager = {}; +couponManager.ruleToSave = {}; +couponManager.ruleIdToUpdate = false; \ No newline at end of file diff --git a/templates/admin/default/assets/less/thelia/thelia.less b/templates/admin/default/assets/less/thelia/thelia.less index 8576272bf..ee85c7510 100644 --- a/templates/admin/default/assets/less/thelia/thelia.less +++ b/templates/admin/default/assets/less/thelia/thelia.less @@ -251,6 +251,6 @@ .loading{ background: url("@{imgDir}/ajax-loader.gif") no-repeat; - height: 24px; - width: 24px; + height: 30px; + width: 30px; } \ No newline at end of file diff --git a/templates/admin/default/coupon-create.html b/templates/admin/default/coupon-create.html index 7cb31ee09..e8fcb73f5 100755 --- a/templates/admin/default/coupon-create.html +++ b/templates/admin/default/coupon-create.html @@ -16,7 +16,7 @@ {form name="thelia.admin.coupon.creation"} - {include file='coupon/form.html' formAction={url path={$formAction}}} + {include file='coupon/form.html' formAction={url path={$formAction}} noRules=true} {/form} diff --git a/templates/admin/default/coupon-update.html b/templates/admin/default/coupon-update.html index 9b6387cd7..16771539a 100755 --- a/templates/admin/default/coupon-update.html +++ b/templates/admin/default/coupon-update.html @@ -16,9 +16,10 @@ {form name="thelia.admin.coupon.creation"} - {include file='coupon/form.html' formAction={url path={$formAction}} form=$form} + {include file='coupon/form.html' formAction={url path={$formAction}} form=$form noRules=false} {/form} + {/block} @@ -37,19 +38,19 @@ {/javascripts} + {javascripts file='assets/js/coupon.js'} + + {/javascripts} + {/block} diff --git a/templates/admin/default/coupon/form.html b/templates/admin/default/coupon/form.html index e22136d41..5d30d201d 100644 --- a/templates/admin/default/coupon/form.html +++ b/templates/admin/default/coupon/form.html @@ -161,134 +161,122 @@ - -
-
-
- - - - - - - - - {include file='coupon/rules.html' rules=$rulesObject} - {*{foreach from=$rulesObject item=rule name=rulesForeach}*} - {**} - {**} - - {**} - {**} - {*{/foreach}*} - -
- {intl l='Rules'} -
{intl l='Conditions'}{intl l='Actions'}
*} - {*{if !$smarty.foreach.rulesForeach.first}*} - {*{intl l='And'}*} - {*{/if}*} - {*{$rule.tooltip nofilter}*} - {**} - {* {intl l='Edit'}*} - {* {intl l='Delete'}*} - {*
- - - -
-
- - - - -
- - - + {if $noRules} + {include file='includes/notifications.html' message={intl l='Please save your Coupon in oder to affect it some application fields'}} + {else} +
+
+ + + + + + + + + + {include file='coupon/rules.html' rules=$rules} + +
+ {intl l='Rules'} +
{intl l='Conditions'}{intl l='Actions'}
+
-
- - +
+
+ + + + +
+ + + +
+ +
+ + +
+ +
+ {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {**} + {*
*} + {*
*} + {**} + + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {**} + {*
*} + {*
*} + + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {*
*} + {*
*} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {*
Categories list
*} + {*
*} + {*
*} +
- -
- {**} - {*
*} - {*
*} - {**} - {*
*} - {*
*} - {**} - {**} - {*
*} - {*
*} - {**} - - {**} - {*
*} - {*
*} - {**} - {*
*} - {*
*} - {**} - {**} - {*
*} - {*
*} - - {**} - {*
*} - {*
*} - {**} - {*
*} - {*
*} - {**} - {*
*} - {*
*} - {*
*} - {*
*} - {**} - {**} - {**} - {**} - {**} - {**} - {**} - {**} - {**} - {**} - {*
Categories list
*} - {*
*} - {*
*} -
-
-
+ + {/if} diff --git a/templates/admin/default/coupon/rule-input-ajax.html b/templates/admin/default/coupon/rule-input-ajax.html index cf921932b..cdf683d21 100644 --- a/templates/admin/default/coupon/rule-input-ajax.html +++ b/templates/admin/default/coupon/rule-input-ajax.html @@ -1,4 +1,3 @@ -{*{$inputs.inputs|var_dump}*} {foreach from=$inputs.inputs key=name item=input}
@@ -71,32 +70,33 @@ {*
*} \ No newline at end of file diff --git a/templates/admin/default/coupon/rules.html b/templates/admin/default/coupon/rules.html index 8dca66c49..199ee44c3 100644 --- a/templates/admin/default/coupon/rules.html +++ b/templates/admin/default/coupon/rules.html @@ -1,4 +1,4 @@ -{foreach from=$rules item=rule name=rulesForeach} +{foreach from=$rules item=rule key=i name=rulesForeach} {if !$smarty.foreach.rulesForeach.first} @@ -7,10 +7,10 @@ {$rule nofilter} - + {intl l='Edit'} - + {intl l='Delete'} diff --git a/templates/admin/default/login.html b/templates/admin/default/login.html index bddc9fb08..07e238c88 100755 --- a/templates/admin/default/login.html +++ b/templates/admin/default/login.html @@ -28,13 +28,13 @@ {form_field form=$form field='username'} - + {/form_field} {form_field form=$form field='password'} - + {/form_field} diff --git a/templates/admin/default/orders.html b/templates/admin/default/orders.html new file mode 100644 index 000000000..8693f2a33 --- /dev/null +++ b/templates/admin/default/orders.html @@ -0,0 +1,159 @@ +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Orders'}{/block} + +{block name="check-permissions"}admin.orders.view{/block} + +{block name="main-content"} +
+ +
+ + + + {module_include location='orders_top'} + +
+
+
+
+ + + + + + + + + + + + {module_include location='orders_table_header'} + + + + + + + + + + + + + + + + {module_include location='orders_table_row'} + + + + + + + + + + + + + {module_include location='orders_table_row'} + + + + + + + + + + + + + {module_include location='orders_table_row'} + + + + + + + +
+ {intl l='Orders'} + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.orders.create"} + + + + {/loop} +
{intl l="Order n°"}{intl l="Date & Hour"}{intl l="Compagny"}{intl l="Name"}{intl l="Amount"}{intl l="Status"}{intl l="Actions"}
0123045012304511/09/2013 10:24:31TheliaDupont251 €Paid +
+ + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} + + {/loop} + + {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} + + {/loop} +
+
0123045012304511/09/2013 10:24:31TheliaDupont251 €Canceled +
+ + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} + + {/loop} + + {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} + + {/loop} +
+
0123045012304511/09/2013 10:24:31TheliaDupont251 €Current +
+ + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"} + + {/loop} + + {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"} + + {/loop} +
+
+
+
+
+
+ + {module_include location='orders_bottom'} + +
+
+ +{* Delete order confirmation dialog *} + +{capture "delete_order_dialog"} + + +{/capture} + +{include + file = "includes/generic-confirm-dialog.html" + + dialog_id = "delete_order_dialog" + dialog_title = {intl l="Delete an order"} + dialog_message = {intl l="Do you really want to delete this order ?"} + + form_action = {url path='/admin/orders/delete'} + form_content = {$smarty.capture.delete_order_dialog nofilter} +} + +{/block} \ No newline at end of file diff --git a/templates/default_save/category.html b/templates/default_save/category.html index 2e216d0c0..0a8e04460 100755 --- a/templates/default_save/category.html +++ b/templates/default_save/category.html @@ -1,9 +1,3 @@ - - - {debugbar_renderHead} - - -

Category page

@@ -148,8 +142,4 @@ {/loop} -
- - {debugbar_render} - - \ No newline at end of file + \ No newline at end of file diff --git a/templates/default_save/product.html b/templates/default_save/product.html index 441585aba..cde8b61eb 100755 --- a/templates/default_save/product.html +++ b/templates/default_save/product.html @@ -8,7 +8,7 @@ Index : {navigate to="index"}
{ifloop rel="product"} -{loop type="product" name="product" current="true" min_price="50" max_price="100"} +{loop type="product" name="product" current="true"}

PRODUCT ({$ID}) : {$REF}

diff --git a/tests/functionnal/casperjs/conf/local.js b/tests/functionnal/casperjs/conf/local.js new file mode 100644 index 000000000..9fa930598 --- /dev/null +++ b/tests/functionnal/casperjs/conf/local.js @@ -0,0 +1,3 @@ +//LOCAL = ton pc +var thelia2_base_url = 'http://www.thelia2.dev/index_dev.php/'; +casper.test.done(0); diff --git a/tests/functionnal/casperjs/exe/00_parameters.js b/tests/functionnal/casperjs/exe/00_parameters.js new file mode 100644 index 000000000..a32ee89b5 --- /dev/null +++ b/tests/functionnal/casperjs/exe/00_parameters.js @@ -0,0 +1,17 @@ + +casper.test.comment('Please edit 00_parameters.js to add your configuration'); + +var thelia2_login_admin_url = thelia2_base_url + 'admin/login'; +var thelia2_login_coupon_list_url = thelia2_base_url + 'admin/login'; +var thelia2_login_coupon_create_url = thelia2_base_url + 'admin/coupon/create'; +var thelia2_login_coupon_read_url = thelia2_base_url + 'admin/coupon/read/1'; +var thelia2_login_coupon_update_url = thelia2_base_url + 'admin/coupon/update/1'; + + + +//var findMyId = /([0-9]+)$/; +//var currentId; + +casper.test.comment('Variables are set'); + +casper.test.done(0); diff --git a/tests/functionnal/casperjs/exe/10_login.js b/tests/functionnal/casperjs/exe/10_login.js new file mode 100644 index 000000000..81757168d --- /dev/null +++ b/tests/functionnal/casperjs/exe/10_login.js @@ -0,0 +1,27 @@ +casper.test.comment('Testing login'); + +casper.start(thelia2_login_admin_url, function() { + this.echo('\nLOGIN'); + this.test.assertTitle('Welcome - Thelia Back Office', 'Web page title OK'); + this.sendKeys('input#username', 'thelia2'); + this.sendKeys('input#password', 'thelia2'); + this.click('form[action*="checklogin"] button[type="submit"]'); +}); + +casper.wait(1000, function() { + this.echo("\nWaiting...."); +}); + +casper.then(function(){ + this.echo('\nDASHBOARD'); + + console.log('Now on : ' + this.getCurrentUrl()); + // @todo implement dashboard +// this.test.assertTitle('Back-office home - Thelia Back Office', 'Web page title OK'); +// this.test.assertSelectorHasText('#wrapper > div', ' This is the administration home page. Put some interesting statistics here, and display useful information :) ', 'Web page main content OK'); +}); + +//RUN +casper.run(function() { + this.test.done(); +}); \ No newline at end of file diff --git a/tests/functionnal/casperjs/exe/30_coupons.js b/tests/functionnal/casperjs/exe/30_coupons.js new file mode 100644 index 000000000..6031d71f8 --- /dev/null +++ b/tests/functionnal/casperjs/exe/30_coupons.js @@ -0,0 +1,46 @@ +casper.test.comment('Testing coupons'); + + +////LIST +// @todo implement + +////CREATE +// @todo implement + +//UPDATE COUPON RULE +casper.start(thelia2_login_coupon_update_url, function() { + console.log('Now on : ' + this.getCurrentUrl()); + this.echo('\nCOUPON RULE - EDIT'); + this.test.assertTitle('Update coupon - Thelia Back Office', 'Web page title OK'); +// this.test.assertSelectorHasText('#content-header > h1', 'Liste des pays', 'Web page main content OK'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(1)', 'If cart total amount is superior to 40 EUR','1st default rule found'); + this.test.assertSelectorHasText('tbody#constraint-list tr:nth-child(2)', 'If cart total amount is inferior to 400 EUR','2nd default rule found'); + + // Create rule + this.evaluate(function() { +// document.querySelector('select#category-rule').selectedItem = 'thelia.constraint.rule.available_for_x_articles'; + $('#category-rule').val('thelia.constraint.rule.available_for_x_articles').change(); + return true; + }); + this.capture('tests/functionnal/casperjs/pictures/screenshot-category-rule.png'); +// this.click('constraint-list > tr:last-child > td > a.constraint-update-btn'); +}); + +casper.wait(1000, function() { + this.echo("\nWaiting...."); +}); + +casper.then(function(){ + +}); + +////EDIT CHECK +// @todo implement + +////DELETE +// @todo implement + +//RUN +casper.run(function() { + this.test.done(); +}); \ No newline at end of file