fix(checkin): bump invoice.status pending → awaiting_user_confirmation
All checks were successful
Build & Deploy API / build-and-deploy (push) Successful in 1m6s
All checks were successful
Build & Deploy API / build-and-deploy (push) Successful in 1m6s
Bug V1 documenté dans flow.md mais jamais corrigé : le job send_checkin_job
envoyait l'email + marquait la CheckinTask `sent`, mais ne touchait pas le
statut de la facture. Conséquence : l'user reçoit le mail check-in dans sa
boîte mais la modale in-app au refresh ne l'affiche pas (la modale liste
uniquement les `awaiting_user_confirmation` côté DB).
Fix : après l'envoi mail OK et le mark CheckinTask=sent, on bump
`Invoice.status = 'awaiting_user_confirmation'` SI elle est encore
en `pending`. Pas de bump si entre temps :
- mark-paid (status=paid)
- litigation/cancelled (transitions manuelles)
- in_relance (impossible mais safe)
Doc flow.md mise à jour pour refléter le nouveau comportement (effets
de la transition pending → awaiting + déprécation de la note "TODO V1.5").
Pour les factures existantes en prod qui ont déjà reçu le mail mais
restent en `pending` (cas pré-fix) : backfill manuel via SQL :
UPDATE invoices SET status = 'awaiting_user_confirmation'
WHERE status = 'pending'
AND id IN (
SELECT invoice_id FROM checkin_tasks WHERE status = 'sent'
);
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
023f08c261
commit
ab75f1f979
@ -63,7 +63,23 @@ export async function sendCheckinJob(jobData: { taskId: string; plain: string })
|
||||
pendingUrl,
|
||||
})
|
||||
|
||||
const sentAt = await clock.now(invoice.organizationId)
|
||||
task.status = 'sent'
|
||||
task.sentAt = await clock.now(invoice.organizationId)
|
||||
task.sentAt = sentAt
|
||||
await task.save()
|
||||
|
||||
// Bascule le statut de la facture en `awaiting_user_confirmation`. Le
|
||||
// check-in vient de partir, l'user doit répondre. C'est ce statut que
|
||||
// la modale in-app (`/api/v1/checkin/inapp/pending`) liste pour rappeler
|
||||
// à l'user qu'il y a des décisions à prendre.
|
||||
// Ne touche pas si le statut a déjà bougé entre temps (in_relance, paid,
|
||||
// litigation, etc.) — only bump from `pending`.
|
||||
if (invoice.status === 'pending') {
|
||||
invoice.status = 'awaiting_user_confirmation'
|
||||
await invoice.save()
|
||||
logger.info(
|
||||
{ invoiceId: invoice.id, numero: invoice.numero },
|
||||
'sendCheckinJob: invoice status bumped pending → awaiting_user_confirmation'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
14
docs/flow.md
14
docs/flow.md
@ -92,8 +92,11 @@ Transitions manuelles (par l'user, depuis la fiche facture) :
|
||||
|
||||
#### `pending → awaiting_user_confirmation`
|
||||
- **Qui déclenche** : le scheduler `CheckinTask`, automatiquement, quand `dueDate` est atteinte.
|
||||
- **Effet** : un email check-in part à l'user (pas au client) avec 2 liens *Oui (payée)* / *Non (toujours impayée)*. La `CheckinTask` est marquée `sent`.
|
||||
- **Note V1** : dans la prod actuelle, le statut DB de l'invoice reste techniquement `pending` jusqu'à ce que l'user réponde — c'est le seed démo qui force `awaiting_user_confirmation` pour pré-peupler des cas. À aligner V1.5 (le job `send_checkin_job` devrait push le statut).
|
||||
- **Effet** :
|
||||
- Un email check-in part à l'user (pas au client) avec 2 liens *Oui (payée)* / *Non (toujours impayée)*
|
||||
- La `CheckinTask` est marquée `sent`
|
||||
- **L'`Invoice.status` passe de `pending` à `awaiting_user_confirmation`** (uniquement si encore en `pending` — pas de bump si la facture a été marquée payée ou autre entre temps)
|
||||
- Côté SPA : la modale check-in `usePendingCheckins` voit désormais cette facture et l'affiche au prochain login / refocus
|
||||
|
||||
#### `awaiting_user_confirmation → paid` (réponse "Oui")
|
||||
- **Qui déclenche** : l'user, via 4 surfaces possibles :
|
||||
@ -223,8 +226,11 @@ Sans ça, le SaaS ferait peur (peur de relancer un client qui vient de payer). A
|
||||
### 5.2 Architecture des `CheckinTask`
|
||||
|
||||
- Un `CheckinTask` est créé à la création de l'invoice (sauf si `pending` future) — programmé pour `dueDate`.
|
||||
- Au moment où le job tourne (queue `checkins`), il envoie l'email à l'user, marque la task `sent`, mais **ne change PAS le statut de l'invoice côté prod** (TODO V1.5 — bascule en `awaiting_user_confirmation` quand l'email est envoyé).
|
||||
- L'user a 24h (TTL) pour cliquer un des 2 liens email. Au-delà, la task expire (status `expired`) — elle ne refire pas, mais l'user peut toujours répondre via la modale in-app ou la fiche.
|
||||
- Au moment où le job tourne (queue `checkins`), il :
|
||||
1. Envoie l'email à l'user
|
||||
2. Marque la `CheckinTask.status = 'sent'`
|
||||
3. **Bump l'`Invoice.status` en `awaiting_user_confirmation`** si encore `pending` (la modale in-app la voit alors)
|
||||
- L'user a 24h (TTL) pour cliquer un des 2 liens email. Au-delà, la task expire (status `expired`) — elle ne refire pas, mais l'user peut toujours répondre via la modale in-app ou la fiche (le statut reste `awaiting_user_confirmation` tant qu'il n'a pas répondu).
|
||||
|
||||
### 5.3 Architecture des `RelanceTask`
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user