feat(rental): Sprint D — panier + checkout + carbet integration #77

Merged
tarzzan merged 1 commit from feat/rental-sprint-d into main 2026-06-02 08:44:26 +00:00
Owner

Sprint D — Panier + checkout + intégration carbet

Sous-marketplace de location de matériel, étape 4/5 : flux complet panier → paiement → confirmation, plus l'intégration côté carbet et la page récap pour le locataire.

  • src/lib/rental-cart.ts : schéma Zod, EMPTY_CART, parseCart/serializeCart, diffDays
  • src/lib/rental-cart-server.ts : read/write cookie côté serveur
  • src/components/RentalCartProvider.tsx : context + useCart() (add/remove/update/clear), persistance auto
  • <RentalCartProvider initial={cookie}> wrappé dans layout.tsx (hydratation server→client)

UI panier

  • /panier — récap regroupé par prestataire, sous-totaux, caution
  • Édition lignes (dates / qté) + retrait / vider, bouton « Valider et payer »
  • <AddToCart /> sur /materiel/[itemId] (date picker + qté + feedback)
  • Badge 🛒 dans SiteHeader avec compteur (visible quand panier non vide)

API checkout

  • POST /api/rentals/checkout :
    • Validation auth + items actifs + provider approved + qté/dates
    • Transaction Prisma : recheck stock par fenêtre + crée 1 RentalBooking par prestataire (split auto) + RentalLines (snapshot prix) + RentalItemAvailability (blocage des dispos)
    • Calcule commissionAmount selon provider.commissionPct
    • Stripe activé → Checkout Session unique, 1 line_item par RentalBooking, metadata {type:"rental-bundle", rentalBookingIds:[...]}
    • Stripe désactivé → crée en PENDING, retourne rentalBookingIds
    • Vide le cookie panier, audit log rental.checkout.created
  • Webhook étendu :
    • checkout.session.completed type=rental-bundleupdateMany CONFIRMED+SUCCEEDED
    • payment_intent.payment_failed metadata.rentalBookingIds → CANCELLED + suppression des RentalItemAvailability (libère le stock)

Intégration carbet

  • /carbets/[slug] : nouveau panneau « Compléter votre séjour » qui recommande les items des prestataires de la même rivière + System D
  • /reservations/[id] : nouvelle section « Matériel associé » qui liste les RentalBookings liées au booking carbet
  • /mes-locations : page récap toutes les locations du tenant (System D + tiers, liées carbet ou standalone), avec contact prestataire affiché une fois CONFIRMED
  • Lien « Mes locations » ajouté dans SiteHeader

Test plan

  • Ajouter 2 items au panier depuis /materiel/[itemId] → badge 🛒 affiche 2
  • /panier regroupe par prestataire avec sous-totaux corrects
  • POST /api/rentals/checkout non-authentifié → 401
  • POST /api/rentals/checkout authentifié sans Stripe → crée RentalBookings PENDING + bloque dispos
  • Concurrence : 2 paniers concurrents sur dernier stock → 1 réussit, l'autre 409
  • /carbets/[slug] affiche bien le panneau « Compléter votre séjour » avec items du même fleuve
  • /reservations/[id] montre la section « Matériel associé » si des RentalBookings sont liées
  • /mes-locations liste les locations passées et à venir

🤖 Generated with Claude Code

## Sprint D — Panier + checkout + intégration carbet Sous-marketplace de location de matériel, étape 4/5 : flux complet panier → paiement → confirmation, plus l'intégration côté carbet et la page récap pour le locataire. ### Cart (cookie + React Context) - `src/lib/rental-cart.ts` : schéma Zod, EMPTY_CART, parseCart/serializeCart, diffDays - `src/lib/rental-cart-server.ts` : read/write cookie côté serveur - `src/components/RentalCartProvider.tsx` : context + useCart() (add/remove/update/clear), persistance auto - `<RentalCartProvider initial={cookie}>` wrappé dans `layout.tsx` (hydratation server→client) ### UI panier - `/panier` — récap regroupé par prestataire, sous-totaux, caution - Édition lignes (dates / qté) + retrait / vider, bouton « Valider et payer » - `<AddToCart />` sur `/materiel/[itemId]` (date picker + qté + feedback) - Badge 🛒 dans `SiteHeader` avec compteur (visible quand panier non vide) ### API checkout - `POST /api/rentals/checkout` : - Validation auth + items actifs + provider approved + qté/dates - **Transaction Prisma** : recheck stock par fenêtre + crée 1 RentalBooking par prestataire (split auto) + RentalLines (snapshot prix) + RentalItemAvailability (blocage des dispos) - Calcule commissionAmount selon `provider.commissionPct` - **Stripe activé** → Checkout Session unique, 1 line_item par RentalBooking, metadata `{type:"rental-bundle", rentalBookingIds:[...]}` - **Stripe désactivé** → crée en PENDING, retourne `rentalBookingIds` - Vide le cookie panier, audit log `rental.checkout.created` - Webhook étendu : - `checkout.session.completed` `type=rental-bundle` → `updateMany` CONFIRMED+SUCCEEDED - `payment_intent.payment_failed` `metadata.rentalBookingIds` → CANCELLED + suppression des `RentalItemAvailability` (libère le stock) ### Intégration carbet - `/carbets/[slug]` : nouveau panneau « Compléter votre séjour » qui recommande les items des prestataires de la **même rivière** + System D - `/reservations/[id]` : nouvelle section « Matériel associé » qui liste les RentalBookings liées au booking carbet - `/mes-locations` : page récap toutes les locations du tenant (System D + tiers, liées carbet ou standalone), avec contact prestataire affiché une fois CONFIRMED - Lien « Mes locations » ajouté dans `SiteHeader` ### Test plan - [ ] Ajouter 2 items au panier depuis `/materiel/[itemId]` → badge 🛒 affiche 2 - [ ] `/panier` regroupe par prestataire avec sous-totaux corrects - [ ] `POST /api/rentals/checkout` non-authentifié → 401 - [ ] `POST /api/rentals/checkout` authentifié sans Stripe → crée RentalBookings PENDING + bloque dispos - [ ] Concurrence : 2 paniers concurrents sur dernier stock → 1 réussit, l'autre 409 - [ ] `/carbets/[slug]` affiche bien le panneau « Compléter votre séjour » avec items du même fleuve - [ ] `/reservations/[id]` montre la section « Matériel associé » si des RentalBookings sont liées - [ ] `/mes-locations` liste les locations passées et à venir 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tarzzan added 1 commit 2026-06-02 08:42:31 +00:00
feat(rental): Sprint D — panier + checkout + intégration carbet
Some checks failed
CI / test (pull_request) Failing after 1m8s
91b4d918ea
Cart lib + cookie persistence (karbe-rental-cart, 30j) avec context React
useCart(). Provider wrappé dans layout pour hydratation server→client.

Page /panier :
- Récap regroupé par prestataire (sous-totaux, caution)
- Édition lignes (dates, qté), suppression, vider panier
- Bouton « Valider et payer » → POST /api/rentals/checkout
- Badge 🛒 dans SiteHeader avec total items

Composant <AddToCart /> sur /materiel/[itemId] avec date picker + qté.

API POST /api/rentals/checkout :
- Validation auth + items actifs + provider approved + qté/dates
- Transaction Prisma : recheck stock par fenêtre + crée 1 RentalBooking
  par prestataire + RentalLines (snapshot prix) + RentalItemAvailability
  (blocage des dispos)
- Calcul commissionAmount selon provider.commissionPct
- Si Stripe activé : Checkout Session unique avec 1 line_item par
  RentalBooking, metadata {type:"rental-bundle", rentalBookingIds:[]}
- Sinon : crée en PENDING, retourne rentalBookingIds
- Vide le cookie panier après création
- Audit log rental.checkout.created

Webhook Stripe étendu :
- checkout.session.completed type=rental-bundle → CONFIRMED+SUCCEEDED
  sur toutes les RentalBookings du bundle
- payment_intent.payment_failed metadata.rentalBookingIds → CANCELLED
  + supprime les RentalItemAvailability (libère le stock)

Intégration carbet :
- /carbets/[slug] : panneau « Compléter votre séjour » avec items des
  prestataires de la même rivière + System D (recommandation contextuelle)
- /reservations/[id] : section « Matériel associé » listant les
  RentalBookings liées
- /mes-locations : page récap toutes les locations (System D + tiers,
  liées carbet ou standalone)
- Lien « Mes locations » dans SiteHeader

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tarzzan merged commit 0723e50189 into main 2026-06-02 08:44:26 +00:00
tarzzan deleted branch feat/rental-sprint-d 2026-06-02 08:44:26 +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: tarzzan/karbe#77
No description provided.