Files
2025-08-02 16:30:27 +02:00

150 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
namespace KupShop\GraphQLBundle\ApiAdmin\Util;
use KupShop\CatalogBundle\ProductList\ProductList;
use KupShop\GraphQLBundle\ApiAdmin\Types\Purchase\Input\PurchaseCalculateInput;
use KupShop\GraphQLBundle\Exception\GraphQLNotFoundException;
use KupShop\GraphQLBundle\Exception\GraphQLValidationException;
use KupShop\KupShopBundle\Context\ContextManager;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Context\UserContext;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\Functional\Mapping;
use KupShop\KupShopBundle\Util\Price\Price;
use KupShop\KupShopBundle\Util\Price\PriceCalculator;
use KupShop\OrderDiscountBundle\Util\DiscountManager;
use KupShop\OrderingBundle\Entity\Purchase\ProductPurchaseItem;
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
use Query\Operator;
use Query\Product;
class PurchaseUtil
{
public function __construct(
protected ProductList $productList,
protected \KupShop\OrderingBundle\Util\Purchase\PurchaseUtil $purchaseUtil,
protected DiscountManager $discountManager,
protected ContextManager $contextManager,
) {
}
public function calculatePurchaseState(PurchaseCalculateInput $input): \KupShop\GraphQLBundle\ApiAdmin\Types\Purchase\PurchaseState
{
if (empty($input->items)) {
throw new GraphQLValidationException('Argument "items" cannot be empty!');
}
$purchaseState = $this->contextManager->activateContexts([UserContext::class => $input->userId], function () use ($input) {
$productList = clone $this->productList;
$productList->setVariationsAsResult(true);
$purchaseState = $this->createPurchaseState();
$productListProducts = [];
$productListCodes = [];
// pripravim si produkty, ktere budu nacitat pres product list
foreach ($input->items as $item) {
if (empty($item->productId) && empty($item->code)) {
throw new GraphQLValidationException('Invalid "PurchaseItemInput"! One of these fields is required: productId, code');
}
if ($item->code) {
$productListCodes[] = $item->code;
}
if ($item->productId) {
$productListProducts[$item->productId] = $productListProducts[$item->productId] ?? null;
if ($item->variationId) {
$productListProducts[$item->productId][] = $item->variationId;
}
}
}
// specka pro nacteni produktu / variant podle idcek
if (!empty($productListProducts)) {
$productList->andSpec(Product::productsAndVariationsIds($productListProducts));
}
// specka pro nacteni produkt / variant podle kodu
if (!empty($productListCodes)) {
$productList->andSpec(Operator::orX(
Operator::inStringArray($productListCodes, 'p.code'),
Operator::inStringArray($productListCodes, 'pv.code')
));
}
$products = $productList->getProducts()->toArray();
$productsByCode = Mapping::mapKeys($products, fn ($k, $v) => [$v->variationCode ?? $v->code, $v]);
$currencyContext = Contexts::get(CurrencyContext::class);
$currency = $currencyContext->getActive();
// dohledam Product a pridam PurchaseItem do PurchaseStatu
foreach ($input->items as $item) {
$product = null;
if ($item->code) {
if (!($product = ($productsByCode[$item->code] ?? null))) {
throw new GraphQLNotFoundException(sprintf('Product with code "%s" was not found!', $item->code));
}
}
if ($item->productId) {
$productKey = $item->productId.($item->variationId ? '/'.$item->variationId : '');
if (!($product = ($products[$productKey] ?? null))) {
throw new GraphQLNotFoundException(sprintf('Product with ID "%s" and variation ID "%s" was not found!', $item->productId, $item->variationId));
}
}
if (!$product) {
throw new GraphQLNotFoundException('Product was not found!');
}
// pokud specifikovali cenu, tak pro ceneni pouziju externi cneu
if ($item->price) {
$itemPrice = new Price(toDecimal($item->price)->removeVat($product->vat), $currency, $product->vat);
} else {
// ve vychozim stavu vezmu cenu od produktu
$itemPrice = PriceCalculator::toPrice($product->getProductPrice());
}
// vytvorim a pridam novy ProductPurchaseItem
$productPurchaseItem = new ProductPurchaseItem(
$product->id,
$product->variationId ?? null,
$item->pieces,
$itemPrice
);
$productPurchaseItem->setProduct($product);
$purchaseState->addProduct($productPurchaseItem);
}
// pridam kupony
foreach ($input->coupons ?? [] as $coupon) {
$purchaseState->addCoupon($coupon);
}
// prepocitam PurchaseState, abych v nem mel slevy a nasetuju ho do discount manager
$this->discountManager->setPurchaseState(
$this->purchaseUtil->recalculateTotalPrices($purchaseState)
);
// pres discount manager prepocitam purchase state, aby se mi aplikovali ruzne slevy atd
return $this->discountManager->recalculate();
});
return new \KupShop\GraphQLBundle\ApiAdmin\Types\Purchase\PurchaseState(
$purchaseState
);
}
protected function createPurchaseState(): PurchaseState
{
return new PurchaseState([]);
}
}