7a149dd84d
Вынесены can_* для кассы и посещаемости, синхронизация в builders/signals, seed групп в core.0023–0024. Co-authored-by: Cursor <cursoragent@cursor.com>
212 lines
7.7 KiB
Python
212 lines
7.7 KiB
Python
from datetime import date
|
||
|
||
from django.contrib.auth.models import Group
|
||
from django.test import SimpleTestCase, TestCase, override_settings
|
||
|
||
from apps.employees.models import Employee
|
||
from apps.portal_connector.client import PnmsClient, PnmsClientError
|
||
from apps.portal_connector.msorter_client import MsorterClient, MsorterClientError
|
||
from apps.portal_connector.msorter_services import build_msorter_payload
|
||
|
||
|
||
class PnmsClientTlsTests(SimpleTestCase):
|
||
"""В проде identity-payload может содержать password_hash — только https://."""
|
||
|
||
@override_settings(
|
||
DEBUG=False,
|
||
PNMS_SYNC_ENABLED=True,
|
||
PNMS_BASE_URL='http://pnms.example',
|
||
PNMS_ACORE_TOKEN='secret',
|
||
)
|
||
def test_http_rejected_when_debug_false(self):
|
||
with self.assertRaises(PnmsClientError) as cm:
|
||
PnmsClient().post('/api/sync/from-acore/employees/', {'employees': []})
|
||
self.assertIn('https://', str(cm.exception))
|
||
|
||
@override_settings(
|
||
DEBUG=False,
|
||
PNMS_SYNC_ENABLED=True,
|
||
PNMS_BASE_URL='https://pnms.example',
|
||
PNMS_ACORE_TOKEN='secret',
|
||
)
|
||
def test_https_allowed_when_debug_false(self):
|
||
PnmsClient()._ensure_tls()
|
||
|
||
@override_settings(
|
||
DEBUG=True,
|
||
PNMS_SYNC_ENABLED=True,
|
||
PNMS_BASE_URL='http://localhost:8001',
|
||
PNMS_ACORE_TOKEN='secret',
|
||
)
|
||
def test_http_allowed_in_debug(self):
|
||
PnmsClient()._ensure_tls()
|
||
|
||
|
||
class MsorterClientTlsTests(SimpleTestCase):
|
||
@override_settings(
|
||
DEBUG=False,
|
||
MSORTER_SYNC_ENABLED=True,
|
||
MSORTER_BASE_URL='http://msorter.example',
|
||
MSORTER_ACORE_TOKEN='secret',
|
||
)
|
||
def test_http_rejected_when_debug_false(self):
|
||
with self.assertRaises(MsorterClientError) as cm:
|
||
MsorterClient().post('/api/sync/from-acore/employees/', {'employees': []})
|
||
self.assertIn('https://', str(cm.exception))
|
||
|
||
|
||
class MsorterPayloadTests(TestCase):
|
||
def test_access_false_without_group(self):
|
||
emp = Employee.objects.create_user(
|
||
username='no-mail',
|
||
password='x',
|
||
first_name='N',
|
||
last_name='M',
|
||
hire_date=date(2020, 1, 1),
|
||
)
|
||
payload = build_msorter_payload(emp)
|
||
self.assertFalse(payload['access'])
|
||
self.assertFalse(payload['is_active'])
|
||
|
||
def test_access_true_with_pochta_group(self):
|
||
emp = Employee.objects.create_user(
|
||
username='has-mail',
|
||
password='x',
|
||
first_name='H',
|
||
last_name='M',
|
||
hire_date=date(2020, 1, 1),
|
||
)
|
||
group, _ = Group.objects.get_or_create(name='Почта')
|
||
emp.groups.add(group)
|
||
payload = build_msorter_payload(emp, include_password=True)
|
||
self.assertTrue(payload['access'])
|
||
self.assertTrue(payload['is_active'])
|
||
self.assertIn('password_hash', payload)
|
||
self.assertTrue(payload['reset_password'])
|
||
|
||
|
||
class PvmsClientTlsTests(SimpleTestCase):
|
||
@override_settings(
|
||
DEBUG=False,
|
||
PVMS_SYNC_ENABLED=True,
|
||
PVMS_BASE_URL='http://pvms.example',
|
||
PVMS_ACORE_TOKEN='secret',
|
||
)
|
||
def test_http_rejected_when_debug_false(self):
|
||
from apps.portal_connector.pvms_client import PvmsClient, PvmsClientError
|
||
with self.assertRaises(PvmsClientError) as cm:
|
||
PvmsClient().post('/api/sync/from-acore/employees/', {'employees': []})
|
||
self.assertIn('https://', str(cm.exception))
|
||
|
||
|
||
class PvmsPayloadTests(TestCase):
|
||
def test_employee_payload(self):
|
||
from apps.portal_connector.pvms_builders import build_pvms_employee_payload
|
||
|
||
emp = Employee.objects.create_user(
|
||
username='pvms-user',
|
||
password='x',
|
||
first_name='P',
|
||
last_name='V',
|
||
hire_date=date(2020, 1, 1),
|
||
)
|
||
payload = build_pvms_employee_payload(emp, include_password=True)
|
||
self.assertEqual(payload['acore_id'], emp.pk)
|
||
self.assertEqual(payload['username'], 'pvms-user')
|
||
self.assertIn('password_hash', payload)
|
||
self.assertTrue(payload['reset_password'])
|
||
self.assertEqual(payload['role'], 'employee')
|
||
|
||
|
||
class PasswordPushSignalTests(TestCase):
|
||
@override_settings(
|
||
PNMS_SYNC_ENABLED=True,
|
||
PVMS_SYNC_ENABLED=True,
|
||
MSORTER_SYNC_ENABLED=True,
|
||
)
|
||
def test_password_change_enqueues_include_password(self):
|
||
from unittest.mock import patch
|
||
|
||
emp = Employee.objects.create_user(
|
||
username='pwd-sync',
|
||
password='old',
|
||
first_name='P',
|
||
last_name='W',
|
||
hire_date=date(2020, 1, 1),
|
||
)
|
||
with (
|
||
patch('apps.portal_connector.tasks.push_employee_to_pnms.delay') as pnms,
|
||
patch('apps.portal_connector.tasks.push_employee_to_pvms.delay') as pvms,
|
||
patch('apps.portal_connector.tasks.push_employee_to_msorter.delay') as msorter,
|
||
):
|
||
emp.set_password('new-secret')
|
||
emp.save()
|
||
pnms.assert_called_once_with(emp.pk, include_password=True)
|
||
pvms.assert_called_once_with(emp.pk, include_password=True)
|
||
msorter.assert_called_once_with(emp.pk, include_password=True)
|
||
|
||
|
||
class PushAllDefaultsTests(SimpleTestCase):
|
||
def test_push_all_identity_defaults_no_passwords(self):
|
||
import inspect
|
||
from apps.portal_connector.tasks import push_all_identity_to_pnms
|
||
|
||
params = inspect.signature(push_all_identity_to_pnms).parameters
|
||
self.assertEqual(params['include_password'].default, False)
|
||
|
||
|
||
class PosPermissionsSeedTests(TestCase):
|
||
def test_pnms_can_permissions_exist_and_revisor_seeded(self):
|
||
from django.contrib.auth.models import Permission
|
||
from apps.portal_connector.pos_permissions import (
|
||
PNMS_ACCESS_APP_LABEL,
|
||
PNMS_ACCESS_MODEL,
|
||
POS_PERMISSION_CODENAMES,
|
||
)
|
||
|
||
qs = Permission.objects.filter(
|
||
content_type__app_label=PNMS_ACCESS_APP_LABEL,
|
||
content_type__model=PNMS_ACCESS_MODEL,
|
||
)
|
||
self.assertEqual(qs.count(), len(POS_PERMISSION_CODENAMES))
|
||
revisor = Group.objects.get(name='Ревизор')
|
||
codes = set(revisor.permissions.filter(
|
||
content_type__model=PNMS_ACCESS_MODEL,
|
||
).values_list('codename', flat=True))
|
||
self.assertIn('can_deactivate_receipt', codes)
|
||
self.assertIn('can_create_return', codes)
|
||
self.assertIn('can_do_inventory', codes)
|
||
|
||
def test_build_employee_payload_includes_group_pos_perms(self):
|
||
from apps.portal_connector.builders import build_employee_payload
|
||
|
||
emp = Employee.objects.create_user(
|
||
username='pos-revisor',
|
||
password='x',
|
||
first_name='R',
|
||
last_name='V',
|
||
hire_date=date(2020, 1, 1),
|
||
)
|
||
emp.groups.add(Group.objects.get(name='Ревизор'))
|
||
payload = build_employee_payload(emp)
|
||
self.assertIn('can_deactivate_receipt', payload['pos_permissions'])
|
||
self.assertIn('can_do_inventory', payload['pos_permissions'])
|
||
|
||
|
||
class GroupChangePushTests(TestCase):
|
||
@override_settings(PNMS_SYNC_ENABLED=True, PVMS_SYNC_ENABLED=False, MSORTER_SYNC_ENABLED=False)
|
||
def test_group_m2m_enqueues_pnms_push(self):
|
||
from unittest.mock import patch
|
||
|
||
emp = Employee.objects.create_user(
|
||
username='grp-sync',
|
||
password='x',
|
||
first_name='G',
|
||
last_name='S',
|
||
hire_date=date(2020, 1, 1),
|
||
)
|
||
group = Group.objects.get(name='Фармацевт')
|
||
with patch('apps.portal_connector.tasks.push_employee_to_pnms.delay') as pnms:
|
||
emp.groups.add(group)
|
||
pnms.assert_called_once_with(emp.pk, include_password=False)
|