Files
ACORE/apps/locations/models/pharmacy_visibility.py
T
2026-09-21 20:37:18 +03:00

150 lines
5.7 KiB
Python

"""Политика видимости вкладок карточки аптеки (синглтон, настраивается в админке)."""
from __future__ import annotations
from django.db import models
from django.utils.translation import gettext_lazy as _
class PharmacyCardVisibility(models.Model):
"""Кто видит операционные блоки на /pharmacies/<id>/.
Синглтон (pk=1). Уровни одинаковы для всех вкладок — матрица в админке.
"""
class Level(models.TextChoices):
EVERYONE = 'everyone', _('Все авторизованные')
OWN_OR_STAFF = 'own_or_staff', _('Своя аптека или staff')
STAFF = 'staff', _('Только staff / суперпользователь')
IT = 'it', _('Группа IT / доступ IT-отдел')
HIDDEN = 'hidden', _('Скрыто (кроме суперпользователя)')
show_staff = models.CharField(
_('Персонал'), max_length=20,
choices=Level.choices, default=Level.OWN_OR_STAFF,
)
show_equipment = models.CharField(
_('Оборудование'), max_length=20,
choices=Level.choices, default=Level.OWN_OR_STAFF,
)
show_internet = models.CharField(
_('Интернет-договоры'), max_length=20,
choices=Level.choices, default=Level.OWN_OR_STAFF,
)
show_rro = models.CharField(
_('РРО / ПРРО'), max_length=20,
choices=Level.choices, default=Level.OWN_OR_STAFF,
)
show_utilities = models.CharField(
_('Коммунальные показания'), max_length=20,
choices=Level.choices, default=Level.OWN_OR_STAFF,
)
show_documents = models.CharField(
_('Документы'), max_length=20,
choices=Level.choices, default=Level.OWN_OR_STAFF,
)
edit_pharmacy = models.CharField(
_('Редактирование карточки'), max_length=20,
choices=Level.choices, default=Level.STAFF,
help_text=_(
'Кто может менять реквизиты аптеки в портале '
'(не в админке). По умолчанию — только staff.'
),
)
class Meta:
verbose_name = _('Видимость карточки аптеки')
verbose_name_plural = _('Видимость карточки аптеки')
def __str__(self):
return str(_('Видимость карточки аптеки'))
def save(self, *args, **kwargs):
self.pk = 1
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
pass
@classmethod
def load(cls) -> 'PharmacyCardVisibility':
from django.db import connection
from django.db.utils import ProgrammingError
try:
obj, _ = cls.objects.get_or_create(pk=1)
return obj
except ProgrammingError:
# Миграция 0013 ещё не применена — не валим карточку аптеки.
connection.rollback()
return cls(
pk=1,
show_staff=cls.Level.OWN_OR_STAFF,
show_equipment=cls.Level.OWN_OR_STAFF,
show_internet=cls.Level.OWN_OR_STAFF,
show_rro=cls.Level.OWN_OR_STAFF,
show_utilities=cls.Level.OWN_OR_STAFF,
show_documents=cls.Level.OWN_OR_STAFF,
edit_pharmacy=cls.Level.STAFF,
)
SECTIONS = (
'staff',
'equipment',
'internet',
'rro',
'utilities',
'documents',
)
def level_for(self, section: str) -> str:
return getattr(self, f'show_{section}', self.Level.OWN_OR_STAFF)
def user_can_view_pharmacy_section(user, pharmacy, level: str) -> bool:
"""Проверка уровня видимости для user × pharmacy."""
if not user or not getattr(user, 'is_authenticated', False):
return False
from core.location_access import accessible_pharmacies
if not accessible_pharmacies(user).filter(pk=pharmacy.pk).exists():
return False
if getattr(user, 'is_superuser', False):
return True
if level == PharmacyCardVisibility.Level.HIDDEN:
return False
if level == PharmacyCardVisibility.Level.EVERYONE:
return True
if level == PharmacyCardVisibility.Level.STAFF:
return bool(getattr(user, 'is_staff', False))
if level == PharmacyCardVisibility.Level.OWN_OR_STAFF:
if getattr(user, 'is_staff', False):
return True
return True # область уже проверена: своя или закреплённая аптека
if level == PharmacyCardVisibility.Level.IT:
from core.portal_access import user_can_access
if user_can_access(user, 'it_manager'):
return True
return user.groups.filter(name='IT').exists()
return False
def user_can_edit_pharmacy(user, pharmacy) -> bool:
"""Чи може user редагувати реквізити аптеки в порталі."""
policy = PharmacyCardVisibility.load()
return user_can_view_pharmacy_section(user, pharmacy, policy.edit_pharmacy)
def pharmacy_card_flags(user, pharmacy) -> dict[str, bool]:
"""Словник can_view_<section> / can_edit за поточною політикою."""
policy = PharmacyCardVisibility.load()
flags = {
f'can_view_{section}': user_can_view_pharmacy_section(
user, pharmacy, policy.level_for(section),
)
for section in PharmacyCardVisibility.SECTIONS
}
flags['can_edit'] = user_can_view_pharmacy_section(
user, pharmacy, policy.edit_pharmacy,
)
return flags