blocker phase 5

This commit is contained in:
hamid
2026-08-02 21:33:10 +03:30
parent 08949a24de
commit 340012b2f8
3 changed files with 44 additions and 28 deletions
+6 -12
View File
@@ -2,18 +2,12 @@
* When true, the BNPL domain is served by the in-memory mock (`apis/mockApi.ts`) behind the `BnplApi`
* seam.
*
* **Mock is primary this phase.** b12 ships the eligibility/initiate/webhook/settle endpoints server-side,
* but the D1D5 checkout cannot run real end-to-end from the client yet:
* - the accepted request being financed comes from the **mock-primary** `bookingRequests` store (f7), so a
* real `initiate` would reference an id that exists only in memory (same reason f9 payment is mock-primary);
* - the contract serves **no provider/plan options** (D1/D2), **no repayment schedule** (D4 — the contract
* explicitly does not model the customer's repayment schedule), and **no provider-reported installment
* status** for the Wallet (D5) → REQ-022/023/024;
* - nothing fires the provider webhook in dev, so a real order would never settle.
* The mock closes the loop: the settle (down-payment cleared) converts the f7 request, inserts a **confirmed**
* booking into the f8 store (the SAME bridge f9 uses — a settled BNPL order is a card payment net-of-fee),
* and seeds a Wallet installment plan — so C6 → D1 → … → D4 → confirmation → D5 demos end-to-end. Flip to
* `false` once the upstream domains are real and REQ-022/023/024 land — no hook/component change.
* **Mock is still primary** (blocker-phase 05 landed Bug A — the seeded BNPL gateway — but not Bug B):
* the D1 wizard hard-gates on `getBnplOptions` (`GET checkout_bnpl/options/{id}`), and `getBnplSchedule` /
* `getWalletInstallments` have no server counterpart either — `CheckoutBnplController` only ever grew
* `eligibility` / `initiate` / `GET {id}` / `by_request/{id}` (REQ-022/023/024 never landed). Flipping this
* flag today trades the old "mock store ages out" failure for an immediate `isError` on D1. Flip once those
* three endpoints exist server-side — no hook/component change needed at that point.
*/
export const USE_BNPL_MOCK = true;
+7 -2
View File
@@ -21,8 +21,13 @@ Effort is a rough size, not a schedule: **S** = small/contained, **M** = a real
- **The 30-minute payment countdown can lie.** Booking deadlines are stored without a timezone, so the timer
a customer sees can silently show hours more time than they actually have, and expire while they still
think they're fine. *(Effort: S)*
- **Installment (buy-now-pay-later) payments don't work at all.** No installment plan is ever actually set up
behind the scenes, so every attempt fails immediately. *(Effort: SM, two related issues)*
- **Installment (buy-now-pay-later) payments don't work at all.** The behind-the-scenes setup that lets an
installment plan get created at all is now fixed — but the on-screen wizard still can't be turned on to use
it: three of its screens (choosing a plan, seeing the repayment schedule, and the "my installments" wallet
view) call server endpoints that were never actually built, so switching off the fake demo data today would
make the first screen show an error immediately instead of the outdated-mock failure it shows now. Those
three endpoints need to be built before this can be turned on for real. *(Effort: SM, one part fixed, one
part bigger than first scoped)*
- **Refunds are demo-only today.** The refund screens read fake, disconnected sample data; turning that off
today would show a refund of the wrong amount (off by a factor of 100) for any real cancellation.
*(Effort: M)*
@@ -8,6 +8,7 @@ using Baya.Application.Contracts.Payments;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Contracts.Search;
using Baya.Application.Contracts.SupportAlerts;
using Baya.Domain.Entities.Bnpl;
using Baya.Domain.Entities.Payments;
using Baya.Infrastructure.Persistence.Interceptors;
using Baya.Infrastructure.Persistence.Repositories.Common;
@@ -128,27 +129,43 @@ public static class ServiceCollectionExtensions
/// <summary>
/// Idempotently seeds one active <c>standard</c> payment gateway so the b10 card rail has a selectable
/// provider out of the box. <c>config_json</c> is encrypted at rest by the EF converter on save (so it
/// must go through the DbContext, not <c>HasData</c>). Real merchant credentials come from appsettings /
/// environment per deployment — this sandbox row is non-secret and only enables the local/dev flow.
/// provider out of the box, plus one active <c>bnpl</c> gateway (<c>balinyaar</c>, the in-house
/// net-of-fee provider per money.md §6 — needs no external credentials) so b12's eligibility/initiate
/// handlers have a gateway to select instead of short-circuiting. <c>config_json</c> is encrypted at rest
/// by the EF converter on save (so it must go through the DbContext, not <c>HasData</c>). Real merchant
/// credentials come from appsettings / environment per deployment — these sandbox rows are non-secret and
/// only enable the local/dev flow.
/// </summary>
public static async Task SeedPaymentGatewaysAsync(this WebApplication app)
{
await using var scope = app.Services.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
if (await context.Set<PaymentGateway>().AnyAsync(g => g.Type == PaymentGatewayType.Standard))
return;
context.Set<PaymentGateway>().Add(new PaymentGateway
if (!await context.Set<PaymentGateway>().AnyAsync(g => g.Type == PaymentGatewayType.Standard))
{
ProviderCode = "zarinpal",
Type = PaymentGatewayType.Standard,
DisplayName = "ZarinPal (sandbox)",
ConfigJson = "{\"merchantId\":\"00000000-0000-0000-0000-000000000000\",\"baseUrl\":\"https://sandbox.zarinpal.com\",\"sandbox\":true}",
IsActive = true,
Priority = 0
});
context.Set<PaymentGateway>().Add(new PaymentGateway
{
ProviderCode = "zarinpal",
Type = PaymentGatewayType.Standard,
DisplayName = "ZarinPal (sandbox)",
ConfigJson = "{\"merchantId\":\"00000000-0000-0000-0000-000000000000\",\"baseUrl\":\"https://sandbox.zarinpal.com\",\"sandbox\":true}",
IsActive = true,
Priority = 0
});
}
if (!await context.Set<PaymentGateway>().AnyAsync(g => g.Type == PaymentGatewayType.Bnpl))
{
context.Set<PaymentGateway>().Add(new PaymentGateway
{
ProviderCode = BnplProviderCodes.Balinyaar,
Type = PaymentGatewayType.Bnpl,
DisplayName = "Balinyaar BNPL",
ConfigJson = "{\"sandbox\":true}",
IsActive = true,
Priority = 0
});
}
await context.SaveChangesAsync();
}