ldc-boutique-cnc-sable/infra/Adapters/Repositories/EloquentOrderRepository.php
2026-10-27 09:58:12 +01:00

147 lines
5 KiB
PHP

<?php
declare(strict_types=1);
namespace Infrastructure\Adapters\Repositories;
use App\Models\Order;
use App\Models\OrderLine;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterval;
use Domain\Models\Entities\Order as DomainOrder;
use Domain\Models\ValueObjects\Entities\OrderId;
use Domain\Models\ValueObjects\Entities\ShopId;
use Domain\Models\ValueObjects\OrderLine as DomainOrderLine;
use Domain\Models\ValueObjects\PickupTimeSlot;
use Domain\Ports\Repositories\OrderRepository;
use Illuminate\Support\Carbon;
use Ramsey\Uuid\Uuid;
class EloquentOrderRepository implements OrderRepository
{
#[\Override]
public function find(OrderId $id): ?DomainOrder
{
$eloquentOrder = Order::query()
->with('lines')
->where('id', $id->value)
->first();
if (! $eloquentOrder) {
return null;
}
return $this->toEntity($eloquentOrder);
}
#[\Override]
public function persist(DomainOrder $order): void
{
$eloquentOrder = Order::query()
->where('id', $order->id->value->toString())
->firstOrNew();
$eloquentOrder->id = $order->id->value->toString();
$eloquentOrder->shop_id = $order->shopId->value->toString();
$eloquentOrder->reference = $order->reference;
$eloquentOrder->employee = clone $order->employee;
$eloquentOrder->delivery_address = clone $order->deliveryAddress;
$eloquentOrder->pickup_day = Carbon::instance($order->pickupTimeSlot->getAt());
$eloquentOrder->status = $order->status;
$eloquentOrder->total = clone $order->getTotal();
$eloquentOrder->save();
OrderLine::query()
->where('order_id', $order->id->value->toString())
->delete();
$linesToInsert = [];
$now = now();
foreach ($order->getLines() as $line) {
$eloquentOrderLine = new OrderLine();
$eloquentOrderLine->order_id = $order->id->value->toString();
$eloquentOrderLine->product = clone $line->product;
$eloquentOrderLine->quantity = $line->quantity;
$eloquentOrderLine->total_ttc = clone $line->totalTtc;
// Use values directly from the domain OrderLine
$eloquentOrderLine->tax_rate = $line->product->taxRate;
$eloquentOrderLine->unit_price = clone $line->unitPriceHt;
$eloquentOrderLine->unit_tax = clone $line->unitTax;
$eloquentOrderLine->unit_discount = clone $line->unitDiscount;
$eloquentOrderLine->total_discount = clone $line->totalDiscount;
$eloquentOrderLine->total_ht = clone $line->totalHt;
$eloquentOrderLine->total_tax = clone $line->totalTax;
$attributes = $eloquentOrderLine->getAttributes();
$attributes['created_at'] = $now;
$attributes['updated_at'] = $now;
$linesToInsert[] = $attributes;
}
if (! empty($linesToInsert)) {
OrderLine::query()->insert($linesToInsert);
}
}
#[\Override]
public function delete(DomainOrder $order): void
{
Order::query()
->where('id', $order->id->value)
->delete();
}
/** @return array<int, DomainOrder> */
public function getAll(): array
{
return Order::query()
->with('lines')
->get()
->map(fn (Order $eloquentOrder) => $this->toEntity($eloquentOrder))
->all();
}
private function toEntity(Order $model): DomainOrder
{
$lines = $model->lines->map(function (OrderLine $line) {
return new DomainOrderLine(
product: $line->product,
quantity: $line->quantity,
unitPriceHt: $line->unit_price,
unitDiscount: $line->unit_discount,
unitTax: $line->unit_tax,
totalHt: $line->total_ht,
totalDiscount: $line->total_discount,
totalTax: $line->total_tax,
totalTtc: $line->total_ttc
);
})->all();
if ($model->shop === null) {
throw new \UnexpectedValueException('Order missing shop');
}
if ($model->employee === null) {
throw new \UnexpectedValueException('Order missing employee');
}
return new DomainOrder(
id: $model->getId(),
shopId: new ShopId(Uuid::fromString((string) $model->shop_id)),
reference: $model->reference,
employee: clone $model->employee,
deliveryAddress: clone $model->delivery_address,
pickupTimeSlot: new PickupTimeSlot(
$model->pickup_day ? CarbonImmutable::instance($model->pickup_day) : CarbonImmutable::now(),
CarbonInterval::minutes(PickupTimeSlot::LENGTH)
),
status: $model->status,
total: clone $model->total,
lines: $lines
);
}
}