Initial commit: site monorepo with API, web, and infra.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
влад
2026-07-16 10:11:54 +03:00
co-authored by Cursor
commit 016910ffb7
447 changed files with 73972 additions and 0 deletions
@@ -0,0 +1,183 @@
from __future__ import annotations
import json
from datetime import UTC, datetime
from typing import Any
from sqlalchemy import DateTime, select
from app.core.database import session_scope
from app.modules.zootech.catalog_models import (
ZootechDailyComponentNormAdjustment,
ZootechDailyIngredientReplacement,
ZootechDailyIngredientSkip,
ZootechDailyTripSkip,
ZootechDailyUnloadingGroupSkip,
ZootechFeedDispenser,
ZootechFeedingLocation,
ZootechFeedingPeriod,
ZootechFeedingPoint,
ZootechFeedMixer,
ZootechPeriodRecipe,
ZootechTrip,
ZootechUnloadingGroup,
)
from app.modules.zootech.models import ZootechComponent, ZootechIngredient, ZootechRecipe
TABLE_MODEL_MAP = {
"component": ZootechComponent,
"recipe": ZootechRecipe,
"ingredient": ZootechIngredient,
"unloading_group": ZootechUnloadingGroup,
"feed_mixer": ZootechFeedMixer,
"feed_dispenser": ZootechFeedDispenser,
"feeding_location": ZootechFeedingLocation,
"feeding_period": ZootechFeedingPeriod,
"feeding_point": ZootechFeedingPoint,
"period_recipes": ZootechPeriodRecipe,
"daily_trip_skip": ZootechDailyTripSkip,
"daily_ingredient_skip": ZootechDailyIngredientSkip,
"daily_unloading_group_skip": ZootechDailyUnloadingGroupSkip,
"daily_ingredient_replacement": ZootechDailyIngredientReplacement,
"daily_component_norm_adjustment": ZootechDailyComponentNormAdjustment,
"trip": ZootechTrip,
}
def _coerce_for_model(model, key: str, value: Any) -> Any:
if value is None:
return value
column = model.__table__.columns.get(key)
if column is None:
return value
if isinstance(column.type, DateTime) and isinstance(value, str):
try:
return datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError:
return datetime.now(UTC)
return value
def _parse_period_recipe_id(record_id: str) -> tuple[str, str]:
if ":" in record_id:
period_id, recipe_id = record_id.split(":", 1)
return period_id, recipe_id
return record_id, record_id
def load_catalog_row(enterprise_id: str, table_name: str, record_id: str) -> dict[str, Any] | None:
model = TABLE_MODEL_MAP.get(table_name)
if not model:
return None
with session_scope() as db:
if model is ZootechPeriodRecipe:
period_id, recipe_id = _parse_period_recipe_id(record_id)
row = db.scalar(
select(model).where(
model.enterprise_id == enterprise_id,
model.period_id == period_id,
model.recipe_id == recipe_id,
)
)
else:
row = db.scalar(
select(model).where(model.enterprise_id == enterprise_id, model.id == record_id)
)
if not row:
return None
return _row_to_dict(row, table_name)
def apply_catalog_change(
enterprise_id: str,
table_name: str,
record_id: str,
action: str,
payload: dict[str, Any],
version: int,
content_hash: str,
) -> None:
model = TABLE_MODEL_MAP.get(table_name)
if not model:
return
with session_scope() as db:
if model is ZootechPeriodRecipe:
period_id, recipe_id = _parse_period_recipe_id(record_id)
row = db.scalar(
select(model).where(
model.enterprise_id == enterprise_id,
model.period_id == period_id,
model.recipe_id == recipe_id,
)
)
else:
row = db.scalar(
select(model).where(model.enterprise_id == enterprise_id, model.id == record_id)
)
if action == "delete":
if row:
row.is_deleted = True
row.version = version
row.content_hash = content_hash
row.updated_at = datetime.now(UTC)
return
data = dict(payload)
data["enterprise_id"] = enterprise_id
data["version"] = version
data["content_hash"] = content_hash
data["is_deleted"] = False
if model is ZootechPeriodRecipe:
data["period_id"] = data.get("period_id") or _parse_period_recipe_id(record_id)[0]
data["recipe_id"] = data.get("recipe_id") or _parse_period_recipe_id(record_id)[1]
else:
data["id"] = record_id
if row:
_apply_fields(row, data, model)
row.updated_at = datetime.now(UTC)
else:
allowed = {c.key for c in model.__table__.columns}
filtered = {
k: _coerce_for_model(model, k, v) for k, v in data.items() if k in allowed
}
extra = {k: v for k, v in data.items() if k not in allowed}
if extra and "payload_json" in allowed:
filtered["payload_json"] = json.dumps(extra, ensure_ascii=False)
db.add(model(**filtered))
def _apply_fields(row, data: dict[str, Any], model) -> None:
allowed = {c.key for c in model.__table__.columns}
extra: dict[str, Any] = {}
for key, value in data.items():
if key in allowed and key not in ("enterprise_id", "created_at"):
setattr(row, key, _coerce_for_model(model, key, value))
elif key not in ("enterprise_id", "created_at", "id"):
extra[key] = value
if model is ZootechRecipe and "ingredients" in data:
row.payload_json = json.dumps(data.get("ingredients"), ensure_ascii=False)
elif extra and "payload_json" in allowed:
row.payload_json = json.dumps(extra, ensure_ascii=False)
def _row_to_dict(row, table_name: str) -> dict[str, Any]:
result = {}
for col in row.__table__.columns:
val = getattr(row, col.key)
if isinstance(val, datetime):
val = val.isoformat()
result[col.key] = val
if isinstance(row, ZootechRecipe) and row.payload_json:
try:
parsed = json.loads(row.payload_json)
if isinstance(parsed, list):
result["ingredients"] = parsed
except json.JSONDecodeError:
pass
if table_name == "period_recipes":
result["id"] = f"{row.period_id}:{row.recipe_id}"
elif hasattr(row, "payload_json") and row.payload_json and table_name != "recipe":
try:
result.update(json.loads(row.payload_json))
except json.JSONDecodeError:
pass
return result