Files
kupshop/bundles/KupShop/PreordersBundle/Tests/PreordersTest.php
2025-08-02 16:30:27 +02:00

339 lines
12 KiB
PHP

<?php
declare(strict_types=1);
namespace KupShop\PreordersBundle\Tests;
use KupShop\DevelopmentBundle\Util\Tests\CartTestTrait;
use KupShop\KupShopBundle\Context\PriceLevelContext;
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
use KupShop\PreordersBundle\Entity\UserPreorder;
use KupShop\PreordersBundle\Service\DynamicContexts;
use KupShop\PreordersBundle\Service\DynamicPrices;
use KupShop\PreordersBundle\Service\OrderCreator;
use KupShop\PreordersBundle\Service\PreorderItemsUpdater;
use KupShop\PreordersBundle\Service\PreorderUtil;
use KupShop\PricelistBundle\Context\PricelistContext;
use Query\Operator;
use Query\QueryBuilder;
class PreordersTest extends \DatabaseTestCase
{
use PreordersTestHelper;
use CartTestTrait;
private OrderCreator $orderService;
private PreorderItemsUpdater $itemsUpdater;
private DynamicContexts $contextsService;
protected function setUp(): void
{
parent::setUp();
$this->orderService = $this->get(OrderCreator::class);
$this->itemsUpdater = $this->get(PreorderItemsUpdater::class);
$this->contextsService = $this->get(DynamicContexts::class);
}
public function testItemsUpdater()
{
$userId = 1;
$this->loginUser($userId);
$dateId = $this->createDate(1);
$userPreorder = new UserPreorder($userId, $dateId);
$this->assertEmpty($userPreorder->getItems(true));
$this->itemsUpdater->updateItems($userPreorder, [
['id_product' => 4, 'id_variation' => '1', 'pieces' => 1],
['id_product' => 4, 'id_variation' => '2', 'pieces' => 2],
['id_product' => 10, 'id_variation' => null, 'pieces' => 3],
]);
$expected = [
[
'id_product' => 10,
'id_variation' => null,
'id_user' => 1,
'piece_price' => '1539.1304',
'pieces' => 3,
'pieces_sent' => 0,
'vat' => 2,
'product_title' => 'Black and Decker Core EGBL108K aku vrtačka',
'variation_title' => null,
'title' => 'Black and Decker Core EGBL108K aku vrtačka',
'price_total' => '4617.3912',
'price_remaining' => '4617.3912',
'currency' => 'CZK',
],
[
'id_product' => 4,
'id_variation' => 2,
'id_user' => 1,
'piece_price' => '3636.3636',
'pieces' => 2,
'pieces_sent' => 0,
'vat' => 1,
'product_title' => 'Columbia Lay D Down',
'variation_title' => 'Barva: modrá',
'title' => 'Columbia Lay D Down Barva: modrá',
'price_total' => '7272.7272',
'price_remaining' => '7272.7272',
'currency' => 'CZK',
],
[
'id_product' => 4,
'id_variation' => 1,
'id_user' => 1,
'piece_price' => '3636.3636',
'pieces' => 1,
'pieces_sent' => 0,
'vat' => 1,
'product_title' => 'Columbia Lay D Down',
'variation_title' => 'Barva: bílá',
'title' => 'Columbia Lay D Down Barva: bílá',
'price_total' => '3636.3636',
'price_remaining' => '3636.3636',
'currency' => 'CZK',
],
];
$items = $userPreorder->getItems(true);
foreach ($items as &$item) {
unset($item['id']);
unset($item['id_preorder_date']);
unset($item['has_variations']);
}
$this->assertEquals($expected, $items);
}
public function testCreateOrderFromPreorder()
{
$userPreorder = $this->createTestUserPreorder();
$itemsToAdd = [];
foreach ($userPreorder->getItems(true) as $item) {
$itemsToAdd[$item['id']] = (int) $item['pieces'] - 1;
}
$orderCreated = $this->orderService->createOrder($userPreorder, $itemsToAdd);
$order = new \Order();
$order->createFromDB($orderCreated->id);
$orderItems = [];
foreach ($order->getPurchaseState()->getProducts() as $product) {
$orderItems[] = [
'id_product' => $product->id_product,
'id_variation' => $product->id_variation,
'pieces' => $product->getPieces(),
'price' => $product->getPrice()->getPriceWithoutVat(),
'piece_price' => $product->getPiecePriceWithoutVat(),
];
}
$expected = [
[
'id_product' => 4,
'id_variation' => 2,
'pieces' => 1,
'price' => \Decimal::create('3636.36363636', 8),
'piece_price' => \Decimal::create('3636.36363636', 8),
],
[
'id_product' => 10,
'id_variation' => null,
'pieces' => 2,
'price' => \Decimal::create('3078.26086957', 8),
'piece_price' => \Decimal::create('1539.13043479', 8),
],
];
$this->assertEquals($expected, $orderItems);
$expectedPreorderItems = [
[
'id_product' => 4,
'id_variation' => 1,
'id_user' => 1,
'piece_price' => '3636.3636',
'pieces' => 1,
'pieces_sent' => 0,
'vat' => 1,
'product_title' => 'Columbia Lay D Down',
'variation_title' => 'Barva: bílá',
'title' => 'Columbia Lay D Down Barva: bílá',
'price_total' => '3636.3636',
'price_remaining' => '3636.3636',
'currency' => 'CZK',
],
[
'id_product' => 4,
'id_variation' => 2,
'id_user' => 1,
'piece_price' => '3636.3636',
'pieces' => 2,
'pieces_sent' => 1,
'vat' => 1,
'product_title' => 'Columbia Lay D Down',
'variation_title' => 'Barva: modrá',
'title' => 'Columbia Lay D Down Barva: modrá',
'price_total' => '7272.7272',
'price_remaining' => '3636.3636',
'currency' => 'CZK',
],
[
'id_product' => 10,
'id_variation' => null,
'id_user' => 1,
'piece_price' => '1539.1304',
'pieces' => 3,
'pieces_sent' => 2,
'vat' => 2,
'product_title' => 'Black and Decker Core EGBL108K aku vrtačka',
'variation_title' => null,
'title' => 'Black and Decker Core EGBL108K aku vrtačka',
'price_total' => '4617.3912',
'price_remaining' => '1539.1304',
'currency' => 'CZK',
],
];
$itemsToAdd = $userPreorder->getItems(true);
// each time - different ids
foreach ($itemsToAdd as &$item) {
unset($item['id']);
unset($item['id_preorder_date']);
unset($item['has_variations']);
}
$this->assertEquals($expectedPreorderItems, $itemsToAdd);
}
public function testCreateProductList()
{
$userPreorder = $this->createTestUserPreorder();
$list = $this->get(PreorderUtil::class)->getPreorderProductList($userPreorder->getItems(true), false);
$this->contextsService->withDynamicPrices(
$userPreorder->getPreorder(),
$userPreorder->getItems(true),
function () use ($list, $userPreorder, &$products, &$purchaseState) {
$products = $list->getProducts();
$refList = (new \ProductList(true))
->andSpec(function (QueryBuilder $qb) use ($products) {
$qb->andWhere(Operator::inIntArray($products->getProductIds(), 'p.id'));
});
$this->get(DynamicPrices::class)->inject($products, $refList, $userPreorder->getPreorder());
$this->assertEquals([4, 10], $products->getProductIds());
$purchaseState = PreorderUtil::toPurchaseState($products);
$this->assertEquals(
self::PRICE_LEVEL_12,
(int) $this->get(PriceLevelContext::class)->getActiveId(),
);
$this->assertEquals(
self::PRICELIST_BASE,
(int) $this->get(PricelistContext::class)->getActiveId(),
);
$this->get(PurchaseUtil::class)->recalculateTotalPrices($purchaseState);
},
);
$this->assertEqualsWithDelta(
\Decimal::create('15525.8173', 4)->asFloat(),
$purchaseState->getTotalPrice()->getPriceWithoutVat()->asFloat(),
0.01,
);
foreach ($products as /* @var \Product $product */ $product) {
if (!empty($product->variations)) {
foreach ($product->variations as $variation) {
$this->assertEquals(
$variation['dynamic_prices'][2]['price']->getPriceWithoutVat(),
$variation['preorder_piece_price']->getPriceWithoutVat(),
);
$this->assertEqualsWithDelta(
$variation['dynamic_prices'][2]['price']->getPriceWithoutVat()->asFloat(),
$variation['productPrice']->getPriceWithoutVat()->asFloat(),
0.01,
);
}
continue;
}
$this->assertEquals(
$product['dynamic_prices'][2]['price']->getPriceWithoutVat(),
$product->getProductPrice()->getPriceWithoutVat(),
);
$this->assertEquals(
$product['dynamic_prices'][2]['price']->getPriceWithoutVat(),
$product['preorder_piece_price']->getPriceWithoutVat(),
);
}
}
/**
* 3 otevřené termíny: <br>
* <i>&emsp;2 z předobjednávky s ID=1 a 1 z předobjednávky s ID=2</i><br>
* Používám jenom ty z předobjednávky s ID=1<br>.
*
* 1) Přidam nějaký produkty do obou termínů, ale abych nepřekročil do první slevový hladiny.<br>
* 2) Pak do jednoho termínu přidam přes PreorderItemsUpdater::updateItems nějakej produkt, abych tu hladinu překročil. <br>
*
* Co se stane: měly by se přepočítat ceny v OBOU TERMÍNECH (tzn. i v tom, do kterýho jsem nic nepřidal v kroku 2)
*/
public function testUpdatesPricesOfAllDatesWhileUsingMultipleDates(): void
{
$this->setUseMultipleDates();
$dates = $this->createTestMultipleDates();
$user = $this->getUserWithAllPreorders();
$openDateIds = array_column(PreorderUtil::getOpenDates($user), 'id');
[$firstDate, $secondDate] = array_filter(
$dates,
fn (array $d) => $d['id_preorder'] == 1 && in_array($d['id'], $openDateIds),
);
$first = new UserPreorder($user->id, $firstDate['id']);
$second = new UserPreorder($user->id, $secondDate['id']);
$updater = $this->get(PreorderItemsUpdater::class);
$updater->updateItems($first, [
['id_product' => 11, 'id_variation' => 22, 'pieces' => 1],
]);
$updater->updateItems($second, [
['id_product' => 11, 'id_variation' => 22, 'pieces' => 1],
]);
// Nic se neaktivovalo -> ceny jsou stejné jako v DB
$this->assertEqualsWithDelta(275, $this->sumUserPreorderItems($first), 1);
$this->assertEqualsWithDelta(275, $this->sumUserPreorderItems($second), 1);
// Přidám produkt, co stojí 2400 -> dostanu se do 1. slevové hladiny
$updater->updateItems($first, [
['id_product' => 6, 'id_variation' => 17, 'pieces' => 1],
]);
$this->assertEqualsWithDelta(252, $this->sumUserPreorderItems($second), 1);
// Počítání pouze přes jeden termín -> cena se vrátí na původní úroveň
$this->setUseMultipleDates(false);
$updater->recalculatePiecePrices($second);
$this->assertEqualsWithDelta(275, $this->sumUserPreorderItems($second), 1);
}
}