feat(rental): Sprint M — refonds + annulations Stripe #87
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/rental-sprint-m"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Sprint M — Refonds + annulations rental Stripe
Complète le flow rental : actuellement l'annulation se fait juste en flippant
status=CANCELLEDsans refund/email/release. Sprint M ajoute la vraie logique métier.Politique de remboursement v1
src/lib/rental-refund.ts(NEW)computeRentalRefund({startDate, itemsTotal, depositTotal, now?})→{ itemsRefund, depositRefund, totalRefund, policy, policyLabel }. Arrondi au centime, support Prisma.Decimal.POST /api/rentals/[id]/cancelcancelledBypour adapter l'emailrefunds.create. Échec Stripe = audit-logged mais le flip status continue (l'asso pourra rembourser manuellement)deleteManyRentalItemAvailability (libère le stock)rental.cancelavec montants, policy, cancelledBy, stripeRefundId, stripeRefundErrorsendRentalCancelledà tenant + provider (sauf si provider est le canceller)<CancelRentalButton />Composant client confirm dialog inline avec textarea motif (max 500 chars). Branché sur :
/mes-locations— « Annuler ma location » sur résa PENDING/CONFIRMEDBookingDecision(utilisé par/espace-prestataire/reservationsET/espace-ce/materiel/reservations) — remplace l'ancienne mini-confirm qui flippait juste le status, désormais via la vraie API refundEmail
sendRentalCancelled(to, firstName, rbId, providerName, refundAmount, currency, policyLabel, cancelledBy)— texte adapté selon cancelledBy ("Vous avez annulé" / " a annulé" / "L'équipe Karbé a annulé"). Mention TTL Stripe 3-5j.Tests
tests/lib/rental-refund.test.ts(8 cas) : FULL @ 10+ jours et @ 7j exact, PARTIAL_50, DEPOSIT_ONLY < 24h + passé, arrondi centime, zéro caution, policyLabel content checks.70/70 tests ✓ (62 précédents + 8 nouveaux). Lint + typecheck + build ✓.
Test plan
/mes-locations→ bouton « Annuler ma location » sur résa CONFIRMED future → confirm dialog → API → DB CANCELLED + REFUNDED + availability supprimée + emails dry-run/espace-prestataire/reservations→ bouton Annuler → idem/espace-ce/materiel/reservations→ bouton Annuler → idem🤖 Generated with Claude Code
Politique de remboursement v1 : - > 7 jours du début → FULL (location + caution) - 1 à 7 jours → PARTIAL_50 (50% location + caution intégrale) - < 24h ou passé → DEPOSIT_ONLY (caution seulement, pas de remboursement sur la location) src/lib/rental-refund.ts (NEW) : computeRentalRefund({startDate, itemsTotal, depositTotal}) → { itemsRefund, depositRefund, totalRefund, policy, policyLabel }. Arrondi au centime, support de Decimal. POST /api/rentals/[id]/cancel : - Auth multi-rôle : tenant de la booking, RENTAL_PROVIDER nominal ou CE_MANAGER de l'org du provider, ADMIN. Détecte `cancelledBy` pour adapter l'email. - Refuse si status ∉ {PENDING, CONFIRMED} (HANDED_OVER → non annulable, contacter Karbé). - Calcule le refund selon la politique. - Stripe refund best-effort si paymentStatus=SUCCEEDED + stripeSessionId existante + isStripeConfigured + totalRefund > 0. Retrieve session → payment_intent → refunds.create. Échec Stripe = audit-logged mais le flip status continue (l'asso pourra rembourser manuellement). - Transaction : update RentalBooking (CANCELLED + paymentStatus REFUNDED si SUCCEEDED sinon FAILED) + delete RentalItemAvailability (libère stock). - Audit log rental.cancel avec montants, policy, cancelledBy, stripeRefundId, stripeRefundError. - Email best-effort : sendRentalCancelled à tenant + provider (sauf si provider est le canceller). src/components/CancelRentalButton.tsx : composant client confirm dialog inline avec textarea motif (max 500 chars). Branché sur : - /mes-locations : « Annuler ma location » sur résa PENDING/CONFIRMED - BookingDecision (utilisé par /espace-prestataire/reservations ET /espace-ce/materiel/reservations) : remplace l'ancienne mini-confirm qui flippait juste le status, désormais via la vraie API refund sendRentalCancelled email : adapté selon cancelledBy ("Vous avez annulé" / "<Provider> a annulé" / "L'équipe Karbé a annulé"). tests/lib/rental-refund.test.ts : 8 cas (FULL @ 10+ et 7j, PARTIAL_50, DEPOSIT_ONLY < 24h et passé, arrondi centime, zéro caution, policyLabel). Total projet : 70/70 ✓. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>