Persist material efficiency snapshots
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
"""Immutable PostgreSQL history of feedback-aligned KPI points."""
|
||||
|
||||
from typing import Protocol
|
||||
|
||||
import psycopg
|
||||
|
||||
from production_analytics.calculations.config import finite_number
|
||||
from production_analytics.service.material_efficiency import MaterialEfficiencySnapshot
|
||||
from production_analytics.service.postgres_material import PostgresSettings
|
||||
|
||||
|
||||
class MaterialEfficiencyWriter(Protocol):
|
||||
def write(self, snapshot: MaterialEfficiencySnapshot) -> bool: ...
|
||||
|
||||
|
||||
class PostgresMaterialEfficiencyWriter:
|
||||
def __init__(self, settings: PostgresSettings) -> None:
|
||||
self.settings = settings
|
||||
|
||||
def write(self, snapshot: MaterialEfficiencySnapshot) -> bool:
|
||||
for name in ("erp_feedback_timestamp", "material_snapshot_timestamp"):
|
||||
if getattr(snapshot, name).utcoffset() is None:
|
||||
raise ValueError(f"{name} must be timezone-aware")
|
||||
for name in (
|
||||
"good_quantity_m2",
|
||||
"material_consumption_kg",
|
||||
"material_consumption_kg_per_m2",
|
||||
"material_consumption_g_per_m2",
|
||||
):
|
||||
finite_number(getattr(snapshot, name), name)
|
||||
if snapshot.nominal_width_m is not None:
|
||||
finite_number(snapshot.nominal_width_m, "nominal_width_m")
|
||||
# Context exit commits/rolls back and closes; later cycles reconnect after outages.
|
||||
with psycopg.connect(
|
||||
host=self.settings.host,
|
||||
port=self.settings.port,
|
||||
dbname=self.settings.dbname,
|
||||
user=self.settings.user,
|
||||
password=self.settings.password,
|
||||
connect_timeout=10,
|
||||
options="-c statement_timeout=10000",
|
||||
) as connection:
|
||||
row = connection.execute(
|
||||
"""INSERT INTO material_efficiency_snapshots (
|
||||
erp_feedback_timestamp, material_snapshot_timestamp, calculation_id,
|
||||
machine_id, workplace, erp_production_order, enlyze_production_order,
|
||||
article_number, article_description, nominal_width_m, good_quantity_m2,
|
||||
material_consumption_kg, material_consumption_kg_per_m2,
|
||||
material_consumption_g_per_m2
|
||||
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
ON CONFLICT (calculation_id, machine_id, enlyze_production_order,
|
||||
erp_feedback_timestamp) DO NOTHING
|
||||
RETURNING 1""",
|
||||
(
|
||||
snapshot.erp_feedback_timestamp,
|
||||
snapshot.material_snapshot_timestamp,
|
||||
snapshot.calculation_id,
|
||||
snapshot.machine_id,
|
||||
snapshot.workplace,
|
||||
snapshot.erp_production_order,
|
||||
snapshot.enlyze_production_order,
|
||||
snapshot.article_number,
|
||||
snapshot.article_description,
|
||||
snapshot.nominal_width_m,
|
||||
snapshot.good_quantity_m2,
|
||||
snapshot.material_consumption_kg,
|
||||
snapshot.material_consumption_kg_per_m2,
|
||||
snapshot.material_consumption_g_per_m2,
|
||||
),
|
||||
).fetchone()
|
||||
return row is not None
|
||||
Reference in New Issue
Block a user