Files
kupshop/bundles/KupShop/ContentBundle/View/OrderEditView.php
2025-08-02 16:30:27 +02:00

511 lines
18 KiB
PHP

<?php
namespace KupShop\ContentBundle\View;
use KupShop\GraphQLBundle\EventListener\JsShopRefreshListener;
use KupShop\KupShopBundle\Context\ContextManager;
use KupShop\KupShopBundle\Exception\RedirectException;
use KupShop\KupShopBundle\Util\Functional\Mapping;
use KupShop\KupShopBundle\Views\Traits\RequestTrait;
use KupShop\KupShopBundle\Views\View;
use KupShop\OrderDiscountBundle\Util\DiscountManager;
use KupShop\OrderingBundle\Event\OrderEvent;
use KupShop\OrderingBundle\OrderDelivery;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
use KupShop\ProductsChargesBundle\Actions\Frontend\OrdersChargesHandler;
use Query\Operator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Contracts\Service\Attribute\Required;
class OrderEditView extends View
{
use RequestTrait;
protected string $smartyFallback = 'account';
protected string $entrypoint = 'account';
protected $template = 'orderEdit.tpl';
protected $orderId;
protected $user;
/** @var \Order|null */
protected $order;
/** @var OrderDelivery */
protected $orderDelivery;
#[Required]
public PurchaseUtil $purchaseUtil;
public DiscountManager $discountManager;
#[Required]
public OrderInfo $orderInfo;
public function __construct(
protected SessionInterface $session,
private ContextManager $contextManager,
private EventDispatcherInterface $eventDispatcher,
private \Cart $cart,
) {
$this->user = \User::getCurrentUser();
}
public function getResponse(?Request $request = null)
{
if (!findModule('order_edit')) {
redirection('MODUL_NOT_FOUND');
}
if ($this->orderId === null || $this->orderId == 0) {
return new RedirectResponse(
createScriptURL([
'URL' => 'launch.php',
's' => 'orders',
'ESCAPE' => 'NO',
])
);
}
$this->checkUser();
return parent::getResponse($request);
}
public function getBodyVariables()
{
$vars = parent::getBodyVariables();
$this->contextManager->activateOrder($this->getOrder(), function () use (&$vars) {
$vars += $this->editOrder();
});
return $vars;
}
public function getTitle()
{
return str_replace('%ORDERNO', $this->order->order_no, translate('title', 'orderView'));
}
public function getBreadcrumbs()
{
$url = createScriptURL([
'URL' => 'launch.php',
's' => 'orders',
]);
return getReturnNavigation(-1, 'NO_TYPE', [['link' => $url, 'text' => translate('returnNav', 'orderView')[0]], ['text' => translate('returnNav', 'orderView')[1]]]);
}
public function getWpjToolbar()
{
$arr = [
'url' => getAdminUrl('orders', ['ID' => $this->orderId]),
'title' => 'Upravit objednávku',
];
return array_merge(parent::getWpjToolbar(), $arr);
}
private function getOrder()
{
if (!$this->order) {
$this->order = new \Order();
$this->order->setEditMode();
$this->order->createFromDB($this->orderId);
}
return $this->order;
}
/** @required */
public function setOrderDelivery(OrderDelivery $orderDelivery)
{
$this->orderDelivery = $orderDelivery;
}
public function recalculateDelivery()
{
return $this->orderDelivery->recalculateDelivery($this->order, $this->order->getDeliveryId());
}
private function editOrder()
{
$pageVars = [];
$originalOrder = new \Order();
$originalOrder->createFromDB($this->orderId);
$pageVars['order'] = $this->order;
$pageVars['editable'] = $this->order->isEditable();
if ($pageVars['editable'] > 0) {
// Check there are no negative pieces (returns)
foreach ($originalOrder->fetchItems() as $item) {
if ($item['pieces'] < 0) {
$pageVars['editable'] = 0;
}
}
}
if ($pageVars['editable'] == 0) {
$this->addErrorMessage('Tato objednávka bohužel nejde upravovat.');
throw new RedirectException(
createScriptURL([
'URL' => 'launch.php',
's' => 'orderView',
'IDo' => $this->orderId,
'cf' => $this->request->get('cf'),
])
);
}
if ($pageVars['editable'] == 1) {
sqlQuery('DELETE FROM '.getTableName('order_edit')." WHERE id_order='{$this->orderId}'");
sqlQuery('INSERT INTO '.getTableName('order_edit').'
SELECT NULL, id, id_order, id_product, id_variation, id_parent, pieces, pieces_reserved, piece_price, total_price, descr, tax, NOW(), note, discount '
.(findModule(\Modules::PRODUCTS, \Modules::SUB_PRICE_BUY) ? ', price_buy' : '').'
FROM '.getTableName('order_items')."
WHERE id_order='{$this->orderId}' AND total_price != 0");
$pageVars['editable'] = 2;
}
if (in_array($this->getAcn(), ['recount', 'deleteItem', 'send', 'addCart'])) {
switch ($this->getAcn()) {
case 'addCart':
$this->addCart();
break;
case 'deleteItem':
$this->deleteItem();
break;
default:
$pieces = $this->getPieces();
// update item
foreach ($pieces as $IDitem => $piece) {
if (is_numeric($piece) && intval($piece) >= 0) {
$this->order->updateItem($IDitem, intval($piece));
}
}
}
}
// order_discounts gifts
// TODO: Tohle budeme moci vyhodit, jakmile se začnou obecně ukládat na PurchaseState data z `$data['handled']` - Action Handlerů.
$actionHandlersData = getVal('action_handler');
$charges = null;
if (!$actionHandlersData) {
if ($gift = $this->order->getPurchaseState()->getCustomData('gift')) {
$qb = sqlQueryBuilder()->select('id, id_order_discount')->from('order_discounts_actions')
->where(Operator::inIntArray(array_keys($gift), 'id_order_discount'))
->andWhere(Operator::equals(['type' => 'gift']))->execute();
$gift_actions = sqlFetchAll($qb, ['id' => 'id_order_discount']);
foreach ($gift_actions as $id_action => $id_order_discount) {
$data = array_pop($gift[$id_order_discount]);
if ($data['selected']) {
if (empty($data['id_variation'])) {
$data = ['gift' => $data['id_product']];
} else {
$data['gift'] = $data['id_variation'];
}
}
$actionHandlersData[$id_action] = $data;
}
}
$charges = array_filter($this->order->fetchItems(),
fn ($item) => (($item['note']['item_type'] ?? null) == 'orders_charge') && !empty($item['note']['id_charge']));
$charges = Mapping::mapKeys($charges, fn ($k, $item) => [$item['note']['id_charge'], $item]);
}
$this->discountManager->setPurchaseState($this->order->getPurchaseState());
if ($actionHandlersData) {
$this->discountManager->setActionHandlersData($actionHandlersData);
}
$purchaseState = $this->discountManager->recalculate();
if ($handlers = $this->discountManager->getActionHandlers()) {
$purchaseState->setDiscountHandlers($handlers);
$ordersChargesHandlers = array_filter($handlers, function ($handler) {
return $handler instanceof OrdersChargesHandler;
});
if ($ordersChargesHandlers && $charges) {
foreach ($ordersChargesHandlers as $handler) {
$id_discount = $handler->getOrderDiscount()?->getId();
if ($id_discount && in_array($id_discount, $purchaseState->getUsedDiscounts())) {
$vars = $handler->getVars();
$id_charge = $vars['data']['id_charge'] ?? null;
if ($id_charge && array_key_exists($id_charge, $charges)) {
$data = ['checked' => 'Y'];
$handler->handleData($data);
$actionHandlersData[$handler->getActionId()] = $data;
$this->discountManager->setActionHandlersData($actionHandlersData);
}
}
}
}
}
$this->order->total_price = $purchaseState->getTotalPrice()->getPriceWithVat();
$this->order->total_price_without_vat = $purchaseState->getTotalPrice()->getPriceWithoutVat();
if (in_array($this->getAcn(), ['recount', 'deleteItem', 'send', 'addCart'])) {
// Check for products not on stock
$failedProducts = $this->checkProductsInStore();
$pageVars['failedProducts'] = $failedProducts;
// Check for delivery exception
try {
$this->recalculateDelivery();
} catch (\Exception $e) {
$pageVars['failedDelivery'] = $e->getMessage();
}
if (empty($failedProducts) && empty($pageVars['failedDelivery'])) {
// send
if ($this->getAcn() == 'send') {
sqlGetConnection()->transactional(function () {
$this->order->setPurchaseState(null);
$this->discountManager->setPurchaseState($this->order->getPurchaseState());
$purchaseState = $this->discountManager->recalculate();
// Musím vynulovat IDčka položek, protože by se pak míchaly dohromady IDčka order_item a order_edit tabulek
foreach ($purchaseState->getPurchaseItems() as $purchaseItem) {
$purchaseItem->setId(null);
}
$this->purchaseUtil->createOrderFromPurchaseState($purchaseState, $this->order->id);
if ($gift = $this->order->getPurchaseState()->getCustomData('gift')) {
$discountsData = $this->order->getData('discounts');
$discountsData['gift'] = $gift;
$this->order->setData('discounts', $discountsData);
}
// Clean edit items
sqlQuery('DELETE FROM order_edit WHERE id_order=:id_order', ['id_order' => $this->orderId]);
$this->order->changeStatus(0, 'Uživatel editoval objednávku', false);
$this->sendOrderEvent($this->order, OrderEvent::USER_EDITED);
});
}
if (!isAjax()) {
throw new RedirectException(
createScriptURL([
'URL' => 'launch.php',
's' => 'orderView',
'IDo' => $this->orderId,
'edit' => $this->getAcn() != 'send',
'cf' => $this->request->get('cf'),
])
);
}
}
} else {
// Check for products not on stock
$failedProducts = $this->checkProductsInStore();
$pageVars['failedProducts'] = $failedProducts;
// Check for delivery exception
try {
$this->recalculateDelivery();
} catch (\Exception $e) {
$pageVars['failedDelivery'] = $e->getMessage();
}
}
if ($this->getAcn() == 'storno') {
$this->storno();
}
if ($this->getAcn() == 'cancel') {
$this->cancel();
}
$this->order->fetchItems();
$this->order->fetchItemsPhoto();
return $pageVars;
}
public function sendOrderEvent($order, $eventName)
{
$event = new OrderEvent($order);
$this->eventDispatcher->dispatch($event, $eventName);
return $event;
}
/**
* @throws RedirectException
*/
private function cancel()
{
sqlQuery('DELETE FROM '.getTableName('order_edit')." WHERE id_order='{$this->orderId}'");
throw new RedirectException(
createScriptURL([
'URL' => 'launch.php',
's' => 'orderView',
'IDo' => $this->orderId,
'cf' => $this->request->get('cf'),
])
);
}
/**
* @throws RedirectException
*/
protected function storno()
{
$this->order->setEditMode(false);
$this->order->storno();
throw new RedirectException(
createScriptURL([
'URL' => 'launch.php',
's' => 'orderView',
'IDo' => $this->orderId,
'cf' => $this->request->get('cf'),
])
);
}
protected function checkProductsInStore()
{
if (\Settings::getDefault()->order_availability !== \Settings::ORDER_AVAILABILITY_ALL) {
$qb = sqlQueryBuilder();
$qb->select('p.id, pv.id as id_variation, p.title, pv.title AS variation_title')
->from('order_edit', 'c')
->leftJoin('c', 'order_items', 'oi', "oi.id_order IS NULL OR (oi.id_order = {$this->orderId}
AND (c.id_product = oi.id_product AND ((c.id_variation IS NULL AND oi.id_variation IS NULL) OR c.id_variation = oi.id_variation)))")
->leftJoin('c', 'products', 'p', 'c.id_product = p.id')
->leftJoin('c', 'products_variations', 'pv', 'c.id_variation=pv.id')
->where('p.id IS NOT NULL')
->andWhere(\Query\Operator::equals(['c.id_order' => $this->orderId]))
->andWhere(\Query\Product::getProductInStock($qb).' < (c.pieces - IFNULL(oi.pieces, 0))');
if (findModule(\Modules::PRODUCTS, 'order_not_in_store')) {
$qb->andWhere(\Query\Operator::not('FIND_IN_SET("PR", p.campaign)'));
}
$failedProducts = sqlFetchAll($qb, 'id');
return $failedProducts;
}
return null;
}
/**
* @throws RedirectException
*/
private function addCart()
{
// projit kosik
$where = ($this->user) ? ['id_user' => $this->user->id] : ['user_key' => \Cart::getCartID()];
sqlStartTransaction();
$SQL_cart = sqlQueryBuilder()->select('pieces, id_variation, id_product, note')
->from('cart')->where(\Query\Operator::equals($where))
->orderBy('date', 'DESC')->execute();
foreach ($SQL_cart as $row) {
$this->order->insertItem($row['id_product'], $row['id_variation'], $row['pieces'], $row['note']);
}
// Clean shopping cart
sqlQueryBuilder()->delete('cart')->where(\Query\Operator::equals($where))->execute();
sqlFinishTransaction();
if (findModule(\Modules::JS_SHOP)) {
$this->session->set(JsShopRefreshListener::SESSION_NAME, true);
}
$this->cart->invalidatePurchaseState();
}
private function deleteItem()
{
$IDitem = intval(getVal('IDi'));
$this->order->deleteItem($IDitem);
}
private function getPieces()
{
return getVal('pieces', null, []);
}
private function getAcn()
{
return getVal('acn', null, getVal('act'));
}
private function checkUser()
{
if ($this->user) {
$SQL = sqlQuery('SELECT id
FROM '.getTableName('orders')."
WHERE id='".$this->orderId."' AND id_user='".$this->user->id."'
LIMIT 1");
if (sqlNumRows($SQL) == 0) {
redirection('INDEX');
}
sqlFreeResult($SQL);
} else {
$cf = $this->request->get('cf');
if ($cf === null) {
redirection('LOGIN');
}
$qb = sqlQueryBuilder()
->select('id')
->from('orders')
->where('id=:IDo')
->setMaxResults(1)
->setParameter('IDo', $this->orderId)
->execute();
$code = null;
if ($qb->rowCount() == 1) {
$order = new \Order($this->orderId);
$code = $order->getSecurityCode();
}
if ($code != $cf || $qb->rowCount() == 0) {
throw new RedirectException(
createScriptURL([
'URL' => 'launch.php',
's' => 'orderView',
'IDo' => $this->orderId,
'cf' => $cf,
])
);
}
}
}
/**
* @return $this
*/
public function setOrderId($orderId)
{
$this->orderId = intval($orderId);
return $this;
}
#[Required]
public function setDiscountManager(?DiscountManager $discountManager = null): void
{
$this->discountManager = $discountManager;
}
}