Step 02 — Conformist (Invoicing)

- Ajout Symfony Messenger comme bus d'intégration
- MessengerSalesEventPublisher remplace le NaivePublisher pour dispatch via Messenger
- WhenOrderConfirmed (Invoicing) : consumer Conformist qui consomme sales.v1.OrderConfirmed tel quel
- Tests de compatibilité Conformist et intégration
- Configuration Messenger avec transport sync
This commit is contained in:
2026-03-04 00:31:08 +01:00
parent 21b8f37411
commit dcc81ec9bb
8 changed files with 454 additions and 3 deletions

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace MiniShop\Invoicing\Interfaces\Messaging;
use MiniShop\Contracts\Sales\V1\Event\OrderConfirmed;
use MiniShop\Invoicing\Application\Command\IssueInvoiceForExternalOrder;
use MiniShop\Invoicing\Application\Command\IssueInvoiceForExternalOrderHandler;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
/**
* Conformist : Invoicing consomme le contrat sales.v1.OrderConfirmed tel quel,
* sans traduction. La dependance upstream est explicite.
*/
#[AsMessageHandler]
final readonly class WhenOrderConfirmed
{
public function __construct(
private IssueInvoiceForExternalOrderHandler $handler,
) {}
public function __invoke(OrderConfirmed $message): void
{
($this->handler)(new IssueInvoiceForExternalOrder(
externalOrderId: $message->orderId,
customerName: 'Customer ' . $message->customerId,
customerAddress: 'N/A',
lines: array_map(
static fn (array $line): array => [
'description' => $line['productName'],
'quantity' => $line['quantity'],
'unitPriceInCents' => $line['unitPriceInCents'],
'currency' => $line['currency'],
],
$message->lines,
),
));
}
}

View File

@@ -0,0 +1,64 @@
<?php
declare(strict_types=1);
namespace MiniShop\Sales\Infrastructure\Messaging;
use MiniShop\Contracts\Sales\V1\Event\OrderCancelled as OrderCancelledContract;
use MiniShop\Contracts\Sales\V1\Event\OrderConfirmed as OrderConfirmedContract;
use MiniShop\Contracts\Sales\V1\Event\OrderPlaced as OrderPlacedContract;
use MiniShop\Sales\Application\Port\SalesEventPublisher;
use MiniShop\Sales\Domain\Event\OrderCancelled;
use MiniShop\Sales\Domain\Event\OrderConfirmed;
use MiniShop\Sales\Domain\Event\OrderPlaced;
use MiniShop\Sales\Domain\Model\OrderLine;
use Symfony\Component\Messenger\MessageBusInterface;
/**
* Publie les evenements de domaine Sales sous forme de contrats Published Language
* via Symfony Messenger. Remplace le NaiveSalesEventPublisher.
*/
final readonly class MessengerSalesEventPublisher implements SalesEventPublisher
{
public function __construct(
private MessageBusInterface $messageBus,
) {}
public function publishOrderPlaced(OrderPlaced $event): void
{
$this->messageBus->dispatch(new OrderPlacedContract(
orderId: $event->orderId->toString(),
customerId: $event->customerId->toString(),
totalInCents: $event->total->amount,
currency: $event->total->currency,
placedAt: $event->placedAt->format(\DateTimeInterface::ATOM),
lines: [],
));
}
public function publishOrderConfirmed(OrderConfirmed $event): void
{
$this->messageBus->dispatch(new OrderConfirmedContract(
orderId: $event->orderId->toString(),
customerId: $event->customerId->toString(),
totalInCents: $event->total->amount,
currency: $event->total->currency,
lines: array_map(
static fn (OrderLine $line): array => [
'productName' => $line->productName,
'quantity' => $line->quantity,
'unitPriceInCents' => $line->unitPrice->amount,
'currency' => $line->unitPrice->currency,
],
$event->lines,
),
));
}
public function publishOrderCancelled(OrderCancelled $event): void
{
$this->messageBus->dispatch(new OrderCancelledContract(
orderId: $event->orderId->toString(),
));
}
}