305 lines
12 KiB
PHP
305 lines
12 KiB
PHP
<?php
|
|
|
|
namespace KupShop\POSBundle\Util;
|
|
|
|
use FilipSedivy\EET\Utils\UUID;
|
|
use KupShop\AdminBundle\Util\ActivityLog;
|
|
use KupShop\ContentBundle\View\Exception\ValidationException;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosOrderPaymentsCollection;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosPaymentCollection;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Order\PosOrderResponse;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Payments\PosConfirmPayment;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Payments\PosOrderPayment;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Payments\PosPayment;
|
|
use KupShop\GraphQLBundle\ApiPos\Types\Payments\PosPaymentsStatusUpdate;
|
|
use KupShop\GraphQLBundle\ApiShared\ApiUtil;
|
|
use KupShop\KupShopBundle\Context\CurrencyContext;
|
|
use KupShop\KupShopBundle\Context\PosContext;
|
|
use KupShop\KupShopBundle\Util\Database\QueryHint;
|
|
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
|
|
use KupShop\OrderingBundle\Exception\OrderingException;
|
|
use KupShop\POSBundle\Event\PosOrderEvent;
|
|
use KupShop\WarehouseBundle\Util\StoreItemWorker;
|
|
use Query\Operator;
|
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
|
|
|
class PosPaymentUtil
|
|
{
|
|
use \DatabaseCommunication;
|
|
|
|
public function __construct(
|
|
protected PosUtil $posUtil,
|
|
protected CurrencyContext $currencyContext,
|
|
protected PosContext $posContext,
|
|
protected EventDispatcherInterface $eventDispatcher,
|
|
protected ?PosWarehouseUtil $posWarehouseUtil = null,
|
|
protected ?StoreItemWorker $storeItemWorker = null,
|
|
) {
|
|
}
|
|
|
|
public function getOrderPayments(int $idOrder, ?\Order $order = null): PosOrderPaymentsCollection
|
|
{
|
|
if (!$order) {
|
|
$order = new \Order();
|
|
$order->createFromDB($idOrder);
|
|
}
|
|
|
|
$payments = [];
|
|
foreach ($order->getPaymentsArray() as $payment) {
|
|
$payments[] = new PosOrderPayment(payment: $payment);
|
|
}
|
|
|
|
return new PosOrderPaymentsCollection(
|
|
items: $payments
|
|
);
|
|
}
|
|
|
|
public function setPaymentStatus(int $idOrder, array $payments): PosPaymentsStatusUpdate
|
|
{
|
|
$order = new \Order();
|
|
$order->createFromDB($idOrder);
|
|
$classPayment = $order->getDeliveryType()->getPayment();
|
|
$classPayment->setOrder($order);
|
|
|
|
foreach ($payments as $payment) {
|
|
if (in_array($payment->status, [\Payment::STATUS_PENDING, \Payment::STATUS_FINISHED, \Payment::STATUS_CREATED, \Payment::STATUS_STORNO])) {
|
|
$classPayment->setStatus($payment->status, $payment->uuid);
|
|
|
|
if ($payment->terminal ?? false) {
|
|
if (!$classPayment->paymentId) {
|
|
throw new ValidationException('Proběhlo potvrzení platby, ale není nastaveno ID platby');
|
|
}
|
|
sqlQueryBuilder()
|
|
->update('order_payments')
|
|
->set('payment_data', 'JSON_MERGE(payment_data, :terminalData)')
|
|
->setParameter('terminalData', json_encode(['terminal' => $payment->terminal]))
|
|
->andWhere(Operator::equals(['id' => $classPayment->paymentId]))
|
|
->execute();
|
|
}
|
|
}
|
|
}
|
|
|
|
$results = [];
|
|
$paymentArray = null;
|
|
$isPaid = null;
|
|
$remainingPayment = null;
|
|
QueryHint::withRouteToMaster(function () use ($order, &$paymentArray, &$isPaid, &$remainingPayment) {
|
|
$paymentArray = $order->getPaymentsArray();
|
|
$isPaid = $order->isPaid();
|
|
$remainingPayment = $order->getRemainingPayment();
|
|
});
|
|
|
|
foreach ($paymentArray as $payment) {
|
|
$results[] = new PosOrderPayment(payment: $payment);
|
|
}
|
|
|
|
return new PosPaymentsStatusUpdate(
|
|
isPaid: $isPaid,
|
|
remainingPayment: $remainingPayment,
|
|
posOrderPayments: new PosOrderPaymentsCollection($results),
|
|
);
|
|
}
|
|
|
|
public function confirmPayment(int $idOrder, string $uuidPayment, string $paidPrice, string $methodPayment, ?string $terminal = null): PosConfirmPayment
|
|
{
|
|
$order = new \Order();
|
|
$order->createFromDB($idOrder);
|
|
$order->fetchItems();
|
|
|
|
$exceptionMessage = null;
|
|
if ($uuidPayment != 'UNDEFINED') {
|
|
$classPayment = $order->getDeliveryType()->getPayment();
|
|
$classPayment->setOrder($order);
|
|
|
|
// Pokud spadne generování unikátního čísla faktury, tak se nesmí zahodit nic co se stane po přepnutí statusu platby
|
|
try {
|
|
$classPayment->setStatus(\Payment::STATUS_FINISHED, $uuidPayment);
|
|
} catch (OrderingException $exception) {
|
|
$exceptionMessage = $exception->getMessage();
|
|
}
|
|
|
|
if ($terminal) {
|
|
if (!$classPayment->paymentId) {
|
|
throw new ValidationException('Proběhlo potvrzení platby, ale není nastaveno ID platby');
|
|
}
|
|
sqlQueryBuilder()
|
|
->update('order_payments')
|
|
->set('payment_data', 'JSON_MERGE(payment_data, :terminalData)')
|
|
->setParameter('terminalData', json_encode(['terminal' => $terminal]))
|
|
->andWhere(Operator::equals(['id' => $classPayment->paymentId]))
|
|
->execute();
|
|
}
|
|
}
|
|
|
|
if ($order->isPaid()) {
|
|
$this->eventDispatcher->dispatch(new PosOrderEvent($order->getPurchaseState(), $this->posContext->getActiveId(), $order), PosOrderEvent::ORDER_PAID_BY_POS);
|
|
}
|
|
|
|
if ($order->isPaid() && toDecimal($paidPrice)->isZero() && !$order->getDeliveryId()) {
|
|
$this->changeOrderDelivery(
|
|
posId: $this->posContext->getActiveId(),
|
|
order: $order,
|
|
paymentMethod: $methodPayment,
|
|
);
|
|
}
|
|
|
|
return new PosConfirmPayment(
|
|
posOrderResponse: new PosOrderResponse(
|
|
idOrder: $order->id,
|
|
noOrder: $order['order_no'],
|
|
isPaid: $order->isPaid(),
|
|
remainingPayment: $order->getRemainingPayment(),
|
|
status: $order->status,
|
|
uuidPayment: $uuidPayment
|
|
),
|
|
saved: true,
|
|
exception: $exceptionMessage
|
|
);
|
|
}
|
|
|
|
public function createNonOrderPayment(int $idPos, string $price, string $note, $method): int
|
|
{
|
|
global $adminID;
|
|
|
|
return sqlGetConnection()->transactional(function () use ($adminID, $idPos, $price, $note, $method) {
|
|
$this->insertSQL('order_payments', [
|
|
'price' => $price,
|
|
'method' => $method,
|
|
'note' => $note,
|
|
'date' => date('Y-m-d H:i:s'),
|
|
'admin' => !empty($adminID) ? $adminID : null,
|
|
]);
|
|
|
|
$id_payment = sqlInsertId();
|
|
$this->insertSQL('pos_payments_relation', [
|
|
'id_pos' => $idPos,
|
|
'id_payment' => $id_payment,
|
|
]);
|
|
|
|
return 200;
|
|
});
|
|
}
|
|
|
|
public function getPosPaymentList(int $idPos, int $pageDivide, int $page, ?string $method = null): PosPaymentCollection
|
|
{
|
|
return QueryHint::withRouteToMaster(function () use ($idPos, $pageDivide, $page, $method) {
|
|
$qb = $this->getQueryPaymentLoader($idPos, $pageDivide, $page);
|
|
$next = $this->getQueryPaymentLoader($idPos, $pageDivide, $page + 1)->execute()->fetchAll();
|
|
|
|
if (!empty($method)) {
|
|
$qb->where('pos.method = ?')->setParameter(0, $method);
|
|
}
|
|
|
|
$qb2 = sqlQueryBuilder()
|
|
->select('SUM(price) as in_pos')
|
|
->from('order_payments', 'op')
|
|
->andWhere(Operator::orX(
|
|
Operator::equals(['op.method' => \Payment::METHOD_CASH]),
|
|
Operator::equals(['op.method' => \Payment::METHOD_CASH_INSERTION]),
|
|
Operator::equals(['op.method' => \Payment::METHOD_CASH_SELECTION]),
|
|
Operator::equals(['op.method' => \Payment::METHOD_EET_INVOICE_CASH]),
|
|
))
|
|
->leftJoin('op', 'pos_payments_relation', 'ppr', 'ppr.id_payment = op.id')
|
|
->andWhere(Operator::equals(['op.status' => \Payment::STATUS_FINISHED]))
|
|
->andWhere('ppr.id_pos = :pos_id')
|
|
->setParameter('pos_id', $idPos);
|
|
|
|
$dataCollection = [];
|
|
|
|
$baseCurrencySymbol = $this->currencyContext->getDefault()->getSymbol();
|
|
|
|
foreach ($qb->execute()->fetchAll() as $row) {
|
|
$dataCollection[] = new PosPayment(
|
|
$row['id'],
|
|
ApiUtil::prepareDateTimeFromDB($row['date'])->format('H:i:s d.m.Y'),
|
|
$row['id_order'],
|
|
$row['price'],
|
|
'',
|
|
\Pos::METHODS[$row['method']],
|
|
$row['note'],
|
|
$row['admin'],
|
|
$row['currency_symbol'] ?: $baseCurrencySymbol
|
|
);
|
|
}
|
|
|
|
return new PosPaymentCollection(
|
|
$dataCollection,
|
|
sqlFetchArray($qb2->execute())['in_pos'],
|
|
$page,
|
|
($page - 1) > 0,
|
|
count($next) > 0
|
|
);
|
|
});
|
|
}
|
|
|
|
private function getQueryPaymentLoader($idPos, $pageDivide, $page)
|
|
{
|
|
$qb = sqlQueryBuilder()
|
|
->select('pos.id', 'pos.note', 'pos.price', 'a.login as admin', 'pos.method', 'pos.id_order', 'date')
|
|
->from('order_payments', 'pos')
|
|
->leftJoin('pos', 'admins', 'a', 'pos.admin=a.id')
|
|
->leftJoin('pos', 'pos_payments_relation', 'ppr', 'ppr.id_payment = pos.id')
|
|
->andWhere('ppr.id_pos = :pos_id')
|
|
->andWhere(Operator::equals(['pos.status' => \Payment::STATUS_FINISHED]))
|
|
->orderBy('pos.date', 'DESC')
|
|
->setParameter('pos_id', $idPos)
|
|
->setMaxResults($pageDivide)
|
|
->setFirstResult($pageDivide * ($page - 1));
|
|
if (findModule(\Modules::CURRENCIES)) {
|
|
$qb->addSelect('c.symbol as currency_symbol')
|
|
->leftJoin('pos', 'orders', 'o', 'o.id=pos.id_order')
|
|
->leftJoin('o', 'currencies', 'c', 'o.currency=c.id');
|
|
} else {
|
|
$qb->addSelect('null as currency_symbol');
|
|
}
|
|
|
|
return $qb;
|
|
}
|
|
|
|
public function changeOrderDelivery(int $posId, \Order $order, string $paymentMethod): void
|
|
{
|
|
$deliveryType = $this->posUtil->getPosDeliveryType($posId, $paymentMethod);
|
|
$order->id_delivery = $deliveryType['id'];
|
|
$order->delivery_type = $deliveryType['name'];
|
|
$order->updateSQL('orders', ['id_delivery' => $deliveryType['id'], 'delivery_type' => $deliveryType['name']], ['id' => $order->id]);
|
|
}
|
|
|
|
public function createOrderPayment(\Order $order, PurchaseState $purchaseState, bool $purchase = false): ?string
|
|
{
|
|
$methodPayment = $purchaseState->getCustomData('methodPayment');
|
|
if ($methodPayment == 'UNDEFINED' || $methodPayment == 'INVOICE') {
|
|
return null;
|
|
}
|
|
|
|
$paidPrice = $purchaseState->getCustomData('paidPrice');
|
|
try {
|
|
return sqlGetConnection()->transactional(function () use ($order, $paidPrice, $methodPayment) {
|
|
$idPos = $this->posContext->getActiveId();
|
|
$this->changeOrderDelivery(posId: $idPos, order: $order, paymentMethod: $methodPayment);
|
|
$classPayment = $order->getDeliveryType()->getPayment();
|
|
$classPayment->setOrder($order);
|
|
$uuid = UUID::v4();
|
|
$classPayment->createPayment($uuid, toDecimal($paidPrice));
|
|
if ($classPayment->paymentId) {
|
|
sqlQueryBuilder()
|
|
->insert('pos_payments_relation')
|
|
->values([
|
|
'id_pos' => $idPos,
|
|
'id_payment' => $classPayment->paymentId,
|
|
])
|
|
->execute();
|
|
|
|
return $uuid;
|
|
}
|
|
|
|
return null;
|
|
});
|
|
} catch (\Exception|\Throwable $e) {
|
|
$id = addActivityLog(ActivityLog::SEVERITY_NOTICE, ActivityLog::TYPE_COMMUNICATION, "POS API: vytvoření platby selhalo s chybou: {$e->getMessage()}");
|
|
$order->logHistory("<a href=\"javascript:nw('reportActivities', '{$id}', '');\"> Vytvoření platby z pokladny skončilo s chybou.</a>");
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
}
|