Дал мастеру доступ к пунктам
All checks were successful
Deploy MES Core / deploy (push) Successful in 11s

This commit is contained in:
2026-04-13 08:10:21 +03:00
parent 28537447f8
commit fa881877d7
3 changed files with 81 additions and 56 deletions

Binary file not shown.

View File

@@ -224,7 +224,7 @@
<div class="col-md-4"> <div class="col-md-4">
<label class="form-label">Склад</label> <label class="form-label">Склад</label>
<select class="form-select" name="location_id" required> <select class="form-select" name="location_id" required>
{% for loc in locations %} {% for loc in transfer_locations %}
<option value="{{ loc.id }}">{{ loc }}</option> <option value="{{ loc.id }}">{{ loc }}</option>
{% endfor %} {% endfor %}
</select> </select>

View File

@@ -966,9 +966,8 @@ class PlanningStagesView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/planning_stages.html' template_name = 'shiftflow/planning_stages.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'manager', 'observer', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'manager', 'observer']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
@@ -1888,17 +1887,18 @@ class PlanningView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/planning.html' template_name = 'shiftflow/planning.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director', 'observer']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) profile = getattr(self.request.user, 'profile', None)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') roles = get_user_roles(self.request.user)
role = primary_role(roles)
context['user_role'] = role context['user_role'] = role
context['user_roles'] = sorted(roles)
allowed_ws = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else [] allowed_ws = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else []
context['allowed_workshop_ids'] = allowed_ws context['allowed_workshop_ids'] = allowed_ws
@@ -1923,17 +1923,18 @@ class DealPlanningView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/planning_deal.html' template_name = 'shiftflow/planning_deal.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director', 'observer']):
if role not in ['admin', 'technologist', 'master', 'clerk']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) profile = getattr(self.request.user, 'profile', None)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') roles = get_user_roles(self.request.user)
role = primary_role(roles)
context['user_role'] = role context['user_role'] = role
context['user_roles'] = sorted(roles)
allowed_ws = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else [] allowed_ws = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else []
context['allowed_workshop_ids'] = allowed_ws context['allowed_workshop_ids'] = allowed_ws
@@ -2525,17 +2526,17 @@ class CustomersView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/customers.html' template_name = 'shiftflow/customers.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director', 'observer']):
if role not in ['admin', 'technologist', 'master', 'clerk']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) roles = get_user_roles(self.request.user)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') role = primary_role(roles)
context['user_role'] = role context['user_role'] = role
context['user_roles'] = sorted(roles)
companies = Company.objects.all().order_by('name') companies = Company.objects.all().order_by('name')
context['companies'] = companies context['companies'] = companies
@@ -2546,17 +2547,18 @@ class CustomerDealsView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/customer_deals.html' template_name = 'shiftflow/customer_deals.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director', 'observer']):
if role not in ['admin', 'technologist', 'master', 'clerk']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) profile = getattr(self.request.user, 'profile', None)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') roles = get_user_roles(self.request.user)
role = primary_role(roles)
context['user_role'] = role context['user_role'] = role
context['user_roles'] = sorted(roles)
allowed_ws = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else [] allowed_ws = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else []
context['allowed_workshop_ids'] = allowed_ws context['allowed_workshop_ids'] = allowed_ws
@@ -3296,17 +3298,17 @@ class DirectoriesView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/directories.html' template_name = 'shiftflow/directories.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'observer', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) roles = get_user_roles(self.request.user)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') role = primary_role(roles)
ctx['user_role'] = role ctx['user_role'] = role
ctx['user_roles'] = sorted(roles)
return ctx return ctx
@@ -3314,26 +3316,25 @@ class LocationsCatalogView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/locations_catalog.html' template_name = 'shiftflow/locations_catalog.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'observer', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) roles = get_user_roles(self.request.user)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') role = primary_role(roles)
ctx['user_role'] = role ctx['user_role'] = role
ctx['can_edit'] = role in ['admin', 'prod_head', 'director'] ctx['user_roles'] = sorted(roles)
ctx['can_edit'] = has_any_role(roles, ['admin', 'prod_head', 'director'])
ctx['locations'] = list(Location.objects.order_by('name')) ctx['locations'] = list(Location.objects.order_by('name'))
return ctx return ctx
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'prod_head', 'director']):
if role not in ['admin', 'prod_head', 'director']:
return redirect('locations_catalog') return redirect('locations_catalog')
action = (request.POST.get('action') or '').strip() action = (request.POST.get('action') or '').strip()
@@ -3377,17 +3378,17 @@ class WorkshopsCatalogView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/workshops_catalog.html' template_name = 'shiftflow/workshops_catalog.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'observer', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) roles = get_user_roles(self.request.user)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') role = primary_role(roles)
ctx['user_role'] = role ctx['user_role'] = role
ctx['user_roles'] = sorted(roles)
workshops = list(Workshop.objects.select_related('location').order_by('id')) workshops = list(Workshop.objects.select_related('location').order_by('id'))
ws_ids = [int(w.id) for w in workshops] ws_ids = [int(w.id) for w in workshops]
@@ -3414,12 +3415,12 @@ class MachinesCatalogView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/machines_catalog.html' template_name = 'shiftflow/machines_catalog.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'observer', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']:
return redirect('registry') return redirect('registry')
self.role = role self.roles = roles
self.can_edit = role in ['admin', 'prod_head', 'director'] self.role = primary_role(roles)
self.can_edit = has_any_role(roles, ['admin', 'prod_head', 'director'])
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def _workshop_id(self): def _workshop_id(self):
@@ -3889,17 +3890,18 @@ class WarehouseStocksView(LoginRequiredMixin, TemplateView):
template_name = 'shiftflow/warehouse_stocks.html' template_name = 'shiftflow/warehouse_stocks.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'observer', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk', 'observer']:
return redirect('registry') return redirect('registry')
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs) ctx = super().get_context_data(**kwargs)
profile = getattr(self.request.user, 'profile', None) profile = getattr(self.request.user, 'profile', None)
role = profile.role if profile else ('admin' if self.request.user.is_superuser else 'operator') roles = get_user_roles(self.request.user)
role = primary_role(roles)
ctx['user_role'] = role ctx['user_role'] = role
ctx['user_roles'] = sorted(roles)
ship_loc = ( ship_loc = (
Location.objects.filter( Location.objects.filter(
@@ -3975,8 +3977,20 @@ class WarehouseStocksView(LoginRequiredMixin, TemplateView):
ctx['selected_kind'] = kind ctx['selected_kind'] = kind
ctx['q'] = q ctx['q'] = q
ctx['can_transfer'] = role in ['admin', 'technologist', 'master', 'clerk'] ctx['can_transfer'] = has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director'])
ctx['can_receive'] = role in ['admin', 'technologist', 'master', 'clerk'] ctx['can_receive'] = has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director'])
allowed_transfer_locations = None
if role == 'master' and not has_any_role(roles, ['admin', 'technologist', 'clerk', 'prod_head', 'director']):
allowed_ws_ids = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else []
if not allowed_ws_ids and profile:
user_machine_ids = list(profile.machines.values_list('id', flat=True))
allowed_ws_ids = list(Machine.objects.filter(id__in=user_machine_ids).exclude(workshop_id__isnull=True).values_list('workshop_id', flat=True))
allowed_loc_ids = list(Workshop.objects.filter(id__in=allowed_ws_ids).exclude(location_id__isnull=True).values_list('location_id', flat=True))
if allowed_loc_ids:
allowed_transfer_locations = list(Location.objects.filter(id__in=allowed_loc_ids).order_by('name'))
ctx['transfer_locations'] = allowed_transfer_locations if allowed_transfer_locations is not None else locations
ctx['materials'] = Material.objects.select_related('category').all().order_by('full_name') ctx['materials'] = Material.objects.select_related('category').all().order_by('full_name')
ctx['entities'] = ProductEntity.objects.all().order_by('drawing_number', 'name') ctx['entities'] = ProductEntity.objects.all().order_by('drawing_number', 'name')
@@ -3991,8 +4005,9 @@ class WarehouseStocksView(LoginRequiredMixin, TemplateView):
class WarehouseTransferCreateView(LoginRequiredMixin, View): class WarehouseTransferCreateView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) profile = getattr(request.user, 'profile', None)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') roles = get_user_roles(request.user)
if role not in ['admin', 'technologist', 'master', 'clerk']: role = primary_role(roles)
if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']):
return JsonResponse({'error': 'forbidden'}, status=403) return JsonResponse({'error': 'forbidden'}, status=403)
stock_item_id = (request.POST.get('stock_item_id') or '').strip() stock_item_id = (request.POST.get('stock_item_id') or '').strip()
@@ -4021,6 +4036,17 @@ class WarehouseTransferCreateView(LoginRequiredMixin, View):
messages.error(request, 'Склад назначения должен отличаться от склада-источника.') messages.error(request, 'Склад назначения должен отличаться от склада-источника.')
return redirect(next_url) return redirect(next_url)
if role == 'master' and not has_any_role(roles, ['admin', 'technologist', 'clerk', 'prod_head', 'director']):
allowed_ws_ids = list(profile.allowed_workshops.values_list('id', flat=True)) if profile else []
if not allowed_ws_ids and profile:
user_machine_ids = list(profile.machines.values_list('id', flat=True))
allowed_ws_ids = list(Machine.objects.filter(id__in=user_machine_ids).exclude(workshop_id__isnull=True).values_list('workshop_id', flat=True))
allowed_loc_ids = list(Workshop.objects.filter(id__in=allowed_ws_ids).exclude(location_id__isnull=True).values_list('location_id', flat=True))
if not allowed_loc_ids or int(to_location_id) not in {int(x) for x in allowed_loc_ids}:
messages.error(request, 'Мастер может перемещать только на склад своего цеха.')
return redirect(next_url)
tr = TransferRecord.objects.create( tr = TransferRecord.objects.create(
from_location_id=si.location_id, from_location_id=si.location_id,
to_location_id=int(to_location_id), to_location_id=int(to_location_id),
@@ -4044,9 +4070,8 @@ class WarehouseTransferCreateView(LoginRequiredMixin, View):
class WarehouseReceiptCreateView(LoginRequiredMixin, View): class WarehouseReceiptCreateView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
profile = getattr(request.user, 'profile', None) roles = get_user_roles(request.user)
role = profile.role if profile else ('admin' if request.user.is_superuser else 'operator') if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']):
if role not in ['admin', 'technologist', 'master', 'clerk']:
return JsonResponse({'error': 'forbidden'}, status=403) return JsonResponse({'error': 'forbidden'}, status=403)
next_url = (request.POST.get('next') or '').strip() next_url = (request.POST.get('next') or '').strip()