150 lines
5.7 KiB
Python
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
|