setUpDB(); $this->orderRepository = $this->container->get(OrderRepository::class); $this->orderItemRepository = $this->container->get(OrderItemRepository::class); $this->drinkTypeRepository = $this->container->get(DrinkTypeRepository::class); $this->inventoryService = $this->container->get(InventoryService::class); $this->configService = $this->container->get(ConfigurationService::class); $this->service = $this->container->get(OrderService::class); // Create a drink type for testing $this->drinkType = new DrinkType('Cola', 'Refreshing cola drink', 10); $this->drinkTypeRepository->save($this->drinkType); } public function testGetAllOrders(): void { // Initially the repository should be empty $this->assertCount(0, $this->service->getAllOrders()); // Create some orders $order1 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-01')); $order2 = new Order(Order::STATUS_FULFILLED, new DateTimeImmutable('2023-01-02')); $this->orderRepository->save($order1); $this->orderRepository->save($order2); // Now getAllOrders should return both orders $orders = $this->service->getAllOrders(); $this->assertCount(2, $orders); $this->assertContainsOnlyInstancesOf(Order::class, $orders); } public function testGetOrderById(): void { // Create an order $order = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-01')); $this->orderRepository->save($order); // Get the ID $id = $order->getId(); $this->assertNotNull($id); // Find by ID $foundOrder = $this->service->getOrderById($id); $this->assertInstanceOf(Order::class, $foundOrder); $this->assertEquals(Order::STATUS_NEW, $foundOrder->getStatus()); $this->assertEquals('2023-01-01', $foundOrder->getCreatedAt()->format('Y-m-d')); // Try to find a non-existent ID $nonExistentId = 9999; $this->assertNull($this->service->getOrderById($nonExistentId)); } public function testGetOrdersByStatus(): void { // Create orders with different statuses $order1 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-01')); $order2 = new Order(Order::STATUS_IN_WORK, new DateTimeImmutable('2023-01-02')); $order3 = new Order(Order::STATUS_ORDERED, new DateTimeImmutable('2023-01-03')); $order4 = new Order(Order::STATUS_FULFILLED, new DateTimeImmutable('2023-01-04')); $order5 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-05')); $this->orderRepository->save($order1); $this->orderRepository->save($order2); $this->orderRepository->save($order3); $this->orderRepository->save($order4); $this->orderRepository->save($order5); // Get orders by status $newOrders = $this->service->getOrdersByStatus(Order::STATUS_NEW); $this->assertCount(2, $newOrders); $this->assertContainsOnlyInstancesOf(Order::class, $newOrders); // Check that the orders have the correct status foreach ($newOrders as $order) { $this->assertEquals(Order::STATUS_NEW, $order->getStatus()); } // Get orders by another status $fulfilledOrders = $this->service->getOrdersByStatus(Order::STATUS_FULFILLED); $this->assertCount(1, $fulfilledOrders); $this->assertEquals(Order::STATUS_FULFILLED, $fulfilledOrders[0]->getStatus()); } public function testGetOrdersByDateRange(): void { // Create orders with different dates $order1 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-01')); $order2 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-02')); $order3 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-03')); $order4 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-04')); $order5 = new Order(Order::STATUS_NEW, new DateTimeImmutable('2023-01-05')); $this->orderRepository->save($order1); $this->orderRepository->save($order2); $this->orderRepository->save($order3); $this->orderRepository->save($order4); $this->orderRepository->save($order5); // Get orders in a specific date range $start = new DateTimeImmutable('2023-01-02'); $end = new DateTimeImmutable('2023-01-04'); $orders = $this->service->getOrdersByDateRange($start, $end); $this->assertCount(3, $orders); // Check that the orders are within the date range foreach ($orders as $order) { $createdAt = $order->getCreatedAt(); $this->assertTrue($createdAt >= $start && $createdAt <= $end); } } public function testCreateOrder(): void { // Create an order with items $items = [ ['drinkTypeId' => $this->drinkType->getId(), 'quantity' => 5], ]; $order = $this->service->createOrder($items); // Check that the order was created correctly $this->assertInstanceOf(Order::class, $order); $this->assertEquals(Order::STATUS_NEW, $order->getStatus()); // Refresh the order from the database $refreshedOrder = $this->service->getOrderById($order->getId()); $this->assertInstanceOf(Order::class, $refreshedOrder); // Check that the order items were created correctly $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(1, $orderItems); $orderItem = $orderItems->first(); $this->assertEquals($this->drinkType->getId(), $orderItem->getDrinkType()->getId()); $this->assertEquals(5, $orderItem->getQuantity()); // Try to create an order with an invalid drink type ID $this->expectException(InvalidArgumentException::class); $this->service->createOrder([['drinkTypeId' => 9999, 'quantity' => 5]]); } public function testCreateOrderFromStockLevels(): void { // Set the low stock threshold to 70% so that 3/5 (60%) is considered low stock $this->configService->setConfigValue(SystemSettingKey::LOW_STOCK_THRESHOLD->value, '70'); // Create a drink type with low stock $drinkType = new DrinkType('Fanta', 'Orange soda', 5); $this->drinkTypeRepository->save($drinkType); // Create inventory records $this->inventoryService->updateStockLevel($this->drinkType, 15); // Excess stock $this->inventoryService->updateStockLevel($drinkType, 3); // Low stock // Create an order from stock levels $order = $this->service->createOrderFromStockLevels(); // Check that the order was created correctly $this->assertInstanceOf(Order::class, $order); $this->assertEquals(Order::STATUS_NEW, $order->getStatus()); // Refresh the order from the database $refreshedOrder = $this->service->getOrderById($order->getId()); $this->assertInstanceOf(Order::class, $refreshedOrder); // Check that the order items were created correctly $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(1, $orderItems); // Only one drink type has low stock $orderItem = $orderItems->first(); $this->assertEquals($drinkType->getId(), $orderItem->getDrinkType()->getId()); $this->assertEquals(2, $orderItem->getQuantity()); // Shortage is 2 } public function testUpdateOrderStatus(): void { // Create an order $order = new Order(Order::STATUS_NEW); $this->orderRepository->save($order); // Update the status $updatedOrder = $this->service->updateOrderStatus($order, Order::STATUS_IN_WORK); $this->assertEquals(Order::STATUS_IN_WORK, $updatedOrder->getStatus()); // Check that it was updated in the database $foundOrder = $this->service->getOrderById($order->getId()); $this->assertEquals(Order::STATUS_IN_WORK, $foundOrder->getStatus()); // Update to fulfilled status $orderItem = new OrderItem($this->drinkType, 5, $foundOrder); $this->orderItemRepository->save($orderItem); // Refresh the order from the database $refreshedOrder = $this->service->getOrderById($foundOrder->getId()); $this->assertInstanceOf(Order::class, $refreshedOrder); $this->assertCount(1, $refreshedOrder->getOrderItems()); // Create an initial inventory record with a specific timestamp $timestamp1 = new DateTimeImmutable('2023-01-01 10:00:00'); $this->inventoryService->updateStockLevel($this->drinkType, 10, $timestamp1); // Update the status to fulfilled $updatedOrder = $this->service->updateOrderStatus($refreshedOrder, Order::STATUS_FULFILLED); $this->assertEquals(Order::STATUS_FULFILLED, $updatedOrder->getStatus()); // Check that the inventory was updated with a new record that has a later timestamp $currentStock = $this->inventoryService->getCurrentStockLevel($this->drinkType); $this->assertEquals(15, $currentStock); // 10 + 5 = 15 // Try to update to an invalid status $this->expectException(InvalidArgumentException::class); $this->service->updateOrderStatus($updatedOrder, 'invalid_status'); } public function testAddOrderItem(): void { // Create an order $order = new Order(Order::STATUS_NEW); $this->orderRepository->save($order); // Add an item $orderItem = $this->service->addOrderItem($order, $this->drinkType, 5); // Check that the item was added correctly $this->assertInstanceOf(OrderItem::class, $orderItem); $this->assertEquals($this->drinkType->getId(), $orderItem->getDrinkType()->getId()); $this->assertEquals(5, $orderItem->getQuantity()); $this->assertEquals($order->getId(), $orderItem->getOrder()->getId()); // Refresh the order from the database $refreshedOrder = $this->service->getOrderById($order->getId()); $this->assertInstanceOf(Order::class, $refreshedOrder); // Check that the item is in the order $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(1, $orderItems); $this->assertEquals($orderItem->getId(), $orderItems->first()->getId()); // Add another item for the same drink type $orderItem2 = $this->service->addOrderItem($refreshedOrder, $this->drinkType, 3); // Check that the quantity was updated $this->assertEquals(8, $orderItem2->getQuantity()); // 5 + 3 = 8 // Refresh the order again $refreshedOrder = $this->service->getOrderById($refreshedOrder->getId()); // Check that there's still only one item in the order $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(1, $orderItems); // Create another drink type $anotherDrinkType = new DrinkType('Fanta', 'Orange soda', 5); $this->drinkTypeRepository->save($anotherDrinkType); // Add an item for the new drink type $orderItem3 = $this->service->addOrderItem($refreshedOrder, $anotherDrinkType, 2); // Check that the item was added correctly $this->assertInstanceOf(OrderItem::class, $orderItem3); $this->assertEquals($anotherDrinkType->getId(), $orderItem3->getDrinkType()->getId()); $this->assertEquals(2, $orderItem3->getQuantity()); // Refresh the order again $refreshedOrder = $this->service->getOrderById($refreshedOrder->getId()); // Check that there are now two items in the order $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(2, $orderItems); // Try to add an item to an order that's not in 'new' or 'in_work' status $refreshedOrder->setStatus(Order::STATUS_ORDERED); $this->orderRepository->save($refreshedOrder); $this->expectException(InvalidArgumentException::class); $this->service->addOrderItem($refreshedOrder, $this->drinkType, 1); } public function testRemoveOrderItem(): void { // Create an order $order = new Order(Order::STATUS_NEW); $this->orderRepository->save($order); // Add an item $orderItem = $this->service->addOrderItem($order, $this->drinkType, 5); // Refresh the order from the database $refreshedOrder = $this->service->getOrderById($order->getId()); $this->assertInstanceOf(Order::class, $refreshedOrder); // Check that the item is in the order $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(1, $orderItems); $this->assertEquals($orderItem->getId(), $orderItems->first()->getId()); // Remove the item $this->service->removeOrderItem($refreshedOrder, $orderItem); // Refresh the order again $refreshedOrder = $this->service->getOrderById($refreshedOrder->getId()); // Check that the item is gone $orderItems = $refreshedOrder->getOrderItems(); $this->assertCount(0, $orderItems); // Try to remove an item from an order that's not in 'new' or 'in_work' status $refreshedOrder->setStatus(Order::STATUS_ORDERED); $this->orderRepository->save($refreshedOrder); $orderItem = new OrderItem($this->drinkType, 5, $refreshedOrder); $this->orderItemRepository->save($orderItem); $this->expectException(InvalidArgumentException::class); $this->service->removeOrderItem($refreshedOrder, $orderItem); } public function testDeleteOrder(): void { // Create an order $order = new Order(Order::STATUS_NEW); $this->orderRepository->save($order); // Get the ID $id = $order->getId(); $this->assertNotNull($id); // Check that it exists $this->assertInstanceOf(Order::class, $this->service->getOrderById($id)); // Delete it $this->service->deleteOrder($order); // Check that it's gone $this->assertNull($this->service->getOrderById($id)); // Try to delete an order that's not in 'new' status $order = new Order(Order::STATUS_IN_WORK); $this->orderRepository->save($order); $this->expectException(InvalidArgumentException::class); $this->service->deleteOrder($order); } }