Rajout du dossier core + MAJ .gitignore

This commit is contained in:
2019-11-21 12:48:42 +01:00
parent f4aabcb9b1
commit 459f8966b0
10448 changed files with 1835600 additions and 1 deletions

View File

@@ -0,0 +1,352 @@
<?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;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\TranslatorInterface;
use Thelia\Condition\ConditionEvaluator;
use Thelia\Core\HttpFoundation\Request;
use Thelia\Core\Template\ParserInterface;
use Thelia\Log\Tlog;
use Thelia\Model\AddressQuery;
use Thelia\Model\Country;
use Thelia\Model\Coupon;
use Thelia\Model\CouponQuery;
use Thelia\Model\Currency;
use Thelia\Model\CurrencyQuery;
/**
* Allow to assist in getting relevant data on the current application state
*
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class BaseFacade implements FacadeInterface
{
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var Translator Service Translator */
protected $translator = null;
/** @var ParserInterface The thelia parser */
private $parser = null;
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Return a Cart a CouponManager can process
*
* @return \Thelia\Model\Cart
*/
public function getCart()
{
return $this->getRequest()->getSession()->getSessionCart($this->getDispatcher());
}
/**
* Return an Address a CouponManager can process
*
* @return \Thelia\Model\Address
*/
public function getDeliveryAddress()
{
try {
return AddressQuery::create()->findPk(
$this->getRequest()->getSession()->getOrder()->getChoosenDeliveryAddress()
);
} catch (\Exception $ex) {
throw new \LogicException("Failed to get delivery address (" . $ex->getMessage() . ")");
}
}
/**
* Return an Customer a CouponManager can process
*
* @return \Thelia\Model\Customer
*/
public function getCustomer()
{
return $this->container->get('thelia.securityContext')->getCustomerUser();
}
/**
* Return Checkout total price
*
* @return float
*/
public function getCheckoutTotalPrice()
{
return $this->getRequest()->getSession()->getOrder()->getTotalAmount();
}
/**
* Return Checkout total postage (only) price
*
* @return float
*/
public function getCheckoutPostagePrice()
{
return $this->getRequest()->getSession()->getOrder()->getPostage();
}
/**
* Return Products total price
*
* @param bool $withItemsInPromo if true, the discounted items are included in the total
*
* @return float
*/
public function getCartTotalPrice($withItemsInPromo = true)
{
$total = 0;
$cartItems = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->getCartItems();
foreach ($cartItems as $cartItem) {
if ($withItemsInPromo || ! $cartItem->getPromo()) {
$total += $cartItem->getRealPrice() * $cartItem->getQuantity();
}
}
return $total;
}
public function getCartTotalTaxPrice($withItemsInPromo = true)
{
$taxCountry = $this->getContainer()->get('thelia.taxEngine')->getDeliveryCountry();
$cartItems = $this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->getCartItems();
$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();
}
/**
* Return the Checkout currency EUR|USD
*
* @return Currency
*/
public function getCheckoutCurrency()
{
return $this->getRequest()->getSession()->getCurrency()->getCode();
}
/**
* Return the number of Products in the Cart
*
* @return int
*/
public function getNbArticlesInCart()
{
return count($this->getRequest()->getSession()->getSessionCart($this->getDispatcher())->getCartItems());
}
public function getNbArticlesInCartIncludeQuantity()
{
$cartItems = $this->getCart()->getCartItems();
$quantity = 0;
foreach ($cartItems as $cartItem) {
$quantity += $cartItem->getQuantity();
}
return $quantity;
}
/**
* Return all Coupon given during the Checkout
*
* @return array Array of CouponInterface
*/
public function getCurrentCoupons()
{
$couponCodes = $this->getRequest()->getSession()->getConsumedCoupons();
if (null === $couponCodes) {
return array();
}
/** @var CouponFactory $couponFactory */
$couponFactory = $this->container->get('thelia.coupon.factory');
$coupons = [];
foreach ($couponCodes as $couponCode) {
// Only valid coupons are returned
try {
if (false !== $couponInterface = $couponFactory->buildCouponFromCode($couponCode)) {
$coupons[] = $couponInterface;
}
} catch (\Exception $ex) {
// Just ignore the coupon and log the problem, just in case someone realize it.
Tlog::getInstance()->warning(
sprintf("Coupon %s ignored, exception occurred: %s", $couponCode, $ex->getMessage())
);
}
}
return $coupons;
}
/**
* Find one Coupon in the database from its code
*
* @param string $code Coupon code
*
* @return Coupon
*/
public function findOneCouponByCode($code)
{
$couponQuery = CouponQuery::create();
return $couponQuery->findOneByCode($code);
}
/**
* Return platform Container
*
* @return Container
*/
public function getContainer()
{
return $this->container;
}
/**
* Return platform TranslatorInterface
*
* @return TranslatorInterface
*/
public function getTranslator()
{
return $this->container->get('thelia.translator');
}
/**
* Return platform Parser
*
* @return ParserInterface
*/
public function getParser()
{
if ($this->parser == null) {
$this->parser = $this->container->get('thelia.parser');
// Define the current back-office template that should be used
$this->parser->setTemplateDefinition(
$this->parser->getTemplateHelper()->getActiveAdminTemplate()
);
}
return $this->parser;
}
/**
* Return the main currency
* THe one used to set prices in BackOffice
*
* @return string
*/
public function getMainCurrency()
{
return $this->getRequest()->getSession()->getCurrency();
}
/**
* Return request
*
* @return Request
*/
public function getRequest()
{
return $this->container->get('request_stack')->getCurrentRequest();
}
/**
* Return Constraint Validator
*
* @return ConditionEvaluator
*/
public function getConditionEvaluator()
{
return $this->container->get('thelia.condition.validator');
}
/**
* Return all available currencies
*
* @return array of Currency
*/
public function getAvailableCurrencies()
{
$currencies = CurrencyQuery::create();
return $currencies->find();
}
/**
* Return the event dispatcher,
*
* @return \Symfony\Component\EventDispatcher\EventDispatcher
*/
public function getDispatcher()
{
return $this->container->get('event_dispatcher');
}
/**
* Add a coupon in session
* @param $couponCode
* @return mixed|void
*/
public function pushCouponInSession($couponCode)
{
$consumedCoupons = $this->getRequest()->getSession()->getConsumedCoupons();
if (!isset($consumedCoupons) || !$consumedCoupons) {
$consumedCoupons = array();
}
if (!isset($consumedCoupons[$couponCode])) {
// Prevent accumulation of the same Coupon on a Checkout
$consumedCoupons[$couponCode] = $couponCode;
$this->getRequest()->getSession()->setConsumedCoupons($consumedCoupons);
}
}
}

View File

@@ -0,0 +1,156 @@
<?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;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Condition\ConditionFactory;
use Thelia\Coupon\Type\CouponInterface;
use Thelia\Exception\CouponNotReleaseException;
use Thelia\Exception\InactiveCouponException;
use Thelia\Exception\CouponExpiredException;
use Thelia\Exception\CouponNoUsageLeftException;
use Thelia\Exception\InvalidConditionException;
use Thelia\Exception\UnmatchableConditionException;
use Thelia\Model\Coupon;
/**
* Generate a CouponInterface
*
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class CouponFactory
{
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var FacadeInterface Provide necessary value from Thelia*/
protected $facade;
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->facade = $container->get('thelia.facade');
}
/**
* Build a CouponInterface from its database data
*
* @param string $couponCode Coupon code ex: XMAS
* @return CouponInterface
* @throws CouponExpiredException
* @throws CouponNoUsageLeftException
* @throws CouponNotReleaseException
*/
public function buildCouponFromCode($couponCode)
{
/** @var Coupon $couponModel */
$couponModel = $this->facade->findOneCouponByCode($couponCode);
if ($couponModel === null) {
return false;
}
// check if coupon is enabled
if (!$couponModel->getIsEnabled()) {
throw new InactiveCouponException($couponCode);
}
$nowDateTime = new \DateTime();
// Check coupon start date
if ($couponModel->getStartDate() !== null && $couponModel->getStartDate() > $nowDateTime) {
throw new CouponNotReleaseException($couponCode);
}
// Check coupon expiration date
if ($couponModel->getExpirationDate() < $nowDateTime) {
throw new CouponExpiredException($couponCode);
}
// Check coupon usage count
if (! $couponModel->isUsageUnlimited()) {
if (null === $customer = $this->facade->getCustomer()) {
throw new UnmatchableConditionException($couponCode);
}
if ($couponModel->getUsagesLeft($customer->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)
);
}
return $couponInterface;
}
/**
* Build a CouponInterface from its Model data contained in the DataBase
*
* @param Coupon $model Database data
*
* @return CouponInterface ready to use CouponInterface object instance
*/
public function buildCouponFromModel(Coupon $model)
{
$isCumulative = ($model->getIsCumulative() == 1 ? true : false);
$isRemovingPostage = ($model->getIsRemovingPostage() == 1 ? true : false);
if (!$this->container->has($model->getType())) {
return false;
}
/** @var CouponInterface $couponManager*/
$couponManager = $this->container->get($model->getType());
$couponManager->set(
$this->facade,
$model->getCode(),
$model->getTitle(),
$model->getShortDescription(),
$model->getDescription(),
$model->getEffects(),
$isCumulative,
$isRemovingPostage,
$model->getIsAvailableOnSpecialOffers(),
$model->getIsEnabled(),
$model->getMaxUsage(),
$model->getExpirationDate(),
$model->getFreeShippingForCountries(),
$model->getFreeShippingForModules(),
$model->getPerCustomerUsageCount()
);
/** @var ConditionFactory $conditionFactory */
$conditionFactory = $this->container->get('thelia.condition.factory');
$conditions = $conditionFactory->unserializeConditionCollection(
$model->getSerializedConditions()
);
$couponManager->setConditions($conditions);
return clone $couponManager;
}
}

View File

@@ -0,0 +1,377 @@
<?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;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Condition\Implementation\ConditionInterface;
use Thelia\Coupon\Type\CouponInterface;
use Thelia\Exception\UnmatchableConditionException;
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
*
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
class CouponManager
{
/** @var FacadeInterface Provides necessary value from Thelia */
protected $facade = null;
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var array Available Coupons (Services) */
protected $availableCoupons = array();
/** @var array Available Conditions (Services) */
protected $availableConditions = array();
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
$this->facade = $container->get('thelia.facade');
}
/**
* 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);
$discount = $this->getEffect($couponsKept);
// Just In Case test
$checkoutTotalPrice = $this->facade->getCartTotalTaxPrice();
if ($discount >= $checkoutTotalPrice) {
$discount = $checkoutTotalPrice;
}
}
return $discount;
}
/**
* @param $code
* @return mixed|void
*/
public function pushCouponInSession($code)
{
$this->facade->pushCouponInSession($code);
}
/**
* 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(Order $order)
{
$coupons = $this->facade->getCurrentCoupons();
if (count($coupons) == 0) {
return false;
}
$couponsKept = $this->sortCoupons($coupons);
/** @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;
}
}
return false;
}
/**
* @return array
*/
public function getCouponsKept()
{
return $this->sortCoupons($this->facade->getCurrentCoupons());
}
/**
* Sort Coupon to keep
* Coupon not cumulative cancels previous
*
* @param array $coupons CouponInterface to process
*
* @return array Array of CouponInterface sorted
*/
protected function sortCoupons(array $coupons)
{
$couponsKept = array();
/** @var CouponInterface $coupon */
foreach ($coupons as $coupon) {
if ($coupon && !$coupon->isExpired()) {
if ($coupon->isCumulative()) {
if (isset($couponsKept[0])) {
/** @var CouponInterface $previousCoupon */
$previousCoupon = $couponsKept[0];
if ($previousCoupon->isCumulative()) {
// Add Coupon
$couponsKept[] = $coupon;
} else {
// Reset Coupons, add last
$couponsKept = array($coupon);
}
} else {
// Reset Coupons, add last
$couponsKept = array($coupon);
}
} else {
// Reset Coupons, add last
$couponsKept = array($coupon);
}
}
}
$coupons = $couponsKept;
$couponsKept = array();
/** @var CouponInterface $coupon */
foreach ($coupons as $coupon) {
try {
if ($coupon->isMatching()) {
$couponsKept[] = $coupon;
}
} catch (UnmatchableConditionException $e) {
// ignore unmatchable coupon
continue;
}
}
return $couponsKept;
}
/**
* Process given Coupon in order to get their cumulative effects
*
* @param array $coupons CouponInterface to process
*
* @return float discount
*/
protected function getEffect(array $coupons)
{
$discount = 0.00;
/** @var CouponInterface $coupon */
foreach ($coupons as $coupon) {
$discount += $coupon->exec($this->facade);
}
return $discount;
}
/**
* Add an available CouponManager (Services)
*
* @param CouponInterface $coupon CouponManager
*/
public function addAvailableCoupon(CouponInterface $coupon)
{
$this->availableCoupons[] = $coupon;
}
/**
* Get all available CouponManagers (Services)
*
* @return array
*/
public function getAvailableCoupons()
{
return $this->availableCoupons;
}
/**
* Add an available ConstraintManager (Services)
*
* @param ConditionInterface $condition ConditionInterface
*/
public function addAvailableCondition(ConditionInterface $condition)
{
$this->availableConditions[] = $condition;
}
/**
* Get all available ConstraintManagers (Services)
*
* @return array
*/
public function getAvailableConditions()
{
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 int|null $customerId the ID of the ordering customer
*
* @return int Usage left after decremental
*/
public function decrementQuantity(Coupon $coupon, $customerId = null)
{
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;
}
}

View File

@@ -0,0 +1,197 @@
<?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;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
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;
/**
* Allow to assist in getting relevant data on the current application state
*
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
interface FacadeInterface
{
/**
* Constructor
*
* @param ContainerInterface $container Service container
*/
public function __construct(ContainerInterface $container);
/**
* Return a Cart a CouponManager can process
*
* @return \Thelia\Model\Cart
*/
public function getCart();
/**
* Return an Address a CouponManager can process
*
* @return \Thelia\Model\Address
*/
public function getDeliveryAddress();
/**
* @return Country the delivery country
*/
public function getDeliveryCountry();
/**
* Return an Customer a CouponManager can process
*
* @return \Thelia\Model\Customer
*/
public function getCustomer();
/**
* Return Checkout total price
*
* @return float
*/
public function getCheckoutTotalPrice();
/**
* 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($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($withItemsInPromo = true);
/**
* Return the Checkout currency EUR|USD
*
* @return string
*/
public function getCheckoutCurrency();
/**
* Return Checkout total postage (only) price
*
* @return float
*/
public function getCheckoutPostagePrice();
/**
* Return the number of Products in the Cart
*
* @return int
*/
public function getNbArticlesInCart();
/**
* Return the number of Products include quantity in the Cart
*
* @return int
*/
public function getNbArticlesInCartIncludeQuantity();
/**
* Return all Coupon given during the Checkout
*
* @return array Array of CouponInterface
*/
public function getCurrentCoupons();
/**
* Find one Coupon in the database from its code
*
* @param string $code Coupon code
*
* @return Coupon
*/
public function findOneCouponByCode($code);
/**
* Return platform Container
*
* @return Container
*/
public function getContainer();
/**
* Return platform TranslatorInterface
*
* @return TranslatorInterface
*/
public function getTranslator();
/**
* Return platform ParserInterface
*
* @return ParserInterface
*/
public function getParser();
/**
* Return the main currency
* THe one used to set prices in BackOffice
*
* @return string
*/
public function getMainCurrency();
/**
* Return request
*
* @return Request
*/
public function getRequest();
/**
* Return Condition Evaluator
*
* @return ConditionEvaluator
*/
public function getConditionEvaluator();
/**
* Return all available currencies
*
* @return array of Currency
*/
public function getAvailableCurrencies();
/**
* Return the event dispatcher,
*
* @return \Symfony\Component\EventDispatcher\EventDispatcher
*/
public function getDispatcher();
/**
* Add a coupon in session
*
* @param $couponCode
* @return mixed|void
*/
public function pushCouponInSession($couponCode);
}

View File

@@ -0,0 +1,137 @@
<?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;
use Thelia\Model\Category;
/**
* 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 $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;
}
}

View File

@@ -0,0 +1,189 @@
<?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 $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;
}
}

View 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 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 $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;
}
}

View File

@@ -0,0 +1,173 @@
<?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 $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;
}
}

View File

@@ -0,0 +1,60 @@
<?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\CartItem;
/**
* 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 $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);
}

View 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;
use Thelia\Model\CartItem;
/**
* 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
*/
public function setFieldsValue($effects)
{
$this->amount = $effects[$this->getAmountFieldName()];
}
/**
* @inheritdoc
*/
public function getCartItemDiscount(CartItem $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;
}
}

View File

@@ -0,0 +1,521 @@
<?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\Condition\ConditionCollection;
use Thelia\Condition\ConditionEvaluator;
use Thelia\Condition\ConditionOrganizerInterface;
use Thelia\Core\Translation\Translator;
use Thelia\Coupon\FacadeInterface;
use Thelia\Form\CouponCreationForm;
use Thelia\Model\CouponCountry;
use Thelia\Model\CouponModule;
/**
* Assist in writing a CouponInterface
*
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
abstract class CouponAbstract implements CouponInterface
{
/**
* 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';
/**
* 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;
/** @var Translator Service Translator */
protected $translator = null;
/** @var ConditionOrganizerInterface */
protected $organizer = null;
/** @var ConditionCollection Array of ConditionInterface */
protected $conditions = null;
/** @var ConditionEvaluator Condition validator */
protected $conditionEvaluator = null;
/** @var string Service Id */
protected $serviceId = null;
/** @var float Amount that will be removed from the Checkout (Coupon Effect) */
protected $amount = 0;
/** @var array Get the Coupon effects params */
protected $effects = array('amount' => 0);
/** @var string Coupon code (ex: XMAS) */
protected $code = null;
/** @var string Coupon title (ex: Coupon for XMAS) */
protected $title = null;
/** @var string Coupon short description */
protected $shortDescription = null;
/** @var string Coupon description */
protected $description = null;
/** @var bool if Coupon is enabled */
protected $isEnabled = false;
/** @var \DateTime Coupon start date */
protected $startDate = null;
/** @var \DateTime Coupon expiration date */
protected $expirationDate = null;
/** @var bool if Coupon is cumulative */
protected $isCumulative = false;
/** @var bool if Coupon is removing postage */
protected $isRemovingPostage = false;
/** @var int Max time a Coupon can be used (-1 = unlimited) */
protected $maxUsage = -1;
/** @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
*
* @param FacadeInterface $facade Service facade
*/
public function __construct(FacadeInterface $facade)
{
$this->facade = $facade;
$this->translator = $facade->getTranslator();
$this->conditionEvaluator = $facade->getConditionEvaluator();
}
/**
* Set Condition Organizer
*
* @param ConditionOrganizerInterface $organizer Manage Condition groups (&& and ||)
*
* @return $this
*/
public function setOrganizer($organizer)
{
$this->organizer = $organizer;
return $this;
}
/**
* @inheritdoc
*/
public function set(
FacadeInterface $facade,
$code,
$title,
$shortDescription,
$description,
array $effects,
$isCumulative,
$isRemovingPostage,
$isAvailableOnSpecialOffers,
$isEnabled,
$maxUsage,
\DateTime $expirationDate,
$freeShippingForCountries,
$freeShippingForModules,
$perCustomerUsageCount
) {
$this->code = $code;
$this->title = $title;
$this->shortDescription = $shortDescription;
$this->description = $description;
$this->isCumulative = $isCumulative;
$this->isRemovingPostage = $isRemovingPostage;
$this->isAvailableOnSpecialOffers = $isAvailableOnSpecialOffers;
$this->isEnabled = $isEnabled;
$this->maxUsage = $maxUsage;
$this->expirationDate = $expirationDate;
$this->facade = $facade;
$this->effects = $effects;
// 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
* @return $this
*/
public function setPerCustomerUsageCount($perCustomerUsageCount)
{
$this->perCustomerUsageCount = $perCustomerUsageCount;
return $this;
}
/**
* @return true
*/
public function getPerCustomerUsageCount()
{
return $this->perCustomerUsageCount;
}
/**
* Return Coupon code (ex: XMAS)
*
* @return string
*/
public function getCode()
{
return $this->code;
}
/**
* Return Coupon title (ex: Coupon for XMAS)
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Return Coupon short description
*
* @return string
*/
public function getShortDescription()
{
return $this->shortDescription;
}
/**
* Return Coupon description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* If Coupon is cumulative or prevent any accumulation
* If is cumulative you can sum Coupon effects
* If not cancel all other Coupon and take the last given
*
* @return bool
*/
public function isCumulative()
{
return $this->isCumulative;
}
/**
* If Coupon is removing Checkout Postage
*
* @return bool
*/
public function isRemovingPostage()
{
return $this->isRemovingPostage;
}
/**
* @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()
{
return $this->amount;
}
/**
* Return condition to validate the Coupon or not
*
* @return ConditionCollection
*/
public function getConditions()
{
return clone $this->conditions;
}
/**
* Replace the existing Conditions by those given in parameter
* If one Condition is badly implemented, no Condition will be added
*
* @param ConditionCollection $conditions ConditionInterface to add
*
* @return $this
* @throws \Thelia\Exception\InvalidConditionException
*/
public function setConditions(ConditionCollection $conditions)
{
$this->conditions = $conditions;
return $this;
}
/**
* Return Coupon expiration date
*
* @return \DateTime
*/
public function getExpirationDate()
{
return clone $this->expirationDate;
}
/**
* Check if the Coupon can be used against a
* product already with a special offer price
*
* @return boolean
*/
public function isAvailableOnSpecialOffers()
{
return $this->isAvailableOnSpecialOffers;
}
/**
* Check if Coupon has been disabled by admin
*
* @return boolean
*/
public function isEnabled()
{
return $this->isEnabled;
}
/**
* Return how many time the Coupon can be used again
* Ex : -1 unlimited
*
* @return int
*/
public function getMaxUsage()
{
return $this->maxUsage;
}
/**
* Check if the Coupon is already Expired
*
* @return bool
*/
public function isExpired()
{
$ret = true;
$now = new \DateTime();
if ($this->expirationDate > $now) {
$ret = false;
}
return $ret;
}
/**
* Get Coupon Manager service Id
*
* @return string
*/
public function getServiceId()
{
return $this->serviceId;
}
/**
* Check if the current state of the application is matching this Coupon conditions
* Thelia variables are given by the FacadeInterface
*
* @return bool
*/
public function isMatching()
{
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
* Override this method to do something useful
*
* @return string HTML string
*/
public function drawBackOfficeInputs()
{
return $this->facade->getParser()->render('coupon/type-fragments/remove-x.html', [
'label' => $this->getInputName(),
'fieldId' => self::AMOUNT_FIELD_NAME,
'fieldName' => $this->makeCouponFieldName(self::AMOUNT_FIELD_NAME),
'value' => $this->amount
]);
}
/**
* 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 overriden to be useful.
*
* @param string $fieldName
* @param string $fieldValue
* @return mixed
* @throws \InvalidArgumentException if the field value is not valid.
*/
protected function checkCouponFieldValue(/** @noinspection PhpUnusedParameterInspection */ $fieldName, $fieldValue)
{
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.
}
public function isInUse()
{
return in_array(
$this->code,
$this->facade->getRequest()->getSession()->getConsumedCoupons()
);
}
}

View File

@@ -0,0 +1,251 @@
<?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 Propel\Runtime\Collection\ObjectCollection;
use Thelia\Condition\ConditionCollection;
use Thelia\Coupon\FacadeInterface;
/**
* Represents a Coupon ready to be processed in a Checkout process
*
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>
*
*/
interface CouponInterface
{
/**
* Get I18n name
*
* @return string
*/
public function getName();
/**
* Get I18n tooltip
*
* @return string
*/
public function getToolTip();
/**
* Get Coupon Manager service Id
*
* @return string
*/
public function getServiceId();
/**
* Set Coupon
*
* @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,
$code,
$title,
$shortDescription,
$description,
array $effects,
$isCumulative,
$isRemovingPostage,
$isAvailableOnSpecialOffers,
$isEnabled,
$maxUsage,
\DateTime $expirationDate,
$freeShippingForCountries,
$freeShippingForModules,
$perCustomerUsageCount
);
/**
* Return Coupon code (ex: XMAS)
*
* @return string
*/
public function getCode();
/**
* Return Coupon title (ex: Coupon for XMAS)
*
* @return string
*/
public function getTitle();
/**
* Return Coupon short description
*
* @return string
*/
public function getShortDescription();
/**
* Return Coupon description
*
* @return string
*/
public function getDescription();
/**
* If Coupon is cumulative or prevent any accumulation
* If is cumulative you can sum Coupon effects
* If not cancel all other Coupon and take the last given
*
* @return bool
*/
public function isCumulative();
/**
* If Coupon is removing Checkout Postage
*
* @return bool
*/
public function isRemovingPostage();
/**
* Return condition to validate the Coupon or not
*
* @return ConditionCollection A set of ConditionInterface
*/
public function getConditions();
/**
* Replace the existing Conditions by those given in parameter
* If one Condition is badly implemented, no Condition will be added
*
* @param ConditionCollection $conditions ConditionInterface to add
*
* @return $this
* @throws \Thelia\Exception\InvalidConditionException
*/
public function setConditions(ConditionCollection $conditions);
/**
* Return Coupon expiration date
*
* @return \DateTime
*/
public function getExpirationDate();
/**
* Check if the Coupon can be used against a
* product already with a special offer price
*
* @return boolean
*/
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
*
* @return boolean
*/
public function isEnabled();
/**
* Return how many time the Coupon can be used again
* Ex : -1 unlimited
*
* @return int
*/
public function getMaxUsage();
/**
* Check if the Coupon is already Expired
*
* @return bool
*/
public function isExpired();
/**
* Return an amount thant will be subtracted to the cart total, or zero.
*
* This method could also perform something else than the calculating an amount to subtract from the cart. It may
* add a product to the cart, for example. In this case, an amount of 0 will be returned.
*
* WARNING: this method could be called several times, so perform suitable checks before performing cart
* manipulations, so that the coupon effect will not be applied several times.
*
* @return float Amount removed from the cart total
*/
public function exec();
/**
* Check if the current Coupon is matching its conditions
* Thelia variables are given by the FacadeInterface
*
* @return bool
*/
public function isMatching();
/**
* Draw the input displayed in the BackOffice
* allowing Admin to set its Coupon effect
*
* @return string HTML string
*/
public function drawBackOfficeInputs();
/**
* @return ObjectCollection list of country IDs for which shipping is free. All if empty
*/
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();
/**
* @return bool true if the coupon is currently in use in the current order process, false otherwise
*/
public function isInUse();
}

View File

@@ -0,0 +1,330 @@
<?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 $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();
}
}
if ($freeProductCartItem instanceof CartItem) {
// The discount is the product price.
$discount = $freeProductCartItem->getRealTaxedPrice($this->facade->getDeliveryCountry());
}
// 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());
}
/**
* @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()
);
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();
}
}

View File

@@ -0,0 +1,94 @@
<?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\Model\CartItem;
/**
* 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
*/
public function setFieldsValue($effects)
{
$this->percentage = $effects[$this->getPercentageFieldName()];
}
/**
* @inheritdoc
*/
public function getCartItemDiscount(CartItem $cartItem)
{
return $cartItem->getQuantity() * $cartItem->getRealTaxedPrice($this->facade->getDeliveryCountry()) * ($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;
}
}

View File

@@ -0,0 +1,64 @@
<?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());
}
/**
* @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()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-attributes.html');
}
}

View File

@@ -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 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());
}
/**
* @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()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-categories.html');
}
}

View File

@@ -0,0 +1,69 @@
<?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());
}
/**
* @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()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-amount-on-products.html');
}
}

View 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;
/**
* 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());
}
/**
* @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()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-attributes.html');
}
}

View File

@@ -0,0 +1,67 @@
<?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());
}
/**
* @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()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-categories.html');
}
}

View File

@@ -0,0 +1,74 @@
<?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());
}
/**
* @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()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-percentage-on-products.html');
}
}

View File

@@ -0,0 +1,74 @@
<?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 Guillaume MOREL <gmorel@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
*
*/
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;
}
/**
* @inheritdoc
*/
public function getName()
{
return $this->facade
->getTranslator()
->trans('Fixed Amount Discount', array());
}
/**
* @inheritdoc
*/
public function getToolTip()
{
$toolTip = $this->facade
->getTranslator()
->trans(
'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.',
array()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function exec()
{
return $this->amount;
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-x-amount.html');
}
}

View File

@@ -0,0 +1,77 @@
<?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;
/**
* @package Coupon
* @author Guillaume MOREL <gmorel@openstudio.fr>, Franck Allimant <franck@cqfdev.fr>
*
*/
class RemoveXPercent extends AbstractRemove
{
const INPUT_PERCENTAGE_NAME = 'percentage';
use PercentageCouponTrait;
/** @var string Service Id */
protected $serviceId = 'thelia.coupon.type.remove_x_percent';
/**
* @inheritdoc
*/
protected function getPercentageFieldName()
{
return self::INPUT_PERCENTAGE_NAME;
}
/**
* @inheritdoc
*/
public function getName()
{
return $this->facade
->getTranslator()
->trans('Remove X percent to total cart', array());
}
/**
* @inheritdoc
*/
public function getToolTip()
{
$toolTip = $this->facade
->getTranslator()
->trans(
'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.',
array()
);
return $toolTip;
}
/**
* @inheritdoc
*/
public function exec()
{
return round($this->facade->getCartTotalTaxPrice($this->isAvailableOnSpecialOffers()) * $this->percentage/100, 2);
}
/**
* @inheritdoc
*/
public function drawBackOfficeInputs()
{
return $this->callDrawBackOfficeInputs('coupon/type-fragments/remove-x-percent.html');
}
}