feature/vente-manuel #173

Merged
Nora merged 14 commits from feature/vente-manuel into develop 2026-09-04 16:11:33 +00:00
Owner
No description provided.
Nora added 13 commits 2026-09-04 15:27:09 +00:00
Jumeau sobre d'EditionAssigner : l'attribution du numéro passe par le port
Shared ArtworkInventory sous le verrou de ligne, dans une seule transaction
(RG4/RG7), et la commande manuelle porte un payment_intent_id `manual_<id>`
(colonne NOT NULL + UNIQUE). Ni Stripe, ni remboursement, ni idempotence par
event.id : il n'y a pas de livraison rejouable ici, deux enregistrements = deux
tirages, ce qui est le comportement voulu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Le dispatch part dans la transaction (outbox : le transport `critical` est
Doctrine) et vise directement GenerateCertificateMessage. OrderPaid reste
réservé au tunnel Stripe : il déclencherait Gelato, la facture et l'e-mail
client, sans objet pour un tirage imprimé à la maison.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Runner inerte : ni édition vendue, ni commande écrite, ni certificat demandé.
Vérifié par mutation (sortir sellOneEdition de la closure casse le test). Seul
nextId() reste hors transaction, pour un id stable au retry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Au plafond (RG7), l'exception traverse le use case sans être attrapée : sans
paiement encaissé, RG9 ne s'applique pas, il n'y a rien à rembourser. Ni
commande, ni demande de certificat. Mutation vérifiée (avaler l'exception casse
le test).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Port Shared PublishedProjectionCache, appelé après la transaction : purger un
cache de lecture ne fait pas partie de l'unité de travail, et une vente qui
échoue n'atteint jamais cette ligne. Sans ça, la fiche publique garderait son
compte d'exemplaires — et raterait la bascule « épuisée » — jusqu'à la
publication suivante.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
ManualSaleInput + ManualSaleType : format pris dans le catalogue existant (aucun
nouveau case PrintFormat, startingPrice() réduit sur tous), prix en centimes
(MoneyType rendrait un float, le domaine compte en entiers), 0 accepté pour un
tirage perso, pays validé ici pour que ShippingAddress ne lève pas un 500.
csrf_protection à false : le jeton est vérifié par le contrôleur, comme les
autres actions POST du back-office.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
GET /admin/manual-sale/{artworkId} : rappel de l'œuvre (génération, algorithme,
vendus/plafond) et formulaire pré-rempli (format 30x40 nu à son prix catalogue,
adresse studio depuis app.manual_sale.*). Hors CRUD Œuvres, qui ne gagne aucune
méthode. Œuvre inconnue → 404, jamais un 500. ManualSaleDefaults regroupe les
sept scalaires pour tenir le budget de paramètres du contrôleur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Jeton vérifié explicitement (403 sinon), formulaire invalide ré-affiché sans
vente, sinon appel du use case puis flash « Édition n/plafond attribuée » et
retour aux Commandes, où vivent déjà les boutons certificat. GET refusé (405) :
une vente ne part jamais d'un lien préchargé.

L'œuvre n'est volontairement pas chargée avant la vente : l'inventaire la prend
en SELECT … FOR UPDATE, et relire une ligne déjà suivie par l'EntityManager de
la requête ré-hydrate un agrégat aux propriétés readonly (500).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Les deux refus de l'agrégat (plafond atteint RG7, statut non vendable) sont des
états ordinaires du back-office : message et retour sur l'écran de confirmation,
là où l'admin a cliqué — il n'y a aucune commande à montrer. Le template rend
désormais les flashes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Action linkToRoute (comme les boutons sociaux), index + détail, visible sur le
seul statut published — plus strict que le prédicat social, qui couvre aussi
sold_out où la vente serait toujours refusée. Aucune méthode ajoutée au
contrôleur : il ne connaît qu'un nom de route.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
editions_sold +1 par l'agrégat, ligne shop_order avec le bon numéro d'édition et
un payment_intent_id préfixé manual_, GenerateCertificateMessage sur le
transport durable critical et rien sur async. Dernier exemplaire → statut
sold_out. Mutation vérifiée : retirer le dispatch fait tomber le test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
docs: vente manuelle livrée, plan supprimé (T12)
Some checks failed
CI / Renderer - couverture JS (pull_request) Has been skipped
CI / Renderer - audit des dépendances JS (pull_request) Successful in 1m42s
CI / Renderer - tests + lint JS (pull_request) Successful in 12m12s
CI / PHP - tests + static + lint (pull_request) Failing after 14m35s
900bdedae2
Une ligne dans CLAUDE.md §Back-office ; le plan et ses douze fiches disparaissent
(convention du dépôt, récupérables en git). Rien au backlog : les réserves du
plan sont des choix assumés. Go-live = déploiement applicatif normal, puis
renseigner l'adresse studio réelle dans app.manual_sale.*.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
fix(shop): vente manuelle passe par un event Shared pour le certificat
All checks were successful
CI / Renderer - couverture JS (pull_request) Has been skipped
CI / Renderer - audit des dépendances JS (pull_request) Successful in 53s
CI / Renderer - tests + lint JS (pull_request) Successful in 6m52s
CI / PHP - tests + static + lint (pull_request) Successful in 7m30s
ee12df9da6
Le guard mago interdit à Shop de référencer App\Fulfillment\Application :
RecordManualSale dispatchait GenerateCertificateMessage en direct. L'intention
voyage désormais en App\Shared\Event\CertificateRequested (transport durable
`critical`, toujours dans la transaction = outbox), et Fulfillment garde le
travail via RequestCertificate, jumeau de RegenerateCertificate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGcN9W9G34uwKgR333uGvh
Nora merged commit dab3961943 into develop 2026-09-04 16:11:33 +00:00
Nora deleted branch feature/vente-manuel 2026-09-04 16:11:34 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Nora/ArtAutomatic!173
No description provided.