Files
calminer-docs/specifications/pricing_settings_data_model.md
zwitschi 29f16139a3 feat: documentation update
- 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.
2025-11-11 18:34:02 +01:00

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, and moisture_penalty_per_pct map directly to the dataclass fields.
  • pricing_metal_settings rows provide per-metal overrides. During load, prefer metal-specific values when present, falling back to the parent record. These values hydrate a composed PricingMetadata or supplementary structure passed to the evaluator.
  • pricing_impurity_settings rows populate PricingMetadata.impurity_thresholds and PricingMetadata.impurity_penalty_per_ppm dictionaries.

Usage Notes

  • Global defaults can be represented by a pricing_settings row referenced by new projects. Future migrations will add projects.pricing_settings_id to point at the desired configuration.
  • The metadata JSON 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_settings ensures a baseline record (slug default) exists during FastAPI startup and when running scripts/initial_data.py. Initial values come from config.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_metadata loads the persisted defaults using UnitOfWork.get_pricing_metadata(include_children=True). If the slug is missing, it reseeds the default record from the bootstrap metadata before returning a PricingMetadata instance.
  • Callers therefore observe a consistent fallback chain: project-specific settings → default database record → freshly seeded defaults derived from environment values.