176 lines
7.0 KiB
Python
176 lines
7.0 KiB
Python
"""
|
|
Populate the `name_ar` (Arabic name) field on Department rows from a
|
|
hard-coded English -> Arabic mapping.
|
|
|
|
The mapping covers every department name present in the database. Keys are
|
|
normalized (case-insensitive, trailing "department" stripped, whitespace
|
|
collapsed) so that "Surgery", "Surgery Department" and "surgery department"
|
|
all resolve to the same Arabic value.
|
|
|
|
Arabic terms are cross-referenced with
|
|
apps/complaints/management/commands/arabic_dept_mapping.py to keep the
|
|
project's Arabic vocabulary consistent.
|
|
|
|
Usage:
|
|
python manage.py set_department_arabic_names # fill empties
|
|
python manage.py set_department_arabic_names --dry-run # preview only
|
|
python manage.py set_department_arabic_names --overwrite # re-translate all
|
|
python manage.py set_department_arabic_names --hospital-code HH-N
|
|
"""
|
|
|
|
import re
|
|
|
|
from django.core.management.base import BaseCommand
|
|
from django.db import transaction
|
|
|
|
from apps.organizations.models import Department
|
|
|
|
ENGLISH_TO_ARABIC = {
|
|
"laboratory": "قسم المختبر",
|
|
"icu": "وحدة العناية المركزة",
|
|
"security": "قسم الأمن",
|
|
"maintenance": "قسم الصيانة",
|
|
"housekeeping": "قسم النظافة",
|
|
"medical reports": "قسم التقارير الطبية",
|
|
"reception": "الاستقبال",
|
|
"administration": "الإدارة",
|
|
"surgery": "قسم الجراحة",
|
|
"cardiology": "قسم القلب",
|
|
"orthopedics": "قسم جراحة العظام",
|
|
"orthopedic": "قسم جراحة العظام",
|
|
"nursing": "قسم التمريض",
|
|
"pharmacy": "قسم الصيدلية",
|
|
"pediatrics": "قسم الأطفال",
|
|
"pediatric": "قسم الأطفال",
|
|
"emergency": "قسم الطوارئ",
|
|
"anesthesia": "قسم التخدير",
|
|
"biomedical": "قسم الهندسة الطبية الحيوية",
|
|
"contact center": "قسم مركز الاتصال",
|
|
"critical care": "قسم العناية المركزة",
|
|
"dental": "قسم الأسنان",
|
|
"dermatology": "قسم الجلدية",
|
|
"emergency administrative": "إدارة الطوارئ",
|
|
"emergency medicine": "قسم طب الطوارئ",
|
|
"executive administration": "الإدارة التنفيذية",
|
|
"facility management & maintenance": "قسم إدارة المرافق والصيانة",
|
|
"financial collection & claims": "قسم المالية والتحصيل والمطالبات",
|
|
"food services": "قسم خدمات الطعام",
|
|
"hr": "قسم الموارد البشرية",
|
|
"housekeeping & hospitality": "قسم النظافة والضيافة",
|
|
"ivf": "قسم أطفال الأنابيب",
|
|
"infection control": "قسم مكافحة العدوى",
|
|
"information technology": "قسم تقنية المعلومات",
|
|
"inpatient": "قسم التنويم",
|
|
"internal medicine": "قسم الباطنية",
|
|
"laundry": "قسم الغسيل",
|
|
"medical administration": "الإدارة الطبية",
|
|
"medical ancillary services": "قسم الخدمات الطبية المساندة",
|
|
"medical approvals": "قسم الموافقات الطبية",
|
|
"medical records": "قسم السجلات الطبية",
|
|
"oncology": "قسم الأورام",
|
|
"obstetrics & gynecology": "قسم النساء والولادة",
|
|
"operating rooms": "قسم غرف العمليات",
|
|
"operating rooms (or)": "قسم غرف العمليات",
|
|
"ophthalmology": "قسم العيون",
|
|
"outpatient": "قسم العيادات الخارجية",
|
|
"patient affairs": "قسم علاقات المرضى",
|
|
"patient experience": "قسم تجربة المريض",
|
|
"radiology": "قسم الأشعة",
|
|
"support services": "قسم الخدمات المساندة",
|
|
}
|
|
|
|
_DEPT_SUFFIX_RE = re.compile(r"\s+department$", re.IGNORECASE)
|
|
_WS_RE = re.compile(r"\s+")
|
|
|
|
|
|
def _normalize_en(value: str) -> str:
|
|
"""Normalize an English department name for mapping lookup."""
|
|
if not value:
|
|
return ""
|
|
value = _DEPT_SUFFIX_RE.sub("", str(value).strip())
|
|
value = _WS_RE.sub(" ", value).strip()
|
|
return value.lower()
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = "Populate Department.name_ar from a hard-coded English -> Arabic mapping"
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Preview changes without writing to the database",
|
|
)
|
|
parser.add_argument(
|
|
"--overwrite",
|
|
action="store_true",
|
|
help="Re-translate even departments that already have name_ar set",
|
|
)
|
|
parser.add_argument(
|
|
"--hospital-code",
|
|
type=str,
|
|
help="Limit to a single hospital code (default: all hospitals)",
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
dry_run = options["dry_run"]
|
|
overwrite = options["overwrite"]
|
|
hospital_code = options["hospital_code"]
|
|
|
|
qs = Department.objects.select_related("hospital").order_by("hospital__code", "name_en", "name")
|
|
if hospital_code:
|
|
qs = qs.filter(hospital__code=hospital_code)
|
|
if not overwrite:
|
|
qs = qs.filter(name_ar="")
|
|
|
|
self.stdout.write(self.style.MIGRATE_HEADING(
|
|
f"Department Arabic names (hospital={hospital_code or 'ALL'}, "
|
|
f"overwrite={overwrite}, dry_run={dry_run})"
|
|
))
|
|
|
|
updated = 0
|
|
skipped = 0
|
|
unmapped = []
|
|
|
|
with transaction.atomic():
|
|
for dept in qs.iterator():
|
|
key = _normalize_en(dept.name_en) or _normalize_en(dept.name)
|
|
arabic = ENGLISH_TO_ARABIC.get(key)
|
|
|
|
if not arabic:
|
|
unmapped.append((dept, key))
|
|
skipped += 1
|
|
continue
|
|
|
|
if dept.name_ar == arabic:
|
|
skipped += 1
|
|
continue
|
|
|
|
label = f"[{dept.hospital.code if dept.hospital else '-'}] {dept.code}: " \
|
|
f"{dept.name_en or dept.name!r}"
|
|
if dry_run:
|
|
self.stdout.write(f" ~ {label} -> {arabic}")
|
|
else:
|
|
dept.name_ar = arabic
|
|
dept.save(update_fields=["name_ar"])
|
|
self.stdout.write(self.style.SUCCESS(f" + {label} -> {arabic}"))
|
|
updated += 1
|
|
|
|
self.stdout.write("")
|
|
self.stdout.write(self.style.SUCCESS(
|
|
f"Done: {updated} {'would be ' if dry_run else ''}updated, {skipped} skipped"
|
|
))
|
|
|
|
if unmapped:
|
|
self.stdout.write(self.style.WARNING(
|
|
f"\n{len(unmapped)} department(s) had no mapping (left unchanged):"
|
|
))
|
|
for dept, key in unmapped:
|
|
self.stdout.write(self.style.WARNING(
|
|
f" - [{dept.hospital.code if dept.hospital else '-'}] {dept.code}: "
|
|
f"{dept.name_en or dept.name!r} (key={key!r})"
|
|
))
|
|
self.stdout.write(self.style.WARNING(
|
|
"\nAdd the missing keys to ENGLISH_TO_ARABIC and re-run."
|
|
))
|