451 lines
16 KiB
PHP
451 lines
16 KiB
PHP
<?php
|
|
|
|
namespace KupShop\POSBundle\Tests;
|
|
|
|
use Doctrine\DBAL\Exception;
|
|
use KupShop\GraphQLBundle\ApiAdmin\Types;
|
|
use KupShop\KupShopBundle\Context\CurrencyContext;
|
|
use KupShop\KupShopBundle\Context\PosContext;
|
|
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
|
use KupShop\KupShopBundle\Util\Contexts;
|
|
use KupShop\KupShopBundle\Util\Price\Price;
|
|
use KupShop\OrderingBundle\Entity\Order\OrderItem;
|
|
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
|
|
use KupShop\OrderingBundle\Entity\Purchase\TextPurchaseItem;
|
|
use KupShop\OrderingBundle\Util\Purchase\PurchaseUtil;
|
|
use KupShop\POSBundle\Util\PosEntity;
|
|
use KupShop\POSBundle\Util\PosOrderUtil;
|
|
use KupShop\POSBundle\Util\PosPaymentUtil;
|
|
use KupShop\POSBundle\Util\PosPurchaseStateUtil;
|
|
use KupShop\POSBundle\Util\PosWarehouseUtil;
|
|
use KupShop\WarehouseBundle\Util\StoreItemWorker;
|
|
|
|
class PosOrderTest extends \DatabaseTestCase
|
|
{
|
|
public function getDataSet()
|
|
{
|
|
return $this->getJsonDataSetFromFile();
|
|
}
|
|
|
|
protected PosPurchaseStateUtil $posPurchaseStateUtil;
|
|
protected PurchaseUtil $purchaseUtil;
|
|
protected CurrencyContext $currencyContext;
|
|
protected PosOrderUtil $posOrderUtil;
|
|
protected PosWarehouseUtil $posWarehouseUtil;
|
|
private StoreItemWorker $storeItemWorker;
|
|
private PosPaymentUtil $posPaymentUtil;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
global $adminID;
|
|
$adminID = null;
|
|
parent::setUp();
|
|
}
|
|
|
|
protected function setEnvironment()
|
|
{
|
|
$this->purchaseUtil = ServiceContainer::getService(PurchaseUtil::class);
|
|
$this->currencyContext = ServiceContainer::getService(CurrencyContext::class);
|
|
$this->posOrderUtil = ServiceContainer::getService(PosOrderUtil::class);
|
|
$this->posWarehouseUtil = ServiceContainer::getService(PosWarehouseUtil::class);
|
|
$this->storeItemWorker = ServiceContainer::getService(StoreItemWorker::class);
|
|
$this->posEntity = ServiceContainer::getService(PosEntity::class);
|
|
$this->posPaymentUtil = ServiceContainer::getService(PosPaymentUtil::class);
|
|
$this->posPurchaseStateUtil = ServiceContainer::getService(PosPurchaseStateUtil::class);
|
|
}
|
|
|
|
private function getPosEntity(): PosEntity
|
|
{
|
|
$posContext = Contexts::get(PosContext::class);
|
|
$posContext->activate(2);
|
|
|
|
return $posContext->getActive();
|
|
}
|
|
|
|
private function getTestOrderItems($idOrderItem1 = null, $idOrderItem2 = null): array
|
|
{
|
|
return [
|
|
new Types\Order\OrderItem(
|
|
new OrderItem(
|
|
[
|
|
'idProduct' => 43866,
|
|
'idVariation' => 24004,
|
|
'pieces' => 1,
|
|
'vat' => '21',
|
|
'priceWithoutVat' => 3297.5207,
|
|
'discount' => null,
|
|
'idOrderItem' => $idOrderItem1,
|
|
]
|
|
)
|
|
),
|
|
new Types\Order\OrderItem(
|
|
new OrderItem(
|
|
[
|
|
'idProduct' => 12145,
|
|
'idVariation' => null,
|
|
'pieces' => 1,
|
|
'vat' => '21',
|
|
'priceWithoutVat' => 252.0661,
|
|
'discount' => null,
|
|
'idOrderItem' => $idOrderItem2,
|
|
]
|
|
)
|
|
),
|
|
];
|
|
}
|
|
|
|
private function getTestPurchaseState(): PurchaseState
|
|
{
|
|
$couponItems = null;
|
|
|
|
return $this->posPurchaseStateUtil->createStateFromApi($this->getTestOrderItems(), $couponItems);
|
|
}
|
|
|
|
public function testCreatePurchaseStateFromPos()
|
|
{
|
|
$this->setEnvironment();
|
|
$purchaseState = $this->getTestPurchaseState();
|
|
|
|
$this->assertEquals(toDecimal('4295.0000')->round(2), $purchaseState->getTotalPrice()->getPriceWithVat()->round(2));
|
|
$this->assertEquals(toDecimal('3549.5868')->round(2), $purchaseState->getTotalPrice()->getPriceWithoutVat()->round(2));
|
|
|
|
$purchaseState->addProduct(
|
|
new TextPurchaseItem(
|
|
'Textová položka',
|
|
2,
|
|
new Price(toDecimal('1239.6694'),
|
|
$this->currencyContext->getActive(),
|
|
'21'
|
|
),
|
|
'21')
|
|
);
|
|
|
|
$purchaseState = $this->purchaseUtil->recalculateTotalPrices($purchaseState);
|
|
$this->assertEquals(toDecimal('5795.0000')->round(2), $purchaseState->getTotalPrice()->getPriceWithVat()->round(2));
|
|
$this->assertEquals(toDecimal('4789.2562')->round(2), $purchaseState->getTotalPrice()->getPriceWithoutVat()->round(2));
|
|
}
|
|
|
|
public function testCreateOrderFromPurchaseState()
|
|
{
|
|
$this->setEnvironment();
|
|
$this->getPosEntity();
|
|
|
|
// ---- check before update -----
|
|
$inStoreVar = sqlQueryBuilder()
|
|
->select('in_store')
|
|
->from('products_variations')
|
|
->andWhere('id_product = 43866 AND id = 24004')
|
|
->execute()
|
|
->fetchOne();
|
|
$this->assertEquals(2, $inStoreVar);
|
|
|
|
$inStoreStoreItem = sqlQueryBuilder()
|
|
->select('quantity')
|
|
->from('stores_items')
|
|
->andWhere('id = 78')
|
|
->execute()
|
|
->fetchOne();
|
|
$this->assertEquals(20, $inStoreStoreItem);
|
|
// ------------------------------
|
|
|
|
$orderResponse = $this->posOrderUtil->recalculateAndUpdateOrder(
|
|
$this->getTestOrderItems(),
|
|
[],
|
|
[],
|
|
[],
|
|
null,
|
|
null,
|
|
null,
|
|
true,
|
|
'CASH',
|
|
'1',
|
|
true
|
|
);
|
|
$this->assertCount(2, $orderResponse->getItems());
|
|
|
|
$insertedOrder = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('orders')
|
|
->where('id=:id_order')
|
|
->setParameter('id_order', $orderResponse->getOrderInfo()->getIdOrder())
|
|
->execute()
|
|
->fetch();
|
|
$this->assertEquals(toDecimal('4295')->round(2), $insertedOrder['total_price']);
|
|
$this->assertEquals(toDecimal('3549.5868')->round(2), $insertedOrder['total_price_without_vat']);
|
|
|
|
$orderItems = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('order_items')
|
|
->where('id_order=:id_order')
|
|
->setParameter('id_order', $insertedOrder['id'])
|
|
->execute()
|
|
->fetchAll();
|
|
$this->assertCount(2, $orderItems);
|
|
|
|
// ---- after before update -----
|
|
$inStoreVar = sqlQueryBuilder()
|
|
->select('in_store')
|
|
->from('products_variations')
|
|
->andWhere('id_product = 43866 AND id = 24004')
|
|
->execute()
|
|
->fetchOne();
|
|
$this->assertEquals(1, $inStoreVar);
|
|
|
|
$inStoreStoreItem = sqlQueryBuilder()
|
|
->select('quantity')
|
|
->from('stores_items')
|
|
->andWhere('id = 78')
|
|
->execute()
|
|
->fetchOne();
|
|
$this->assertEquals(19, $inStoreStoreItem);
|
|
// ------------------------------
|
|
}
|
|
|
|
public function testPurchaseStateStockInItemsCheck()
|
|
{
|
|
$this->setEnvironment();
|
|
$posEntity = $this->getPosEntity();
|
|
$purchaseState = $this->getTestPurchaseState();
|
|
|
|
$purchaseState->addProduct(
|
|
new TextPurchaseItem(
|
|
'Textová položka',
|
|
2,
|
|
new Price(toDecimal('1239.6694'),
|
|
$this->currencyContext->getActive(),
|
|
'21'
|
|
),
|
|
'21')
|
|
);
|
|
|
|
$status = 'OK';
|
|
try {
|
|
$this->posWarehouseUtil->checkPurchaseStateItemsStockIn($purchaseState, $posEntity);
|
|
} catch (\Exception $e) {
|
|
$status = $e->getMessage();
|
|
}
|
|
|
|
$this->assertEquals('OK', $status);
|
|
|
|
$purchaseState->getProducts()[1]->pieces = 2;
|
|
|
|
try {
|
|
$this->posWarehouseUtil->checkPurchaseStateItemsStockIn($purchaseState, $posEntity);
|
|
} catch (\Exception $e) {
|
|
$status = $e->getMessage();
|
|
}
|
|
|
|
$this->assertEquals('Produkt Bosch vzduchový filtr Octavia 1Z TSI není v požadovaném množství na skladu.', $status);
|
|
}
|
|
|
|
public function testMoveProductsToVirtualBox()
|
|
{
|
|
$this->removeModule(\Modules::PRODUCTS_BATCHES);
|
|
$this->setEnvironment();
|
|
$posEntity = $this->getPosEntity();
|
|
|
|
$order = new \Order();
|
|
$order->createFromDB(183932);
|
|
$order->fetchItems();
|
|
|
|
$this->posWarehouseUtil->checkPurchaseStateItemsStockIn($order->getPurchaseState(), $posEntity);
|
|
|
|
// Check positions before move
|
|
$positions = $this->storeItemWorker->checkProductByEanAndLocation('8596389006365')['positions'];
|
|
|
|
$this->assertEquals(1, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '1138'))[0]['pieces']);
|
|
$this->assertEquals(2, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '1139'))[0]['pieces']);
|
|
|
|
// Najde se rozdíl položek mezi boxem a objednávkou
|
|
$warehouseDiff = $this->storeItemWorker->checkOrderMatchesBoxContent(
|
|
id_warehouse_order: $warehouseOrder['id'] ?? null,
|
|
id_order: $order->id,
|
|
id_box: $posEntity->getVirtualBox()
|
|
);
|
|
|
|
// Provede vyrovnání boxu
|
|
$this->posWarehouseUtil->updateBoxToMatchOrder(
|
|
order: $order,
|
|
warehouseDiffs: $warehouseDiff,
|
|
idBox: $posEntity->getVirtualBox()
|
|
);
|
|
|
|
// Check positions after move
|
|
$positions = $this->storeItemWorker->checkProductByEanAndLocation('8596389006365')['positions'];
|
|
$this->assertEquals(0, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '1138'))[0]['pieces']);
|
|
$this->assertEquals(1, array_values(array_filter($positions, fn ($x) => $x['id_position'] == '1139'))[0]['pieces']);
|
|
}
|
|
|
|
public function getOrderItems()
|
|
{
|
|
return [
|
|
new \KupShop\GraphQLBundle\ApiAdmin\Types\Order\OrderItem(new \KupShop\OrderingBundle\Entity\Order\OrderItem([
|
|
'discount' => null,
|
|
'idCharge' => null,
|
|
'idOrderItem' => null,
|
|
'idProduct' => 21113,
|
|
'idVariation' => null,
|
|
'pieces' => 1,
|
|
'priceWithoutVat' => '139.0000',
|
|
'serialNumbers' => null,
|
|
'title' => 'Na kytaru bez not',
|
|
'uuid' => '8129826c-21de-47cf-a660-eb8c7309dae7',
|
|
'vat' => '0',
|
|
])),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @throws Exception
|
|
*/
|
|
public function testWholeProcessCreateOrderFromPosWithSeparatePaymentAndCompleting()
|
|
{
|
|
$this->setEnvironment();
|
|
$posEntity = $this->getPosEntity();
|
|
$GLOBALS['adminID'] = 0;
|
|
|
|
// Update And Recalculate pos state (API object simulated)
|
|
$response = $this->posOrderUtil->recalculateAndUpdateOrder(
|
|
$this->getTestOrderItems(),
|
|
[],
|
|
[],
|
|
[],
|
|
null,
|
|
null,
|
|
null,
|
|
false,
|
|
'UNDEFINED',
|
|
'0',
|
|
true
|
|
);
|
|
|
|
// 3297.5207 (Položka 1) + 252.0661 (Položka 2) = 3549.5868 -> 4295.000028 (s DPH)
|
|
$this->assertEquals(toDecimal('4295.00')->round(2), toDecimal($response->getPriceWithVat())->round(2));
|
|
$this->assertEquals(toDecimal('3549.59')->round(2), toDecimal($response->getPriceWithoutVat())->round(2));
|
|
$this->assertCount(2, $response->getItems());
|
|
|
|
// Create order process with not finish payment
|
|
$response = $this->posOrderUtil->recalculateAndUpdateOrder(
|
|
$this->getTestOrderItems(),
|
|
[],
|
|
[],
|
|
[],
|
|
null,
|
|
null,
|
|
null,
|
|
true,
|
|
'CASH',
|
|
'100',
|
|
true
|
|
);
|
|
$this->assertEquals(-1, $response->getOrderInfo()->getStatus());
|
|
$this->assertEquals('4295', $response->getOrderInfo()->getRemainingPayment());
|
|
$this->assertFalse($response->getOrderInfo()->getIsPaid());
|
|
$this->assertCount(2, $response->getItems());
|
|
$this->assertEquals(43866, $response->getItems()[0]->getIdProduct());
|
|
$this->assertEquals('3297.5207', $response->getItems()[0]->getPiecePrice());
|
|
$idOrder = $response->getOrderInfo()->getIdOrder();
|
|
|
|
// Mám uloženo (mergnu idOrderItem jinak se bude znova hledat 1 kus na skladu) - tohle udělá pokladna
|
|
$items = $this->getTestOrderItems($response->getItems()[0]->getId(), $response->getItems()[1]->getId());
|
|
|
|
// Confirm payment
|
|
$response = $this->posPaymentUtil->confirmPayment($idOrder, $response->getOrderInfo()->getUuidPayment(), '100', 'CASH');
|
|
$this->assertEquals($idOrder, $response->getOrderInfo()->getIdOrder());
|
|
$this->assertTrue($response->getSaved());
|
|
$this->assertEquals('4195', $response->getOrderInfo()->getRemainingPayment()); // 4295 - 100 = 4195
|
|
$this->assertFalse($response->getOrderInfo()->getIsPaid());
|
|
|
|
// Create payment CARD - 4195
|
|
$response = $this->posOrderUtil->recalculateAndUpdateOrder(
|
|
$items,
|
|
[],
|
|
[],
|
|
[],
|
|
null,
|
|
null,
|
|
$idOrder,
|
|
true,
|
|
'CARD',
|
|
'4195',
|
|
true
|
|
);
|
|
$this->assertTrue($response->getSaved());
|
|
|
|
// STATUS PAID
|
|
$response = $this->posPaymentUtil->confirmPayment($response->getOrderInfo()->getIdOrder(), $response->getOrderInfo()->getUuidPayment(), '4195', 'CARD');
|
|
$this->assertEquals($idOrder, $response->getOrderInfo()->getIdOrder());
|
|
$this->assertTrue($response->getSaved());
|
|
$this->assertEquals('0', $response->getOrderInfo()->getRemainingPayment());
|
|
$this->assertTrue($response->getOrderInfo()->getIsPaid());
|
|
|
|
// Finish order
|
|
$response = $this->posOrderUtil->finishOrder($idOrder);
|
|
$this->assertNull($response->getException());
|
|
$this->assertEquals($idOrder, $response->getIdOrder());
|
|
|
|
// Check order DB data
|
|
$qb = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('orders')
|
|
->andWhere('id = :idOrder')
|
|
->setParameter('idOrder', $idOrder)
|
|
->execute()
|
|
->fetchAssociative();
|
|
$this->assertEquals('POS', $qb['flags']);
|
|
$this->assertEquals('pos', $qb['source']);
|
|
$this->assertEquals(1, $qb['status_payed']);
|
|
$this->assertEquals('Platba kartou na pobočce - Osobní odběr Praha', $qb['delivery_type']); // Saves last one -> CARD
|
|
$this->assertEquals('Maloobchodní prodej', $qb['invoice_name']);
|
|
$this->assertEquals(toDecimal('4295')->round(2), toDecimal($qb['total_price'])->round(2));
|
|
$this->assertEquals(toDecimal('3549.5868')->round(2), toDecimal($qb['total_price_without_vat'])->round(2));
|
|
|
|
$qb = sqlQueryBuilder()
|
|
->select('*')
|
|
->from('pos_payments_relation', 'ppr')
|
|
->leftJoin('ppr', 'order_payments', 'op', 'ppr.id_payment = op.id')
|
|
->andWhere('ppr.id_pos = :idPos AND op.id_order = :idOrder')
|
|
->setParameter('idPos', $posEntity->getId())
|
|
->setParameter('idOrder', $idOrder)
|
|
->execute()
|
|
->fetchAllAssociative();
|
|
$this->assertCount(2, $qb);
|
|
$this->assertEquals(1, $qb[0]['method']);
|
|
$this->assertEquals(toDecimal('100')->round(2), toDecimal($qb[0]['price'])->round(2));
|
|
$this->assertEquals(2, $qb[1]['method']);
|
|
$this->assertEquals(toDecimal('4195')->round(2), toDecimal($qb[1]['price'])->round(2));
|
|
}
|
|
|
|
/**
|
|
* @dataProvider data_testFindProduct
|
|
*/
|
|
public function testFindProduct(array $testData)
|
|
{
|
|
$this->setEnvironment();
|
|
$this->getPosEntity();
|
|
|
|
$response = $this->posOrderUtil->recalculateAndUpdateOrder(
|
|
$this->getOrderItems(),
|
|
[],
|
|
$testData['search'],
|
|
[],
|
|
null,
|
|
null,
|
|
null,
|
|
false,
|
|
'CARD',
|
|
'4195',
|
|
true
|
|
);
|
|
|
|
$this->assertEquals($testData['expectedIdProduct'], $response->getItems()[1]->getIdProduct() ?? null);
|
|
}
|
|
|
|
public function data_testFindProduct()
|
|
{
|
|
yield 'code' => [['search' => ['1F0129620/ 1987429405'], 'expectedIdProduct' => '12145']];
|
|
yield 'normalEan' => [['search' => ['3165143344057'], 'expectedIdProduct' => '12145']];
|
|
yield 'eanWithZero' => [['search' => ['003165143344057'], 'expectedIdProduct' => '12145']];
|
|
}
|
|
}
|