"""Сид шаблона «Открытие аптеки» с типовыми шагами по отделам. python manage.py seed_project_templates """ from __future__ import annotations from django.core.management.base import BaseCommand from django.db import transaction from apps.projects.models import ( ProjectTemplate, ProjectTemplateStep, ProjectTemplateStepItem, ) from core.models.directories import Directory # (step_title, dept_code_or_name_hints, offset_days, duration_days, [item titles]) PHARMACY_OPENING_STEPS = [ ( 'Подготовка помещения и договора', ['юрист', 'legal', 'юридич'], 0, 21, [ 'Согласовать договор аренды', 'Проверить адрес и зону лицензирования', 'Получить технический паспорт / планы', ], ), ( 'Лицензирование', ['лиценз', 'фармацевт', 'качест'], 7, 30, [ 'Подготовить пакет документов на лицензию', 'Подать заявление в регулятор', 'Получить лицензию / внести изменения', ], ), ( 'IT и коммуникации', ['it', 'ит', 'информац'], 14, 21, [ 'Заказать канал связи / интернет', 'Установить РРО / ПРРО и ПО кассы', 'Настроить учётки AD / портал / почту', 'Проверить видеонаблюдение и сигнализацию', ], ), ( 'Закупки и оборудование', ['закуп', 'снабж', 'логист'], 14, 28, [ 'Заказать торговое оборудование', 'Закупить стартовый товарный запас', 'Организовать доставку и приёмку', ], ), ( 'HR и персонал', ['hr', 'кадр', 'персонал'], 21, 30, [ 'Утвердить штатное расписание', 'Нанять заведующего и фармацевтов', 'Оформить допуски и обучение', ], ), ( 'Маркетинг и открытие', ['маркет', 'реклам', 'pr'], 45, 21, [ 'Подготовить вывеску и оформление', 'Анонс открытия / акции', 'Чек-лист дня открытия', ], ), ] def _find_department(hints: list[str]): depts = list( Directory.objects.filter( directory_type__code='department', is_active=True, ) ) for hint in hints: h = hint.lower() for d in depts: blob = f'{d.code or ""} {d.name or ""}'.lower() if h in blob: return d return None class Command(BaseCommand): help = 'Seed project template «Открытие аптеки».' @transaction.atomic def handle(self, *args, **options): tpl, created = ProjectTemplate.objects.get_or_create( name='Открытие аптеки', defaults={ 'description': ( 'Типовой процесс открытия новой аптеки (1–3 месяца): ' 'лицензии, IT, закупки, HR, маркетинг.' ), 'default_duration_days': 90, 'is_active': True, }, ) if not created: tpl.description = tpl.description or ( 'Типовой процесс открытия новой аптеки (1–3 месяца).' ) tpl.default_duration_days = tpl.default_duration_days or 90 tpl.is_active = True tpl.save() # Refresh steps only if empty if tpl.steps.exists(): self.stdout.write( self.style.WARNING( f'Template «{tpl.name}» already has steps — skipped rewrite.' ) ) return for order, (title, hints, offset, duration, items) in enumerate( PHARMACY_OPENING_STEPS, ): dept = _find_department(hints) step = ProjectTemplateStep.objects.create( template=tpl, title=title, order=order, department=dept, offset_days=offset, duration_days=duration, ) for j, item_title in enumerate(items): ProjectTemplateStepItem.objects.create( step=step, title=item_title, order=j, priority='medium', ) dept_label = dept.name if dept else '— (отдел не найден, назначьте в админке)' self.stdout.write(f' + {title} → {dept_label}') self.stdout.write(self.style.SUCCESS( f'Seeded template «{tpl.name}» with {tpl.steps.count()} steps.' ))