fix: make invoice payment activation idempotent (#18)
Closes #2 ## Summary - make `markInvoicePaid` idempotent for already-paid invoices and reject invalid terminal transitions - add admin actor metadata and audit-log writes for `mark-paid`, including replayed no-op calls - add focused DB tests for first activation, replay safety, and invalid transition handling - document the current payment system, including invoice creation, manual activation, quota reset, and current limitations ## Testing - built `infra/docker/web.Dockerfile` - ran `pnpm --filter @nproxy/db test` inside the built container - verified `@nproxy/db build` and `@nproxy/web build` during the image build Co-authored-by: sirily <sirily@git.shararam.party> Reviewed-on: #18
This commit was merged in pull request #18.
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
} from "node:http";
|
||||
import { loadConfig } from "@nproxy/config";
|
||||
import {
|
||||
BillingError,
|
||||
createPrismaAccountStore,
|
||||
createPrismaAuthStore,
|
||||
createPrismaBillingStore,
|
||||
@@ -211,7 +212,13 @@ const server = createServer(async (request, response) => {
|
||||
}
|
||||
|
||||
const invoiceId = decodeURIComponent(invoiceMarkPaidMatch[1] ?? "");
|
||||
const invoice = await billingStore.markInvoicePaid({ invoiceId });
|
||||
const invoice = await billingStore.markInvoicePaid({
|
||||
invoiceId,
|
||||
actor: {
|
||||
type: "web_admin",
|
||||
ref: authenticatedSession.user.id,
|
||||
},
|
||||
});
|
||||
sendJson(response, 200, {
|
||||
invoice: serializeBillingInvoice(invoice),
|
||||
});
|
||||
@@ -672,6 +679,23 @@ function handleRequestError(
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof BillingError) {
|
||||
const statusCode =
|
||||
error.code === "invoice_not_found"
|
||||
? 404
|
||||
: error.code === "invoice_transition_not_allowed"
|
||||
? 409
|
||||
: 400;
|
||||
|
||||
sendJson(response, statusCode, {
|
||||
error: {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (error instanceof GenerationRequestError) {
|
||||
const statusCode =
|
||||
error.code === "missing_active_subscription"
|
||||
|
||||
Reference in New Issue
Block a user