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

550 lines
21 KiB
PHP

<?php
namespace KupShop\WarehouseBundle\Tests;
use KupShop\WarehouseBundle\Entity\StoreItem;
use KupShop\WarehouseBundle\Exception\WarehouseBaseException;
use KupShop\WarehouseBundle\Util\StockInWorker;
use KupShop\WarehouseBundle\Util\StoreItemWorker;
use KupShop\WarehouseBundle\Util\StoreTransferWorker;
use Query\Operator;
class StoreAppTest extends \DatabaseTestCase
{
protected function setUp(): void
{
parent::setUp();
sqlQuery('SET SESSION sql_mode = "TRADITIONAL"');
}
public function getDataSet()
{
return $this->getJsonDataSetFromFile('CheckAppTest.json');
}
public function testStoreItem()
{
// $productStockIn = sqlQueryBuilder()->select('in_store')->from('products')->where(Operator::equals(['id' => 3822]))->execute()->fetchColumn();
$variationStockIn = sqlQueryBuilder()->select('in_store')->from('products_variations')->where(Operator::equals(['id' => 1718603]))->execute()->fetchColumn();
$worker = $this->get(StockInWorker::class);
$result = $worker->SubmitStockIn(218867, $this->getStockInRows());
$stockInWorker = $this->get(StoreItemWorker::class);
$stockInWorker->storeItemFromTable(
'1234567891234', 2, 'PRIJEM', 'A1-3'
);
// stul
$row = sqlQueryBuilder()->select('*')->from('warehouse_products')->where(Operator::equals([
'id_product' => 101900,
'id_variation' => 1718603,
'id_position' => 7,
]))->execute()->fetch();
$this->assertEquals(1, $row['pieces']);
// pozice
$row = sqlQueryBuilder()->select('*')->from('warehouse_products')->where(Operator::equals([
'id_product' => 101900,
'id_variation' => 1718603,
'id_position' => 4,
]))->execute()->fetch();
$this->assertEquals(2, $row['pieces']);
// odebrani posledniho kusu
$stockInWorker->storeItemFromTable(
'1234567891234', 1, 'PRIJEM', 'A1-3'
);
// musi ze stolu byt smazat
$row = sqlQueryBuilder()->select('*')->from('warehouse_products')->where(Operator::equals([
'id_product' => 101900,
'id_variation' => 1718603,
'id_position' => 7,
]))->execute()->fetch();
$this->assertFalse($row);
// pohyb a nesmazani
$stockInWorker->updateOnPosition(
new StoreItem(['id_product' => 101900, 'id_variation' => 1718603]), 4, -3
);
$row = sqlQueryBuilder()->select('*')->from('warehouse_products')->where(Operator::equals([
'id_product' => 101900,
'id_variation' => 1718603,
'id_position' => 4,
]))->execute()->fetch();
$this->assertEquals(0, $row['pieces']);
}
public function testMoveBetweenPositions()
{
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 4));
$this->assertEquals(5, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
$stockInWorker = $this->get(StoreItemWorker::class);
$stockInWorker->moveBetweenPositions(new StoreItem(['id_product' => 101900, 'id_variation' => 1718603]), 2, 12, 4);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
$this->assertEquals(2, $this->getPiecesOnPosition(101900, 1718603, 4)['pieces']);
}
public function testMoveBetweenStores()
{
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 17));
$this->assertEquals(5, $this->getPiecesOnPosition(101900, 1718603, 16)['pieces']);
$stockInWorker = $this->get(StoreItemWorker::class);
$stockInWorker->moveBetweenPositions(new StoreItem(['id_product' => 101900, 'id_variation' => 1718603]), 2, 16, 17);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 16)['pieces']);
$this->assertEquals(2, $this->getPiecesOnPosition(101900, 1718603, 17)['pieces']);
$this->assertEquals(3, $this->getPiecesInStore(101900, 1718603, 1)['quantity']);
$this->assertEquals(2, $this->getPiecesInStore(101900, 1718603, 2)['quantity']);
}
public function testMoveBetweenPositionsIntoNegative()
{
$this->expectException(WarehouseBaseException::class);
$this->expectExceptionMessage('Na zdrojové pozici (A1-4) není dostatek kusů (8)! Produkt: Tretry Shimano SH-RT4MM, šedá melange');
$stockInWorker = $this->get(StoreItemWorker::class);
$stockInWorker->moveBetweenPositions(new StoreItem(['id_product' => 101900, 'id_variation' => 1718603]), 8, 12, 4);
}
protected function getPiecesOnPosition($id_product, $id_variation, $id_position)
{
return sqlQueryBuilder()->select('*')->from('warehouse_products')->where(Operator::equalsNullable([
'id_product' => $id_product,
'id_variation' => $id_variation,
'id_position' => $id_position,
]))->execute()->fetch();
}
protected function getPiecesInStore($id_product, $id_variation, $id_store)
{
return sqlQueryBuilder()->select('*')->from('stores_items')->where(Operator::equalsNullable([
'id_product' => $id_product,
'id_variation' => $id_variation,
'id_store' => $id_store,
]))->execute()->fetch();
}
/**
* @throws \Exception
*/
public function testCompleteOrderCheckout()
{
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 5));
$checkoutsItem = [
0 => new \stdClass(),
];
/** @var StoreItemWorker $stockInWorker */
$stockInWorker = $this->get(StoreItemWorker::class);
$order = $stockInWorker->startCheckout('123', 'BOX-2');
$checkoutsItem[0]->uuid = '1';
$checkoutsItem[0]->ean = '8592627018541';
$checkoutsItem[0]->position = 'A1-4';
$checkoutsItem[0]->id_item = '333';
$checkoutsItem[0]->pieces = '3';
$state = new \stdClass();
$state->checkouts = $checkoutsItem;
$stockInWorker->commit($order['order']['id_warehouse'], $state);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 5)['pieces']);
$this->assertEquals(2, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
return $order['order']['id_warehouse'];
}
/**
* @throws \Exception
*/
public function testAsyncSaveOrder()
{
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 5));
$checkoutsItem = [
0 => new \stdClass(),
];
/** @var StoreItemWorker $stockInWorker */
$stockInWorker = $this->get(StoreItemWorker::class);
$order = $stockInWorker->startCheckout('123', 'BOX-2');
$checkoutsItem[0]->uuid = '1';
$checkoutsItem[0]->ean = '8592627018541';
$checkoutsItem[0]->position = 'A1-4';
$checkoutsItem[0]->id_item = '333';
$checkoutsItem[0]->pieces = '3';
$state = new \stdClass();
$state->checkouts = $checkoutsItem;
$stockInWorker->commit($order['order']['id_warehouse'], $state);
$stockInWorker->commit($order['order']['id_warehouse'], $state);
$stockInWorker->commit($order['order']['id_warehouse'], $state);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 5)['pieces']);
$this->assertEquals(2, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
return $order['order']['id_warehouse'];
}
public function testAsyncSaveOrderStoreTransferWorker()
{
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 6)); // BOX-6
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 8)); // BOX-12
$checkoutsItem = [
0 => new \stdClass(),
];
/** @var StoreTransferWorker $storeTransferWorker */
$storeTransferWorker = $this->get(StoreTransferWorker::class);
$order = $storeTransferWorker->startCheckout('TR1', 'BOX-6');
$this->assertFalse($order['result']);
$this->assertEquals('Přepravka BOX-6 už obsahuje objednávku 124!', $order['message']);
$order = $storeTransferWorker->startCheckout('TR1', 'BOX-12');
$checkoutsItem[0]->uuid = '1';
$checkoutsItem[0]->ean = '8592627018541';
$checkoutsItem[0]->position = 'A2-3';
$checkoutsItem[0]->id_item = '1';
$checkoutsItem[0]->pieces = '3';
$state = new \stdClass();
$state->checkouts = $checkoutsItem;
$storeTransferWorker->commit($order['order']['id_warehouse'], $state);
$storeTransferWorker->commit($order['order']['id_warehouse'], $state);
$storeTransferWorker->commit($order['order']['id_warehouse'], $state);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 8)['pieces']);
$this->assertEquals(2, $this->getPiecesOnPosition(101900, 1718603, 16)['pieces']);
}
public function testLoadOrderStoreItemsStoreTransferWorker()
{
/** @var StoreTransferWorker $storeTransferWorker */
$storeTransferWorker = $this->get(StoreTransferWorker::class);
[$checkouts, $items] = $storeTransferWorker->loadOrderStoreItems('TR1');
$this->assertNotEmpty($items);
}
protected function getStockInRows()
{
$data = [
371506 => new \stdClass(),
371505 => new \stdClass(),
371507 => new \stdClass(),
];
$data[371506]->checked = 2;
$data[371506]->id = 371506;
$data[371506]->id_product = 3822;
$data[371506]->id_variation = null;
$data[371505]->checked = 3;
$data[371505]->id = 371505;
$data[371505]->id_product = 101900;
$data[371505]->id_variation = 1718603;
$data[371507]->checked = 0;
$data[371507]->id = 371507;
$data[371507]->id_product = 101900;
$data[371507]->id_variation = 1718604;
return $data;
}
public function testUncompleteOrderStorno()
{
$this->assertFalse($this->getPiecesOnPosition(101900, null, 13));
$this->assertEquals(1, $this->getPiecesOnPosition(101900, 1718604, 5)['pieces']);
\Order::createFromDbOrderNo('123')->storno(false);
$this->assertEquals(1, $this->getPiecesOnPosition(101900, 1718604, 13)['pieces']);
$this->assertFalse($this->getPiecesOnPosition(101900, null, 12));
$this->assertFalse($this->getPiecesOnPosition(101900, 1718604, 5));
$this->assertFalse(returnSQLResult('SELECT id_position FROM warehouse_orders WHERE id=123'));
}
public function testCompleteOrderStorno()
{
$this->assertEquals(1, sqlQueryBuilder()->update('warehouse_orders')
->set('id_position', 'NULL')->set('date_close', 'NOW()')->where(Operator::equals(['id_order' => 123]))->execute());
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 13));
$this->assertEquals(5, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
\Order::createFromDbOrderNo('123')->storno(false);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 13)['pieces']);
$this->assertEquals(5, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
}
public function testOrderMatchesBox()
{
/** @var StoreItemWorker $StoreItemWorker */
$StoreItemWorker = $this->get(StoreItemWorker::class);
$state = json_decode_strict(returnSQLResult('SELECT state FROM warehouse_orders WHERE id=:id', ['id' => 92]));
$StoreItemWorker->commit(92, $state);
$errors = $StoreItemWorker->checkOrderMatchesBoxContent(92);
$product3822 = new \Product(3822);
$product3822->createFromDB(3822);
$product101900 = new \Product(101900);
$product101900->createFromDB(101900);
$this->assertEquals([
[
'id_product' => '3822',
'id_variation' => null,
'pieces' => '3',
'message' => 'V přepravce chybí 3x produkt Brzdové lanko Shimano DURA-ACE, SIL-TEC, 1,6 x 2050 mm',
'id_item' => '335',
'pieces_box' => '0',
'position' => null,
'product' => $product3822,
'id_order' => 123,
],
[
'id_product' => '101900',
'id_variation' => '1718604',
'pieces' => '0',
'message' => 'V přepravce přebývá 1x produkt Tretry Shimano SH-RT4MM, šedá melange Velikost: 46',
'pieces_box' => '1',
'position' => '2|BOX-2',
'product' => $product101900,
'id_order' => 123,
'batches_in_box' => null,
],
[
'id_product' => '101900',
'id_variation' => '1718603',
'pieces' => '3',
'message' => 'V přepravce je špatný počet kusů (1 přepravka != 3 objednávka) produktu Tretry Shimano SH-RT4MM, šedá melange Velikost: 45',
'id_item' => '333',
'pieces_box' => '1',
'position' => '4|A1-4',
'product' => $product101900,
'id_order' => 123,
'batches_in_box' => null,
],
], $errors);
}
public function testNonProductOrderMatchesBox()
{
/** @var StoreItemWorker $StoreItemWorker */
$StoreItemWorker = $this->get(StoreItemWorker::class);
$errors = $StoreItemWorker->checkOrderMatchesBoxContent(null, 125);
$this->assertEmpty($errors);
}
public function testOrderWithoutRecordInWarehouseOrdersMatchesBox()
{
/** @var StoreItemWorker $StoreItemWorker */
$StoreItemWorker = $this->get(StoreItemWorker::class);
$errors = $StoreItemWorker->checkOrderMatchesBoxContent(null, 123);
$this->assertNotEmpty($errors);
}
public function testSearchProductByEan()
{
/** @var StoreItemWorker $StoreItemWorker */
$StoreItemWorker = $this->get(StoreItemWorker::class);
$this->assertEquals(101900, $StoreItemWorker->checkProductByEanAndLocation(1234567891234, 4)['id_product']);
$this->assertEquals(3823, $StoreItemWorker->checkProductByEanAndLocation(32165498712, 3)['id_product']);
$this->assertEquals(3823, $StoreItemWorker->checkProductByEanAndLocation(999999999999, 3)['id_product']);
}
public function testSorting()
{
/** @var StoreItemWorker $StoreItemWorker */
$StoreItemWorker = $this->get(StoreItemWorker::class);
$errors = $StoreItemWorker->checkOrderMatchesBoxContent(93);
$product4000 = new \Product(4000);
$product4000->createFromDB(4000);
$product101900 = new \Product(101900);
$product101900->createFromDB(101900);
$product5000 = new \Product(5000);
$product5000->createFromDB(5000);
$this->assertEquals([
[
'id_product' => '4000',
'id_variation' => null,
'pieces' => '3',
'id_item' => '338',
'position' => '1|A1-3',
'message' => 'V přepravce chybí 3x produkt Brzdové lanko Shimano DURA-ACE, SIL-TEC, 1,6 x 2050 mm',
'pieces_box' => '0',
'product' => $product4000,
'id_order' => '124',
],
[
'id_product' => '5000',
'id_variation' => null,
'pieces' => '1',
'id_item' => '12345',
'position' => '1|A1-3',
'message' => 'V přepravce chybí 1x produkt Produkt8',
'pieces_box' => '0',
'product' => $product5000,
'id_order' => '124',
],
[
'id_product' => '101900',
'id_variation' => '1718603',
'pieces' => '3',
'id_item' => '339',
'position' => '4|A1-4',
'message' => 'V přepravce chybí 3x produkt Tretry Shimano SH-RT4MM, šedá melange Velikost: 45',
'pieces_box' => '0',
'product' => $product101900,
'id_order' => '124',
],
], $errors);
}
public function testSaveOrderMassCheckout()
{
$this->assertFalse($this->getPiecesOnPosition(101900, 1718603, 5));
$this->assertFalse($this->getPiecesOnPosition(3822, null, 5));
$state = new \stdClass();
$state->checkouts = [];
/** @var StoreItemWorker $stockInWorker */
$stockInWorker = $this->get(StoreItemWorker::class);
$order = $stockInWorker->startMassCheckout(json_decode('[{"order_no":"123","box":"BOX-2"},{"order_no":"124","box":"BOX-6"}]'));
$state->checkouts[0] = $this->getCheckoutItem('1', 'A1-4', '333', '123', '3');
$stockInWorker->commitMass($state);
self::assertArrayHasKey(1, $state->commits);
$state->checkouts[1] = $this->getCheckoutItem('2', 'A1-3', '12345', '124', '1');
$stockInWorker->commitMass($state);
self::assertArrayHasKey(2, $state->commits);
$state->checkouts[3] = $this->getCheckoutItem('3', 'A2-3', '338', '123', '1');
$state->checkouts[4] = $this->getCheckoutItem('4', 'A1-3', '338', '123', '2');
$stockInWorker->commitMass($state);
$this->assertEquals(3, $this->getPiecesOnPosition(101900, 1718603, 5)['pieces']);
$this->assertEquals(2, $this->getPiecesOnPosition(101900, 1718603, 12)['pieces']);
$this->assertEquals(1, $this->getPiecesOnPosition(5000, null, 6)['pieces']);
$this->assertEquals(4, $this->getPiecesOnPosition(5000, null, 4)['pieces']);
$this->assertEquals(3, $this->getPiecesOnPosition(4000, null, 5)['pieces']);
$this->assertEquals(198, $this->getPiecesOnPosition(4000, null, 4)['pieces']);
}
protected function getCheckoutItem($uuid, $position, $id_item, $id_order, $pieces)
{
$checkoutsItem = new \stdClass();
$checkoutsItem->uuid = $uuid;
$checkoutsItem->ean = null;
$checkoutsItem->position = $position;
$checkoutsItem->id_item = $id_item;
$checkoutsItem->id_order = $id_order;
$checkoutsItem->pieces = $pieces;
return $checkoutsItem;
}
public function testStartMassCheckout()
{
/** @var StoreItemWorker $stockInWorker */
$stockInWorker = $this->get(StoreItemWorker::class);
$order = $stockInWorker->startMassCheckout(json_decode('[{"order_no":"123","box":"BOX-2"},{"order_no":"124","box":"BOX-6"}]'));
self::assertTrue($order['result']);
$containsProducts = array_filter($order['order']['items'], function ($item) {
return in_array($item['id'], ['335', '12345']);
});
self::assertEquals(2, count($containsProducts));
$containsIdOrders = array_filter($order['order']['items'], function ($item) {
return $item['id_order'] ?? false;
});
self::assertEquals(count($order['order']['items']), count($containsIdOrders));
$warehouseOrders = sqlQueryBuilder()->select('COUNT(id)')->from('warehouse_orders')
->where(Operator::inIntArray([123, 124], 'id_order'))
->andWhere('id_position IS NOT NULL')
->execute()->fetchColumn();
self::assertEquals(2, $warehouseOrders);
$itemsOrdering = array_map(function ($item) {
return $item['id'];
}, $order['order']['items']);
self::assertEquals(['335', '338', '12345', '336', '101900_1718604', '333', '339'], $itemsOrdering);
}
public function testFinishOrderMassCheckout()
{
$state = new \stdClass();
$state->checkouts = [];
/** @var StoreItemWorker $stockInWorker */
$stockInWorker = $this->get(StoreItemWorker::class);
$order = $stockInWorker->startMassCheckout(json_decode('[{"order_no":"601","box":"BOX-13"},{"order_no":"603","box":"BOX-12"}]'));
$state->checkouts[0] = $this->getCheckoutItem('1', 'A1-3', '650', '600', '2');
$state->checkouts[1] = $this->getCheckoutItem('2', 'A1-3', '651', '602', '1');
$stockInWorker->commitMass($state);
list($checkouts, $items) = $stockInWorker->loadOrderStoreMassItems([600, 602]);
self::assertEquals(602, $checkouts[0]['id_order']);
self::assertEquals(1, $checkouts[0]['pieces']);
self::assertEquals(602, $items[0]['id_order']);
self::assertEquals(2, $items[0]['pieces']);
$state->checkouts[2] = $this->getCheckoutItem('3', 'A1-3', '651', '602', '1');
$stockInWorker->commitMass($state);
$stockInWorker->finishCompletedOrders([600, 602]);
$finishedOrders = sqlQueryBuilder()->select('COUNT(*)')->from('warehouse_orders')
->where(Operator::inIntArray([600, 602], 'id_order'))
->andWhere('date_finish IS NOT NULL')
->execute()->fetchColumn();
self::assertEquals(2, $finishedOrders);
self::assertEquals(2, $this->getPiecesOnPosition(101900, 1718605, 8)['pieces']);
self::assertEquals(2, $this->getPiecesOnPosition(101900, 1718605, 100)['pieces']);
}
}