- Removed fully qualified names for better readability. - Streamlined code by using direct class references.
116 lines
3.4 KiB
PHP
116 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Domain\Models\Entities;
|
|
|
|
use Carbon\CarbonImmutable;
|
|
use Domain\Enums\OrderStatus;
|
|
use Domain\Events\AnOrderHasBeenPlaced;
|
|
use Domain\Events\Dto\OrderPlacedLine;
|
|
use Domain\Events\Dto\OrderPlacedShop;
|
|
use Domain\Models\ValueObjects\BasketProduct;
|
|
use Domain\Models\ValueObjects\DeliveryAddress;
|
|
use Domain\Models\ValueObjects\Entities\OrderId;
|
|
use Domain\Models\ValueObjects\Entities\ShopId;
|
|
use Domain\Models\ValueObjects\OrderEmployee;
|
|
use Domain\Models\ValueObjects\OrderLine;
|
|
use Domain\Models\ValueObjects\OrderReference;
|
|
use Domain\Models\ValueObjects\PickupTimeSlot;
|
|
use Money\Money;
|
|
use Shared\DDD\Entity;
|
|
|
|
/** @implements \Shared\DDD\Entity<\Domain\Models\ValueObjects\Entities\OrderId> */
|
|
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
|
|
)
|
|
);
|
|
}
|
|
}
|