refactor: ( bookings ) unify authenticated booking flow with guest service

This commit is contained in:
Abubeker Yasin
2026-07-27 11:07:33 +03:00
parent dfef97a718
commit afcae037fc
11 changed files with 283 additions and 84 deletions

View File

@@ -296,9 +296,10 @@ export class IntentsService {
* expiresAt, so opening a fresh session would leave two concurrently-payable
* sessions and invite a double charge (observed in prod: a superseded Telebirr
* session was paid after cancellation, orphaning the capture).
* - Expired, or the requested amount/currency changed: retired (CANCELLED, no
* notification — nothing was paid; a payment.failed here would wrongly fail the
* domain order mid-retry) and null is returned so the caller opens a fresh session.
* - Expired, or the requested amount/currency or platform (web↔mobile) changed:
* retired (CANCELLED, no notification — nothing was paid; a payment.failed here
* would wrongly fail the domain order mid-retry) and null is returned so the caller
* opens a fresh session with the correct amount/clientAction for the new platform.
*
* When the status query itself errors, the existing intent is reused unchanged:
* superseding blind could leave two live sessions and a double charge.
@@ -332,8 +333,15 @@ export class IntentsService {
const chargeChanged =
intent.amountMinor !== request.amountMinor ||
intent.currency !== request.currency;
// A web↔mobile switch needs a different clientAction shape (e.g. Telebirr:
// REDIRECT for web vs LAUNCH_APP for the native app), so reusing the stored
// session would hand the payer the wrong launch method and break the return.
// Detect the stored session's platform from its clientAction and retire on a switch.
const storedIsMobileLaunch = intent.clientAction?.type === "LAUNCH_APP";
const requestedMobile = (request.platform ?? "web") === "mobile";
const platformChanged = storedIsMobileLaunch !== requestedMobile;
if (!expired && !chargeChanged) {
if (!expired && !chargeChanged && !platformChanged) {
this.logger.log(
`intent ${intent.id} reused (live ${intent.provider} session, unpaid, not expired) for ` +
`${request.service}/${request.referenceType}/${request.referenceId}`,
@@ -346,7 +354,7 @@ export class IntentsService {
failureCode: expired ? "EXPIRED" : "SUPERSEDED",
failureMessage: expired
? "Provider session expired before the payer acted"
: "Payer re-initiated with a changed amount; previous session superseded",
: "Payer re-initiated with a changed amount or platform; previous session superseded",
});
this.logger.log(
`intent ${intent.id} retired (${expired ? "EXPIRED" : "SUPERSEDED"}) — fresh session will be opened`,