Phase 4 Stage 10 Maestro: 09_chat_tab.yaml + seed-pending-payment endpoint
Closes the Stage 10 acceptance criterion §10.11 #13 (Maestro coverage). - New dev-only `POST /internal/_test/seed-pending-payment` — inserts a payment_sessions row in `pending` status with expires_at 20m out, so the Pembayaran sub-tab has a deterministic row to render. Body accepts { phone, isExtension?, amount?, durationMinutes?, mode? }. Gated on NODE_ENV != 'production' like the other test routes. - New Maestro helper script `seed_pending_payment.js` mirrors the existing seed_history_session pattern. - New flow `09_chat_tab.yaml`: cold-start onboarding → home (returning view) → seed completed session + seed pending payment → tap "💬 chat" bottom-nav → lands on /chat/aktif via redirect → assert "aktif" / "pembayaran" / "selesai" pills + empty-state copy → tap pembayaran → assert "menunggu pembayaran sesi" + "bayar Rp..." → tap selesai → assert "X menit" duration row → tap row → assert "Transkrip Chat" appbar → back → still on /chat/selesai. Maestro parsed the YAML cleanly and started executing against the device; full run requires backend + online mitra in dev DB (same pre-reqs as flows 03/05/06/08). - TECH_DEBT entry: Stage 10 retired the standalone bestie-history list screen, which means (a) the "curhat lagi" targeted-payment entry point has no UI affordance anywhere in the app — its plumbing in payment_notifier / payment_screen is now orphaned, and (b) the Stage 8 flow `08_returning_targeted.yaml` will fail at `assertVisible: "Riwayat Chat"` because it expects the deleted screen. Three fix paths listed in the entry for product to pick. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -245,4 +245,45 @@ export const internalTestRoutes = async (fastify) => {
|
||||
`
|
||||
return { ok: true, session_id: session.id, mitra_id: mitra.id, mitra_name: mitra.display_name }
|
||||
})
|
||||
|
||||
// Seed a payment_sessions row in `pending` status for the customer linked
|
||||
// to `phone`, with expires_at safely in the future. Used by Maestro Stage
|
||||
// 10 flow (09_chat_tab.yaml) to populate the Pembayaran sub-tab without
|
||||
// walking the multi-screen S6 paywall → method → duration → method flow.
|
||||
//
|
||||
// Body: { phone, isExtension?, amount?, durationMinutes?, mode? }
|
||||
// - isExtension: defaults false (initial-session payment)
|
||||
// - amount: defaults 5000 IDR
|
||||
// - durationMinutes: defaults 15
|
||||
// - mode: 'chat' (default) | 'call'
|
||||
fastify.post('/seed-pending-payment', async (request, reply) => {
|
||||
const phone = request.body?.phone
|
||||
if (!phone) {
|
||||
return reply.code(400).send({ error: 'phone required in body' })
|
||||
}
|
||||
const isExtension = request.body?.isExtension === true
|
||||
const amount = Number.isFinite(request.body?.amount) ? request.body.amount : 5000
|
||||
const durationMinutes = Number.isFinite(request.body?.durationMinutes)
|
||||
? request.body.durationMinutes
|
||||
: 15
|
||||
const mode = request.body?.mode === 'call' ? 'call' : 'chat'
|
||||
|
||||
const [customer] = await sql`
|
||||
SELECT id FROM customers WHERE phone = ${phone} LIMIT 1
|
||||
`
|
||||
if (!customer) {
|
||||
return reply.code(404).send({ error: 'no_customer_for_phone', phone })
|
||||
}
|
||||
const [row] = await sql`
|
||||
INSERT INTO payment_sessions (
|
||||
customer_id, amount, duration_minutes, is_first_session_discount,
|
||||
is_extension, status, mode, expires_at
|
||||
) VALUES (
|
||||
${customer.id}, ${amount}, ${durationMinutes}, false,
|
||||
${isExtension}, 'pending', ${mode}, NOW() + INTERVAL '20 minutes'
|
||||
)
|
||||
RETURNING id, customer_id, amount, is_extension, status, expires_at
|
||||
`
|
||||
return { ok: true, payment_id: row.id, ...row }
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user