Merge branch 'master' of github.com:thelia/thelia

This commit is contained in:
Manuel Raynaud
2013-09-11 17:24:46 +02:00
43 changed files with 1434 additions and 828 deletions

View File

@@ -24,6 +24,7 @@
namespace Thelia\Action; namespace Thelia\Action;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Constraint\ConstraintFactory;
use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent;
use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Event\TheliaEvents;
use Thelia\Model\Coupon as CouponModel; use Thelia\Model\Coupon as CouponModel;
@@ -65,18 +66,6 @@ class Coupon extends BaseAction implements EventSubscriberInterface
$this->createOrUpdate($coupon, $event); $this->createOrUpdate($coupon, $event);
} }
/**
* Occurring when a Coupon rule is about to be created
*
* @param CouponCreateOrUpdateEvent $event Event creation or update Event
*/
public function createRule(CouponCreateOrUpdateEvent $event)
{
$coupon = $event->getCoupon();
$this->createOrUpdate($coupon, $event);
}
/** /**
* Occurring when a Coupon rule is about to be updated * Occurring when a Coupon rule is about to be updated
* *
@@ -86,19 +75,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface
{ {
$coupon = $event->getCoupon(); $coupon = $event->getCoupon();
$this->createOrUpdate($coupon, $event); $this->createOrUpdateRule($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);
} }
/** /**
@@ -127,6 +104,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface
$event->getTitle(), $event->getTitle(),
$event->getAmount(), $event->getAmount(),
$event->getEffect(), $event->getEffect(),
$event->isRemovingPostage(),
$event->getShortDescription(), $event->getShortDescription(),
$event->getDescription(), $event->getDescription(),
$event->isEnabled(), $event->isEnabled(),
@@ -134,7 +112,28 @@ class Coupon extends BaseAction implements EventSubscriberInterface
$event->isAvailableOnSpecialOffers(), $event->isAvailableOnSpecialOffers(),
$event->isCumulative(), $event->isCumulative(),
$event->getMaxUsage(), $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() $event->getLocale()
); );
@@ -169,8 +168,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface
TheliaEvents::COUPON_DISABLE => array("disable", 128), TheliaEvents::COUPON_DISABLE => array("disable", 128),
TheliaEvents::COUPON_ENABLE => array("enable", 128), TheliaEvents::COUPON_ENABLE => array("enable", 128),
TheliaEvents::COUPON_CONSUME => array("consume", 128), TheliaEvents::COUPON_CONSUME => array("consume", 128),
TheliaEvents::COUPON_RULE_UPDATE => array("updateRule", 128), TheliaEvents::COUPON_RULE_UPDATE => array("updateRule", 128)
TheliaEvents::COUPON_RULE_DELETE => array("deleteRule", 128)
); );
} }
} }

View File

@@ -44,6 +44,14 @@
<!-- end Customer rule management --> <!-- end Customer rule management -->
<!-- Order rule management -->
<route id="admin.order" path="/admin/order">
<default key="_controller">Thelia\Controller\Admin\OrderController::indexAction</default>
</route>
<!-- end Customer rule management -->
<!-- Categories management --> <!-- Categories management -->
<route id="admin.categories.default" path="/admin/categories"> <route id="admin.categories.default" path="/admin/categories">

View File

@@ -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 * Check validators relevancy and store them
* *
@@ -249,49 +185,6 @@ class AvailableForTotalAmountManager extends CouponRuleAbstract
return false; 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 * 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;
// }
} }

View File

@@ -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 * 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( throw new \InvalidArgumentException(
'Value for quantity field is not legit' 'Value for quantity field is not legit'
); );
@@ -210,26 +139,6 @@ class AvailableForXArticlesManager extends CouponRuleAbstract
return false; 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 * Get I18n name
* *
@@ -267,36 +176,6 @@ class AvailableForXArticlesManager extends CouponRuleAbstract
return $toolTip; return $toolTip;
} }
// /**
// * Populate a Rule from a form admin
// *
// * @param array $operators Rule Operator set by the Admin
// * @param array $values Rule Values set by the Admin
// *
// * @throws InvalidArgumentException
// * @return $this
// */
// public function populateFromForm(array $operators, array $values)
// {
// if ($values[self::PARAM1_QUANTITY] === null) {
// throw new InvalidArgumentException(
// 'The Rule ' . get_class() . 'needs at least a quantity set (' . self::PARAM1_QUANTITY. ')'
// );
// }
//
// $this->quantityValidator = new 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 * Generate inputs ready to be drawn
* *

View File

@@ -26,12 +26,17 @@ namespace Thelia\Controller\Admin;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Router; use Symfony\Component\Routing\Router;
use Thelia\Constraint\ConstraintFactory; use Thelia\Constraint\ConstraintFactory;
use Thelia\Constraint\ConstraintFactoryTest;
use Thelia\Constraint\Rule\AvailableForTotalAmount; use Thelia\Constraint\Rule\AvailableForTotalAmount;
use Thelia\Constraint\Rule\CouponRuleInterface; use Thelia\Constraint\Rule\CouponRuleInterface;
use Thelia\Constraint\Validator\PriceParam; use Thelia\Constraint\Validator\PriceParam;
use Thelia\Core\Event\Coupon\CouponCreateEvent;
use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent;
use Thelia\Core\Event\Coupon\CouponEvent; use Thelia\Core\Event\Coupon\CouponEvent;
use Thelia\Core\Event\TheliaEvents; 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\Core\Translation\Translator;
use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponAdapterInterface;
use Thelia\Coupon\CouponManager; use Thelia\Coupon\CouponManager;
@@ -153,6 +158,13 @@ class CouponController extends BaseAdminController
); );
} else { } else {
// Prepare the data that will hydrate the form // 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( $data = array(
'code' => $coupon->getCode(), 'code' => $coupon->getCode(),
'title' => $coupon->getTitle(), 'title' => $coupon->getTitle(),
@@ -166,18 +178,12 @@ class CouponController extends BaseAdminController
'isCumulative' => ($coupon->getIsCumulative() == 1), 'isCumulative' => ($coupon->getIsCumulative() == 1),
'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1),
'maxUsage' => $coupon->getMaxUsage(), 'maxUsage' => $coupon->getMaxUsage(),
'rules' => new CouponRuleCollection(array()), 'rules' => $rules,
'locale' => $coupon->getLocale(), 'locale' => $coupon->getLocale(),
); );
$args['rulesObject'] = array(); $args['rulesObject'] = array();
/** @var ConstraintFactory $constraintFactory */
$constraintFactory = $this->container->get('thelia.constraint.factory');
$rules = $constraintFactory->unserializeCouponRuleCollection(
$coupon->getSerializedRules()
);
/** @var CouponRuleInterface $rule */ /** @var CouponRuleInterface $rule */
foreach ($rules->getRules() as $rule) { foreach ($rules->getRules() as $rule) {
$args['rulesObject'][] = array( $args['rulesObject'][] = array(
@@ -188,6 +194,8 @@ class CouponController extends BaseAdminController
); );
} }
$args['rules'] = $this->cleanRuleForTemplate($rules);
// Setup the object form // Setup the object form
$changeForm = new CouponCreationForm($this->getRequest(), 'form', $data); $changeForm = new CouponCreationForm($this->getRequest(), 'form', $data);
@@ -211,99 +219,103 @@ class CouponController extends BaseAdminController
$args['formAction'] = 'admin/coupon/update/' . $couponId; $args['formAction'] = 'admin/coupon/update/' . $couponId;
return $this->render( return $this->render('coupon-update', $args);
'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()); // $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 * Manage Coupons read display
@@ -367,6 +379,7 @@ class CouponController extends BaseAdminController
); );
} }
/** /**
* Manage Coupons read display * Manage Coupons read display
* *
@@ -404,7 +417,6 @@ class CouponController extends BaseAdminController
$constraintFactory = $this->container->get('thelia.constraint.factory'); $constraintFactory = $this->container->get('thelia.constraint.factory');
$rulesReceived = json_decode($this->getRequest()->get('rules')); $rulesReceived = json_decode($this->getRequest()->get('rules'));
foreach ($rulesReceived as $ruleReceived) { foreach ($rulesReceived as $ruleReceived) {
var_dump('building ', $ruleReceived->values);
$rule = $constraintFactory->build( $rule = $constraintFactory->build(
$ruleReceived->serviceId, $ruleReceived->serviceId,
(array) $ruleReceived->operators, (array) $ruleReceived->operators,
@@ -433,6 +445,7 @@ class CouponController extends BaseAdminController
$rules, $rules,
$coupon->getLocale() $coupon->getLocale()
); );
$couponEvent->setCoupon($coupon);
$eventToDispatch = TheliaEvents::COUPON_RULE_UPDATE; $eventToDispatch = TheliaEvents::COUPON_RULE_UPDATE;
// Dispatch Event to the Action // Dispatch Event to the Action
@@ -688,4 +701,6 @@ class CouponController extends BaseAdminController
// } // }
// } // }
} }

View File

@@ -0,0 +1,39 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Controller\Admin;
/**
* Class OrderController
* @package Thelia\Controller\Admin
* @author Manuel Raynaud <mraynaud@openstudio.fr>
*/
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));
}
}

View File

@@ -294,21 +294,6 @@ final class TheliaEvents
*/ */
const AFTER_COUPON_RULE_UPDATE = "action.after_update_coupon_rule"; const AFTER_COUPON_RULE_UPDATE = "action.after_update_coupon_rule";
/**
* Sent when attempting to delete Coupon Rule
*/
const COUPON_RULE_DELETE = "action.delete_coupon_rule";
/**
* Sent just before an attempt to delete a Coupon Rule
*/
const BEFORE_COUPON_RULE_DELETE = "action.before_delete_coupon_rule";
/**
* Sent just after an attempt to delete a Coupon Rule
*/
const AFTER_COUPON_RULE_DELETE = "action.after_delete_coupon_rule";
// -- Configuration management --------------------------------------------- // -- Configuration management ---------------------------------------------
const CONFIG_CREATE = "action.createConfig"; const CONFIG_CREATE = "action.createConfig";
@@ -358,4 +343,5 @@ final class TheliaEvents
const BEFORE_DELETECURRENCY = "action.before_deleteCurrency"; const BEFORE_DELETECURRENCY = "action.before_deleteCurrency";
const AFTER_DELETECURRENCY = "action.after_deleteCurrency"; const AFTER_DELETECURRENCY = "action.after_deleteCurrency";
} }

View File

@@ -83,7 +83,7 @@ class Thelia extends Kernel
$con = Propel::getConnection(\Thelia\Model\Map\ProductTableMap::DATABASE_NAME); $con = Propel::getConnection(\Thelia\Model\Map\ProductTableMap::DATABASE_NAME);
$con->setAttribute(ConnectionWrapper::PROPEL_ATTR_CACHE_PREPARES, true); $con->setAttribute(ConnectionWrapper::PROPEL_ATTR_CACHE_PREPARES, true);
if ($this->isDebug()) { if ($this->isDebug()) {
//$serviceContainer->setLogger('defaultLogger', \Thelia\Log\Tlog::getInstance()); $serviceContainer->setLogger('defaultLogger', \Thelia\Log\Tlog::getInstance());
$con->useDebug(true); $con->useDebug(true);
} }
} }

View File

@@ -27,9 +27,18 @@ class TaxEngineException extends \RuntimeException
{ {
const UNKNOWN_EXCEPTION = 0; 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_PRODUCT = 501;
const UNDEFINED_COUNTRY = 502; const UNDEFINED_COUNTRY = 502;
const UNDEFINED_TAX_RULES_COLLECTION = 503; const UNDEFINED_TAX_RULES_COLLECTION = 503;
const UNDEFINED_REQUIREMENTS = 504;
const UNDEFINED_REQUIREMENT_VALUE = 505;
const BAD_AMOUNT_FORMAT = 601; const BAD_AMOUNT_FORMAT = 601;

View File

@@ -0,0 +1,39 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\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);
}
}

View File

@@ -66,10 +66,16 @@ abstract class Tax implements ActiveRecordInterface
protected $id; protected $id;
/** /**
* The value for the rate field. * The value for the type field.
* @var double * @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. * 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() } // 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) * @return \Thelia\Model\Tax The current object (for fluent API support)
*/ */
public function setRate($v) public function setType($v)
{ {
if ($v !== null) { if ($v !== null) {
$v = (double) $v; $v = (string) $v;
} }
if ($this->rate !== $v) { if ($this->type !== $v) {
$this->rate = $v; $this->type = $v;
$this->modifiedColumns[] = TaxTableMap::RATE; $this->modifiedColumns[] = TaxTableMap::TYPE;
} }
return $this; 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. * 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)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : TaxTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)];
$this->id = (null !== $col) ? (int) $col : null; $this->id = (null !== $col) ? (int) $col : null;
$col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxTableMap::translateFieldName('Rate', TableMap::TYPE_PHPNAME, $indexType)]; $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxTableMap::translateFieldName('Type', TableMap::TYPE_PHPNAME, $indexType)];
$this->rate = (null !== $col) ? (double) $col : null; $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') { if ($col === '0000-00-00 00:00:00') {
$col = null; $col = null;
} }
$this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : 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') { if ($col === '0000-00-00 00:00:00') {
$col = null; $col = null;
} }
@@ -591,7 +632,7 @@ abstract class Tax implements ActiveRecordInterface
$this->ensureConsistency(); $this->ensureConsistency();
} }
return $startcol + 4; // 4 = TaxTableMap::NUM_HYDRATE_COLUMNS. return $startcol + 5; // 5 = TaxTableMap::NUM_HYDRATE_COLUMNS.
} catch (Exception $e) { } catch (Exception $e) {
throw new PropelException("Error populating \Thelia\Model\Tax object", 0, $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)) { if ($this->isColumnModified(TaxTableMap::ID)) {
$modifiedColumns[':p' . $index++] = 'ID'; $modifiedColumns[':p' . $index++] = 'ID';
} }
if ($this->isColumnModified(TaxTableMap::RATE)) { if ($this->isColumnModified(TaxTableMap::TYPE)) {
$modifiedColumns[':p' . $index++] = 'RATE'; $modifiedColumns[':p' . $index++] = 'TYPE';
}
if ($this->isColumnModified(TaxTableMap::SERIALIZED_REQUIREMENTS)) {
$modifiedColumns[':p' . $index++] = 'SERIALIZED_REQUIREMENTS';
} }
if ($this->isColumnModified(TaxTableMap::CREATED_AT)) { if ($this->isColumnModified(TaxTableMap::CREATED_AT)) {
$modifiedColumns[':p' . $index++] = 'CREATED_AT'; $modifiedColumns[':p' . $index++] = 'CREATED_AT';
@@ -875,8 +919,11 @@ abstract class Tax implements ActiveRecordInterface
case 'ID': case 'ID':
$stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT);
break; break;
case 'RATE': case 'TYPE':
$stmt->bindValue($identifier, $this->rate, PDO::PARAM_STR); $stmt->bindValue($identifier, $this->type, PDO::PARAM_STR);
break;
case 'SERIALIZED_REQUIREMENTS':
$stmt->bindValue($identifier, $this->serialized_requirements, PDO::PARAM_STR);
break; break;
case 'CREATED_AT': case 'CREATED_AT':
$stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); $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(); return $this->getId();
break; break;
case 1: case 1:
return $this->getRate(); return $this->getType();
break; break;
case 2: case 2:
return $this->getCreatedAt(); return $this->getSerializedRequirements();
break; break;
case 3: case 3:
return $this->getCreatedAt();
break;
case 4:
return $this->getUpdatedAt(); return $this->getUpdatedAt();
break; break;
default: default:
@@ -988,9 +1038,10 @@ abstract class Tax implements ActiveRecordInterface
$keys = TaxTableMap::getFieldNames($keyType); $keys = TaxTableMap::getFieldNames($keyType);
$result = array( $result = array(
$keys[0] => $this->getId(), $keys[0] => $this->getId(),
$keys[1] => $this->getRate(), $keys[1] => $this->getType(),
$keys[2] => $this->getCreatedAt(), $keys[2] => $this->getSerializedRequirements(),
$keys[3] => $this->getUpdatedAt(), $keys[3] => $this->getCreatedAt(),
$keys[4] => $this->getUpdatedAt(),
); );
$virtualColumns = $this->virtualColumns; $virtualColumns = $this->virtualColumns;
foreach($virtualColumns as $key => $virtualColumn) foreach($virtualColumns as $key => $virtualColumn)
@@ -1043,12 +1094,15 @@ abstract class Tax implements ActiveRecordInterface
$this->setId($value); $this->setId($value);
break; break;
case 1: case 1:
$this->setRate($value); $this->setType($value);
break; break;
case 2: case 2:
$this->setCreatedAt($value); $this->setSerializedRequirements($value);
break; break;
case 3: case 3:
$this->setCreatedAt($value);
break;
case 4:
$this->setUpdatedAt($value); $this->setUpdatedAt($value);
break; break;
} // switch() } // switch()
@@ -1076,9 +1130,10 @@ abstract class Tax implements ActiveRecordInterface
$keys = TaxTableMap::getFieldNames($keyType); $keys = TaxTableMap::getFieldNames($keyType);
if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); 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[1], $arr)) $this->setType($arr[$keys[1]]);
if (array_key_exists($keys[2], $arr)) $this->setCreatedAt($arr[$keys[2]]); if (array_key_exists($keys[2], $arr)) $this->setSerializedRequirements($arr[$keys[2]]);
if (array_key_exists($keys[3], $arr)) $this->setUpdatedAt($arr[$keys[3]]); 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); $criteria = new Criteria(TaxTableMap::DATABASE_NAME);
if ($this->isColumnModified(TaxTableMap::ID)) $criteria->add(TaxTableMap::ID, $this->id); 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::CREATED_AT)) $criteria->add(TaxTableMap::CREATED_AT, $this->created_at);
if ($this->isColumnModified(TaxTableMap::UPDATED_AT)) $criteria->add(TaxTableMap::UPDATED_AT, $this->updated_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) 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->setCreatedAt($this->getCreatedAt());
$copyObj->setUpdatedAt($this->getUpdatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt());
@@ -1729,7 +1786,8 @@ abstract class Tax implements ActiveRecordInterface
public function clear() public function clear()
{ {
$this->id = null; $this->id = null;
$this->rate = null; $this->type = null;
$this->serialized_requirements = null;
$this->created_at = null; $this->created_at = null;
$this->updated_at = null; $this->updated_at = null;
$this->alreadyInSave = false; $this->alreadyInSave = false;

View File

@@ -23,12 +23,14 @@ use Thelia\Model\Map\TaxTableMap;
* *
* *
* @method ChildTaxQuery orderById($order = Criteria::ASC) Order by the id column * @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 orderByCreatedAt($order = Criteria::ASC) Order by the created_at column
* @method ChildTaxQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * @method ChildTaxQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column
* *
* @method ChildTaxQuery groupById() Group by the id 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 groupByCreatedAt() Group by the created_at column
* @method ChildTaxQuery groupByUpdatedAt() Group by the updated_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 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 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 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 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 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 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 * @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) 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 { try {
$stmt = $con->prepare($sql); $stmt = $con->prepare($sql);
$stmt->bindValue(':p0', $key, PDO::PARAM_INT); $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: * Example usage:
* <code> * <code>
* $query->filterByRate(1234); // WHERE rate = 1234 * $query->filterByType('fooValue'); // WHERE type = 'fooValue'
* $query->filterByRate(array(12, 34)); // WHERE rate IN (12, 34) * $query->filterByType('%fooValue%'); // WHERE type LIKE '%fooValue%'
* $query->filterByRate(array('min' => 12)); // WHERE rate > 12
* </code> * </code>
* *
* @param mixed $rate The value to use as filter. * @param string $type The value to use as filter.
* Use scalar values for equality. * Accepts wildcards (* and % trigger a LIKE)
* Use array values for in_array() equivalent.
* Use associative array('min' => $minValue, 'max' => $maxValue) for intervals.
* @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL
* *
* @return ChildTaxQuery The current query, for fluid interface * @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)) { if (null === $comparison) {
$useMinMax = false; if (is_array($type)) {
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) {
$comparison = Criteria::IN; $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:
* <code>
* $query->filterBySerializedRequirements('fooValue'); // WHERE serialized_requirements = 'fooValue'
* $query->filterBySerializedRequirements('%fooValue%'); // WHERE serialized_requirements LIKE '%fooValue%'
* </code>
*
* @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);
} }
/** /**

View File

@@ -49,24 +49,25 @@ class Coupon extends BaseCoupon
/** /**
* Constructor * Create or Update this Coupon
* *
* @param string $code Coupon Code * @param string $code Coupon Code
* @param string $title Coupon title * @param string $title Coupon title
* @param float $amount Amount removed from the Total Checkout * @param float $amount Amount removed from the Total Checkout
* @param string $effect Coupon effect * @param string $effect Coupon effect
* @param string $shortDescription Coupon short description * @param bool $isRemovingPostage Is removing Postage
* @param string $description Coupon description * @param string $shortDescription Coupon short description
* @param boolean $isEnabled Enable/Disable * @param string $description Coupon description
* @param \DateTime $expirationDate Coupon expiration date * @param boolean $isEnabled Enable/Disable
* @param boolean $isAvailableOnSpecialOffers Is available on special offers * @param \DateTime $expirationDate Coupon expiration date
* @param boolean $isCumulative Is cumulative * @param boolean $isAvailableOnSpecialOffers Is available on special offers
* @param boolean $isRemovingPostage Is removing Postage * @param boolean $isCumulative Is cumulative
* @param int $maxUsage Coupon quantity * @param int $maxUsage Coupon quantity
* @param CouponRuleCollection $rules CouponRuleInterface to add * @param string $locale Coupon Language code ISO (ex: fr_FR)
* @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) $this->setCode($code)
->setTitle($title) ->setTitle($title)
@@ -74,13 +75,13 @@ class Coupon extends BaseCoupon
->setDescription($description) ->setDescription($description)
->setType($effect) ->setType($effect)
->setAmount($amount) ->setAmount($amount)
->setIsRemovingPostage($isRemovingPostage)
->setType($amount) ->setType($amount)
->setIsEnabled($isEnabled) ->setIsEnabled($isEnabled)
->setExpirationDate($expirationDate) ->setExpirationDate($expirationDate)
->setIsAvailableOnSpecialOffers($isAvailableOnSpecialOffers) ->setIsAvailableOnSpecialOffers($isAvailableOnSpecialOffers)
->setIsCumulative($isCumulative) ->setIsCumulative($isCumulative)
->setMaxUsage($maxUsage) ->setMaxUsage($maxUsage);
->setRules($rules);
// Set object language (i18n) // Set object language (i18n)
if (!is_null($locale)) { if (!is_null($locale)) {
@@ -99,33 +100,34 @@ class Coupon extends BaseCoupon
} }
} }
// /** /**
// * Set the value of [serialized_rules] column. * Create or Update this coupon rule
// * Convert a CouponRuleCollection into a serialized array of SerializableRule *
// * * @param string $serializableRules Serialized rules ready to be saved
// * @param CouponRuleCollection $rules A set of Rules * @param string $locale Coupon Language code ISO (ex: fr_FR)
// * *
// * @return \Thelia\Model\Coupon The current object (for fluent API support) * @throws \Exception
// */ */
// public function setRules(CouponRuleCollection $rules) function createOrUpdateRules($serializableRules, $locale)
// { {
// $serializedRules = null; $this->setSerializedRules($serializableRules);
// if ($rules !== null) {
// /** @var $rule CouponRuleInterface */ // Set object language (i18n)
// foreach ($rules->getRules() as $rule) { if (!is_null($locale)) {
// $serializedRules[] = $rule->getSerializableRule(); $this->setLocale($locale);
// } }
//
// $serializedRules = (string) base64_encode(serialize($serializedRules)); $con = Propel::getWriteConnection(CouponTableMap::DATABASE_NAME);
// } $con->beginTransaction();
// try {
// if ($this->serialized_rules !== $serializedRules) { $this->save($con);
// $this->serialized_rules = $serializedRules; $con->commit();
// $this->modifiedColumns[] = CouponTableMap::SERIALIZED_RULES;
// } } catch(\Exception $e) {
// $con->rollback();
// return $this; throw $e;
// } }
}

View File

@@ -57,7 +57,7 @@ class TaxTableMap extends TableMap
/** /**
* The total number of columns * The total number of columns
*/ */
const NUM_COLUMNS = 4; const NUM_COLUMNS = 5;
/** /**
* The number of lazy-loaded columns * 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) * 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 * the column name for the ID field
@@ -75,9 +75,14 @@ class TaxTableMap extends TableMap
const ID = 'tax.ID'; 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 * 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' * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id'
*/ */
protected static $fieldNames = array ( protected static $fieldNames = array (
self::TYPE_PHPNAME => array('Id', 'Rate', 'CreatedAt', 'UpdatedAt', ), self::TYPE_PHPNAME => array('Id', 'Type', 'SerializedRequirements', 'CreatedAt', 'UpdatedAt', ),
self::TYPE_STUDLYPHPNAME => array('id', 'rate', 'createdAt', 'updatedAt', ), self::TYPE_STUDLYPHPNAME => array('id', 'type', 'serializedRequirements', 'createdAt', 'updatedAt', ),
self::TYPE_COLNAME => array(TaxTableMap::ID, TaxTableMap::RATE, TaxTableMap::CREATED_AT, TaxTableMap::UPDATED_AT, ), self::TYPE_COLNAME => array(TaxTableMap::ID, TaxTableMap::TYPE, TaxTableMap::SERIALIZED_REQUIREMENTS, TaxTableMap::CREATED_AT, TaxTableMap::UPDATED_AT, ),
self::TYPE_RAW_COLNAME => array('ID', 'RATE', 'CREATED_AT', 'UPDATED_AT', ), self::TYPE_RAW_COLNAME => array('ID', 'TYPE', 'SERIALIZED_REQUIREMENTS', 'CREATED_AT', 'UPDATED_AT', ),
self::TYPE_FIELDNAME => array('id', 'rate', 'created_at', 'updated_at', ), self::TYPE_FIELDNAME => array('id', 'type', 'serialized_requirements', 'created_at', 'updated_at', ),
self::TYPE_NUM => array(0, 1, 2, 3, ) 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 * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0
*/ */
protected static $fieldKeys = array ( protected static $fieldKeys = array (
self::TYPE_PHPNAME => array('Id' => 0, 'Rate' => 1, 'CreatedAt' => 2, 'UpdatedAt' => 3, ), self::TYPE_PHPNAME => array('Id' => 0, 'Type' => 1, 'SerializedRequirements' => 2, 'CreatedAt' => 3, 'UpdatedAt' => 4, ),
self::TYPE_STUDLYPHPNAME => array('id' => 0, 'rate' => 1, 'createdAt' => 2, 'updatedAt' => 3, ), self::TYPE_STUDLYPHPNAME => array('id' => 0, 'type' => 1, 'serializedRequirements' => 2, 'createdAt' => 3, 'updatedAt' => 4, ),
self::TYPE_COLNAME => array(TaxTableMap::ID => 0, TaxTableMap::RATE => 1, TaxTableMap::CREATED_AT => 2, TaxTableMap::UPDATED_AT => 3, ), 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, 'RATE' => 1, 'CREATED_AT' => 2, 'UPDATED_AT' => 3, ), self::TYPE_RAW_COLNAME => array('ID' => 0, 'TYPE' => 1, 'SERIALIZED_REQUIREMENTS' => 2, 'CREATED_AT' => 3, 'UPDATED_AT' => 4, ),
self::TYPE_FIELDNAME => array('id' => 0, 'rate' => 1, 'created_at' => 2, 'updated_at' => 3, ), 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, ) self::TYPE_NUM => array(0, 1, 2, 3, 4, )
); );
/** /**
@@ -150,7 +155,8 @@ class TaxTableMap extends TableMap
$this->setUseIdGenerator(true); $this->setUseIdGenerator(true);
// columns // columns
$this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null); $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('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null);
$this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null);
} // initialize() } // initialize()
@@ -327,12 +333,14 @@ class TaxTableMap extends TableMap
{ {
if (null === $alias) { if (null === $alias) {
$criteria->addSelectColumn(TaxTableMap::ID); $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::CREATED_AT);
$criteria->addSelectColumn(TaxTableMap::UPDATED_AT); $criteria->addSelectColumn(TaxTableMap::UPDATED_AT);
} else { } else {
$criteria->addSelectColumn($alias . '.ID'); $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 . '.CREATED_AT');
$criteria->addSelectColumn($alias . '.UPDATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT');
} }

View File

@@ -4,6 +4,7 @@ namespace Thelia\Model;
use Thelia\Exception\TaxEngineException; use Thelia\Exception\TaxEngineException;
use Thelia\Model\Base\Tax as BaseTax; use Thelia\Model\Base\Tax as BaseTax;
use Thelia\TaxEngine\TaxType\BaseTaxType;
class Tax extends BaseTax class Tax extends BaseTax
{ {
@@ -33,14 +34,37 @@ class Tax extends BaseTax
return $taxRuleCountryPosition; return $taxRuleCountryPosition;
} }
public function getTaxRuleRateSum() public function getTypeInstance()
{ {
try { $class = '\\Thelia\\TaxEngine\\TaxType\\' . $this->getType();
$taxRuleRateSum = $this->getVirtualColumn(TaxRuleQuery::ALIAS_FOR_TAX_RATE_SUM);
} catch(PropelException $e) { /* test type */
throw new PropelException("Virtual column `" . TaxRuleQuery::ALIAS_FOR_TAX_RATE_SUM . "` does not exist in Tax::getTaxRuleRateSum"); 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;
} }
} }

View File

@@ -20,21 +20,18 @@ use Thelia\Model\Map\TaxTableMap;
class TaxRuleQuery extends BaseTaxRuleQuery class TaxRuleQuery extends BaseTaxRuleQuery
{ {
const ALIAS_FOR_TAX_RULE_COUNTRY_POSITION = 'taxRuleCountryPosition'; 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() $search = TaxQuery::create()
->filterByTaxRuleCountry( ->filterByTaxRuleCountry(
TaxRuleCountryQuery::create() TaxRuleCountryQuery::create()
->filterByCountry($country, Criteria::EQUAL) ->filterByCountry($country, Criteria::EQUAL)
->filterByTaxRuleId($product->getTaxRuleId()) ->filterByTaxRuleId($product->getTaxRuleId())
->groupByPosition()
->orderByPosition() ->orderByPosition()
->find() ->find()
) )
->withColumn(TaxRuleCountryTableMap::POSITION, self::ALIAS_FOR_TAX_RULE_COUNTRY_POSITION) ->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(); return $search->find();

View File

@@ -34,9 +34,12 @@ use Thelia\Model\TaxRuleQuery;
*/ */
class Calculator class Calculator
{ {
/**
* @var TaxRuleQuery
*/
protected $taxRuleQuery = null; protected $taxRuleQuery = null;
protected $taxRulesGroupedCollection = null; protected $taxRulesCollection = null;
protected $product = null; protected $product = null;
protected $country = null; protected $country = null;
@@ -50,7 +53,7 @@ class Calculator
{ {
$this->product = null; $this->product = null;
$this->country = null; $this->country = null;
$this->taxRulesGroupedCollection = null; $this->taxRulesCollection = null;
if($product->getId() === null) { if($product->getId() === null) {
throw new TaxEngineException('Product id is empty in Calculator::load', TaxEngineException::UNDEFINED_PRODUCT); throw new TaxEngineException('Product id is empty in Calculator::load', TaxEngineException::UNDEFINED_PRODUCT);
@@ -62,34 +65,38 @@ class Calculator
$this->product = $product; $this->product = $product;
$this->country = $country; $this->country = $country;
$this->taxRulesGroupedCollection = $this->taxRuleQuery->getTaxCalculatorGroupedCollection($product, $country); $this->taxRulesCollection = $this->taxRuleQuery->getTaxCalculatorCollection($product, $country);
return $this; 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); 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); throw new TaxEngineException('BAD AMOUNT FORMAT', TaxEngineException::BAD_AMOUNT_FORMAT);
} }
$totalTaxAmount = 0; $totalTaxAmount = 0;
foreach($this->taxRulesGroupedCollection as $taxRule) { foreach($this->taxRulesCollection as $taxRule) {
$rateSum = $taxRule->getTaxRuleRateSum(); $taxType = $taxRule->getTypeInstance();
$taxAmount = $amount * $rateSum * 0.01;
$taxType->loadRequirements($taxRule->getRequirements());
$taxAmount = $taxType->calculate($untaxedPrice);
$totalTaxAmount += $taxAmount; $totalTaxAmount += $taxAmount;
$amount += $taxAmount; $untaxedPrice += $taxAmount;
} }
return $totalTaxAmount; return $totalTaxAmount;
} }
public function getTaxedPrice($amount) public function getTaxedPrice($untaxedPrice)
{ {
return $amount + $this->getTaxAmount($amount); return $untaxedPrice + $this->getTaxAmount($untaxedPrice);
} }
} }

View File

@@ -0,0 +1,78 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\TaxEngine\TaxType;
use Thelia\Exception\TaxEngineException;
use Thelia\Type\TypeInterface;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
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];
}
}

View File

@@ -0,0 +1,47 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\TaxEngine\TaxType;
use Thelia\Type\FloatToFloatArrayType;
use Thelia\Type\ModelType;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
class featureSlicePercentTaxType extends BaseTaxType
{
public function calculate($untaxedPrice)
{
}
public function getRequirementsList()
{
return array(
'featureId' => new ModelType('Currency'),
'slices' => new FloatToFloatArrayType(),
);
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\TaxEngine\TaxType;
use Thelia\Type\FloatType;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
class PricePercentTaxType extends BaseTaxType
{
public function calculate($untaxedPrice)
{
return $untaxedPrice * $this->getRequirement("percent") * 0.01;
}
public function getRequirementsList()
{
return array(
'percent' => new FloatType(),
);
}
}

View File

@@ -83,9 +83,9 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
$calculator = new Calculator(); $calculator = new Calculator();
$taxRuleQuery = $this->getMock('\Thelia\Model\TaxRuleQuery', array('getTaxCalculatorGroupedCollection')); $taxRuleQuery = $this->getMock('\Thelia\Model\TaxRuleQuery', array('getTaxCalculatorCollection'));
$taxRuleQuery->expects($this->once()) $taxRuleQuery->expects($this->once())
->method('getTaxCalculatorGroupedCollection') ->method('getTaxCalculatorCollection')
->with($productQuery, $countryQuery) ->with($productQuery, $countryQuery)
->will($this->returnValue('foo')); ->will($this->returnValue('foo'));
@@ -104,7 +104,7 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
); );
$this->assertEquals( $this->assertEquals(
'foo', 'foo',
$this->getProperty('taxRulesGroupedCollection')->getValue($calculator) $this->getProperty('taxRulesCollection')->getValue($calculator)
); );
} }
@@ -124,35 +124,37 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetTaxAmountBadAmount() public function testGetTaxAmountBadAmount()
{ {
$taxRulesGroupedCollection = new ObjectCollection(); $taxRulesCollection = new ObjectCollection();
$calculator = new Calculator(); $calculator = new Calculator();
$rewritingUrlQuery = $this->getProperty('taxRulesGroupedCollection'); $rewritingUrlQuery = $this->getProperty('taxRulesCollection');
$rewritingUrlQuery->setValue($calculator, $taxRulesGroupedCollection); $rewritingUrlQuery->setValue($calculator, $taxRulesCollection);
$calculator->getTaxAmount('foo'); $calculator->getTaxAmount('foo');
} }
public function testGetTaxAmountAndGetTaxedPrice() public function testGetTaxAmountAndGetTaxedPrice()
{ {
$taxRulesGroupedCollection = new ObjectCollection(); $taxRulesCollection = new ObjectCollection();
$taxRulesGroupedCollection->setModel('\Thelia\Model\Tax'); $taxRulesCollection->setModel('\Thelia\Model\Tax');
$tax = new 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 = new Tax();
$tax->setVirtualColumn('taxRateSum', 8); $tax->setType('PricePercentTaxType')
->setRequirements(array('percent' => 8));
$taxRulesGroupedCollection->append($tax); $taxRulesCollection->append($tax);
$calculator = new Calculator(); $calculator = new Calculator();
$rewritingUrlQuery = $this->getProperty('taxRulesGroupedCollection'); $rewritingUrlQuery = $this->getProperty('taxRulesCollection');
$rewritingUrlQuery->setValue($calculator, $taxRulesGroupedCollection); $rewritingUrlQuery->setValue($calculator, $taxRulesCollection);
$taxAmount = $calculator->getTaxAmount(500); $taxAmount = $calculator->getTaxAmount(500);
$taxedPrice = $calculator->getTaxedPrice(500); $taxedPrice = $calculator->getTaxedPrice(500);

View File

@@ -0,0 +1,56 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Type;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
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;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*************************************************************************************/
/* */
/* Thelia */
/* */
/* Copyright (c) OpenStudio */
/* email : info@thelia.net */
/* web : http://www.thelia.net */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the GNU General Public License as published by */
/* the Free Software Foundation; either version 3 of the License */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* */
/*************************************************************************************/
namespace Thelia\Type;
use Propel\Runtime\ActiveRecord\ActiveRecordInterface;
use Thelia\Exception\TypeException;
/**
*
* @author Etienne Roudeix <eroudeix@openstudio.fr>
*
*/
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;
}
}

View File

@@ -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()), ('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()), ('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()), ('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()); ('process_assets', '1', 0, 0, NOW(), NOW());
INSERT INTO `module` (`id`, `code`, `type`, `activate`, `position`, `full_namespace`, `created_at`, `updated_at`) VALUES INSERT INTO `module` (`id`, `code`, `type`, `activate`, `position`, `full_namespace`, `created_at`, `updated_at`) VALUES
(1, 'DebugBar', 1, 1, 1, 'DebugBar\\DebugBar', NOW(), NOW()); (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, 'es_ES', 'USA - Alabama', '', '', ''),
(268, 'fr_FR', '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 VALUES
(1, '19.6', NOW(), NOW()); (1, 'PricePercentTaxType', 'eyJwZXJjZW50IjoxOS42fQ==', NOW(), NOW());
INSERT INTO `tax_i18n` (`id`, `locale`, `title`) INSERT INTO `tax_i18n` (`id`, `locale`, `title`)
VALUES VALUES

View File

@@ -111,7 +111,8 @@ DROP TABLE IF EXISTS `tax`;
CREATE TABLE `tax` CREATE TABLE `tax`
( (
`id` INTEGER NOT NULL AUTO_INCREMENT, `id` INTEGER NOT NULL AUTO_INCREMENT,
`rate` FLOAT NOT NULL, `type` VARCHAR(255) NOT NULL,
`serialized_requirements` TEXT NOT NULL,
`created_at` DATETIME, `created_at` DATETIME,
`updated_at` DATETIME, `updated_at` DATETIME,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)

View File

@@ -86,7 +86,8 @@
</table> </table>
<table name="tax" namespace="Thelia\Model"> <table name="tax" namespace="Thelia\Model">
<column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" /> <column autoIncrement="true" name="id" primaryKey="true" required="true" type="INTEGER" />
<column name="rate" required="true" type="FLOAT" /> <column name="type" required="true" size="255" type="VARCHAR" />
<column name="serialized_requirements" required="true" type="LONGVARCHAR" />
<column name="title" size="255" type="VARCHAR" /> <column name="title" size="255" type="VARCHAR" />
<column name="description" type="LONGVARCHAR" /> <column name="description" type="LONGVARCHAR" />
<behavior name="timestampable" /> <behavior name="timestampable" />

25
run_casperjs.sh Executable file
View File

@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -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;

View File

@@ -251,6 +251,6 @@
.loading{ .loading{
background: url("@{imgDir}/ajax-loader.gif") no-repeat; background: url("@{imgDir}/ajax-loader.gif") no-repeat;
height: 24px; height: 30px;
width: 24px; width: 30px;
} }

View File

@@ -16,7 +16,7 @@
</div> </div>
{form name="thelia.admin.coupon.creation"} {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} {/form}
</section> <!-- #wrapper --> </section> <!-- #wrapper -->

View File

@@ -16,9 +16,10 @@
</div> </div>
{form name="thelia.admin.coupon.creation"} {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} {/form}
</section> <!-- #wrapper --> </section> <!-- #wrapper -->
{/block} {/block}
@@ -37,19 +38,19 @@
<script src="{$asset_url}"></script> <script src="{$asset_url}"></script>
{/javascripts} {/javascripts}
{javascripts file='assets/js/coupon.js'}
<script src="{$asset_url}"></script>
{/javascripts}
<script> <script>
$(function($){ $(function($){
miniBrowser(0, '/test_to_remove/datas_coupon_edit.json'); miniBrowser(0, '/test_to_remove/datas_coupon_edit.json');
// Init Rules // Init Rules
var initRule = function() { couponManager.initRules = function() {
var rules = []; var rules = [];
{foreach from=$rulesObject key=k item=rule} {foreach from=$rulesObject key=k item=rule}
// Init rule
var rule = {}; var rule = {};
rule['serviceId'] = '{$rule.serviceId nofilter}'; rule['serviceId'] = '{$rule.serviceId nofilter}';
rule['operators'] = {}; rule['operators'] = {};
@@ -59,24 +60,24 @@
rule['operators']['{$input nofilter}'] = '{$operator nofilter}'; rule['operators']['{$input nofilter}'] = '{$operator nofilter}';
rule['values']['{$input nofilter}'] = '{$rule.validators.setValues[$input] nofilter}'; rule['values']['{$input nofilter}'] = '{$rule.validators.setValues[$input] nofilter}';
{/foreach} {/foreach}
// Add rule
rules.push(rule); rules.push(rule);
{/foreach} {/foreach}
return rules; return rules;
} };
// Save Rules AJAX // Save Rules AJAX
var saveRuleAjax = function() { couponManager.saveRuleAjax = function() {
$('#constraint-add-operators-values').html('<div class="loading" ></div>');
console.log('about to save');
console.log(couponManager.rulesToSave);
var $url = '{$urlAjaxUpdateRules}'; var $url = '{$urlAjaxUpdateRules}';
console.log('save');
console.log('{$urlAjaxUpdateRules}');
console.log(rules);
console.log(JSON.stringify(rules));
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: $url, url: $url,
{*data: {literal}{{/literal}rules:rules{literal}}{/literal},*} data: {literal}{{/literal}rules:JSON.stringify(couponManager.rulesToSave){literal}}{/literal},
data: {literal}{{/literal}rules:JSON.stringify(rules){literal}}{/literal},
statusCode: { statusCode: {
404: function() { 404: function() {
$('#constraint-add-operators-values').html( $('#constraint-add-operators-values').html(
@@ -87,75 +88,34 @@
}).done(function(data) { }).done(function(data) {
$('#constraint-list').html(data); $('#constraint-list').html(data);
$('#constraint-add-operators-values').html(''); $('#constraint-add-operators-values').html('');
couponManager.onClickUpdateRule();
couponManager.onClickDeleteRule();
}); });
} };
// Remove 1 Rule then Save Rules AJAX // Reload rule inputs
var removeRuleAjax = function($id) { couponManager.loadRuleInputs = function(ruleId, callBack) {
rules.slice($id, 1); $('#constraint-add-operators-values').html('<div class="loading" ></div>');
saveRuleAjax(); var url = "{$urlAjaxGetRuleInput}";
} url = url.replace('ruleId', ruleId)
$.ajax({
// Add 1 Rule then Save Rules AJAX url: url,
var addRuleAjax = function() { statusCode: {
rules.push(ruleToSave); 404: function() {
saveRuleAjax(); $('#constraint-add-operators-values').html(
} '{intl l='Please select another rule'}'
);
var rules = initRule();
console.log(rules);
// Save rules on click
var onClickSaveRule = function() {
$('#constraint-save-btn').on('click', function (e) {
addRuleAjax();
});
}
onClickSaveRule();
// Remove rule on click
var onClickDeleteRule = function() {
$('#constraint-delete-btn').on('click', function (e) {
// removeRuleAjax();
});
}
onClickDeleteRule();
// Reload effect inputs when changing effect
var onEffectChange = function() {
$('#effect').on('change', function (e) {
var optionSelected = $("option:selected", this);
$('#effectToolTip').html(optionSelected.attr("data-description"));
});
}
onEffectChange();
// Reload rule inputs when changing effect
var onRuleChange = function() {
$('#category-rule').on('change', function (e) {
$('#constraint-add-operators-values').html('<div class="loading" ></div>');
var url = "{$urlAjaxGetRuleInput}";
url = url.replace('ruleId', $(this).val())
$.ajax({
url: url,
statusCode: {
404: function() {
$('#constraint-add-operators-values').html(
'{intl l='Please select another rule'}'
);
}
} }
}).done(function(data) { }
$('#constraint-add-operators-values').html(data); }).done(function(data) {
}); $('#constraint-add-operators-values').html(data);
return callBack();
}); });
} };
onRuleChange();
// Rules which will be saved
couponManager.rulesToSave = couponManager.initRules();
}); });
</script> </script>
{/block} {/block}

View File

@@ -161,134 +161,122 @@
</div> </div>
</section> </section>
{if $noRules}
<section class="row"> {include file='includes/notifications.html' message={intl l='Please save your Coupon in oder to affect it some application fields'}}
<div class="col-md-12 general-block-decorator"> {else}
<table class="table table-striped"> <section class="row">
<caption class="clearfix"> <div class="col-md-12 general-block-decorator">
{intl l='Rules'} <table class="table table-striped">
</caption> <caption class="clearfix">
<thead> {intl l='Rules'}
<tr> </caption>
<th>{intl l='Conditions'}</th> <thead>
<th>{intl l='Actions'}</th> <tr>
</tr> <th>{intl l='Conditions'}</th>
</thead> <th>{intl l='Actions'}</th>
<tbody id="constraint-list"> </tr>
{include file='coupon/rules.html' rules=$rulesObject} </thead>
{*{foreach from=$rulesObject item=rule name=rulesForeach}*} <tbody id="constraint-list">
{*<tr>*} {include file='coupon/rules.html' rules=$rules}
{*<td>*} </tbody>
{*{if !$smarty.foreach.rulesForeach.first}*} </table>
{*<span class="label label-info">{intl l='And'}</span>*}
{*{/if}*}
{*{$rule.tooltip nofilter}*}
{*</td>*}
{*<td>*}
{*<a href="#url" class="btn btn-default btn-primary btn-medium"><span class="glyphicon glyphicon-edit"></span> {intl l='Edit'}</a>*}
{*<a href="#url" class="btn btn-default btn-danger btn-medium" data-toggle="confirm" data-target="#delete"><span class="glyphicon glyphicon-remove"></span> {intl l='Delete'}</a>*}
{*</td>*}
{*</tr>*}
{*{/foreach}*}
</tbody>
</table>
</div>
</section>
<section class="row">
<div class="col-md-12 general-block-decorator clearfix">
<a id="constraint-save-btn" title="{intl l='Save this rule'}" class="btn btn-default btn-primary pull-right">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
<div id="rule-add-organizer" class="form-group col-md-2">
<label for="type">{intl l='Condition type :'}</label>
<label class="radio">
<input type="radio" name="type" id="type" value="1" checked> {intl l='And'}
</label>
<label class="radio">
<input type="radio" name="type" value="2"> {intl l='Or'}
</label>
</div> </div>
</section>
<div id="rule-add-type" class="form-group col-md-4"> <section class="row">
<label for="categoryRule">{intl l='Rule\'s category :'}</label> <div class="col-md-12 general-block-decorator clearfix">
<select name="categoryRule" id="category-rule" class="form-control"> <a id="constraint-save-btn" title="{intl l='Save this rule'}" class="btn btn-default btn-primary pull-right">
{foreach from=$availableRules item=availableRule} <span class="glyphicon glyphicon-plus-sign"></span>
<option value="{$availableRule.serviceId}" data-description="{$availableRule.toolTip}">{$availableRule.name}</option> </a>
{/foreach}
</select> <div id="rule-add-organizer" class="form-group col-md-2">
<label for="type">{intl l='Condition type :'}</label>
<label class="radio">
<input type="radio" name="type" id="type" value="1" checked> {intl l='And'}
</label>
<label class="radio">
<input type="radio" name="type" value="2"> {intl l='Or'}
</label>
</div>
<div id="rule-add-type" class="form-group col-md-4">
<label for="categoryRule">{intl l='Rule\'s category :'}</label>
<select name="categoryRule" id="category-rule" class="form-control">
{foreach from=$availableRules item=availableRule}
<option value="{$availableRule.serviceId}" data-description="{$availableRule.toolTip}">{$availableRule.name}</option>
{/foreach}
</select>
</div>
<div id="constraint-add-operators-values" class="form-group col-md-6">
{*<label for="operator">{intl l='Operator :'}</label>*}
{*<div class="row">*}
{*<div class="col-lg-6">*}
{*<select name="operator" id="operator" class="form-control">*}
{*<option value="1">is superior to</option>*}
{*<option value="2">equals to</option>*}
{*<option value="3">is inferior to</option>*}
{*<option value="4">is inferior or equals to</option>*}
{*<option value="5">is superior or equals to</option>*}
{*</select>*}
{*</div>*}
{*<div class="input-group col-lg-6">*}
{*<input type="text" name="value" class="form-control">*}
{*<span class="input-group-addon">&euro;</span>*}
{*</div>*}
{*</div>*}
{**}
{*<label for="operator">Operator :</label>*}
{*<div class="row">*}
{*<div class="col-lg-6">*}
{*<select name="operator" id="operator" class="form-control">*}
{*<option value="1">is superior to</option>*}
{*<option value="2">equals to</option>*}
{*<option value="3">is inferior to</option>*}
{*<option value="4">is inferior or equals to</option>*}
{*<option value="5">is superior or equals to</option>*}
{*</select>*}
{*</div>*}
{*<div class="input-group col-lg-6 date" data-date="12/02/2012" data-date-format="dd/mm/yyyy">*}
{*<input type="text" name="value" class="form-control">*}
{*<span class="input-group-addon"><span class="glyphicon glyphicon-th"></span></span>*}
{*</div>*}
{*</div>*}
{*<label for="operator">Operator :</label>*}
{*<div class="row">*}
{*<div class="col-lg-6">*}
{*<select name="operator" id="operator" class="form-control">*}
{*<option value="1">is superior to</option>*}
{*<option value="2">equals to</option>*}
{*<option value="3">is inferior to</option>*}
{*<option value="4">is inferior or equals to</option>*}
{*<option value="5">is superior or equals to</option>*}
{*</select>*}
{*</div>*}
{*<div class="col-lg-6">*}
{*<input type="text" name="value" class="form-control">*}
{*</div>*}
{*</div>*}
{*<div class="row">*}
{*<div class="col-lg-12">*}
{*<table class="table table-bordered">*}
{*<tr>*}
{*<td id="minibrowser-breadcrumb"></td>*}
{*</tr>*}
{*<tr>*}
{*<th><span class="icon-th-list"></span> Categories list</th>*}
{*</tr>*}
{*<tr>*}
{*<td id="minibrowser-categories"></td>*}
{*</tr>*}
{*</table>*}
{*</div>*}
{*</div>*}
</div>
</div> </div>
</section>
<div id="constraint-add-operators-values" class="form-group col-md-6"> {/if}
{*<label for="operator">{intl l='Operator :'}</label>*}
{*<div class="row">*}
{*<div class="col-lg-6">*}
{*<select name="operator" id="operator" class="form-control">*}
{*<option value="1">is superior to</option>*}
{*<option value="2">equals to</option>*}
{*<option value="3">is inferior to</option>*}
{*<option value="4">is inferior or equals to</option>*}
{*<option value="5">is superior or equals to</option>*}
{*</select>*}
{*</div>*}
{*<div class="input-group col-lg-6">*}
{*<input type="text" name="value" class="form-control">*}
{*<span class="input-group-addon">&euro;</span>*}
{*</div>*}
{*</div>*}
{**}
{*<label for="operator">Operator :</label>*}
{*<div class="row">*}
{*<div class="col-lg-6">*}
{*<select name="operator" id="operator" class="form-control">*}
{*<option value="1">is superior to</option>*}
{*<option value="2">equals to</option>*}
{*<option value="3">is inferior to</option>*}
{*<option value="4">is inferior or equals to</option>*}
{*<option value="5">is superior or equals to</option>*}
{*</select>*}
{*</div>*}
{*<div class="input-group col-lg-6 date" data-date="12/02/2012" data-date-format="dd/mm/yyyy">*}
{*<input type="text" name="value" class="form-control">*}
{*<span class="input-group-addon"><span class="glyphicon glyphicon-th"></span></span>*}
{*</div>*}
{*</div>*}
{*<label for="operator">Operator :</label>*}
{*<div class="row">*}
{*<div class="col-lg-6">*}
{*<select name="operator" id="operator" class="form-control">*}
{*<option value="1">is superior to</option>*}
{*<option value="2">equals to</option>*}
{*<option value="3">is inferior to</option>*}
{*<option value="4">is inferior or equals to</option>*}
{*<option value="5">is superior or equals to</option>*}
{*</select>*}
{*</div>*}
{*<div class="col-lg-6">*}
{*<input type="text" name="value" class="form-control">*}
{*</div>*}
{*</div>*}
{*<div class="row">*}
{*<div class="col-lg-12">*}
{*<table class="table table-bordered">*}
{*<tr>*}
{*<td id="minibrowser-breadcrumb"></td>*}
{*</tr>*}
{*<tr>*}
{*<th><span class="icon-th-list"></span> Categories list</th>*}
{*</tr>*}
{*<tr>*}
{*<td id="minibrowser-categories"></td>*}
{*</tr>*}
{*</table>*}
{*</div>*}
{*</div>*}
</div>
</div>
</section>
</form> </form>

View File

@@ -1,4 +1,3 @@
{*{$inputs.inputs|var_dump}*}
{foreach from=$inputs.inputs key=name item=input} {foreach from=$inputs.inputs key=name item=input}
<label for="operator">{$input.title}</label> <label for="operator">{$input.title}</label>
<div class="row"> <div class="row">
@@ -71,32 +70,33 @@
{*</div>*} {*</div>*}
<script> <script>
var ruleToSave = {};
ruleToSave['serviceId'] = '{$ruleId}'; // Init Rules to set
ruleToSave['operators'] = {}; couponManager.ruleToSave['serviceId'] = '{$ruleId}';
ruleToSave['values'] = {}; couponManager.ruleToSave['operators'] = {literal}{}{/literal};
{foreach from=$inputs.inputs key=name item=input} couponManager.ruleToSave['values'] = {literal}{}{/literal};
ruleToSave['operators']['{$name nofilter}'] = '{foreach from=$inputs.inputs[$name].availableOperators key=keyOperator item=valueOperator name=operators}{if $smarty.foreach.operators.first}{$keyOperator nofilter}{/if}{/foreach}'; {foreach from=$inputs.inputs key=name item=input}
ruleToSave['values']['{$name nofilter}'] = '{if count($inputs.inputs[$name].availableValues) != 0}{foreach from=$inputs.inputs[$name].availableValues key=keyValue item=valueValue name=values}{if $smarty.foreach.values.first}{$keyValue nofilter}{/if}{/foreach}{else}to set{/if}'; couponManager.ruleToSave['operators']['{$name nofilter}'] = '{foreach from=$inputs.inputs[$name].availableOperators key=keyOperator item=valueOperator name=operators}{if $smarty.foreach.operators.first}{$keyOperator nofilter}{/if}{/foreach}';
{/foreach} couponManager.ruleToSave['values']['{$name nofilter}'] = '{if count($inputs.inputs[$name].availableValues) != 0}{foreach from=$inputs.inputs[$name].availableValues key=keyValue item=valueValue name=values}{if $smarty.foreach.values.first}{$keyValue nofilter}{/if}{/foreach}{else}to set{/if}';
{/foreach}
// Update ruleToSave Array ready to be saved // Fill in ready to be saved rule array
var onInputsChange = function() {literal}{{/literal} couponManager.onInputsChange = function() {literal}{{/literal}
{foreach from=$inputs.inputs key=name item=input} {foreach from=$inputs.inputs key=name item=input}
$('#{$name}-operator').change(function (e) { // Operator selector
var $this = $(this); $('#{$name}-operator').change(function (e) {
ruleToSave['operators']['{$name nofilter}'] = $this.val(); console.log('changin operator');
console.log('#{$name}-operator changed ' + $this.val()); var $this = $(this);
console.log(ruleToSave); couponManager.ruleToSave['operators']['{$name nofilter}'] = $this.val();
}); });
$('#{$name}-value').change(function (e) { // Value input
var $this = $(this); $('#{$name}-value').change(function (e) {
ruleToSave['values']['{$name nofilter}'] = $this.val(); console.log('changin value');
console.log('#{$name}-value changed ' + $this.val()); var $this = $(this);
console.log(ruleToSave); couponManager.ruleToSave['values']['{$name nofilter}'] = $this.val();
}); });
{/foreach} {/foreach}
{literal}}{/literal} {literal}}{/literal}
onInputsChange(); couponManager.onInputsChange();
</script> </script>

View File

@@ -1,4 +1,4 @@
{foreach from=$rules item=rule name=rulesForeach} {foreach from=$rules item=rule key=i name=rulesForeach}
<tr> <tr>
<td> <td>
{if !$smarty.foreach.rulesForeach.first} {if !$smarty.foreach.rulesForeach.first}
@@ -7,10 +7,10 @@
{$rule nofilter} {$rule nofilter}
</td> </td>
<td> <td>
<a class="btn btn-default btn-primary btn-medium" href="{$urlEdit}"> <a data-int="{$i}" class="btn btn-default btn-primary btn-medium constraint-update-btn" href="{$urlEdit}">
<span class="glyphicon glyphicon-edit"></span> {intl l='Edit'} <span class="glyphicon glyphicon-edit"></span> {intl l='Edit'}
</a> </a>
<a data-target="#delete" data-toggle="confirm" class="btn btn-default btn-danger btn-medium" href="{$urlDelete}"> <a data-int="{$i}" data-target="#delete" data-toggle="confirm" class="btn btn-default btn-danger btn-medium constraint-delete-btn" href="{$urlDelete}">
<span class="glyphicon glyphicon-remove"></span> {intl l='Delete'} <span class="glyphicon glyphicon-remove"></span> {intl l='Delete'}
</a> </a>
</td> </td>

View File

@@ -28,13 +28,13 @@
{form_field form=$form field='username'} {form_field form=$form field='username'}
<span {if $error}class="error"{/if}> <span {if $error}class="error"{/if}>
<input type="text" class="input" placeholder="{intl l='User name'}" name="{$name}" value="{$value}" {$attr} /> <input type="text" id="username" class="input" placeholder="{intl l='User name'}" name="{$name}" value="{$value}" {$attr} />
</span> </span>
{/form_field} {/form_field}
{form_field form=$form field='password'} {form_field form=$form field='password'}
<span {if $error}class="error"{/if}> <span {if $error}class="error"{/if}>
<input type="password" class="input" placeholder="{intl l='Password'}" name="{$name}" {$attr} /> <input type="password" id="password" class="input" placeholder="{intl l='Password'}" name="{$name}" {$attr} />
</span> </span>
{/form_field} {/form_field}

View File

@@ -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"}
<div class="orders">
<div id="wrapper" class="container">
<ul class="breadcrumb">
<li><a href="{url path='/admin/home'}">{intl l="Home"}</a></li>
<li><a href="{url path='/admin/orders'}">{intl l="Orders"}</a></li>
</ul>
{module_include location='orders_top'}
<div class="row">
<div class="col-md-12">
<form action="{url path='/admin/orders/update-values'}" method="post">
<div class="general-block-decorator">
<table class="table table-striped table-condensed table-left-aligned">
<caption class="clearfix">
{intl l='Orders'}
{loop type="auth" name="can_create" roles="ADMIN" permissions="admin.orders.create"}
<a class="btn btn-default btn-primary pull-right" title="{intl l='Create an order'}" href="#creation_dialog">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
{/loop}
</caption>
<thead>
<tr>
<th>{intl l="Order n°"}</th>
<th>{intl l="Date & Hour"}</th>
<th>{intl l="Compagny"}</th>
<th>{intl l="Name"}</th>
<th>{intl l="Amount"}</th>
<th>{intl l="Status"}</th>
{module_include location='orders_table_header'}
<th>{intl l="Actions"}</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="">01230450123045</a></td>
<td>11/09/2013 10:24:31</td>
<td>Thelia</td>
<td><a href="">Dupont</a></td>
<td>251 &euro;</td>
<td><span class="label label-success">Paid</span></td>
{module_include location='orders_table_row'}
<td>
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/orders/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
<a class="btn btn-default btn-xs" title="{intl l='Delete this order'}" href="#delete_order_dialog" data-id="{$ID}" data-toggle="modal"><span class="glyphicon glyphicon-trash"></span></a>
{/loop}
</div>
</td>
</tr>
<tr>
<td><a href="">01230450123045</a></td>
<td>11/09/2013 10:24:31</td>
<td>Thelia</td>
<td><a href="">Dupont</a></td>
<td>251 &euro;</td>
<td><span class="label label-danger">Canceled</span></td>
{module_include location='orders_table_row'}
<td>
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/orders/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
<a class="btn btn-default btn-xs" title="{intl l='Delete this order'}" href="#delete_order_dialog" data-id="{$ID}" data-toggle="modal"><span class="glyphicon glyphicon-trash"></span></a>
{/loop}
</div>
</td>
</tr>
<tr>
<td><a href="">01230450123045</a></td>
<td>11/09/2013 10:24:31</td>
<td>Thelia</td>
<td><a href="">Dupont</a></td>
<td>251 &euro;</td>
<td><span class="label label-info">Current</span></td>
{module_include location='orders_table_row'}
<td>
<div class="btn-group">
{loop type="auth" name="can_change" roles="ADMIN" permissions="admin.orders.edit"}
<a class="btn btn-default btn-xs" title="{intl l='Edit this order'}" href="{url path='/admin/orders/update/$ID'}"><span class="glyphicon glyphicon-edit"></span></a>
{/loop}
{loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.orders.delete"}
<a class="btn btn-default btn-xs" title="{intl l='Delete this order'}" href="#delete_order_dialog" data-id="{$ID}" data-toggle="modal"><span class="glyphicon glyphicon-trash"></span></a>
{/loop}
</div>
</td>
</tr>
<!-- <tr>
<td colspan="3">
<div class="alert alert-info">
{intl l="No mailing template has been created yet. Click the + button to create one."}
</div>
</td>
</tr> -->
</tbody>
</table>
</div>
</form>
</div>
</div>
{module_include location='orders_bottom'}
</div>
</div>
{* Delete order confirmation dialog *}
{capture "delete_order_dialog"}
<input type="hidden" name="current_order_id" value="{$current_order_id}" />
<input type="hidden" name="order_id" id="delete_order_id" value"" />
{/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}

View File

@@ -1,9 +1,3 @@
<html>
<head>
{debugbar_renderHead}
</head>
<body>
<h1>Category page</h1> <h1>Category page</h1>
<div style="border: solid 8px; margin: 0px; padding: 0px; width: 45%; float: left"> <div style="border: solid 8px; margin: 0px; padding: 0px; width: 45%; float: left">
@@ -148,8 +142,4 @@
{/loop} {/loop}
</ul> </ul>
</div> </div>
{debugbar_render}
</body>
</html>

View File

@@ -8,7 +8,7 @@ Index : {navigate to="index"}<br />
{ifloop rel="product"} {ifloop rel="product"}
{loop type="product" name="product" current="true" min_price="50" max_price="100"} {loop type="product" name="product" current="true"}
<div style="border: dashed 2px red; padding: 20px; margin: 10px;"> <div style="border: dashed 2px red; padding: 20px; margin: 10px;">
<h2>PRODUCT ({$ID}) : {$REF}</h2> <h2>PRODUCT ({$ID}) : {$REF}</h2>

View File

@@ -0,0 +1,3 @@
//LOCAL = ton pc
var thelia2_base_url = 'http://www.thelia2.dev/index_dev.php/';
casper.test.done(0);

View File

@@ -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);

View File

@@ -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();
});

View File

@@ -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();
});