Files
westech-r2/westech_r2/migrations/migrate_serial_grades.py
T
Westech Admin 232c4af3b6 Fix migration script: read cosmetic_grade from Device Condition Report, not Serial No
Serial No.cosmetic_grade is empty on production. The actual C# data lives
in Device Condition Report (42,940 records). Updated script to lookup
latest report per serial_no and map from there.
2026-05-19 18:24:48 +00:00

98 lines
3.3 KiB
Python

"""
Data Migration: Populate new Serial No fields from Device Condition Report data.
Run this IMMEDIATELY after `bench migrate` on production.
Requires: all new fields already exist (grade, cpu_test, ram_test, etc.)
Maps cosmetic_grade C# values from latest Device Condition Report → new grade field:
C5-C9 → High
C4 → Med
C3 → Low
C0-C2, blank, anything else → Flagged
"""
import frappe
from frappe.utils import now
def run():
print(f"[{now()}] Starting Serial No grade migration...")
# Get all Serial Nos with their latest Device Condition Report
serials = frappe.get_all("Serial No",
fields=["name"],
limit_page_length=0
)
stats = {"high": 0, "med": 0, "low": 0, "flagged": 0, "skipped": 0, "errors": 0, "no_report": 0}
for i, s in enumerate(serials):
try:
# Find latest Device Condition Report for this serial
reports = frappe.get_all("Device Condition Report",
filters={"serial_no": s.name},
fields=["cosmetic_grade"],
order_by="creation DESC",
limit=1
)
if not reports:
# No report found - flag it
new_grade = "Flagged"
stats["no_report"] += 1
else:
cosmetic = (reports[0].cosmetic_grade or "").strip().upper()
# Map cosmetic_grade → new grade
if cosmetic in ("C5", "C6", "C7", "C8", "C9"):
new_grade = "High"
stats["high"] += 1
elif cosmetic == "C4":
new_grade = "Med"
stats["med"] += 1
elif cosmetic == "C3":
new_grade = "Low"
stats["low"] += 1
else:
new_grade = "Flagged"
stats["flagged"] += 1
# Only update if grade is blank
current_grade = frappe.db.get_value("Serial No", s.name, "grade")
if current_grade and current_grade in ("High", "Med", "Low", "Flagged"):
stats["skipped"] += 1
continue
# Determine pricing_status
if new_grade == "Flagged":
pricing_status = "Flagged"
else:
pricing_status = "Needs Pricing"
frappe.db.set_value("Serial No", s.name, {
"grade": new_grade,
"pricing_status": pricing_status
})
if (i + 1) % 1000 == 0:
frappe.db.commit()
print(f" Processed {i + 1}/{len(serials)}...")
except Exception as e:
stats["errors"] += 1
frappe.log_error(f"Migration error for {s.name}: {e}", "Serial Grade Migration")
frappe.db.commit()
print(f"\n[{now()}] Migration complete!")
print(f" Total Serial Nos: {len(serials)}")
print(f" High: {stats['high']}")
print(f" Med: {stats['med']}")
print(f" Low: {stats['low']}")
print(f" Flagged (from missing/bad grade): {stats['flagged']}")
print(f" Flagged (no report found): {stats['no_report']}")
print(f" Skipped (already migrated): {stats['skipped']}")
print(f" Errors: {stats['errors']}")
if __name__ == "__main__":
run()