"""Views портала для локаций / аптек.""" from __future__ import annotations from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden from django.shortcuts import get_object_or_404 from django.views.decorators.http import require_POST from core.utils.htmx import render_page from core.location_access import accessible_pharmacies from .forms import PortalPharmacyEditForm, PortalVendorForm from .models import Location, Pharmacy, pharmacy_card_flags, user_can_edit_pharmacy def user_can_manage_vendors(user) -> bool: """IT-раздел или staff — могут вести справочник сервисов/поставщиков.""" if not user or not getattr(user, 'is_authenticated', False): return False if getattr(user, 'is_staff', False) or getattr(user, 'is_superuser', False): return True from core.portal_access import user_can_access return user_can_access(user, 'it_manager') def _vendor_form_errors(form) -> str: errors = [] for field, msgs in form.errors.items(): label = form.fields[field].label if field in form.fields else field for msg in msgs: errors.append(f'{label}: {msg}' if field != '__all__' else msg) return ' '.join(errors) or 'Не удалось сохранить.' def _dislocation_vendors_response(request, *, message=None, error=None, form=None): from core.views import dislocation_view request._dislo_tab = 'vendors' if message: request._dislo_vendor_message = message if error: request._dislo_vendor_error = error if form is not None: request._dislo_vendor_form = form return dislocation_view(request) def _pharmacy_detail_context(request, pharmacy, *, form=None, edit_mode=False, form_message=None, form_error=None): """Контекст карточки аптеки (общий для GET/POST).""" from apps.employees.models import Employee from apps.it_manager.models import Equipment, InternetContract from apps.rro.models import CashRegister from apps.utilities.models import UtilityReading flags = pharmacy_card_flags(request.user, pharmacy) staff = [] if flags['can_view_staff']: staff = list( Employee.objects.filter(user_pharmacy=pharmacy, is_active=True) .select_related('post').order_by('last_name', 'first_name') ) equipment = [] if flags['can_view_equipment']: equipment = list( Equipment.objects.filter(location=pharmacy) .select_related( 'equipment_model__equipment_type', 'equipment_model__brand', 'status', 'assigned_to', ) .order_by('equipment_model__equipment_type__name', 'equipment_model__name') ) internet_contracts = [] if flags['can_view_internet']: internet_contracts = list( InternetContract.objects.filter(location=pharmacy) .select_related('provider', 'service_type', 'connection_type', 'status') .order_by('-start_date') ) cash_registers = [] if flags['can_view_rro']: cash_registers = list( CashRegister.objects.filter(pharmacy=pharmacy) .select_related('vendor', 'status') .order_by('-is_primary', 'kind', 'fiscal_number') ) utility_readings = [] if flags['can_view_utilities']: from apps.utilities.helpers import attach_reading_display utility_readings = list( UtilityReading.objects.filter(pharmacy=pharmacy) .select_related('utility_type', 'submitted_by') .order_by('-reading_date')[:50] ) attach_reading_display(utility_readings) can_edit = flags['can_edit'] if edit_mode and can_edit and form is None: form = PortalPharmacyEditForm(instance=pharmacy, user=request.user) return { 'pharmacy': pharmacy, 'staff': staff, 'staff_count': len(staff), 'phones': list(pharmacy.phones.filter(is_active=True)), 'equipment': equipment, 'internet_contracts': internet_contracts, 'cash_registers': cash_registers, 'utility_readings': utility_readings, **flags, 'can_view_ops': any(flags[f'can_view_{s}'] for s in ( 'staff', 'equipment', 'internet', 'rro', 'utilities', 'documents', )), 'pharmacy_edit_mode': bool(edit_mode and can_edit), 'pharmacy_edit_form': form if (edit_mode and can_edit) else None, 'pharmacy_form_message': form_message, 'pharmacy_form_error': form_error, } @login_required @require_POST def pharmacy_update_view(request, pk): pharmacy = get_object_or_404( accessible_pharmacies(request.user).select_related( 'organization', 'location_region', 'head_pharmacist__post', 'responsible_manager', 'curator', ).prefetch_related('phones'), pk=pk, ) if not user_can_edit_pharmacy(request.user, pharmacy): return HttpResponseForbidden() form = PortalPharmacyEditForm(request.POST, instance=pharmacy, user=request.user) if form.is_valid(): pharmacy = form.save(commit=False) pharmacy._history_user = request.user pharmacy.location_type = 'pharmacy' pharmacy.save() form.save_m2m() pharmacy.refresh_from_db() context = _pharmacy_detail_context( request, pharmacy, form_message='Изменения сохранены.', ) return render_page(request, 'pharmacy-detail.html', context) errors = [] for field, msgs in form.errors.items(): label = form.fields[field].label if field in form.fields else field for msg in msgs: errors.append(f'{label}: {msg}' if field != '__all__' else msg) context = _pharmacy_detail_context( request, pharmacy, form=form, edit_mode=True, form_error=' '.join(errors) or 'Не удалось сохранить.', ) return render_page(request, 'pharmacy-detail.html', context) def _vendor_detail_context(request, vendor, *, form=None, edit_mode=False, form_message=None, form_error=None): can_edit = user_can_manage_vendors(request.user) if edit_mode and can_edit and form is None: form = PortalVendorForm(instance=vendor) return { 'vendor': vendor, 'can_edit_vendor': can_edit, 'vendor_edit_mode': bool(edit_mode and can_edit), 'vendor_edit_form': form if (edit_mode and can_edit) else None, 'vendor_form_message': form_message, 'vendor_form_error': form_error, } @login_required def vendor_detail_view(request, pk): vendor = get_object_or_404( Location.objects.select_related('location_region'), pk=pk, location_type='vendor', ) edit_mode = request.GET.get('edit') == '1' if edit_mode and not user_can_manage_vendors(request.user): return HttpResponseForbidden() context = _vendor_detail_context(request, vendor, edit_mode=edit_mode) return render_page(request, 'vendor-detail.html', context) @login_required @require_POST def vendor_create_view(request): if not user_can_manage_vendors(request.user): return HttpResponseForbidden() form = PortalVendorForm(request.POST) if form.is_valid(): form.save() return _dislocation_vendors_response(request, message='Сервис / поставщик добавлен.') return _dislocation_vendors_response( request, error=_vendor_form_errors(form), form=form, ) @login_required @require_POST def vendor_update_view(request, pk): if not user_can_manage_vendors(request.user): return HttpResponseForbidden() vendor = get_object_or_404(Location, pk=pk, location_type='vendor') form = PortalVendorForm(request.POST, instance=vendor) # Если пришли с карточки — остаёмся на ней from_card = request.POST.get('from_card') == '1' if form.is_valid(): vendor = form.save() if from_card: context = _vendor_detail_context( request, vendor, form_message='Изменения сохранены.', ) return render_page(request, 'vendor-detail.html', context) return _dislocation_vendors_response(request, message='Изменения сохранены.') if from_card: context = _vendor_detail_context( request, vendor, form=form, edit_mode=True, form_error=_vendor_form_errors(form), ) return render_page(request, 'vendor-detail.html', context) return _dislocation_vendors_response( request, error=_vendor_form_errors(form), form=form, )