Добавил редактирование материалла на странице склада
All checks were successful
Deploy MES Core / deploy (push) Successful in 12s
All checks were successful
Deploy MES Core / deploy (push) Successful in 12s
This commit is contained in:
@@ -4442,6 +4442,184 @@ class WarehouseStocksView(LoginRequiredMixin, TemplateView):
|
||||
return ctx
|
||||
|
||||
|
||||
class WarehouseStockItemUpdateView(LoginRequiredMixin, View):
|
||||
def post(self, request, *args, **kwargs):
|
||||
profile = getattr(request.user, 'profile', None)
|
||||
roles = get_user_roles(request.user)
|
||||
role = primary_role(roles)
|
||||
if not has_any_role(roles, ['admin', 'technologist', 'master', 'clerk', 'prod_head', 'director']):
|
||||
return JsonResponse({'error': 'forbidden'}, status=403)
|
||||
|
||||
next_url = (request.POST.get('next') or '').strip()
|
||||
if not next_url.startswith('/'):
|
||||
next_url = reverse_lazy('warehouse_stocks')
|
||||
|
||||
stock_item_id = (request.POST.get('stock_item_id') or '').strip()
|
||||
if not stock_item_id.isdigit():
|
||||
messages.error(request, 'Не выбрана складская позиция.')
|
||||
return redirect(next_url)
|
||||
|
||||
qty_raw = (request.POST.get('quantity') or '').strip().replace(',', '.')
|
||||
len_raw = (request.POST.get('current_length') or '').strip().replace(',', '.')
|
||||
wid_raw = (request.POST.get('current_width') or '').strip().replace(',', '.')
|
||||
deal_id_raw = (request.POST.get('deal_id') or '').strip()
|
||||
unique_id_raw = (request.POST.get('unique_id') or '').strip()
|
||||
material_id_raw = (request.POST.get('material_id') or '').strip()
|
||||
location_id_raw = (request.POST.get('location_id') or '').strip()
|
||||
|
||||
try:
|
||||
qty = float(qty_raw)
|
||||
except ValueError:
|
||||
qty = 0.0
|
||||
if qty <= 0:
|
||||
messages.error(request, 'Количество должно быть больше 0.')
|
||||
return redirect(next_url)
|
||||
|
||||
def parse_float_opt(s: str):
|
||||
s = (s or '').strip().replace(',', '.')
|
||||
if not s:
|
||||
return None
|
||||
try:
|
||||
return float(s)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
cur_len = parse_float_opt(len_raw)
|
||||
cur_wid = parse_float_opt(wid_raw)
|
||||
|
||||
is_remnant = bool(request.POST.get('is_remnant'))
|
||||
is_customer_supplied = bool(request.POST.get('is_customer_supplied'))
|
||||
|
||||
deal_id = None
|
||||
if deal_id_raw.isdigit():
|
||||
deal_id = int(deal_id_raw)
|
||||
|
||||
material_id = None
|
||||
if material_id_raw.isdigit():
|
||||
material_id = int(material_id_raw)
|
||||
|
||||
location_id = None
|
||||
if location_id_raw.isdigit():
|
||||
location_id = int(location_id_raw)
|
||||
|
||||
unique_id = unique_id_raw or None
|
||||
|
||||
with transaction.atomic():
|
||||
si = (
|
||||
StockItem.objects.select_for_update(of=('self',))
|
||||
.select_related('material', 'material__category', 'location', 'deal')
|
||||
.filter(id=int(stock_item_id), is_archived=False)
|
||||
.first()
|
||||
)
|
||||
if not si:
|
||||
messages.error(request, 'Складская позиция не найдена.')
|
||||
return redirect(next_url)
|
||||
|
||||
if not getattr(si, 'material_id', None) or getattr(si, 'entity_id', None):
|
||||
messages.error(request, 'Редактирование доступно только для сырья/ДО.')
|
||||
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 allowed_loc_ids and int(si.location_id) not in {int(x) for x in allowed_loc_ids}:
|
||||
messages.error(request, 'Мастер может редактировать только позиции своего цеха.')
|
||||
return redirect(next_url)
|
||||
|
||||
ship_loc = (
|
||||
Location.objects.filter(
|
||||
Q(name__icontains='отгруж')
|
||||
| Q(name__icontains='Отгруж')
|
||||
| Q(name__icontains='отгруз')
|
||||
| Q(name__icontains='Отгруз')
|
||||
)
|
||||
.order_by('id')
|
||||
.first()
|
||||
)
|
||||
ship_loc_id = ship_loc.id if ship_loc else None
|
||||
|
||||
if deal_id is not None:
|
||||
ok = Deal.objects.filter(id=int(deal_id)).exists()
|
||||
if not ok:
|
||||
messages.error(request, 'Выбрана несуществующая сделка.')
|
||||
return redirect(next_url)
|
||||
|
||||
if material_id is None:
|
||||
messages.error(request, 'Выбери материал.')
|
||||
return redirect(next_url)
|
||||
mat = Material.objects.select_related('category').filter(id=int(material_id)).first()
|
||||
if not mat:
|
||||
messages.error(request, 'Материал не найден.')
|
||||
return redirect(next_url)
|
||||
|
||||
if location_id is None:
|
||||
messages.error(request, 'Выбери склад.')
|
||||
return redirect(next_url)
|
||||
loc = Location.objects.filter(id=int(location_id)).first()
|
||||
if not loc:
|
||||
messages.error(request, 'Склад не найден.')
|
||||
return redirect(next_url)
|
||||
if ship_loc_id and int(location_id) == int(ship_loc_id):
|
||||
messages.error(request, 'Перенос на склад отгрузки выполняется через отгрузку/перемещение.')
|
||||
return redirect(next_url)
|
||||
|
||||
ff = (getattr(getattr(mat, 'category', None), 'form_factor', '') or '').strip().lower()
|
||||
|
||||
if ff == 'sheet':
|
||||
if cur_len is None or cur_wid is None:
|
||||
messages.error(request, 'Для листового материала нужно заполнить длину и ширину (мм).')
|
||||
return redirect(next_url)
|
||||
elif ff == 'bar':
|
||||
if cur_len is None:
|
||||
messages.error(request, 'Для проката нужно заполнить длину (мм).')
|
||||
return redirect(next_url)
|
||||
cur_wid = None
|
||||
|
||||
if unique_id:
|
||||
exists = StockItem.objects.filter(unique_id=unique_id).exclude(id=int(si.id)).exists()
|
||||
if exists:
|
||||
messages.error(request, 'Маркировка (ID) уже используется в другой позиции.')
|
||||
return redirect(next_url)
|
||||
|
||||
si.quantity = float(qty)
|
||||
si.current_length = cur_len
|
||||
si.current_width = cur_wid
|
||||
si.deal_id = deal_id
|
||||
si.unique_id = unique_id
|
||||
si.is_remnant = bool(is_remnant)
|
||||
si.is_customer_supplied = bool(is_customer_supplied)
|
||||
si.material_id = int(material_id)
|
||||
si.location_id = int(location_id)
|
||||
si.save(
|
||||
update_fields=[
|
||||
'quantity',
|
||||
'current_length',
|
||||
'current_width',
|
||||
'deal',
|
||||
'unique_id',
|
||||
'is_remnant',
|
||||
'is_customer_supplied',
|
||||
'material',
|
||||
'location',
|
||||
]
|
||||
)
|
||||
|
||||
messages.success(request, 'Позиция обновлена.')
|
||||
return redirect(next_url)
|
||||
|
||||
|
||||
class WarehouseTransferCreateView(LoginRequiredMixin, View):
|
||||
def post(self, request, *args, **kwargs):
|
||||
profile = getattr(request.user, 'profile', None)
|
||||
|
||||
Reference in New Issue
Block a user