From c104f313ce6a29ee3dc45f7bf27e4f6394962833 Mon Sep 17 00:00:00 2001 From: sdarbinyan Date: Tue, 18 Aug 2026 13:28:56 +0400 Subject: [PATCH] feat: real FX quote gateway, swapped in behind useMockData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FxQuoteApiGateway calls GET /api/v2/pricing/fx-quote per PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §3.1. Deliberately thin - no caching or retry here, since the caller decides what an expired quote means (re-fetch vs block checkout) and baking that into the gateway would hide the decision. Token now resolves to the real gateway whenever useMockData is false, matching the existing pattern in runtime-provider-strategy.service.ts. Additive only: nothing that reads prices today was rewired to this gateway yet. That rewiring touches checkout's charge-amount computation and is deferred - see the session summary for why. Co-Authored-By: Claude Opus 5 --- .../pricing/services/fx-quote-api.gateway.ts | 23 +++++++++++++++++++ .../services/fx-quote-gateway.token.ts | 6 +++-- 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/app/core/pricing/services/fx-quote-api.gateway.ts diff --git a/src/app/core/pricing/services/fx-quote-api.gateway.ts b/src/app/core/pricing/services/fx-quote-api.gateway.ts new file mode 100644 index 0000000..1c1fa28 --- /dev/null +++ b/src/app/core/pricing/services/fx-quote-api.gateway.ts @@ -0,0 +1,23 @@ +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { FxQuote } from '../models/fx-quote.model'; +import { FxQuoteGateway } from './fx-quote-gateway.interface'; + +/** + * Real FX gateway. Contract: docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §3.1. + * + * Deliberately thin: no caching, no retry logic here. TTL/expiry handling is + * the caller's job (isFxQuoteExpired), because the caller decides what to do + * with an expired quote (re-fetch vs block checkout) - baking a policy into + * the gateway would hide that decision. + */ +@Injectable({ providedIn: 'root' }) +export class FxQuoteApiGateway implements FxQuoteGateway { + private readonly http = inject(HttpClient); + + getQuote(base: string, quote: string): Observable { + const params = new HttpParams().set('base', base).set('quote', quote); + return this.http.get('/api/v2/pricing/fx-quote', { params }); + } +} diff --git a/src/app/core/pricing/services/fx-quote-gateway.token.ts b/src/app/core/pricing/services/fx-quote-gateway.token.ts index 0fc131b..6336fc9 100644 --- a/src/app/core/pricing/services/fx-quote-gateway.token.ts +++ b/src/app/core/pricing/services/fx-quote-gateway.token.ts @@ -1,9 +1,11 @@ import { InjectionToken, inject } from '@angular/core'; +import { environment } from '../../../../environments/environment'; import { FxQuoteGateway } from './fx-quote-gateway.interface'; import { FxQuoteLocalGateway } from './fx-quote-local.gateway'; +import { FxQuoteApiGateway } from './fx-quote-api.gateway'; -/** Swap point for the real FX backend from docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §3.1. */ +/** Swap point for docs/backend/PHASE-1-MONEY-FX-PAYMENTS-CONTRACT.md §3.1. */ export const FX_QUOTE_GATEWAY = new InjectionToken('FX_QUOTE_GATEWAY', { providedIn: 'root', - factory: () => inject(FxQuoteLocalGateway), + factory: () => (environment.useMockData ? inject(FxQuoteLocalGateway) : inject(FxQuoteApiGateway)), });