500 lines
17 KiB
PHP
500 lines
17 KiB
PHP
<?php
|
|
/*************************************************************************************/
|
|
/* This file is part of the Thelia package. */
|
|
/* */
|
|
/* Copyright (c) OpenStudio */
|
|
/* email : dev@thelia.net */
|
|
/* web : http://www.thelia.net */
|
|
/* */
|
|
/* For the full copyright and license information, please view the LICENSE.txt */
|
|
/* file that was distributed with this source code. */
|
|
/*************************************************************************************/
|
|
|
|
namespace Thelia\Action;
|
|
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
use Thelia\Cart\CartTrait;
|
|
use Thelia\Core\Event\Order\OrderAddressEvent;
|
|
use Thelia\Core\Event\Order\OrderEvent;
|
|
use Thelia\Core\Event\Order\OrderManualEvent;
|
|
use Thelia\Core\Event\Order\OrderPaymentEvent;
|
|
use Thelia\Core\Event\TheliaEvents;
|
|
use Thelia\Core\HttpFoundation\Request;
|
|
use Thelia\Core\Security\SecurityContext;
|
|
use Thelia\Core\Template\ParserInterface;
|
|
use Thelia\Exception\TheliaProcessException;
|
|
use Thelia\Mailer\MailerFactory;
|
|
use Thelia\Model\AddressQuery;
|
|
use Thelia\Model\Cart as CartModel;
|
|
use Thelia\Model\ConfigQuery;
|
|
use Thelia\Model\Currency as CurrencyModel;
|
|
use Thelia\Model\Customer as CustomerModel;
|
|
use Thelia\Model\Lang as LangModel;
|
|
use Thelia\Model\Map\OrderTableMap;
|
|
use Thelia\Model\MessageQuery;
|
|
use Thelia\Model\Order as ModelOrder;
|
|
use Thelia\Model\OrderAddress;
|
|
use Thelia\Model\OrderProduct;
|
|
use Thelia\Model\OrderProductAttributeCombination;
|
|
use Thelia\Model\OrderStatusQuery;
|
|
use Thelia\Tools\I18n;
|
|
|
|
/**
|
|
*
|
|
* Class Order
|
|
* @package Thelia\Action
|
|
* @author Etienne Roudeix <eroudeix@openstudio.fr>
|
|
*/
|
|
class Order extends BaseAction implements EventSubscriberInterface
|
|
{
|
|
use CartTrait;
|
|
|
|
/**
|
|
* @var \Thelia\Core\HttpFoundation\Request
|
|
*/
|
|
protected $request;
|
|
/**
|
|
* @var MailerFactory
|
|
*/
|
|
protected $mailer;
|
|
/**
|
|
* @var ParserInterface
|
|
*/
|
|
protected $parser;
|
|
/**
|
|
* @var SecurityContext
|
|
*/
|
|
protected $securityContext;
|
|
|
|
public function __construct(Request $request, ParserInterface $parser, MailerFactory $mailer, SecurityContext $securityContext)
|
|
{
|
|
$this->request = $request;
|
|
$this->parser = $parser;
|
|
$this->mailer = $mailer;
|
|
$this->securityContext = $securityContext;
|
|
}
|
|
|
|
/**
|
|
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
|
*/
|
|
public function setDeliveryAddress(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$order->chosenDeliveryAddress = $event->getDeliveryAddress();
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
/**
|
|
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
|
*/
|
|
public function setDeliveryModule(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$deliveryModuleId = $event->getDeliveryModule();
|
|
|
|
$order->setDeliveryModuleId($deliveryModuleId);
|
|
|
|
// Reset postage cost if the delivery module had been removed
|
|
if ($deliveryModuleId <= 0) {
|
|
$order->setPostage(0);
|
|
}
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
/**
|
|
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
|
*/
|
|
public function setPostage(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$order->setPostage($event->getPostage());
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
/**
|
|
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
|
*/
|
|
public function setInvoiceAddress(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$order->chosenInvoiceAddress = $event->getInvoiceAddress();
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
/**
|
|
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
|
*/
|
|
public function setPaymentModule(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$order->setPaymentModuleId($event->getPaymentModule());
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
protected function createOrder(EventDispatcherInterface $dispatcher, ModelOrder $sessionOrder, CurrencyModel $currency, LangModel $lang, CartModel $cart, CustomerModel $customer)
|
|
{
|
|
$con = \Propel\Runtime\Propel::getConnection(
|
|
OrderTableMap::DATABASE_NAME
|
|
);
|
|
|
|
$con->beginTransaction();
|
|
|
|
$placedOrder = $sessionOrder->copy();
|
|
$placedOrder->setDispatcher($dispatcher);
|
|
|
|
$deliveryAddress = AddressQuery::create()->findPk($sessionOrder->chosenDeliveryAddress);
|
|
$taxCountry = $deliveryAddress->getCountry();
|
|
$invoiceAddress = AddressQuery::create()->findPk($sessionOrder->chosenInvoiceAddress);
|
|
$cartItems = $cart->getCartItems();
|
|
|
|
/* fulfill order */
|
|
$placedOrder->setCustomerId($customer->getId());
|
|
$placedOrder->setCurrencyId($currency->getId());
|
|
$placedOrder->setCurrencyRate($currency->getRate());
|
|
$placedOrder->setLangId($lang->getId());
|
|
|
|
/* hard save the delivery and invoice addresses */
|
|
$deliveryOrderAddress = new OrderAddress();
|
|
$deliveryOrderAddress
|
|
->setCustomerTitleId($deliveryAddress->getTitleId())
|
|
->setCompany($deliveryAddress->getCompany())
|
|
->setFirstname($deliveryAddress->getFirstname())
|
|
->setLastname($deliveryAddress->getLastname())
|
|
->setAddress1($deliveryAddress->getAddress1())
|
|
->setAddress2($deliveryAddress->getAddress2())
|
|
->setAddress3($deliveryAddress->getAddress3())
|
|
->setZipcode($deliveryAddress->getZipcode())
|
|
->setCity($deliveryAddress->getCity())
|
|
->setPhone($deliveryAddress->getPhone())
|
|
->setCountryId($deliveryAddress->getCountryId())
|
|
->save($con)
|
|
;
|
|
|
|
$invoiceOrderAddress = new OrderAddress();
|
|
$invoiceOrderAddress
|
|
->setCustomerTitleId($invoiceAddress->getTitleId())
|
|
->setCompany($invoiceAddress->getCompany())
|
|
->setFirstname($invoiceAddress->getFirstname())
|
|
->setLastname($invoiceAddress->getLastname())
|
|
->setAddress1($invoiceAddress->getAddress1())
|
|
->setAddress2($invoiceAddress->getAddress2())
|
|
->setAddress3($invoiceAddress->getAddress3())
|
|
->setZipcode($invoiceAddress->getZipcode())
|
|
->setCity($invoiceAddress->getCity())
|
|
->setPhone($invoiceAddress->getPhone())
|
|
->setCountryId($invoiceAddress->getCountryId())
|
|
->save($con)
|
|
;
|
|
|
|
$placedOrder->setDeliveryOrderAddressId($deliveryOrderAddress->getId());
|
|
$placedOrder->setInvoiceOrderAddressId($invoiceOrderAddress->getId());
|
|
|
|
$placedOrder->setStatusId(
|
|
OrderStatusQuery::getNotPaidStatus()->getId()
|
|
);
|
|
|
|
/* memorize discount */
|
|
$placedOrder->setDiscount(
|
|
$cart->getDiscount()
|
|
);
|
|
|
|
$placedOrder->save($con);
|
|
|
|
/* fulfill order_products and decrease stock */
|
|
|
|
foreach ($cartItems as $cartItem) {
|
|
$product = $cartItem->getProduct();
|
|
|
|
/* get translation */
|
|
$productI18n = I18n::forceI18nRetrieving($lang->getLocale(), 'Product', $product->getId());
|
|
|
|
$pse = $cartItem->getProductSaleElements();
|
|
|
|
/* check still in stock */
|
|
if ($cartItem->getQuantity() > $pse->getQuantity()) {
|
|
throw new TheliaProcessException("Not enough stock", TheliaProcessException::CART_ITEM_NOT_ENOUGH_STOCK, $cartItem);
|
|
}
|
|
|
|
/* decrease stock */
|
|
$pse->setQuantity(
|
|
$pse->getQuantity() - $cartItem->getQuantity()
|
|
);
|
|
$pse->save($con);
|
|
|
|
/* get tax */
|
|
$taxRuleI18n = I18n::forceI18nRetrieving($lang->getLocale(), 'TaxRule', $product->getTaxRuleId());
|
|
|
|
$taxDetail = $product->getTaxRule()->getTaxDetail(
|
|
$product,
|
|
$taxCountry,
|
|
$cartItem->getPrice(),
|
|
$cartItem->getPromoPrice(),
|
|
$lang->getLocale()
|
|
);
|
|
|
|
$orderProduct = new OrderProduct();
|
|
$orderProduct
|
|
->setOrderId($placedOrder->getId())
|
|
->setProductRef($product->getRef())
|
|
->setProductSaleElementsRef($pse->getRef())
|
|
->setTitle($productI18n->getTitle())
|
|
->setChapo($productI18n->getChapo())
|
|
->setDescription($productI18n->getDescription())
|
|
->setPostscriptum($productI18n->getPostscriptum())
|
|
->setQuantity($cartItem->getQuantity())
|
|
->setPrice($cartItem->getPrice())
|
|
->setPromoPrice($cartItem->getPromoPrice())
|
|
->setWasNew($pse->getNewness())
|
|
->setWasInPromo($cartItem->getPromo())
|
|
->setWeight($pse->getWeight())
|
|
->setTaxRuleTitle($taxRuleI18n->getTitle())
|
|
->setTaxRuleDescription($taxRuleI18n->getDescription())
|
|
->setEanCode($pse->getEanCode())
|
|
->setCartIemId($cartItem->getId())
|
|
->setDispatcher($dispatcher)
|
|
->save($con)
|
|
;
|
|
|
|
/* fulfill order_product_tax */
|
|
foreach ($taxDetail as $tax) {
|
|
$tax->setOrderProductId($orderProduct->getId());
|
|
$tax->save($con);
|
|
}
|
|
|
|
/* fulfill order_attribute_combination and decrease stock */
|
|
foreach ($pse->getAttributeCombinations() as $attributeCombination) {
|
|
$attribute = I18n::forceI18nRetrieving($lang->getLocale(), 'Attribute', $attributeCombination->getAttributeId());
|
|
$attributeAv = I18n::forceI18nRetrieving($lang->getLocale(), 'AttributeAv', $attributeCombination->getAttributeAvId());
|
|
|
|
$orderAttributeCombination = new OrderProductAttributeCombination();
|
|
$orderAttributeCombination
|
|
->setOrderProductId($orderProduct->getId())
|
|
->setAttributeTitle($attribute->getTitle())
|
|
->setAttributeChapo($attribute->getChapo())
|
|
->setAttributeDescription($attribute->getDescription())
|
|
->setAttributePostscriptum($attribute->getPostscriptum())
|
|
->setAttributeAvTitle($attributeAv->getTitle())
|
|
->setAttributeAvChapo($attributeAv->getChapo())
|
|
->setAttributeAvDescription($attributeAv->getDescription())
|
|
->setAttributeAvPostscriptum($attributeAv->getPostscriptum())
|
|
->save($con);
|
|
}
|
|
}
|
|
|
|
$con->commit();
|
|
|
|
return $placedOrder;
|
|
}
|
|
|
|
/**
|
|
* Create an order outside of the front-office context, e.g. manually from the back-office.
|
|
*/
|
|
public function createManual(OrderManualEvent $event)
|
|
{
|
|
$placedOrder = $this->createOrder(
|
|
$event->getDispatcher(),
|
|
$event->getOrder(),
|
|
$event->getCurrency(),
|
|
$event->getLang(),
|
|
$event->getCart(),
|
|
$event->getCustomer()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param OrderEvent $event
|
|
*
|
|
* @throws \Thelia\Exception\TheliaProcessException
|
|
*/
|
|
public function create(OrderEvent $event)
|
|
{
|
|
$session = $this->getSession();
|
|
|
|
$placedOrder = $this->createOrder(
|
|
$event->getDispatcher(),
|
|
$event->getOrder(),
|
|
$session->getCurrency(),
|
|
$session->getLang(),
|
|
$session->getCart(),
|
|
$this->securityContext->getCustomerUser()
|
|
);
|
|
|
|
$event->getDispatcher()->dispatch(TheliaEvents::ORDER_BEFORE_PAYMENT, new OrderEvent($placedOrder));
|
|
|
|
/* but memorize placed order */
|
|
$event->setOrder(new \Thelia\Model\Order());
|
|
$event->setPlacedOrder($placedOrder);
|
|
|
|
/* empty cart */
|
|
$dispatcher = $event->getDispatcher();
|
|
|
|
/* call pay method */
|
|
$payEvent = new OrderPaymentEvent($placedOrder);
|
|
|
|
$dispatcher->dispatch(TheliaEvents::MODULE_PAY, $payEvent);
|
|
|
|
if ($payEvent->hasResponse()) {
|
|
$event->setResponse($payEvent->getResponse());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param \Thelia\Core\Event\Order\OrderEvent $event
|
|
*/
|
|
public function sendOrderEmail(OrderEvent $event)
|
|
{
|
|
$contact_email = ConfigQuery::read('store_email');
|
|
|
|
if ($contact_email) {
|
|
|
|
$message = MessageQuery::create()
|
|
->filterByName('order_confirmation')
|
|
->findOne();
|
|
|
|
if (false === $message) {
|
|
throw new \Exception("Failed to load message 'order_confirmation'.");
|
|
}
|
|
|
|
$order = $event->getOrder();
|
|
$customer = $order->getCustomer();
|
|
|
|
$this->parser->assign('order_id', $order->getId());
|
|
$this->parser->assign('order_ref', $order->getRef());
|
|
|
|
$message
|
|
->setLocale($order->getLang()->getLocale());
|
|
|
|
$instance = \Swift_Message::newInstance()
|
|
->addTo($customer->getEmail(), $customer->getFirstname()." ".$customer->getLastname())
|
|
->addFrom($contact_email, ConfigQuery::read('store_name'))
|
|
;
|
|
|
|
// Build subject and body
|
|
|
|
$message->buildMessage($this->parser, $instance);
|
|
|
|
$this->getMailer()->send($instance);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* return an instance of \Swift_Mailer with good Transporter configured.
|
|
*
|
|
* @return \Swift_Mailer
|
|
*/
|
|
public function getMailer()
|
|
{
|
|
return $this->mailer->getSwiftMailer();
|
|
}
|
|
|
|
/**
|
|
* @param OrderEvent $event
|
|
*/
|
|
public function updateStatus(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$order->setStatusId($event->getStatus());
|
|
$order->save();
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
/**
|
|
* @param OrderEvent $event
|
|
*/
|
|
public function updateDeliveryRef(OrderEvent $event)
|
|
{
|
|
$order = $event->getOrder();
|
|
|
|
$order->setDeliveryRef($event->getDeliveryRef());
|
|
$order->save();
|
|
|
|
$event->setOrder($order);
|
|
}
|
|
|
|
/**
|
|
* @param OrderAddressEvent $event
|
|
*/
|
|
public function updateAddress(OrderAddressEvent $event)
|
|
{
|
|
$orderAddress = $event->getOrderAddress();
|
|
|
|
$orderAddress
|
|
->setCustomerTitleId($event->getTitle())
|
|
->setCompany($event->getCompany())
|
|
->setFirstname($event->getFirstname())
|
|
->setLastname($event->getLastname())
|
|
->setAddress1($event->getAddress1())
|
|
->setAddress2($event->getAddress2())
|
|
->setAddress3($event->getAddress3())
|
|
->setZipcode($event->getZipcode())
|
|
->setCity($event->getCity())
|
|
->setCountryId($event->getCountry())
|
|
->setPhone($event->getPhone())
|
|
;
|
|
$orderAddress->save();
|
|
|
|
$event->setOrderAddress($orderAddress);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of event names this subscriber wants to listen to.
|
|
*
|
|
* The array keys are event names and the value can be:
|
|
*
|
|
* * The method name to call (priority defaults to 0)
|
|
* * An array composed of the method name to call and the priority
|
|
* * An array of arrays composed of the method names to call and respective
|
|
* priorities, or 0 if unset
|
|
*
|
|
* For instance:
|
|
*
|
|
* * array('eventName' => 'methodName')
|
|
* * array('eventName' => array('methodName', $priority))
|
|
* * array('eventName' => array(array('methodName1', $priority), array('methodName2'))
|
|
*
|
|
* @return array The event names to listen to
|
|
*
|
|
* @api
|
|
*/
|
|
public static function getSubscribedEvents()
|
|
{
|
|
return array(
|
|
TheliaEvents::ORDER_SET_DELIVERY_ADDRESS => array("setDeliveryAddress", 128),
|
|
TheliaEvents::ORDER_SET_DELIVERY_MODULE => array("setDeliveryModule", 128),
|
|
TheliaEvents::ORDER_SET_POSTAGE => array("setPostage", 128),
|
|
TheliaEvents::ORDER_SET_INVOICE_ADDRESS => array("setInvoiceAddress", 128),
|
|
TheliaEvents::ORDER_SET_PAYMENT_MODULE => array("setPaymentModule", 128),
|
|
TheliaEvents::ORDER_PAY => array("create", 128),
|
|
TheliaEvents::ORDER_BEFORE_PAYMENT => array("sendOrderEmail", 128),
|
|
TheliaEvents::ORDER_UPDATE_STATUS => array("updateStatus", 128),
|
|
TheliaEvents::ORDER_UPDATE_DELIVERY_REF => array("updateDeliveryRef", 128),
|
|
TheliaEvents::ORDER_UPDATE_ADDRESS => array("updateAddress", 128),
|
|
TheliaEvents::ORDER_CREATE_MANUAL => array("createManual", 128),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the session from the current request
|
|
*
|
|
* @return \Thelia\Core\HttpFoundation\Session\Session
|
|
*/
|
|
protected function getSession()
|
|
{
|
|
return $this->request->getSession();
|
|
}
|
|
}
|