Merge branch 'master' into tinymce
Conflicts: local/modules/Tinymce/templates/backOffice/default/include/tinymce_init.tpl
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -42,3 +42,8 @@ templates/*
|
||||
!templates/email/
|
||||
!templates/frontOffice/
|
||||
!templates/pdf/
|
||||
|
||||
#Ignore CodeKit
|
||||
codekit-config.json
|
||||
config.codekit
|
||||
.codekit-cache
|
||||
|
||||
@@ -10,6 +10,8 @@ env:
|
||||
- DB_USER=root
|
||||
|
||||
before_script:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -y language-pack-fr language-pack-fr-base
|
||||
- phpenv config-add travis.php.ini
|
||||
- composer self-update
|
||||
- composer install --prefer-dist --dev
|
||||
|
||||
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,4 +1,13 @@
|
||||
#2.0.3
|
||||
- New coupon type: Free product if selected products are in the cart.
|
||||
|
||||
#2.0.2
|
||||
- Coupon UI has been redesigned.
|
||||
- New coupon types:
|
||||
- Constant discount on selected products
|
||||
- Constant discount on products of selected categories
|
||||
- Percentage discount on selected products
|
||||
- Percentage discount on products of selected categories
|
||||
- New coupon conditions :
|
||||
- Start date
|
||||
- Billing country
|
||||
@@ -6,7 +15,21 @@
|
||||
- Cart contains product
|
||||
- Cart contains product from category
|
||||
- For specific customers
|
||||
|
||||
- Free shipping can now be restricted to some countries and/or shipping methods
|
||||
- session initialization use now event dispatcher :
|
||||
- name event : thelia_kernel.session (see Thelia\Core\TheliakernelEvents::SESSION
|
||||
- class event : Thelia\Core\Event\SessionEvent
|
||||
- example : Thelia\Core\EventListener\SessionListener
|
||||
- Creation of Thelia\Core\TheliakernelEvents class for referencing kernel event
|
||||
- Add new command line that refresh modules list `Thelia module:refresh`
|
||||
- Coupon internals have been simplified and improved.
|
||||
- Error messages are displayed in install process
|
||||
- Add pagination on catalog page in Back-Office
|
||||
- Add Hong Kong to country list
|
||||
- Fixed issue #452 when installing Thelia on database with special characters
|
||||
- implement search on content, folder and category loop.
|
||||
- all form are documented
|
||||
- template exists for managing google sitemap : sitemap.html
|
||||
|
||||
#2.0.1
|
||||
- possibility to apply a permanent discount on a customer
|
||||
|
||||
@@ -32,6 +32,5 @@ if (!file_exists(THELIA_CONF_DIR . 'database.yml') && !defined('THELIA_INSTALL_M
|
||||
} else {
|
||||
$request = \Thelia\Core\HttpFoundation\Request::createFromGlobals();
|
||||
header('Location: '.$request->getUriForPath('/install'));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Core\Event\Cart\CartEvent;
|
||||
use Thelia\Core\Event\Currency\CurrencyChangeEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model\Base\ProductSaleElementsQuery;
|
||||
use Thelia\Model\Currency;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\CartItemQuery;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Currency;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Model\Tools\ProductPriceTools;
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
namespace Thelia\Action;
|
||||
|
||||
use Propel\Runtime\Propel;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Condition\ConditionFactory;
|
||||
use Thelia\Condition\Implementation\ConditionInterface;
|
||||
use Thelia\Core\Event\Coupon\CouponConsumeEvent;
|
||||
@@ -22,17 +24,23 @@ use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Coupon\CouponFactory;
|
||||
use Thelia\Coupon\CouponManager;
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
use Thelia\Model\Coupon as CouponModel;
|
||||
use Thelia\Model\CouponCountry;
|
||||
use Thelia\Model\CouponCountryQuery;
|
||||
use Thelia\Model\CouponModule;
|
||||
use Thelia\Model\CouponModuleQuery;
|
||||
use Thelia\Model\CouponQuery;
|
||||
use Thelia\Model\Map\OrderCouponTableMap;
|
||||
use Thelia\Model\OrderCoupon;
|
||||
use Thelia\Model\OrderCouponCountry;
|
||||
use Thelia\Model\OrderCouponModule;
|
||||
|
||||
/**
|
||||
* Process Coupon Events
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
@@ -101,6 +109,17 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$this->createOrUpdateCondition($modelCoupon, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all coupons in session.
|
||||
*/
|
||||
public function clearAllCoupons()
|
||||
{
|
||||
// Tell coupons to clear any data they may have stored
|
||||
$this->couponManager->clear();
|
||||
|
||||
$this->request->getSession()->setConsumedCoupons(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Occurring when a Coupon condition is about to be consumed
|
||||
*
|
||||
@@ -115,7 +134,9 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$coupon = $this->couponFactory->buildCouponFromCode($event->getCode());
|
||||
|
||||
if ($coupon) {
|
||||
|
||||
$isValid = $coupon->isMatching();
|
||||
|
||||
if ($isValid) {
|
||||
$consumedCoupons = $this->request->getSession()->getConsumedCoupons();
|
||||
|
||||
@@ -124,35 +145,35 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
if (!isset($consumedCoupons[$event->getCode()])) {
|
||||
|
||||
// Prevent accumulation of the same Coupon on a Checkout
|
||||
$consumedCoupons[$event->getCode()] = $event->getCode();
|
||||
|
||||
$this->request->getSession()->setConsumedCoupons($consumedCoupons);
|
||||
|
||||
$totalDiscount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
->getCart()
|
||||
->setDiscount($totalDiscount)
|
||||
->save();
|
||||
$this->request
|
||||
->getSession()
|
||||
->getOrder()
|
||||
->setDiscount($totalDiscount)
|
||||
// ->save()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
$totalDiscount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
->getCart()
|
||||
->setDiscount($totalDiscount)
|
||||
->save();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
->getOrder()
|
||||
->setDiscount($totalDiscount)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
$event->setIsValid($isValid);
|
||||
$event->setDiscount($totalDiscount);
|
||||
}
|
||||
|
||||
public function updateOrderDiscount($event)
|
||||
public function updateOrderDiscount(/** @noinspection PhpUnusedParameterInspection */ $event)
|
||||
{
|
||||
|
||||
$discount = $this->couponManager->getDiscount();
|
||||
|
||||
$this->request
|
||||
@@ -160,6 +181,7 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
->getCart()
|
||||
->setDiscount($discount)
|
||||
->save();
|
||||
|
||||
$this->request
|
||||
->getSession()
|
||||
->getOrder()
|
||||
@@ -202,7 +224,10 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
$event->isCumulative(),
|
||||
$event->getMaxUsage(),
|
||||
$defaultSerializedRule,
|
||||
$event->getLocale()
|
||||
$event->getLocale(),
|
||||
$event->getFreeShippingForCountries(),
|
||||
$event->getFreeShippingForMethods(),
|
||||
$event->getPerCustomerUsageCount()
|
||||
);
|
||||
|
||||
$event->setCouponModel($coupon);
|
||||
@@ -235,8 +260,9 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
public function testFreePostage(OrderEvent $event)
|
||||
{
|
||||
if ($this->couponManager->isCouponRemovingPostage()) {
|
||||
$order = $event->getOrder();
|
||||
$order = $event->getOrder();
|
||||
|
||||
if ($this->couponManager->isCouponRemovingPostage($order)) {
|
||||
|
||||
$order->setPostage(0);
|
||||
|
||||
@@ -248,42 +274,85 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
|
||||
/**
|
||||
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
||||
*
|
||||
* @throws \Exception if something goes wrong.
|
||||
*/
|
||||
public function afterOrder(OrderEvent $event)
|
||||
{
|
||||
$consumedCoupons = $this->request->getSession()->getConsumedCoupons();
|
||||
|
||||
if (is_array($consumedCoupons)) {
|
||||
foreach ($consumedCoupons as $couponCode) {
|
||||
$couponQuery = CouponQuery::create();
|
||||
$couponModel = $couponQuery->findOneByCode($couponCode);
|
||||
$couponModel->setLocale($this->request->getSession()->getLang()->getLocale());
|
||||
|
||||
/* decrease coupon quantity */
|
||||
$this->couponManager->decrementQuantity($couponModel);
|
||||
$con = Propel::getWriteConnection(OrderCouponTableMap::DATABASE_NAME);
|
||||
$con->beginTransaction();
|
||||
|
||||
/* memorize coupon */
|
||||
$orderCoupon = new OrderCoupon();
|
||||
$orderCoupon->setOrder($event->getOrder())
|
||||
->setCode($couponModel->getCode())
|
||||
->setType($couponModel->getType())
|
||||
->setAmount($couponModel->getAmount())
|
||||
try {
|
||||
foreach ($consumedCoupons as $couponCode) {
|
||||
$couponQuery = CouponQuery::create();
|
||||
$couponModel = $couponQuery->findOneByCode($couponCode);
|
||||
$couponModel->setLocale($this->request->getSession()->getLang()->getLocale());
|
||||
|
||||
->setTitle($couponModel->getTitle())
|
||||
->setShortDescription($couponModel->getShortDescription())
|
||||
->setDescription($couponModel->getDescription())
|
||||
/* decrease coupon quantity */
|
||||
$this->couponManager->decrementQuantity($couponModel, $event->getOrder()->getCustomerId());
|
||||
|
||||
->setExpirationDate($couponModel->getExpirationDate())
|
||||
->setIsCumulative($couponModel->getIsCumulative())
|
||||
->setIsRemovingPostage($couponModel->getIsRemovingPostage())
|
||||
->setIsAvailableOnSpecialOffers($couponModel->getIsAvailableOnSpecialOffers())
|
||||
->setSerializedConditions($couponModel->getSerializedConditions())
|
||||
;
|
||||
$orderCoupon->save();
|
||||
/* memorize coupon */
|
||||
$orderCoupon = new OrderCoupon();
|
||||
$orderCoupon->setOrder($event->getOrder())
|
||||
->setCode($couponModel->getCode())
|
||||
->setType($couponModel->getType())
|
||||
->setAmount($couponModel->getAmount())
|
||||
|
||||
->setTitle($couponModel->getTitle())
|
||||
->setShortDescription($couponModel->getShortDescription())
|
||||
->setDescription($couponModel->getDescription())
|
||||
|
||||
->setExpirationDate($couponModel->getExpirationDate())
|
||||
->setIsCumulative($couponModel->getIsCumulative())
|
||||
->setIsRemovingPostage($couponModel->getIsRemovingPostage())
|
||||
->setIsAvailableOnSpecialOffers($couponModel->getIsAvailableOnSpecialOffers())
|
||||
->setSerializedConditions($couponModel->getSerializedConditions())
|
||||
->setPerCustomerUsageCount($couponModel->getPerCustomerUsageCount())
|
||||
;
|
||||
$orderCoupon->save();
|
||||
|
||||
// Copy order coupon free shipping data for countries and modules
|
||||
$couponCountries = CouponCountryQuery::create()->filterByCouponId($couponModel->getId())->find();
|
||||
|
||||
/** @var CouponCountry $couponCountry */
|
||||
foreach ($couponCountries as $couponCountry) {
|
||||
$occ = new OrderCouponCountry();
|
||||
|
||||
$occ
|
||||
->setCouponId($orderCoupon->getId())
|
||||
->setCountryId($couponCountry->getCountryId())
|
||||
->save();
|
||||
;
|
||||
}
|
||||
|
||||
$couponModules = CouponModuleQuery::create()->filterByCouponId($couponModel->getId())->find();
|
||||
|
||||
/** @var CouponModule $couponModule */
|
||||
foreach ($couponModules as $couponModule) {
|
||||
$ocm = new OrderCouponModule();
|
||||
|
||||
$ocm
|
||||
->setCouponId($orderCoupon->getId())
|
||||
->setModuleId($couponModule->getModuleId())
|
||||
->save();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
$con->commit();
|
||||
} catch (\Exception $ex) {
|
||||
$con->rollBack();
|
||||
|
||||
throw($ex);
|
||||
}
|
||||
}
|
||||
|
||||
$this->request->getSession()->setConsumedCoupons(array());
|
||||
// Clear all coupons.
|
||||
$event->getDispatcher()->dispatch(TheliaEvents::COUPON_CLEAR_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,8 +381,9 @@ class Coupon extends BaseAction implements EventSubscriberInterface
|
||||
TheliaEvents::COUPON_CREATE => array("create", 128),
|
||||
TheliaEvents::COUPON_UPDATE => array("update", 128),
|
||||
TheliaEvents::COUPON_CONSUME => array("consume", 128),
|
||||
TheliaEvents::COUPON_CLEAR_ALL => array("clearAllCoupons", 128),
|
||||
TheliaEvents::COUPON_CONDITION_UPDATE => array("updateCondition", 128),
|
||||
TheliaEvents::ORDER_SET_POSTAGE => array("testFreePostage", 256),
|
||||
TheliaEvents::ORDER_SET_POSTAGE => array("testFreePostage", 132),
|
||||
TheliaEvents::ORDER_BEFORE_PAYMENT => array("afterOrder", 128),
|
||||
TheliaEvents::CART_ADDITEM => array("updateOrderDiscount", 10),
|
||||
TheliaEvents::CART_UPDATEITEM => array("updateOrderDiscount", 10),
|
||||
|
||||
@@ -161,7 +161,7 @@ class Module extends BaseAction implements EventSubscriberInterface
|
||||
);
|
||||
}
|
||||
|
||||
$paymentModuleInstance = $this->container->get(sprintf('module.%s', $paymentModule->getCode()));
|
||||
$paymentModuleInstance = $paymentModule->getModuleInstance($this->container);
|
||||
|
||||
$response = $paymentModuleInstance->pay($order);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->chosenDeliveryAddress = $event->getDeliveryAddress();
|
||||
$order->setChoosenDeliveryAddress($event->getDeliveryAddress());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
{
|
||||
$order = $event->getOrder();
|
||||
|
||||
$order->chosenInvoiceAddress = $event->getInvoiceAddress();
|
||||
$order->setChoosenInvoiceAddress($event->getInvoiceAddress());
|
||||
|
||||
$event->setOrder($order);
|
||||
}
|
||||
@@ -153,9 +153,9 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
$placedOrder = $sessionOrder->copy();
|
||||
$placedOrder->setDispatcher($dispatcher);
|
||||
|
||||
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->chosenDeliveryAddress);
|
||||
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenDeliveryAddress());
|
||||
$taxCountry = $deliveryAddress->getCountry();
|
||||
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->chosenInvoiceAddress);
|
||||
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenInvoiceAddress());
|
||||
$cartItems = $cart->getCartItems();
|
||||
|
||||
/* fulfill order */
|
||||
@@ -302,14 +302,18 @@ class Order extends BaseAction implements EventSubscriberInterface
|
||||
*/
|
||||
public function createManual(OrderManualEvent $event)
|
||||
{
|
||||
$this->createOrder(
|
||||
$event->getDispatcher(),
|
||||
$event->getOrder(),
|
||||
$event->getCurrency(),
|
||||
$event->getLang(),
|
||||
$event->getCart(),
|
||||
$event->getCustomer()
|
||||
$event->setPlacedOrder(
|
||||
$this->createOrder(
|
||||
$event->getDispatcher(),
|
||||
$event->getOrder(),
|
||||
$event->getCurrency(),
|
||||
$event->getLang(),
|
||||
$event->getCart(),
|
||||
$event->getCustomer()
|
||||
)
|
||||
);
|
||||
|
||||
$event->setOrder(new \Thelia\Model\Order());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
54
core/lib/Thelia/Command/ModuleRefreshCommand.php
Normal file
54
core/lib/Thelia/Command/ModuleRefreshCommand.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Thelia\Module\ModuleManagement;
|
||||
|
||||
/**
|
||||
* Class ModuleRefreshCommand
|
||||
* Refresh modules list
|
||||
*
|
||||
* @package Thelia\Command
|
||||
* @author Jérôme Billiras <jbilliras@openstudio.fr>
|
||||
*/
|
||||
class ModuleRefreshCommand extends ContainerAwareCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('module:refresh')
|
||||
->setDescription('Refresh modules list');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$moduleManagement = new ModuleManagement;
|
||||
$moduleManagement->updateModules();
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException(sprintf('Refresh modules list fail with Exception : [%d] %s', $e->getCode(), $e->getMessage()));
|
||||
}
|
||||
|
||||
if (method_exists($output, 'renderBlock')) {
|
||||
$output->renderBlock([
|
||||
'',
|
||||
'Modules list successfully refreshed',
|
||||
''
|
||||
],
|
||||
'bg=green;fg=black'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,8 @@ namespace Thelia\Condition\Implementation;
|
||||
use Thelia\Condition\Operators;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
use Thelia\Model\Base\CountryQuery;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\Model\CountryQuery;
|
||||
|
||||
/**
|
||||
* Check a Checkout against its Product number
|
||||
@@ -44,9 +45,9 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
parent::__construct($facade);
|
||||
}
|
||||
|
||||
protected abstract function getSummaryLabel($cntryStrList, $i18nOperator);
|
||||
abstract protected function getSummaryLabel($cntryStrList, $i18nOperator);
|
||||
|
||||
protected abstract function getFormLabel();
|
||||
abstract protected function getFormLabel();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@@ -87,6 +88,7 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
// The delivery address should match one of the selected countries.
|
||||
|
||||
/* TODO !!!! */
|
||||
|
||||
return $this->conditionValidator->variableOpComparison(
|
||||
$this->facade->getNbArticlesInCart(),
|
||||
$this->operators[self::COUNTRIES_LIST],
|
||||
@@ -109,8 +111,8 @@ abstract class AbstractMatchCountries extends ConditionAbstract
|
||||
|
||||
if (null !== $cntryList = CountryQuery::create()->findPks($cntryIds)) {
|
||||
|
||||
/** @var Category $cntry */
|
||||
foreach($cntryList as $cntry) {
|
||||
/** @var Country $cntry */
|
||||
foreach ($cntryList as $cntry) {
|
||||
$cntryStrList .= $cntry->getTitle() . ', ';
|
||||
}
|
||||
|
||||
|
||||
@@ -93,12 +93,12 @@ class CartContainsCategories extends ConditionAbstract
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach($cartItems as $cartItem) {
|
||||
foreach ($cartItems as $cartItem) {
|
||||
|
||||
$categories = $cartItem->getProduct()->getCategories();
|
||||
|
||||
/** @var Category $category */
|
||||
foreach($categories as $category) {
|
||||
foreach ($categories as $category) {
|
||||
$catecoryInCart = $this->conditionValidator->variableOpComparison(
|
||||
$category->getId(),
|
||||
$this->operators[self::CATEGORIES_LIST],
|
||||
@@ -156,7 +156,7 @@ class CartContainsCategories extends ConditionAbstract
|
||||
if (null !== $catList = CategoryQuery::create()->findPks($catIds)) {
|
||||
|
||||
/** @var Category $cat */
|
||||
foreach($catList as $cat) {
|
||||
foreach ($catList as $cat) {
|
||||
$catStrList .= $cat->getTitle() . ', ';
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Thelia\Condition\Implementation;
|
||||
use Thelia\Condition\Operators;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
use Thelia\Model\Base\ProductQuery;
|
||||
use Thelia\Model\ProductQuery;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\Product;
|
||||
|
||||
@@ -93,13 +93,12 @@ class CartContainsProducts extends ConditionAbstract
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach($cartItems as $cartItem) {
|
||||
foreach ($cartItems as $cartItem) {
|
||||
|
||||
if ($this->conditionValidator->variableOpComparison(
|
||||
$cartItem->getProduct()->getId(),
|
||||
$this->operators[self::PRODUCTS_LIST],
|
||||
$this->values[self::PRODUCTS_LIST])) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -149,7 +148,7 @@ class CartContainsProducts extends ConditionAbstract
|
||||
if (null !== $prodList = ProductQuery::create()->findPks($prodIds)) {
|
||||
|
||||
/** @var Product $prod */
|
||||
foreach($prodList as $prod) {
|
||||
foreach ($prodList as $prod) {
|
||||
$prodStrList .= $prod->getTitle() . ', ';
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionOperatorException;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
use Thelia\Model\Base\CurrencyQuery;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\Currency;
|
||||
use Thelia\Type\FloatType;
|
||||
|
||||
@@ -66,15 +66,15 @@ abstract class ConditionAbstract implements ConditionInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $operatorList the list of comparison operator values, as entered in the condition parameter form
|
||||
* @param array $operatorList the list of comparison operator values, as entered in the condition parameter form
|
||||
* @param string $parameterName the name of the parameter to check
|
||||
*
|
||||
* @return $this
|
||||
*
|
||||
* @throws \Thelia\Exception\InvalidConditionOperatorException if the operator value is not in the allowed value
|
||||
*/
|
||||
protected function checkComparisonOperatorValue($operatorList, $parameterName) {
|
||||
|
||||
protected function checkComparisonOperatorValue($operatorList, $parameterName)
|
||||
{
|
||||
$isOperator1Legit = $this->isOperatorLegit(
|
||||
$operatorList[$parameterName],
|
||||
$this->availableOperators[$parameterName]
|
||||
|
||||
@@ -139,7 +139,7 @@ class ForSomeCustomers extends ConditionAbstract
|
||||
if (null !== $custList = CustomerQuery::create()->findPks($custIds)) {
|
||||
|
||||
/** @var Customer $cust */
|
||||
foreach($custList as $cust) {
|
||||
foreach ($custList as $cust) {
|
||||
$custStrList .= $cust->getLastname() . ' ' . $cust->getFirstname() . ' ('.$cust->getRef().'), ';
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ class MatchBillingCountries extends AbstractMatchCountries
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
protected function getSummaryLabel($cntryStrList, $i18nOperator) {
|
||||
|
||||
protected function getSummaryLabel($cntryStrList, $i18nOperator)
|
||||
{
|
||||
return $this->translator->trans(
|
||||
'Only if order billing country is %op% <strong>%countries_list%</strong>', [
|
||||
'%countries_list%' => $cntryStrList,
|
||||
@@ -79,7 +79,8 @@ class MatchBillingCountries extends AbstractMatchCountries
|
||||
);
|
||||
}
|
||||
|
||||
protected function getFormLabel() {
|
||||
protected function getFormLabel()
|
||||
{
|
||||
return $this->translator->trans(
|
||||
'Billing coutry is', [], 'condition'
|
||||
);
|
||||
|
||||
@@ -69,8 +69,8 @@ class MatchDeliveryCountries extends AbstractMatchCountries
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
protected function getSummaryLabel($cntryStrList, $i18nOperator) {
|
||||
|
||||
protected function getSummaryLabel($cntryStrList, $i18nOperator)
|
||||
{
|
||||
return $this->translator->trans(
|
||||
'Only if order shipping country is %op% <strong>%countries_list%</strong>', [
|
||||
'%countries_list%' => $cntryStrList,
|
||||
@@ -79,7 +79,8 @@ class MatchDeliveryCountries extends AbstractMatchCountries
|
||||
);
|
||||
}
|
||||
|
||||
protected function getFormLabel() {
|
||||
protected function getFormLabel()
|
||||
{
|
||||
return $this->translator->trans(
|
||||
'Delivery coutry is', [], 'condition'
|
||||
);
|
||||
|
||||
@@ -26,8 +26,8 @@ class MatchForEveryone extends ConditionAbstract
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function __construct(FacadeInterface $facade) {
|
||||
|
||||
public function __construct(FacadeInterface $facade)
|
||||
{
|
||||
// Define the allowed comparison operators
|
||||
$this->availableOperators = [];
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace Thelia\Condition\Implementation;
|
||||
|
||||
use Thelia\Condition\Operators;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionOperatorException;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,11 +14,7 @@ namespace Thelia\Condition\Implementation;
|
||||
|
||||
use Thelia\Condition\Operators;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Exception\InvalidConditionOperatorException;
|
||||
use Thelia\Exception\InvalidConditionValueException;
|
||||
use Thelia\Model\Category;
|
||||
use Thelia\Model\CategoryImageQuery;
|
||||
use Thelia\Model\CategoryQuery;
|
||||
use Thelia\Tools\DateTimeFormat;
|
||||
|
||||
/**
|
||||
@@ -59,6 +55,8 @@ class StartDate extends ConditionAbstract
|
||||
*/
|
||||
public function setValidatorsFromForm(array $operators, array $values)
|
||||
{
|
||||
$this->checkComparisonOperatorValue($operators, self::START_DATE);
|
||||
|
||||
if (! isset($values[self::START_DATE])) {
|
||||
$values[self::START_DATE] = time();
|
||||
}
|
||||
@@ -76,8 +74,7 @@ class StartDate extends ConditionAbstract
|
||||
}
|
||||
|
||||
$timestamp = $date->getTimestamp();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$timestamp = $values[self::START_DATE];
|
||||
}
|
||||
|
||||
@@ -147,7 +144,8 @@ class StartDate extends ConditionAbstract
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
private function getDateFormat() {
|
||||
private function getDateFormat()
|
||||
{
|
||||
return DateTimeFormat::getInstance($this->facade->getRequest())->getFormat("date");
|
||||
}
|
||||
|
||||
@@ -177,8 +175,7 @@ class StartDate extends ConditionAbstract
|
||||
$date->setTimestamp($this->values[self::START_DATE]);
|
||||
|
||||
$strDate = $date->format($this->getDateFormat());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$strDate = '';
|
||||
}
|
||||
|
||||
|
||||
@@ -25,25 +25,32 @@ return array(
|
||||
'Administrator ID not found' => 'Administrator ID not found',
|
||||
'Advertise this product as new' => 'Advertise this product as new',
|
||||
'Alerts' => 'Alerts',
|
||||
'All countries' => 'All countries',
|
||||
'All shipping methods' => 'All shipping methods',
|
||||
'Alpha code 2 *' => 'Alpha code 2 *',
|
||||
'Alpha code 3 *' => 'Alpha code 3 *',
|
||||
'Apply exchange rates on price in %sym' => 'Apply exchange rates on price in %sym',
|
||||
'At least one of cart products categories is %op% <strong>%categories_list%</strong>' => 'At least one of cart products categories is %op% <strong>%categories_list%</strong>',
|
||||
'Attribute ID:Attribute AV ID' => 'Attribute ID:Attribute AV ID',
|
||||
'Auth mode' => 'Auth mode',
|
||||
'Available quantity' => 'Available quantity',
|
||||
'Available quantity *' => 'Available quantity *',
|
||||
'Available shipping zones' => 'Available shipping zones',
|
||||
'Bad tax list JSON' => 'Bad tax list JSON',
|
||||
'Billing country condition' => 'Pays de facturation',
|
||||
'Billing country' => 'Billing country',
|
||||
'Billing coutry is' => 'Le pays de facturation est',
|
||||
'Business ID' => 'Business ID',
|
||||
'By cart total amount' => 'By cart total amount',
|
||||
'Cannot find a default country. Please define one.' => 'Cannot find a default country. Please define one.',
|
||||
'Cannot find the shop country. Please select a shop country.' => 'Cannot find the shop country. Please select a shop country.',
|
||||
'Cannot instanciante module "%name%": the namespace is null. Maybe the model is not loaded ?' => 'Cannot instanciante module "%name%": the namespace is null. Maybe the model is not loaded ?',
|
||||
'Cart item count condition' => 'Cart item count condition',
|
||||
'Cart contains at least a product %op% <strong>%products_list%</strong>' => 'Cart contains at least a product %op% <strong>%products_list%</strong>',
|
||||
'Cart contains categories condition' => 'Cart contains categories condition',
|
||||
'Cart contains specific products' => 'Cart contains specific products',
|
||||
'Cart item count' => 'Cart item count',
|
||||
'Cart item count is' => 'Cart item count is',
|
||||
'Cart total amount' => 'Cart total amount',
|
||||
'Cart total amount is' => 'Cart total amount is',
|
||||
'Catalog' => 'Catalog',
|
||||
'Category title *' => 'Category title *',
|
||||
'Cellphone' => 'Cellphone',
|
||||
'Chapo' => 'Chapo',
|
||||
@@ -61,22 +68,24 @@ return array(
|
||||
'Country ID not found' => 'Country ID not found',
|
||||
'Country area' => 'Country area',
|
||||
'Country title *' => 'Country title *',
|
||||
'Coupon %code is expired.' => 'Coupon %code is expired.',
|
||||
'Critical' => 'Critical',
|
||||
'Current Password' => 'Current Password',
|
||||
'Customer is %op% <strong>%customer_list%</strong>' => 'Customer is %op% <strong>%customer_list%</strong>',
|
||||
'Date \'%date\' is invalid, please enter a valid date using %fmt format' => 'Date \'%date\' is invalid, please enter a valid date using %fmt format',
|
||||
'Debug' => 'Debug',
|
||||
'Decimal places' => 'Decimal places',
|
||||
'Default folder *' => 'Default folder *',
|
||||
'Default product category *' => 'Default product category *',
|
||||
'Default product sale element' => 'Default product sale element',
|
||||
'Deleting document for %id% with parent id %parentId%' => 'Deleting document for %id% with parent id %parentId%',
|
||||
'Deleting image for %id% with parent id %parentId%' => 'Deleting image for %id% with parent id %parentId%',
|
||||
'Delivery country condition' => 'Pays de livraison',
|
||||
'Delivery country' => 'Delivery country',
|
||||
'Delivery coutry is' => 'Le pays de livraison est',
|
||||
'Delivery module ID not found' => 'Delivery module ID not found',
|
||||
'Description' => 'Description',
|
||||
'Detailed description' => 'Detailed description',
|
||||
'Disabled' => 'Disabled',
|
||||
'Discount amount' => 'Discount amount',
|
||||
'Document deleted successfully' => 'Document deleted successfully',
|
||||
'Document position updated' => 'Document position updated',
|
||||
'EAN Code' => 'EAN Code',
|
||||
@@ -103,11 +112,18 @@ return array(
|
||||
'First Name' => 'First Name',
|
||||
'Firstname' => 'Firstname',
|
||||
'Fixed Amount Discount' => 'Fixed Amount Discount',
|
||||
'Fixed amount discount for selected attribute values' => 'Fixed amount discount for selected attribute values',
|
||||
'Fixed amount discount for selected categories' => 'Fixed amount discount for selected categories',
|
||||
'Fixed amount discount for selected products' => 'Fixed amount discount for selected products',
|
||||
'Folder' => 'Folder',
|
||||
'Folder title *' => 'Folder title *',
|
||||
'For one ore more customers' => 'For one ore more customers',
|
||||
'Free product when buying one or more selected products' => 'Free product when buying one or more selected products',
|
||||
'Full Name' => 'Full Name',
|
||||
'Greater than' => 'Greater than',
|
||||
'Greater than or equals' => 'Greater than or equals',
|
||||
'HTML Message' => 'HTML Message',
|
||||
'Home' => 'Home',
|
||||
'Host' => 'Host',
|
||||
'I would like to receive the newsletter or the latest news.' => 'I would like to receive the newsletter or the latest news.',
|
||||
'ISO 4217 code *' => 'ISO 4217 code *',
|
||||
@@ -140,6 +156,7 @@ return array(
|
||||
'Loop must implements one of the following interfaces : `PropelSearchLoopInterface`, `ArraySearchLoopInterface`' => 'Loop must implements one of the following interfaces : `PropelSearchLoopInterface`, `ArraySearchLoopInterface`',
|
||||
'Loop type \'%type\' is not defined.' => 'Loop type \'%type\' is not defined.',
|
||||
'Make this address as my primary address' => 'Make this address as my primary address',
|
||||
'Maximum usage count reached for coupon %code' => 'Maximum usage count reached for coupon %code',
|
||||
'Message subject' => 'Message subject',
|
||||
'Meta Description' => 'Meta Description',
|
||||
'Meta Keywords' => 'Meta Keywords',
|
||||
@@ -170,19 +187,30 @@ return array(
|
||||
'Order address ID not found' => 'Order address ID not found',
|
||||
'Order ref. %ref is now unpaid.' => 'Order ref. %ref is now unpaid.',
|
||||
'Order ref. %ref, ID %id has been successfully paid.' => 'Order ref. %ref, ID %id has been successfully paid.',
|
||||
'Overall' => 'Overall',
|
||||
'Page Title' => 'Page Title',
|
||||
'Parent category *' => 'Parent category *',
|
||||
'Parent folder *' => 'Parent folder *',
|
||||
'Password' => 'Password',
|
||||
'Password *' => 'Password *',
|
||||
'Password confirmation' => 'Password confirmation',
|
||||
'Percent Discount' => 'Percent Discount',
|
||||
'Per customer' => 'Per customer',
|
||||
'Percentage discount for selected attribute values' => 'Percentage discount for selected attribute values',
|
||||
'Percentage discount for selected categories' => 'Percentage discount for selected categories',
|
||||
'Percentage discount for selected products' => 'Percentage discount for selected products',
|
||||
'Percentage of the product price' => 'Percentage of the product price',
|
||||
'Phone' => 'Phone',
|
||||
'Please accept the Terms and conditions in order to register.' => 'Please accept the Terms and conditions in order to register.',
|
||||
'Please check your input: %error' => 'Please check your input: %error',
|
||||
'Please enter your email address' => 'Please enter your email address',
|
||||
'Please enter your password' => 'Please enter your password',
|
||||
'Please select a category' => 'Please select a category',
|
||||
'Please select an attribute' => 'Please select an attribute',
|
||||
'Please select at least one attribute value' => 'Please select at least one attribute value',
|
||||
'Please select at least one category' => 'Please select at least one category',
|
||||
'Please select at least one product' => 'Please select at least one product',
|
||||
'Please select the category of the offred product' => 'Please select the category of the offred product',
|
||||
'Please select the offered product' => 'Please select the offered product',
|
||||
'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Please specify either \'path\' or \'file\' parameter in {url} function.',
|
||||
'Port' => 'Port',
|
||||
'Post Scriptum' => 'Post Scriptum',
|
||||
@@ -260,6 +288,9 @@ return array(
|
||||
'Text Message' => 'Text Message',
|
||||
'The TaxEngine should be passed to this form before using it.' => 'The TaxEngine should be passed to this form before using it.',
|
||||
'The cart item count should match the condition' => 'The cart item count should match the condition',
|
||||
'The coupon applies if the cart contains at least one product of the selected categories' => 'The coupon applies if the cart contains at least one product of the selected categories',
|
||||
'The coupon applies if the cart contains at least one product of the specified product list' => 'The coupon applies if the cart contains at least one product of the specified product list',
|
||||
'The coupon applies to some customers only' => 'The coupon applies to some customers only',
|
||||
'The coupon applies to the selected delivery countries' => 'Ce code promo s\'applique seulement aux pays de facturation sélectionnés',
|
||||
'The coupon is valid after a given date' => 'Le code promo est valide seulement à partir d\'une certaine date',
|
||||
'The image which replaces an undefined country flag (%file) was not found. Please check unknown-flag-path configuration variable, and check that the image exists.' => 'The image which replaces an undefined country flag (%file) was not found. Please check unknown-flag-path configuration variable, and check that the image exists.',
|
||||
@@ -267,7 +298,14 @@ return array(
|
||||
'This category is online.' => 'This category is online.',
|
||||
'This condition is always true' => 'This condition is always true',
|
||||
'This content is online.' => 'This content is online.',
|
||||
'This coupon adds a free product to the cart if one of the selected products is in the cart.' => 'This coupon adds a free product to the cart if one of the selected products is in the cart.',
|
||||
'This coupon does not exists' => 'This coupon does not exists',
|
||||
'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon will offert a flat percentage off a shopper\'s entire order (not applied to shipping costs or tax rates). If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon will offert a flat percentage off a shopper\'s entire order (not applied to shipping costs or tax rates). If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This coupon will subtracts a set amount from the total cost of an order. If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'This coupon will subtracts a set amount from the total cost of an order. If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
'This email already exists.' => 'This email already exists.',
|
||||
@@ -298,6 +336,8 @@ return array(
|
||||
'Username *' => 'Username *',
|
||||
'Valid only from %date% to the coupon expiration date' => 'Valide à partir du %date% jusqu\'à la date d\'expiration',
|
||||
'Value' => 'Value',
|
||||
'Value %val for Discount Amount is invalid. Please enter a positive value.' => 'Value %val for Discount Amount is invalid. Please enter a positive value.',
|
||||
'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.' => 'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.',
|
||||
'Value *' => 'Value *',
|
||||
'Warnings' => 'Warnings',
|
||||
'Weight' => 'Weight',
|
||||
|
||||
@@ -25,23 +25,32 @@ return array(
|
||||
'Administrator ID not found' => 'ID de l\'administrateur not trouvé',
|
||||
'Advertise this product as new' => 'Afficher ce produit comme nouveau',
|
||||
'Alerts' => 'Alertes',
|
||||
'All countries' => 'Tous les pays',
|
||||
'All shipping methods' => 'Tous les modes de livraison',
|
||||
'Alpha code 2 *' => 'Code Alpha 2 *',
|
||||
'Alpha code 3 *' => 'Code Alpha 3 *',
|
||||
'Apply exchange rates on price in %sym' => 'Appliquer le taux de change sur le prix en %sym',
|
||||
'At least one of cart products categories is %op% <strong>%categories_list%</strong>' => 'Au moins une des catégories des produits présents dans le panier %op% <strong>%categories_list%</strong> ',
|
||||
'Attribute ID:Attribute AV ID' => 'Déclinaison ID : Valeur de déclinaison ID',
|
||||
'Auth mode' => 'Mode d\'authentification',
|
||||
'Available quantity' => 'Quantité disponible',
|
||||
'Available quantity *' => 'Quantité disponible *',
|
||||
'Available shipping zones' => 'Zones de livraison disponibles',
|
||||
'Bad tax list JSON' => 'Mauvais JSON de la liste des taxes',
|
||||
'Billing country' => 'Pays de livraison',
|
||||
'Billing coutry is' => 'Pays de facturation',
|
||||
'Business ID' => 'ID du business',
|
||||
'By cart total amount' => 'Montant total du panier',
|
||||
'Cannot find a default country. Please define one.' => 'Impossible de trouver un pays par défaut. Veuillez en définir un.',
|
||||
'Cannot find the shop country. Please select a shop country.' => 'Impossible de trouver le pays du magasin. Veuillez en sélectionner un.',
|
||||
'Cannot instanciante module "%name%": the namespace is null. Maybe the model is not loaded ?' => 'Ne peut instancier le module "%name%": le namespace est null. Peut-être que le modèle n\'est pas chargé ?',
|
||||
'Cart item count condition' => 'Nombre d\'articles dans le panier',
|
||||
'Cart contains at least a product %op% <strong>%products_list%</strong>' => 'Le panier contient au moins un produit %op% <strong>%products_list%</strong> ',
|
||||
'Cart contains categories condition' => 'Valable si le panier contient/ne contient pas des produits appartenant à certaines catégories',
|
||||
'Cart contains specific products' => 'Valable si le panier contient certains produits',
|
||||
'Cart item count' => 'Nombre d\'artciles dans le panier',
|
||||
'Cart item count is' => 'Le nombre d\'articles dans le panier est',
|
||||
'Cart total amount' => 'Montant total du panier',
|
||||
'Cart total amount is' => 'Le total du panier est',
|
||||
'Catalog' => 'Catalogue',
|
||||
'Category title *' => 'Titre de la catégorie *',
|
||||
'Cellphone' => 'Numéro de portable',
|
||||
'Chapo' => 'Chapeau',
|
||||
@@ -59,20 +68,24 @@ return array(
|
||||
'Country ID not found' => 'ID du pays non trouvé',
|
||||
'Country area' => 'Zone du pays',
|
||||
'Country title *' => 'Pays *',
|
||||
'Coupon %code is expired.' => 'La date limite d\'utilisation du coupon %code est dépassée.',
|
||||
'Critical' => 'Critique',
|
||||
'Current Password' => 'Mot de passe actuel.',
|
||||
'Customer is %op% <strong>%customer_list%</strong>' => 'Le client est %op% <strong>%customer_list%</strong> ',
|
||||
'Date \'%date\' is invalid, please enter a valid date using %fmt format' => 'La date \'%date\' est incorrecte, merci d\'indiquer une date au format %fmt',
|
||||
'Debug' => 'Debug',
|
||||
'Decimal places' => 'Nombre de chiffres après la virgule',
|
||||
'Default folder *' => 'Dossier par défaut *',
|
||||
'Default product category *' => 'Catégorie du produit par défaut *',
|
||||
'Default product sale element' => 'Product Sale Element par défaut',
|
||||
'Deleting document for %id% with parent id %parentId%' => 'Suppression du document %id% avec l\'ID parent %parentId%',
|
||||
'Deleting image for %id% with parent id %parentId%' => 'Suppression de l\'image %id% avec l\'ID parent %parentId%',
|
||||
'Delivery country' => 'Pays de livraison',
|
||||
'Delivery coutry is' => 'Le pays de livraison est',
|
||||
'Delivery module ID not found' => 'Id du module de livraison non trouvé',
|
||||
'Description' => 'Description',
|
||||
'Detailed description' => 'Description détaillée',
|
||||
'Disabled' => 'Désactivé',
|
||||
'Discount amount' => 'Montant de la remise',
|
||||
'Document deleted successfully' => 'Le document a été supprimé.',
|
||||
'Document position updated' => 'La position du document a été modfiée',
|
||||
'EAN Code' => 'Code EAN',
|
||||
@@ -81,7 +94,7 @@ return array(
|
||||
'Emergency' => 'Urgence',
|
||||
'Enable remote SMTP use' => 'Activer l\'utilisation d\'un serveur SMTP distant.',
|
||||
'Encryption' => 'Chiffrement',
|
||||
'Equals' => 'Egal à',
|
||||
'Equal to' => 'Egal à',
|
||||
'Error during %action process : %error. Exception was %exc' => 'Erreur lors de %action: %error. Exception: %exc ',
|
||||
'Error occured while processing order ref. %ref, ID %id: %err' => 'Un erreur est survenue paedant le traitement de la commande ref. %ref, ID %id; %err',
|
||||
'Errors' => 'Erreurs',
|
||||
@@ -99,11 +112,18 @@ return array(
|
||||
'First Name' => 'Prénom',
|
||||
'Firstname' => 'Prénom',
|
||||
'Fixed Amount Discount' => 'Remise d\'un montant fixe',
|
||||
'Fixed amount discount for selected attribute values' => 'Remise constante pour certaines valeurs de déclinaison',
|
||||
'Fixed amount discount for selected categories' => 'Remise fixe pour certaines catégories',
|
||||
'Fixed amount discount for selected products' => 'Remise fixe pour certains produits',
|
||||
'Folder' => 'Dossier',
|
||||
'Folder title *' => 'Titre du dossier *',
|
||||
'For one ore more customers' => 'Valable pour un ou plusieurs clients',
|
||||
'Free product when buying one or more selected products' => 'Un produit offert pour l\'achat d\'un ou plusieurs produits',
|
||||
'Full Name' => 'Nom complet',
|
||||
'Greater than' => 'Supérieur à',
|
||||
'Greater than or equals' => 'Supérieur ou égal à',
|
||||
'HTML Message' => 'Message au format HTML',
|
||||
'Home' => 'Accueil',
|
||||
'Host' => 'Nom de l\'hôte',
|
||||
'I would like to receive the newsletter or the latest news.' => 'Je souhaite recevoir la lettre d\'information ou les dernières actualités.',
|
||||
'ISO 4217 code *' => 'Code ISO 4217 *',
|
||||
@@ -136,6 +156,7 @@ return array(
|
||||
'Loop must implements one of the following interfaces : `PropelSearchLoopInterface`, `ArraySearchLoopInterface`' => 'Une boucle doit implémenter au moins une de ces interfaces : `PropelSearchLoopInterface`, `ArraySearchLoopInterface`',
|
||||
'Loop type \'%type\' is not defined.' => 'La boucle de type \'%type\' n\'existe pas.',
|
||||
'Make this address as my primary address' => 'Choisir cette adresse comme adresse par défaut',
|
||||
'Maximum usage count reached for coupon %code' => 'Le nombre maximum d\'utilisation pour le coupon %code est dépassé.',
|
||||
'Message subject' => 'Sujet',
|
||||
'Meta Description' => 'Meta description',
|
||||
'Meta Keywords' => 'Meta keywords',
|
||||
@@ -157,26 +178,39 @@ return array(
|
||||
'No module found for code \'%item\'' => 'Aucun module trouvé pour \'%item\' ',
|
||||
'No pagination currently defined for loop name \'%name\'' => 'La pagination n\'est pas définie pour la boucle \'%name\'',
|
||||
'No, I am a new customer.' => 'Non, je suis un nouveau client.',
|
||||
'Not equals' => 'Différent de',
|
||||
'Not equal to' => 'Différent de',
|
||||
'Not found' => 'Non trouvé.',
|
||||
'Not in' => 'Non compris dans',
|
||||
'Notices' => 'Notices',
|
||||
'Only if order billing country is %op% <strong>%countries_list%</strong>' => 'Si le pays de facturation %op% <strong>%countries_list%</strong> ',
|
||||
'Only if order shipping country is %op% <strong>%countries_list%</strong>' => 'Si le pays de livraison %op% <strong>%countries_list%</strong> ',
|
||||
'Order address ID not found' => 'ID de l\'adresse de la commande non trouvé',
|
||||
'Order ref. %ref is now unpaid.' => 'La commande %ref, ID %id est désormais non payée',
|
||||
'Order ref. %ref, ID %id has been successfully paid.' => 'La commande ref. %ref, ID %id a été correctement payée',
|
||||
'Overall' => 'Pour tous les clients',
|
||||
'Page Title' => 'Titre de la page',
|
||||
'Parent category *' => 'Catégorie parente *',
|
||||
'Parent folder *' => 'Dossier parent *',
|
||||
'Password' => 'Mot de passe',
|
||||
'Password *' => 'Mot de passe *',
|
||||
'Password confirmation' => 'Confirmation du mot de passe.',
|
||||
'Percent Discount' => 'Remise en pourcentage de la commande',
|
||||
'Per customer' => 'Par client',
|
||||
'Percentage discount for selected attribute values' => 'Remise en pourcentage pour certaines valeurs de déclinaison',
|
||||
'Percentage discount for selected categories' => 'Remise en pourcentage pour certaines catégories',
|
||||
'Percentage discount for selected products' => 'Remise en pourcentage pour certains produits',
|
||||
'Percentage of the product price' => 'Pourcentage du prix du produit',
|
||||
'Phone' => 'Téléphone',
|
||||
'Please accept the Terms and conditions in order to register.' => 'Veuillez accepter les termes et conditions pour vous inscrire.',
|
||||
'Please check your input: %error' => 'Merci de vérifier votre saisie: %error',
|
||||
'Please enter your email address' => 'Renseignez votre adresse mail',
|
||||
'Please enter your password' => 'Entrez votre mot de passe.',
|
||||
'Please select a category' => 'Merci de choisir une catégorie',
|
||||
'Please select an attribute' => 'Merci de choisir une déclinaison',
|
||||
'Please select at least one attribute value' => 'Merci de choisir au moins une valeur de déclinaison',
|
||||
'Please select at least one category' => 'Merci de choisir au moins une catégorie.',
|
||||
'Please select at least one product' => 'Merci de choisir au moins un produit',
|
||||
'Please select the category of the offred product' => 'Merci de choisir la catégorie du produit offert',
|
||||
'Please select the offered product' => 'Merci de choisir le produit offert',
|
||||
'Please specify either \'path\' or \'file\' parameter in {url} function.' => 'Veuillez spécifier soit le paramètre \'chemin\' ou \'fichier\' dans la fonction {url}',
|
||||
'Port' => 'Port',
|
||||
'Post Scriptum' => 'Post-scriptum',
|
||||
@@ -230,6 +264,7 @@ return array(
|
||||
'Sorry, you are not allowed to perform this action.' => 'Désolé, vous n\'êtes pas autorisé à réaliser cette action.',
|
||||
'Sorry, you\'re not allowed to perform this action' => 'Désolé, vous n\'êtes pas autorisé à réaliser cette action.',
|
||||
'Source IP' => 'IP source',
|
||||
'Start date' => 'Date de début de validité',
|
||||
'Stats on %month/%year' => 'Statistiques pour %month/%year ',
|
||||
'Store configuration failed.' => 'Erreur de configuration du magasin.',
|
||||
'Store email address' => 'Adresse mail du magasin',
|
||||
@@ -253,12 +288,24 @@ return array(
|
||||
'Text Message' => 'Message au format texte',
|
||||
'The TaxEngine should be passed to this form before using it.' => 'Le moteur de taxe doit être passé au formulaire avant d\'être utilisé.',
|
||||
'The cart item count should match the condition' => 'Le nombre d\'articles dans le panier doit vérifier la condition',
|
||||
'The coupon applies if the cart contains at least one product of the selected categories' => 'Le code promo est valable si le panier contient/ne contient pas des produits appartenant aux catégories sélectionnées',
|
||||
'The coupon applies if the cart contains at least one product of the specified product list' => 'Le code promo est valable si le panier contient/ne contient pas au moins un des produits selectionnés',
|
||||
'The coupon applies to some customers only' => 'Ce code promo est valable pour les clients sélectionnés',
|
||||
'The coupon applies to the selected delivery countries' => 'Ce code promo s\'applique pour les pays de livraison sélectionnés',
|
||||
'The coupon is valid after a given date' => 'Le code promo est valide à partir de cette date',
|
||||
'The image which replaces an undefined country flag (%file) was not found. Please check unknown-flag-path configuration variable, and check that the image exists.' => 'L\'image qui remplace un drapeau de pays manquant (%file) n\'a pas été trouvée. Merci de vérifier la variable de configuration unknown-flag-path.',
|
||||
'The loop name \'%name\' is already defined in %className class' => 'La boucle \'%name\' est déjà définir dans la classe %className',
|
||||
'This category is online.' => 'Cette catégorie est en ligne.',
|
||||
'This condition is always true' => 'Cette condition est troujours vérifiée',
|
||||
'This content is online.' => 'Ce contenu est en ligne.',
|
||||
'This coupon adds a free product to the cart if one of the selected products is in the cart.' => 'Ce coupon ajoute un produit gratuit (sous forme de remise) au panier, si un des produits indiqués est présent dans le panier.',
|
||||
'This coupon does not exists' => 'Ce code promo n\'existe pas',
|
||||
'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire du total de la commande le pourcentage indiqué du prix de chacun des produits appartenant aux catégories sélectionnées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.',
|
||||
'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire du total de la commande le pourcentage indiqué du prix de chacun des produits ayant au moins une des valeurs de déclinaisons indiquées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.',
|
||||
'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire du total de la commande le pourcentage indiqué du prix de chacun des produits sélectionnés. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.',
|
||||
'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande pour chacun des produits appartenant aux catégories sélectionnées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.',
|
||||
'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande pour chacun des produits ayant au moins une des valeurs de déclinaisons indiquées. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.',
|
||||
'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande pour chacun des produits sélectionnés. Si la remise est supérieure au total de la commande, seul le port sera dû, à moins que le code promo n\'offre aussi le port.',
|
||||
'This coupon will offert a flat percentage off a shopper\'s entire order (not applied to shipping costs or tax rates). If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le pourcentage indiqué du total de la commande, hors frais de port et taxes. Si la remise est supérieur au total de la commande, seul le port sera facturé, à moins que le code promo n\'offre aussi les frais port.',
|
||||
'This coupon will subtracts a set amount from the total cost of an order. If the discount is greater than the total order corst, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.' => 'Ce code promo retire le montant indiqué du total de la commande, hors frais de port et taxes. Si la remise est supérieur au total de la commande, seul le port sera facturé, à moins que le code promo n\'offre aussi les frais port.',
|
||||
'This email already exists.' => 'Cette adresse email existe déjà',
|
||||
@@ -287,7 +334,10 @@ return array(
|
||||
'Unsupported magic method %name. only getArgname() is supported.' => 'La méthode magique %name n\'est pas supportée. Seule get<argname>() est supporté..',
|
||||
'Username' => 'Nom d\'utilisateur',
|
||||
'Username *' => 'Nom d\'utilisateur *',
|
||||
'Valid only from %date% to the coupon expiration date' => 'Valide à partir de %date% jusqu\'à la date d\'expoiration',
|
||||
'Value' => 'Valeur',
|
||||
'Value %val for Discount Amount is invalid. Please enter a positive value.' => 'La valeur %val pour le montant de la remise est invalide. Merci d\'indiquer une valeur positive.',
|
||||
'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.' => 'La valeur %val pour le pourcentage de remise est invalide. Merci d\'indiquer un nombre entre 1 et 100',
|
||||
'Value *' => 'Valeur *',
|
||||
'Warnings' => 'Avertissements',
|
||||
'Weight' => 'Poids',
|
||||
@@ -299,6 +349,7 @@ return array(
|
||||
'Your current password does not match.' => 'Votre mot de passe actuel ne correspond pas',
|
||||
'Zip code' => 'Code postal',
|
||||
'date format' => 'Format de date',
|
||||
'decimal separator' => 'Séparateur décimal',
|
||||
'delivery module %s is not a Thelia\Module\DeliveryModuleInterface' => 'le module de livraison %s n\'est pas un Thelia\Module\DeliveryModuleInterface',
|
||||
'language locale' => 'Langue locale',
|
||||
'mailing system modification' => 'Modification du système d\'envoi de mail.',
|
||||
@@ -308,5 +359,6 @@ return array(
|
||||
'permanent discount (in percent)' => 'Remise permanente (en pourcentage)',
|
||||
'quantity value is not valid' => 'la valeur de la quantité n\'est pas valide',
|
||||
'this product id does not exists : %d' => 'l\'id du produit %d n\'existe pas',
|
||||
'thousands separator' => 'Séparateur des milliers',
|
||||
'time format' => 'Format d\'heure',
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<command class="Thelia\Command\ModuleGenerateCommand"/>
|
||||
<command class="Thelia\Command\ModuleGenerateModelCommand"/>
|
||||
<command class="Thelia\Command\ModuleGenerateSqlCommand"/>
|
||||
<command class="Thelia\Command\ModuleRefreshCommand"/>
|
||||
<command class="Thelia\Command\ModuleActivateCommand"/>
|
||||
<command class="Thelia\Command\ModuleDeactivateCommand"/>
|
||||
<command class="Thelia\Command\CreateAdminUser"/>
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
<service id="response.listener" class="Thelia\Core\EventListener\ResponseListener">
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
|
||||
<service id="session.listener" class="Thelia\Core\EventListener\SessionListener">
|
||||
<tag name="kernel.event_subscriber"/>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
</config>
|
||||
|
||||
@@ -4,32 +4,75 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
|
||||
|
||||
|
||||
<services>
|
||||
|
||||
|
||||
<!-- Coupon module -->
|
||||
|
||||
<service id="thelia.facade" class="Thelia\Coupon\BaseFacade">
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.manager" class="Thelia\Coupon\CouponManager">
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.factory" class="Thelia\Coupon\CouponFactory">
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
|
||||
<!-- Coupon types -->
|
||||
|
||||
<service id="thelia.coupon.type.remove_x_amount" class="Thelia\Coupon\Type\RemoveXAmount">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_x_percent" class="Thelia\Coupon\Type\RemoveXPercent">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_amount_on_categories" class="Thelia\Coupon\Type\RemoveAmountOnCategories">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_percentage_on_categories" class="Thelia\Coupon\Type\RemovePercentageOnCategories">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_amount_on_products" class="Thelia\Coupon\Type\RemoveAmountOnProducts">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_percentage_on_products" class="Thelia\Coupon\Type\RemovePercentageOnProducts">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_percentage_on_products" class="Thelia\Coupon\Type\RemovePercentageOnProducts">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_amount_on_attribute_av" class="Thelia\Coupon\Type\RemoveAmountOnAttributeValues">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.remove_percentage_on_attribute_av" class="Thelia\Coupon\Type\RemovePercentageOnAttributeValues">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<service id="thelia.coupon.type.free_product" class="Thelia\Coupon\Type\FreeProduct">
|
||||
<argument type="service" id="thelia.facade" />
|
||||
<tag name="thelia.coupon.addCoupon"/>
|
||||
</service>
|
||||
|
||||
<!-- Condition module -->
|
||||
|
||||
<service id="thelia.condition.factory" class="Thelia\Condition\ConditionFactory">
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
@@ -83,5 +126,4 @@
|
||||
</service>
|
||||
|
||||
</services>
|
||||
|
||||
</config>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<default key="_controller">Thelia\Controller\Admin\HomeController::defaultAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.home.view" path="/admin/latest-thelia-version">
|
||||
<route id="admin.home.latestVersion" path="/admin/latest-thelia-version">
|
||||
<default key="_controller">Thelia\Controller\Admin\HomeController::getLatestTheliaVersion</default>
|
||||
</route>
|
||||
|
||||
@@ -466,7 +466,7 @@
|
||||
<default key="_controller">Thelia\Controller\Admin\ContentController::createAction</default>
|
||||
</route>
|
||||
|
||||
<route id="admin.content.update" path="admin/content/update/{content_id}">
|
||||
<route id="admin.content.update" path="/admin/content/update/{content_id}">
|
||||
<default key="_controller">Thelia\Controller\Admin\ContentController::updateAction</default>
|
||||
<requirement key="content_id">\d+</requirement>
|
||||
</route>
|
||||
|
||||
@@ -23,7 +23,6 @@ use Thelia\Model\ConfigQuery;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Thelia\Core\Security\Exception\AuthenticationException;
|
||||
use Thelia\Tools\URL;
|
||||
use Thelia\Tools\Redirect;
|
||||
use Thelia\Model\AdminLog;
|
||||
|
||||
use Thelia\Model\LangQuery;
|
||||
|
||||
@@ -169,7 +169,8 @@ class CategoryController extends AbstractSeoCrudController
|
||||
return array(
|
||||
'category_id' => $this->getRequest()->get('category_id', 0),
|
||||
'folder_id' => $this->getRequest()->get('folder_id', 0),
|
||||
'current_tab' => $this->getRequest()->get('current_tab', 'general')
|
||||
'current_tab' => $this->getRequest()->get('current_tab', 'general'),
|
||||
'page' => $this->getRequest()->get('page', 1)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -182,14 +183,17 @@ class CategoryController extends AbstractSeoCrudController
|
||||
array(
|
||||
'category_order' => $currentOrder,
|
||||
'product_order' => $product_order,
|
||||
'category_id' => $this->getRequest()->get('category_id', 0)
|
||||
'category_id' => $this->getRequest()->get('category_id', 0),
|
||||
'page' => $this->getRequest()->get('page', 1)
|
||||
));
|
||||
}
|
||||
|
||||
protected function redirectToListTemplate()
|
||||
{
|
||||
$category_id = $this->getRequest()->get('category_id', 0);
|
||||
$this->redirectToListTemplateWithId($category_id);
|
||||
$this->redirectToRoute('admin.categories', array(
|
||||
'category_id' => $this->getRequest()->get('category_id', 0),
|
||||
'page' => $this->getRequest()->get('page', 1))
|
||||
);
|
||||
}
|
||||
|
||||
protected function redirectToListTemplateWithId($category_id)
|
||||
|
||||
@@ -20,6 +20,7 @@ use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Form\CountryCreationForm;
|
||||
use Thelia\Form\CountryModificationForm;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\CountryQuery;
|
||||
|
||||
/**
|
||||
@@ -228,7 +229,7 @@ class CountryController extends AbstractCrudController
|
||||
public function toggleDefaultAction()
|
||||
{
|
||||
if (null !== $response = $this->checkAuth($this->resourceCode, array(), AccessManager::UPDATE)) return $response;
|
||||
$content = null;
|
||||
|
||||
if (null !== $country_id = $this->getRequest()->get('country_id')) {
|
||||
$toogleDefaultEvent = new CountryToggleDefaultEvent($country_id);
|
||||
try {
|
||||
@@ -238,7 +239,7 @@ class CountryController extends AbstractCrudController
|
||||
return $this->nullResponse();
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
$content = $ex->getMessage();
|
||||
Tlog::getInstance()->error($ex->getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace Thelia\Controller\Admin;
|
||||
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Router;
|
||||
@@ -25,16 +26,17 @@ use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Coupon\CouponFactory;
|
||||
use Thelia\Coupon\CouponManager;
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Coupon\Type\CouponAbstract;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
use Thelia\Coupon\Type\RemoveXPercent;
|
||||
use Thelia\Form\CouponCreationForm;
|
||||
use Thelia\Form\Exception\FormValidationException;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\Coupon;
|
||||
use Thelia\Model\CouponCountry;
|
||||
use Thelia\Model\CouponModule;
|
||||
use Thelia\Model\CouponQuery;
|
||||
use Thelia\Model\LangQuery;
|
||||
use Thelia\Tools\Rest\ResponseRest;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Control View and Action (Model) via Events
|
||||
@@ -78,11 +80,13 @@ class CouponController extends BaseAdminController
|
||||
$eventToDispatch = TheliaEvents::COUPON_CREATE;
|
||||
|
||||
if ($this->getRequest()->isMethod('POST')) {
|
||||
$this->validateCreateOrUpdateForm(
|
||||
if(null !== $response = $this->validateCreateOrUpdateForm(
|
||||
$eventToDispatch,
|
||||
'created',
|
||||
'creation'
|
||||
);
|
||||
)){
|
||||
return $response;
|
||||
}
|
||||
} else {
|
||||
// If no input for expirationDate, now + 2 months
|
||||
$defaultDate = new \DateTime();
|
||||
@@ -137,12 +141,14 @@ class CouponController extends BaseAdminController
|
||||
|
||||
// Update
|
||||
if ($this->getRequest()->isMethod('POST')) {
|
||||
$this->validateCreateOrUpdateForm(
|
||||
if (null !== $response = $this->validateCreateOrUpdateForm(
|
||||
$eventToDispatch,
|
||||
'updated',
|
||||
'update',
|
||||
$coupon
|
||||
);
|
||||
)) {
|
||||
return $response;
|
||||
}
|
||||
} else {
|
||||
// Display
|
||||
// Prepare the data that will hydrate the form
|
||||
@@ -152,6 +158,21 @@ class CouponController extends BaseAdminController
|
||||
$coupon->getSerializedConditions()
|
||||
);
|
||||
|
||||
$freeShippingForCountries = $freeShippingForModules = [];
|
||||
|
||||
/** @var CouponCountry $item */
|
||||
foreach ($coupon->getFreeShippingForCountries() as $item) {
|
||||
$freeShippingForCountries[] = $item->getCountryId();
|
||||
}
|
||||
|
||||
/** @var CouponModule $item */
|
||||
foreach ($coupon->getFreeShippingForModules() as $item) {
|
||||
$freeShippingForModules[] = $item->getModuleId();
|
||||
}
|
||||
|
||||
if (empty($freeShippingForCountries)) $freeShippingForCountries[] = 0;
|
||||
if (empty($freeShippingForModules)) $freeShippingForModules[] = 0;
|
||||
|
||||
$data = [
|
||||
'code' => $coupon->getCode(),
|
||||
'title' => $coupon->getTitle(),
|
||||
@@ -167,6 +188,9 @@ class CouponController extends BaseAdminController
|
||||
'maxUsage' => $coupon->getMaxUsage(),
|
||||
'conditions' => $conditions,
|
||||
'locale' => $this->getCurrentEditionLocale(),
|
||||
'freeShippingForCountries' => $freeShippingForCountries,
|
||||
'freeShippingForModules' => $freeShippingForModules,
|
||||
'perCustomerUsageCount' => $coupon->getPerCustomerUsageCount(),
|
||||
];
|
||||
|
||||
$args['conditions'] = $this->cleanConditionForTemplate($conditions);
|
||||
@@ -179,6 +203,7 @@ class CouponController extends BaseAdminController
|
||||
}
|
||||
|
||||
$args['couponCode'] = $coupon->getCode();
|
||||
$args['couponType'] = $coupon->getType();
|
||||
$args['availableCoupons'] = $this->getAvailableCoupons();
|
||||
$args['couponInputsHtml'] = $couponManager->drawBackOfficeInputs();
|
||||
$args['urlAjaxAdminCouponDrawInputs'] = $this->getRoute(
|
||||
@@ -455,7 +480,7 @@ class CouponController extends BaseAdminController
|
||||
{
|
||||
// Create the form from the request
|
||||
$couponForm = new CouponCreationForm($this->getRequest());
|
||||
|
||||
$response = null;
|
||||
$message = false;
|
||||
try {
|
||||
// Check the form against conditions violations
|
||||
@@ -479,20 +504,19 @@ class CouponController extends BaseAdminController
|
||||
);
|
||||
|
||||
if ($this->getRequest()->get('save_mode') == 'stay') {
|
||||
$this->redirect(
|
||||
str_replace(
|
||||
'{id}',
|
||||
$couponEvent->getCouponModel()->getId(),
|
||||
$couponForm->getSuccessUrl()
|
||||
)
|
||||
$response = RedirectResponse::create(str_replace(
|
||||
'{id}',
|
||||
$couponEvent->getCouponModel()->getId(),
|
||||
$couponForm->getSuccessUrl()
|
||||
));
|
||||
|
||||
} else {
|
||||
// Redirect to the success URL
|
||||
$response = RedirectResponse::create(
|
||||
URL::getInstance()->absoluteUrl($this->getRoute('admin.coupon.list'))
|
||||
);
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
// Redirect to the success URL
|
||||
$this->redirectToRoute('admin.coupon.list');
|
||||
|
||||
} catch (FormValidationException $ex) {
|
||||
// Invalid data entered
|
||||
$message = $this->createStandardFormValidationErrorMessage($ex);
|
||||
@@ -514,7 +538,7 @@ class CouponController extends BaseAdminController
|
||||
->setGeneralError($message);
|
||||
}
|
||||
|
||||
return $this;
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -557,7 +581,7 @@ class CouponController extends BaseAdminController
|
||||
$condition['serviceId'] = $availableCoupon->getServiceId();
|
||||
$condition['name'] = $availableCoupon->getName();
|
||||
$condition['toolTip'] = $availableCoupon->getToolTip();
|
||||
$condition['inputName'] = $availableCoupon->getInputName();
|
||||
|
||||
$cleanedCoupons[] = $condition;
|
||||
}
|
||||
|
||||
@@ -604,17 +628,23 @@ class CouponController extends BaseAdminController
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this->checkXmlHttpRequest();
|
||||
if (! empty($couponServiceId)) {
|
||||
$this->checkXmlHttpRequest();
|
||||
|
||||
/** @var CouponInterface $coupon */
|
||||
$couponManager = $this->container->get($couponServiceId);
|
||||
/** @var CouponInterface $coupon */
|
||||
$couponManager = $this->container->get($couponServiceId);
|
||||
|
||||
if (!$couponManager instanceof CouponInterface) {
|
||||
$this->pageNotFound();
|
||||
if (!$couponManager instanceof CouponInterface) {
|
||||
$this->pageNotFound();
|
||||
}
|
||||
|
||||
$response = new ResponseRest($couponManager->drawBackOfficeInputs());
|
||||
} else {
|
||||
// Return an empty response if the service ID is not defined
|
||||
// Typically, when the user chooses "Please select a coupon type"
|
||||
$response = new ResponseRest('');
|
||||
}
|
||||
|
||||
$response = new ResponseRest($couponManager->drawBackOfficeInputs());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -656,35 +686,6 @@ class CouponController extends BaseAdminController
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add percentage logic if found in the Coupon post data
|
||||
*
|
||||
* @param array $effects Effect parameters to populate
|
||||
* @param array $extendedInputNames Extended Inputs to manage
|
||||
*
|
||||
* @return array Populated effect with percentage
|
||||
*/
|
||||
protected function addExtendedLogic(array $effects, array $extendedInputNames)
|
||||
{
|
||||
/** @var Request $request */
|
||||
$request = $this->container->get('request');
|
||||
$postData = $request->request;
|
||||
// Validate quantity input
|
||||
|
||||
if ($postData->has(RemoveXPercent::INPUT_EXTENDED__NAME)) {
|
||||
$extentedPostData = $postData->get(RemoveXPercent::INPUT_EXTENDED__NAME);
|
||||
|
||||
foreach ($extendedInputNames as $extendedInputName) {
|
||||
if (isset($extentedPostData[$extendedInputName])) {
|
||||
$inputValue = $extentedPostData[$extendedInputName];
|
||||
$effects[$extendedInputName] = $inputValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed the Coupon Create or Update event with the User inputs
|
||||
*
|
||||
@@ -698,16 +699,15 @@ class CouponController extends BaseAdminController
|
||||
// Get the form field values
|
||||
$data = $form->getData();
|
||||
$serviceId = $data['type'];
|
||||
/** @var CouponInterface $couponManager */
|
||||
$couponManager = $this->container->get($serviceId);
|
||||
$effects = [CouponAbstract::INPUT_AMOUNT_NAME => $data[CouponAbstract::INPUT_AMOUNT_NAME]];
|
||||
$effects = $this->addExtendedLogic($effects, $couponManager->getExtendedInputs());
|
||||
|
||||
/** @var CouponInterface $coupon */
|
||||
$coupon = $this->container->get($serviceId);
|
||||
|
||||
$couponEvent = new CouponCreateOrUpdateEvent(
|
||||
$data['code'],
|
||||
$serviceId,
|
||||
$data['title'],
|
||||
$effects,
|
||||
$coupon->getEffects($data),
|
||||
$data['shortDescription'],
|
||||
$data['description'],
|
||||
$data['isEnabled'],
|
||||
@@ -716,7 +716,10 @@ class CouponController extends BaseAdminController
|
||||
$data['isCumulative'],
|
||||
$data['isRemovingPostage'],
|
||||
$data['maxUsage'],
|
||||
$data['locale']
|
||||
$data['locale'],
|
||||
$data['freeShippingForCountries'],
|
||||
$data['freeShippingForModules'],
|
||||
$data['perCustomerUsageCount']
|
||||
);
|
||||
|
||||
// If Update mode
|
||||
@@ -774,7 +777,10 @@ class CouponController extends BaseAdminController
|
||||
$coupon->getIsCumulative(),
|
||||
$coupon->getIsRemovingPostage(),
|
||||
$coupon->getMaxUsage(),
|
||||
$coupon->getLocale()
|
||||
$coupon->getLocale(),
|
||||
$coupon->getFreeShippingForCountries(),
|
||||
$coupon->getFreeShippingForModules(),
|
||||
$coupon->getPerCustomerUsageCount()
|
||||
);
|
||||
$couponEvent->setCouponModel($coupon);
|
||||
$couponEvent->setConditions($conditions);
|
||||
|
||||
@@ -31,10 +31,12 @@ use Thelia\Model\ContentDocument;
|
||||
use Thelia\Model\ContentImage;
|
||||
use Thelia\Model\FolderDocument;
|
||||
use Thelia\Model\FolderImage;
|
||||
use Thelia\Model\Lang;
|
||||
use Thelia\Model\ProductDocument;
|
||||
use Thelia\Model\ProductImage;
|
||||
use Thelia\Tools\FileManager;
|
||||
use Thelia\Tools\Rest\ResponseRest;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
/**
|
||||
* Created by JetBrains PhpStorm.
|
||||
@@ -182,6 +184,7 @@ class FileController extends BaseAdminController
|
||||
}
|
||||
|
||||
$documentModel->setParentId($parentId);
|
||||
$documentModel->setLocale(Lang::getDefaultLanguage()->getLocale());
|
||||
$documentModel->setTitle($fileBeingUploaded->getClientOriginalName());
|
||||
|
||||
$documentCreateOrUpdateEvent = new DocumentCreateOrUpdateEvent(
|
||||
@@ -309,7 +312,8 @@ class FileController extends BaseAdminController
|
||||
'imageId' => $imageId,
|
||||
'imageType' => $parentType,
|
||||
'redirectUrl' => $redirectUrl,
|
||||
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_IMAGES)
|
||||
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_IMAGES),
|
||||
'breadcrumb' => $image->getBreadcrumb($this->getRouter($this->getCurrentRouter()), $this->container, 'images')
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
$this->pageNotFound();
|
||||
@@ -338,7 +342,8 @@ class FileController extends BaseAdminController
|
||||
'documentId' => $documentId,
|
||||
'documentType' => $parentType,
|
||||
'redirectUrl' => $redirectUrl,
|
||||
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_DOCUMENTS)
|
||||
'formId' => $fileManager->getFormId($parentType, FileManager::FILE_TYPE_DOCUMENTS),
|
||||
'breadcrumb' => $document->getBreadcrumb($this->getRouter($this->getCurrentRouter()), $this->container, 'documents')
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
$this->pageNotFound();
|
||||
@@ -389,7 +394,7 @@ class FileController extends BaseAdminController
|
||||
$this->adminLogAppend(AdminResources::retrieve($parentType), AccessManager::UPDATE, sprintf('Image with Ref %s (ID %d) modified', $imageUpdated->getTitle(), $imageUpdated->getId()));
|
||||
|
||||
if ($this->getRequest()->get('save_mode') == 'close') {
|
||||
$this->redirectToRoute('admin.images');
|
||||
$this->redirect(URL::getInstance()->absoluteUrl($fileManager->getRedirectionUrl($parentType, $image->getParentId(), FileManager::FILE_TYPE_IMAGES)));
|
||||
} else {
|
||||
$this->redirectSuccess($imageModification);
|
||||
}
|
||||
@@ -466,7 +471,7 @@ class FileController extends BaseAdminController
|
||||
$this->adminLogAppend(AdminResources::retrieve($parentType), AccessManager::UPDATE, sprintf('Document with Ref %s (ID %d) modified', $documentUpdated->getTitle(), $documentUpdated->getId()));
|
||||
|
||||
if ($this->getRequest()->get('save_mode') == 'close') {
|
||||
$this->redirectToRoute('admin.documents');
|
||||
$this->redirect(URL::getInstance()->absoluteUrl($fileManager->getRedirectionUrl($parentType, $document->getParentId(), FileManager::FILE_TYPE_DOCUMENTS)));
|
||||
} else {
|
||||
$this->redirectSuccess($documentModification);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Security\AccessManager;
|
||||
use Thelia\Form\OrderUpdateAddress;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
use Thelia\Model\Base\OrderAddressQuery;
|
||||
use Thelia\Model\OrderAddressQuery;
|
||||
use Thelia\Model\OrderQuery;
|
||||
use Thelia\Model\OrderStatusQuery;
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
@@ -361,7 +361,8 @@ class ProductController extends AbstractSeoCrudController
|
||||
'product_id' => $this->getRequest()->get('product_id', 0),
|
||||
'folder_id' => $this->getRequest()->get('folder_id', 0),
|
||||
'accessory_category_id' => $this->getRequest()->get('accessory_category_id', 0),
|
||||
'current_tab' => $this->getRequest()->get('current_tab', 'general')
|
||||
'current_tab' => $this->getRequest()->get('current_tab', 'general'),
|
||||
'page' => $this->getRequest()->get('page', 1)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -386,7 +387,8 @@ class ProductController extends AbstractSeoCrudController
|
||||
return $this->render('categories',
|
||||
array(
|
||||
'product_order' => $currentOrder,
|
||||
'category_id' => $this->getCategoryId()
|
||||
'category_id' => $this->getCategoryId(),
|
||||
'page' => $this->getRequest()->get('page', 1)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -394,7 +396,10 @@ class ProductController extends AbstractSeoCrudController
|
||||
{
|
||||
$this->redirectToRoute(
|
||||
'admin.products.default',
|
||||
array('category_id' => $this->getCategoryId())
|
||||
array(
|
||||
'category_id' => $this->getCategoryId(),
|
||||
'page' => $this->getRequest()->get('page', 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -438,18 +443,6 @@ class ProductController extends AbstractSeoCrudController
|
||||
);
|
||||
}
|
||||
|
||||
protected function performAdditionalUpdateAction($updateEvent)
|
||||
{
|
||||
if ($this->getRequest()->get('save_mode') != 'stay') {
|
||||
|
||||
// Redirect to parent product list
|
||||
$this->redirectToRoute(
|
||||
'admin.categories.default',
|
||||
array('category_id' => $this->getCategoryId())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function performAdditionalUpdatePositionAction($positionEvent)
|
||||
{
|
||||
// Redirect to parent product list
|
||||
|
||||
@@ -291,7 +291,7 @@ abstract class BaseController extends ContainerAware
|
||||
protected function getRouteFromRouter($routerName, $routeId, $parameters = array(), $referenceType = Router::ABSOLUTE_URL)
|
||||
{
|
||||
/** @var Router $router */
|
||||
$router = $this->container->get($routerName);
|
||||
$router = $this->getRouter($routerName);
|
||||
|
||||
if ($router == null) {
|
||||
throw new \InvalidArgumentException(sprintf("Router '%s' does not exists.", $routerName));
|
||||
@@ -300,6 +300,15 @@ abstract class BaseController extends ContainerAware
|
||||
return $router->generate($routeId, $parameters, $referenceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $routerName
|
||||
* @return Router
|
||||
*/
|
||||
protected function getRouter($routerName)
|
||||
{
|
||||
return $this->container->get($routerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a 404 error
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace Thelia\Controller\Front;
|
||||
use Symfony\Component\Routing\Router;
|
||||
use Thelia\Controller\BaseController;
|
||||
use Thelia\Core\HttpFoundation\Response;
|
||||
use Thelia\Core\Template\TemplateDefinition;
|
||||
use Thelia\Core\Template\TemplateHelper;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
|
||||
use Thelia\Tools\URL;
|
||||
|
||||
class BaseFrontController extends BaseController
|
||||
@@ -65,7 +65,15 @@ class BaseFrontController extends BaseController
|
||||
protected function checkValidDelivery()
|
||||
{
|
||||
$order = $this->getSession()->getOrder();
|
||||
if (null === $order || null === $order->chosenDeliveryAddress || null === $order->getDeliveryModuleId() || null === AddressQuery::create()->findPk($order->chosenDeliveryAddress) || null === ModuleQuery::create()->findPk($order->getDeliveryModuleId())) {
|
||||
if (null === $order
|
||||
||
|
||||
null === $order->getChoosenDeliveryAddress()
|
||||
||
|
||||
null === $order->getDeliveryModuleId()
|
||||
||
|
||||
null === AddressQuery::create()->findPk($order->getChoosenDeliveryAddress())
|
||||
||
|
||||
null === ModuleQuery::create()->findPk($order->getDeliveryModuleId())) {
|
||||
$this->redirectToRoute("order.delivery");
|
||||
}
|
||||
}
|
||||
@@ -73,13 +81,21 @@ class BaseFrontController extends BaseController
|
||||
protected function checkValidInvoice()
|
||||
{
|
||||
$order = $this->getSession()->getOrder();
|
||||
if (null === $order || null === $order->chosenInvoiceAddress || null === $order->getPaymentModuleId() || null === AddressQuery::create()->findPk($order->chosenInvoiceAddress) || null === ModuleQuery::create()->findPk($order->getPaymentModuleId())) {
|
||||
if (null === $order
|
||||
||
|
||||
null === $order->getChoosenInvoiceAddress()
|
||||
||
|
||||
null === $order->getPaymentModuleId()
|
||||
||
|
||||
null === AddressQuery::create()->findPk($order->getChoosenInvoiceAddress())
|
||||
||
|
||||
null === ModuleQuery::create()->findPk($order->getPaymentModuleId())) {
|
||||
$this->redirectToRoute("order.invoice");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ParserInterface instance parser
|
||||
* @return TemplateDefinition the template
|
||||
*/
|
||||
protected function getParser($template = null)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Thelia\Core\Event\Cart;
|
||||
|
||||
use Thelia\Core\Event\ActionEvent;
|
||||
use Thelia\Model\Cart;
|
||||
use Thelia\Model\CartItem;
|
||||
|
||||
class CartEvent extends ActionEvent
|
||||
{
|
||||
@@ -31,7 +32,8 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $append
|
||||
* @param bool $append
|
||||
* @return CartEvent
|
||||
*/
|
||||
public function setAppend($append)
|
||||
{
|
||||
@@ -41,7 +43,7 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return bool
|
||||
*/
|
||||
public function getAppend()
|
||||
{
|
||||
@@ -49,7 +51,8 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $cartItem
|
||||
* @param CartItem $cartItem
|
||||
* @return CartEvent
|
||||
*/
|
||||
public function setCartItem($cartItem)
|
||||
{
|
||||
@@ -59,7 +62,7 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return CartItem
|
||||
*/
|
||||
public function getCartItem()
|
||||
{
|
||||
@@ -67,7 +70,8 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $newness
|
||||
* @param bool $newness
|
||||
* @return CartEvent
|
||||
*/
|
||||
public function setNewness($newness)
|
||||
{
|
||||
@@ -77,7 +81,7 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return bool
|
||||
*/
|
||||
public function getNewness()
|
||||
{
|
||||
@@ -85,7 +89,8 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $product
|
||||
* @param int $product the product ID
|
||||
* @return CartEvent
|
||||
*/
|
||||
public function setProduct($product)
|
||||
{
|
||||
@@ -95,7 +100,7 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return int the product ID
|
||||
*/
|
||||
public function getProduct()
|
||||
{
|
||||
@@ -103,7 +108,8 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $productSaleElementsId
|
||||
* @param int $productSaleElementsId
|
||||
* @return CartEvent
|
||||
*/
|
||||
public function setProductSaleElementsId($productSaleElementsId)
|
||||
{
|
||||
@@ -113,7 +119,7 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return int
|
||||
*/
|
||||
public function getProductSaleElementsId()
|
||||
{
|
||||
@@ -121,7 +127,8 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $quantity
|
||||
* @param int $quantity
|
||||
* @return CartEvent
|
||||
*/
|
||||
public function setQuantity($quantity)
|
||||
{
|
||||
@@ -131,7 +138,7 @@ class CartEvent extends ActionEvent
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return int
|
||||
*/
|
||||
public function getQuantity()
|
||||
{
|
||||
|
||||
@@ -31,19 +31,42 @@ class CouponConsumeEvent extends ActionEvent
|
||||
/** @var bool If Coupon is valid or if Customer meets coupon conditions */
|
||||
protected $isValid = null;
|
||||
|
||||
/** @var bool true if coupon offers free shipping */
|
||||
protected $freeShipping = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $code Coupon code
|
||||
* @param float $discount Total discount given by this coupon
|
||||
* @param bool $isValid If Coupon is valid or
|
||||
* if Customer meets coupon conditions
|
||||
* @param string $code Coupon code
|
||||
* @param float $discount Total discount given by this coupon
|
||||
* @param bool $isValid If Coupon is valid or f Customer meets coupon conditions
|
||||
* @param bool $freeShipping true if coupon offers free shipping
|
||||
*/
|
||||
public function __construct($code, $discount = null, $isValid = null)
|
||||
public function __construct($code, $discount = null, $isValid = null, $freeShipping = false)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->discount = $discount;
|
||||
$this->isValid = $isValid;
|
||||
$this->discount = $discount;
|
||||
|
||||
$this->freeShipping = $freeShipping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boolean $freeShipping
|
||||
*/
|
||||
public function setFreeShipping($freeShipping)
|
||||
{
|
||||
$this->freeShipping = $freeShipping;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function getFreeShipping()
|
||||
{
|
||||
return $this->freeShipping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,6 +73,15 @@ class CouponCreateOrUpdateEvent extends ActionEvent
|
||||
/** @var string Language code ISO (ex: fr_FR) */
|
||||
protected $locale = null;
|
||||
|
||||
/** @var array ID of Countries to which shipping is free */
|
||||
protected $freeShippingForCountries;
|
||||
|
||||
/** @var array ID of Shipping modules for which shipping is free */
|
||||
protected $freeShippingForMethods;
|
||||
|
||||
/** @var true if usage count is per customer only */
|
||||
protected $perCustomerUsageCount;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -91,8 +100,15 @@ class CouponCreateOrUpdateEvent extends ActionEvent
|
||||
* @param boolean $isRemovingPostage Is removing Postage
|
||||
* @param int $maxUsage Coupon quantity
|
||||
* @param string $locale Coupon Language code ISO (ex: fr_FR)
|
||||
* @param array $freeShippingForCountries ID of Countries to which shipping is free
|
||||
* @param array $freeShippingForMethods ID of Shipping modules for which shipping is free
|
||||
* @param boolean $perCustomerUsageCount Usage count is per customer
|
||||
*/
|
||||
public function __construct($code, $serviceId, $title, array $effects, $shortDescription, $description, $isEnabled, \DateTime $expirationDate, $isAvailableOnSpecialOffers, $isCumulative, $isRemovingPostage, $maxUsage, $locale)
|
||||
public function __construct(
|
||||
$code, $serviceId, $title, array $effects, $shortDescription, $description,
|
||||
$isEnabled, \DateTime $expirationDate, $isAvailableOnSpecialOffers, $isCumulative,
|
||||
$isRemovingPostage, $maxUsage, $locale, $freeShippingForCountries, $freeShippingForMethods,
|
||||
$perCustomerUsageCount)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->description = $description;
|
||||
@@ -107,6 +123,65 @@ class CouponCreateOrUpdateEvent extends ActionEvent
|
||||
$this->serviceId = $serviceId;
|
||||
$this->locale = $locale;
|
||||
$this->setEffects($effects);
|
||||
$this->freeShippingForCountries = $freeShippingForCountries;
|
||||
$this->freeShippingForMethods = $freeShippingForMethods;
|
||||
$this->perCustomerUsageCount = $perCustomerUsageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param true $perCustomerUsageCount
|
||||
*/
|
||||
public function setPerCustomerUsageCount($perCustomerUsageCount)
|
||||
{
|
||||
$this->perCustomerUsageCount = $perCustomerUsageCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true
|
||||
*/
|
||||
public function getPerCustomerUsageCount()
|
||||
{
|
||||
return $this->perCustomerUsageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $freeShippingForCountries
|
||||
* @return $this
|
||||
*/
|
||||
public function setFreeShippingForCountries($freeShippingForCountries)
|
||||
{
|
||||
$this->freeShippingForCountries = $freeShippingForCountries;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFreeShippingForCountries()
|
||||
{
|
||||
return $this->freeShippingForCountries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $freeShippingForMethods
|
||||
* @return $this
|
||||
*/
|
||||
public function setFreeShippingForMethods($freeShippingForMethods)
|
||||
{
|
||||
$this->freeShippingForMethods = $freeShippingForMethods;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFreeShippingForMethods()
|
||||
{
|
||||
return $this->freeShippingForMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -252,10 +327,9 @@ class CouponCreateOrUpdateEvent extends ActionEvent
|
||||
*/
|
||||
public function setEffects(array $effects)
|
||||
{
|
||||
if (null === $effects['amount']) {
|
||||
throw new InvalidArgumentException('Missing key \'amount\' in Coupon effect ready to be serialized array');
|
||||
}
|
||||
$this->amount = $effects['amount'];
|
||||
// Amount is now optionnal.
|
||||
$this->amount = isset($effects['amount']) ? $effects['amount'] : 0;
|
||||
|
||||
$this->effects = $effects;
|
||||
}
|
||||
|
||||
|
||||
73
core/lib/Thelia/Core/Event/SessionEvent.php
Normal file
73
core/lib/Thelia/Core/Event/SessionEvent.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Core\Event;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* Class SessionEvent
|
||||
* @package Thelia\Core\Event
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
class SessionEvent extends ActionEvent
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function getContainer()
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
public function getEnv()
|
||||
{
|
||||
return $this->container->getParameter('kernel.environment');
|
||||
}
|
||||
|
||||
public function getDebug()
|
||||
{
|
||||
return $this->container->getParameter('kernel.debug');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $session
|
||||
*/
|
||||
public function setSession(SessionInterface $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -464,6 +464,11 @@ final class TheliaEvents
|
||||
*/
|
||||
const COUPON_CONSUME = "action.consume_coupon";
|
||||
|
||||
/**
|
||||
* Sent when all coupons in the current session should be cleared
|
||||
*/
|
||||
const COUPON_CLEAR_ALL = "action.clear_all_coupon";
|
||||
|
||||
/**
|
||||
* Sent just before an attempt to use a Coupon
|
||||
*/
|
||||
|
||||
81
core/lib/Thelia/Core/EventListener/SessionListener.php
Normal file
81
core/lib/Thelia/Core/EventListener/SessionListener.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Core\EventListener;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
|
||||
use Thelia\Core\Event\SessionEvent;
|
||||
use Thelia\Core\HttpFoundation\Session\Session;
|
||||
use Thelia\Core\TheliaKernelEvents;
|
||||
use Thelia\Model\ConfigQuery;
|
||||
|
||||
/**
|
||||
* Class SessionListener
|
||||
* @package Thelia\Core\EventListener
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
class SessionListener implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
public function prodSession(SessionEvent $event)
|
||||
{
|
||||
$storage = new NativeSessionStorage();
|
||||
$storage->setSaveHandler(new NativeFileSessionHandler(ConfigQuery::read("session_config.save_path", THELIA_ROOT . '/local/session/')));
|
||||
$event->setSession($this->getSession($storage));
|
||||
}
|
||||
|
||||
public function testSession(SessionEvent $event)
|
||||
{
|
||||
if ($event->getEnv() == 'test') {
|
||||
$storage = new MockFileSessionStorage($event->getContainer()->getParameter('kernel.cache_dir') . DS . 'sessions');
|
||||
$event->setSession($this->getSession($storage));
|
||||
$event->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
public function getSession(SessionStorageInterface $storage)
|
||||
{
|
||||
return new Session($storage);
|
||||
}
|
||||
/**
|
||||
* Returns an array of event names this subscriber wants to listen to.
|
||||
*
|
||||
* The array keys are event names and the value can be:
|
||||
*
|
||||
* * The method name to call (priority defaults to 0)
|
||||
* * An array composed of the method name to call and the priority
|
||||
* * An array of arrays composed of the method names to call and respective
|
||||
* priorities, or 0 if unset
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* * array('eventName' => 'methodName')
|
||||
* * array('eventName' => array('methodName', $priority))
|
||||
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
||||
*
|
||||
* @return array The event names to listen to
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
TheliaKernelEvents::SESSION =>[
|
||||
['prodSession', 0],
|
||||
['testSession', 128]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ use Thelia\Core\Template\Exception\ResourceNotFoundException;
|
||||
|
||||
use Thelia\Core\Template\TemplateHelper;
|
||||
use Thelia\Exception\OrderException;
|
||||
use Thelia\Tools\Redirect;
|
||||
|
||||
use Thelia\Core\Security\Exception\AuthenticationException;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\AttributeQuery;
|
||||
use Thelia\Model\AttributeQuery;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
use Thelia\Model\ProductQuery;
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\AttributeAvQuery;
|
||||
use Thelia\Model\AttributeAvQuery;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\AttributeCombinationQuery;
|
||||
use Thelia\Model\AttributeCombinationQuery;
|
||||
use Thelia\Model\Map\AttributeAvTableMap;
|
||||
use Thelia\Model\Map\AttributeTableMap;
|
||||
use Thelia\Type\TypeCollection;
|
||||
|
||||
@@ -82,9 +82,9 @@ class Cart extends BaseLoop implements ArraySearchLoopInterface
|
||||
public function parseResults(LoopResult $loopResult)
|
||||
{
|
||||
$taxCountry = $this->container->get('thelia.taxEngine')->getDeliveryCountry();
|
||||
|
||||
$locale = $this->request->getSession()->getLang()->getLocale();
|
||||
foreach ($loopResult->getResultDataCollection() as $cartItem) {
|
||||
$product = $cartItem->getProduct();
|
||||
$product = $cartItem->getProduct(null, $locale);
|
||||
$productSaleElement = $cartItem->getProductSaleElements();
|
||||
|
||||
$loopResultRow = new LoopResultRow();
|
||||
@@ -102,7 +102,7 @@ class Cart extends BaseLoop implements ArraySearchLoopInterface
|
||||
->set("PROMO_TAXED_PRICE", $cartItem->getTaxedPromoPrice($taxCountry))
|
||||
->set("IS_PROMO", $cartItem->getPromo() === 1 ? 1 : 0);
|
||||
$loopResultRow->set("PRODUCT_SALE_ELEMENTS_ID", $productSaleElement->getId());
|
||||
|
||||
$loopResultRow->set("PRODUCT_SALE_ELEMENTS_REF", $productSaleElement->getRef());
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
@@ -51,7 +52,7 @@ use Thelia\Model\ProductQuery;
|
||||
* @author Manuel Raynaud <mraynaud@openstudio.fr>
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
*/
|
||||
class Category extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
class Category extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
@@ -83,6 +84,23 @@ class Category extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of available field to search in
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
}
|
||||
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
{
|
||||
$search = CategoryQuery::create();
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
@@ -37,7 +38,7 @@ use Thelia\Type\BooleanOrBothType;
|
||||
* @package Thelia\Core\Template\Loop
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
*/
|
||||
class Content extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
class Content extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
@@ -60,7 +61,20 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
new Argument(
|
||||
'order',
|
||||
new TypeCollection(
|
||||
new Type\EnumListType(array('alpha', 'alpha-reverse', 'manual', 'manual_reverse', 'random', 'given_id'))
|
||||
new Type\EnumListType(
|
||||
array(
|
||||
'alpha',
|
||||
'alpha-reverse',
|
||||
'manual',
|
||||
'manual_reverse',
|
||||
'random',
|
||||
'given_id',
|
||||
'created',
|
||||
'created_reverse',
|
||||
'updated',
|
||||
'updated_reverse'
|
||||
)
|
||||
)
|
||||
),
|
||||
'alpha'
|
||||
),
|
||||
@@ -69,6 +83,23 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of available field to search in
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
}
|
||||
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
{
|
||||
|
||||
@@ -178,6 +209,18 @@ class Content extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
$search->clearOrderByColumns();
|
||||
$search->addAscendingOrderByColumn('RAND()');
|
||||
break(2);
|
||||
case "created":
|
||||
$search->addAscendingOrderByColumn('created_at');
|
||||
break;
|
||||
case "created_reverse":
|
||||
$search->addDescendingOrderByColumn('created_at');
|
||||
break;
|
||||
case "updated":
|
||||
$search->addAscendingOrderByColumn('updated_at');
|
||||
break;
|
||||
case "updated_reverse":
|
||||
$search->addDescendingOrderByColumn('updated_at');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
use Thelia\Model\CouponModule;
|
||||
use Thelia\Model\Coupon as MCoupon;
|
||||
use Thelia\Model\CouponCountry;
|
||||
use Thelia\Model\CouponQuery;
|
||||
use Thelia\Model\Map\CouponTableMap;
|
||||
use Thelia\Type\EnumListType;
|
||||
@@ -152,8 +154,6 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
|
||||
/** @var Request $request */
|
||||
$request = $this->container->get('request');
|
||||
/** @var Lang $lang */
|
||||
$lang = $request->getSession()->getLang();
|
||||
|
||||
/** @var MCoupon $coupon */
|
||||
foreach ($loopResult->getResultDataCollection() as $coupon) {
|
||||
@@ -178,7 +178,10 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
$coupon->getIsAvailableOnSpecialOffers(),
|
||||
$coupon->getIsEnabled(),
|
||||
$coupon->getMaxUsage(),
|
||||
$coupon->getExpirationDate()
|
||||
$coupon->getExpirationDate(),
|
||||
$coupon->getFreeShippingForCountries(),
|
||||
$coupon->getFreeShippingForModules(),
|
||||
$coupon->getPerCustomerUsageCount()
|
||||
);
|
||||
|
||||
$cleanedConditions = array();
|
||||
@@ -191,6 +194,18 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
$cleanedConditions[] = $temp;
|
||||
}
|
||||
|
||||
$freeShippingForCountriesIds = [];
|
||||
/** @var CouponCountry $couponCountry */
|
||||
foreach ($coupon->getFreeShippingForCountries() as $couponCountry) {
|
||||
$freeShippingForCountriesIds[] = $couponCountry->getCountryId();
|
||||
}
|
||||
|
||||
$freeShippingForModulesIds = [];
|
||||
/** @var CouponModule $couponModule */
|
||||
foreach ($coupon->getFreeShippingForModules() as $couponModule) {
|
||||
$freeShippingForModulesIds[] = $couponModule->getModuleId();
|
||||
}
|
||||
|
||||
$loopResultRow
|
||||
->set("ID", $coupon->getId())
|
||||
->set("IS_TRANSLATED", $coupon->getVirtualColumn('IS_TRANSLATED'))
|
||||
@@ -201,6 +216,7 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
->set("DESCRIPTION", $coupon->getVirtualColumn('i18n_DESCRIPTION'))
|
||||
->set("EXPIRATION_DATE", $coupon->getExpirationDate())
|
||||
->set("USAGE_LEFT", $coupon->getMaxUsage())
|
||||
->set("PER_CUSTOMER_USAGE_COUNT", $coupon->getPerCustomerUsageCount())
|
||||
->set("IS_CUMULATIVE", $coupon->getIsCumulative())
|
||||
->set("IS_REMOVING_POSTAGE", $coupon->getIsRemovingPostage())
|
||||
->set("IS_AVAILABLE_ON_SPECIAL_OFFERS", $coupon->getIsAvailableOnSpecialOffers())
|
||||
@@ -209,7 +225,11 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
->set("APPLICATION_CONDITIONS", $cleanedConditions)
|
||||
->set("TOOLTIP", $couponManager->getToolTip())
|
||||
->set("DAY_LEFT_BEFORE_EXPIRATION", max(0, $coupon->getVirtualColumn('days_left')))
|
||||
->set("SERVICE_ID", $couponManager->getServiceId());
|
||||
->set("SERVICE_ID", $couponManager->getServiceId())
|
||||
->set("FREE_SHIPPING_FOR_COUNTRIES_LIST", implode(',', $freeShippingForCountriesIds))
|
||||
->set("FREE_SHIPPING_FOR_MODULES_LIST", implode(',', $freeShippingForModulesIds))
|
||||
;
|
||||
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class Delivery extends BaseSpecificModule
|
||||
$loopResultRow = new LoopResultRow($deliveryModule);
|
||||
|
||||
/** @var DeliveryModuleInterface $moduleInstance */
|
||||
$moduleInstance = $this->container->get(sprintf('module.%s', $deliveryModule->getCode()));
|
||||
$moduleInstance = $deliveryModule->getModuleInstance($this->container);
|
||||
|
||||
if (false === $moduleInstance instanceof DeliveryModuleInterface) {
|
||||
throw new \RuntimeException(sprintf("delivery module %s is not a Thelia\Module\DeliveryModuleInterface", $deliveryModule->getCode()));
|
||||
|
||||
@@ -237,7 +237,7 @@ class Document extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
$loopResultRow
|
||||
->set("ID" , $result->getId())
|
||||
->set("LOCALE" , $this->locale)
|
||||
->set("DOCUMENT_URL" , $event->getFileUrl())
|
||||
->set("DOCUMENT_URL" , $event->getDocumentUrl())
|
||||
->set("DOCUMENT_PATH" , $event->getDocumentPath())
|
||||
->set("ORIGINAL_DOCUMENT_PATH", $source_filepath)
|
||||
->set("TITLE" , $result->getVirtualColumn('i18n_TITLE'))
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\FeatureAvQuery;
|
||||
use Thelia\Model\FeatureAvQuery;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\FeatureProductQuery;
|
||||
use Thelia\Model\FeatureProductQuery;
|
||||
use Thelia\Model\Map\FeatureAvTableMap;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
|
||||
@@ -18,6 +18,7 @@ use Thelia\Core\Template\Element\LoopResult;
|
||||
use Thelia\Core\Template\Element\LoopResultRow;
|
||||
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Element\SearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
@@ -33,7 +34,7 @@ use Thelia\Type\BooleanOrBothType;
|
||||
* @package Thelia\Core\Template\Loop
|
||||
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
||||
*/
|
||||
class Folder extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
class Folder extends BaseI18nLoop implements PropelSearchLoopInterface, SearchLoopInterface
|
||||
{
|
||||
protected $timestampable = true;
|
||||
protected $versionable = true;
|
||||
@@ -62,6 +63,23 @@ class Folder extends BaseI18nLoop implements PropelSearchLoopInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of available field to search in
|
||||
*/
|
||||
public function getSearchIn()
|
||||
{
|
||||
return [
|
||||
"title"
|
||||
];
|
||||
}
|
||||
|
||||
public function doSearch(&$search, $searchTerm, $searchIn, $searchCriteria)
|
||||
{
|
||||
$search->_and();
|
||||
|
||||
$search->where("CASE WHEN NOT ISNULL(`requested_locale_i18n`.ID) THEN `requested_locale_i18n`.`TITLE` ELSE `default_locale_i18n`.`TITLE` END ".$searchCriteria." ?", $searchTerm, \PDO::PARAM_STR);
|
||||
}
|
||||
|
||||
public function buildModelCriteria()
|
||||
{
|
||||
$search = FolderQuery::create();
|
||||
|
||||
@@ -20,6 +20,8 @@ use Thelia\Core\Template\Element\LoopResultRow;
|
||||
use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Model\OrderCouponCountry;
|
||||
use Thelia\Model\OrderCouponModule;
|
||||
use Thelia\Model\OrderCouponQuery;
|
||||
use Thelia\Model\OrderQuery;
|
||||
|
||||
@@ -52,9 +54,10 @@ class OrderCoupon extends BaseLoop implements PropelSearchLoopInterface
|
||||
|
||||
$order = $this->getOrder();
|
||||
|
||||
$search->filterByOrderId($order, Criteria::EQUAL);
|
||||
|
||||
$search->orderById(Criteria::ASC);
|
||||
$search
|
||||
->filterByOrderId($order, Criteria::EQUAL)
|
||||
->orderById(Criteria::ASC)
|
||||
;
|
||||
|
||||
return $search;
|
||||
|
||||
@@ -64,26 +67,48 @@ class OrderCoupon extends BaseLoop implements PropelSearchLoopInterface
|
||||
{
|
||||
$this->container->get('thelia.condition.factory');
|
||||
|
||||
/** @var OrderCoupon $orderCoupon */
|
||||
foreach ($loopResult->getResultDataCollection() as $orderCoupon) {
|
||||
$loopResultRow = new LoopResultRow($orderCoupon);
|
||||
if (null !== $order = OrderQuery::create()->findPk($this->getOrder())) {
|
||||
|
||||
$now = time();
|
||||
$datediff = $orderCoupon->getExpirationDate()->getTimestamp() - $now;
|
||||
$daysLeftBeforeExpiration = floor($datediff/(60*60*24));
|
||||
$oneDayInSeconds = 86400;
|
||||
|
||||
$loopResultRow->set("ID", $orderCoupon->getId())
|
||||
->set("CODE", $orderCoupon->getCode())
|
||||
->set("TITLE", $orderCoupon->getTitle())
|
||||
->set("SHORT_DESCRIPTION", $orderCoupon->getShortDescription())
|
||||
->set("DESCRIPTION", $orderCoupon->getDescription())
|
||||
->set("EXPIRATION_DATE", $orderCoupon->getExpirationDate( OrderQuery::create()->findPk($this->getOrder())->getLangId() ))
|
||||
->set("IS_CUMULATIVE", $orderCoupon->getIsCumulative())
|
||||
->set("IS_REMOVING_POSTAGE", $orderCoupon->getIsRemovingPostage())
|
||||
->set("IS_AVAILABLE_ON_SPECIAL_OFFERS", $orderCoupon->getIsAvailableOnSpecialOffers())
|
||||
->set("DAY_LEFT_BEFORE_EXPIRATION", $daysLeftBeforeExpiration)
|
||||
;
|
||||
$loopResult->addRow($loopResultRow);
|
||||
/** @var \Thelia\Model\OrderCoupon $orderCoupon */
|
||||
foreach ($loopResult->getResultDataCollection() as $orderCoupon) {
|
||||
|
||||
$loopResultRow = new LoopResultRow($orderCoupon);
|
||||
|
||||
$now = time();
|
||||
$datediff = $orderCoupon->getExpirationDate()->getTimestamp() - $now;
|
||||
$daysLeftBeforeExpiration = floor($datediff/($oneDayInSeconds));
|
||||
|
||||
$freeShippingForCountriesIds = [];
|
||||
/** @var OrderCouponCountry $couponCountry */
|
||||
foreach ($orderCoupon->getFreeShippingForCountries() as $couponCountry) {
|
||||
$freeShippingForCountriesIds[] = $couponCountry->getCountryId();
|
||||
}
|
||||
|
||||
$freeShippingForModulesIds = [];
|
||||
/** @var OrderCouponModule $couponModule */
|
||||
foreach ($orderCoupon->getFreeShippingForModules() as $couponModule) {
|
||||
$freeShippingForModulesIds[] = $couponModule->getModuleId();
|
||||
}
|
||||
|
||||
$loopResultRow->set("ID", $orderCoupon->getId())
|
||||
->set("CODE", $orderCoupon->getCode())
|
||||
->set("TITLE", $orderCoupon->getTitle())
|
||||
->set("SHORT_DESCRIPTION", $orderCoupon->getShortDescription())
|
||||
->set("DESCRIPTION", $orderCoupon->getDescription())
|
||||
->set("EXPIRATION_DATE", $orderCoupon->getExpirationDate( $order->getLangId() ))
|
||||
->set("IS_CUMULATIVE", $orderCoupon->getIsCumulative())
|
||||
->set("IS_REMOVING_POSTAGE", $orderCoupon->getIsRemovingPostage())
|
||||
->set("IS_AVAILABLE_ON_SPECIAL_OFFERS", $orderCoupon->getIsAvailableOnSpecialOffers())
|
||||
->set("DAY_LEFT_BEFORE_EXPIRATION", $daysLeftBeforeExpiration)
|
||||
->set("FREE_SHIPPING_FOR_COUNTRIES_LIST", implode(',', $freeShippingForCountriesIds))
|
||||
->set("FREE_SHIPPING_FOR_MODULES_LIST", implode(',', $freeShippingForModulesIds))
|
||||
->set("PER_CUSTOMER_USAGE_COUNT", $orderCoupon->getPerCustomerUsageCount())
|
||||
;
|
||||
|
||||
$loopResult->addRow($loopResultRow);
|
||||
}
|
||||
}
|
||||
|
||||
return $loopResult;
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\OrderProductQuery;
|
||||
use Thelia\Model\OrderProductQuery;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -41,7 +41,8 @@ class OrderProduct extends BaseLoop implements PropelSearchLoopInterface
|
||||
protected function getArgDefinitions()
|
||||
{
|
||||
return new ArgumentCollection(
|
||||
Argument::createIntTypeArgument('order', null, true)
|
||||
Argument::createIntTypeArgument('order', null, true),
|
||||
Argument::createIntListTypeArgument('id')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,6 +59,10 @@ class OrderProduct extends BaseLoop implements PropelSearchLoopInterface
|
||||
|
||||
$search->filterByOrderId($order, Criteria::EQUAL);
|
||||
|
||||
if (null !== $this->getId()) {
|
||||
$search->filterById($this->getId(), Criteria::IN);
|
||||
}
|
||||
|
||||
$search->orderById(Criteria::ASC);
|
||||
|
||||
return $search;
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\OrderProductAttributeCombinationQuery;
|
||||
use Thelia\Model\OrderProductAttributeCombinationQuery;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class Payment extends BaseSpecificModule implements PropelSearchLoopInterface
|
||||
foreach ($loopResult->getResultDataCollection() as $paymentModule) {
|
||||
$loopResultRow = new LoopResultRow($paymentModule);
|
||||
|
||||
$moduleInstance = $this->container->get(sprintf('module.%s', $paymentModule->getCode()));
|
||||
$moduleInstance = $paymentModule->getModuleInstance($this->container);
|
||||
|
||||
if (false === $moduleInstance instanceof PaymentModuleInterface) {
|
||||
throw new \RuntimeException(sprintf("payment module %s is not a Thelia\Module\PaymentModuleInterface", $paymentModule->getCode()));
|
||||
|
||||
@@ -22,7 +22,7 @@ use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Exception\TaxEngineException;
|
||||
use Thelia\Model\Base\ProductSaleElementsQuery;
|
||||
use Thelia\Model\ProductSaleElementsQuery;
|
||||
use Thelia\Model\CurrencyQuery;
|
||||
use Thelia\Model\Map\ProductSaleElementsTableMap;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\TemplateQuery;
|
||||
use Thelia\Model\TemplateQuery;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -21,7 +21,7 @@ use Thelia\Core\Template\Element\PropelSearchLoopInterface;
|
||||
use Thelia\Core\Template\Loop\Argument\ArgumentCollection;
|
||||
use Thelia\Core\Template\Loop\Argument\Argument;
|
||||
|
||||
use Thelia\Model\Base\TaxRuleCountryQuery;
|
||||
use Thelia\Model\TaxRuleCountryQuery;
|
||||
use Thelia\Type\TypeCollection;
|
||||
use Thelia\Type;
|
||||
use Thelia\Model\TaxQuery;
|
||||
|
||||
@@ -162,8 +162,7 @@ class SmartyAssetsManager
|
||||
$filters,
|
||||
$debug
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Tlog::getInstance()->addError("Asset $assetSource".DS."$file was not found.");
|
||||
}
|
||||
|
||||
|
||||
@@ -43,18 +43,7 @@ class Assets extends AbstractSmartyPlugin
|
||||
|
||||
public function blockJavascripts($params, $content, \Smarty_Internal_Template $template, &$repeat)
|
||||
{
|
||||
try {
|
||||
return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat);
|
||||
} catch (\Exception $e) {
|
||||
$catchException = $this->getNormalizedParam($params, array('catchException'));
|
||||
if ($catchException == "true") {
|
||||
$repeat = false;
|
||||
|
||||
return null;
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
return $this->assetManager->processSmartyPluginCall('js', $params, $content, $template, $repeat);
|
||||
}
|
||||
|
||||
public function blockImages($params, $content, \Smarty_Internal_Template $template, &$repeat)
|
||||
|
||||
@@ -169,7 +169,7 @@ class CartPostage extends AbstractSmartyPlugin
|
||||
foreach ($deliveryModules as $deliveryModule) {
|
||||
|
||||
/** @var DeliveryModuleInterface $moduleInstance */
|
||||
$moduleInstance = $this->container->get(sprintf('module.%s', $deliveryModule->getCode()));
|
||||
$moduleInstance = $deliveryModule->getModuleInstance($this->container);
|
||||
|
||||
if (false === $moduleInstance instanceof DeliveryModuleInterface) {
|
||||
throw new \RuntimeException(sprintf("delivery module %s is not a Thelia\Module\DeliveryModuleInterface", $deliveryModule->getCode()));
|
||||
|
||||
@@ -204,9 +204,9 @@ class DataAccessFunctions extends AbstractSmartyPlugin
|
||||
case 'discount':
|
||||
return $order->getDiscount();
|
||||
case 'delivery_address':
|
||||
return $order->chosenDeliveryAddress;
|
||||
return $order->getChoosenDeliveryAddress();
|
||||
case 'invoice_address':
|
||||
return $order->chosenInvoiceAddress;
|
||||
return $order->getChoosenInvoiceAddress();
|
||||
case 'delivery_module':
|
||||
return $order->getDeliveryModuleId();
|
||||
case 'payment_module':
|
||||
@@ -402,7 +402,7 @@ class DataAccessFunctions extends AbstractSmartyPlugin
|
||||
return $noGetterData[$keyAttribute];
|
||||
}
|
||||
|
||||
$getter = sprintf("get%s", ucfirst($attribute));
|
||||
$getter = sprintf("get%s", $this->underscoreToCamelcase($attribute));
|
||||
if (method_exists($data, $getter)) {
|
||||
$return = $data->$getter();
|
||||
|
||||
@@ -427,6 +427,27 @@ class DataAccessFunctions extends AbstractSmartyPlugin
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Transcode an underscored string into a camel-cased string, eg. default_folder into DefaultFolder
|
||||
*
|
||||
* @param string $str the string to convert from underscore to camel-case
|
||||
*
|
||||
* @return string the camel cased string.
|
||||
*/
|
||||
private function underscoreToCamelcase($str)
|
||||
{
|
||||
// Split string in words.
|
||||
$words = explode('_', strtolower($str));
|
||||
|
||||
$return = '';
|
||||
|
||||
foreach ($words as $word) {
|
||||
$return .= ucfirst(trim($word));
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins hendled by this class
|
||||
*
|
||||
|
||||
@@ -50,6 +50,7 @@ class Format extends AbstractSmartyPlugin
|
||||
*
|
||||
* ex :
|
||||
* {format_date date=$dateTimeObject format="Y-m-d H:i:s"} will output the format with specific format
|
||||
* {format_date date=$dateTimeObject format="%e %B %Y" locale="fr_FR"} will output the format with specific format (see strftime() function)
|
||||
* {format_date date=$dateTimeObject output="date"} will output the date using the default date system format
|
||||
* {format_date date=$dateTimeObject} will output with the default datetime system format
|
||||
*
|
||||
@@ -86,7 +87,32 @@ class Format extends AbstractSmartyPlugin
|
||||
$format = DateTimeFormat::getInstance($this->request)->getFormat($this->getParam($params, "output", null));
|
||||
}
|
||||
|
||||
return $date->format($format);
|
||||
$locale = $this->getParam($params,'locale', false);
|
||||
|
||||
if (false === $locale) {
|
||||
$value = $date->format($format);
|
||||
} else {
|
||||
$value = $this->formatDateWithLocale($date, $locale, $format);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function formatDateWithLocale(\DateTime $date, $locale, $format)
|
||||
{
|
||||
if (function_exists('setlocale')) {
|
||||
// Save the current locale
|
||||
$systemLocale = setlocale('LC_TIME', 0);
|
||||
setlocale('LC_TIME', $locale);
|
||||
$localizedDate = strftime($format, $date->getTimestamp());
|
||||
// Restore the locale
|
||||
setlocale('LC_TIME', $systemLocale);
|
||||
|
||||
return $localizedDate;
|
||||
} else {
|
||||
// setlocale() function not available => error
|
||||
throw new SmartyPluginException("The setlocale() function is not available on your system.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -82,7 +82,7 @@ class Security extends AbstractSmartyPlugin
|
||||
$order = $this->request->getSession()->getOrder();
|
||||
/* Does address and module still exists ? We assume address owner can't change neither module type */
|
||||
if ($order !== null) {
|
||||
$checkAddress = AddressQuery::create()->findPk($order->chosenDeliveryAddress);
|
||||
$checkAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress());
|
||||
$checkModule = ModuleQuery::create()->findPk($order->getDeliveryModuleId());
|
||||
}
|
||||
if (null === $order || null == $checkAddress || null === $checkModule) {
|
||||
|
||||
@@ -47,20 +47,26 @@ class Translation extends AbstractSmartyPlugin
|
||||
*/
|
||||
public function translate($params, &$smarty)
|
||||
{
|
||||
// All parameters other than 'l' and 'd' are supposed to be variables. Build an array of var => value pairs
|
||||
// All parameters other than 'l' and 'd' and 'js' are supposed to be variables. Build an array of var => value pairs
|
||||
// and pass it to the translator
|
||||
$vars = array();
|
||||
|
||||
foreach ($params as $name => $value) {
|
||||
if ($name != 'l' && $name != 'd') $vars["%$name"] = $value;
|
||||
if ($name != 'l' && $name != 'd' && $name != 'js') $vars["%$name"] = $value;
|
||||
}
|
||||
|
||||
return $this->translator->trans(
|
||||
$str = $this->translator->trans(
|
||||
$this->getParam($params, 'l'),
|
||||
$vars,
|
||||
$this->getParam($params, 'd', $this->defaultTranslationDomain)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->getParam($params, 'js', 0)) {
|
||||
$str = preg_replace("/(['\"])/", "\\\\$1", $str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various smarty plugins handled by this class
|
||||
|
||||
@@ -152,9 +152,9 @@ class UrlGenerator extends AbstractSmartyPlugin
|
||||
protected function getNavigateToValues()
|
||||
{
|
||||
return array(
|
||||
"current" => "getCurrentUrl",
|
||||
"return_to" => "getReturnToUrl",
|
||||
"index" => "getIndexUrl",
|
||||
"current" => "getCurrentUrl",
|
||||
"previous" => "getPreviousUrl",
|
||||
"index" => "getIndexUrl",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ class UrlGenerator extends AbstractSmartyPlugin
|
||||
$navigateToValues = $this->getNavigateToValues();
|
||||
|
||||
if (!array_key_exists($to, $navigateToValues)) {
|
||||
throw new \InvalidArgumentException("Incorrect value for parameter `to` in `navigate` substitution.");
|
||||
throw new \InvalidArgumentException(sprintf("Incorrect value `%s` for parameter `to` in `navigate` substitution.", $to));
|
||||
}
|
||||
|
||||
return $navigateToValues[$to];
|
||||
@@ -178,7 +178,7 @@ class UrlGenerator extends AbstractSmartyPlugin
|
||||
return $this->request->getUri();
|
||||
}
|
||||
|
||||
protected function getReturnToUrl()
|
||||
protected function getPreviousUrl()
|
||||
{
|
||||
return URL::getInstance()->absoluteUrl($this->request->getSession()->getReturnToUrl());
|
||||
}
|
||||
|
||||
@@ -60,13 +60,13 @@ class TemplateHelper
|
||||
$tplVar = 'active-front-template';
|
||||
break;
|
||||
case TemplateDefinition::BACK_OFFICE:
|
||||
$tplVar = 'active-front-template';
|
||||
$tplVar = 'active-admin-template';
|
||||
break;
|
||||
case TemplateDefinition::PDF:
|
||||
$tplVar = 'active-front-template';
|
||||
$tplVar = 'active-pdf-template';
|
||||
break;
|
||||
case TemplateDefinition::EMAIL:
|
||||
$tplVar = 'active-front-template';
|
||||
$tplVar = 'active-mail-template';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ use Thelia\Model\ModuleQuery;
|
||||
class Thelia extends Kernel
|
||||
{
|
||||
|
||||
const THELIA_VERSION = '2.0.1';
|
||||
const THELIA_VERSION = '2.0.2';
|
||||
|
||||
public function init()
|
||||
{
|
||||
|
||||
@@ -20,9 +20,9 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Session;
|
||||
|
||||
use Thelia\Core\Event\Currency\CurrencyChangeEvent;
|
||||
use Thelia\Core\Event\SessionEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Model;
|
||||
|
||||
@@ -203,26 +203,13 @@ class TheliaHttpKernel extends HttpKernel
|
||||
|
||||
public function initSession(Request $request)
|
||||
{
|
||||
if (null === self::$session) {
|
||||
$storage = new Session\Storage\NativeSessionStorage();
|
||||
if (null === $session = self::$session) {
|
||||
$container = $this->getContainer();
|
||||
$event = new SessionEvent($this->container);
|
||||
$dispatcher = $container->get('event_dispatcher');
|
||||
$dispatcher->dispatch(TheliaKernelEvents::SESSION, $event);
|
||||
|
||||
if (Model\ConfigQuery::read("session_config.default")) {
|
||||
$storage->setSaveHandler(new Session\Storage\Handler\NativeFileSessionHandler(Model\ConfigQuery::read("session_config.save_path", THELIA_ROOT . '/local/session/')));
|
||||
} else {
|
||||
$handlerString = Model\ConfigQuery::read("session_config.handlers", 'Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler');
|
||||
|
||||
$handler = new $handlerString;
|
||||
|
||||
$storage->setSaveHandler($handler);
|
||||
}
|
||||
|
||||
if (Model\ConfigQuery::read("session_config.config", null)) {
|
||||
$storage->setOptions(json_decode(Model\ConfigQuery::read("session_config.config")));
|
||||
}
|
||||
|
||||
self::$session = $session = new \Thelia\Core\HttpFoundation\Session\Session($storage);
|
||||
} else {
|
||||
$session = self::$session;
|
||||
self::$session = $session = $event->getSession();
|
||||
}
|
||||
|
||||
$session->start();
|
||||
|
||||
25
core/lib/Thelia/Core/TheliaKernelEvents.php
Normal file
25
core/lib/Thelia/Core/TheliaKernelEvents.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Core;
|
||||
|
||||
/**
|
||||
* Class TheliaKernelEvents
|
||||
* @package Thelia\Core
|
||||
* @author manuel raynaud <mraynaud@openstudio.fr>
|
||||
*/
|
||||
final class TheliaKernelEvents
|
||||
{
|
||||
|
||||
const SESSION = "thelia_kernel.session";
|
||||
|
||||
}
|
||||
@@ -14,7 +14,6 @@ namespace Thelia\Core\Translation;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Translation\Translator as BaseTranslator;
|
||||
use Thelia\Log\Tlog;
|
||||
|
||||
class Translator extends BaseTranslator
|
||||
{
|
||||
@@ -74,14 +73,9 @@ class Translator extends BaseTranslator
|
||||
$this->loadCatalogue($locale);
|
||||
}
|
||||
|
||||
if (! $this->catalogues[$locale]->has((string) $id, $domain)) {
|
||||
|
||||
}
|
||||
|
||||
if ($this->catalogues[$locale]->has((string) $id, $domain)) {
|
||||
return parent::trans($id, $parameters, $domain, $locale);
|
||||
} else {
|
||||
//Tlog::getInstance()->addWarning("Undefined translation: locale: $locale, domain: $domain, ID: $id");
|
||||
|
||||
if ($return_default_if_not_available)
|
||||
return strtr($id, $parameters);
|
||||
|
||||
@@ -21,6 +21,7 @@ use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Core\Template\TemplateHelper;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\Model\Coupon;
|
||||
use Thelia\Model\CouponQuery;
|
||||
use Thelia\Cart\CartTrait;
|
||||
@@ -77,9 +78,8 @@ class BaseFacade implements FacadeInterface
|
||||
public function getDeliveryAddress()
|
||||
{
|
||||
try {
|
||||
return AddressQuery::create()->findPk($this->getRequest()->getSession()->getOrder()->chosenDeliveryAddress);
|
||||
}
|
||||
catch(\Exception $ex) {
|
||||
return AddressQuery::create()->findPk($this->getRequest()->getSession()->getOrder()->getChoosenDeliveryAddress());
|
||||
} catch (\Exception $ex) {
|
||||
throw new \LogicException("Failed to get delivery address (" . $ex->getMessage() . ")");
|
||||
}
|
||||
}
|
||||
@@ -119,17 +119,43 @@ class BaseFacade implements FacadeInterface
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getCartTotalPrice()
|
||||
public function getCartTotalPrice($withItemsInPromo = true)
|
||||
{
|
||||
return $this->getRequest()->getSession()->getCart()->getTotalAmount();
|
||||
$total = 0;
|
||||
|
||||
$cartItems = $this->getRequest()->getSession()->getCart()->getCartItems();
|
||||
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if ($withItemsInPromo || ! $cartItem->getPromo()) {
|
||||
$total += $cartItem->getRealPrice() * $cartItem->getQuantity();
|
||||
}
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
public function getCartTotalTaxPrice()
|
||||
public function getCartTotalTaxPrice($withItemsInPromo = true)
|
||||
{
|
||||
$taxCountry = $this->getContainer()->get('thelia.taxEngine')->getDeliveryCountry();
|
||||
$cartItems = $this->getRequest()->getSession()->getCart()->getCartItems();
|
||||
|
||||
return $this->getCart()->getTaxedAmount($taxCountry, false);
|
||||
$total = 0;
|
||||
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if ($withItemsInPromo || ! $cartItem->getPromo()) {
|
||||
$total += $cartItem->getRealTaxedPrice($taxCountry) * $cartItem->getQuantity();
|
||||
}
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Country the delivery country
|
||||
*/
|
||||
public function getDeliveryCountry()
|
||||
{
|
||||
return $this->getContainer()->get('thelia.taxEngine')->getDeliveryCountry();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Thelia\Condition\ConditionFactory;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
use Thelia\Exception\CouponExpiredException;
|
||||
use Thelia\Exception\CouponNoUsageLeftException;
|
||||
use Thelia\Exception\InvalidConditionException;
|
||||
use Thelia\Model\Coupon;
|
||||
|
||||
@@ -62,12 +63,19 @@ class CouponFactory
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check coupon expiration date
|
||||
if ($couponModel->getExpirationDate() < new \DateTime()) {
|
||||
throw new CouponExpiredException($couponCode);
|
||||
}
|
||||
|
||||
// Check coupon usage count
|
||||
if (! $couponModel->isUsageUnlimited() && $couponModel->getUsagesLeft($this->facade->getCustomer()->getId()) <= 0) {
|
||||
throw new CouponNoUsageLeftException($couponCode);
|
||||
}
|
||||
|
||||
/** @var CouponInterface $couponInterface */
|
||||
$couponInterface = $this->buildCouponFromModel($couponModel);
|
||||
|
||||
if ($couponInterface && $couponInterface->getConditions()->count() == 0) {
|
||||
throw new InvalidConditionException(
|
||||
get_class($couponInterface)
|
||||
@@ -107,7 +115,10 @@ class CouponFactory
|
||||
$model->getIsAvailableOnSpecialOffers(),
|
||||
$model->getIsEnabled(),
|
||||
$model->getMaxUsage(),
|
||||
$model->getExpirationDate()
|
||||
$model->getExpirationDate(),
|
||||
$model->getFreeShippingForCountries(),
|
||||
$model->getFreeShippingForModules(),
|
||||
$model->getPerCustomerUsageCount()
|
||||
);
|
||||
|
||||
/** @var ConditionFactory $conditionFactory */
|
||||
|
||||
@@ -15,7 +15,14 @@ namespace Thelia\Coupon;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Thelia\Condition\Implementation\ConditionInterface;
|
||||
use Thelia\Coupon\Type\CouponInterface;
|
||||
use Thelia\Log\Tlog;
|
||||
use Thelia\Model\AddressQuery;
|
||||
use Thelia\Model\CouponModule;
|
||||
use Thelia\Model\Coupon;
|
||||
use Thelia\Model\CouponCountry;
|
||||
use Thelia\Model\CouponCustomerCount;
|
||||
use Thelia\Model\CouponCustomerCountQuery;
|
||||
use Thelia\Model\Order;
|
||||
|
||||
/**
|
||||
* Manage how Coupons could interact with a Checkout
|
||||
@@ -51,14 +58,15 @@ class CouponManager
|
||||
|
||||
/**
|
||||
* Get Discount for the given Coupons
|
||||
*
|
||||
* @api
|
||||
* @return float checkout discount
|
||||
*/
|
||||
public function getDiscount()
|
||||
{
|
||||
$discount = 0.00;
|
||||
|
||||
$coupons = $this->facade->getCurrentCoupons();
|
||||
|
||||
if (count($coupons) > 0) {
|
||||
$couponsKept = $this->sortCoupons($coupons);
|
||||
|
||||
@@ -66,6 +74,7 @@ class CouponManager
|
||||
|
||||
// Just In Case test
|
||||
$checkoutTotalPrice = $this->facade->getCartTotalTaxPrice();
|
||||
|
||||
if ($discount >= $checkoutTotalPrice) {
|
||||
$discount = $checkoutTotalPrice;
|
||||
}
|
||||
@@ -76,11 +85,15 @@ class CouponManager
|
||||
|
||||
/**
|
||||
* Check if there is a Coupon removing Postage
|
||||
*
|
||||
* @param Order $order the order for which we have to check if postage is free
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCouponRemovingPostage()
|
||||
public function isCouponRemovingPostage(Order $order)
|
||||
{
|
||||
$coupons = $this->facade->getCurrentCoupons();
|
||||
|
||||
if (count($coupons) == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -89,7 +102,60 @@ class CouponManager
|
||||
|
||||
/** @var CouponInterface $coupon */
|
||||
foreach ($couponsKept as $coupon) {
|
||||
|
||||
if ($coupon->isRemovingPostage()) {
|
||||
|
||||
// Check if delivery country is on the list of countries for which delivery is free
|
||||
// If the list is empty, the shipping is free for all countries.
|
||||
$couponCountries = $coupon->getFreeShippingForCountries();
|
||||
|
||||
if (! $couponCountries->isEmpty()) {
|
||||
|
||||
if (null === $deliveryAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$countryValid = false;
|
||||
|
||||
$deliveryCountryId = $deliveryAddress->getCountryId();
|
||||
|
||||
/** @var CouponCountry $couponCountry */
|
||||
foreach ($couponCountries as $couponCountry) {
|
||||
if ($deliveryCountryId == $couponCountry->getCountryId()) {
|
||||
$countryValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $countryValid) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if shipping method is on the list of methods for which delivery is free
|
||||
// If the list is empty, the shipping is free for all methods.
|
||||
$couponModules = $coupon->getFreeShippingForModules();
|
||||
|
||||
if (! $couponModules->isEmpty()) {
|
||||
|
||||
$moduleValid = false;
|
||||
|
||||
$shippingModuleId = $order->getDeliveryModuleId();
|
||||
|
||||
/** @var CouponModule $couponModule */
|
||||
foreach ($couponModules as $couponModule) {
|
||||
if ($shippingModuleId == $couponModule->getModuleId()) {
|
||||
$moduleValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $moduleValid) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// All conditions are met, the shipping is free !
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -205,32 +271,86 @@ class CouponManager
|
||||
return $this->availableConditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data kept by coupons
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$coupons = $this->facade->getCurrentCoupons();
|
||||
|
||||
/** @var CouponInterface $coupon */
|
||||
foreach ($coupons as $coupon) {
|
||||
$coupon->clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement this coupon quantity
|
||||
*
|
||||
* To call when a coupon is consumed
|
||||
*
|
||||
* @param \Thelia\Model\Coupon $coupon Coupon consumed
|
||||
* @param \Thelia\Model\Coupon $coupon Coupon consumed
|
||||
* @param int|null $customerId the ID of the ordering customer
|
||||
*
|
||||
* @return int Usage left after decremental
|
||||
*/
|
||||
public function decrementQuantity(Coupon $coupon)
|
||||
public function decrementQuantity(Coupon $coupon, $customerId = null)
|
||||
{
|
||||
$ret = -1;
|
||||
try {
|
||||
|
||||
$usageLeft = $coupon->getMaxUsage();
|
||||
|
||||
if ($usageLeft > 0) {
|
||||
$usageLeft--;
|
||||
$coupon->setMaxUsage($usageLeft);
|
||||
|
||||
$coupon->save();
|
||||
$ret = $usageLeft;
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
if ($coupon->isUsageUnlimited()) {
|
||||
$ret = true;
|
||||
} else {
|
||||
$ret = false;
|
||||
|
||||
try {
|
||||
|
||||
$usageLeft = $coupon->getUsagesLeft($customerId);
|
||||
|
||||
if ($usageLeft > 0) {
|
||||
|
||||
// If the coupon usage is per user, add an entry to coupon customer usage count table
|
||||
if ($coupon->getPerCustomerUsageCount()) {
|
||||
|
||||
if (null == $customerId) {
|
||||
throw new \LogicException("Customer should not be null at this time.");
|
||||
}
|
||||
|
||||
$ccc = CouponCustomerCountQuery::create()
|
||||
->filterByCouponId($coupon->getId())
|
||||
->filterByCustomerId($customerId)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if ($ccc === null) {
|
||||
$ccc = new CouponCustomerCount();
|
||||
|
||||
$ccc
|
||||
->setCustomerId($customerId)
|
||||
->setCouponId($coupon->getId())
|
||||
->setCount(0);
|
||||
}
|
||||
|
||||
$newCount = 1 + $ccc->getCount();
|
||||
|
||||
$ccc
|
||||
->setCount($newCount)
|
||||
->save()
|
||||
;
|
||||
|
||||
$ret = $usageLeft - $newCount;
|
||||
} else {
|
||||
$usageLeft--;
|
||||
|
||||
$coupon->setMaxUsage($usageLeft);
|
||||
|
||||
$coupon->save();
|
||||
|
||||
$ret = $usageLeft;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $ex) {
|
||||
// Just log the problem.
|
||||
Tlog::getInstance()->addError(sprintf("Failed to decrement coupon %s: %s", $coupon->getCode(), $ex->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
|
||||
@@ -18,6 +18,7 @@ use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Thelia\Condition\ConditionEvaluator;
|
||||
use Thelia\Core\HttpFoundation\Request;
|
||||
use Thelia\Core\Template\ParserInterface;
|
||||
use Thelia\Model\Country;
|
||||
use Thelia\Model\Coupon;
|
||||
|
||||
/**
|
||||
@@ -51,6 +52,11 @@ interface FacadeInterface
|
||||
*/
|
||||
public function getDeliveryAddress();
|
||||
|
||||
/**
|
||||
* @return Country the delivery country
|
||||
*/
|
||||
public function getDeliveryCountry();
|
||||
|
||||
/**
|
||||
* Return an Customer a CouponManager can process
|
||||
*
|
||||
@@ -68,17 +74,19 @@ interface FacadeInterface
|
||||
/**
|
||||
* Return Products total price
|
||||
* CartTotalPrice = Checkout total - discount - postage
|
||||
* @param bool $withItemsInPromo true (default) if item in promotion should be included in the total, false otherwise.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getCartTotalPrice();
|
||||
public function getCartTotalPrice($withItemsInPromo = true);
|
||||
|
||||
/**
|
||||
* Return Product total tax price
|
||||
* @param bool $withItemsInPromo true (default) if item in promotion should be included in the total, false otherwise.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function getCartTotalTaxPrice();
|
||||
public function getCartTotalTaxPrice($withItemsInPromo = true);
|
||||
|
||||
/**
|
||||
* Return the Checkout currency EUR|USD
|
||||
|
||||
128
core/lib/Thelia/Coupon/Type/AbstractRemove.php
Normal file
128
core/lib/Thelia/Coupon/Type/AbstractRemove.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Model\CartItem;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
abstract class AbstractRemove extends CouponAbstract implements AmountAndPercentageCouponInterface
|
||||
{
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
*
|
||||
* @param Array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
/**
|
||||
* Get the discount for a specific cart item.
|
||||
*
|
||||
* @param CartItem $cartItem the cart item
|
||||
* @return float the discount value
|
||||
*/
|
||||
abstract public function getCartItemDiscount($cartItem);
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
$code,
|
||||
$title,
|
||||
$shortDescription,
|
||||
$description,
|
||||
array $effects,
|
||||
$isCumulative,
|
||||
$isRemovingPostage,
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
)
|
||||
{
|
||||
parent::set(
|
||||
$facade, $code, $title, $shortDescription, $description, $effects,
|
||||
$isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
);
|
||||
|
||||
$this->setFieldsValue($effects);
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
// This coupon subtracts the specified amount from the order total
|
||||
// for each product of the selected categories.
|
||||
$discount = 0;
|
||||
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
|
||||
$categories = $cartItem->getProduct()->getCategories();
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
|
||||
if (in_array($category->getId(), $this->category_list)) {
|
||||
$discount += $this->getCartItemDiscount($cartItem);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $discount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBaseBackOfficeInputs($templateName, $otherFields)
|
||||
{
|
||||
return $this->facade->getParser()->render($templateName, $otherFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getBaseFieldList($otherFields)
|
||||
{
|
||||
return array_merge($otherFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function checkBaseCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
return $fieldValue;
|
||||
}
|
||||
}
|
||||
180
core/lib/Thelia/Coupon/Type/AbstractRemoveOnAttributeValues.php
Normal file
180
core/lib/Thelia/Coupon/Type/AbstractRemoveOnAttributeValues.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Model\AttributeCombination;
|
||||
use Thelia\Model\CartItem;
|
||||
|
||||
/**
|
||||
* The base class to process a discount related to Attribute values.
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
abstract class AbstractRemoveOnAttributeValues extends CouponAbstract implements AmountAndPercentageCouponInterface
|
||||
{
|
||||
const ATTRIBUTES_AV_LIST = 'attribute_avs';
|
||||
const ATTRIBUTE = 'attribute_id';
|
||||
|
||||
public $attributeAvList = array();
|
||||
public $attribute = 0;
|
||||
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
* @param Array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
/**
|
||||
* Get the discount for a specific cart item.
|
||||
*
|
||||
* @param CartItem $cartItem the cart item
|
||||
* @return float the discount value
|
||||
*/
|
||||
abstract public function getCartItemDiscount($cartItem);
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
$code,
|
||||
$title,
|
||||
$shortDescription,
|
||||
$description,
|
||||
array $effects,
|
||||
$isCumulative,
|
||||
$isRemovingPostage,
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
)
|
||||
{
|
||||
parent::set(
|
||||
$facade, $code, $title, $shortDescription, $description, $effects,
|
||||
$isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
);
|
||||
|
||||
$this->attributeAvList = isset($effects[self::ATTRIBUTES_AV_LIST]) ? $effects[self::ATTRIBUTES_AV_LIST] : array();
|
||||
|
||||
if (! is_array($this->attributeAvList)) $this->attributeAvList = array($this->attributeAvList);
|
||||
|
||||
$this->attribute = isset($effects[self::ATTRIBUTE]) ? $effects[self::ATTRIBUTE] : 0;
|
||||
|
||||
$this->setFieldsValue($effects);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
// This coupon subtracts the specified amount from the order total
|
||||
// for each product which uses the selected attributes
|
||||
$discount = 0;
|
||||
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
|
||||
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
|
||||
$productSaleElements = $cartItem->getProductSaleElements();
|
||||
|
||||
$combinations = $productSaleElements->getAttributeCombinations();
|
||||
|
||||
/** @var AttributeCombination $combination */
|
||||
foreach ($combinations as $combination) {
|
||||
|
||||
$attrValue = $combination->getAttributeAvId();
|
||||
|
||||
if (in_array($attrValue, $this->attributeAvList)) {
|
||||
$discount += $this->getCartItemDiscount($cartItem);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $discount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the template which implements coupon specific user-input,
|
||||
* using the provided template file, and a list of specific input fields.
|
||||
*
|
||||
* @param string $templateName the path to the template
|
||||
* @param array $otherFields the list of additional fields fields
|
||||
*
|
||||
* @return string the rendered template.
|
||||
*/
|
||||
public function drawBaseBackOfficeInputs($templateName, $otherFields)
|
||||
{
|
||||
return $this->facade->getParser()->render($templateName, array_merge($otherFields, [
|
||||
|
||||
// The attributes list field
|
||||
'attribute_field_name' => $this->makeCouponFieldName(self::ATTRIBUTE),
|
||||
'attribute_value' => $this->attribute,
|
||||
|
||||
// The attributes list field
|
||||
'attribute_av_field_name' => $this->makeCouponFieldName(self::ATTRIBUTES_AV_LIST),
|
||||
'attribute_av_values' => $this->attributeAvList
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getBaseFieldList($otherFields)
|
||||
{
|
||||
return array_merge($otherFields, [self::ATTRIBUTE, self::ATTRIBUTES_AV_LIST]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function checkBaseCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
if ($fieldName === self::ATTRIBUTE) {
|
||||
if (empty($fieldValue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select an attribute'
|
||||
)
|
||||
);
|
||||
}
|
||||
} elseif ($fieldName === self::ATTRIBUTES_AV_LIST) {
|
||||
if (empty($fieldValue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select at least one attribute value'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldValue;
|
||||
}
|
||||
}
|
||||
152
core/lib/Thelia/Coupon/Type/AbstractRemoveOnCategories.php
Normal file
152
core/lib/Thelia/Coupon/Type/AbstractRemoveOnCategories.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Model\CartItem;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
abstract class AbstractRemoveOnCategories extends CouponAbstract implements AmountAndPercentageCouponInterface
|
||||
{
|
||||
const CATEGORIES_LIST = 'categories';
|
||||
|
||||
protected $category_list = array();
|
||||
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
*
|
||||
* @param Array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
/**
|
||||
* Get the discount for a specific cart item.
|
||||
*
|
||||
* @param CartItem $cartItem the cart item
|
||||
* @return float the discount value
|
||||
*/
|
||||
abstract public function getCartItemDiscount($cartItem);
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
$code,
|
||||
$title,
|
||||
$shortDescription,
|
||||
$description,
|
||||
array $effects,
|
||||
$isCumulative,
|
||||
$isRemovingPostage,
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
)
|
||||
{
|
||||
parent::set(
|
||||
$facade, $code, $title, $shortDescription, $description, $effects,
|
||||
$isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
);
|
||||
|
||||
$this->category_list = isset($effects[self::CATEGORIES_LIST]) ? $effects[self::CATEGORIES_LIST] : array();
|
||||
|
||||
if (! is_array($this->category_list)) $this->category_list = array($this->category_list);
|
||||
|
||||
$this->setFieldsValue($effects);
|
||||
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
// This coupon subtracts the specified amount from the order total
|
||||
// for each product of the selected categories.
|
||||
$discount = 0;
|
||||
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
|
||||
$categories = $cartItem->getProduct()->getCategories();
|
||||
|
||||
/** @var Category $category */
|
||||
foreach ($categories as $category) {
|
||||
|
||||
if (in_array($category->getId(), $this->category_list)) {
|
||||
$discount += $this->getCartItemDiscount($cartItem);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $discount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBaseBackOfficeInputs($templateName, $otherFields)
|
||||
{
|
||||
return $this->facade->getParser()->render($templateName, array_merge($otherFields, [
|
||||
|
||||
// The categories list field
|
||||
'categories_field_name' => $this->makeCouponFieldName(self::CATEGORIES_LIST),
|
||||
'categories_values' => $this->category_list
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getBaseFieldList($otherFields)
|
||||
{
|
||||
return array_merge($otherFields, [self::CATEGORIES_LIST]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function checkBaseCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
if ($fieldName === self::CATEGORIES_LIST) {
|
||||
if (empty($fieldValue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select at least one category'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldValue;
|
||||
}
|
||||
}
|
||||
162
core/lib/Thelia/Coupon/Type/AbstractRemoveOnProducts.php
Normal file
162
core/lib/Thelia/Coupon/Type/AbstractRemoveOnProducts.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Model\CartItem;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
abstract class AbstractRemoveOnProducts extends CouponAbstract implements AmountAndPercentageCouponInterface
|
||||
{
|
||||
const CATEGORY_ID = 'category_id';
|
||||
const PRODUCTS_LIST = 'products';
|
||||
|
||||
public $category_id = 0;
|
||||
public $product_list = array();
|
||||
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
*
|
||||
* @param Array $effects the Coupon effects params
|
||||
*/
|
||||
abstract public function setFieldsValue($effects);
|
||||
|
||||
/**
|
||||
* Get the discount for a specific cart item.
|
||||
*
|
||||
* @param CartItem $cartItem the cart item
|
||||
* @return float the discount value
|
||||
*/
|
||||
abstract public function getCartItemDiscount($cartItem);
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
$code,
|
||||
$title,
|
||||
$shortDescription,
|
||||
$description,
|
||||
array $effects,
|
||||
$isCumulative,
|
||||
$isRemovingPostage,
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
)
|
||||
{
|
||||
parent::set(
|
||||
$facade, $code, $title, $shortDescription, $description, $effects,
|
||||
$isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
);
|
||||
|
||||
$this->product_list = isset($effects[self::PRODUCTS_LIST]) ? $effects[self::PRODUCTS_LIST] : array();
|
||||
|
||||
if (! is_array($this->product_list)) $this->product_list = array($this->product_list);
|
||||
|
||||
$this->category_id = isset($effects[self::CATEGORY_ID]) ? $effects[self::CATEGORY_ID] : 0;
|
||||
|
||||
$this->setFieldsValue($effects);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
// This coupon subtracts the specified amount from the order total
|
||||
// for each product of the selected products.
|
||||
$discount = 0;
|
||||
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if (in_array($cartItem->getProduct()->getId(), $this->product_list)) {
|
||||
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
|
||||
$discount += $this->getCartItemDiscount($cartItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $discount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBaseBackOfficeInputs($templateName, $otherFields)
|
||||
{
|
||||
return $this->facade->getParser()->render($templateName, array_merge($otherFields, [
|
||||
|
||||
// The category ID field
|
||||
'category_id_field_name' => $this->makeCouponFieldName(self::CATEGORY_ID),
|
||||
'category_id_value' => $this->category_id,
|
||||
|
||||
// The products list field
|
||||
'products_field_name' => $this->makeCouponFieldName(self::PRODUCTS_LIST),
|
||||
'products_values' => $this->product_list,
|
||||
'products_values_csv' => implode(', ', $this->product_list)
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getBaseFieldList($otherFields)
|
||||
{
|
||||
return array_merge($otherFields, [self::CATEGORY_ID, self::PRODUCTS_LIST]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function checkBaseCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
if ($fieldName === self::CATEGORY_ID) {
|
||||
if (empty($fieldValue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select a category'
|
||||
)
|
||||
);
|
||||
}
|
||||
} elseif ($fieldName === self::PRODUCTS_LIST) {
|
||||
if (empty($fieldValue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select at least one product'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
/**
|
||||
* Represents a Coupon ready to be processed in a Checkout process
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
*
|
||||
*/
|
||||
interface AmountAndPercentageCouponInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Set the value of specific coupon fields.
|
||||
* @param Array $effects the Coupon effects params
|
||||
*/
|
||||
public function setFieldsValue($effects);
|
||||
|
||||
/**
|
||||
* Get the discount for a specific cart item.
|
||||
*
|
||||
* @param CartItem $cartItem the cart item
|
||||
* @return float the discount value
|
||||
*/
|
||||
public function getCartItemDiscount($cartItem);
|
||||
|
||||
/**
|
||||
* Renders the template which implements coupon specific user-input,
|
||||
* using the provided template file, and a list of specific input fields.
|
||||
*
|
||||
* @param string $templateName the path to the template
|
||||
* @param array $otherFields the list of additional fields fields
|
||||
*
|
||||
* @return string the rendered template.
|
||||
*/
|
||||
public function drawBaseBackOfficeInputs($templateName, $otherFields);
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getBaseFieldList($otherFields);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function checkBaseCouponFieldValue($fieldName, $fieldValue);
|
||||
}
|
||||
93
core/lib/Thelia/Coupon/Type/AmountCouponTrait.php
Normal file
93
core/lib/Thelia/Coupon/Type/AmountCouponTrait.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
|
||||
/**
|
||||
* A trait to manage a coupon which removes a constant amount from the order total.
|
||||
* Should be used on coupons classes which implements AmountAndPercentageCouponInterface
|
||||
*
|
||||
* Class AmountCouponTrait
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
* @package Thelia\Coupon\Type
|
||||
*/
|
||||
Trait AmountCouponTrait {
|
||||
|
||||
// The amount is already defined in CouponAbstract, and should not be redefined here.
|
||||
// protected $amount = 0;
|
||||
|
||||
/**
|
||||
* Should return the amount field name, defined in the parent class.
|
||||
*
|
||||
* @return string the percentage field name
|
||||
*/
|
||||
abstract protected function getAmountFieldName();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function setFieldsValue($effects)
|
||||
{
|
||||
$this->amount = $effects[$this->getAmountFieldName()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getCartItemDiscount($cartItem)
|
||||
{
|
||||
return $cartItem->getQuantity() * $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function callDrawBackOfficeInputs($templateName)
|
||||
{
|
||||
return $this->drawBaseBackOfficeInputs($templateName, [
|
||||
'amount_field_name' => $this->makeCouponFieldName($this->getAmountFieldName()),
|
||||
'amount_value' => $this->amount
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getFieldList()
|
||||
{
|
||||
return $this->getBaseFieldList([$this->getAmountFieldName()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function checkCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
$this->checkBaseCouponFieldValue($fieldName, $fieldValue);
|
||||
|
||||
if ($fieldName === $this->getAmountFieldName()) {
|
||||
|
||||
if (floatval($fieldValue) < 0) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Value %val for Discount Amount is invalid. Please enter a positive value.',
|
||||
[ '%val' => $fieldValue]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldValue;
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,14 @@
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Condition\ConditionEvaluator;
|
||||
use Thelia\Condition\ConditionOrganizerInterface;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Condition\ConditionOrganizerInterface;
|
||||
use Thelia\Form\CouponCreationForm;
|
||||
use Thelia\Model\CouponCountry;
|
||||
use Thelia\Model\CouponModule;
|
||||
|
||||
/**
|
||||
* Assist in writing a CouponInterface
|
||||
@@ -27,12 +30,21 @@ use Thelia\Condition\ConditionOrganizerInterface;
|
||||
*/
|
||||
abstract class CouponAbstract implements CouponInterface
|
||||
{
|
||||
const INPUT_EXTENDED__NAME = 'thelia_coupon_creation_extended';
|
||||
/**
|
||||
* The dataset name for all coupon specific input fields, that do not appear in the CouPonCreationForm form.
|
||||
*
|
||||
* In the input form, these fields have to be created like:
|
||||
*
|
||||
* thelia_coupon_specific[my_field, thelia_coupon_creation_extended[my_other_field]
|
||||
*
|
||||
* use the makeCouponField() method to do that safely.
|
||||
*/
|
||||
const COUPON_DATASET_NAME = 'coupon_specific';
|
||||
|
||||
const INPUT_AMOUNT_NAME = 'amount';
|
||||
|
||||
/** @var array Extended Inputs to manage */
|
||||
protected $extendedInputs = array();
|
||||
/**
|
||||
* A standard 'amount' filed name, thant can be used in coupons which extends this class
|
||||
*/
|
||||
const AMOUNT_FIELD_NAME = 'amount';
|
||||
|
||||
/** @var FacadeInterface Provide necessary value from Thelia */
|
||||
protected $facade = null;
|
||||
@@ -88,6 +100,15 @@ abstract class CouponAbstract implements CouponInterface
|
||||
/** @var bool if Coupon is available for Products already on special offers */
|
||||
protected $isAvailableOnSpecialOffers = false;
|
||||
|
||||
/** @var CouponCountry[] list of country IDs for which shipping is free. All if empty*/
|
||||
protected $freeShippingForCountries = [];
|
||||
|
||||
/** @var CouponModule[] list of shipping module IDs for which shippiog is free. All if empty*/
|
||||
protected $freeShippingForModules = [];
|
||||
|
||||
/** @var true if usage count is per customer only */
|
||||
protected $perCustomerUsageCount;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -115,23 +136,7 @@ abstract class CouponAbstract implements CouponInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Coupon
|
||||
*
|
||||
* @param FacadeInterface $facade Provides necessary value from Thelia
|
||||
* @param string $code Coupon code (ex: XMAS)
|
||||
* @param string $title Coupon title (ex: Coupon for XMAS)
|
||||
* @param string $shortDescription Coupon short description
|
||||
* @param string $description Coupon description
|
||||
* @param array $effects Coupon effects params
|
||||
* @param bool $isCumulative If Coupon is cumulative
|
||||
* @param bool $isRemovingPostage If Coupon is removing postage
|
||||
* @param bool $isAvailableOnSpecialOffers If available on Product already
|
||||
* on special offer price
|
||||
* @param bool $isEnabled False if Coupon is disabled by admin
|
||||
* @param int $maxUsage How many usage left
|
||||
* @param \Datetime $expirationDate When the Code is expiring
|
||||
*
|
||||
* @return $this
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
@@ -145,7 +150,10 @@ abstract class CouponAbstract implements CouponInterface
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate
|
||||
\DateTime $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
)
|
||||
{
|
||||
$this->code = $code;
|
||||
@@ -163,11 +171,34 @@ abstract class CouponAbstract implements CouponInterface
|
||||
$this->facade = $facade;
|
||||
|
||||
$this->effects = $effects;
|
||||
$this->amount = $effects[self::INPUT_AMOUNT_NAME];
|
||||
// Amount is now optional.
|
||||
$this->amount = isset($effects[self::AMOUNT_FIELD_NAME]) ? $effects[self::AMOUNT_FIELD_NAME] : 0;
|
||||
|
||||
$this->freeShippingForCountries = $freeShippingForCountries;
|
||||
$this->freeShippingForModules = $freeShippingForModules;
|
||||
$this->perCustomerUsageCount = $perCustomerUsageCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param true $perCustomerUsageCount
|
||||
*/
|
||||
public function setPerCustomerUsageCount($perCustomerUsageCount)
|
||||
{
|
||||
$this->perCustomerUsageCount = $perCustomerUsageCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true
|
||||
*/
|
||||
public function getPerCustomerUsageCount()
|
||||
{
|
||||
return $this->perCustomerUsageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Coupon code (ex: XMAS)
|
||||
*
|
||||
@@ -231,10 +262,23 @@ abstract class CouponAbstract implements CouponInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Return effects generated by the coupon
|
||||
* A negative value
|
||||
*
|
||||
* @return float Amount removed from the Total Checkout
|
||||
* @return array list of country IDs for which shipping is free. All if empty
|
||||
*/
|
||||
public function getFreeShippingForCountries()
|
||||
{
|
||||
return $this->freeShippingForCountries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array list of module IDs for which shipping is free. All if empty
|
||||
*/
|
||||
public function getFreeShippingForModules()
|
||||
{
|
||||
return $this->freeShippingForModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
@@ -347,6 +391,19 @@ abstract class CouponAbstract implements CouponInterface
|
||||
return $this->conditionEvaluator->isMatching($this->conditions);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the field label than will be displayed in the form.
|
||||
* This method should be overridden to be useful.
|
||||
*
|
||||
* For backward compatibility only.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputName()
|
||||
{
|
||||
return "Please override getInputName() method";
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the input displayed in the BackOffice
|
||||
* allowing Admin to set its Coupon effect
|
||||
@@ -358,19 +415,96 @@ abstract class CouponAbstract implements CouponInterface
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/type-fragments/remove-x.html', [
|
||||
'label' => $this->getInputName(),
|
||||
'fieldName' => self::INPUT_AMOUNT_NAME,
|
||||
'fieldId' => self::AMOUNT_FIELD_NAME,
|
||||
'fieldName' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME),
|
||||
'value' => $this->amount
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all extended inputs name to manage
|
||||
* This methods checks a field value. If the field has a correct value, this value is returned
|
||||
* Otherwise, an InvalidArgumentException describing the problem should be thrown.
|
||||
*
|
||||
* This method should be ovveriden to be useful.
|
||||
*
|
||||
* @param $fieldName
|
||||
* @param $fieldValue
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException if the field valiue is not valid.
|
||||
*/
|
||||
public function getExtendedInputs()
|
||||
protected function checkCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
return $this->extendedInputs;
|
||||
return $fieldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to get the value of a standard field name
|
||||
*
|
||||
* @param string $fieldName the field name
|
||||
* @param array $data the input form data (e.g. $form->getData())
|
||||
* @param mixed $defaultValue the default value if the field is not found.
|
||||
*
|
||||
* @return mixed the input value, or the default one
|
||||
*
|
||||
* @throws \InvalidArgumentException if the field is not found, and no default value has been defined.
|
||||
*/
|
||||
protected function getCouponFieldValue($fieldName, $data, $defaultValue = null)
|
||||
{
|
||||
if (isset($data[self::COUPON_DATASET_NAME][$fieldName])) {
|
||||
return $this->checkCouponFieldValue(
|
||||
$fieldName,
|
||||
$data[self::COUPON_DATASET_NAME][$fieldName]
|
||||
);
|
||||
} elseif (null !== $defaultValue) {
|
||||
return $defaultValue;
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf("The coupon field name %s was not found in the coupon form", $fieldName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to create an standard field name that will be used in the coupon form
|
||||
*
|
||||
* @param string $fieldName the field name
|
||||
* @return string the complete name, ready to be used in a form.
|
||||
*/
|
||||
protected function makeCouponFieldName($fieldName)
|
||||
{
|
||||
return sprintf("%s[%s][%s]", CouponCreationForm::COUPON_CREATION_FORM_NAME, self::COUPON_DATASET_NAME, $fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the fields name for this coupon.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFieldList()
|
||||
{
|
||||
return [self::AMOUNT_FIELD_NAME];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the effect array from the list of fields
|
||||
*
|
||||
* @param array $data the input form data (e.g. $form->getData())
|
||||
* @return array a filedName => fieldValue array
|
||||
*/
|
||||
public function getEffects($data)
|
||||
{
|
||||
$effects = [];
|
||||
|
||||
foreach ($this->getFieldList() as $fieldName) {
|
||||
$effects[$fieldName] = $this->getCouponFieldValue($fieldName, $data);
|
||||
}
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
// Does nothing. Override this function as needed.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Propel\Runtime\Collection\ObjectCollection;
|
||||
use Thelia\Condition\ConditionCollection;
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
|
||||
@@ -31,13 +32,6 @@ interface CouponInterface
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Get I18n amount input name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputName();
|
||||
|
||||
/**
|
||||
* Get I18n tooltip
|
||||
*
|
||||
@@ -55,19 +49,22 @@ interface CouponInterface
|
||||
/**
|
||||
* Set Coupon
|
||||
*
|
||||
* @param FacadeInterface $facade Provides necessary value from Thelia
|
||||
* @param string $code Coupon code (ex: XMAS)
|
||||
* @param string $title Coupon title (ex: Coupon for XMAS)
|
||||
* @param string $shortDescription Coupon short description
|
||||
* @param string $description Coupon description
|
||||
* @param array $effects Coupon effects params
|
||||
* @param bool $isCumulative If Coupon is cumulative
|
||||
* @param bool $isRemovingPostage If Coupon is removing postage
|
||||
* @param bool $isAvailableOnSpecialOffers If available on Product already
|
||||
* on special offer price
|
||||
* @param bool $isEnabled False if Coupon is disabled by admin
|
||||
* @param int $maxUsage How many usage left
|
||||
* @param \Datetime $expirationDate When the Code is expiring
|
||||
* @param FacadeInterface $facade Provides necessary value from Thelia
|
||||
* @param string $code Coupon code (ex: XMAS)
|
||||
* @param string $title Coupon title (ex: Coupon for XMAS)
|
||||
* @param string $shortDescription Coupon short description
|
||||
* @param string $description Coupon description
|
||||
* @param array $effects Coupon effects params
|
||||
* @param bool $isCumulative If Coupon is cumulative
|
||||
* @param bool $isRemovingPostage If Coupon is removing postage
|
||||
* @param bool $isAvailableOnSpecialOffers If available on Product already
|
||||
* on special offer price
|
||||
* @param bool $isEnabled False if Coupon is disabled by admin
|
||||
* @param int $maxUsage How many usage left
|
||||
* @param \Datetime $expirationDate When the Code is expiring
|
||||
* @param ObjectCollection $freeShippingForCountries list of countries which shipping is free. All if empty
|
||||
* @param ObjectCollection $freeShippingForModules list of modules for which shipping is free. All if empty
|
||||
* @param bool $perCustomerUsageCount true if usage count is per customer only
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
@@ -81,7 +78,11 @@ interface CouponInterface
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate);
|
||||
\DateTime $expirationDate,
|
||||
$freeShippingForCountries,
|
||||
$freeShippingForModules,
|
||||
$perCustomerUsageCount
|
||||
);
|
||||
|
||||
/**
|
||||
* Return Coupon code (ex: XMAS)
|
||||
@@ -160,6 +161,14 @@ interface CouponInterface
|
||||
*/
|
||||
public function isAvailableOnSpecialOffers();
|
||||
|
||||
/**
|
||||
* Check if the Coupon can be used against a
|
||||
* product already with a special offer price
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getPerCustomerUsageCount();
|
||||
|
||||
/**
|
||||
* Check if Coupon has been disabled by admin
|
||||
*
|
||||
@@ -212,10 +221,27 @@ interface CouponInterface
|
||||
public function drawBackOfficeInputs();
|
||||
|
||||
/**
|
||||
* Get all extended inputs name to manage
|
||||
*
|
||||
* @return mixed
|
||||
* @return ObjectCollection list of country IDs for which shipping is free. All if empty
|
||||
*/
|
||||
public function getExtendedInputs();
|
||||
public function getFreeShippingForCountries();
|
||||
|
||||
/**
|
||||
* @return ObjectCollection list of module IDs for which shipping is free. All if empty
|
||||
*/
|
||||
public function getFreeShippingForModules();
|
||||
|
||||
/**
|
||||
* Create the effect array from the list of fields
|
||||
*
|
||||
* @param array $data the input form data (e.g. $form->getData())
|
||||
*
|
||||
* @return array a filedName => fieldValue array
|
||||
*/
|
||||
public function getEffects($data);
|
||||
|
||||
/**
|
||||
* Clear all the data the coupon may have stored, called after an order is completed.
|
||||
*/
|
||||
public function clear();
|
||||
|
||||
}
|
||||
|
||||
345
core/lib/Thelia/Coupon/Type/FreeProduct.php
Normal file
345
core/lib/Thelia/Coupon/Type/FreeProduct.php
Normal file
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Core\Event\Cart\CartEvent;
|
||||
use Thelia\Core\Event\TheliaEvents;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\CartItem;
|
||||
use Thelia\Model\CartItemQuery;
|
||||
use Thelia\Model\Product;
|
||||
use Thelia\Model\ProductQuery;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class FreeProduct extends AbstractRemoveOnProducts
|
||||
{
|
||||
const OFFERED_PRODUCT_ID = 'offered_product_id';
|
||||
const OFFERED_CATEGORY_ID = 'offered_category_id';
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.free_product';
|
||||
|
||||
protected $offeredProductId;
|
||||
protected $offeredCategoryId;
|
||||
|
||||
/**
|
||||
* This constant is user to mark a free product as in the process of being added to the cart,
|
||||
* but the CartItem ID is not yet been defined.
|
||||
*/
|
||||
const ADD_TO_CART_IN_PROCESS = -1;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function setFieldsValue($effects)
|
||||
{
|
||||
$this->offeredProductId = $effects[self::OFFERED_PRODUCT_ID];
|
||||
$this->offeredCategoryId = $effects[self::OFFERED_CATEGORY_ID];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getCartItemDiscount($cartItem)
|
||||
{
|
||||
// This method is not used, we use our own implementation of exec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The session variable where the cart item IDs for the free products are stored
|
||||
*/
|
||||
protected function getSessionVarName()
|
||||
{
|
||||
return "coupon.free_product.cart_items." . $this->getCode();
|
||||
}
|
||||
/**
|
||||
* Return the cart item id which contains the free product related to a given product
|
||||
*
|
||||
* @param Product $product the product in the cart which triggered the discount
|
||||
*
|
||||
* @return bool|int|CartItem the cart item which contains the free product, or false if the product is no longer in the cart, or ADD_TO_CART_IN_PROCESS if the adding process is not finished
|
||||
*/
|
||||
protected function getRelatedCartItem($product)
|
||||
{
|
||||
$cartItemIdList = $this->facade->getRequest()->getSession()->get(
|
||||
$this->getSessionVarName(),
|
||||
array()
|
||||
);
|
||||
|
||||
if (isset($cartItemIdList[$product->getId()])) {
|
||||
|
||||
$cartItemId = $cartItemIdList[$product->getId()];
|
||||
|
||||
if ($cartItemId == self::ADD_TO_CART_IN_PROCESS) {
|
||||
return self::ADD_TO_CART_IN_PROCESS;
|
||||
} elseif (null !== $cartItem = CartItemQuery::create()->findPk($cartItemId)) {
|
||||
return $cartItem;
|
||||
}
|
||||
} else {
|
||||
// Maybe the product we're offering is already in the cart ? Search it.
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if ($cartItem->getProduct()->getId() == $this->offeredProductId) {
|
||||
|
||||
// We found the product. Store its cart item as the free product container.
|
||||
$this->setRelatedCartItem($product, $cartItem->getId());
|
||||
|
||||
return $cartItem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cart item id which contains the free product related to a given product
|
||||
*
|
||||
* @param Product $product the product in the cart which triggered the discount
|
||||
* @param bool|int $cartItemId the cart item ID which contains the free product, or just true if the free product is not yet added.
|
||||
*/
|
||||
protected function setRelatedCartItem($product, $cartItemId)
|
||||
{
|
||||
$cartItemIdList = $this->facade->getRequest()->getSession()->get(
|
||||
$this->getSessionVarName(),
|
||||
array()
|
||||
);
|
||||
|
||||
if (! is_array($cartItemIdList)) $cartItemIdList = array();
|
||||
|
||||
$cartItemIdList[$product->getId()] = $cartItemId;
|
||||
|
||||
$this->facade->getRequest()->getSession()->set(
|
||||
$this->getSessionVarName(),
|
||||
$cartItemIdList
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product id / cart item id list.
|
||||
*
|
||||
* @return array an array where the free product ID is the key, and the related cart item id the value.
|
||||
*/
|
||||
protected function getFreeProductsCartItemIds()
|
||||
{
|
||||
return $this->facade->getRequest()->getSession()->get(
|
||||
$this->getSessionVarName(),
|
||||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the session variable.
|
||||
*/
|
||||
protected function clearFreeProductsCartItemIds()
|
||||
{
|
||||
return $this->facade->getRequest()->getSession()->remove($this->getSessionVarName());
|
||||
}
|
||||
|
||||
/**
|
||||
* We overload this method here to remove the free products when the
|
||||
* coupons conditions are no longer met.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function isMatching()
|
||||
{
|
||||
$match = parent::isMatching();
|
||||
|
||||
if (! $match) {
|
||||
// Cancel coupon effect (but no not remove the product)
|
||||
$this->clearFreeProductsCartItemIds();
|
||||
}
|
||||
|
||||
return $match;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
$discount = 0;
|
||||
|
||||
$cartItems = $this->facade->getCart()->getCartItems();
|
||||
|
||||
/** @var Product $eligibleProduct */
|
||||
$eligibleProduct = null;
|
||||
|
||||
/** @var CartItem $cartItem */
|
||||
foreach ($cartItems as $cartItem) {
|
||||
if (in_array($cartItem->getProduct()->getId(), $this->product_list)) {
|
||||
if (! $cartItem->getPromo() || $this->isAvailableOnSpecialOffers()) {
|
||||
$eligibleProduct = $cartItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($eligibleProduct !== null) {
|
||||
|
||||
// Get the cart item for the eligible product
|
||||
$freeProductCartItem = $this->getRelatedCartItem($eligibleProduct);
|
||||
|
||||
// We add the free product it only if it not yet in the cart.
|
||||
if ($freeProductCartItem === false) {
|
||||
|
||||
if (null !== $freeProduct = ProductQuery::create()->findPk($this->offeredProductId)) {
|
||||
|
||||
// Store in the session that the free product is added to the cart,
|
||||
// so that we don't enter the following infinite loop :
|
||||
//
|
||||
// 1) exec() adds a product by firing a CART_ADDITEM event,
|
||||
// 2) the event is processed by Action\Coupon::updateOrderDiscount(),
|
||||
// 3) Action\Coupon::updateOrderDiscount() calls CouponManager::getDiscount()
|
||||
// 4) CouponManager::getDiscount() calls exec() -> Infinite loop !!
|
||||
|
||||
// Store a marker first, we do not have the cart item id yet.
|
||||
$this->setRelatedCartItem($eligibleProduct, self::ADD_TO_CART_IN_PROCESS);
|
||||
|
||||
$cartEvent = new CartEvent($this->facade->getCart());
|
||||
|
||||
$cartEvent->setNewness(true);
|
||||
$cartEvent->setAppend(false);
|
||||
$cartEvent->setQuantity(1);
|
||||
$cartEvent->setProductSaleElementsId($freeProduct->getDefaultSaleElements()->getId());
|
||||
$cartEvent->setProduct($this->offeredProductId);
|
||||
|
||||
$this->facade->getDispatcher()->dispatch(TheliaEvents::CART_ADDITEM, $cartEvent);
|
||||
|
||||
// Store the final cart item ID.
|
||||
$this->setRelatedCartItem($eligibleProduct, $cartEvent->getCartItem()->getId());
|
||||
|
||||
$freeProductCartItem = $cartEvent->getCartItem();
|
||||
|
||||
// Setting product price is dangerous, as the customer could change the ordered quantity of this product.
|
||||
// We will instead add the product price to the order discount.
|
||||
// $cartEvent->getCartItem()->setPrice(0)->save();
|
||||
}
|
||||
}
|
||||
|
||||
if ($freeProductCartItem instanceof CartItem) {
|
||||
|
||||
$taxCountry = $this->facade->getDeliveryCountry();
|
||||
|
||||
// The discount is the product price.
|
||||
$discount = $freeProductCartItem->getPromo() ?
|
||||
$freeProductCartItem->getPromoPrice() : $freeProductCartItem->getPrice();
|
||||
}
|
||||
}
|
||||
// No eligible product was found !
|
||||
else {
|
||||
// Remove all free products for this coupon, but no not remove the product from the cart.
|
||||
$this->clearFreeProductsCartItemIds();
|
||||
}
|
||||
|
||||
return $discount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getFieldList()
|
||||
{
|
||||
return $this->getBaseFieldList([self::OFFERED_CATEGORY_ID, self::OFFERED_PRODUCT_ID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function checkCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
$this->checkBaseCouponFieldValue($fieldName, $fieldValue);
|
||||
|
||||
if ($fieldName === self::OFFERED_PRODUCT_ID) {
|
||||
|
||||
if (floatval($fieldValue) < 0) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select the offered product'
|
||||
)
|
||||
);
|
||||
}
|
||||
} elseif ($fieldName === self::OFFERED_CATEGORY_ID) {
|
||||
if (empty($fieldValue)) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Please select the category of the offred product'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Free product when buying one or more selected products', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon adds a free product to the cart if one of the selected products is in the cart.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->drawBaseBackOfficeInputs("coupon/type-fragments/free-product.html", [
|
||||
'offered_category_field_name' => $this->makeCouponFieldName(self::OFFERED_CATEGORY_ID),
|
||||
'offered_category_value' => $this->offeredCategoryId,
|
||||
|
||||
'offered_product_field_name' => $this->makeCouponFieldName(self::OFFERED_PRODUCT_ID),
|
||||
'offered_product_value' => $this->offeredProductId
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
// Clear the session variable when the coupon is cleared.
|
||||
$this->clearFreeProductsCartItemIds();
|
||||
}
|
||||
}
|
||||
92
core/lib/Thelia/Coupon/Type/PercentageCouponTrait.php
Normal file
92
core/lib/Thelia/Coupon/Type/PercentageCouponTrait.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
/**
|
||||
* A trait to manage a coupon which removes a percentage of cart items from the order total.
|
||||
* Should be used on coupons classes which implements AmountAndPercentageCouponInterface
|
||||
*
|
||||
* Class PercentageCouponTrait
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
* @package Thelia\Coupon\Type
|
||||
*/
|
||||
Trait PercentageCouponTrait {
|
||||
|
||||
public $percentage = 0;
|
||||
|
||||
/**
|
||||
* Should return the percentage field name, defined in the parent class.
|
||||
*
|
||||
* @return string the percentage field name
|
||||
*/
|
||||
abstract protected function getPercentageFieldName();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function setFieldsValue($effects)
|
||||
{
|
||||
$this->percentage = $effects[$this->getPercentageFieldName()];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getCartItemDiscount($cartItem)
|
||||
{
|
||||
return $cartItem->getQuantity() * $cartItem->getPrice() * ($this->percentage / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function callDrawBackOfficeInputs($templateName)
|
||||
{
|
||||
return $this->drawBaseBackOfficeInputs($templateName, [
|
||||
'percentage_field_name' => $this->makeCouponFieldName($this->getPercentageFieldName()),
|
||||
'percentage_value' => $this->percentage,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getFieldList()
|
||||
{
|
||||
return $this->getBaseFieldList([$this->getPercentageFieldName()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function checkCouponFieldValue($fieldName, $fieldValue)
|
||||
{
|
||||
$this->checkBaseCouponFieldValue($fieldName, $fieldValue);
|
||||
|
||||
if ($fieldName === $this->getPercentageFieldName()) {
|
||||
|
||||
$pcent = floatval($fieldValue);
|
||||
|
||||
if ($pcent <= 0 || $pcent > 100) {
|
||||
throw new \InvalidArgumentException(
|
||||
Translator::getInstance()->trans(
|
||||
'Value %val for Percent Discount is invalid. Please enter a positive value between 1 and 100.',
|
||||
[ '%val' => $fieldValue]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $fieldValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class RemoveAmountOnAttributeValues extends AbstractRemoveOnAttributeValues
|
||||
{
|
||||
use AmountCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_amount_on_attribute_av';
|
||||
|
||||
protected function getAmountFieldName()
|
||||
{
|
||||
return self::AMOUNT_FIELD_NAME;
|
||||
}
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Fixed amount discount for selected attribute values', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon subtracts the specified amount from the order total for each product which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-attributes.html');
|
||||
}
|
||||
}
|
||||
66
core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php
Normal file
66
core/lib/Thelia/Coupon/Type/RemoveAmountOnCategories.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class RemoveAmountOnCategories extends AbstractRemoveOnCategories
|
||||
{
|
||||
use AmountCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_amount_on_categories';
|
||||
|
||||
protected function getAmountFieldName()
|
||||
{
|
||||
return self::AMOUNT_FIELD_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Fixed amount discount for selected categories', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon subtracts the specified amount from the order total for each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-categories.html');
|
||||
}
|
||||
}
|
||||
70
core/lib/Thelia/Coupon/Type/RemoveAmountOnProducts.php
Normal file
70
core/lib/Thelia/Coupon/Type/RemoveAmountOnProducts.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Model\Product;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class RemoveAmountOnProducts extends AbstractRemoveOnProducts
|
||||
{
|
||||
use AmountCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_amount_on_products';
|
||||
|
||||
protected function getAmountFieldName()
|
||||
{
|
||||
return self::AMOUNT_FIELD_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Fixed amount discount for selected products', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon subtracts the specified amount from the order total for each selected product. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-products.html');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class RemovePercentageOnAttributeValues extends AbstractRemoveOnAttributeValues
|
||||
{
|
||||
const PERCENTAGE = 'percentage';
|
||||
|
||||
use PercentageCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_percentage_on_attribute_av';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getPercentageFieldName()
|
||||
{
|
||||
return self::PERCENTAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Percentage discount for selected attribute values', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon subtracts from the order total the specified percentage of each product price which uses the selected attribute values. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-attributes.html');
|
||||
}
|
||||
}
|
||||
68
core/lib/Thelia/Coupon/Type/RemovePercentageOnCategories.php
Normal file
68
core/lib/Thelia/Coupon/Type/RemovePercentageOnCategories.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
/**
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class RemovePercentageOnCategories extends AbstractRemoveOnCategories
|
||||
{
|
||||
const PERCENTAGE = 'percentage';
|
||||
|
||||
use PercentageCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_percentage_on_categories';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getPercentageFieldName()
|
||||
{
|
||||
return self::PERCENTAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Percentage discount for selected categories', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon subtracts from the order total a percentage of the price of each product which belongs to the selected categories. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-categories.html');
|
||||
}
|
||||
}
|
||||
75
core/lib/Thelia/Coupon/Type/RemovePercentageOnProducts.php
Normal file
75
core/lib/Thelia/Coupon/Type/RemovePercentageOnProducts.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Model\Product;
|
||||
|
||||
/**
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class RemovePercentageOnProducts extends AbstractRemoveOnProducts
|
||||
{
|
||||
const PERCENTAGE = 'percentage';
|
||||
|
||||
use PercentageCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_percentage_on_products';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getPercentageFieldName()
|
||||
{
|
||||
return self::PERCENTAGE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Percentage discount for selected products', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
$toolTip = $this->facade
|
||||
->getTranslator()
|
||||
->trans(
|
||||
'This coupon subtracts from the order total the specified percentage of each selected product price. If the discount is greater than the total order, the customer will only pay the shipping, or nothing if the coupon also provides free shipping.',
|
||||
array(),
|
||||
'coupon'
|
||||
);
|
||||
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-products.html');
|
||||
}
|
||||
}
|
||||
@@ -16,18 +16,23 @@ namespace Thelia\Coupon\Type;
|
||||
* Allow to remove an amount from the checkout total
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class RemoveXAmount extends CouponAbstract
|
||||
class RemoveXAmount extends AbstractRemove
|
||||
{
|
||||
use AmountCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_x_amount';
|
||||
|
||||
protected function getAmountFieldName()
|
||||
{
|
||||
return self::AMOUNT_FIELD_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n name
|
||||
*
|
||||
* @return string
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -37,21 +42,7 @@ class RemoveXAmount extends CouponAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n amount input name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Discount amount', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n tooltip
|
||||
*
|
||||
* @return string
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
@@ -66,12 +57,19 @@ class RemoveXAmount extends CouponAbstract
|
||||
return $toolTip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/type-fragments/remove-x-amount.html', [
|
||||
'label' => $this->getInputName(),
|
||||
'fieldName' => self::INPUT_AMOUNT_NAME,
|
||||
'value' => $this->amount
|
||||
]);
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-x-amount.html');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,93 +12,30 @@
|
||||
|
||||
namespace Thelia\Coupon\Type;
|
||||
|
||||
use Thelia\Coupon\FacadeInterface;
|
||||
|
||||
/**
|
||||
* @package Coupon
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>
|
||||
* @author Guillaume MOREL <gmorel@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
|
||||
*
|
||||
*/
|
||||
class RemoveXPercent extends CouponAbstract
|
||||
class RemoveXPercent extends AbstractRemove
|
||||
{
|
||||
const INPUT_PERCENTAGE_NAME = 'percentage';
|
||||
|
||||
use PercentageCouponTrait;
|
||||
|
||||
/** @var string Service Id */
|
||||
protected $serviceId = 'thelia.coupon.type.remove_x_percent';
|
||||
|
||||
/** @var float Percentage removed from the Cart */
|
||||
protected $percentage = 0;
|
||||
|
||||
/** @var array Extended Inputs to manage */
|
||||
protected $extendedInputs = array(
|
||||
self::INPUT_PERCENTAGE_NAME
|
||||
);
|
||||
|
||||
/**
|
||||
* Set Coupon
|
||||
*
|
||||
* @param FacadeInterface $facade Provides necessary value from Thelia
|
||||
* @param string $code Coupon code (ex: XMAS)
|
||||
* @param string $title Coupon title (ex: Coupon for XMAS)
|
||||
* @param string $shortDescription Coupon short description
|
||||
* @param string $description Coupon description
|
||||
* @param array $effects Coupon effects params
|
||||
* @param bool $isCumulative If Coupon is cumulative
|
||||
* @param bool $isRemovingPostage If Coupon is removing postage
|
||||
* @param bool $isAvailableOnSpecialOffers If available on Product already
|
||||
* on special offer price
|
||||
* @param bool $isEnabled False if Coupon is disabled by admin
|
||||
* @param int $maxUsage How many usage left
|
||||
* @param \Datetime $expirationDate When the Code is expiring
|
||||
*
|
||||
* @return $this
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function set(
|
||||
FacadeInterface $facade,
|
||||
$code,
|
||||
$title,
|
||||
$shortDescription,
|
||||
$description,
|
||||
array $effects,
|
||||
$isCumulative,
|
||||
$isRemovingPostage,
|
||||
$isAvailableOnSpecialOffers,
|
||||
$isEnabled,
|
||||
$maxUsage,
|
||||
\DateTime $expirationDate
|
||||
)
|
||||
protected function getPercentageFieldName()
|
||||
{
|
||||
parent::set(
|
||||
$facade, $code, $title, $shortDescription, $description, $effects, $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate
|
||||
);
|
||||
$this->percentage = $effects[self::INPUT_PERCENTAGE_NAME];
|
||||
|
||||
return $this;
|
||||
return self::INPUT_PERCENTAGE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return effects generated by the coupon
|
||||
* A negative value
|
||||
*
|
||||
* @throws \Thelia\Exception\MissingFacadeException
|
||||
* @throws \InvalidArgumentException
|
||||
* @return float
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
if ($this->percentage >= 100) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Percentage must be inferior to 100'
|
||||
);
|
||||
}
|
||||
|
||||
return round($this->facade->getCartTotalTaxPrice() * $this->percentage/100, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n name
|
||||
*
|
||||
* @return string
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
@@ -108,21 +45,7 @@ class RemoveXPercent extends CouponAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n amount input name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getInputName()
|
||||
{
|
||||
return $this->facade
|
||||
->getTranslator()
|
||||
->trans('Percent Discount', array(), 'coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get I18n tooltip
|
||||
*
|
||||
* @return string
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getToolTip()
|
||||
{
|
||||
@@ -138,19 +61,18 @@ class RemoveXPercent extends CouponAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the input displayed in the BackOffice
|
||||
* allowing Admin to set its Coupon effect
|
||||
*
|
||||
* @return string HTML string
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function exec()
|
||||
{
|
||||
return round($this->facade->getCartTotalTaxPrice($this->isAvailableOnSpecialOffers()) * $this->percentage/100, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function drawBackOfficeInputs()
|
||||
{
|
||||
return $this->facade->getParser()->render('coupon/type-fragments/remove-x-percent.html', [
|
||||
'label' => $this->getInputName(),
|
||||
'typeKey' => self::INPUT_AMOUNT_NAME,
|
||||
'fieldId' => self::INPUT_PERCENTAGE_NAME,
|
||||
'fieldName' => self::INPUT_EXTENDED__NAME,
|
||||
'value' => $this->percentage
|
||||
]);
|
||||
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-x-percent.html');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Thelia\Exception;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Log\Tlog;
|
||||
|
||||
/**
|
||||
@@ -30,7 +31,8 @@ class CouponExpiredException extends \Exception
|
||||
*/
|
||||
public function __construct($couponCode)
|
||||
{
|
||||
$message = 'Expired Coupon ' . $couponCode . 'attempt';
|
||||
$message = Translator::getInstance()->trans('Coupon %code is expired.', ['%code' => $couponCode ]);
|
||||
|
||||
Tlog::getInstance()->addWarning($message);
|
||||
|
||||
parent::__construct($message);
|
||||
|
||||
39
core/lib/Thelia/Exception/CouponNoUsageLeftException.php
Normal file
39
core/lib/Thelia/Exception/CouponNoUsageLeftException.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/*************************************************************************************/
|
||||
/* This file is part of the Thelia package. */
|
||||
/* */
|
||||
/* Copyright (c) OpenStudio */
|
||||
/* email : dev@thelia.net */
|
||||
/* web : http://www.thelia.net */
|
||||
/* */
|
||||
/* For the full copyright and license information, please view the LICENSE.txt */
|
||||
/* file that was distributed with this source code. */
|
||||
/*************************************************************************************/
|
||||
|
||||
namespace Thelia\Exception;
|
||||
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Log\Tlog;
|
||||
|
||||
/**
|
||||
* Thrown when a Coupon with no usage lect (etiher overall or per customer usage) is tried
|
||||
*
|
||||
* @package Coupon
|
||||
* @author Franck Allimant <franck@cqfdev.fr>
|
||||
*/
|
||||
class CouponNoUsageLeftException extends \Exception
|
||||
{
|
||||
/**
|
||||
* CouponExpiredException thrown when a Coupon is expired
|
||||
*
|
||||
* @param string $couponCode Coupon code
|
||||
*/
|
||||
public function __construct($couponCode)
|
||||
{
|
||||
$message = Translator::getInstance()->trans('Maximum usage count reached for coupon %code', ['%code' => $couponCode ]);
|
||||
|
||||
Tlog::getInstance()->addWarning($message);
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,11 @@ use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Constraints\NotEqualTo;
|
||||
use Symfony\Component\Validator\ExecutionContextInterface;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\Base\LangQuery;
|
||||
use Thelia\Model\CountryQuery;
|
||||
use Thelia\Model\LangQuery;
|
||||
use Thelia\Model\ModuleQuery;
|
||||
use Thelia\Model\Module;
|
||||
use Thelia\Module\BaseModule;
|
||||
|
||||
/**
|
||||
* Allow to build a form Coupon
|
||||
@@ -29,6 +33,8 @@ use Thelia\Model\Base\LangQuery;
|
||||
*/
|
||||
class CouponCreationForm extends BaseForm
|
||||
{
|
||||
const COUPON_CREATION_FORM_NAME = 'thelia_coupon_creation';
|
||||
|
||||
/**
|
||||
* Build Coupon form
|
||||
*
|
||||
@@ -36,6 +42,33 @@ class CouponCreationForm extends BaseForm
|
||||
*/
|
||||
protected function buildForm()
|
||||
{
|
||||
// Create countries and shipping modules list
|
||||
$countries = [0 => ' '];
|
||||
|
||||
$list = CountryQuery::create()->find();
|
||||
|
||||
/** @var Country $item */
|
||||
foreach ($list as $item) {
|
||||
$countries[$item->getId()] = $item->getTitle();
|
||||
}
|
||||
|
||||
asort($countries);
|
||||
|
||||
$countries[0] = Translator::getInstance()->trans("All countries");
|
||||
|
||||
$modules = [0 => ' '];
|
||||
|
||||
$list = ModuleQuery::create()->filterByActivate(BaseModule::IS_ACTIVATED)->filterByType(BaseModule::DELIVERY_MODULE_TYPE)->find();
|
||||
|
||||
/** @var Module $item */
|
||||
foreach ($list as $item) {
|
||||
$modules[$item->getId()] = $item->getTitle();
|
||||
}
|
||||
|
||||
asort($modules);
|
||||
|
||||
$modules[0] = Translator::getInstance()->trans("All shipping methods");
|
||||
|
||||
$this->formBuilder
|
||||
->add(
|
||||
'code',
|
||||
@@ -79,14 +112,6 @@ class CouponCreationForm extends BaseForm
|
||||
)
|
||||
)
|
||||
)
|
||||
->add(
|
||||
'amount',
|
||||
'money',
|
||||
array(
|
||||
'constraints' => array(
|
||||
new NotBlank()
|
||||
))
|
||||
)
|
||||
->add(
|
||||
'isEnabled',
|
||||
'text',
|
||||
@@ -116,6 +141,22 @@ class CouponCreationForm extends BaseForm
|
||||
'text',
|
||||
array()
|
||||
)
|
||||
->add(
|
||||
'freeShippingForCountries',
|
||||
'choice',
|
||||
array(
|
||||
'multiple' => true,
|
||||
'choices' => $countries
|
||||
)
|
||||
)
|
||||
->add(
|
||||
'freeShippingForModules',
|
||||
'choice',
|
||||
array(
|
||||
'multiple' => true,
|
||||
'choices' => $modules
|
||||
)
|
||||
)
|
||||
->add(
|
||||
'isAvailableOnSpecialOffers',
|
||||
'text',
|
||||
@@ -131,6 +172,18 @@ class CouponCreationForm extends BaseForm
|
||||
)
|
||||
)
|
||||
)
|
||||
->add(
|
||||
'perCustomerUsageCount',
|
||||
'choice',
|
||||
array(
|
||||
'multiple' => false,
|
||||
'required' => true,
|
||||
'choices' => [
|
||||
1 => Translator::getInstance()->trans('Per customer'),
|
||||
0 => Translator::getInstance()->trans('Overall')
|
||||
]
|
||||
)
|
||||
)
|
||||
->add(
|
||||
'locale',
|
||||
'hidden',
|
||||
@@ -139,7 +192,12 @@ class CouponCreationForm extends BaseForm
|
||||
new NotBlank()
|
||||
)
|
||||
)
|
||||
);
|
||||
)
|
||||
->add('coupon_specific', 'collection', array(
|
||||
'allow_add' => true,
|
||||
'allow_delete' => true,
|
||||
))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,6 +225,6 @@ class CouponCreationForm extends BaseForm
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'thelia_coupon_creation';
|
||||
return self::COUPON_CREATION_FORM_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use Symfony\Component\Validator\Constraints;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ExecutionContextInterface;
|
||||
use Thelia\Core\Translation\Translator;
|
||||
use Thelia\Model\Base\CustomerQuery;
|
||||
use Thelia\Model\CustomerQuery;
|
||||
|
||||
/**
|
||||
* Class CustomerLogin
|
||||
|
||||
@@ -110,7 +110,7 @@ class LangCreateForm extends BaseForm
|
||||
'constraints' => array(
|
||||
new NotBlank()
|
||||
),
|
||||
'label' => Translator::getInstance()->trans('Sets the number of decimal points'),
|
||||
'label' => Translator::getInstance()->trans('Decimal places'),
|
||||
'label_attr' => array(
|
||||
'for' => 'decimals'
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user