Skip to main content

FxRateLoad

Load the customer's own exchange rates (the ones it closes its books with) from an ERP. The reports convert invoice amounts with them; where the customer has no rate for a currency, the reports use Nuntiq's platform rates for that currency. The customer's rate wins, also when it is for another period (a monthly rate beats a platform day rate).

Use the get_fx_rates entrypoint. Its job token may read and write exchange rates and the delta state, nothing else.

Import​

from lib.objects.fx_rate import FxRateLoad

How a rate is expressed​

Against the tenant's base currency: 1 base = per_base units of the currency, for a period:

period_typeperiod_startrate_type
day (default)the dayalways close
weekthe Mondayaverage or close
monththe 1staverage or close

Day rates also build the week and month average and closing rates of their periods (source derived), unless you load a week or month rate yourself. Loading a rate for an existing currency, period and rate type replaces it.

A rate can also be given as a pair: 1 from_currency = rate to_currency on date, when the base currency is one of the two. Any other pair is refused. Most ERPs publish pairs against the company currency, so this is usually the easiest shape.

Methods​

MethodWhat it does
base_currency()The tenant's base currency, e.g. 'USD'
new()Queue a rate against the base (currency_code, period_type, period_start, rate_type, per_base)
new_pair(from, to, rate, date)Queue a day rate given as a pair
save_all()Send the queued rates, 5000 per request. Each request is all or nothing: one rate that is not valid fails that request (400 with the errors). Returns the number saved
get(page=1, page_size=None, **filters) / get_all(**filters)Read the tenant's rates, newest period first. Filters: currency, period_type, from, to (period starts). from is a Python keyword, so pass it as **{'from': '2026-09-01'}
delete_period(currency, period_start, period_type=None, rate_type=None)Delete one period's rates of a currency
delete_range(currency, date_from, date_to, period_type=None, rate_type=None)Delete every period start in a range, e.g. a month of day rates you restate. Week and month rates derived from deleted days are rebuilt from the days left
effective(currencies, date=None, target=None, rate_type='average')The rate the reports use per currency on a date, and its source: tenant, platform, mixed (yours for one currency, the platform's for the other), same or fallback_1 (no rate: converted at 1 and flagged). average is what spend reports use, close what open-invoice reports (aging, accrual) use

The tenant's rates have no external id: the key is currency, period type, period start and rate type. There is no full_load (nothing is removed because it is missing from a load); restate with delete_range() first.

Example​

from datetime import date
from lib.objects.fx_rate import FxRateLoad


def run(context):
load = FxRateLoad(context)
base = load.base_currency()

# 1 EUR = 1.0855 USD on 30 September (pair, base on one side)
load.new_pair('EUR', base, 1.0855, '2026-09-30')

# the September average for GBP, against the base
r = load.new()
r.currency_code = 'GBP'
r.period_type = 'month'
r.period_start = '2026-09-01'
r.rate_type = 'average'
r.per_base = 0.7461 # 1 USD = 0.7461 GBP

load.save_all()

for row in load.effective(['EUR', 'GBP'], date='2026-09-30'):
context.logger.info(f"1 {row['currency_code']} = {row['rate']} {base} ({row['source']})")

A full entrypoint with a delta cursor and a restate option is in connectors/get_fx_rates.py.

Local fixtures​

  • fixtures/fx_rate.json: the tenant's rates.
  • fixtures/fx_settings.json: one row with base_currency and fx_period_type (the period the reports use: day, week or month).
  • fixtures/platform_fx_rate.json: a few platform rates (per_usd), so effective() can show the platform and mixed sources locally.

Menu option r restores them from fixtures/_seed/.