- Completed export workflow implementation (query builders, CSV/XLSX serializers, streaming API endpoints, UI modals, automated tests). - Added export modal UI and client script to trigger downloads directly from dashboard. - Documented import/export field mapping and usage guidelines in FR-008. - Updated installation guide with export environment variables, dependencies, and CLI/CI usage instructions.
7.9 KiB
7.9 KiB
Pricing Settings Data Model
Objective
Persist pricing configuration values that currently live in environment variables so projects can own default payable percentages, currency, and penalty factors without redeploying the application.
Core Entity: pricing_settings
Holds the defaults that are injected into PricingMetadata when evaluating scenarios.
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
Integer | No | Identity | Primary key |
name |
String(128) | No | — | Human readable label displayed in the UI |
slug |
String(64) | No | — | Unique code used for programmatic lookup (e.g. default, contract-a) |
description |
Text | Yes | NULL |
Optional descriptive text |
default_currency |
String(3) | Yes | NULL |
Normalised ISO-4217 code; fallback when scenario currency is absent |
default_payable_pct |
Numeric(5,2) | No | 100.00 |
Default payable percentage applied when not supplied with an input |
moisture_threshold_pct |
Numeric(5,2) | No | 8.00 |
Percentage moisture threshold before penalties apply |
moisture_penalty_per_pct |
Numeric(14,4) | No | 0.0000 |
Currency amount deducted per percentage point above the moisture threshold |
metadata |
JSON | Yes | NULL |
Future extension bucket (e.g. FX assumptions) |
created_at |
DateTime(timezone=True) | No | now() |
Creation timestamp |
updated_at |
DateTime(timezone=True) | No | now() |
Auto updated timestamp |
Child Entity: pricing_metal_settings
Stores overrides that apply to specific commodities (payable percentage or alternate thresholds).
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
Integer | No | Identity | Primary key |
pricing_settings_id |
Integer (FK) | No | — | References pricing_settings.id with cascade delete |
metal_code |
String(32) | No | — | Normalised commodity identifier (e.g. copper, gold) |
payable_pct |
Numeric(5,2) | Yes | NULL |
Contractual payable percentage for this metal; overrides parent value when set |
moisture_threshold_pct |
Numeric(5,2) | Yes | NULL |
Optional metal specific moisture threshold |
moisture_penalty_per_pct |
Numeric(14,4) | Yes | NULL |
Optional metal specific penalty factor |
data |
JSON | Yes | NULL |
Additional metal settings (credits, payable deductions) |
created_at |
DateTime(timezone=True) | No | now() |
Creation timestamp |
updated_at |
DateTime(timezone=True) | No | now() |
Auto updated timestamp |
metal_code should have a unique constraint together with pricing_settings_id to prevent duplication.
Child Entity: pricing_impurity_settings
Represents impurity penalty factors and thresholds that are injected into PricingMetadata.impurity_thresholds and PricingMetadata.impurity_penalty_per_ppm.
| Column | Type | Nullable | Default | Notes |
|---|---|---|---|---|
id |
Integer | No | Identity | Primary key |
pricing_settings_id |
Integer (FK) | No | — | References pricing_settings.id with cascade delete |
impurity_code |
String(32) | No | — | Identifier such as As, Pb, Zn |
threshold_ppm |
Numeric(14,4) | No | 0.0000 |
Contractual impurity allowance |
penalty_per_ppm |
Numeric(14,4) | No | 0.0000 |
Currency penalty applied per ppm above the threshold |
notes |
Text | Yes | NULL |
Optional narrative about the contract rule |
created_at |
DateTime(timezone=True) | No | now() |
Creation timestamp |
updated_at |
DateTime(timezone=True) | No | now() |
Auto updated timestamp |
Add a unique constraint on (pricing_settings_id, impurity_code).
Mapping to PricingMetadata
default_currency,default_payable_pct,moisture_threshold_pct, andmoisture_penalty_per_pctmap directly to the dataclass fields.pricing_metal_settingsrows provide per-metal overrides. During load, prefer metal-specific values when present, falling back to the parent record. These values hydrate a composedPricingMetadataor supplementary structure passed to the evaluator.pricing_impurity_settingsrows populatePricingMetadata.impurity_thresholdsandPricingMetadata.impurity_penalty_per_ppmdictionaries.
Usage Notes
- Global defaults can be represented by a
pricing_settingsrow referenced by new projects. Future migrations will addprojects.pricing_settings_idto point at the desired configuration. - The
metadataJSON column gives room to store additional contract attributes (e.g. minimum lot penalties, premium formulas) without immediate schema churn. - Numeric precision follows existing financial models (two decimal places for percentages, four for monetary/ppm penalties) to align with current tests.
Bootstrap & Runtime Loading
services.bootstrap.bootstrap_pricing_settingsensures a baseline record (slugdefault) exists during FastAPI startup and when runningscripts/initial_data.py. Initial values come fromconfig.settings.Settings.pricing_metadata(), allowing operators to shape the first record via environment variables.- When projects lack an explicit configuration, the bootstrap associates them with the default record through
UnitOfWork.set_project_pricing_settings, guaranteeing every project has pricing metadata. - At request time,
dependencies.get_pricing_metadataloads the persisted defaults usingUnitOfWork.get_pricing_metadata(include_children=True). If the slug is missing, it reseeds the default record from the bootstrap metadata before returning aPricingMetadatainstance. - Callers therefore observe a consistent fallback chain: project-specific settings → default database record → freshly seeded defaults derived from environment values.