src/invoice-settlement-types.tsTypeScript
@@ -0,0 +1,51 @@
1+
export interface DueInvoice {2+
id: string;3+
accountId: string;4+
totalCents: number;5+
}6+
7+
export interface ChargeReceipt {8+
chargeId: string;9+
acceptedAt: Date;10+
}11+
12+
export interface PaymentProvider {13+
charge(request: {14+
accountId: string;15+
amountCents: number;16+
idempotencyKey: string;17+
}): Promise<ChargeReceipt>;18+
}19+
20+
export class PaymentProviderError extends Error {21+
constructor(22+
message: string,23+
readonly kind: "declined" | "temporarily-unavailable",24+
) {25+
super(message);26+
this.name = "PaymentProviderError";27+
}28+
}29+
30+
export interface SettlementTransaction {31+
loadCheckpoint(): Promise<string | null>;32+
listDueAfter(checkpoint: string | null, limit: number): Promise<DueInvoice[]>;33+
getPayableTotal(invoiceId: string): Promise<number>;34+
markPaid(invoiceId: string, receipt: ChargeReceipt): Promise<void>;35+
recordFailure(invoiceId: string, message: string, retryable: boolean): Promise<void>;36+
saveCheckpoint(invoiceId: string): Promise<void>;37+
}38+
39+
export interface SettlementDependencies {40+
ids: { next(): string };41+
payments: PaymentProvider;42+
repository: {43+
withBatchLock<T>(work: (transaction: SettlementTransaction) => Promise<T>): Promise<T>;44+
};45+
}46+
47+
export interface SettlementResult {48+
attempted: number;49+
paid: number;50+
failed: number;51+
}