Add RRO, portal section perms, dislocation presets, and hiring intern flow.
Ship cash-register registry, section-based portal access, configurable dislocation columns, and trial-hire intern accounts with credentials PDF.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
from datetime import date
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.test import TestCase
|
||||
|
||||
from core.models import Directory, DirectoryType
|
||||
from apps.locations.models import Pharmacy
|
||||
from apps.rro.models import CashRegister
|
||||
|
||||
Employee = get_user_model()
|
||||
|
||||
|
||||
class CashRegisterModelTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
org_type = DirectoryType.objects.create(code='organization', name='Организация')
|
||||
region_type = DirectoryType.objects.create(code='region', name='Регион')
|
||||
status_type, _ = DirectoryType.objects.get_or_create(
|
||||
code='rro_status', defaults={'name': 'Статус РРО/ПРРО', 'hierarchy_type': 'strict'},
|
||||
)
|
||||
cls.status_active, _ = Directory.objects.get_or_create(
|
||||
directory_type=status_type, code='active',
|
||||
defaults={'name': 'Активный', 'is_active': True},
|
||||
)
|
||||
cls.region = Directory.objects.create(directory_type=region_type, code='od', name='Одесса')
|
||||
cls.org = Directory.objects.create(directory_type=org_type, code='akc', name='АКС')
|
||||
cls.pharmacy = Pharmacy.objects.create(
|
||||
organization=cls.org, location_region=cls.region,
|
||||
pharmacy_number=42, location_type='pharmacy',
|
||||
street='Тестовая', house_number='1',
|
||||
)
|
||||
cls.pharmacy2 = Pharmacy.objects.create(
|
||||
organization=cls.org, location_region=cls.region,
|
||||
pharmacy_number=43, location_type='pharmacy',
|
||||
street='Другая', house_number='2',
|
||||
)
|
||||
|
||||
def _reg(self, **kw):
|
||||
defaults = {
|
||||
'pharmacy': self.pharmacy,
|
||||
'kind': CashRegister.Kind.PRRO,
|
||||
'fiscal_number': kw.pop('fiscal_number', f'FN-{CashRegister.objects.count()+1}'),
|
||||
'status': self.status_active,
|
||||
}
|
||||
defaults.update(kw)
|
||||
return CashRegister(**defaults)
|
||||
|
||||
def test_seed_statuses_exist(self):
|
||||
codes = set(
|
||||
Directory.objects.filter(directory_type__code='rro_status')
|
||||
.values_list('code', flat=True)
|
||||
)
|
||||
self.assertTrue({'active', 'reserve', 'repair', 'decommissioned'} <= codes)
|
||||
|
||||
def test_unique_fiscal_number(self):
|
||||
self._reg(fiscal_number='FN-UNIQUE').save()
|
||||
with self.assertRaises(IntegrityError):
|
||||
with transaction.atomic():
|
||||
self._reg(fiscal_number='FN-UNIQUE', pharmacy=self.pharmacy2).save()
|
||||
|
||||
def test_only_one_primary_per_pharmacy(self):
|
||||
a = self._reg(fiscal_number='FN-P1', is_primary=True)
|
||||
a.full_clean()
|
||||
a.save()
|
||||
b = self._reg(fiscal_number='FN-P2', is_primary=True)
|
||||
with self.assertRaises(ValidationError):
|
||||
b.full_clean()
|
||||
|
||||
def test_primary_ok_on_different_pharmacies(self):
|
||||
a = self._reg(fiscal_number='FN-A', is_primary=True)
|
||||
a.full_clean()
|
||||
a.save()
|
||||
b = self._reg(fiscal_number='FN-B', pharmacy=self.pharmacy2, is_primary=True)
|
||||
b.full_clean()
|
||||
b.save()
|
||||
|
||||
|
||||
class CashRegisterPortalTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
org_type = DirectoryType.objects.create(code='organization', name='Организация')
|
||||
region_type = DirectoryType.objects.create(code='region', name='Регион')
|
||||
status_type, _ = DirectoryType.objects.get_or_create(
|
||||
code='rro_status', defaults={'name': 'Статус РРО/ПРРО', 'hierarchy_type': 'strict'},
|
||||
)
|
||||
cls.status_active, _ = Directory.objects.get_or_create(
|
||||
directory_type=status_type, code='active',
|
||||
defaults={'name': 'Активный', 'is_active': True},
|
||||
)
|
||||
region = Directory.objects.create(directory_type=region_type, code='kv', name='Киев')
|
||||
org = Directory.objects.create(directory_type=org_type, code='org', name='ТестОрг')
|
||||
cls.pharmacy = Pharmacy.objects.create(
|
||||
organization=org, location_region=region,
|
||||
pharmacy_number=7, location_type='pharmacy',
|
||||
street='Главная', house_number='7',
|
||||
)
|
||||
CashRegister.objects.create(
|
||||
pharmacy=cls.pharmacy, kind=CashRegister.Kind.RRO,
|
||||
fiscal_number='FN-PORTAL-1', status=cls.status_active,
|
||||
model_name='Datecs FP-700', is_primary=True,
|
||||
)
|
||||
cls.user = Employee.objects.create(
|
||||
username='rro.staff',
|
||||
email='rro.staff@company.local',
|
||||
first_name='РРО',
|
||||
last_name='Тест',
|
||||
hire_date=date(2026, 1, 1),
|
||||
user_location_type='office',
|
||||
is_staff=True,
|
||||
mattermost_sync_enabled=False,
|
||||
ad_sync_enabled=False,
|
||||
totp_enabled=True,
|
||||
)
|
||||
|
||||
def _login(self):
|
||||
self.client.force_login(self.user)
|
||||
session = self.client.session
|
||||
session['2fa_verified'] = True
|
||||
session.save()
|
||||
|
||||
def test_rro_list_page(self):
|
||||
self._login()
|
||||
resp = self.client.get('/rro/', HTTP_HX_REQUEST='true')
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertContains(resp, 'FN-PORTAL-1')
|
||||
|
||||
def test_pharmacy_detail_rro_tab(self):
|
||||
self._login()
|
||||
resp = self.client.get(f'/pharmacies/{self.pharmacy.pk}/', HTTP_HX_REQUEST='true')
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertContains(resp, 'FN-PORTAL-1')
|
||||
self.assertContains(resp, 'ph-panel-rro')
|
||||
Reference in New Issue
Block a user