---
id: WF-ACC-BKS-004
title: Fill Missing Provider Currency Quotes
trigger: A caller requests provider rates for a unit and effective date.
product_area: accounting
module: books
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
inference: []
source_sha:
  services-accounting: f47cb263875bbc0c5640fba7dae6785ec32695f8
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-ACC-BKS-004
crosses: []
idempotency: >-
  Existing unit, currency and date rows are skipped. The provider pull has no
  idempotency key and can be repeated; successful inserts rely on the dated-rate
  uniqueness key.
concurrency: >-
  Concurrent fills may both fetch quotes, but conflicting dated inserts preserve
  the first row. The final write does not recheck the earlier provider-source
  setting, so a concurrent source switch can still receive provider data.
hops:
  - 'n': 1
    actor_or_service: Books service (first transaction)
    action: >-
      Read the unit and rate settings, choose requested provider currencies and
      skip dates already holding quotes.
    anchor: >-
      services-accounting:modules/books/services/exchange-rates/fill-exchange-rates.ts:fillExchangeRates
    seam: sync
    on_failure: >-
      Refuse missing units, invalid currency choices or an empty
      provider-sourced set before writing.
    left_inconsistent: No quote has been created.
    observer: the caller
    provenance: test
    source: >-
      services-accounting:modules/books/tests/integration/services/persistence/exchange-rates.integration.spec.js#skips
      a currency whose day already holds a rate, reports one the provider did
      not price, and stores a quote on the provider’s own earlier day
  - 'n': 2
    actor_or_service: Bound provider through Platform’s integration gateway
    action: >-
      Pull quotes once through Platform’s bound integration outside a database
      transaction.
    anchor: >-
      services-accounting:modules/books/services/exchange-rates/integrations-exchange-rate-provider.ts
    seam: sync
    on_failure: >-
      Report unavailable or declined provider results without storing quotes;
      preserve Platform’s error classification when applicable.
    left_inconsistent: 'Platform may retain an execution log, but Accounting writes no quote.'
    observer: The requesting caller and the provider execution log
    provenance: test
    source: >-
      services-accounting:modules/books/tests/integration/services/persistence/exchange-rates.integration.spec.js#refuses
      provider_unavailable and provider_declined, writing nothing
  - 'n': 3
    actor_or_service: Books service (second transaction)
    action: >-
      Insert eligible quotes using each provider date and retain quote,
      connection and execution references; ignore existing dated rows.
    anchor: >-
      services-accounting:modules/books/services/persistence/exchange-rates.ts:insertProviderRates
    seam: sync
    on_failure: >-
      Roll back the quote transaction if a reference removed meanwhile makes
      insertion invalid.
    left_inconsistent: >-
      The provider was called, but this failed insert transaction stores no
      quotes.
    observer: the caller
    provenance: observed
    source: >-
      services-accounting:modules/books/services/persistence/exchange-rates.ts:insertProviderRates
  - 'n': 4
    actor_or_service: Books service
    action: >-
      Return the inserted quotes, skipped currencies and currencies left
      unpriced.
    anchor: >-
      services-accounting:modules/books/services/exchange-rates/fill-exchange-rates.ts:FillExchangeRatesResult
    seam: sync
    on_failure: Return the result without a further persistence stage.
    left_inconsistent: Only the committed quote rows remain.
    observer: the console dialog
    provenance: test
    source: >-
      services-accounting:modules/books/tests/integration/services/persistence/exchange-rates.integration.spec.js#skips
      a currency whose day already holds a rate, reports one the provider did
      not price, and stores a quote on the provider’s own earlier day
branches:
  - condition: Receive an earlier provider date
    path: >-
      Keep the provider’s actual date; later resolution can choose it as the
      latest quote at or before the requested date.
  - condition: Correct an incorrect provider quote
    path: Remove the stored provider row and refill; ordinary editing is refused.
  - condition: Find every requested date already priced
    path: Return skipped currencies immediately without invoking the provider.
waits: []
evidence:
  - >-
    services-accounting at f47cb263:
    modules/books/services/exchange-rates/fill-exchange-rates.ts,
    integrations-exchange-rate-provider.ts;
    services/ports/exchange-rate-provider.ts;
    services/persistence/exchange-rates.ts
  - >-
    services-accounting at f47cb263:
    docs/architecture/accounting-2.0/02-decisions.md#P-4
  - >-
    react-console at baf6dae3:
    components/configuration/accounting/fill-exchange-rates-dialog.tsx
controls: [TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-CRY-001, TC-DAT-001, TC-DAT-002, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-002, TC-PI-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Fill Missing Provider Currency Quotes

## What It Does

Provider filling separates planning, the external read and quote persistence. It fetches only eligible currencies whose requested date is missing, then stores quotes with the date and origin the provider supplied. The response distinguishes written, skipped and unpriced currencies.

## The Flow

```mermaid
flowchart TD
  h0["Read the unit and rate settings, choose requested provider currencies and skip dates already holding quotes."]
  h1["Pull quotes once through Platform’s bound integration outside a database transaction."]
  h0 --> h1
  h2["Insert eligible quotes using each provider date and retain quote, connection and execution references; ignore existing dated rows."]
  h1 --> h2
  h3["Return the inserted quotes, skipped currencies and currencies left unpriced."]
  h2 --> h3
```

## When Something Fails

Provider failures leave Accounting unchanged. A persistence failure can discard a successful external answer without requiring compensation, because the pull moves no money. Retrying is allowed and uniqueness prevents overwriting existing dated quotes. A currency changed to manual sourcing during the pull can still receive a provider quote; no final source check is implemented. Existing stub evidence does not establish a successful live-provider execution.

## Open Design Questions

Nightly automatic filling is not implemented in the examined flow. Product and engineering need to decide whether a final source check is required.
