Phase8: Auto bill credit card
All checks were successful
Build and Push / build (push) Successful in 1m44s
All checks were successful
Build and Push / build (push) Successful in 1m44s
This commit is contained in:
@@ -4,7 +4,6 @@ import {
|
||||
createTenantRequest,
|
||||
createTenantRequestPendingPayment,
|
||||
deletePendingPaymentRequest,
|
||||
getOrgBillingConfig,
|
||||
getTenantRequestById,
|
||||
listTenantRequestsByOrgId,
|
||||
listActiveTenantRequestsByOrgId,
|
||||
@@ -417,29 +416,6 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// Phase 9b (revised): a saved card on file IS the consent to
|
||||
// auto-bill. There is no customer-facing "disable auto-pay"
|
||||
// switch — ordering requires a card, full stop. The
|
||||
// auto_charge_enabled flag is now an admin-only pause (used
|
||||
// during disputes) and does NOT block a customer from ordering:
|
||||
// if admin has paused recurring charges, that's a separate
|
||||
// concern handled on the invoice side, not here. So the gate is
|
||||
// simply: do they have a card on file?
|
||||
const cfg = await getOrgBillingConfig(user.orgId);
|
||||
const hasSavedCard = !!cfg.stripeDefaultPaymentMethodId;
|
||||
if (!hasSavedCard) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error:
|
||||
"A payment card is required before ordering a new instance. " +
|
||||
"Please save a card on /settings/billing, then submit again.",
|
||||
code: "card_required",
|
||||
redirectTo: "/settings/billing",
|
||||
},
|
||||
{ status: 402 }
|
||||
);
|
||||
}
|
||||
|
||||
// Look up the setup fee. If it's 0 we skip the Checkout flow
|
||||
// entirely and create a normal pending request (same as the
|
||||
// pre-Phase-9b behaviour).
|
||||
@@ -524,35 +500,33 @@ export async function POST(request: Request) {
|
||||
tenantRequest.id
|
||||
);
|
||||
|
||||
// Build the billing snapshot from the org's address (already
|
||||
// fetched above for the wizard's billing-address resolution).
|
||||
// The snapshot is what the invoice + Stripe customer use.
|
||||
//
|
||||
// orgBilling MUST exist here: the auto-pay pre-check above
|
||||
// requires a saved Stripe PaymentMethod, which can only be
|
||||
// created via ensureStripeCustomerForOrg, which requires
|
||||
// org_billing. If it's missing the system is in an inconsistent
|
||||
// state we shouldn't paper over.
|
||||
if (!orgBilling) {
|
||||
// Re-fetch orgBilling here: the variable at the top of POST was
|
||||
// captured BEFORE the upsertOrgBilling call upstream (which fires
|
||||
// when the wizard collected the address on first onboarding). For
|
||||
// a brand-new user that initial fetch returned null; only by
|
||||
// re-fetching now do we get the row we just wrote. Existing
|
||||
// customers get the same orgBilling back either way.
|
||||
const billingForOrder = await getOrgBilling(user.orgId);
|
||||
if (!billingForOrder) {
|
||||
console.error(
|
||||
`Paid-fee onboarding path reached without org_billing for org ${user.orgId} — auto-pay pre-check should have prevented this.`
|
||||
`Paid-fee onboarding path: no org_billing for org ${user.orgId} even after upsert — wizard did not collect address?`
|
||||
);
|
||||
await deletePendingPaymentRequest(tenantRequest.id).catch(() => undefined);
|
||||
return NextResponse.json(
|
||||
{ error: "Billing record missing. Please re-save your billing details on /settings/billing." },
|
||||
{ error: "Billing record missing. Please re-save your billing details." },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
const billingSnapshot: InvoiceBillingSnapshot = {
|
||||
companyName: orgBilling.companyName,
|
||||
contactName: orgBilling.contactName ?? null,
|
||||
streetAddress: orgBilling.streetAddress,
|
||||
postalCode: orgBilling.postalCode,
|
||||
city: orgBilling.city,
|
||||
country: orgBilling.country,
|
||||
vatNumber: orgBilling.vatNumber ?? null,
|
||||
billingEmail: orgBilling.billingEmail,
|
||||
notes: orgBilling.notes ?? null,
|
||||
companyName: billingForOrder.companyName,
|
||||
contactName: billingForOrder.contactName ?? null,
|
||||
streetAddress: billingForOrder.streetAddress,
|
||||
postalCode: billingForOrder.postalCode,
|
||||
city: billingForOrder.city,
|
||||
country: billingForOrder.country,
|
||||
vatNumber: billingForOrder.vatNumber ?? null,
|
||||
billingEmail: billingForOrder.billingEmail,
|
||||
notes: billingForOrder.notes ?? null,
|
||||
};
|
||||
|
||||
// Locale for the invoice + PDF — pick from the org's country
|
||||
|
||||
Reference in New Issue
Block a user