*/ final class Order implements Entity { public function __construct( public readonly OrderId $id, public readonly ShopId $shopId, public readonly OrderReference $reference, public readonly OrderEmployee $employee, public readonly DeliveryAddress $deliveryAddress, public readonly PickupTimeSlot $pickupTimeSlot, public OrderStatus $status, private readonly Money $total, /** @var OrderLine[] */ private array $lines, ) { if ($total->getAmount() <= 0) { throw new \DomainException('Total amount must be greater than zero'); } foreach ($lines as $line) { if (! ($line instanceof OrderLine)) { throw new \DomainException('All lines must be instances of OrderLine'); } } } #[\Override] public function id(): OrderId { return $this->id; } public function getTotal(): Money { return $this->total; } /** @return OrderLine[] */ public function getLines(): array { return $this->lines; } public function cancel(): void { if ($this->status === OrderStatus::CANCELED) { return; } $this->status = OrderStatus::CANCELED; } public static function fromBasket( OrderId $id, OrderReference $reference, Basket $basket, PickupTimeSlot $pickupTimeSlot, Shopper $shopper, Shop $shop ): self { $lines = array_map( fn (BasketProduct $item) => OrderLine::fromBasketProduct($item), array_values($basket->items()) ); return new self( id: $id, shopId: clone $shop->id(), reference: $reference, employee: OrderEmployee::fromShopper($shopper), deliveryAddress: DeliveryAddress::fromShop($shop), pickupTimeSlot: clone $pickupTimeSlot, status: OrderStatus::VALIDATED, total: clone $basket->totalTaxIncluded(), lines: $lines ); } public function toPlacedEvent(): AnOrderHasBeenPlaced { return new AnOrderHasBeenPlaced( orderId: $this->id(), reference: $this->reference, totalTtc: $this->getTotal(), byMatricule: $this->employee->matricule, employee: clone $this->employee, shop: OrderPlacedShop::fromDeliveryAddress($this->deliveryAddress), pickupDay: CarbonImmutable::instance($this->pickupTimeSlot->getAt()), lines: array_map( fn (OrderLine $line) => OrderPlacedLine::fromOrderLine($line), $this->lines ) ); } }