feat: 批次追踪链优化

This commit is contained in:
caoqianming 2025-07-03 13:58:31 +08:00
parent 89aca50f44
commit 17284dcf4f
2 changed files with 69 additions and 39 deletions

View File

@ -278,7 +278,7 @@ class InmService:
else:
for item in MIOItem.objects.filter(mio=instance):
BatchSt.g_create(
batch=item.batch, mio=instance, material_start=item.material, reuse_node=True)
batch=item.batch, mio=instance, material_start=item.material, check_mat_start=True)
from apps.pum.services import PumService
if is_reverse:
cls.update_mb(instance, -1)
@ -291,7 +291,7 @@ class InmService:
else:
for item in MIOItem.objects.filter(mio=instance):
BatchSt.g_create(
batch=item.batch, mio=instance, material_start=item.material, reuse_node=True)
batch=item.batch, mio=instance, material_start=item.material, check_mat_start=True)
if is_reverse:
cls.update_mb(instance, -1)
else:
@ -448,13 +448,16 @@ class InmService:
if mio.type == MIO.MIO_TYPE_PUR_IN:
from apps.pum.services import PumService
cls.update_mb_item(mioitem, -1)
BatchLog.clear(mioitem=mioitem)
PumService.mio_purin(mio=mio, is_reverse=True, mioitem=mioitem)
mioitem.delete()
elif mio.type == MIO.MIO_TYPE_OTHER_IN:
cls.update_mb_item(mioitem, -1)
BatchLog.clear(mioitem=mioitem)
mioitem.delete()
elif mio.type == MIO.MIO_TYPE_DO_OUT:
do_in(mioitem)
BatchLog.clear(mioitem=mioitem)
mioitem.delete()
else:
raise ParseError("不支持该出入库单明细撤销")

View File

@ -14,6 +14,7 @@ from django.db.models import Count
from django.db import transaction
from django.db.models import Max
import re
from django.db.models import Q
# Create your models here.
class SfLog(CommonADModel):
@ -655,45 +656,57 @@ class BatchSt(BaseModel):
unique_together = [("batch", "version")]
@classmethod
def g_create(cls, batch:str, mio=None, mioitem=None, handover=None, mlog=None, material_start=None, reuse_node=False, exclude_batchst_ids=[]):
def g_create(cls, batch:str, mio=None, mioitem=None, handover=None, mlog=None, material_start=None, check_mat_start=False, exclude_batchst_ids=[]):
"""
创建新的批次
"""
if mioitem:
mio = mioitem.mio
if mio is None and handover is None and mlog is None:
try:
node = cls.objects.exclude(id__in=exclude_batchst_ids).get(batch=batch)
except cls.DoesNotExist:
return cls.objects.create(batch=batch), True
except cls.MultipleObjectsReturned:
# 兼容性处理
node = cls.objects.filter(batch=batch).exclude(id__in=exclude_batchst_ids).order_by('-version').first()
if node is None:
raise ParseError(f"{node.batch}-该批次号本次操作不可引用")
try:
node = cls.objects.get(batch=batch, version=1)
if check_mat_start:
if node.material_start is None:
node.material_start = material_start
node.save(update_fields = ["material_start"])
if node.material_start != material_start:
raise ParseError(f"{batch}-该批次号因物料不同不可引用")
return node, False
else:
version = 1
if mio is None and handover is None and mlog is None:
raise ParseError("mio or handover or mlog must be provided")
# 带有来源的批次获取,需检查批次号是否可用
cls_qs = cls.objects.filter(batch=batch)
if cls_qs.exists():
if reuse_node:
node:BatchSt = (cls_qs.filter(mio__isnull=False)|cls_qs.filter(handover=None, mio=None, mlog=None)).order_by('-version').first()
if node is None:
raise ParseError(f"{batch}-该批次号因物料不同不可引用")
elif node.material_start is None:
node.material_start = material_start
node.save(update_fields = ["material_start"])
# elif node.material_start is not None and node.material_start != material_start:
# raise ParseError(f"{batch}-该批次号因物料不同不可引用-{str(node.material_start)} vs {str(material_start)}")
return node, False
else:
latest_version = BatchSt.objects.filter(batch=batch).aggregate(Max("version"))["version__max"]
version = latest_version + 1
ins = cls.objects.create(batch=batch, mio=mio, mioitem=mioitem, handover=handover, mlog=mlog, material_start=material_start, version=version)
return ins, True
except cls.DoesNotExist:
return cls.objects.create(batch=batch, mio=mio, mioitem=mioitem, handover=handover, mlog=mlog, material_start=material_start, version=1), True
# if mio is None and handover is None and mlog is None:
# try:
# node = cls.objects.exclude(id__in=exclude_batchst_ids).get(batch=batch)
# except cls.DoesNotExist:
# return cls.objects.create(batch=batch), True
# except cls.MultipleObjectsReturned:
# # 兼容性处理
# node = cls.objects.filter(batch=batch).exclude(id__in=exclude_batchst_ids).order_by('-version').first()
# if node is None:
# raise ParseError(f"{node.batch}-该批次号本次操作不可引用")
# return node, False
# else:
# version = 1
# if mio is None and handover is None and mlog is None:
# raise ParseError("mio or handover or mlog must be provided")
# # 带有来源的批次获取,需检查批次号是否可用
# cls_qs = cls.objects.filter(batch=batch)
# if cls_qs.exists():
# if reuse_node:
# node:BatchSt = (cls_qs.filter(mio__isnull=False)|cls_qs.filter(handover=None, mio=None, mlog=None)).order_by('-version').first()
# if node is None:
# raise ParseError(f"{batch}-该批次号因物料不同不可引用")
# elif node.material_start is None:
# node.material_start = material_start
# node.save(update_fields = ["material_start"])
# # elif node.material_start is not None and node.material_start != material_start:
# # raise ParseError(f"{batch}-该批次号因物料不同不可引用-{str(node.material_start)} vs {str(material_start)}")
# return node, False
# else:
# latest_version = BatchSt.objects.filter(batch=batch).aggregate(Max("version"))["version__max"]
# version = latest_version + 1
# ins = cls.objects.create(batch=batch, mio=mio, mioitem=mioitem, handover=handover, mlog=mlog, material_start=material_start, version=version)
# return ins, True
@classmethod
@transaction.atomic
@ -738,11 +751,25 @@ class BatchLog(BaseModel):
@classmethod
def clear(cls, handover=None, mlog=None, mio=None, mioitem=None):
if handover:
cls.objects.filter(handover=handover).delete()
BatchSt.objects.filter(handover=handover).delete()
logs = cls.objects.filter(handover=handover)
for log in logs:
source = log.source
target = log.target
log.delete()
if not BatchLog.objects.filter(Q(source=source) | Q(target=source)).exists():
source.delete()
if not BatchLog.objects.filter(Q(source=target) | Q(target=target)).exists():
target.delete()
if mlog:
cls.objects.filter(mlog=mlog).delete()
BatchSt.objects.filter(mlog=mlog).delete()
logs = cls.objects.filter(mlog=mlog)
for log in logs:
source = log.source
target = log.target
log.delete()
if not BatchLog.objects.filter(Q(source=source) | Q(target=source)).exists():
source.delete()
if not BatchLog.objects.filter(Q(source=target) | Q(target=target)).exists():
target.delete()
if mio:
BatchSt.objects.filter(mio=mio).delete()
if mioitem: