src/refund-types.tsTypeScript
@@ -0,0 +1,80 @@
1+
export interface PaymentRecord {2+
id: string;3+
merchantId: string;4+
capturedAmountMinor: number;5+
currency: string;6+
}7+
8+
export interface RefundRecord {9+
id: string;10+
merchantId: string;11+
paymentId: string;12+
requestKey: string;13+
amountMinor: number;14+
currency: string;15+
status: "pending" | "succeeded" | "failed";16+
}17+
18+
export interface RefundRepository {19+
findPayment(paymentId: string, transaction?: object): Promise<PaymentRecord | null>;20+
findByRequestKey(21+
merchantId: string,22+
requestKey: string,23+
transaction?: object,24+
): Promise<RefundRecord | null>;25+
listForPayment(paymentId: string, transaction?: object): Promise<RefundRecord[]>;26+
create(refund: RefundRecord, transaction?: object): Promise<void>;27+
markSucceeded(28+
refundId: string,29+
providerRefundId: string,30+
transaction?: object,31+
): Promise<void>;32+
}33+
34+
export interface RefundCommandOutbox {35+
enqueue(36+
command: { refundId: string; paymentId: string; amountMinor: number; currency: string },37+
transaction?: object,38+
): Promise<void>;39+
}40+
41+
export interface PaymentProvider {42+
startRefund(input: {43+
paymentId: string;44+
amountMinor: number;45+
currency: string;46+
idempotencyKey: string;47+
}): Promise<48+
| { status: "accepted"; providerRefundId: string }49+
| { status: "rejected"; reason: string }50+
>;51+
}52+
53+
export interface RefundDependencies {54+
refunds: RefundRepository;55+
commands: RefundCommandOutbox;56+
provider: PaymentProvider;57+
ids: { next(): string };58+
database: {59+
withPaymentLock<T>(paymentId: string, work: (transaction: object) => Promise<T>): Promise<T>;60+
};61+
}62+
63+
export interface RefundWebhookEvent {64+
eventId: string;65+
type: "refund.succeeded";66+
refundId: string;67+
providerRefundId: string;68+
}69+
70+
export interface RefundWebhookVerifier {71+
verify(rawBody: string, signature: string): Promise<RefundWebhookEvent>;72+
}73+
74+
export interface WebhookEventStore {75+
claimOnce(eventId: string): Promise<boolean>;76+
claimAndApply(77+
eventId: string,78+
apply: (transaction: object) => Promise<void>,79+
): Promise<boolean>;80+
}