feat(checkout): enhance payment submission with error handling and polling logic
This commit is contained in:
@@ -23,6 +23,7 @@ describe('CheckoutPageComponent payment validation', () => {
|
||||
prepareItemEditing: ReturnType<typeof vi.fn>;
|
||||
cancelPurchase: ReturnType<typeof vi.fn>;
|
||||
generatePaymentIntent: ReturnType<typeof vi.fn>;
|
||||
submitPurchaseForReview: ReturnType<typeof vi.fn>;
|
||||
getPurchase: ReturnType<typeof vi.fn>;
|
||||
withCustomLoading: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
@@ -69,6 +70,7 @@ describe('CheckoutPageComponent payment validation', () => {
|
||||
generatePaymentIntent: vi.fn().mockResolvedValue({
|
||||
qr_data: { qr_code: 'qr-value' },
|
||||
}),
|
||||
submitPurchaseForReview: vi.fn().mockResolvedValue({ status: 'pending_payment' }),
|
||||
getPurchase: vi.fn().mockResolvedValue({ status: 'pending_payment' }),
|
||||
withCustomLoading: vi.fn(),
|
||||
};
|
||||
@@ -218,8 +220,9 @@ describe('CheckoutPageComponent payment validation', () => {
|
||||
const { component } = createComponent();
|
||||
component.selectedPaymentMethod.set('transfer');
|
||||
|
||||
component.onComplete();
|
||||
await component.onComplete();
|
||||
expect(component.transferValidationStatus()).toBe('checking');
|
||||
expect(checkoutServiceStub.submitPurchaseForReview).toHaveBeenCalledWith('tenant-test', 25);
|
||||
expect(checkoutServiceStub.getPurchase).not.toHaveBeenCalled();
|
||||
|
||||
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
||||
@@ -241,7 +244,7 @@ describe('CheckoutPageComponent payment validation', () => {
|
||||
const { component } = createComponent();
|
||||
component.selectedPaymentMethod.set('transfer');
|
||||
|
||||
component.onComplete();
|
||||
await component.onComplete();
|
||||
await vi.advanceTimersByTimeAsync(3_000);
|
||||
|
||||
expect(checkoutServiceStub.getPurchase).toHaveBeenCalledWith('tenant-test', 25);
|
||||
@@ -255,7 +258,7 @@ describe('CheckoutPageComponent payment validation', () => {
|
||||
const { component } = createComponent();
|
||||
component.selectedPaymentMethod.set('transfer');
|
||||
|
||||
component.onComplete();
|
||||
await component.onComplete();
|
||||
await vi.advanceTimersByTimeAsync(12_000);
|
||||
|
||||
expect(checkoutServiceStub.getPurchase).toHaveBeenCalledTimes(4);
|
||||
@@ -264,6 +267,20 @@ describe('CheckoutPageComponent payment validation', () => {
|
||||
expect(routerStub.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not poll when submitting a transfer for review fails', async () => {
|
||||
vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
checkoutServiceStub.submitPurchaseForReview.mockRejectedValue(new Error('network error'));
|
||||
const { component } = createComponent();
|
||||
component.selectedPaymentMethod.set('transfer');
|
||||
|
||||
await component.onComplete();
|
||||
await vi.advanceTimersByTimeAsync(12_000);
|
||||
|
||||
expect(checkoutServiceStub.submitPurchaseForReview).toHaveBeenCalledWith('tenant-test', 25);
|
||||
expect(checkoutServiceStub.getPurchase).not.toHaveBeenCalled();
|
||||
expect(component.transferValidationStatus()).toBe('error');
|
||||
});
|
||||
|
||||
it('cancels transfer polling when the payment method changes or the component is destroyed', async () => {
|
||||
const first = createComponent();
|
||||
first.component.selectedPaymentMethod.set('transfer');
|
||||
|
||||
@@ -514,7 +514,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
protected onComplete(): void {
|
||||
protected async onComplete(): Promise<void> {
|
||||
const purchaseId = this.createdPurchaseId();
|
||||
const tenant = this.tenantService.tenant();
|
||||
|
||||
@@ -533,7 +533,29 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
|
||||
this.transferPollingAttempts = 0;
|
||||
|
||||
const runId = this.transferPollingRunId;
|
||||
this.scheduleTransferPoll(runId);
|
||||
|
||||
try {
|
||||
const purchase = await this.checkoutService
|
||||
.withCustomLoading()
|
||||
.submitPurchaseForReview(tenant.codigo, purchaseId);
|
||||
|
||||
if (runId !== this.transferPollingRunId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (purchase.status === 'paid') {
|
||||
this.navigateToPurchaseStatus(purchaseId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.scheduleTransferPoll(runId);
|
||||
} catch (error) {
|
||||
console.error('Failed to submit transfer payment for review:', error);
|
||||
|
||||
if (runId === this.transferPollingRunId) {
|
||||
this.transferValidationStatus.set('error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private scheduleTransferPoll(runId: number): void {
|
||||
|
||||
Reference in New Issue
Block a user