Inital commit

This commit is contained in:
2020-11-19 15:36:28 +01:00
parent 71f32f83d3
commit 66ce4ee218
18077 changed files with 2166122 additions and 35184 deletions

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns="http://thelia.net/schema/dic/config"
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">
<loops>
<!-- sample definition
<loop name="MySuperLoop" class="MyModule\Loop\MySuperLoop" />
-->
</loops>
<forms>
<form name="admin.order.creation.form.configure" class="OrderCreation\Form\ConfigurationForm" />
<form name="admin.order.creation.create.form" class="OrderCreation\Form\OrderCreationCreateForm" />
<form name="admin.order.redirects.payment.form" class="OrderCreation\Form\ConfigurationRedirectsPayementForm" />
</forms>
<commands>
<!--
<command class="MyModule\Command\MySuperCommand" />
-->
</commands>
<services>
<service id="order.creation.action" class="OrderCreation\EventListeners\OrderCreationListener" scope="request">
<argument type="service" id="request"/>
<argument type="service" id="event_dispatcher"/>
<argument type="service" id="thelia.taxEngine"/>
<tag name="kernel.event_subscriber"/>
</service>
</services>
<hooks>
<hook id="order.creation.hook.back" >
<tag name="hook.event_listener" event="customer.edit-js" type="back" templates="render:customer-edit-js.html" />
<tag name="hook.event_listener" event="customer.edit" type="back" templates="render:customer-edit.html" />
<tag name="hook.event_listener" event="module.configuration" type="back" templates="render:module_configuration.html" />
</hook>
</hooks>
<!--
<exports>
</exports>
-->
<!--
<imports>
</imports>
-->
</config>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module>
<fullnamespace>OrderCreation\OrderCreation</fullnamespace>
<descriptive locale="en_US">
<title>Order creation in back-office</title>
</descriptive>
<descriptive locale="fr_FR">
<title>Creation de commande depuis l'administration</title>
</descriptive>
<version>1.8.0</version>
<author>
<name>gbarral</name>
<email>gbarral@openstudio.fr</email>
</author>
<type>classic</type>
<thelia>2.1.1</thelia>
<stability>prod</stability>
</module>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="admin.order.creation.config.ajax" path="/admin/module/OrderCreation/config/ajax" methods="get">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::getConfigurationAjaxAction</default>
</route>
<route id="admin.order.creation.configure" path="/admin/module/OrderCreation/configure" methods="post">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::configureAction</default>
</route>
<route id="admin.order.creation.create" path="/admin/module/OrderCreation/order/create" methods="post">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::createOrderAction</default>
</route>
<route id="admin.order.creation.add.item" path="/admin/module/OrderCreation/add-item/{position}" methods="get">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::addItemAction</default>
<requirement key="position">\d+</requirement>
</route>
<route id="admin.order.creation.list-products" path="/admin/module/OrderCreation/{productId}/list-products/{categoryId}.{_format}" methods="GET">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::getAvailableProductAction</default>
<requirement key="_format">xml|json</requirement>
</route>
<route id="admin.order.creation.country.request" path="/admin/module/OrderCreation/update/country/request" methods="POST">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::updateCountryInRequest</default>
</route>
<route id="admin.order.creation.redirectable.payment.request" path="/admin/module/OrderCreation/redirectable-payment/{moduleID}">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::isRedirectable</default>
</route>
<route id="admin.order.creation.set.redirects" path="/admin/module/OrderCreation/configure-redirects-payment" methods="post">
<default key="_controller">OrderCreation\Controller\Admin\OrderCreationAdminController::setRedirectsPayment</default>
</route>
</routes>

View File

@@ -0,0 +1,338 @@
<?php
/**
* Created by PhpStorm.
* User: gbarral
* Date: 28/08/2014
* Time: 10:58
*/
namespace OrderCreation\Controller\Admin;
use OrderCreation\Event\OrderCreationEvent;
use OrderCreation\EventListeners\OrderCreationListener;
use OrderCreation\Form\OrderCreationCreateForm;
use OrderCreation\OrderCreation;
use OrderCreation\OrderCreationConfiguration;
use Propel\Runtime\ActiveQuery\Criteria;
use Propel\Runtime\ActiveQuery\Join;
use Propel\Runtime\Propel;
use Symfony\Component\Security\Acl\Exception\Exception;
use Thelia\Controller\Admin\BaseAdminController;
use Thelia\Core\HttpFoundation\JsonResponse;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\Resource\AdminResources;
use Thelia\Core\Translation\Translator;
use Thelia\Form\CustomerUpdateForm;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Model\AddressQuery;
use Thelia\Model\Base\CustomerQuery;
use Thelia\Model\Base\ProductSaleElementsQuery;
use Thelia\Model\Customer;
use Thelia\Model\Exception\InvalidArgumentException;
use Thelia\Model\Map\OrderTableMap;
use Thelia\Model\Map\ProductCategoryTableMap;
use Thelia\Model\Map\ProductI18nTableMap;
use Thelia\Model\Map\ProductSaleElementsTableMap;
use Thelia\Model\Map\ProductTableMap;
use Thelia\Model\Module;
use Thelia\Model\ModuleQuery;
use Thelia\Model\Order;
use Thelia\Tools\URL;
class OrderCreationAdminController extends BaseAdminController
{
public function addItemAction($position)
{
return $this->render(
"ajax/add-cart-item",
array("position" => $position)
);
}
public function getConfigurationAjaxAction()
{
$tabResult = [];
$moduleId = OrderCreationConfiguration::getDeliveryModuleId();
$tabResult['moduleId'] = $moduleId;
if (OrderCreationConfiguration::getSoColissimoMode()) {
$mode = OrderCreationConfiguration::getDeliveryModuleId();
$tabResult['modeTT'] = $mode;
}
return JsonResponse::create($tabResult);
}
public function configureAction()
{
if (null !== $response = $this->checkAuth(AdminResources::MODULE, ucfirst(OrderCreation::MESSAGE_DOMAIN), AccessManager::UPDATE)) {
return $response;
}
$configurationForm = $this->createForm('admin.order.creation.form.configure');
try {
$form = $this->validateForm($configurationForm, "POST");
$data = $form->getData();
OrderCreationConfiguration::setDeliveryModuleId($data['order_creation_delivery_module_id']);
/** @var Module $module */
$module = ModuleQuery::create()
->filterById($data['order_creation_delivery_module_id'])
->findOne();
$codeModule = "";
if (null !== $module) {
$codeModule = $module->getCode();
}
if (OrderCreation::SOCOLISSIMO == $codeModule) {
OrderCreationConfiguration::setSoColissimoMode('DOM');
} else {
OrderCreationConfiguration::setSoColissimoMode('');
}
$this->adminLogAppend(
OrderCreation::MESSAGE_DOMAIN . ".configuration.message",
AccessManager::UPDATE,
sprintf("OrderCreation configuration updated")
);
if ($this->getRequest()->get('save_mode') == 'stay') {
// If we have to stay on the same page, redisplay the configuration page/
$url = '/admin/module/OrderCreation';
} else {
// If we have to close the page, go back to the module back-office page.
$url = '/admin/modules';
}
return $this->generateRedirect(URL::getInstance()->absoluteUrl($url));
} catch (FormValidationException $ex) {
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
} catch (\Exception $ex) {
$error_msg = $ex->getMessage();
}
$this->setupFormErrorContext(
$this->getTranslator()->trans("OrderCreation configuration", [], OrderCreation::MESSAGE_DOMAIN),
$error_msg,
$configurationForm,
$ex
);
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/OrderCreation'));
}
public function createOrderAction()
{
$response = $this->checkAuth(array(AdminResources::MODULE), array('OrderCreation'), AccessManager::CREATE);
if (null !== $response) {
return $response;
}
$con = Propel::getConnection(OrderTableMap::DATABASE_NAME);
$con->beginTransaction();
$form = new OrderCreationCreateForm($this->getRequest());
$moduleId = OrderCreationConfiguration::getDeliveryModuleId();
if ($moduleId !== null) {
$orderDeliveryParameters = $form->getRequest()->request->get("thelia_order_delivery");
$orderDeliveryParameters[OrderCreationCreateForm::FIELD_NAME_DELIVERY_MODULE_ID] = $moduleId;
$form->getRequest()->request->set("thelia_order_delivery", $orderDeliveryParameters);
}
try {
$formValidate = $this->validateForm($form);
$event = new OrderCreationEvent();
if ($formValidate->get(OrderCreationCreateForm::FIELD_CHECK_REDIRECTS_PAYMENT)->getData()) {
$event->setRedirect(1);
} else {
$event->setRedirect(0);
}
$event
->setContainer($this->getContainer())
->setCustomerId($formValidate->get(OrderCreationCreateForm::FIELD_NAME_CUSTOMER_ID)->getData())
->setDeliveryAddressId($formValidate->get(OrderCreationCreateForm::FIELD_NAME_DELIVERY_ADDRESS_ID)->getData())
->setDeliveryModuleId($formValidate->get(OrderCreationCreateForm::FIELD_NAME_DELIVERY_MODULE_ID)->getData())
->setInvoiceAddressId($formValidate->get(OrderCreationCreateForm::FIELD_NAME_INVOICE_ADDRESS_ID)->getData())
->setPaymentModuleId($formValidate->get(OrderCreationCreateForm::FIELD_NAME_PAYMENT_MODULE_ID)->getData())
->setProductSaleElementIds($formValidate->get(OrderCreationCreateForm::FIELD_NAME_PRODUCT_SALE_ELEMENT_ID)->getData())
->setQuantities($formValidate->get(OrderCreationCreateForm::FIELD_NAME_QUANTITY)->getData())
->setDiscountPrice($formValidate->get(OrderCreationCreateForm::FIELD_DISCOUNT_PRICE)->getData())
->setDiscountType($formValidate->get(OrderCreationCreateForm::FIELD_DISCOUNT_TYPE)->getData())
->setLang($this->getCurrentEditionLang());
$this->dispatch(OrderCreationListener::ADMIN_ORDER_CREATE, $event);
if (null != $event->getResponse()) {
$con->commit();
return $event->getResponse();
}
$con->commit();
} catch (\Exception $e) {
$con->rollBack();
$error_message = $e->getMessage();
$form->setErrorMessage($error_message);
$this->getParserContext()
->addForm($form)
->setGeneralError($error_message);
return $this->generateErrorRedirect($form);
}
return $this->generateSuccessRedirect($form);
}
/**
* @param null $categoryId
* @return \Thelia\Core\HttpFoundation\Response
* @throws \Propel\Runtime\Exception\PropelException
*/
public function getAvailableProductAction($categoryId = null)
{
$result = array();
if ($categoryId !== null) {
$pses = ProductSaleElementsQuery::create()
->useProductQuery()
->useProductCategoryQuery()
->filterByDefaultCategory(true)
->filterByCategoryId($categoryId)
->endUse()
->useI18nQuery($this->getCurrentEditionLocale())
->endUse()
->endUse()
->withColumn(ProductTableMap::ID, 'product_id')
->withColumn(ProductTableMap::REF, 'product_ref')
->withColumn(ProductI18nTableMap::TITLE, 'product_title')
->orderBy('product_title')
->find()
;
/** @var \Thelia\Model\ProductSaleElements $pse */
foreach ($pses as $pse) {
$productRef = $pse->getVirtualColumn('product_ref');
if (! isset($result[$productRef])) {
$result[$productRef] = [
'title' => $pse->getVirtualColumn('product_title'),
'product_id' => $pse->getVirtualColumn('product_id'),
'pse_list' => []
];
}
$result[$productRef]['pse_list'][] = [
'id' => $pse->getId(),
'ref' => $pse->getRef(),
'quantity' => $pse->getQuantity()
];
}
}
return $this->jsonResponse(json_encode($result));
}
/**
* @return \Symfony\Component\HttpFoundation\Response|static
*/
public function updateCountryInRequest()
{
$response = JsonResponse::create([], 200);
try {
$addressId = $this->getRequest()->request->get('address_id');
if (null === $addressId) {
throw new InvalidArgumentException(
$this->getTranslator()->trans(
"You must pass address_id",
[],
OrderCreation::MESSAGE_DOMAIN
)
);
}
$address = AddressQuery::create()->findPk($addressId);
if (null === $address) {
throw new Exception(
$this->getTranslator()->trans(
"Cannot find address with id %addressId",
["%addressId" => $addressId],
OrderCreation::MESSAGE_DOMAIN
)
);
}
$order = new Order();
$order
->setCustomer()
->setChoosenDeliveryAddress($addressId);
$this->getRequest()->getSession()->set(
"thelia.order",
$order
);
$this->getRequest()->getSession()->set(
"thelia.customer_user",
$address->getCustomer()
);
} catch (\Exception $e) {
$response = JsonResponse::create(["error" => $e->getMessage()], 500);
}
return $response;
}
public function setRedirectsPayment()
{
$authFail = $this->checkAuth(AdminResources::MODULE, OrderCreation::MESSAGE_DOMAIN, AccessManager::CREATE);
if ($authFail !== null) {
return $authFail;
}
$configurationRPForm = $this->createForm('admin.order.redirects.payment.form');
try {
$form = $this->validateForm($configurationRPForm, "POST");
$data = $form->getData();
$modules = $data['order_creation_redirects_payment'];
OrderCreationConfiguration::setlistPaymentModule($modules);
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/OrderCreation'));
} catch (FormValidationException $exception) {
$error_msg = $this->createStandardFormValidationErrorMessage($exception);
}
$this->setupFormErrorContext(
$this->getTranslator()->trans("OrderCreation configuration", [], OrderCreation::MESSAGE_DOMAIN),
$error_msg,
$configurationRPForm,
$exception
);
return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/OrderCreation'));
}
public function isRedirectable($moduleID)
{
$modules = json_decode(OrderCreationConfiguration::getlistPaymentModule());
if (in_array($moduleID, $modules)) {
return $this->jsonResponse(json_encode(['test' => 1]));
}
return $this->jsonResponse(json_encode(['test' => 0]));
}
}

View File

@@ -0,0 +1,350 @@
<?php
/**
* Created by PhpStorm.
* User: gbarral
* Date: 28/08/2014
* Time: 17:13
*/
namespace OrderCreation\Event;
use Thelia\Core\Event\ActionEvent;
class OrderCreationEvent extends ActionEvent
{
/** @var \Symfony\Component\DependencyInjection\ContainerInterface */
protected $container;
/** @var int $customerId */
protected $customerId;
/** @var int $deliveryAddressId */
protected $deliveryAddressId;
/** @var int $invoiceAddressId */
protected $invoiceAddressId;
/** @var int $deliveryModuleId */
protected $deliveryModuleId;
/** @var int $paymentModuleId */
protected $paymentModuleId;
/** @var array $productSaleElementIds */
protected $productSaleElementIds;
/** @var array $quantities */
protected $quantities;
/** @var \Thelia\Model\CartItem $cartItem */
protected $cartItem;
/** @var \Thelia\Model\Order $customerId */
protected $placedOrder;
protected $response;
/** @var double */
protected $discountPrice;
/** @var int */
protected $discountType;
protected $lang;
protected $redirect;
public function __construct()
{
//
}
/**
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
*
* @return OrderCreationEvent
*/
public function setContainer($container)
{
$this->container = $container;
return $this;
}
/**
* @return \Symfony\Component\DependencyInjection\ContainerInterface
*/
public function getContainer()
{
return $this->container;
}
/**
* @param \Thelia\Model\CartItem $cartItem
*
* @return OrderCreationEvent
*/
public function setCartItem($cartItem)
{
$this->cartItem = $cartItem;
return $this;
}
/**
* @return \Thelia\Model\CartItem
*/
public function getCartItem()
{
return $this->cartItem;
}
/**
* @param int $customerId
*
* @return OrderCreationEvent
*/
public function setCustomerId($customerId)
{
$this->customerId = $customerId;
return $this;
}
/**
* @return int
*/
public function getCustomerId()
{
return $this->customerId;
}
/**
* @param int $deliveryAddressId
*
* @return OrderCreationEvent
*/
public function setDeliveryAddressId($deliveryAddressId)
{
$this->deliveryAddressId = $deliveryAddressId;
return $this;
}
/**
* @return int
*/
public function getDeliveryAddressId()
{
return $this->deliveryAddressId;
}
/**
* @param int $deliveryModuleId
*
* @return OrderCreationEvent
*/
public function setDeliveryModuleId($deliveryModuleId)
{
$this->deliveryModuleId = $deliveryModuleId;
return $this;
}
/**
* @return int
*/
public function getDeliveryModuleId()
{
return $this->deliveryModuleId;
}
/**
* @param int $invoiceAddressId
*
* @return OrderCreationEvent
*/
public function setInvoiceAddressId($invoiceAddressId)
{
$this->invoiceAddressId = $invoiceAddressId;
return $this;
}
/**
* @return int
*/
public function getInvoiceAddressId()
{
return $this->invoiceAddressId;
}
/**
* @param int $paymentModuleId
*
* @return OrderCreationEvent
*/
public function setPaymentModuleId($paymentModuleId)
{
$this->paymentModuleId = $paymentModuleId;
return $this;
}
/**
* @return int
*/
public function getPaymentModuleId()
{
return $this->paymentModuleId;
}
/**
* @param \Thelia\Model\Order $placedOrder
*
* @return OrderCreationEvent
*/
public function setPlacedOrder($placedOrder)
{
$this->placedOrder = $placedOrder;
return $this;
}
/**
* @return \Thelia\Model\Order
*/
public function getPlacedOrder()
{
return $this->placedOrder;
}
/**
* @param array $productSaleElementIds
*
* @return OrderCreationEvent
*/
public function setProductSaleElementIds($productSaleElementIds)
{
$this->productSaleElementIds = $productSaleElementIds;
return $this;
}
/**
* @return array
*/
public function getProductSaleElementIds()
{
return $this->productSaleElementIds;
}
/**
* @param array $quantities
*
* @return OrderCreationEvent
*/
public function setQuantities($quantities)
{
$this->quantities = $quantities;
return $this;
}
/**
* @return array
*/
public function getQuantities()
{
return $this->quantities;
}
/**
* @param mixed $response
*
* @return OrderCreationEvent
*/
public function setResponse($response)
{
$this->response = $response;
return $this;
}
/**
* @return mixed
*/
public function getResponse()
{
return $this->response;
}
/**
* @param double $price
* @return OrderCreationEvent
*/
public function setDiscountPrice($price)
{
$this->discountPrice = $price;
return $this;
}
/**
* @param int $discountType
* @return OrderCreationEvent
*/
public function setDiscountType($discountType)
{
$this->discountType = $discountType;
return $this;
}
/**
* @return float
*/
public function getDiscountPrice()
{
return $this->discountPrice;
}
/**
* @return int
*/
public function getDiscountType()
{
return $this->discountType;
}
/**
* @return mixed
*/
public function getLang()
{
return $this->lang;
}
/**
* @param mixed $lang
*/
public function setLang($lang)
{
$this->lang = $lang;
}
/**
* @return mixed
*/
public function getRedirect()
{
return $this->redirect;
}
/**
* @param mixed $redirect
*/
public function setRedirect($redirect)
{
$this->redirect = $redirect;
}
}

View File

@@ -0,0 +1,326 @@
<?php
/**
* Created by PhpStorm.
* User: gbarral
* Date: 28/08/2014
* Time: 17:19
*/
namespace OrderCreation\EventListeners;
use OrderCreation\Event\OrderCreationEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\Coupon\CouponConsumeEvent;
use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent;
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\Model\Base\AddressQuery;
use Thelia\Model\Base\CustomerQuery;
use Thelia\Model\Base\ProductSaleElementsQuery;
use Thelia\Model\Cart;
use Thelia\Model\CartItem;
use Thelia\Model\Coupon;
use Thelia\Model\Currency;
use Thelia\Model\ModuleQuery;
use Thelia\Model\Order;
use Thelia\Model\OrderPostage;
use Thelia\Model\OrderStatusQuery;
use Thelia\Model\ProductPriceQuery;
use Thelia\Model\Sale;
use Thelia\Module\DeliveryModuleInterface;
use Thelia\TaxEngine\TaxEngine;
class OrderCreationListener implements EventSubscriberInterface
{
const ADMIN_ORDER_CREATE = "action.admin.order.create";
const ADMIN_ORDER_BEFORE_ADD_CART = "action.admin.order.before.add.cart";
const ADMIN_ORDER_AFTER_CREATE_MANUAL = "action.admin.order.after.create.manual";
protected $request;
private $eventDispatcher;
private $taxEngine;
/**
* OrderCreationListener constructor.
* @param Request $request
* @param EventDispatcherInterface $eventDispatcher
* @param TaxEngine $taxEngine
*/
public function __construct(
Request $request,
EventDispatcherInterface $eventDispatcher,
TaxEngine $taxEngine
) {
$this->request = $request;
$this->eventDispatcher = $eventDispatcher;
$this->taxEngine = $taxEngine;
}
/**
* 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(
self::ADMIN_ORDER_CREATE => array('adminOrderCreate', 128)
);
}
/**
* @param OrderCreationEvent $event
* @throws \Propel\Runtime\Exception\PropelException
* @throws \Exception
*/
public function adminOrderCreate(OrderCreationEvent $event)
{
$pseIds = $event->getProductSaleElementIds();
$quantities = $event->getQuantities();
/** @var \Thelia\Model\Address $deliveryAddress */
$deliveryAddress = AddressQuery::create()->findPk($event->getDeliveryAddressId());
/** @var \Thelia\Model\Address $invoiceAddress */
$invoiceAddress = AddressQuery::create()->findPk($event->getInvoiceAddressId());
/** @var \Thelia\Model\Module $deliveryModule */
$deliveryModule = ModuleQuery::create()->findPk($event->getDeliveryModuleId());
/** @var \Thelia\Model\Module $paymentModule */
$paymentModule = ModuleQuery::create()->findPk($event->getPaymentModuleId());
/** @var \Thelia\Model\Currency $currency */
$currency = Currency::getDefaultCurrency();
/** @var \Thelia\Model\Customer $customer */
$customer = CustomerQuery::create()->findPk($event->getCustomerId());
$order = new Order();
/** @noinspection PhpParamsInspection */
$order
->setCustomerId($customer->getId())
->setCurrencyId($currency->getId())
->setCurrencyRate($currency->getRate())
->setStatusId(OrderStatusQuery::getNotPaidStatus()->getId())
->setLangId($event->getLang()->getDefaultLanguage()->getId())
->setChoosenDeliveryAddress($deliveryAddress)
->setChoosenInvoiceAddress($invoiceAddress);
//If someone is connected in FRONT, stock it
$oldCustomer = $this->request->getSession()->getCustomerUser();
//Do the same for his cart
$oldCart = $this->request->getSession()->getSessionCart($this->eventDispatcher);
try {
$cartToken = uniqid("createorder", true);
$cart = new Cart();
$cart->setToken($cartToken)
->setCustomer($customer)
->setCurrency($currency->getDefaultCurrency())
->save();
foreach ($pseIds as $key => $pseId) {
/** @var \Thelia\Model\ProductSaleElements $productSaleElements */
if (null != $productSaleElements = ProductSaleElementsQuery::create()->findOneById($pseId)) {
/** @var \Thelia\Model\ProductPrice $productPrice */
if (null != $productPrice = ProductPriceQuery::create()
->filterByProductSaleElementsId($productSaleElements->getId())
->filterByCurrencyId($currency->getDefaultCurrency()->getId())
->findOne()) {
$cartItem = new CartItem();
$cartItem
->setCart($cart)
->setProduct($productSaleElements->getProduct())
->setProductSaleElements($productSaleElements)
->setQuantity($quantities[$key])
->setPrice($productPrice->getPrice())
->setPromoPrice($productPrice->getPromoPrice())
->setPromo($productSaleElements->getPromo())
->setPriceEndOfLife(time() + 60 * 60 * 24 * 30);
$event->setCartItem($cartItem);
$this->eventDispatcher->dispatch(self::ADMIN_ORDER_BEFORE_ADD_CART, $event);
$cartItem->save();
}
}
}
$this->request->getSession()->setCustomerUser($customer);
$this->request->getSession()->set("thelia.cart_id", $cart->getId());
$orderEvent = new OrderEvent($order);
$orderEvent->setDeliveryAddress($deliveryAddress->getId());
$orderEvent->setInvoiceAddress($invoiceAddress->getId());
/** @var $moduleInstance DeliveryModuleInterface */
$moduleInstance = $deliveryModule->getModuleInstance($event->getContainer());
$postage = OrderPostage::loadFromPostage(
$moduleInstance->getPostage($deliveryAddress->getCountry())
);
$orderEvent->setPostage($postage->getAmount());
$orderEvent->setPostageTax($postage->getAmountTax());
$orderEvent->setPostageTaxRuleTitle($postage->getTaxRuleTitle());
$orderEvent->setDeliveryModule($deliveryModule->getId());
$orderEvent->setPaymentModule($paymentModule->getId());
$this->eventDispatcher->dispatch(TheliaEvents::ORDER_SET_DELIVERY_ADDRESS, $orderEvent);
$this->eventDispatcher->dispatch(TheliaEvents::ORDER_SET_INVOICE_ADDRESS, $orderEvent);
$this->eventDispatcher->dispatch(TheliaEvents::ORDER_SET_POSTAGE, $orderEvent);
$this->eventDispatcher->dispatch(TheliaEvents::ORDER_SET_DELIVERY_MODULE, $orderEvent);
$this->eventDispatcher->dispatch(TheliaEvents::ORDER_SET_PAYMENT_MODULE, $orderEvent);
//DO NOT FORGET THAT THE DISCOUNT ORDER HAS TO BE PLACED IN CART
if ($this->request->getSession()->getSessionCart($this->eventDispatcher) != null) {
$cart->setCartItems($this->request->getSession()->getSessionCart($this->eventDispatcher)->getCartItems());
$cart->setDiscount($this->request->getSession()->getSessionCart($this->eventDispatcher)->getDiscount());
}
$cart->save();
$coupon = $this->createCoupon($event, $cart);
if (!empty($coupon)) {
/** @noinspection PhpParamsInspection */
$couponConsumeEvent = new CouponConsumeEvent($coupon->getCode());
// Dispatch Event to the Action
$this->eventDispatcher->dispatch(TheliaEvents::COUPON_CONSUME, $couponConsumeEvent);
}
$orderManualEvent = new OrderManualEvent(
$orderEvent->getOrder(),
$orderEvent->getOrder()->getCurrency(),
$orderEvent->getOrder()->getLang(),
$cart,
$customer
);
$this->request->getSession()->set("thelia.cart_id", $cart->getId());
$this->eventDispatcher->dispatch(TheliaEvents::ORDER_CREATE_MANUAL, $orderManualEvent);
$this->eventDispatcher->dispatch(
TheliaEvents::ORDER_BEFORE_PAYMENT,
new OrderEvent($orderManualEvent->getPlacedOrder())
);
/* but memorize placed order */
$orderEvent->setOrder(new Order());
$orderEvent->setPlacedOrder($orderManualEvent->getPlacedOrder());
/* call pay method */
if (1 == $event->getRedirect()) {
$payEvent = new OrderPaymentEvent($orderManualEvent->getPlacedOrder());
$this->eventDispatcher->dispatch(TheliaEvents::MODULE_PAY, $payEvent);
if ($payEvent->hasResponse()) {
$event->setResponse($payEvent->getResponse());
}
$event->setPlacedOrder($orderManualEvent->getPlacedOrder());
}
$this->eventDispatcher->dispatch(self::ADMIN_ORDER_AFTER_CREATE_MANUAL, $event);
} catch (\Exception $e) {
throw $e;
} finally {
//Reconnect the front user (if any)
if ($oldCustomer != null) {
$this->request->getSession()->setCustomerUser($oldCustomer);
//And fill his cart
if ($oldCart != null) {
$this->request->getSession()->set("thelia.cart_id", $oldCart->getId());
}
} else {
$this->request->getSession()->clearCustomerUser();
}
}
}
/**
* @param $event OrderCreationEvent
* @param $cart Cart
* @return null|Coupon
* @throws \Exception
*/
protected function createCoupon($event, $cart)
{
if (empty($event->getDiscountPrice())) {
return null;
}
/** @noinspection CaseSensitivityServiceInspection */
$taxCountry = $this->taxEngine->getDeliveryCountry();
/** @noinspection MissingService */
$taxState = $this->taxEngine->getDeliveryState();
$cartAmountTTC = $cart->getTaxedAmount($taxCountry, false, $taxState);
$code = uniqid("bo-order-", true);
$title = sprintf('Order %d %s', $event->getCustomerId(), (new \DateTime())->format("Y-m-d H:i:s"));
switch ($event->getDiscountType()) {
case Sale::OFFSET_TYPE_AMOUNT:
$discountValue = min($event->getDiscountPrice(), $cartAmountTTC);
$effects = ['amount' => $discountValue];
$couponServiceId = 'thelia.coupon.type.remove_x_amount';
break;
case Sale::OFFSET_TYPE_PERCENTAGE:
$discountValue = max(0.00, min(100.00, $event->getDiscountPrice()));
$effects = ['percentage' => $discountValue];
$couponServiceId = 'thelia.coupon.type.remove_x_percent';
break;
default:
return null;
}
// Expiration dans 1 an
$dateExpiration = (new \DateTime())->add(new \DateInterval('P1Y'));
$couponEvent = new CouponCreateOrUpdateEvent(
$code,
$couponServiceId,
$title,
$effects,
'',
'',
true,
$dateExpiration,
false,
true,
false,
1,
$event->getLang()->getLocale(),
[],
[],
1
);
$this->eventDispatcher->dispatch(TheliaEvents::COUPON_CREATE, $couponEvent);
return $couponEvent->getCouponModel();
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
* Created by PhpStorm.
* User: audreymartel
* Date: 27/07/2018
* Time: 15:51
*/
namespace OrderCreation\Form;
use OrderCreation\OrderCreation;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Thelia\Form\BaseForm;
class ConfigurationForm extends BaseForm
{
protected function buildForm()
{
$this->formBuilder
->add(
'order_creation_delivery_module_id',
TextType::class,
[
'label' => $this->translator->trans("Delivery module use to create order in back office", [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => array(
'help' => $this->translator->trans('Leave blank to select delivery module on each order', [], OrderCreation::MESSAGE_DOMAIN)
),
'data' => OrderCreation::getConfigValue('order_creation_delivery_module_id'),
'constraints' => [],
]
);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* Created by PhpStorm.
* User: audreymartel
* Date: 27/07/2018
* Time: 15:51
*/
namespace OrderCreation\Form;
use OrderCreation\OrderCreation;
use OrderCreation\OrderCreationConfiguration;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Thelia\Form\BaseForm;
use Thelia\Model\Module;
use Thelia\Model\ModuleQuery;
class ConfigurationRedirectsPayementForm extends BaseForm
{
protected function buildForm()
{
$this->formBuilder
->add(
'order_creation_redirects_payment',
ChoiceType::class,
[
'label' => $this->translator->trans(
"Select all redirectable payment modules",
[],
OrderCreation::MESSAGE_DOMAIN
),
'expanded' => true,
'multiple' => true,
'choices' => $this->getPaymentModuleList(),
'data' => $this->getSelectedModule(),
]
);
}
private function getPaymentModuleList()
{
$modules = ModuleQuery::create()
->filterByType(3)
->filterByActivate(1)
->find();
if (0 != count($modules->getData())) {
$tabChoices = [];
/** @var Module $module */
foreach ($modules->getData() as $module) {
$tabChoices[$module->getId()] = $module->getCode();
}
return $tabChoices;
} else {
return [];
}
}
private function getSelectedModule()
{
$listModules = OrderCreationConfiguration::getlistPaymentModule();
return json_decode($listModules);
}
}

View File

@@ -0,0 +1,197 @@
<?php
/**
* Created by PhpStorm.
* User: gbarral
* Date: 28/08/2014
* Time: 11:02
*/
namespace OrderCreation\Form;
use OrderCreation\OrderCreation;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Validator\Constraints\GreaterThan;
use Symfony\Component\Validator\Constraints\NotBlank;
use Thelia\Form\BaseForm;
use Thelia\Model\Sale;
class OrderCreationCreateForm extends BaseForm
{
const FIELD_NAME_CUSTOMER_ID = 'customer_id';
const FIELD_NAME_DELIVERY_ADDRESS_ID = 'delivery_address_id';
const FIELD_NAME_INVOICE_ADDRESS_ID = 'invoice_address_id';
const FIELD_NAME_DELIVERY_MODULE_ID = 'delivery-module';
const FIELD_NAME_PAYMENT_MODULE_ID = 'payment_module_id';
const FIELD_NAME_PRODUCT_SALE_ELEMENT_ID = 'product_sale_element_id';
const FIELD_NAME_QUANTITY = 'quantity';
const FIELD_DISCOUNT_TYPE = 'discount_type';
const FIELD_DISCOUNT_PRICE = 'discount_price';
const FIELD_CHECK_REDIRECTS_PAYMENT = 'redirects_payment';
protected function buildForm()
{
$this->formBuilder
->add(
self::FIELD_NAME_CUSTOMER_ID,
IntegerType::class,
[
'constraints' => [
new NotBlank()
],
'label' => $this->translator->trans("Customer", [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_CUSTOMER_ID . '_form'
]
]
)
->add(
self::FIELD_NAME_DELIVERY_ADDRESS_ID,
IntegerType::class,
[
'constraints' => [
new NotBlank()
],
'label' => $this->translator->trans("Delivery address", [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_DELIVERY_ADDRESS_ID . '_form'
]
]
)
->add(
self::FIELD_NAME_INVOICE_ADDRESS_ID,
IntegerType::class,
[
'constraints' => [
new NotBlank()
],
'label' => $this->translator->trans("Invoice address", [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_INVOICE_ADDRESS_ID . '_form'
]
]
)
->add(
self::FIELD_NAME_DELIVERY_MODULE_ID,
IntegerType::class,
[
'constraints' => [
new NotBlank()
],
'label' => $this->translator->trans("Transport solution", [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_DELIVERY_MODULE_ID . '_form'
]
]
)
->add(
self::FIELD_NAME_PAYMENT_MODULE_ID,
IntegerType::class,
[
'constraints' => [
new NotBlank()
],
'label' => $this->translator->trans("Payment solution", [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_PAYMENT_MODULE_ID . '_form'
]
]
)
->add(
self::FIELD_NAME_PRODUCT_SALE_ELEMENT_ID,
CollectionType::class,
[
'type' => 'number',
'label' => $this->translator->trans('Product', [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_PRODUCT_SALE_ELEMENT_ID . '_form'
],
'allow_add' => true,
'allow_delete' => true,
]
)
->add(
self::FIELD_NAME_QUANTITY,
CollectionType::class,
[
'type' => 'number',
'label' => $this->translator->trans('Quantity', [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_NAME_QUANTITY . '_form'
],
'allow_add' => true,
'allow_delete' => true,
'options' => [
'constraints' => [
new NotBlank(),
new GreaterThan(
['value' => 0]
)
]
]
]
)
->add(
self::FIELD_DISCOUNT_TYPE,
ChoiceType::class,
[
'constraints' => [ new NotBlank() ],
'choices' => [
Sale::OFFSET_TYPE_AMOUNT => $this->translator->trans('Constant amount', [], 'core'),
Sale::OFFSET_TYPE_PERCENTAGE => $this->translator->trans('Percentage', [], 'core'),
],
'required' => true,
'label' => $this->translator->trans('Discount type', [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_DISCOUNT_TYPE,
'help' => $this->translator->trans('Select the discount type that will be applied to the order price', [], OrderCreation::MESSAGE_DOMAIN),
],
'attr' => []
]
)
->add(
self::FIELD_DISCOUNT_PRICE,
NumberType::class,
[
'required' => false,
'constraints' => [],
'label' => $this->translator->trans('Discount value', [], OrderCreation::MESSAGE_DOMAIN),
'attr' => [
'placeholder' => $this->translator->trans('Discount included taxes', [], OrderCreation::MESSAGE_DOMAIN)
],
'label_attr' => [
'for' => self::FIELD_DISCOUNT_PRICE,
'help' => $this->translator->trans('You can define here a specific discount, as a percentage or a constant amount, depending on the selected discount type.', [], OrderCreation::MESSAGE_DOMAIN),
],
]
)
->add(
self::FIELD_CHECK_REDIRECTS_PAYMENT,
"checkbox",
[
"label" => $this->translator->trans('Go to payment page after order creation', [], OrderCreation::MESSAGE_DOMAIN),
'label_attr' => [
'for' => self::FIELD_CHECK_REDIRECTS_PAYMENT,
'help' => $this->translator->trans('Check this box if you want to pay the order with the selected payment module ', [], OrderCreation::MESSAGE_DOMAIN),
],
"required" => false,
"value" => false,
]
)
;
}
/**
* @return string the name of you form. This name must be unique
*/
public function getName()
{
//This name MUST be the same that the form OrderDelivery (because of ajax delivery module return)
return "thelia_order_delivery";
}
}

View File

@@ -0,0 +1,26 @@
<?php
return array(
'Add product to order' => 'Add product to order',
'Add product to this order' => 'Add product to this order',
'Choose' => 'Choose',
'Choose a delivery address first' => 'Choose a delivery address first',
'Configuration de redirection de paiement' => 'Configuration de redirection de paiement',
'Configuration du module de création de commande en BO' => 'Configuration du module de création de commande en BO',
'Generate a new order' => 'Generate a new order',
'Generate a new order for this customer' => 'Generate a new order for this customer',
'List or ordered products' => 'List of ordered products',
'No default delivery module (default)' => 'No default delivery module (default)',
'Please add at lead one product to this order.' => 'Please add at least one product to this order.',
'Please select a delivery adresse to display shipping options' => 'Please select a delivery adresse to display shipping options',
'Please select a product' => 'Please select a product',
'Remove this product from order' => 'Remove this product from order',
'Save' => 'Save',
'Select product category' => 'Select product category',
'There is no products in this order.' => 'There is no products in this order.',
'There\'s no product in this category' => 'There\'s no product in this category',
'You can create here an order for this customer right from your back-office.' => 'You can create here an order for this customer right from your back-office.',
'You should select a shipping method to create an order.' => 'You should select a shipping method to create an order.',
'or' => 'or',
'stock:' => 'stock:',
);

View File

@@ -0,0 +1,26 @@
<?php
return array(
'Add product to order' => 'Ajouter un produit à la commande',
'Add product to this order' => 'Ajouter un produit à cette commande',
'Choose' => 'Choisir',
'Choose a delivery address first' => 'Veuillez choisir une adresse de livraison pour afficher les modes de livraison possibles',
'Configuration de redirection de paiement' => 'Configuration de redirection de paiement',
'Configuration du module de création de commande en BO' => 'Configuration du module de création de commande',
'Generate a new order' => 'Créer une nouvelle commande',
'Generate a new order for this customer' => 'Créer une nouvelle commande pour ce client',
'List or ordered products' => 'Produits commandés',
'No default delivery module (default)' => 'Ne pas utiliser de module de livraison par défaut',
'Please add at lead one product to this order.' => 'Veuillez ajouter au moins un produit à cette commande',
'Please select a delivery adresse to display shipping options' => 'Veuillez choisir une adresse de livraison pour afficher les modes de livraison possibles',
'Please select a product' => 'Merci de choisir un produit',
'Remove this product from order' => 'Retirer ce produit de la commande',
'Save' => 'Enregistrer',
'Select product category' => 'Choisissez une catégorie',
'There is no products in this order.' => 'Il n\'y a pas encore de produits dans cette commande',
'There\'s no product in this category' => 'Il n\'y a pas de produits dans cette catégorie',
'You can create here an order for this customer right from your back-office.' => 'Vous pouvez ici créer une commande pour ce client depuis votre back-office.',
'You should select a shipping method to create an order.' => 'Vous devez choisir un mode de livraison pour finaliser cette commande.',
'or' => 'ou',
'stock:' => 'stock:',
);

View File

@@ -0,0 +1,26 @@
<?php
return array(
'Cannot find address with id %addressId' => 'Cannot find address with id %addressId',
'Check this box if you want to pay the order with the selected payment module ' => 'Check this box if you want to pay the order with the selected payment module ',
'Constant amount' => 'Constant amount',
'Customer' => 'Customer',
'Delivery address' => 'Delivery address',
'Delivery module use to create order in back office' => 'Delivery module assigned to orders created in the back-offcie',
'Discount included taxes' => 'Discount including taxes',
'Discount type' => 'Discount type',
'Discount value' => 'Discount value',
'Go to payment page after order creation' => 'Go to payment page after order creation',
'Invoice address' => 'Invoice address',
'Leave blank to select delivery module on each order' => 'Leave blank to select delivery module for each created order',
'OrderCreation configuration' => 'OrderCreation configuration',
'Payment solution' => 'Payment solution',
'Percentage' => 'Percentage',
'Product' => 'Product',
'Quantity' => 'Quantity',
'Select all redirectable payment modules' => 'Select all online payement modes (e.g. Credit Card, PayPal, ...)',
'Select the discount type that will be applied to the order price' => 'Select the discount type that will be applied to the order total',
'Transport solution' => 'Transport solution',
'You can define here a specific discount, as a percentage or a constant amount, depending on the selected discount type.' => 'You can define here a specific discount, as a percentage or a constant amount, depending on the selected discount type.',
'You must pass address_id' => 'You should enter an address ID',
);

View File

@@ -0,0 +1,26 @@
<?php
return array(
'Cannot find address with id %addressId' => 'Impossible de trouvez l\'adresse avec l\'id %addressId',
'Check this box if you want to pay the order with the selected payment module ' => 'Cocher cette case pour aller à la page de paiement une fois la commande créée',
'Constant amount' => 'Montant fixe',
'Customer' => 'Client',
'Delivery address' => 'Adresse de livraison',
'Delivery module use to create order in back office' => 'Module de livraison utilisé dans la création de commande en bo',
'Discount included taxes' => 'Remise TTC',
'Discount type' => 'Type de promotion',
'Discount value' => 'Valeur de la promotion',
'Go to payment page after order creation' => 'Payer la commande après création',
'Invoice address' => 'Adresse de facturation',
'Leave blank to select delivery module on each order' => 'Laisser vide pour sélectionner le module dans chaque commande',
'OrderCreation configuration' => 'Configuration OrderCreation',
'Payment solution' => 'Moyen de paiement',
'Percentage' => 'Pourcentage',
'Product' => 'Produit',
'Quantity' => 'Quantité',
'Select all redirectable payment modules' => 'Choisissez les modes de paiement en ligne disponibles (exemple : paiement CB, PayPal, ...)',
'Select the discount type that will be applied to the order price' => 'Sélectionner le type de promotion qui sera appliqué au prix de la commande',
'Transport solution' => 'Moyen de transport',
'You can define here a specific discount, as a percentage or a constant amount, depending on the selected discount type.' => 'Vous pouvez définir une promotion spécifique ici, en pourcentage ou en valeur constante, dépendant du type de promotion sélectionné ',
'You must pass address_id' => 'Vous devez passer l\'id de l\'adresse',
);

View File

@@ -0,0 +1,22 @@
<?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 OrderCreation;
use Thelia\Module\BaseModule;
class OrderCreation extends BaseModule
{
const MESSAGE_DOMAIN = "ordercreation";
const SOCOLISSIMO = "SoColissimo";
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* Created by PhpStorm.
* User: audreymartel
* Date: 27/07/2018
* Time: 16:27
*/
namespace OrderCreation;
class OrderCreationConfiguration
{
const CONFIG_KEY_DELIVERY_MODULE_ID = 'order_creation_delivery_module_id';
const SOCOLISSIMO_MODE = 'order_creation_socolissimo_mode';
const LIST_PAYMENT_MODULE = 'order_creation_list_payment_module';
/**
* @param $moduleId integer | null
*/
public static function setDeliveryModuleId($moduleId)
{
OrderCreation::setConfigValue(self::CONFIG_KEY_DELIVERY_MODULE_ID, $moduleId);
}
public static function setSoColissimoMode($mode)
{
OrderCreation::setConfigValue(self::SOCOLISSIMO_MODE, $mode);
}
public static function setlistPaymentModule($list)
{
OrderCreation::setConfigValue(self::LIST_PAYMENT_MODULE, json_encode($list));
}
public static function getSoColissimoMode()
{
return OrderCreation::getConfigValue(self::SOCOLISSIMO_MODE, null);
}
public static function getlistPaymentModule()
{
return OrderCreation::getConfigValue(self::LIST_PAYMENT_MODULE, json_encode([]));
}
/**
* @return integer | null
*/
public static function getDeliveryModuleId()
{
return OrderCreation::getConfigValue(self::CONFIG_KEY_DELIVERY_MODULE_ID, null);
}
}

View File

@@ -0,0 +1,26 @@
# Order Creation
Create order from admin of Thelia2 (2.1.1+)
## Installation
### Manually
* Copy the module into ```<thelia_root>/local/modules/``` directory and be sure that the name of the module is OrderCreation.
* Activate it in your thelia administration panel
### Composer
Add it in your main thelia composer.json file
```
composer require thelia/order-creation-module:~1.0
```
## Usage
Be sure that you have :
- an active payment module
- an active delivery module
Then, go to the customer edit page and click on the button "Create an order for this customer"

View File

@@ -0,0 +1,11 @@
{
"name": "thelia/order-creation-module",
"license": "LGPL-3.0+",
"type": "thelia-module",
"require": {
"thelia/installer": "~1.1"
},
"extra": {
"installer-name": "OrderCreation"
}
}

View File

@@ -0,0 +1,70 @@
{form name="admin.order.creation.create.form"}
{if !isset($pseId)}
{assign var="pseId" value="0"}
{assign var="productId" value="0"}
{assign var="categoryId" value="0"}
{assign var="quantity" value="1"}
{else}
{loop type="product_sale_elements" name="prod" id=$pseId}
{assign var="productId" value=$PRODUCT_ID}
{loop name="cat-product" type="category" product=$PRODUCT_ID visible='*' limit=1}
{assign var="categoryId" value="$ID"}
{/loop}
{/loop}
{/if}
<tr id="tr-{$position}" class="title-without-tabs">
<td colspan="2">
<table class="table table-striped table-condensed">
<tbody>
<tr>
<td colspan="2">
<div class="input-group">
<select id="category{$position}"
required="required"
class="form-control category-list"
data-pse-id="{$pseId}"
data-target="item{$position}"
data-destination="tr-item{$position}">
<option>{intl l="Select product category" d="ordercreation.bo.default"}</option>
{loop name="cat-parent" type="category-tree" category="0" visible="*" product=$productId}
<option value="{$ID}"{if $categoryId == $ID} selected="selected"{/if}>{option_offset l=$LEVEL+1 label=$TITLE}</option>
{/loop}
</select>
<span class="input-group-btn">
<a class="btn btn-danger item-ajax-delete" data-toggle="modal" title="{intl l='Remove this product from order' d="ordercreation.bo.default"}" data-target="tr-{$position}" href="#">
<i class="glyphicon glyphicon-remove"></i>
</a>
</span>
</div>
</td>
</tr>
<tr id="tr-item{$position}" class="hide">
<td>
{form_field field='product_sale_element_id' value_key=$position}
<select required id="item{$position}" class="form-control" name="{$name}"></select>
{/form_field}
</td>
<td class="text-nowrap">
{form_field field='quantity' value_key=$position}
<div class="form-inline">
<div class="form-group">
<label for="quantity{$position}">{$label}</label>
<input id="quantity{$position}" required type="text" class="form-control" name="{$name}" value="{$quantity}">
</div>
</div>
{/form_field}
</td>
</tr>
<tr id="err_tr-item{$position}" class="hide">
<td colspan="2">
<div class="alert alert-warning" style="margin-bottom:0">{intl l="There's no product in this category" d="ordercreation.bo.default"}</div>
</td>
</tr>
</tbody>
</table>
</td>
<td></td>
</tr>
{/form}

View File

@@ -0,0 +1,216 @@
<script>
$(function() {
$.ajax({
url: '{url path="/admin/module/OrderCreation/config/ajax"}',
type: 'get',
dataType: 'json',
success: function (json) {
if (!json.moduleId) {
return;
}
if (json.modeTT) {
$('#mode-socolissimo').append('<input type="hidden" name="socolissimo-home" value="DOM" >');
}
$('#create-order-form-td-delivery-module').hide();
}
});
function updateRedirectableStatus() {
moduleID = $('select', '#create-order-form-td-payment_module_id').val();
url = '{url path="/admin/module/OrderCreation/redirectable-payment/"}';
$.ajax({
url: url + moduleID,
type: 'get',
dataType: 'json',
success: function (json) {
if (json.test === 1) {
$('#create-order-form-td-check-payment-redirect').show();
} else {
$('#create-order-form-td-check-payment-redirect').hide();
}
}
});
}
//Automatic product add during order creation
$('#add-cart-item').click(function (ev) {
$('#empty-order-row').hide();
var nb_products = $(".category-list").length;
$.get("{url path='/admin/module/OrderCreation/add-item'}/" + nb_products, function (data) {
$('#body-order-cart').append(data);
}, 'html');
});
$('#create-order-form-td-payment_module_id').on('change', function (clickEvent) {
updateRedirectableStatus();
});
function makeOption(value, target_pse_id, title)
{
return '<option value="' + value.id + '"'
+ (target_pse_id === value.id ? "selected " : "")
+ '>'
+ (title !== undefined ? title : value.ref) + ' ({intl l='stock:' d="ordercreation.bo.default" js=1} ' + value.quantity + ')'
+ '</option>';
}
$('#body-order-cart').on('change', '.category-list', function (clickEvent) {
var target_id = $(this).data('target');
var target_destination_id = $(this).data('destination');
var target_pse_id = $(this).data('pse-id');
$.ajax({
url: '{url path="/admin/module/OrderCreation/0/list-products/"}' + $(this).val() + '.xml',
type: 'get',
dataType: 'json',
success: function (json) {
var listOfOptions = '';
$.each(json, function (product_ref, product) {
if (product.pse_list.length === 1) {
listOfOptions += makeOption(product.pse_list[0], target_pse_id, product.title);
} else {
listOfOptions += '<optgroup label="'+ product.title + ' (' + product_ref +')">';
$.each(product.pse_list, function (pidx, pse) {
listOfOptions += makeOption(pse, target_pse_id);
});
listOfOptions += '</optgroup>';
}
});
var $targetId = $('#' + target_id);
$targetId.empty();
if (listOfOptions !== '') {
listOfOptions =
'<option value="">{intl l="Please select a product" d="ordercreation.bo.default"}</option>'
+ listOfOptions
;
$targetId.append(listOfOptions);
$('#' + target_destination_id).removeClass('hide');
$('#err_' + target_destination_id).addClass('hide');
} else {
$('#' + target_destination_id).addClass('hide');
$('#err_' + target_destination_id).removeClass('hide');
}
}
});
});
$('#body-order-cart').on('click', '.item-ajax-delete', function (clickEvent) {
$('#' + $(this).data('target')).remove();
if ($(".category-list").length === 0) {
$('#empty-order-row').show();
}
});
$('#type_order_form').change(function (ev) {
if ($(this).val() === 2) {
$('#type_order_info').removeClass('hide');
} else {
$('#type_order_info').addClass('hide');
}
});
var prefixUrl = document.location.href.split('/admin');
var $listDelivery = $('#list-delivery');
$('#delivery_address_id_form').change(function() {
if ($(this).val() !== '') {
$listDelivery.addClass('loading');
// update the country in the request
$.ajax({
type: "POST",
url: prefixUrl[0] + "/admin/module/OrderCreation/update/country/request",
data: {
address_id: $(this).val()
}
})
.done(function (response) {
$.ajax({
type: "GET",
url: prefixUrl[0] + "/order/deliveryModuleList?back=1"
})
.done(function (response) {
$listDelivery.removeClass('loading');
$listDelivery.html(response);
$('#list-delivery input.delivery-method').each(function () {
if ($(this).is(':checked')) {
$('#delivery-module').val($(this).val());
}
});
//clear both between all radio button
$('#list-delivery .radio').each(function () {
$(this).css('clear', 'both');
});
})
.error(function (error) {
$listDelivery.removeClass('loading');
if (typeof (error.statusTexddt) != 'undefined') {
$listDelivery.html('<div class="alert alert-danger">' + error.statusText + '</div>');
}
});
})
.error(function (error) {
$listDelivery.removeClass('loading');
if (typeof (error.statusTexddt) != 'undefined') {
$listDelivery.html('<div class="alert alert-danger">' + error.statusText + '</div>');
}
});
} else {
$('#delivery-module').val(0);
$listDelivery.removeClass('loading');
$listDelivery.html(
'<div class="alert alert-danger">' +
"{intl l='Choose a delivery address first' d='ordercreation.bo.default' js=1}" +
'</div>'
);
}
});
$listDelivery.on('change', '.delivery-method', function () {
$('#delivery-module').val($(this).val());
});
$('form', '#order_create_dialog').submit(function (ev) {
if ($(".category-list").length === 0) {
ev.preventDefault();
alert("{intl l='Please add at lead one product to this order.' d='ordercreation.bo.default' js=1}");
}
if ($(".js-change-delivery-method:checked").length === 0) {
ev.preventDefault();
alert("{intl l='You should select a shipping method to create an order.' d='ordercreation.bo.default' js=1}");
}
});
// Update shipping mode list
$("#delivery_address_id_form").trigger("change");
// Update all products in cart
$('.category-list').trigger("change");
// Update rediect to payment checkbox
updateRedirectableStatus();
});
</script>

View File

@@ -0,0 +1,31 @@
{loop type="auth" name="can_create" role="ADMIN" resource="admin.ordercreation" access="CREATE"}
<div class="row" id="order-creation-block">
<div class="col-md-12 general-block-decorator">
<div class="alert alert-info">
{intl l="You can create here an order for this customer right from your back-office." d="ordercreation.bo.default"}
</div>
<div class="row">
{if $order_creation_error}
<div class="col-md-12">
<div class="alert alert-danger">{$order_creation_error}</div>
</div>
{/if}
{if $order_creation_success}
<div class="col-md-12">
<div class="alert alert-success">{$order_creation_success}</div>
</div>
{/if}
<div class="col-md-12">
<a class="btn btn-default btn-primary action-btn" title="{intl l='Generate a new order' d='ordercreation.bo.default'}" href="#order_create_dialog" data-toggle="modal">
<span>{intl l="Generate a new order for this customer" d="ordercreation.bo.default"}</span>
</a>
</div>
</div>
</div>
</div>
{/loop}
{* -- Create a new order -------------------- *}
{include file="forms/create-order-form.html"}

View File

@@ -0,0 +1,152 @@
{form name="admin.order.creation.create.form"}
{* Capture the dialog body, to pass it to the generic dialog *}
{capture "order_create_dialog"}
{form_hidden_fields form=$form}
{form_field form=$form field='customer_id'}
<input type="hidden" name="{$name}" value="{$customer_id}">
{/form_field}
{form_field form=$form field='error_url'}
<input type="hidden" name="{$name}" value="{url path="/admin/customer/update" customer_id=$customer_id}"/>
{/form_field}
{form_field form=$form field='success_url'}
<input type="hidden" name="{$name}" value="{url path="/admin/customer/update" customer_id=$customer_id}#order-creation-block"/>
{/form_field}
<div class="row">
<div class="col-md-6">
{custom_render_form_field field='delivery_address_id'}
<select {form_field_attributes field='delivery_address_id'}>
<option value="" {if $value == $ID}selected="selected"{/if} >{intl l="Choose" d="ordercreation.bo.default"}</option>
{loop type="address" name="address-delivery" customer=$customer_id}
<option value="{$ID}" {if $value == $ID}selected="selected"{/if}>{$LABEL}</option>
{/loop}
</select>
{/custom_render_form_field}
</div>
<div class="col-md-6">
{custom_render_form_field field='invoice_address_id'}
<select {form_field_attributes field='invoice_address_id'}>
<option value="" {if $value == $ID}selected="selected"{/if} >{intl l="Choose" d="ordercreation.bo.default"}</option>
{loop type="address" name="address-invoice" customer=$customer_id}
<option value="{$ID}" {if $value == $ID}selected="selected"{/if}>{$LABEL}</option>
{/loop}
</select>
{/custom_render_form_field}
</div>
</div>
<div class="row">
<div class="col-md-6">
{render_form_field field='discount_type'}
</div>
<div class="col-md-6">
{custom_render_form_field field='discount_price'}
<div class="input-group">
<input {form_field_attributes field='discount_price'}>
{loop type="currency" name="sale.currencies" backend_context=1 default_only=1}
<span class="input-group-addon">{$SYMBOL} {intl l="or" d="ordercreation.bo.default"} %</span>
{/loop}
</div>
{/custom_render_form_field}
</div>
</div>
<table class="table table-condensed">
<caption><label>{intl l="List or ordered products" d="ordercreation.bo.default"}</label></caption>
<tbody id="body-order-cart">
{$productQuantities = []}
{form_field field='quantity'}
{$productQuantities = $value}
{/form_field}
{$indexProduct=0}
{form_field field='product_sale_element_id'}
{foreach $value as $pseId}
{include
file="../ajax/add-cart-item.html"
productId=$productId
position=$indexProduct
quantity=$productQuantities[$indexProduct]
}
{$indexProduct = $indexProduct+1}
{/foreach}
{/form_field}
{if $indexProduct == 0}
<tr id="empty-order-row">
<td colspan="2">
<div class="alert alert-info" style="margin-bottom: 0">
{intl l="There is no products in this order." d='ordercreation.bo.default'}
</div>
</td>
</tr>
{/if}
</tbody>
<tfoot>
<tr>
<td colspan="2" class="text-right">
<a id="add-cart-item" class="btn btn-default btn-primary action-btn" title="{intl l='Add product to this order' d='ordercreation.bo.default'}" href="#" data-toggle="modal">
<span>{intl l="Add product to order" d="ordercreation.bo.default"}</span>
</a>
</td>
</tr>
</tfoot>
</table>
<div class="row">
<div class="col-md-12">
{custom_render_form_field field='delivery-module'}
<div id="list-delivery">
<div class="alert alert-danger">
{intl l="Please select a delivery adresse to display shipping options" d="ordercreation.bo.default"}
</div>
</div>
{/custom_render_form_field}
</div>
<div class="col-md-6">
<div id="create-order-form-td-payment_module_id">
{custom_render_form_field field='payment_module_id'}
<select {form_field_attributes field='payment_module_id'}>
{loop type="module" name="module-payment" module_type="3" active="1"}
<option value="{$ID}">{$TITLE}</option>
{/loop}
</select>
{/custom_render_form_field}
</div>
</div>
<div class="col-md-6">
<div "id="create-order-form-td-check-payment-redirect">
{render_form_field field='redirects_payment'}
</div>
</div>
</div>
<div class="hidden" id="mode-socolissimo"></div>
{/capture}
{include
file = "includes/generic-create-dialog.html"
dialog_id = "order_create_dialog"
dialog_title = {intl l="Generate a new order" d="ordercreation.bo.default"}
dialog_body = {$smarty.capture.order_create_dialog nofilter}
dialog_ok_label = {intl l="Save" d='ordercreation.bo.default'}
ok_button_id = "submit_order_creation"
form_action = {url path='/admin/module/OrderCreation/order/create'}
form_enctype = {form_enctype form=$form}
form_error_message = $form_error_message
}
{/form}

View File

@@ -0,0 +1,106 @@
<div class="row">
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-12 title title-without-tabs">
{intl d='ordercreation.bo.default' l="Configuration du module de création de commande en BO"}
</div>
</div>
<div class="form-container">
<div class="row">
<div class="col-md-12">
{form name="admin.order.creation.form.configure"}
<form action="{url path="/admin/module/OrderCreation/configure"}" method="post">
{form_hidden_fields form=$form}
{include file = "includes/inner-form-toolbar.html"
hide_flags = true
page_url = "{url path='/admin/module/OrderCreation'}"
close_url = "{url path='/admin/modules'}"
}
{if $form_error}
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger">{$form_error_message}</div>
</div>
</div>
{/if}
<div class="row">
<div class="col-sm-6">
{form_field field="order_creation_delivery_module_id"}
<div class="form-group {if $error}has-error{/if}">
<label for="{$label_attr.for}" class="control-label">{$label} : </label>
<input type="hidden" name="{$name}" id="delivery-module" value="{$value}" />
<select class="form-control" id="delivery_module_id_select">
<option value="">{intl d='ordercreation.bo.default' l='No default delivery module (default)'}</option>
{loop type="module" name="delivery-module" backend_context=1 module_type="2"}
<option value="{$ID}" {if $value == $ID}selected="selected"{/if}>{$CODE} - {$TITLE}</option>
{/loop}
</select>
</div>
{/form_field}
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
</div>
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-12 title title-without-tabs">
{intl d='ordercreation.bo.default' l="Configuration de redirection de paiement"}
</div>
</div>
<form action="{url path="/admin/module/OrderCreation/configure-redirects-payment"}" method="post">
{form name="admin.order.redirects.payment.form"}
{form_hidden_fields form=$form}
{if $form_error}
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger">{$form_error_message}</div>
</div>
</div>
{/if}
<div class="row">
<div class="col-sm-6">
{form_field field="order_creation_redirects_payment"}
<label for="{$label_attr.for}" class="control-label">{$label} : </label>
<select name="{$name}[]" id="" multiple class="form-control">
{loop type="module" name="delivery-module" backend_context=1 module_type="3" active="1"}
{$value}
<option value="{$ID}" {if $ID|in_array:$value|default:[]} selected="selected"{/if}>{$CODE} - {$TITLE}</option>
{/loop}
</select>
{/form_field}
</div>
</div>
{include file = "includes/inner-form-toolbar.html"
hide_flags = true
page_url = "{url path='/admin/module/OrderCreation'}"
close_url = "{url path='/admin/modules'}"
}
</form>
{/form}
</div>
</div>
{block name="javascript-last-call"}
<script type="text/javascript">
window.onload = function () {
$('#delivery_module_id_select').on('change', function () {
$('#delivery-module').val($(this).val());
});
};
</script>
{/block}