Files
ACORE/apps/projects/management/commands/seed_project_templates.py
T
lokses 030bbc98fd projects: модуль проектов с шагами по отделам и Task.
Шаблоны/ручное создание, access_projects, сид «Открытие аптеки». Плюс SILO/S3 для Django media.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-23 16:26:45 +03:00

154 lines
5.4 KiB
Python

"""Сид шаблона «Открытие аптеки» с типовыми шагами по отделам.
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.'
))