148 lines
13 KiB
Python
148 lines
13 KiB
Python
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."))
|