150 lines
6.0 KiB
PHP
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([]);
|
|
}
|
|
}
|