diff --git a/core/lib/Thelia/Action/Delivery.php b/core/lib/Thelia/Action/Delivery.php new file mode 100644 index 0000000000..8d88512114 --- /dev/null +++ b/core/lib/Thelia/Action/Delivery.php @@ -0,0 +1,66 @@ + + */ +class Delivery implements EventSubscriberInterface +{ + /** + * Get postage from module using the classical module functions + * + * @param DeliveryPostageEvent $event + */ + public function getPostage(DeliveryPostageEvent $event, $eventName, EventDispatcherInterface $dispatcher) + { + $module = $event->getModule(); + + // dispatch event to target specific module + $dispatcher->dispatch( + TheliaEvents::getModuleEvent( + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE, + $module->getCode() + ), + $event + ); + + if ($event->isPropagationStopped()) { + return; + } + + // call legacy module method + $event->setValidModule($module->isValidDelivery($event->getCountry())); + if ($event->isValidModule()) { + $event->setPostage($module->getPostage($event->getCountry())); + } + } + + /** + * @inheritdoc + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE => ['getPostage', 128] + ]; + } +} diff --git a/core/lib/Thelia/Action/Order.php b/core/lib/Thelia/Action/Order.php index 947aa34263..5951d619ad 100644 --- a/core/lib/Thelia/Action/Order.php +++ b/core/lib/Thelia/Action/Order.php @@ -13,6 +13,7 @@ namespace Thelia\Action; use Propel\Runtime\Propel; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\RequestStack; @@ -20,6 +21,7 @@ use Thelia\Core\Event\Order\OrderEvent; use Thelia\Core\Event\Order\OrderManualEvent; use Thelia\Core\Event\Order\OrderPaymentEvent; +use Thelia\Core\Event\Payment\ManageStockOnCreationEvent; use Thelia\Core\Event\Product\VirtualProductOrderHandleEvent; use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Security\SecurityContext; @@ -45,6 +47,7 @@ use Thelia\Model\ProductSaleElements; use Thelia\Model\ProductSaleElementsQuery; use Thelia\Model\TaxRuleI18n; +use Thelia\Module\PaymentModuleInterface; use Thelia\Tools\I18n; /** @@ -397,7 +400,10 @@ public function createManual(OrderManualEvent $event, $eventName, EventDispatche $event->getLang(), $event->getCart(), $event->getCustomer(), - $paymentModuleInstance->manageStockOnCreation(), + $this->isModuleManageStockOnCreation( + $dispatcher, + $paymentModuleInstance + ), $event->getUseOrderDefinedAddresses() ) ); @@ -429,7 +435,10 @@ public function create(OrderEvent $event, $eventName, EventDispatcherInterface $ $session->getLang(), $session->getSessionCart($dispatcher), $this->securityContext->getCustomerUser(), - $paymentModuleInstance->manageStockOnCreation() + $this->isModuleManageStockOnCreation( + $dispatcher, + $paymentModuleInstance + ) ); $dispatcher->dispatch(TheliaEvents::ORDER_BEFORE_PAYMENT, new OrderEvent($placedOrder)); @@ -514,12 +523,20 @@ public function sendNotificationEmail(OrderEvent $event) /** * @param OrderEvent $event */ - public function updateStatus(OrderEvent $event) + public function updateStatus(OrderEvent $event, $eventName, EventDispatcherInterface $dispatcher) { $order = $event->getOrder(); $newStatus = $event->getStatus(); + $paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId()); + /** @var PaymentModuleInterface $paymentModuleInstance */ + $paymentModuleInstance = $paymentModule->createInstance(); - $this->updateQuantity($order, $newStatus); + $manageStockOnCreation = $this->isModuleManageStockOnCreation( + $dispatcher, + $paymentModuleInstance + ); + + $this->updateQuantity($order, $newStatus, $manageStockOnCreation); $order->setStatusId($newStatus); $order->save(); @@ -532,14 +549,14 @@ public function updateStatus(OrderEvent $event) * @param $newStatus $newStatus the new status ID * @throws \Thelia\Exception\TheliaProcessException */ - public function updateQuantity(ModelOrder $order, $newStatus) + public function updateQuantity(ModelOrder $order, $newStatus, $manageStockOnCreation = true) { $canceledStatus = OrderStatusQuery::getCancelledStatus()->getId(); $paidStatus = OrderStatusQuery::getPaidStatus()->getId(); if ($newStatus == $canceledStatus || $order->isCancelled()) { $this->updateQuantityForCanceledOrder($order, $newStatus, $canceledStatus); } elseif ($paidStatus == $newStatus && $order->isNotPaid() && $order->getVersion() == 1) { - $this->updateQuantityForPaidOrder($order); + $this->updateQuantityForPaidOrder($order, $manageStockOnCreation); } } @@ -548,14 +565,14 @@ public function updateQuantity(ModelOrder $order, $newStatus) * @throws \Exception * @throws \Propel\Runtime\Exception\PropelException */ - protected function updateQuantityForPaidOrder(ModelOrder $order) + protected function updateQuantityForPaidOrder(ModelOrder $order, $manageStockOnCreation) { $paymentModule = ModuleQuery::create()->findPk($order->getPaymentModuleId()); /** @var \Thelia\Module\PaymentModuleInterface $paymentModuleInstance */ $paymentModuleInstance = $paymentModule->createInstance(); - if (false === $paymentModuleInstance->manageStockOnCreation()) { + if (false === $manageStockOnCreation) { $orderProductList = $order->getOrderProducts(); /** @var OrderProduct $orderProduct */ @@ -652,6 +669,29 @@ public function updateAddress(OrderAddressEvent $event) $event->setOrderAddress($orderAddress); } + /** + * Check if a payment module manage stock on creation + * + * @param EventDispatcher $dispatcher + * @param PaymentModuleInterface $module + * @return bool if the module manage stock on creation, false otherwise + */ + protected function isModuleManageStockOnCreation(EventDispatcherInterface $dispatcher, PaymentModuleInterface $module) + { + $event = new ManageStockOnCreationEvent($module); + + $dispatcher->dispatch( + TheliaEvents::getModuleEvent( + TheliaEvents::MODULE_PAYMENT_MANAGE_STOCK, + $module->getCode() + ) + ); + + return (null !== $event->getManageStock()) + ? $event->getManageStock() + : $module->manageStockOnCreation(); + } + /** * {@inheritdoc} */ diff --git a/core/lib/Thelia/Action/Payment.php b/core/lib/Thelia/Action/Payment.php new file mode 100644 index 0000000000..19f109f44a --- /dev/null +++ b/core/lib/Thelia/Action/Payment.php @@ -0,0 +1,63 @@ + + */ +class Payment implements EventSubscriberInterface +{ + /** + * Check if a module is valid + * + * @param IsValidPaymentEvent $event + */ + public function isValid(IsValidPaymentEvent $event, $eventName, EventDispatcherInterface $dispatcher) + { + $module = $event->getModule(); + + // dispatch event to target specific module + $dispatcher->dispatch( + TheliaEvents::getModuleEvent( + TheliaEvents::MODULE_PAYMENT_IS_VALID, + $module->getCode() + ), + $event + ); + + if ($event->isPropagationStopped()) { + return; + } + + // call legacy module method + $event->setValidModule($module->isValidPayment()); + } + + /** + * @inheritdoc + */ + public static function getSubscribedEvents() + { + return [ + TheliaEvents::MODULE_PAYMENT_IS_VALID => ['isValid', 128], + ]; + } +} diff --git a/core/lib/Thelia/Config/Resources/action.xml b/core/lib/Thelia/Config/Resources/action.xml index 56fdc048f8..92ea7319d4 100644 --- a/core/lib/Thelia/Config/Resources/action.xml +++ b/core/lib/Thelia/Config/Resources/action.xml @@ -225,6 +225,14 @@ + + + + + + + + diff --git a/core/lib/Thelia/Core/Event/Delivery/DeliveryPostageEvent.php b/core/lib/Thelia/Core/Event/Delivery/DeliveryPostageEvent.php new file mode 100644 index 0000000000..a95afbf146 --- /dev/null +++ b/core/lib/Thelia/Core/Event/Delivery/DeliveryPostageEvent.php @@ -0,0 +1,234 @@ + + */ +class DeliveryPostageEvent extends ActionEvent +{ + /** @var DeliveryModuleInterface */ + protected $module = null; + + /** @var Cart */ + protected $cart = null; + + /** @var Address */ + protected $address = null; + + /** @var Country */ + protected $country = null; + + /** @var State */ + protected $state = null; + + /** @var bool */ + protected $validModule = false; + + /** @var OrderPostage|null */ + protected $postage = null; + + /** @var \DateTime|null */ + protected $deliveryDate = null; + + /** @var array */ + protected $additionalData = []; + + /** + * DeliveryPostageEvent constructor. + * @param DeliveryModuleInterface $module + * @param Country $country + * @param Cart $cart + * @param State $state + */ + public function __construct( + DeliveryModuleInterface $module, + Cart $cart, + Address $address = null, + Country $country = null, + State $state = null + ) { + $this->module = $module; + $this->cart = $cart; + $this->address = $address; + $this->country = $country; + $this->state = $state; + } + + /** + * @return Cart + */ + public function getCart() + { + return $this->cart; + } + + /** + * @param Cart $cart + */ + public function setCart($cart) + { + $this->cart = $cart; + return $this; + } + + /** + * @return Address + */ + public function getAddress() + { + return $this->address; + } + + /** + * @param Address $address + */ + public function setAddress($address) + { + $this->address = $address; + return $this; + } + + /** + * @return \DateTime|null + */ + public function getDeliveryDate() + { + return $this->deliveryDate; + } + + /** + * @param \DateTime|null $deliveryDate + */ + public function setDeliveryDate($deliveryDate) + { + $this->deliveryDate = $deliveryDate; + return $this; + } + + /** + * @return DeliveryModuleInterface + */ + public function getModule() + { + return $this->module; + } + + /** + * @param DeliveryModuleInterface $module + */ + public function setModule($module) + { + $this->module = $module; + return $this; + } + + /** + * @return null|OrderPostage + */ + public function getPostage() + { + return $this->postage; + } + + /** + * @param null|double|OrderPostage $postage + */ + public function setPostage($postage) + { + $this->postage = OrderPostage::loadFromPostage($postage); + return $this; + } + + /** + * @return boolean + */ + public function isValidModule() + { + return $this->validModule; + } + + /** + * @param boolean $validModule + */ + public function setValidModule($validModule) + { + $this->validModule = $validModule; + return $this; + } + + /** + * @return bool + */ + public function hasAdditionalData() + { + return count($this->additionalData) > 0; + } + + /** + * @return array + */ + public function getAdditionalData() + { + return $this->additionalData; + } + + /** + * @param array $additionalData + */ + public function setAdditionalData($additionalData) + { + $this->additionalData = $additionalData; + return $this; + } + + /** + * @param string $key the key of the additional data + * @param mixed $value the value of the additional data + * + * return $this + */ + public function addAdditionalData($key, $value) + { + $this->additionalData[$key] = $value; + + return $this; + } + + /** + * @return Country|null + */ + public function getCountry() + { + return $this->getAddress() !== null ? $this->getAddress()->getCountry() : $this->country; + } + + /** + * @return State|null + */ + public function getState() + { + return $this->getAddress() !== null ? $this->getAddress()->getState() : $this->state; + } +} diff --git a/core/lib/Thelia/Core/Event/Payment/BasePaymentEvent.php b/core/lib/Thelia/Core/Event/Payment/BasePaymentEvent.php new file mode 100644 index 0000000000..b19bc6693e --- /dev/null +++ b/core/lib/Thelia/Core/Event/Payment/BasePaymentEvent.php @@ -0,0 +1,54 @@ + + */ +class BasePaymentEvent extends ActionEvent +{ + /** @var PaymentModuleInterface */ + protected $module = null; + + /** + * BasePaymentEvent constructor. + * @param PaymentModuleInterface $module + */ + public function __construct(PaymentModuleInterface $module) + { + $this->module = $module; + } + + /** + * @return PaymentModuleInterface + */ + public function getModule() + { + return $this->module; + } + + /** + * @param PaymentModuleInterface $module + */ + public function setModule($module) + { + $this->module = $module; + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/Payment/IsValidPaymentEvent.php b/core/lib/Thelia/Core/Event/Payment/IsValidPaymentEvent.php new file mode 100644 index 0000000000..e7a6802ceb --- /dev/null +++ b/core/lib/Thelia/Core/Event/Payment/IsValidPaymentEvent.php @@ -0,0 +1,77 @@ + + */ +class IsValidPaymentEvent extends BasePaymentEvent +{ + /** @var Cart */ + protected $cart = null; + + /** @var bool */ + protected $validModule = false; + + /** + * IsValidPaymentEvent constructor. + * + * @param PaymentModuleInterface $module + * @param Cart $cart + */ + public function __construct(PaymentModuleInterface $module, Cart $cart) + { + parent::__construct($module); + $this->cart = $cart; + } + + /** + * @return Cart + */ + public function getCart() + { + return $this->cart; + } + + /** + * @param Cart $cart + */ + public function setCart($cart) + { + $this->cart = $cart; + return $this; + } + + /** + * @return boolean + */ + public function isValidModule() + { + return $this->validModule; + } + + /** + * @param boolean $validModule + */ + public function setValidModule($validModule) + { + $this->validModule = $validModule; + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/Payment/ManageStockOnCreationEvent.php b/core/lib/Thelia/Core/Event/Payment/ManageStockOnCreationEvent.php new file mode 100644 index 0000000000..c43fd8f9c2 --- /dev/null +++ b/core/lib/Thelia/Core/Event/Payment/ManageStockOnCreationEvent.php @@ -0,0 +1,53 @@ + + */ +class ManageStockOnCreationEvent extends BasePaymentEvent +{ + /** @var bool|null */ + protected $manageStock = null; + + /** + * ManageStockOnCreationEvent constructor. + * @param bool|null $manageStock + */ + public function __construct(PaymentModuleInterface $module) + { + parent::__construct($module); + } + + /** + * @return bool|null + */ + public function getManageStock() + { + return $this->manageStock; + } + + /** + * @param bool|null $manageStock + */ + public function setManageStock($manageStock) + { + $this->manageStock = $manageStock; + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 88bbe926a1..28439ab15e 100644 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -813,9 +813,26 @@ public static function getLoopExtendsEvent($eventName, $loopName) const MODULE_DELETE = 'thelia.module.delete'; const MODULE_INSTALL = 'thelia.module.install'; - /* Invoke payment module */ + /** + * Generate the event name for a specific module + * + * @param string $eventName the event name + * @param string $moduleCode the module code + * + * @return string the event name for the module + */ + public static function getModuleEvent($eventName, $moduleCode) + { + return sprintf("%s.%s", $eventName, strtolower($moduleCode)); + } + /* Payment module */ const MODULE_PAY = 'thelia.module.pay'; + const MODULE_PAYMENT_IS_VALID = 'thelia.module.payment.is_valid'; + const MODULE_PAYMENT_MANAGE_STOCK = 'thelia.module.payment.manage_stock'; + + /* Delivery module */ + const MODULE_DELIVERY_GET_POSTAGE = 'thelia.module.delivery.postage'; /** * Hook diff --git a/core/lib/Thelia/Core/Template/Loop/Delivery.php b/core/lib/Thelia/Core/Template/Loop/Delivery.php index 883454fe1b..26a249e5d9 100644 --- a/core/lib/Thelia/Core/Template/Loop/Delivery.php +++ b/core/lib/Thelia/Core/Template/Loop/Delivery.php @@ -12,13 +12,16 @@ namespace Thelia\Core\Template\Loop; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; +use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Template\Element\LoopResult; use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Model\AddressQuery; use Thelia\Model\AreaDeliveryModuleQuery; +use Thelia\Model\Cart; use Thelia\Model\CountryQuery; use Thelia\Model\Module; -use Thelia\Model\OrderPostage; use Thelia\Model\StateQuery; use Thelia\Module\BaseModule; use Thelia\Module\DeliveryModuleInterface; @@ -31,8 +34,11 @@ * @author Etienne Roudeix * * {@inheritdoc} + * + * @method int getAddress() * @method int getCountry() * @method int getState() + * */ class Delivery extends BaseSpecificModule { @@ -41,6 +47,7 @@ public function getArgDefinitions() $collection = parent::getArgDefinitions(); $collection + ->addArgument(Argument::createIntTypeArgument("address")) ->addArgument(Argument::createIntTypeArgument("country")) ->addArgument(Argument::createIntTypeArgument("state")) ; @@ -50,9 +57,19 @@ public function getArgDefinitions() public function parseResults(LoopResult $loopResult) { - $country = $this->getCurrentCountry(); - $state = $this->getCurrentState(); $cart = $this->request->getSession()->getSessionCart($this->dispatcher); + $address = $this->getDeliveryAddress(); + + // todo: remove country and state. just here for backward compatibility + $country = $this->getCurrentCountry($address); + if (null === $country) { + $country = $address->getCountry(); + } + $state = $this->getCurrentState($address); + if (null === $state) { + $country = $address->getCountry(); + } + $virtual = $cart->isVirtual(); /** @var Module $deliveryModule */ @@ -63,7 +80,6 @@ public function parseResults(LoopResult $loopResult) if (null === $areaDeliveryModule && false === $virtual) { continue; - } /** @var DeliveryModuleInterface $moduleInstance */ @@ -81,9 +97,17 @@ public function parseResults(LoopResult $loopResult) try { // Check if module is valid, by calling isValidDelivery(), // or catching a DeliveryException. + /** @var Cart $cart */ + $cart->getAddressDeliveryId(); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $address, $country, $state); + $this->dispatcher->dispatch( + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE, + $deliveryPostageEvent + ); + + if ($deliveryPostageEvent->isValidModule()) { - if ($moduleInstance->isValidDelivery($country)) { - $postage = OrderPostage::loadFromPostage($moduleInstance->getPostage($country)); + $postage = $deliveryPostageEvent->getPostage(); $loopResultRow ->set('ID', $deliveryModule->getId()) @@ -96,7 +120,16 @@ public function parseResults(LoopResult $loopResult) ->set('POSTAGE_TAX', $postage->getAmountTax()) ->set('POSTAGE_UNTAXED', $postage->getAmount() - $postage->getAmountTax()) ->set('POSTAGE_TAX_RULE_TITLE', $postage->getTaxRuleTitle()) + ->set('DELIVERY_DATE', $deliveryPostageEvent->getDeliveryDate()) ; + + // add additional data if it exists + if ($deliveryPostageEvent->hasAdditionalData()) { + foreach ($deliveryPostageEvent->getAdditionalData() as $key => $value) { + $loopResultRow->set($key, $value); + } + } + $this->addOutputFields($loopResultRow, $deliveryModule); $loopResult->addRow($loopResultRow); @@ -126,10 +159,9 @@ protected function getCurrentCountry() throw new \InvalidArgumentException('Cannot found country id: `' . $countryId . '` in delivery loop'); } return $country; - } else { - $country = $this->container->get('thelia.taxEngine')->getDeliveryCountry(); - return $country; } + + return null; } /** @@ -144,9 +176,27 @@ protected function getCurrentState() throw new \InvalidArgumentException('Cannot found state id: `' . $stateId . '` in delivery loop'); } return $state; - } else { - $state = $this->container->get('thelia.taxEngine')->getDeliveryState(); - return $state; } + + return null; + } + + /** + * @return array|mixed|\Thelia\Model\Address + */ + protected function getDeliveryAddress() + { + $address = null; + + $addressId = $this->getAddress(); + if (empty($addressId)) { + $addressId = $this->request->getSession()->getOrder()->getChoosenDeliveryAddress(); + } + + if (!empty($addressId)) { + $address = AddressQuery::create()->findPk($addressId); + } + + return $address; } } diff --git a/core/lib/Thelia/Core/Template/Loop/Payment.php b/core/lib/Thelia/Core/Template/Loop/Payment.php index e5d53ab68a..630e03a2c8 100644 --- a/core/lib/Thelia/Core/Template/Loop/Payment.php +++ b/core/lib/Thelia/Core/Template/Loop/Payment.php @@ -12,6 +12,8 @@ namespace Thelia\Core\Template\Loop; +use Thelia\Core\Event\Payment\IsValidPaymentEvent; +use Thelia\Core\Event\TheliaEvents; use Thelia\Core\Template\Element\LoopResult; use Thelia\Core\Template\Element\LoopResultRow; use Thelia\Core\Template\Element\PropelSearchLoopInterface; @@ -34,13 +36,21 @@ public function getArgDefinitions() public function parseResults(LoopResult $loopResult) { + $cart = $this->request->getSession()->getSessionCart($this->dispatcher); + /** @var \Thelia\Model\Module $paymentModule */ foreach ($loopResult->getResultDataCollection() as $paymentModule) { $loopResultRow = new LoopResultRow($paymentModule); $moduleInstance = $paymentModule->getPaymentModuleInstance($this->container); - if (false === $moduleInstance->isValidPayment()) { + $isValidPaymentEvent = new IsValidPaymentEvent($moduleInstance, $cart); + $this->dispatcher->dispatch( + TheliaEvents::MODULE_PAYMENT_IS_VALID, + $isValidPaymentEvent + ); + + if (false === $isValidPaymentEvent->isValidModule()) { continue; } diff --git a/core/lib/Thelia/Module/BaseModule.php b/core/lib/Thelia/Module/BaseModule.php index cb864e3e8d..bfd8e1a245 100644 --- a/core/lib/Thelia/Module/BaseModule.php +++ b/core/lib/Thelia/Module/BaseModule.php @@ -184,10 +184,7 @@ public function getDispatcher() } /** - * Sets a module titles for various languages - * - * @param Module $module the module. - * @param array $titles an associative array of locale => title_string + * @inheritdoc */ public function setTitle(Module $module, $titles) { @@ -214,12 +211,7 @@ public function setTitle(Module $module, $titles) } /** - * Get a module's configuration variable - * - * @param string $variableName the variable name - * @param string $defaultValue the default value, if variable is not defined - * @param null $valueLocale the required locale, or null to get default one - * @return string the variable value + * @inheritdoc */ public static function getConfigValue($variableName, $defaultValue = null, $valueLocale = null) { @@ -228,14 +220,7 @@ public static function getConfigValue($variableName, $defaultValue = null, $valu } /** - * Set module configuration variable, creating it if required - * - * @param string $variableName the variable name - * @param string $variableValue the variable value - * @param null $valueLocale the locale, or null if not required - * @param bool $createIfNotExists if true, the variable will be created if not already defined - * @throws \LogicException if variable does not exists and $createIfNotExists is false - * @return $this; + * @inheritdoc */ public static function setConfigValue($variableName, $variableValue, $valueLocale = null, $createIfNotExists = true) { @@ -244,17 +229,7 @@ public static function setConfigValue($variableName, $variableValue, $valueLocal } /** - * Ensure the proper deployment of the module's images. - * - * TODO : this method does not take care of internationalization. This is a bug. - * - * @param Module $module the module - * @param string $folderPath the image folder path - * @param ConnectionInterface $con - * - * @throws \Thelia\Exception\ModuleException - * @throws \Exception - * @throws \UnexpectedValueException + * @inheritdoc */ public function deployImageFolder(Module $module, $folderPath, ConnectionInterface $con = null) { @@ -333,8 +308,7 @@ public function deployImageFolder(Module $module, $folderPath, ConnectionInterfa } /** - * @return Module - * @throws \Thelia\Exception\ModuleException + * @inheritdoc */ public function getModuleModel() { @@ -361,6 +335,9 @@ public function getModuleModel() */ private static $moduleIds = []; + /** + * @inheritdoc + */ public static function getModuleId() { $code = self::getModuleCode(); @@ -380,7 +357,7 @@ public static function getModuleId() } /** - * @return string The module code, in a static wayord + * @inheritdoc */ public static function getModuleCode() { @@ -466,40 +443,7 @@ public function getCurrentOrderTotalAmount($with_tax = true, $with_discount = tr } /** - * - * This method adds new compilers to Thelia container - * - * You must return an array. This array can contain : - * - arrays - * - one or many instance(s) of \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface - * - * in the first case, your array must contains 2 indexes. - * The first is the compiler instance and the second the compilerPass type. - * Example : - * return array( - * array( - * new \MyModule\DependencyInjection\Compiler\MySuperCompilerPass(), - * \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION - * ) - * ); - * - * In the seconde case, just an instance of CompilerPassInterface. - * Example : - * return array ( - * new \MyModule\DependencyInjection\Compiler\MySuperCompilerPass() - * ); - * - * But you can combine both behaviors - * Example : - * - * return array( - * new \MyModule\DependencyInjection\Compiler\MySuperCompilerPass(), - * array( - * new \MyModule\DependencyInjection\Compiler\MyOtherSuperCompilerPass(), - * Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION - * ) - * ); - * + * @inheritdoc */ public static function getCompilers() { @@ -507,9 +451,7 @@ public static function getCompilers() } /** - * This method is called when the plugin is installed for the first time - * - * @param ConnectionInterface $con + * @inheritdoc */ public function install(ConnectionInterface $con = null) { @@ -517,11 +459,7 @@ public function install(ConnectionInterface $con = null) } /** - * This method is called when a newer version of the plugin is installed - * - * @param string $currentVersion the current (installed) module version, as defined in the module.xml file - * @param string $newVersion the new module version, as defined in the module.xml file - * @param ConnectionInterface $con + * @inheritdoc */ public function update($currentVersion, $newVersion, ConnectionInterface $con = null) { @@ -529,11 +467,7 @@ public function update($currentVersion, $newVersion, ConnectionInterface $con = } /** - * This method is called before the module activation, and may prevent it by returning false. - * - * @param ConnectionInterface $con - * - * @return bool true to continue module activation, false to prevent it. + * @inheritdoc */ public function preActivation(ConnectionInterface $con = null) { @@ -542,9 +476,7 @@ public function preActivation(ConnectionInterface $con = null) } /** - * This method is called just after the module was successfully activated. - * - * @param ConnectionInterface $con + * @inheritdoc */ public function postActivation(ConnectionInterface $con = null) { @@ -552,10 +484,7 @@ public function postActivation(ConnectionInterface $con = null) } /** - * This method is called before the module de-activation, and may prevent it by returning false. - * - * @param ConnectionInterface $con - * @return bool true to continue module de-activation, false to prevent it. + * @inheritdoc */ public function preDeactivation(ConnectionInterface $con = null) { @@ -563,17 +492,16 @@ public function preDeactivation(ConnectionInterface $con = null) return true; } + /** + * @inheritdoc + */ public function postDeactivation(ConnectionInterface $con = null) { // Override this method to do something useful. } /** - * This method is called just before the deletion of the module, giving the module an opportunity - * to delete its data. - * - * @param ConnectionInterface $con - * @param bool $deleteModuleData if true, the module should remove all its data from the system. + * @inheritdoc */ public function destroy(ConnectionInterface $con = null, $deleteModuleData = false) { @@ -581,51 +509,16 @@ public function destroy(ConnectionInterface $con = null, $deleteModuleData = fal } /** - * @return array - * - * This method must be used when your module defines hooks. - * Override this and return an array of your hooks names to register them - * - * This returned value must be like the example, only type and code are mandatory - * - * Example: - * - * return array( - * - * // Only register the title in the default language - * array( - * "type" => TemplateDefinition::BACK_OFFICE, - * "code" => "my_super_hook_name", - * "title" => "My hook", - * "description" => "My hook is really, really great", - * ), - * - * // Manage i18n - * array( - * "type" => TemplateDefinition::FRONT_OFFICE, - * "code" => "my_hook_name", - * "title" => array( - * "fr_FR" => "Mon Hook", - * "en_US" => "My hook", - * ), - * "description" => array( - * "fr_FR" => "Mon hook est vraiment super", - * "en_US" => "My hook is really, really great", - * ), - * "chapo" => array( - * "fr_FR" => "Mon hook est vraiment super", - * "en_US" => "My hook is really, really great", - * ), - * "block" => true, - * "active" => true - * ) - * ); + * @inheritdoc */ public function getHooks() { return array(); } + /** + * @inheritdoc + */ public function registerHooks() { $moduleHooks = $this->getHooks(); diff --git a/core/lib/Thelia/Module/BaseModuleInterface.php b/core/lib/Thelia/Module/BaseModuleInterface.php index 9c2caccdcf..ffd60bdc0b 100644 --- a/core/lib/Thelia/Module/BaseModuleInterface.php +++ b/core/lib/Thelia/Module/BaseModuleInterface.php @@ -13,20 +13,239 @@ namespace Thelia\Module; use Propel\Runtime\Connection\ConnectionInterface; +use Thelia\Model\Module; interface BaseModuleInterface { + /** + * This method is called when the plugin is installed for the first time + * + * @param ConnectionInterface $con + */ public function install(ConnectionInterface $con = null); + /** + * This method is called when a newer version of the plugin is installed + * + * @param string $currentVersion the current (installed) module version, as defined in the module.xml file + * @param string $newVersion the new module version, as defined in the module.xml file + * @param ConnectionInterface $con + */ + public function update($currentVersion, $newVersion, ConnectionInterface $con = null); + + + /** + * This method is called just before the deletion of the module, giving the module an opportunity + * to delete its data. + * + * @param ConnectionInterface $con + * @param bool $deleteModuleData if true, the module should remove all its data from the system. + */ + public function destroy(ConnectionInterface $con = null, $deleteModuleData = false); + + /** + * This method is called when the module is activated + * + * @param Module $moduleModel the module + */ + public function activate($moduleModel = null); + + /** + * This method is called when the module is deactivated + * + * @param Module $moduleModel the module + */ + public function deActivate($moduleModel = null); + + + /** + * This method is called before the module activation, and may prevent it by returning false. + * + * @param ConnectionInterface $con + * + * @return bool true to continue module activation, false to prevent it. + */ public function preActivation(ConnectionInterface $con = null); + /** + * This method is called just after the module was successfully activated. + * + * @param ConnectionInterface $con + */ public function postActivation(ConnectionInterface $con = null); + /** + * This method is called before the module de-activation, and may prevent it by returning false. + * + * @param ConnectionInterface $con + * @return bool true to continue module de-activation, false to prevent it. + */ public function preDeactivation(ConnectionInterface $con = null); + /** + * This method is called just after the module was successfully deactivated. + * + * @param ConnectionInterface $con + */ public function postDeactivation(ConnectionInterface $con = null); - public function update($currentVersion, $newVersion, ConnectionInterface $con = null); - public function destroy(ConnectionInterface $con = null, $deleteModuleData = false); + /** + * Sets a module titles for various languages + * + * @param Module $module the module. + * @param array $titles an associative array of locale => title_string + */ + public function setTitle(Module $module, $titles); + + /** + * Get a module's configuration variable + * + * @param string $variableName the variable name + * @param string $defaultValue the default value, if variable is not defined + * @param null $valueLocale the required locale, or null to get default one + * @return string the variable value + */ + public static function getConfigValue($variableName, $defaultValue = null, $valueLocale = null); + + /** + * Set module configuration variable, creating it if required + * + * @param string $variableName the variable name + * @param string $variableValue the variable value + * @param null $valueLocale the locale, or null if not required + * @param bool $createIfNotExists if true, the variable will be created if not already defined + * @throws \LogicException if variable does not exists and $createIfNotExists is false + * @return $this; + */ + public static function setConfigValue( + $variableName, + $variableValue, + $valueLocale = null, + $createIfNotExists = true + ); + + /** + * Ensure the proper deployment of the module's images. + * + * TODO : this method does not take care of internationalization. This is a bug. + * + * @param Module $module the module + * @param string $folderPath the image folder path + * @param ConnectionInterface $con + * + * @throws \Thelia\Exception\ModuleException + * @throws \Exception + * @throws \UnexpectedValueException + */ + public function deployImageFolder(Module $module, $folderPath, ConnectionInterface $con = null); + + /** + * @return Module + * @throws \Thelia\Exception\ModuleException + */ + public function getModuleModel(); + + /** + * @return string The module id + */ + public static function getModuleId(); + + /** + * @return string The module code, in a static way + */ + public static function getModuleCode(); + + /** + * @return string The module code + */ + public function getCode(); + + /** + * + * This method adds new compilers to Thelia container + * + * You must return an array. This array can contain : + * - arrays + * - one or many instance(s) of \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface + * + * in the first case, your array must contains 2 indexes. + * The first is the compiler instance and the second the compilerPass type. + * Example : + * return array( + * array( + * new \MyModule\DependencyInjection\Compiler\MySuperCompilerPass(), + * \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION + * ) + * ); + * + * In the seconde case, just an instance of CompilerPassInterface. + * Example : + * return array ( + * new \MyModule\DependencyInjection\Compiler\MySuperCompilerPass() + * ); + * + * But you can combine both behaviors + * Example : + * + * return array( + * new \MyModule\DependencyInjection\Compiler\MySuperCompilerPass(), + * array( + * new \MyModule\DependencyInjection\Compiler\MyOtherSuperCompilerPass(), + * Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION + * ) + * ); + * + */ + public static function getCompilers(); + + + /** + * @return array + * + * This method must be used when your module defines hooks. + * Override this and return an array of your hooks names to register them + * + * This returned value must be like the example, only type and code are mandatory + * + * Example: + * + * return array( + * + * // Only register the title in the default language + * array( + * "type" => TemplateDefinition::BACK_OFFICE, + * "code" => "my_super_hook_name", + * "title" => "My hook", + * "description" => "My hook is really, really great", + * ), + * + * // Manage i18n + * array( + * "type" => TemplateDefinition::FRONT_OFFICE, + * "code" => "my_hook_name", + * "title" => array( + * "fr_FR" => "Mon Hook", + * "en_US" => "My hook", + * ), + * "description" => array( + * "fr_FR" => "Mon hook est vraiment super", + * "en_US" => "My hook is really, really great", + * ), + * "chapo" => array( + * "fr_FR" => "Mon hook est vraiment super", + * "en_US" => "My hook is really, really great", + * ), + * "block" => true, + * "active" => true + * ) + * ); + */ + public function getHooks(); + + /** + * Create or update module hooks returned by the `getHooks` function + */ + public function registerHooks(); + } diff --git a/local/modules/Front/Controller/OrderController.php b/local/modules/Front/Controller/OrderController.php index a3904596c0..68eaa4531a 100644 --- a/local/modules/Front/Controller/OrderController.php +++ b/local/modules/Front/Controller/OrderController.php @@ -25,6 +25,7 @@ use Front\Front; use Propel\Runtime\ActiveQuery\Criteria; use Propel\Runtime\Exception\PropelException; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; use Thelia\Core\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Thelia\Controller\Front\BaseFrontController; @@ -46,6 +47,7 @@ use Thelia\Model\OrderProductQuery; use Thelia\Model\OrderQuery; use Thelia\Module\AbstractDeliveryModule; +use Thelia\Module\Exception\DeliveryException; /** * Class OrderController @@ -65,15 +67,9 @@ public function deliverView() // check if the cart contains only virtual products $cart = $this->getSession()->getSessionCart($this->getDispatcher()); - if ($cart->isVirtual()) { - // get the virtual product module - $customer = $this->getSecurityContext()->getCustomerUser(); - - $deliveryAddress = AddressQuery::create() - ->filterByCustomerId($customer->getId()) - ->orderByIsDefault(Criteria::DESC) - ->findOne(); + $deliveryAddress = $this->getCustomerAddress(); + if ($cart->isVirtual()) { if (null !== $deliveryAddress) { $deliveryModule = ModuleQuery::create()->retrieveVirtualProductDelivery($this->container); @@ -91,7 +87,12 @@ public function deliverView() } } - return $this->render('order-delivery'); + return $this->render( + 'order-delivery', + [ + 'delivery_address_id' => (null !== $deliveryAddress) ? $deliveryAddress->getId() : null + ] + ); } /** @@ -103,10 +104,16 @@ private function registerVirtualProductDelivery($moduleInstance, $deliveryAddres { /* get postage amount */ $deliveryModule = $moduleInstance->getModuleModel(); - $postage = OrderPostage::loadFromPostage( - $moduleInstance->getPostage($deliveryAddress->getCountry()) + $cart = $this->getSession()->getSessionCart($this->getDispatcher()); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress); + + $this->getDispatcher()->dispatch( + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE, + $deliveryPostageEvent ); + $postage = $deliveryPostageEvent->getPostage(); + $orderEvent = $this->getOrderEvent(); $orderEvent->setDeliveryAddress($deliveryAddress->getId()); $orderEvent->setDeliveryModule($deliveryModule->getId()); @@ -170,10 +177,22 @@ public function deliver() /* get postage amount */ $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); - $postage = OrderPostage::loadFromPostage( - $moduleInstance->getPostage($deliveryAddress->getCountry()) + $cart = $this->getSession()->getSessionCart($this->getDispatcher()); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $deliveryAddress); + + $this->getDispatcher()->dispatch( + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE, + $deliveryPostageEvent ); + if (!$deliveryPostageEvent->isValidModule() || null === $deliveryPostageEvent->getPostage()) { + throw new DeliveryException( + $this->getTranslator()->trans('The delivery module is not valid.', [], Front::MESSAGE_DOMAIN) + ); + } + + $postage = $deliveryPostageEvent->getPostage(); + $orderEvent = $this->getOrderEvent(); $orderEvent->setDeliveryAddress($deliveryAddressId); $orderEvent->setDeliveryModule($deliveryModuleId); @@ -181,7 +200,6 @@ public function deliver() $orderEvent->setPostageTax($postage->getAmountTax()); $orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle()); - $this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_DELIVERY_ADDRESS, $orderEvent); $this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_DELIVERY_MODULE, $orderEvent); $this->getDispatcher()->dispatch(TheliaEvents::ORDER_SET_POSTAGE, $orderEvent); @@ -506,6 +524,7 @@ public function getDeliveryModuleListAjaxAction() $this->checkXmlHttpRequest(); // Change the delivery address if customer has changed it + $address = null; $session = $this->getSession(); $addressId = $this->getRequest()->get('address_id', null); if (null !== $addressId && $addressId !== $session->getOrder()->getChoosenDeliveryAddress()) { @@ -515,17 +534,10 @@ public function getDeliveryModuleListAjaxAction() } } - // seems to be not necessary anymore since we have the new adress selected. - // keep for compatibility with old template - // TODO remove in version 2.3 - $countryId = $this->getRequest()->get( - 'country_id', - $this->container->get('thelia.taxEngine')->getDeliveryCountry()->getId() - ); + $address = AddressQuery::create()->findPk($session->getOrder()->getChoosenDeliveryAddress()); - $state = $this->container->get('thelia.taxEngine')->getDeliveryState(); - $stateId = ($state !== null) ? $state->getId() : null; - $stateId = $this->getRequest()->get('state_id', $stateId); + $countryId = $address->getCountryId(); + $stateId = $address->getStateId(); $args = array( 'country' => $countryId, @@ -553,4 +565,33 @@ private function checkStockNotEmpty() return null; } } + + /** + * Retrieve the chosen delivery address for a cart or the default customer address if not exists + * + * @return null|Address + */ + protected function getCustomerAddress() + { + $deliveryAddress = null; + $addressId = $this->getSession()->getOrder()->getChoosenDeliveryAddress(); + if (null === $addressId) { + $customer = $this->getSecurityContext()->getCustomerUser(); + + $deliveryAddress = AddressQuery::create() + ->filterByCustomerId($customer->getId()) + ->orderByIsDefault(Criteria::DESC) + ->findOne(); + + if (null !== $deliveryAddress) { + $this->getSession()->getOrder()->setChoosenDeliveryAddress( + $deliveryAddress->getId() + ); + } + } else { + $deliveryAddress = AddressQuery::create()->findPk($addressId); + } + + return $deliveryAddress; + } } diff --git a/local/modules/TheliaSmarty/Template/Plugins/CartPostage.php b/local/modules/TheliaSmarty/Template/Plugins/CartPostage.php index c528a06184..7d02ceaffc 100644 --- a/local/modules/TheliaSmarty/Template/Plugins/CartPostage.php +++ b/local/modules/TheliaSmarty/Template/Plugins/CartPostage.php @@ -14,9 +14,10 @@ use Propel\Runtime\ActiveQuery\Criteria; use Symfony\Component\DependencyInjection\ContainerInterface; -use Thelia\Model\OrderPostage; -use TheliaSmarty\Template\AbstractSmartyPlugin; -use TheliaSmarty\Template\SmartyPluginDescriptor; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Thelia\Core\Event\Delivery\DeliveryPostageEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\Address; use Thelia\Model\AddressQuery; use Thelia\Model\ConfigQuery; use Thelia\Model\Country; @@ -26,6 +27,8 @@ use Thelia\Module\BaseModule; use Thelia\Module\DeliveryModuleInterface; use Thelia\Module\Exception\DeliveryException; +use TheliaSmarty\Template\AbstractSmartyPlugin; +use TheliaSmarty\Template\SmartyPluginDescriptor; /** * Class CartPostage @@ -36,13 +39,16 @@ class CartPostage extends AbstractSmartyPlugin /** @var \Thelia\Core\HttpFoundation\Request The Request */ protected $request; + /** @var EventDispatcherInterface */ + protected $dispatcher; + /** @var ContainerInterface Service Container */ protected $container = null; /** @var integer $countryId the id of country */ protected $countryId = null; - /** @var integer $deliveryId the id of the cheapest delivery */ + /** @var integer $deliveryId the id of the cheapest delivery */ protected $deliveryId = null; /** @var float $postage the postage amount with taxes */ @@ -65,32 +71,36 @@ public function __construct(ContainerInterface $container) $this->container = $container; $this->request = $container->get('request'); + + $this->dispatcher = $container->get('event_dispatcher'); } /** * Get postage amount for cart * - * @param array $params Block parameters - * @param mixed $content Block content + * @param array $params Block parameters + * @param mixed $content Block content * @param \Smarty_Internal_Template $template Template - * @param bool $repeat Control how many times + * @param bool $repeat Control how many times * the block is displayed * * @return mixed */ public function postage($params, $content, $template, &$repeat) { - if (! $repeat) { + if (!$repeat) { return (null !== $this->countryId) ? $content : ""; } $customer = $this->request->getSession()->getCustomerUser(); - $country = $this->getDeliveryCountry($customer); + /** @var Address $address */ + /** @var Country $country */ + list($address, $country, $state) = $this->getDeliveryInformation($customer); if (null !== $country) { $this->countryId = $country->getId(); // try to get the cheapest delivery for this country - $this->getCheapestDelivery($country); + $this->getCheapestDelivery($address, $country); } $template->assign('country_id', $this->countryId); @@ -115,8 +125,17 @@ public function postage($params, $content, $template, &$repeat) * @param \Thelia\Model\Customer $customer * @return \Thelia\Model\Country */ - protected function getDeliveryCountry(Customer $customer = null) + protected function getDeliveryInformation(Customer $customer = null) { + $address = null; + // get the selected delivery address + if (null !== $addressId = $this->request->getSession()->getOrder()->getChoosenDeliveryAddress()) { + if (null !== $address = AddressQuery::create()->findPk($addressId)) { + $this->isCustomizable = false; + return [$address, $address->getCountry(), null]; + } + } + // get country from customer addresses if (null !== $customer) { $address = AddressQuery::create() @@ -128,7 +147,7 @@ protected function getDeliveryCountry(Customer $customer = null) if (null !== $address) { $this->isCustomizable = false; - return $address->getCountry(); + return [$address, $address->getCountry(), null]; } } @@ -139,7 +158,7 @@ protected function getDeliveryCountry(Customer $customer = null) if (0 !== $cookieVal) { $country = CountryQuery::create()->findPk($cookieVal); if (null !== $country) { - return $country; + return [null, $country, null]; } } } @@ -148,39 +167,43 @@ protected function getDeliveryCountry(Customer $customer = null) try { $country = Country::getDefaultCountry(); - return $country; + return [null, $country, null]; } catch (\LogicException $e) { ; } - return null; + return [null, null, null]; } /** * Retrieve the cheapest delivery for country * - * @param \Thelia\Model\Country $country + * @param \Thelia\Model\Country $country * @return DeliveryModuleInterface */ - protected function getCheapestDelivery(Country $country) + protected function getCheapestDelivery(Address $address = null, Country $country = null) { + $cart = $this->request->getSession()->getSessionCart(); + $deliveryModules = ModuleQuery::create() ->filterByActivate(1) ->filterByType(BaseModule::DELIVERY_MODULE_TYPE, Criteria::EQUAL) - ->find(); - ; + ->find() + ;; /** @var \Thelia\Model\Module $deliveryModule */ foreach ($deliveryModules as $deliveryModule) { $moduleInstance = $deliveryModule->getDeliveryModuleInstance($this->container); try { - // Check if module is valid, by calling isValidDelivery(), - // or catching a DeliveryException. - if ($moduleInstance->isValidDelivery($country)) { - $postage = OrderPostage::loadFromPostage( - $moduleInstance->getPostage($country) - ); + $deliveryPostageEvent = new DeliveryPostageEvent($moduleInstance, $cart, $address, $country, $state); + $this->dispatcher->dispatch( + TheliaEvents::MODULE_DELIVERY_GET_POSTAGE, + $deliveryPostageEvent + ); + + if ($deliveryPostageEvent->isValidModule()) { + $postage = $deliveryPostageEvent->getPostage(); if (null === $this->postage || $this->postage > $postage->getAmount()) { $this->postage = $postage->getAmount(); diff --git a/templates/frontOffice/default/I18n/en_US.php b/templates/frontOffice/default/I18n/en_US.php index 54cab30831..d145a90a83 100755 --- a/templates/frontOffice/default/I18n/en_US.php +++ b/templates/frontOffice/default/I18n/en_US.php @@ -61,6 +61,7 @@ 'Currency' => 'Currency', 'Customer Number' => 'Customer Number', 'Date' => 'Date', + 'Delete' => 'Supprimer', 'Delivery' => 'Delivery', 'Delivery Information' => 'Delivery Information', 'Delivery Mode' => 'Delivery Mode', @@ -77,6 +78,7 @@ 'Edit' => 'Edit', 'Edit this address' => 'Edit this address', 'Estimated shipping ' => 'Estimated shipping ', + 'Expected delivery date: %delivery_date' => 'Date de livraison estimée :', 'Forgot your Password?' => 'Forgot your Password?', 'Free shipping' => 'Free shipping', 'From %price' => 'From %price', diff --git a/templates/frontOffice/default/ajax/order-delivery-module-list.html b/templates/frontOffice/default/ajax/order-delivery-module-list.html index d5347530d4..7b5793e3c6 100644 --- a/templates/frontOffice/default/ajax/order-delivery-module-list.html +++ b/templates/frontOffice/default/ajax/order-delivery-module-list.html @@ -6,10 +6,10 @@ {ifloop rel="deliveries"} - {loop type="delivery" name="deliveries" force_return="true" country=$country state=$state} + {loop type="delivery" name="deliveries" force_return="true" address=$address} {assign var="isDeliveryMethodChecked" value="0"} - + {hook name="order-delivery.extra" module="$ID"} {hook name="order-delivery.javascript" module="$ID"} + {/loop} {/ifloop} {elseloop rel="deliveries"}
{intl l="Sorry! We are not able to give you a delivery method for your order."}
{/elseloop} diff --git a/templates/frontOffice/default/cart.html b/templates/frontOffice/default/cart.html index 2deca1caf1..232a0b55cb 100644 --- a/templates/frontOffice/default/cart.html +++ b/templates/frontOffice/default/cart.html @@ -154,7 +154,7 @@

{/if} {if $delivery_id != 0 }
- {intl l="with:"} {loop type="delivery" name="deliveryLoop" id=$delivery_id}{$TITLE} {/loop} + {intl l="with:"} {loop type="module" name="deliveryLoop" id=$delivery_id}{$TITLE} {/loop}
{else}
diff --git a/templates/frontOffice/default/order-delivery.html b/templates/frontOffice/default/order-delivery.html index 591b016d9d..d2ca84ef14 100644 --- a/templates/frontOffice/default/order-delivery.html +++ b/templates/frontOffice/default/order-delivery.html @@ -58,7 +58,7 @@

{intl l="Billing and delivery"}

{if $value == $ID} {assign var="isDeliveryAddressChecked" value="1"} {/if} - {elseif $DEFAULT} + {elseif $delivery_address_id == $ID} {assign var="isDeliveryAddressChecked" value="1"} {/if}

diff --git a/tests/phpunit/Thelia/Tests/Action/OrderTest.php b/tests/phpunit/Thelia/Tests/Action/OrderTest.php index 2165ee62f2..f898b1baf4 100644 --- a/tests/phpunit/Thelia/Tests/Action/OrderTest.php +++ b/tests/phpunit/Thelia/Tests/Action/OrderTest.php @@ -515,7 +515,7 @@ public function testUpdateStatus(OrderModel $order) $this->orderEvent->setStatus($newStatus); $this->orderEvent->setOrder($order); - $this->orderAction->updateStatus($this->orderEvent); + $this->orderAction->updateStatus($this->orderEvent, null, $this->getMockEventDispatcher()); $this->assertEquals( $newStatus,
{form_field field='delivery-module'} @@ -26,6 +26,12 @@ {$TITLE}
{$DESCRIPTION nofilter} + {if $DELIVERY_DATE} +
+ + {intl l="Expected delivery date: %delivery_date" delivery_date={format_date date=$DELIVERY_DATE output="date"}} + + {/if}

{/form_field} @@ -38,13 +44,18 @@
- {format_money number=$POSTAGE} + {if $POSTAGE} + {format_money number=$POSTAGE} + {else} +   + {/if}