@@ -0,0 +1,84 @@
|
||||
"""Удаление legacy/fp_* профилей стада (одноразовая ops-команда)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from app import db
|
||||
from app.lab.models import LabAnimalProfile, LabProfileNorm, LabRecipeRation
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
_LEGACY_KEY = re.compile(r"^(dairy|beef)-\d+$", re.IGNORECASE)
|
||||
_FP_KEY = re.compile(r"^fp_", re.IGNORECASE)
|
||||
|
||||
|
||||
@dataclass
|
||||
class CleanupReport:
|
||||
dry_run: bool = True
|
||||
profiles_to_delete: list[str] = field(default_factory=list)
|
||||
recipe_ids_cleared: list[str] = field(default_factory=list)
|
||||
norms_deleted: int = 0
|
||||
profiles_deleted: int = 0
|
||||
errors: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
def _should_delete(profile_key: str | None) -> bool:
|
||||
key = (profile_key or "").strip()
|
||||
if not key:
|
||||
return False
|
||||
if key.startswith("lab_math_"):
|
||||
return False
|
||||
if _LEGACY_KEY.match(key):
|
||||
return True
|
||||
if _FP_KEY.match(key):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def cleanup_legacy_profiles(*, dry_run: bool = True, user_id: str = "system") -> CleanupReport:
|
||||
report = CleanupReport(dry_run=dry_run)
|
||||
profiles = LabAnimalProfile.query.filter_by(is_deleted=False).all()
|
||||
to_delete = [p for p in profiles if _should_delete(p.profile_key)]
|
||||
|
||||
for profile in to_delete:
|
||||
report.profiles_to_delete.append(profile.profile_key or profile.id)
|
||||
|
||||
norms_count = LabProfileNorm.query.filter_by(profile_id=profile.id).count()
|
||||
report.norms_deleted += norms_count
|
||||
|
||||
rations = LabRecipeRation.query.filter_by(animal_profile_id=profile.id, is_deleted=False).all()
|
||||
for header in rations:
|
||||
if header.recipe_id not in report.recipe_ids_cleared:
|
||||
report.recipe_ids_cleared.append(header.recipe_id)
|
||||
|
||||
if dry_run:
|
||||
continue
|
||||
|
||||
LabProfileNorm.query.filter_by(profile_id=profile.id).delete(synchronize_session=False)
|
||||
for header in rations:
|
||||
header.animal_profile_id = None
|
||||
header.updated_by = user_id
|
||||
if hasattr(profile, "soft_delete"):
|
||||
profile.soft_delete(user_id)
|
||||
else:
|
||||
db.session.delete(profile)
|
||||
report.profiles_deleted += 1
|
||||
|
||||
if not dry_run:
|
||||
db.session.commit()
|
||||
_log.info(
|
||||
"cleanup_legacy_profiles user=%s deleted=%s rations_cleared=%s",
|
||||
user_id,
|
||||
report.profiles_deleted,
|
||||
len(report.recipe_ids_cleared),
|
||||
)
|
||||
else:
|
||||
_log.info(
|
||||
"cleanup_legacy_profiles dry_run profiles=%s rations=%s",
|
||||
len(report.profiles_to_delete),
|
||||
len(report.recipe_ids_cleared),
|
||||
)
|
||||
return report
|
||||
Reference in New Issue
Block a user