From a5420e6a4210c4e6e00d4dae4773f73d7cdf5141 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Thu, 27 Aug 2026 09:50:33 -0300 Subject: [PATCH] feat(checkout): refresh catalog availability on checkout failure --- .../core/services/checkout.service.spec.ts | 21 +++++++++++- src/app/core/services/checkout.service.ts | 32 ++++++++++++------- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/app/core/services/checkout.service.spec.ts b/src/app/core/services/checkout.service.spec.ts index 57cdc79..ee3adb7 100644 --- a/src/app/core/services/checkout.service.spec.ts +++ b/src/app/core/services/checkout.service.spec.ts @@ -1,9 +1,10 @@ import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { environment } from '../../../environments/environment'; +import { CatalogAvailabilityService } from './catalog/catalog-availability.service'; import { CheckoutService } from './checkout.service'; describe('CheckoutService', () => { @@ -39,6 +40,24 @@ describe('CheckoutService', () => { await expect(purchasePromise).resolves.toMatchObject({ id: 55 }); }); + it('refreshes catalog availability when starting checkout fails', async () => { + const catalogAvailabilityService = TestBed.inject(CatalogAvailabilityService); + const notifyAvailabilityChanged = vi.spyOn( + catalogAvailabilityService, + 'notifyAvailabilityChanged', + ); + const purchasePromise = service.startCheckout('desfile', { cart_id: 12 }); + const request = httpMock.expectOne(`${environment.url}tenants/desfile/compras/start-checkout`); + + request.flush( + { message: 'No hay stock disponible.' }, + { status: 422, statusText: 'Unprocessable Entity' }, + ); + + await expect(purchasePromise).rejects.toBeTruthy(); + expect(notifyAvailabilityChanged).toHaveBeenCalledOnce(); + }); + it('preserves checkout timing fields when completing a purchase', async () => { const purchasePromise = service.completePurchase('desfile', 55); const request = httpMock.expectOne(`${environment.url}tenants/desfile/compras/55/complete`); diff --git a/src/app/core/services/checkout.service.ts b/src/app/core/services/checkout.service.ts index 4d1d2bb..70886d6 100644 --- a/src/app/core/services/checkout.service.ts +++ b/src/app/core/services/checkout.service.ts @@ -1,10 +1,11 @@ -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { firstValueFrom } from 'rxjs'; import { environment } from '../../../environments/environment'; import { ApiPaginatedResponse } from './api-paginated-response.interface'; import { ApiPaginationQueryParams } from './api-pagination-query-params.interface'; import { BaseApiService } from './base-api.service'; +import { CatalogAvailabilityService } from './catalog/catalog-availability.service'; export interface UpdatePurchaseCustomerPayload { dni: string; @@ -126,24 +127,31 @@ export interface PurchaseDetailResponse extends PurchaseStatusResponse { providedIn: 'root', }) export class CheckoutService extends BaseApiService { + private readonly catalogAvailabilityService = inject(CatalogAvailabilityService); + async startCheckout( tenantCode: string, payload: StartCheckoutPayload, ): Promise { - const response = await firstValueFrom( - this.http.post<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>( - `${environment.url}tenants/${tenantCode}/compras/start-checkout`, - payload, - ), - ); + try { + const response = await firstValueFrom( + this.http.post<{ data?: PurchaseDetailResponse } | PurchaseDetailResponse>( + `${environment.url}tenants/${tenantCode}/compras/start-checkout`, + payload, + ), + ); - const purchase = this.extractResponseData(response); + const purchase = this.extractResponseData(response); - if (!purchase?.id) { - throw new Error('Error al crear la compra.'); + if (!purchase?.id) { + throw new Error('Error al crear la compra.'); + } + + return purchase; + } catch (error) { + this.catalogAvailabilityService.notifyAvailabilityChanged(); + throw error; } - - return purchase; } async generatePaymentIntent(