from django.contrib.auth.models import Group, Permission from django.core.management.base import BaseCommand from apps.attachments.models import AttachmentPolicy from apps.tickets.models import SLAConfig, TicketCategory from apps.accounts.models import User from apps.customers.models import ContactGroup from apps.staff.models import OrganizationalUnit, StaffProfile, UnitMembership from apps.tickets.category_catalog import CATEGORY_CATALOG, UNIT_CONTENT class Command(BaseCommand): help = "Create initial categories, policies and permission groups" def merge_legacy_unit(self, legacy_slug, canonical_slug, canonical_name, canonical_description): legacy = OrganizationalUnit.objects.filter(slug=legacy_slug).first() canonical = OrganizationalUnit.objects.filter(slug=canonical_slug).first() if legacy is None: return if canonical is None: legacy.slug = canonical_slug legacy.name = canonical_name legacy.description = canonical_description legacy.save() return from apps.accounts.models import TicketMagicLink from apps.notifications.models import SMSTemplate from apps.tickets.models import GroupDispatch, Ticket canonical.permissions.add(*legacy.permissions.all()) TicketCategory.objects.filter(unit=legacy).update(unit=canonical) Ticket.objects.filter(owning_unit=legacy).update(owning_unit=canonical) Ticket.objects.filter(assigned_unit=legacy).update(assigned_unit=canonical) GroupDispatch.objects.filter(unit=legacy).update(unit=canonical) TicketMagicLink.objects.filter(created_unit=legacy).update(created_unit=canonical) StaffProfile.objects.filter(primary_unit=legacy).update(primary_unit=canonical) for membership in UnitMembership.objects.filter(unit=legacy): existing = UnitMembership.objects.filter(user=membership.user, unit=canonical).first() if existing is None: membership.unit = canonical membership.save(update_fields=["unit", "updated_at"]) continue existing.permissions.add(*membership.permissions.all()) existing.is_active = existing.is_active or membership.is_active existing.is_primary = existing.is_primary or membership.is_primary if membership.ticket_scope == UnitMembership.TicketScope.UNIT: existing.ticket_scope = UnitMembership.TicketScope.UNIT existing.save(update_fields=["is_active", "is_primary", "ticket_scope", "updated_at"]) membership.delete() for group in ContactGroup.objects.filter(unit=legacy): existing = ContactGroup.objects.filter(unit=canonical, name=group.name).first() if existing is None: group.unit = canonical group.save(update_fields=["unit", "updated_at"]) continue existing.contacts.add(*group.contacts.all()) GroupDispatch.objects.filter(contact_group=group).update(contact_group=existing) group.delete() for template in SMSTemplate.objects.filter(unit=legacy): if SMSTemplate.objects.filter(unit=canonical, event_type=template.event_type).exists(): template.delete() else: template.unit = canonical template.save(update_fields=["unit", "updated_at"]) legacy.delete() def handle(self, *args, **opts): self.merge_legacy_unit("accounting", "finance", "مالی / حسابداری", "واحد مالی و حسابداری (یک مفهوم سازمانی)") self.merge_legacy_unit("logistics", "warehouse-loading", "بارگیری انبار", "بارگیری، انبار و ارسال") self.merge_legacy_unit("warehouse", "warehouse-loading", "بارگیری انبار", "بارگیری، انبار و ارسال") categories = [("استعلام قیمت","price"),("درصد تخفیف","discount"),("شرایط فروش","sales-terms"),("موجودی","inventory"),("شرایط ارسال","delivery"),("درخواست نمایندگی","agency"),("شکایت","complaint"),("مشاوره","consulting"),("سایر","other")] for i, (title, slug) in enumerate(categories): TicketCategory.objects.get_or_create(slug=slug, defaults={"title":title,"sort_order":i}) sizes = {"IMAGE":10,"VOICE":25,"VIDEO":100,"PDF":30,"WORD":30,"EXCEL":30,"ZIP":50,"RAR":50} exts = {"IMAGE":[".jpg",".jpeg",".png",".gif",".webp"],"VOICE":[".webm",".ogg",".mp3",".m4a",".wav"],"VIDEO":[".mp4",".webm",".mov"],"PDF":[".pdf"],"WORD":[".doc",".docx"],"EXCEL":[".xls",".xlsx"],"ZIP":[".zip"],"RAR":[".rar"]} for i, (kind, mb) in enumerate(sizes.items()): AttachmentPolicy.objects.get_or_create(attachment_type=kind, defaults={"max_file_size":mb*1024*1024,"allowed_extensions":exts[kind],"sort_order":i}) for priority, first, resolution in [("NORMAL",240,2880),("IMPORTANT",120,1440),("URGENT",30,480)]: SLAConfig.objects.get_or_create(priority=priority, defaults={"first_response_minutes":first,"resolution_minutes":resolution}) expert_codes = ["view_ticket","add_ticket","claim_ticket","transfer_ticket","share_ticket","change_ticket","add_internal_note","edit_own_message","delete_own_message","download_attachment"] supervisor_codes = expert_codes + ["view_message_revisions","change_ticket_priority","view_customer_history"] manager_codes = supervisor_codes + ["view_deleted_message_content","delete_ticket"] role_permissions = { "Sales Expert": expert_codes, "Sales Supervisor": supervisor_codes, "Sales Manager": manager_codes, "Warehouse Expert": expert_codes, "Finance Expert": expert_codes, "CEO": manager_codes + ["view_all_tickets", "create_bulk_dispatch", "view_all_bulk_dispatches", "create_inquiry", "view_all_inquiries"], "General Admin": manager_codes + ["view_all_tickets"], } for group_name, codes in role_permissions.items(): group, _ = Group.objects.get_or_create(name=group_name) group.permissions.set(Permission.objects.filter(codename__in=codes)) units = {} for order, (slug, name, description, external, customer_visible) in enumerate([ ("sales", "فروش", UNIT_CONTENT["sales"]["description"], True, True), ("warehouse-loading", "بارگیری انبار", "عملیات داخلی بارگیری و انبار", True, False), ("finance", "مالی / حسابداری", UNIT_CONTENT["finance"]["description"], True, True), ("executive", "مدیریت ارشد", "مدیریت عامل", False, False), ], 10): unit, _ = OrganizationalUnit.objects.update_or_create(slug=slug, defaults={"name": name, "description": description, "search_keywords": UNIT_CONTENT.get(slug, {}).get("search_keywords", ""), "is_active": True, "accepts_external_tickets": external, "show_in_customer_form": customer_visible, "sort_order": order}) units[slug] = unit for unit_slug, rows in CATEGORY_CATALOG.items(): for sort_order, slug, title, description, search_keywords in rows: TicketCategory.objects.update_or_create(slug=slug, defaults={"unit": units[unit_slug], "title": title, "description": description, "search_keywords": search_keywords, "sort_order": sort_order, "is_active": True, "show_in_customer_form": True}) ContactGroup.objects.get_or_create(unit=units[unit_slug], name=f"مخاطبان {units[unit_slug].name}") TicketCategory.objects.update_or_create( slug="warehouse-loading-general", defaults={"unit": units["warehouse-loading"], "title": "عملیات بارگیری انبار", "description": "هماهنگی داخلی عملیات انبار و بارگیری.", "search_keywords": "انبار بارگیری عملیات داخلی", "sort_order": 10, "is_active": True, "show_in_customer_form": False}, ) TicketCategory.objects.filter(slug__in=("other", "e2e-sms")).update(show_in_customer_form=False) unit_permission_pairs = [ ("tickets", "view_ticket"), ("tickets", "add_ticket"), ("tickets", "claim_ticket"), ("messaging", "add_message"), ("customers", "view_customerprofile"), ("customers", "add_customerprofile"), ("customers", "change_customerprofile"), ("customers", "view_contactgroup"), ("customers", "add_contactgroup"), ("customers", "change_contactgroup"), ] for unit in (units["sales"], units["warehouse-loading"], units["finance"]): unit.permissions.add(*[Permission.objects.get(content_type__app_label=app, codename=code) for app, code in unit_permission_pairs]) people = [ ("kimiya_ghaffari", "کیمیا", "غفاری", "کیمیا غفاری", StaffProfile.Role.SALES_EXPERT, "sales", "کارشناس فروش", UnitMembership.TicketScope.SELF), ("zahra_jamali", "زهرا", "جمالی", "زهرا جمالی", StaffProfile.Role.SALES_EXPERT, "sales", "کارشناس فروش", UnitMembership.TicketScope.SELF), ("maryam_fotovat", "مریم", "فتوت", "مریم فتوت", StaffProfile.Role.SALES_SUPERVISOR, "sales", "سرپرست فروش", UnitMembership.TicketScope.UNIT), ("morteza_sokhaeifard", "مرتضی", "سخائی فرد", "مرتضی سخائی فرد", StaffProfile.Role.SALES_MANAGER, "sales", "مدیر فروش", UnitMembership.TicketScope.UNIT), ("mostafa_sokhaeifard", "مصطفی", "سخائی فرد", "مصطفی سخائی فرد", StaffProfile.Role.CEO, "executive", "مدیرعامل", UnitMembership.TicketScope.UNIT), ("ms_sabzali", "", "سبزعلی", "خانم سبزعلی", StaffProfile.Role.WAREHOUSE_EXPERT, "warehouse-loading", "کارشناس بارگیری انبار", UnitMembership.TicketScope.UNIT), ("mehdi_azami", "مهدی", "عظمی", "آقای مهدی عظمی", StaffProfile.Role.WAREHOUSE_EXPERT, "warehouse-loading", "کارشناس بارگیری انبار", UnitMembership.TicketScope.UNIT), ("fereshteh_yavari", "فرشته", "یاوری", "خانم فرشته یاوری", StaffProfile.Role.FINANCE_EXPERT, "finance", "کارشناس مالی / حسابداری", UnitMembership.TicketScope.UNIT), ("fatemeh_sokhaei", "فاطمه", "سخایی", "خانم فاطمه سخایی", StaffProfile.Role.FINANCE_EXPERT, "finance", "کارشناس مالی / حسابداری", UnitMembership.TicketScope.UNIT), ("rana_nobakht", "رعنا", "نوبخت", "خانم رعنا نوبخت", StaffProfile.Role.FINANCE_EXPERT, "finance", "کارشناس مالی / حسابداری", UnitMembership.TicketScope.UNIT), ("mehdi_liaqat", "مهدی", "لیاقت", "آقای مهدی لیاقت", StaffProfile.Role.FINANCE_EXPERT, "finance", "کارشناس مالی / حسابداری", UnitMembership.TicketScope.UNIT), ("aliasghar_sokhaeifard", "علی اصغر", "سخائی فرد", "علی اصغر سخائی فرد", StaffProfile.Role.FINANCE_EXPERT, "finance", "کارشناس مالی / حسابداری", UnitMembership.TicketScope.UNIT), ] for username, first_name, last_name, display_name, role, unit_slug, title, scope in people: user, created = User.objects.get_or_create(username=username, defaults={"account_type": User.AccountType.STAFF}) user.account_type = User.AccountType.STAFF; user.first_name = first_name; user.last_name = last_name; user.is_active = True if created: user.set_unusable_password() user.save() profile, _ = StaffProfile.objects.update_or_create(user=user, defaults={"primary_unit": units[unit_slug], "role": role, "display_name": display_name, "first_name": first_name, "last_name": last_name, "job_title": title, "is_active": True}) membership = UnitMembership.objects.get(user=user, unit=units[unit_slug]) membership.ticket_scope = scope; membership.is_primary = True; membership.is_active = True; membership.save() user.unit_memberships.exclude(pk=membership.pk).delete() sabzali = User.objects.get(username="ms_sabzali") sabzali.unit_memberships.get(unit=units["warehouse-loading"]).permissions.add(*Permission.objects.filter(content_type__app_label="tickets", codename__in=["create_bulk_dispatch", "create_inquiry"])) ceo = User.objects.get(username="mostafa_sokhaeifard") ceo.user_permissions.add(*Permission.objects.filter(content_type__app_label="tickets", codename__in=["view_all_tickets", "add_ticket", "create_bulk_dispatch", "view_all_bulk_dispatches", "create_inquiry", "view_all_inquiries"])) self.stdout.write(self.style.SUCCESS("Initial data created."))