Free shipping for selected countries and/or shipping methods

This commit is contained in:
Franck Allimant
2014-05-15 20:25:22 +02:00
parent 32542efe28
commit 392abff271
31 changed files with 414 additions and 106 deletions

View File

@@ -202,7 +202,9 @@ class Coupon extends BaseAction implements EventSubscriberInterface
$event->isCumulative(), $event->isCumulative(),
$event->getMaxUsage(), $event->getMaxUsage(),
$defaultSerializedRule, $defaultSerializedRule,
$event->getLocale() $event->getLocale(),
$event->getFreeShippingForCountries(),
$event->getFreeShippingForMethods()
); );
$event->setCouponModel($coupon); $event->setCouponModel($coupon);
@@ -235,8 +237,9 @@ class Coupon extends BaseAction implements EventSubscriberInterface
*/ */
public function testFreePostage(OrderEvent $event) public function testFreePostage(OrderEvent $event)
{ {
if ($this->couponManager->isCouponRemovingPostage()) { $order = $event->getOrder();
$order = $event->getOrder();
if ($this->couponManager->isCouponRemovingPostage($order)) {
$order->setPostage(0); $order->setPostage(0);

View File

@@ -82,7 +82,7 @@ class Order extends BaseAction implements EventSubscriberInterface
{ {
$order = $event->getOrder(); $order = $event->getOrder();
$order->chosenDeliveryAddress = $event->getDeliveryAddress(); $order->setChoosenDeliveryAddress($event->getDeliveryAddress());
$event->setOrder($order); $event->setOrder($order);
} }
@@ -125,7 +125,7 @@ class Order extends BaseAction implements EventSubscriberInterface
{ {
$order = $event->getOrder(); $order = $event->getOrder();
$order->chosenInvoiceAddress = $event->getInvoiceAddress(); $order->setChoosenInvoiceAddress($event->getInvoiceAddress());
$event->setOrder($order); $event->setOrder($order);
} }
@@ -153,9 +153,9 @@ class Order extends BaseAction implements EventSubscriberInterface
$placedOrder = $sessionOrder->copy(); $placedOrder = $sessionOrder->copy();
$placedOrder->setDispatcher($dispatcher); $placedOrder->setDispatcher($dispatcher);
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->chosenDeliveryAddress); $deliveryAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenDeliveryAddress());
$taxCountry = $deliveryAddress->getCountry(); $taxCountry = $deliveryAddress->getCountry();
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->chosenInvoiceAddress); $invoiceAddress = AddressQuery::create()->findPk($sessionOrder->getChoosenInvoiceAddress());
$cartItems = $cart->getCartItems(); $cartItems = $cart->getCartItems();
/* fulfill order */ /* fulfill order */

View File

@@ -4,32 +4,40 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
<services> <services>
<!-- Coupon module --> <!-- Coupon module -->
<service id="thelia.facade" class="Thelia\Coupon\BaseFacade"> <service id="thelia.facade" class="Thelia\Coupon\BaseFacade">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
</service> </service>
<service id="thelia.coupon.manager" class="Thelia\Coupon\CouponManager"> <service id="thelia.coupon.manager" class="Thelia\Coupon\CouponManager">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
</service> </service>
<service id="thelia.coupon.factory" class="Thelia\Coupon\CouponFactory"> <service id="thelia.coupon.factory" class="Thelia\Coupon\CouponFactory">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
</service> </service>
<!-- Coupon types -->
<service id="thelia.coupon.type.remove_x_amount" class="Thelia\Coupon\Type\RemoveXAmount"> <service id="thelia.coupon.type.remove_x_amount" class="Thelia\Coupon\Type\RemoveXAmount">
<argument type="service" id="thelia.facade" /> <argument type="service" id="thelia.facade" />
<tag name="thelia.coupon.addCoupon"/> <tag name="thelia.coupon.addCoupon"/>
</service> </service>
<service id="thelia.coupon.type.remove_x_percent" class="Thelia\Coupon\Type\RemoveXPercent"> <service id="thelia.coupon.type.remove_x_percent" class="Thelia\Coupon\Type\RemoveXPercent">
<argument type="service" id="thelia.facade" /> <argument type="service" id="thelia.facade" />
<tag name="thelia.coupon.addCoupon"/> <tag name="thelia.coupon.addCoupon"/>
</service> </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>
<!-- Condition module --> <!-- Condition module -->
<service id="thelia.condition.factory" class="Thelia\Condition\ConditionFactory"> <service id="thelia.condition.factory" class="Thelia\Condition\ConditionFactory">
<argument type="service" id="service_container" /> <argument type="service" id="service_container" />
</service> </service>
@@ -83,5 +91,4 @@
</service> </service>
</services> </services>
</config> </config>

View File

@@ -32,6 +32,8 @@ use Thelia\Form\CouponCreationForm;
use Thelia\Form\Exception\FormValidationException; use Thelia\Form\Exception\FormValidationException;
use Thelia\Log\Tlog; use Thelia\Log\Tlog;
use Thelia\Model\Coupon; use Thelia\Model\Coupon;
use Thelia\Model\CouponCountry;
use Thelia\Model\CouponModule;
use Thelia\Model\CouponQuery; use Thelia\Model\CouponQuery;
use Thelia\Model\LangQuery; use Thelia\Model\LangQuery;
use Thelia\Tools\Rest\ResponseRest; use Thelia\Tools\Rest\ResponseRest;
@@ -152,6 +154,21 @@ class CouponController extends BaseAdminController
$coupon->getSerializedConditions() $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 = [ $data = [
'code' => $coupon->getCode(), 'code' => $coupon->getCode(),
'title' => $coupon->getTitle(), 'title' => $coupon->getTitle(),
@@ -167,6 +184,8 @@ class CouponController extends BaseAdminController
'maxUsage' => $coupon->getMaxUsage(), 'maxUsage' => $coupon->getMaxUsage(),
'conditions' => $conditions, 'conditions' => $conditions,
'locale' => $this->getCurrentEditionLocale(), 'locale' => $this->getCurrentEditionLocale(),
'freeShippingForCountries' => $freeShippingForCountries,
'freeShippingForModules' => $freeShippingForModules
]; ];
$args['conditions'] = $this->cleanConditionForTemplate($conditions); $args['conditions'] = $this->cleanConditionForTemplate($conditions);
@@ -557,7 +576,7 @@ class CouponController extends BaseAdminController
$condition['serviceId'] = $availableCoupon->getServiceId(); $condition['serviceId'] = $availableCoupon->getServiceId();
$condition['name'] = $availableCoupon->getName(); $condition['name'] = $availableCoupon->getName();
$condition['toolTip'] = $availableCoupon->getToolTip(); $condition['toolTip'] = $availableCoupon->getToolTip();
$condition['inputName'] = $availableCoupon->getInputName(); // $condition['inputName'] = $availableCoupon->getInputName();
$cleanedCoupons[] = $condition; $cleanedCoupons[] = $condition;
} }
@@ -702,7 +721,7 @@ class CouponController extends BaseAdminController
$couponManager = $this->container->get($serviceId); $couponManager = $this->container->get($serviceId);
$effects = [CouponAbstract::INPUT_AMOUNT_NAME => $data[CouponAbstract::INPUT_AMOUNT_NAME]]; $effects = [CouponAbstract::INPUT_AMOUNT_NAME => $data[CouponAbstract::INPUT_AMOUNT_NAME]];
$effects = $this->addExtendedLogic($effects, $couponManager->getExtendedInputs()); $effects = $this->addExtendedLogic($effects, $couponManager->getExtendedInputs());
var_dump($data);
$couponEvent = new CouponCreateOrUpdateEvent( $couponEvent = new CouponCreateOrUpdateEvent(
$data['code'], $data['code'],
$serviceId, $serviceId,
@@ -716,7 +735,9 @@ class CouponController extends BaseAdminController
$data['isCumulative'], $data['isCumulative'],
$data['isRemovingPostage'], $data['isRemovingPostage'],
$data['maxUsage'], $data['maxUsage'],
$data['locale'] $data['locale'],
$data['freeShippingForCountries'],
$data['freeShippingForModules']
); );
// If Update mode // If Update mode
@@ -774,7 +795,9 @@ class CouponController extends BaseAdminController
$coupon->getIsCumulative(), $coupon->getIsCumulative(),
$coupon->getIsRemovingPostage(), $coupon->getIsRemovingPostage(),
$coupon->getMaxUsage(), $coupon->getMaxUsage(),
$coupon->getLocale() $coupon->getLocale(),
$coupon->getFreeShippingForCountries(),
$coupon->getFreeShippingForModules()
); );
$couponEvent->setCouponModel($coupon); $couponEvent->setCouponModel($coupon);
$couponEvent->setConditions($conditions); $couponEvent->setConditions($conditions);

View File

@@ -15,10 +15,10 @@ namespace Thelia\Controller\Front;
use Symfony\Component\Routing\Router; use Symfony\Component\Routing\Router;
use Thelia\Controller\BaseController; use Thelia\Controller\BaseController;
use Thelia\Core\HttpFoundation\Response; use Thelia\Core\HttpFoundation\Response;
use Thelia\Core\Template\TemplateDefinition;
use Thelia\Core\Template\TemplateHelper; use Thelia\Core\Template\TemplateHelper;
use Thelia\Model\AddressQuery; use Thelia\Model\AddressQuery;
use Thelia\Model\ModuleQuery; use Thelia\Model\ModuleQuery;
use Thelia\Tools\URL; use Thelia\Tools\URL;
class BaseFrontController extends BaseController class BaseFrontController extends BaseController
@@ -65,7 +65,15 @@ class BaseFrontController extends BaseController
protected function checkValidDelivery() protected function checkValidDelivery()
{ {
$order = $this->getSession()->getOrder(); $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"); $this->redirectToRoute("order.delivery");
} }
} }
@@ -73,13 +81,21 @@ class BaseFrontController extends BaseController
protected function checkValidInvoice() protected function checkValidInvoice()
{ {
$order = $this->getSession()->getOrder(); $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"); $this->redirectToRoute("order.invoice");
} }
} }
/** /**
* @return ParserInterface instance parser * @return TemplateDefinition the template
*/ */
protected function getParser($template = null) protected function getParser($template = null)
{ {

View File

@@ -31,19 +31,41 @@ class CouponConsumeEvent extends ActionEvent
/** @var bool If Coupon is valid or if Customer meets coupon conditions */ /** @var bool If Coupon is valid or if Customer meets coupon conditions */
protected $isValid = null; protected $isValid = null;
/** @var bool true if coupon offers free shipping */
protected $freeShipping = false;
/** /**
* Constructor * Constructor
* *
* @param string $code Coupon code * @param string $code Coupon code
* @param float $discount Total discount given by this coupon * @param float $discount Total discount given by this coupon
* @param bool $isValid If Coupon is valid or * @param bool $isValid If Coupon is valid or f Customer meets coupon conditions
* if 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->code = $code;
$this->discount = $discount; $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;
} }
/** /**

View File

@@ -73,6 +73,12 @@ class CouponCreateOrUpdateEvent extends ActionEvent
/** @var string Language code ISO (ex: fr_FR) */ /** @var string Language code ISO (ex: fr_FR) */
protected $locale = null; 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;
/** /**
* Constructor * Constructor
* *
@@ -91,8 +97,13 @@ class CouponCreateOrUpdateEvent extends ActionEvent
* @param boolean $isRemovingPostage Is removing Postage * @param boolean $isRemovingPostage Is removing Postage
* @param int $maxUsage Coupon quantity * @param int $maxUsage Coupon quantity
* @param string $locale Coupon Language code ISO (ex: fr_FR) * @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
*/ */
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)
{ {
$this->code = $code; $this->code = $code;
$this->description = $description; $this->description = $description;
@@ -107,6 +118,44 @@ class CouponCreateOrUpdateEvent extends ActionEvent
$this->serviceId = $serviceId; $this->serviceId = $serviceId;
$this->locale = $locale; $this->locale = $locale;
$this->setEffects($effects); $this->setEffects($effects);
$this->freeShippingForCountries = $freeShippingForCountries;
$this->freeShippingForMethods = $freeShippingForMethods;
}
/**
* @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;
} }
/** /**

View File

@@ -178,7 +178,9 @@ class Coupon extends BaseI18nLoop implements PropelSearchLoopInterface
$coupon->getIsAvailableOnSpecialOffers(), $coupon->getIsAvailableOnSpecialOffers(),
$coupon->getIsEnabled(), $coupon->getIsEnabled(),
$coupon->getMaxUsage(), $coupon->getMaxUsage(),
$coupon->getExpirationDate() $coupon->getExpirationDate(),
$coupon->getFreeShippingForCountries(),
$coupon->getFreeShippingForModules()
); );
$cleanedConditions = array(); $cleanedConditions = array();

View File

@@ -204,9 +204,9 @@ class DataAccessFunctions extends AbstractSmartyPlugin
case 'discount': case 'discount':
return $order->getDiscount(); return $order->getDiscount();
case 'delivery_address': case 'delivery_address':
return $order->chosenDeliveryAddress; return $order->getChoosenDeliveryAddress();
case 'invoice_address': case 'invoice_address':
return $order->chosenInvoiceAddress; return $order->getChoosenInvoiceAddress();
case 'delivery_module': case 'delivery_module':
return $order->getDeliveryModuleId(); return $order->getDeliveryModuleId();
case 'payment_module': case 'payment_module':

View File

@@ -82,7 +82,7 @@ class Security extends AbstractSmartyPlugin
$order = $this->request->getSession()->getOrder(); $order = $this->request->getSession()->getOrder();
/* Does address and module still exists ? We assume address owner can't change neither module type */ /* Does address and module still exists ? We assume address owner can't change neither module type */
if ($order !== null) { if ($order !== null) {
$checkAddress = AddressQuery::create()->findPk($order->chosenDeliveryAddress); $checkAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress());
$checkModule = ModuleQuery::create()->findPk($order->getDeliveryModuleId()); $checkModule = ModuleQuery::create()->findPk($order->getDeliveryModuleId());
} }
if (null === $order || null == $checkAddress || null === $checkModule) { if (null === $order || null == $checkAddress || null === $checkModule) {

View File

@@ -77,7 +77,7 @@ class BaseFacade implements FacadeInterface
public function getDeliveryAddress() public function getDeliveryAddress()
{ {
try { try {
return AddressQuery::create()->findPk($this->getRequest()->getSession()->getOrder()->chosenDeliveryAddress); return AddressQuery::create()->findPk($this->getRequest()->getSession()->getOrder()->getChoosenDeliveryAddress());
} }
catch(\Exception $ex) { catch(\Exception $ex) {
throw new \LogicException("Failed to get delivery address (" . $ex->getMessage() . ")"); throw new \LogicException("Failed to get delivery address (" . $ex->getMessage() . ")");

View File

@@ -107,7 +107,9 @@ class CouponFactory
$model->getIsAvailableOnSpecialOffers(), $model->getIsAvailableOnSpecialOffers(),
$model->getIsEnabled(), $model->getIsEnabled(),
$model->getMaxUsage(), $model->getMaxUsage(),
$model->getExpirationDate() $model->getExpirationDate(),
$model->getFreeShippingForCountries(),
$model->getFreeShippingForModules()
); );
/** @var ConditionFactory $conditionFactory */ /** @var ConditionFactory $conditionFactory */

View File

@@ -15,7 +15,14 @@ namespace Thelia\Coupon;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Condition\Implementation\ConditionInterface; use Thelia\Condition\Implementation\ConditionInterface;
use Thelia\Coupon\Type\CouponInterface; use Thelia\Coupon\Type\CouponInterface;
use Thelia\Log\Tlog;
use Thelia\Model\AddressQuery;
use Thelia\Model\Base\CouponModule;
use Thelia\Model\Coupon; use Thelia\Model\Coupon;
use Thelia\Model\CouponCountry;
use Thelia\Model\Order;
use Thelia\Model\OrderAddress;
use Thelia\Model\OrderAddressQuery;
/** /**
* Manage how Coupons could interact with a Checkout * Manage how Coupons could interact with a Checkout
@@ -78,9 +85,10 @@ class CouponManager
* Check if there is a Coupon removing Postage * Check if there is a Coupon removing Postage
* @return bool * @return bool
*/ */
public function isCouponRemovingPostage() public function isCouponRemovingPostage(Order $order)
{ {
$coupons = $this->facade->getCurrentCoupons(); $coupons = $this->facade->getCurrentCoupons();
if (count($coupons) == 0) { if (count($coupons) == 0) {
return false; return false;
} }
@@ -89,7 +97,60 @@ class CouponManager
/** @var CouponInterface $coupon */ /** @var CouponInterface $coupon */
foreach ($couponsKept as $coupon) { foreach ($couponsKept as $coupon) {
if ($coupon->isRemovingPostage()) { 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 true;
} }
} }

View File

@@ -12,11 +12,13 @@
namespace Thelia\Coupon\Type; namespace Thelia\Coupon\Type;
use Thelia\Condition\ConditionCollection;
use Thelia\Condition\ConditionEvaluator; use Thelia\Condition\ConditionEvaluator;
use Thelia\Condition\ConditionOrganizerInterface;
use Thelia\Core\Translation\Translator; use Thelia\Core\Translation\Translator;
use Thelia\Coupon\FacadeInterface; use Thelia\Coupon\FacadeInterface;
use Thelia\Condition\ConditionCollection; use Thelia\Model\CouponCountry;
use Thelia\Condition\ConditionOrganizerInterface; use Thelia\Model\CouponModule;
/** /**
* Assist in writing a CouponInterface * Assist in writing a CouponInterface
@@ -88,6 +90,12 @@ abstract class CouponAbstract implements CouponInterface
/** @var bool if Coupon is available for Products already on special offers */ /** @var bool if Coupon is available for Products already on special offers */
protected $isAvailableOnSpecialOffers = false; 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 = [];
/** /**
* Constructor * Constructor
* *
@@ -115,23 +123,7 @@ abstract class CouponAbstract implements CouponInterface
} }
/** /**
* Set Coupon * @inheritdoc
*
* @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
*/ */
public function set( public function set(
FacadeInterface $facade, FacadeInterface $facade,
@@ -145,7 +137,9 @@ abstract class CouponAbstract implements CouponInterface
$isAvailableOnSpecialOffers, $isAvailableOnSpecialOffers,
$isEnabled, $isEnabled,
$maxUsage, $maxUsage,
\DateTime $expirationDate \DateTime $expirationDate,
$freeShippingForCountries,
$freeShippingForModules
) )
{ {
$this->code = $code; $this->code = $code;
@@ -165,6 +159,9 @@ abstract class CouponAbstract implements CouponInterface
$this->effects = $effects; $this->effects = $effects;
$this->amount = $effects[self::INPUT_AMOUNT_NAME]; $this->amount = $effects[self::INPUT_AMOUNT_NAME];
$this->freeShippingForCountries = $freeShippingForCountries;
$this->freeShippingForModules = $freeShippingForModules;
return $this; return $this;
} }
@@ -230,6 +227,20 @@ abstract class CouponAbstract implements CouponInterface
return $this->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;
}
/** /**
* Return effects generated by the coupon * Return effects generated by the coupon
* A negative value * A negative value

View File

@@ -12,8 +12,11 @@
namespace Thelia\Coupon\Type; namespace Thelia\Coupon\Type;
use Propel\Runtime\Collection\ObjectCollection;
use Thelia\Condition\ConditionCollection; use Thelia\Condition\ConditionCollection;
use Thelia\Coupon\FacadeInterface; use Thelia\Coupon\FacadeInterface;
use Thelia\Model\CouponCountry;
use Thelia\Model\CouponModule;
/** /**
* Represents a Coupon ready to be processed in a Checkout process * Represents a Coupon ready to be processed in a Checkout process
@@ -31,13 +34,6 @@ interface CouponInterface
*/ */
public function getName(); public function getName();
/**
* Get I18n amount input name
*
* @return string
*/
public function getInputName();
/** /**
* Get I18n tooltip * Get I18n tooltip
* *
@@ -68,6 +64,9 @@ interface CouponInterface
* @param bool $isEnabled False if Coupon is disabled by admin * @param bool $isEnabled False if Coupon is disabled by admin
* @param int $maxUsage How many usage left * @param int $maxUsage How many usage left
* @param \Datetime $expirationDate When the Code is expiring * @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
*/ */
public function set( public function set(
FacadeInterface $facade, FacadeInterface $facade,
@@ -81,7 +80,10 @@ interface CouponInterface
$isAvailableOnSpecialOffers, $isAvailableOnSpecialOffers,
$isEnabled, $isEnabled,
$maxUsage, $maxUsage,
\DateTime $expirationDate); \DateTime $expirationDate,
$freeShippingForCountries,
$freeShippingForModules
);
/** /**
* Return Coupon code (ex: XMAS) * Return Coupon code (ex: XMAS)
@@ -218,4 +220,13 @@ interface CouponInterface
*/ */
public function getExtendedInputs(); public function getExtendedInputs();
/**
* @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();
} }

View File

@@ -35,23 +35,7 @@ class RemoveXPercent extends CouponAbstract
); );
/** /**
* Set Coupon * @inheritdoc
*
* @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
*/ */
public function set( public function set(
FacadeInterface $facade, FacadeInterface $facade,
@@ -65,12 +49,18 @@ class RemoveXPercent extends CouponAbstract
$isAvailableOnSpecialOffers, $isAvailableOnSpecialOffers,
$isEnabled, $isEnabled,
$maxUsage, $maxUsage,
\DateTime $expirationDate \DateTime $expirationDate,
$freeShippingForCountries,
$freeShippingForModules
) )
{ {
parent::set( parent::set(
$facade, $code, $title, $shortDescription, $description, $effects, $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate $facade, $code, $title, $shortDescription, $description, $effects,
$isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate,
$freeShippingForCountries,
$freeShippingForModules
); );
$this->percentage = $effects[self::INPUT_PERCENTAGE_NAME]; $this->percentage = $effects[self::INPUT_PERCENTAGE_NAME];
return $this; return $this;

View File

@@ -18,7 +18,14 @@ use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotEqualTo; use Symfony\Component\Validator\Constraints\NotEqualTo;
use Symfony\Component\Validator\ExecutionContextInterface; use Symfony\Component\Validator\ExecutionContextInterface;
use Thelia\Core\Translation\Translator; use Thelia\Core\Translation\Translator;
use Thelia\Model\Base\CountryI18n;
use Thelia\Model\Base\CountryQuery;
use Thelia\Model\Base\LangQuery; use Thelia\Model\Base\LangQuery;
use Thelia\Model\Base\ModuleQuery;
use Thelia\Model\CountryI18nQuery;
use Thelia\Model\Module;
use Thelia\Model\ModuleI18nQuery;
use Thelia\Module\BaseModule;
/** /**
* Allow to build a form Coupon * Allow to build a form Coupon
@@ -36,6 +43,33 @@ class CouponCreationForm extends BaseForm
*/ */
protected function buildForm() 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 $this->formBuilder
->add( ->add(
'code', 'code',
@@ -116,6 +150,22 @@ class CouponCreationForm extends BaseForm
'text', 'text',
array() array()
) )
->add(
'freeShippingForCountries',
'choice',
array(
'multiple' => true,
'choices' => $countries
)
)
->add(
'freeShippingForModules',
'choice',
array(
'multiple' => true,
'choices' => $modules
)
)
->add( ->add(
'isAvailableOnSpecialOffers', 'isAvailableOnSpecialOffers',
'text', 'text',

View File

@@ -25,6 +25,8 @@ namespace Thelia\Model;
use Propel\Runtime\Propel; use Propel\Runtime\Propel;
use Thelia\Model\Base\Coupon as BaseCoupon; use Thelia\Model\Base\Coupon as BaseCoupon;
use Thelia\Model\Base\CouponCountryQuery;
use Thelia\Model\Base\CouponModuleQuery;
use Thelia\Model\Exception\InvalidArgumentException; use Thelia\Model\Exception\InvalidArgumentException;
use Thelia\Model\Map\CouponTableMap; use Thelia\Model\Map\CouponTableMap;
use Thelia\Model\Tools\ModelEventDispatcherTrait; use Thelia\Model\Tools\ModelEventDispatcherTrait;
@@ -127,11 +129,13 @@ class Coupon extends BaseCoupon
; ;
} }
$con->commit();
} catch (\Exception $ex) { } catch (\Exception $ex) {
$con->rollback(); $con->rollback();
throw $ex; throw $ex;
} }
} }
@@ -248,4 +252,21 @@ class Coupon extends BaseCoupon
return $effects; return $effects;
} }
/**
* Return the countries for which free shipping is valid
* @return array|mixed|\Propel\Runtime\Collection\ObjectCollection
*/
public function getFreeShippingForCountries() {
return CouponCountryQuery::create()->filterByCouponId($this->getId())->find();
}
/**
* Return the modules for which free shipping is valid
*
* @return array|mixed|\Propel\Runtime\Collection\ObjectCollection
*/
public function getFreeShippingForModules() {
return CouponModuleQuery::create()->filterByCouponId($this->getId())->find();
}
} }

View File

@@ -121,8 +121,8 @@ class TaxEngine
/* is there a logged in customer ? */ /* is there a logged in customer ? */
if (null !== $customer = $this->session->getCustomerUser()) { if (null !== $customer = $this->session->getCustomerUser()) {
if (null !== $this->session->getOrder() if (null !== $this->session->getOrder()
&& null !== $this->session->getOrder()->chosenDeliveryAddress && null !== $this->session->getOrder()->getChoosenDeliveryAddress()
&& null !== $currentDeliveryAddress = AddressQuery::create()->findPk($this->session->getOrder()->chosenDeliveryAddress)) { && null !== $currentDeliveryAddress = AddressQuery::create()->findPk($this->session->getOrder()->getChoosenDeliveryAddress())) {
$this->taxCountry = $currentDeliveryAddress->getCountry(); $this->taxCountry = $currentDeliveryAddress->getCountry();
} else { } else {
$customerDefaultAddress = $customer->getDefaultAddress(); $customerDefaultAddress = $customer->getDefaultAddress();

View File

@@ -196,7 +196,7 @@ class OrderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals( $this->assertEquals(
321, 321,
$this->orderEvent->getOrder()->chosenDeliveryAddress $this->orderEvent->getOrder()->getChoosenDeliveryAddress()
); );
} }
@@ -208,7 +208,7 @@ class OrderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals( $this->assertEquals(
654, 654,
$this->orderEvent->getOrder()->chosenInvoiceAddress $this->orderEvent->getOrder()->getChoosenInvoiceAddress()
); );
} }
@@ -263,8 +263,8 @@ class OrderTest extends \PHPUnit_Framework_TestCase
$paymentModuleClass = $paymentModule->getFullNamespace(); $paymentModuleClass = $paymentModule->getFullNamespace();
$this->container->set(sprintf('module.%s', $paymentModule->getCode()), new $paymentModuleClass()); $this->container->set(sprintf('module.%s', $paymentModule->getCode()), new $paymentModuleClass());
$this->orderEvent->getOrder()->chosenDeliveryAddress = $validDeliveryAddress->getId(); $this->orderEvent->getOrder()->setChoosenDeliveryAddress($validDeliveryAddress->getId());
$this->orderEvent->getOrder()->chosenInvoiceAddress = $validInvoiceAddress->getId(); $this->orderEvent->getOrder()->setChoosenInvoiceAddress($validInvoiceAddress->getId());
$this->orderEvent->getOrder()->setDeliveryModuleId($deliveryModule->getId()); $this->orderEvent->getOrder()->setDeliveryModuleId($deliveryModule->getId());
$this->orderEvent->getOrder()->setPostage(20); $this->orderEvent->getOrder()->setPostage(20);
$this->orderEvent->getOrder()->setPaymentModuleId($paymentModule->getId()); $this->orderEvent->getOrder()->setPaymentModuleId($paymentModule->getId());

View File

@@ -11,6 +11,7 @@
/*************************************************************************************/ /*************************************************************************************/
namespace Thelia\Coupon; namespace Thelia\Coupon;
use Propel\Runtime\Collection\ObjectCollection;
use Thelia\Condition\ConditionCollection; use Thelia\Condition\ConditionCollection;
use Thelia\Condition\ConditionEvaluator; use Thelia\Condition\ConditionEvaluator;
use Thelia\Condition\ConditionFactory; use Thelia\Condition\ConditionFactory;
@@ -18,7 +19,9 @@ use Thelia\Condition\Implementation\MatchForTotalAmount;
use Thelia\Condition\Operators; use Thelia\Condition\Operators;
use Thelia\Coupon\Type\RemoveXAmount; use Thelia\Coupon\Type\RemoveXAmount;
use Thelia\Model\Coupon; use Thelia\Model\Coupon;
use Thelia\Model\CouponCountry;
use Thelia\Model\CurrencyQuery; use Thelia\Model\CurrencyQuery;
use Thelia\Model\Order;
/** /**
* Unit Test CouponManager Class * Unit Test CouponManager Class
@@ -167,8 +170,13 @@ Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesua
$actual = $couponManager->getDiscount(); $actual = $couponManager->getDiscount();
$expected = 21 + 21.50; $expected = 21 + 21.50;
$order = new Order();
$order->setChoosenDeliveryAddress(1);
$order->setDeliveryModuleId(1);
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
$this->assertTrue($couponManager->isCouponRemovingPostage()); $this->assertTrue($couponManager->isCouponRemovingPostage($order));
} }
/** /**
@@ -390,7 +398,12 @@ Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesua
$coupon = new RemoveXAmount($stubFacade); $coupon = new RemoveXAmount($stubFacade);
$date = new \DateTime(); $date = new \DateTime();
$coupon->set($stubFacade, 'XMAS', '', '', '', array('amount' => 21.00), true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")) ); $coupon->set(
$stubFacade, 'XMAS', '', '', '', array('amount' => 21.00),
true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")),
new ObjectCollection(),
new ObjectCollection()
);
$condition1 = new MatchForTotalAmount($stubFacade); $condition1 = new MatchForTotalAmount($stubFacade);
$operators = array( $operators = array(
@@ -455,7 +468,12 @@ Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesua
$coupon = new RemoveXAmount($stubFacade); $coupon = new RemoveXAmount($stubFacade);
$date = new \DateTime(); $date = new \DateTime();
$coupon->set($stubFacade, 'XMAS', '', '', '', array('amount' => 21.00), true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")) ); $coupon->set(
$stubFacade, 'XMAS', '', '', '', array('amount' => 21.00),
true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")),
new ObjectCollection(),
new ObjectCollection()
);
$condition1 = new MatchForTotalAmount($stubFacade); $condition1 = new MatchForTotalAmount($stubFacade);
$operators = array( $operators = array(

View File

@@ -11,6 +11,7 @@
/*************************************************************************************/ /*************************************************************************************/
namespace Thelia\Coupon\Type; namespace Thelia\Coupon\Type;
use Propel\Runtime\Collection\ObjectCollection;
use Thelia\Condition\ConditionCollection; use Thelia\Condition\ConditionCollection;
use Thelia\Condition\ConditionEvaluator; use Thelia\Condition\ConditionEvaluator;
use Thelia\Condition\Implementation\MatchForTotalAmount; use Thelia\Condition\Implementation\MatchForTotalAmount;
@@ -114,7 +115,12 @@ class RemoveXAmountTest extends \PHPUnit_Framework_TestCase
Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.'; Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.';
$coupon->set($stubFacade, 'XMAS', 'XMAS Coupon', 'Coupon for Springbreak removing 10€ if you have a cart between 40.00€ and 400.00€ (excluded)', $description, array('amount' => 10.00), true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")) ); $coupon->set(
$stubFacade, 'XMAS', 'XMAS Coupon', 'Coupon for Springbreak removing 10€ if you have a cart between 40.00€ and 400.00€ (excluded)',
$description, array('amount' => 10.00), true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")),
new ObjectCollection(),
new ObjectCollection()
);
$condition1 = new MatchForTotalAmount($stubFacade); $condition1 = new MatchForTotalAmount($stubFacade);
$operators = array( $operators = array(

View File

@@ -11,6 +11,7 @@
/*************************************************************************************/ /*************************************************************************************/
namespace Thelia\Coupon\Type; namespace Thelia\Coupon\Type;
use Propel\Runtime\Collection\ObjectCollection;
use Thelia\Condition\ConditionCollection; use Thelia\Condition\ConditionCollection;
use Thelia\Condition\ConditionEvaluator; use Thelia\Condition\ConditionEvaluator;
use Thelia\Condition\Implementation\MatchForTotalAmount; use Thelia\Condition\Implementation\MatchForTotalAmount;
@@ -103,7 +104,13 @@ class RemoveXPercentTest extends \PHPUnit_Framework_TestCase
Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.'; Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.';
$coupon->set($stubFacade, 'XMAS', 'XMAS Coupon', 'Coupon for Springbreak removing 10% if you have a cart between 40.00€ and 400.00€ (excluded)', $description, array('amount' => 0.00, 'percentage' => 10.00), true, true, true, true, 254, $date->setTimestamp(strtotime("today + 3 months")) ); $coupon->set(
$stubFacade, 'XMAS', 'XMAS Coupon', 'Coupon for Springbreak removing 10% if you have a cart between 40.00€ and 400.00€ (excluded)',
$description, array('amount' => 0.00, 'percentage' => 10.00), true, true, true, true,
254, $date->setTimestamp(strtotime("today + 3 months")),
new ObjectCollection(),
new ObjectCollection()
);
$condition1 = new MatchForTotalAmount($stubFacade); $condition1 = new MatchForTotalAmount($stubFacade);
$operators = array( $operators = array(

View File

@@ -174,7 +174,7 @@ class CartController extends BaseFrontController
$order = $this->getSession()->getOrder(); $order = $this->getSession()->getOrder();
if (null !== $order) { if (null !== $order) {
$deliveryModule = $order->getModuleRelatedByDeliveryModuleId(); $deliveryModule = $order->getModuleRelatedByDeliveryModuleId();
$deliveryAddress = AddressQuery::create()->findPk($order->chosenDeliveryAddress); $deliveryAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress());
if (null !== $deliveryModule && null !== $deliveryAddress) { if (null !== $deliveryModule && null !== $deliveryAddress) {
$moduleInstance = $deliveryModule->getModuleInstance($this->container); $moduleInstance = $deliveryModule->getModuleInstance($this->container);

View File

@@ -72,7 +72,7 @@ class CouponController extends BaseFrontController
if (null !== $order) { if (null !== $order) {
$deliveryModule = $order->getModuleRelatedByDeliveryModuleId(); $deliveryModule = $order->getModuleRelatedByDeliveryModuleId();
$deliveryAddress = AddressQuery::create()->findPk($order->chosenDeliveryAddress); $deliveryAddress = AddressQuery::create()->findPk($order->getChoosenDeliveryAddress());
if (null !== $deliveryModule && null !== $deliveryAddress) { if (null !== $deliveryModule && null !== $deliveryAddress) {

View File

@@ -303,5 +303,17 @@ $(function($){
}); });
}; };
// Shipping conditions
$('#is-removing-postage').change(function(ev) {
if ($(this).is(':checked')) {
$('.free-postage-conditions').stop().slideDown();
}
else {
$('.free-postage-conditions').stop().slideUp();
}
})
$.couponManager.onUsageUnlimitedChange(); $.couponManager.onUsageUnlimitedChange();
$('#is-removing-postage').change();
}); });

View File

@@ -6,7 +6,7 @@
<div class="form-group"> <div class="form-group">
<label for="{$categories_field_name}-value">{intl l="The selected categories :"}</label> <label for="{$categories_field_name}-value">{intl l="The selected categories :"}</label>
<select required multiple size="5" class="form-control" id="{$categories_field_name}-value" name="{$categories_field_name}[value][]"> <select required multiple size="5" class="form-control" id="{$categories_field_name}-value" name="{$categories_field_name}[value][]">
{loop type="category-tree" category=0 name="list-of-categories"} {loop type="category-tree" category=0 name="list-of-categories" backend_context=1}
<option style="padding-left: {$LEVEL * 20}px" value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$TITLE}</option> <option style="padding-left: {$LEVEL * 20}px" value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$TITLE}</option>
{/loop} {/loop}
</select> </select>

View File

@@ -6,7 +6,7 @@
<div class="form-group"> <div class="form-group">
<label for="{$products_field_name}-value">{intl l="The selected products :"}</label> <label for="{$products_field_name}-value">{intl l="The selected products :"}</label>
<select required multiple size="5" class="form-control" id="{$products_field_name}-value" name="{$products_field_name}[value][]"> <select required multiple size="5" class="form-control" id="{$products_field_name}-value" name="{$products_field_name}[value][]">
{loop type="product" name="list-of-products" order="alpha"} {loop type="product" name="list-of-products" order="alpha" backend_context=1}
<option value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$TITLE}</option> <option value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$TITLE}</option>
{/loop} {/loop}
</select> </select>

View File

@@ -6,7 +6,7 @@
<div class="form-group"> <div class="form-group">
<label for="{$countries_field_name}-value">{intl l="The selected countries :"}</label> <label for="{$countries_field_name}-value">{intl l="The selected countries :"}</label>
<select required multiple size="5" class="form-control" id="{$countries_field_name}-value" name="{$countries_field_name}[value][]"> <select required multiple size="5" class="form-control" id="{$countries_field_name}-value" name="{$countries_field_name}[value][]">
{loop type="country" name="list-of-countries" order="alpha"} {loop type="country" name="list-of-countries" order="alpha" backend_context=1}
<option style="padding-left: {$LEVEL * 20}px" value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$TITLE}</option> <option style="padding-left: {$LEVEL * 20}px" value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$TITLE}</option>
{/loop} {/loop}
</select> </select>

View File

@@ -6,7 +6,7 @@
<div class="form-group"> <div class="form-group">
<label for="{$customers_field_name}-value">{intl l="The selected customer :"}</label> <label for="{$customers_field_name}-value">{intl l="The selected customer :"}</label>
<select required multiple size="5" class="form-control" id="{$customers_field_name}-value" name="{$customers_field_name}[value][]"> <select required multiple size="5" class="form-control" id="{$customers_field_name}-value" name="{$customers_field_name}[value][]">
{loop type="customer" name="list-of-customers" order="lastname,firstname" current="0" backend_context="1"} {loop type="customer" name="list-of-customers" order="lastname,firstname" current="0" backend_context=1}
<option value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$LASTNAME} {$FIRSTNAME} {$REF}</option> <option value="{$ID}" {if in_array($ID, $values)}selected="selected"{/if}>{$LASTNAME} {$FIRSTNAME} {$REF}</option>
{/loop} {/loop}
</select> </select>

View File

@@ -123,10 +123,9 @@
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="for-countries-only">{intl l="Free shipping to countries :"}</label> <label for="for-countries-only">{intl l="Free shipping to countries :"}</label>
<select multiple size="5" class="form-control" id="for-countries-only" name="{$name}"> <select multiple size="5" class="form-control" id="for-countries-only" name="{$name}">
<option value="">{intl l="All countries"}</option> {foreach $choices as $choice}
{loop type="country" name="list-of-countries" order="alpha" backend_context="1"} <option value="{$choice->value}" {if in_array($choice->value, $value)}selected="selected"{/if}>{$choice->label}</option>
<option style="padding-left: {$LEVEL * 20}px" value="{$ID}">{$TITLE}</option> {/foreach}
{/loop}
</select> </select>
<span class="label-help-block">{intl l='Use Ctrl+click to select (or deselect) more that one country'}</span> <span class="label-help-block">{intl l='Use Ctrl+click to select (or deselect) more that one country'}</span>
</div> </div>
@@ -136,16 +135,14 @@
<div class="form-group {if $error}has-error{/if}"> <div class="form-group {if $error}has-error{/if}">
<label for="for-modules-only">{intl l="Free shipping for methods :"}</label> <label for="for-modules-only">{intl l="Free shipping for methods :"}</label>
<select multiple size="5" class="form-control" id="for-modules-only" name="{$name}"> <select multiple size="5" class="form-control" id="for-modules-only" name="{$name}">
<option value="">{intl l="All shipping methods"}</option> {foreach $choices as $choice}
{loop type="module" name="list-of-shipping-moddule" module_type=2 order=alpha backend_context=1} <option value="{$choice->value}" {if in_array($choice->value, $value)}selected="selected"{/if}>{$choice->label}</option>
<option value="{$ID}">{$TITLE}</option> {/foreach}
{/loop}
</select> </select>
<span class="label-help-block">{intl l='Use Ctrl+click to select (or deselect) more that one shipping method'}</span> <span class="label-help-block">{intl l='Use Ctrl+click to select (or deselect) more that one shipping method'}</span>
</div> </div>
{/form_field} {/form_field}
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">