72 lines
3.1 KiB
Python
72 lines
3.1 KiB
Python
"""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
|