Конкретно пересмотрел логику работы. Легаси вынесена в архив
All checks were successful
Deploy MES Core / deploy (push) Successful in 13s

This commit is contained in:
2026-04-13 07:36:57 +03:00
parent 86215c9fa8
commit 28537447f8
80 changed files with 10246 additions and 684 deletions

View File

@@ -1,4 +1,5 @@
from django.db import transaction
from django.db.models import F
from django.utils import timezone
import logging
@@ -130,3 +131,92 @@ def apply_closing(
)
logger.info('apply_closing:done report=%s', report.id)
@transaction.atomic
def apply_closing_workitems(
*,
user_id: int,
machine_id: int,
material_id: int,
item_actions: dict[int, dict], # workitem_id -> {'action': 'done'|'partial', 'fact': int}
consumptions: dict[int, float],
remnants: list[dict],
) -> None:
logger.info('apply_closing_workitems:start user=%s machine=%s material=%s workitems=%s cons=%s rem=%s', user_id, machine_id, material_id, list(item_actions.keys()), list(consumptions.keys()), len(remnants))
from shiftflow.models import WorkItem, ProductionTask
wis = list(
WorkItem.objects.select_for_update(of=("self",))
.select_related('deal', 'entity', 'machine')
.filter(id__in=list(item_actions.keys()), machine_id=machine_id, status__in=['planned'], entity__planned_material_id=material_id)
.filter(quantity_done__lt=F('quantity_plan'))
)
if not wis:
raise RuntimeError('Не найдено сменных заданий для закрытия.')
report = CuttingSession.objects.create(
operator_id=user_id,
machine_id=machine_id,
used_stock_item=None,
date=timezone.localdate(),
is_closed=False,
)
created_shift = 0
for wi in wis:
spec = item_actions.get(wi.id) or {}
action = (spec.get('action') or '').strip()
fact = int(spec.get('fact') or 0)
if action not in ['done', 'partial']:
continue
plan_total = int(wi.quantity_plan or 0)
done_total = int(wi.quantity_done or 0)
remaining = max(0, plan_total - done_total)
if remaining <= 0:
continue
if action == 'done':
fact = remaining
else:
fact = max(0, min(fact, remaining))
if fact <= 0:
raise RuntimeError('При частичном закрытии факт должен быть больше 0.')
pt = ProductionTask.objects.filter(deal_id=wi.deal_id, entity_id=wi.entity_id).first()
if not pt:
raise RuntimeError('Не найден ProductionTask для задания.')
ShiftItem.objects.create(session=report, task=pt, quantity_fact=fact)
created_shift += 1
wi.quantity_done = done_total + fact
if wi.quantity_done >= plan_total:
wi.status = 'done'
elif wi.quantity_done > 0:
wi.status = 'leftover'
else:
wi.status = 'planned'
wi.save(update_fields=['quantity_done', 'status'])
for stock_item_id, qty in consumptions.items():
if qty and float(qty) > 0:
ProductionReportConsumption.objects.create(report=report, stock_item_id=stock_item_id, material_id=None, quantity=float(qty))
for r in remnants:
qty = float(r.get('quantity') or 0)
if qty <= 0:
continue
ProductionReportRemnant.objects.create(
report=report,
material_id=material_id,
quantity=qty,
current_length=r.get('current_length'),
current_width=r.get('current_width'),
unique_id=None,
)
close_cutting_session(report.id)
logger.info('apply_closing_workitems:done report=%s shift_items=%s', report.id, created_shift)