Files
kupshop/bundles/KupShop/POSBundle/Util/PosUtil.php
2025-08-02 16:30:27 +02:00

306 lines
12 KiB
PHP

<?php
namespace KupShop\POSBundle\Util;
use KupShop\GraphQLBundle\ApiAdmin\Types\Collection\ProductCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosIframeCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosModulesCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosOrderHistoryCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosOrderStatusCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosPermissionCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Collection\PosVatCollection;
use KupShop\GraphQLBundle\ApiPos\Types\Order\PosOrderHistoryItem;
use KupShop\GraphQLBundle\ApiPos\Types\Order\PosOrderStatus;
use KupShop\GraphQLBundle\ApiPos\Types\Pos;
use KupShop\GraphQLBundle\ApiPos\Types\PosAdditionalData;
use KupShop\GraphQLBundle\ApiPos\Types\PosDeliverySetting;
use KupShop\GraphQLBundle\ApiPos\Types\PosIframe;
use KupShop\GraphQLBundle\ApiPos\Types\PosTerminal;
use KupShop\GraphQLBundle\ApiPos\Types\PosVat;
use KupShop\GraphQLBundle\ApiPos\Types\Stats\PosPaymentStats;
use KupShop\GraphQLBundle\ApiPos\Types\Stats\PosStats;
use KupShop\GraphQLBundle\ApiPos\Types\Stats\PosStatVatPrice;
use KupShop\GraphQLBundle\ApiPos\Types\Stats\PosSummaryStats;
use KupShop\GraphQLBundle\ApiShared\Types\DateInterval;
use KupShop\KupShopBundle\Context\CountryContext;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Context\PosContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\POSBundle\Email\InvoiceEmail;
use Query\Operator;
use Symfony\Component\DependencyInjection\ServiceLocator;
class PosUtil
{
private const ORDER_HISTORY_PER_PAGE = 10;
/** @var CurrencyContext */
private $currencyContext;
private CountryContext $countryContext;
/** @var PosTabInterface[] */
private ServiceLocator $serviceLocator;
public function __construct(ServiceLocator $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
$this->currencyContext = ServiceContainer::getService(CurrencyContext::class);
$this->countryContext = ServiceContainer::getService(CountryContext::class);
}
public function getPointsOfSale(): PosCollection
{
$qb = sqlQueryBuilder()
->select('id, name')
->from('pos')
->execute()
->fetchAll();
$posCollection = [];
foreach ($qb as $item) {
$posCollection[] = new Pos(
intval($item['id']),
$item['name']
);
}
return new PosCollection($posCollection);
}
public function getFastAccessProducts(int $idPos): ProductCollection
{
$fastAccessIds = sqlQueryBuilder()
->select("JSON_EXTRACT(data, '$.fast_access_products') as products")
->from('pos')
->where('id = :id_pos')
->setParameter('id_pos', $idPos)
->execute()
->fetch();
$fastAccessProducts = new \KupShop\CatalogBundle\ProductList\ProductCollection();
foreach (json_decode($fastAccessIds['products']) as $id) {
$product = new \Product();
$product->createFromDB($id);
$product->fetchImages(1);
$fastAccessProducts->set($id, $product);
}
return new ProductCollection($fastAccessProducts);
}
public function getOrderHistory(int $idPos, int $page): PosOrderHistoryCollection
{
// op.method konstanty jsou z class.Payment.php
$qb = sqlQueryBuilder()
->select('o.order_no, o.date_created, u.name, u.surname, u.email, o.id, SUM(op.price) as paid, o.total_price, u.id as user_id, o.status, o.status_storno')
->addSelect("
GROUP_CONCAT(
CASE
WHEN op.method = 1 THEN 'Hotově'
WHEN op.method = 2 THEN 'Kartou'
WHEN op.method = 3 THEN 'Na fakturu'
ELSE 'Neznámý způsob'
END
SEPARATOR ', '
) AS payment_methods
")
->from('orders', 'o')
->leftJoin('o', 'users', 'u', 'o.id_user = u.id')
->leftJoin('o', 'order_payments', 'op', 'o.id = op.id_order AND op.status = :payment_status_finished')
->setParameter('payment_status_finished', \Payment::STATUS_FINISHED)
->where('o.pos = :id_pos')
->groupBy('o.order_no, o.date_created')
->orderBy('o.date_created DESC, o.order_no')
->setParameter('id_pos', $idPos)
->setMaxResults(10)
->setFirstResult(($page - 1) * static::ORDER_HISTORY_PER_PAGE);
if (findModule(\Modules::CURRENCIES)) {
$qb->leftJoin('o', 'currencies', 'c', 'o.currency=c.id')
->addSelect('c.symbol as currency_symbol');
} else {
$qb->addSelect("'Kč' as currency_symbol");
}
$historyCollection = [];
foreach ($qb->execute()->fetchAll() as $order) {
$historyCollection[] = new PosOrderHistoryItem($order);
}
return new PosOrderHistoryCollection(
items: $historyCollection
);
}
public function getPosStats(int $idPos, ?DateInterval $interval = null): PosStats
{
$posEntity = new PosEntity();
$posEntity->createFromDB($idPos)->activateContexts();
$posAppStats = new PosAppStats();
$posAppStats->setPosEntity($posEntity);
$posAppStats->setDatetimeInterval($interval);
$posAppStats->fetchStats();
return new PosStats(
$this->loadStatsForMethod($posAppStats->getStats(), \Payment::METHOD_CASH),
$this->loadStatsForMethod($posAppStats->getStats(), \Payment::METHOD_CARD),
$this->loadStatsForMethod($posAppStats->getStats(), \Payment::METHOD_INVOICE),
$posAppStats->getPaidOfTheInvoiceCash(),
$posAppStats->getPaidOfTheInvoiceCard(),
new PosSummaryStats(
$posAppStats->getCashInsertion(),
$posAppStats->getCashSelection(),
$posAppStats->getCompensation(),
$posAppStats->getRounding(),
$posAppStats->getDiscounts(),
$posAppStats->getSales(),
$posAppStats->getActualCashInPos(),
$posAppStats->getNonHandledOrdersCount(),
$posAppStats->getNonHandledOrdersPriceSum(),
)
);
}
public function sendInvoiceByEmail($idOrder): int
{
$emailService = ServiceContainer::getService(InvoiceEmail::class);
$order = new \Order();
$order->createFromDB($idOrder);
$emailService->setOrder($order);
$message = $emailService->getEmail();
// Send it
$emailService->sendEmail($message);
return 0;
}
private function loadStatsForMethod($stats, $method): PosPaymentStats
{
$vats = [];
foreach ($stats[$method] as $vat => $price) {
$vats[] = new PosStatVatPrice($vat, $price);
}
return new PosPaymentStats($vats);
}
public function loadAdditionalData(int $idPos): PosAdditionalData
{
if (!$idPos) {
throw new \Exception('Není vybrána žádná pokladna');
}
Contexts::get(PosContext::class)->activate($idPos);
$posEntity = Contexts::get(PosContext::class)->getActive();
// Loads modules to pos
$modules = $posEntity->getCheckedModules();
// Load permissions to pos
$permissions = $posEntity->getCheckedPermissions();
$delivery_types = sqlQueryBuilder()
->select('CONCAT(cash_dtp.name, " - ", cash_dtd.name) as cash')
->addSelect('CONCAT(card_dtp.name, " - ", card_dtd.name) as card')
->addSelect('CONCAT(invoice_dtp.name, " - ", invoice_dtd.name) as invoice')
->addSelect('custom_dtp.name as custom')
->from('pos', 'pos')
->leftJoin('pos', 'delivery_type', 'cash_dt', 'cash_dt.id=pos.cash_delivery_type')
->leftJoin('cash_dt', 'delivery_type_delivery', 'cash_dtd', 'cash_dtd.id=cash_dt.id_delivery')
->leftJoin('cash_dt', 'delivery_type_payment', 'cash_dtp', 'cash_dtp.id=cash_dt.id_payment')
->leftJoin('pos', 'delivery_type', 'card_dt', 'card_dt.id=pos.card_delivery_type')
->leftJoin('card_dt', 'delivery_type_delivery', 'card_dtd', 'card_dtd.id=card_dt.id_delivery')
->leftJoin('card_dt', 'delivery_type_payment', 'card_dtp', 'card_dtp.id=card_dt.id_payment')
->leftJoin('pos', 'delivery_type', 'invoice_dt', 'invoice_dt.id=pos.invoice_delivery_type')
->leftJoin('invoice_dt', 'delivery_type_delivery', 'invoice_dtd', 'invoice_dtd.id=invoice_dt.id_delivery')
->leftJoin('invoice_dt', 'delivery_type_payment', 'invoice_dtp', 'invoice_dtp.id=invoice_dt.id_payment')
->leftJoin('pos', 'delivery_type', 'custom_dt', 'custom_dt.id=pos.custom_delivery_type')
->leftJoin('custom_dt', 'delivery_type_payment', 'custom_dtp', 'custom_dtp.id=custom_dt.id_payment')
->where(Operator::equals(['pos.id' => $idPos]))
->execute()
->fetchAssociative();
$statuses = [];
foreach (getOrderStatuses() as $key => $orderStatus) {
$statuses[] = new PosOrderStatus($key, $orderStatus['name'] ?? '', getStatuses('handled')[0] == $key ? 'handled' : null);
}
$iframes = [];
foreach ($this->serviceLocator->getProvidedServices() as $className) {
if ($this->serviceLocator->has($className)) {
/** @var PosTabInterface $service */
$service = $this->serviceLocator->get($className);
if ($service->isAllowed()) {
$iframes[] = new PosIframe($service->getId(), $service->getTitle(), $service->getUrl());
}
}
}
return new PosAdditionalData(
$posEntity->getName(),
$this->loadVats(),
$this->currencyContext->getActive(),
$this->countryContext->getActive(),
new PosModulesCollection($modules),
new PosDeliverySetting($delivery_types),
new PosOrderStatusCollection($statuses),
new PosIframeCollection($iframes),
new PosPermissionCollection($permissions),
new PosTerminal($posEntity->getTerminalData()),
$posEntity->getStores(),
$posEntity->getWarehousePositions()
);
}
private function loadVats(): PosVatCollection
{
$qb = sqlQueryBuilder()
->select('descr, vat, is_default')
->from('vats');
if (findModule(\Modules::OSS_VATS)) {
$qb->addSelect('id_country');
} else {
$qb->addSelect("'{$this->countryContext->getActive()->getId()}' AS id_country");
}
$vats = [];
foreach ($qb->execute()->fetchAll() as $vat) {
$vats[] = new PosVat($vat['descr'], $vat['vat'], $vat['is_default'], $vat['id_country']);
}
return new PosVatCollection($vats);
}
public function getPosDeliveryType($idPos, $methodPayment)
{
$paymentMethod = strtolower($methodPayment);
return sqlQueryBuilder()
->select('dt.id, CONCAT(dtp.name, " - ", dtd.name) as name, dtd.class as delivery_class, dtp.class as payment_class, dtp.id as payment_id')
->from('pos', 'pos')
->leftJoin('pos', 'delivery_type', 'dt', "dt.id=pos.{$paymentMethod}_delivery_type")
->leftJoin('dt', 'delivery_type_delivery', 'dtd', 'dtd.id=dt.id_delivery')
->leftJoin('dt', 'delivery_type_payment', 'dtp', 'dtp.id=dt.id_payment')
->where(Operator::equals(['pos.id' => $idPos]))
->execute()
->fetch();
}
public static function getHandledOrderStatus(): int
{
$settingsStatus = \Settings::getDefault()->loadValue('pos')['handle_status'] ?? -1;
if ($settingsStatus >= 0) {
return (int) $settingsStatus;
}
return (int) getStatuses('handled')[0];
}
}