This commit is contained in:
TianyangZhang 2026-01-04 14:16:43 +08:00
commit db910f0804
14 changed files with 320 additions and 70 deletions

View File

@ -12,6 +12,9 @@ class AssetCateSerializer(CustomModelSerializer):
read_only_fields = EXCLUDE_FIELDS read_only_fields = EXCLUDE_FIELDS
class AssetSerializer(CustomModelSerializer): class AssetSerializer(CustomModelSerializer):
keep_dept_name = serializers.CharField(source="keep_dept.name", read_only=True)
keeper_name = serializers.CharField(source="keeper.name", read_only=True)
cate_name = serializers.CharField(source="cate.name", read_only=True)
class Meta: class Meta:
model = Asset model = Asset
fields = '__all__' fields = '__all__'

View File

@ -60,5 +60,12 @@ class AssetLogViewSet(TicketMixin, CustomModelViewSet):
def gen_other_ticket_data(self, instance:AssetLog): def gen_other_ticket_data(self, instance:AssetLog):
return {"keep_dept_name": instance.keep_dept.name} return {"keep_dept_name": instance.keep_dept.name}
@staticmethod
def apply(ticket: Ticket, transition, new_ticket_data: dict):
assetlog:AssetLog = ticket.assetlog_ticket
items = assetlog.items
sr = AssetSerializer(data=items, many=True)
sr.is_valid(raise_exception=True)
sr.save(create_by=ticket.create_by)

View File

@ -401,6 +401,9 @@ class ResignationViewSet(TicketMixin, EuModelViewSet):
search_fields = ["employee__name"] search_fields = ["employee__name"]
workflow_key = "wf_resignation" workflow_key = "wf_resignation"
def gen_other_ticket_data(self, instance):
return {"employee_name": instance.employee.name}
@staticmethod @staticmethod
def update_handle_date(ticket: Ticket, transition, new_ticket_data: dict): def update_handle_date(ticket: Ticket, transition, new_ticket_data: dict):
handle_date = new_ticket_data.get("handle_date", None) handle_date = new_ticket_data.get("handle_date", None)

View File

@ -247,6 +247,15 @@ class MIOItemAListSerializer(CustomModelSerializer):
read_only_fields = EXCLUDE_FIELDS_BASE read_only_fields = EXCLUDE_FIELDS_BASE
class MIOItemListSimpleSerializer(CustomModelSerializer):
warehouse_name = serializers.CharField(source='warehouse.name', read_only=True)
material_name = serializers.StringRelatedField(
source='material', read_only=True)
class Meta:
model = MIOItem
fields = ["id", "mio", "material", "warehouse", "material_name", "warehouse_name", "batch", "count", "test_date", "count_notok"]
class MIOItemSerializer(CustomModelSerializer): class MIOItemSerializer(CustomModelSerializer):
warehouse_name = serializers.CharField(source='warehouse.name', read_only=True) warehouse_name = serializers.CharField(source='warehouse.name', read_only=True)
material_ = MaterialSerializer(source='material', read_only=True) material_ = MaterialSerializer(source='material', read_only=True)

View File

@ -14,7 +14,7 @@ from apps.inm.serializers import (
MaterialBatchSerializer, WareHourseSerializer, MIOListSerializer, MIOItemSerializer, MioItemAnaSerializer, MaterialBatchSerializer, WareHourseSerializer, MIOListSerializer, MIOItemSerializer, MioItemAnaSerializer,
MIODoSerializer, MIOSaleSerializer, MIOPurSerializer, MIOOtherSerializer, MIOItemCreateSerializer, MIODoSerializer, MIOSaleSerializer, MIOPurSerializer, MIOOtherSerializer, MIOItemCreateSerializer,
MaterialBatchDetailSerializer, MIODetailSerializer, MIOItemTestSerializer, MIOItemPurInTestSerializer, MaterialBatchDetailSerializer, MIODetailSerializer, MIOItemTestSerializer, MIOItemPurInTestSerializer,
MIOItemwSerializer, MioItemDetailSerializer, PackSerializer, PackMioSerializer) MIOItemwSerializer, MioItemDetailSerializer, PackSerializer, PackMioSerializer, MIOItemListSimpleSerializer)
from apps.inm.serializers2 import MIOItemwCreateUpdateSerializer from apps.inm.serializers2 import MIOItemwCreateUpdateSerializer
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from apps.inm.services import InmService from apps.inm.services import InmService
@ -163,20 +163,39 @@ class MIOViewSet(CustomModelViewSet):
return mio return mio
def add_info_for_list(self, data): def add_info_for_list(self, data):
# 获取检验状态 # 1. 收集所有mio的ID
mio_dict = {} mio_ids = [item['id'] for item in data]
# 2. 预初始化mio字典和items列表
mio_dict = {item['id']: {
**item,
'is_tested': False, # 默认值设为False
'mioitems': []
} for item in data}
# 3. 批量查询MIOItem数据
if mio_ids: # 避免空查询
mioitems = MIOItemListSimpleSerializer(
instance=MIOItem.objects.filter(
mio__id__in=mio_ids
).select_related("warehouse", "material"),
many=True
).data
# 4. 单次循环处理所有item
for item in mioitems:
mio_id = item['mio']
if mio_id in mio_dict:
mio_dict[mio_id]['mioitems'].append(item)
# 更新is_tested状态只要有一个item有test_date就为True
if item.get('test_date'):
mio_dict[mio_id]['is_tested'] = True
# 5. 直接返回原始data列表避免额外转换
for item in data: for item in data:
item['is_tested'] = None item.update(mio_dict[item['id']])
mio_dict[item['id']] = item
mioitems = list(MIOItem.objects.filter(mio__id__in=mio_dict.keys()).values_list("mio__id", "test_date")) return data
for item in mioitems:
mioId, test_date = item
is_tested = False
if test_date:
is_tested = True
mio_dict[mioId]['is_tested'] = is_tested
datax = [mio_dict[key] for key in mio_dict.keys()]
return datax
def get_serializer_class(self): def get_serializer_class(self):
if self.action in ['create', 'update', 'partial_update']: if self.action in ['create', 'update', 'partial_update']:

View File

@ -157,6 +157,43 @@ def ftestwork_submit(ins:FtestWork, user: User):
# 触发批次统计分析 # 触发批次统计分析
ana_batch_thread(xbatchs=[ins.batch]) ana_batch_thread(xbatchs=[ins.batch])
def ftestwork_revert(ins: FtestWork):
wm:WMaterial = ins.wm
if wm and ins.need_update_wm:
fwd_qs = FtestworkDefect.objects.filter(ftestwork=ins)
for item in fwd_qs:
item:FtestworkDefect = item
if item.count > 0:
wm.count = wm.count + item.count
wm.save()
wmstate = WMaterial.WM_OK
if item.defect.okcate == Defect.DEFECT_NOTOK:
wmstate = WMaterial.WM_NOTOK
try:
wmx = WMaterial.objects.get(
material=wm.material,
batch=wm.batch,
mgroup=wm.mgroup,
belong_dept=wm.belong_dept,
state=wmstate,
notok_sign=None,
defect=item.defect,
)
except Exception as e:
raise ParseError(f'找不到{item.defect.name}的车间库存: {str(e)}')
wmx.count = wmx.count - item.count
if wmx.count < 0:
raise ParseError("数量不足,撤回失败")
wmx.save()
else:
raise ParseError("该检验工作不支持撤回")
ins.submit_user = None
ins.submit_time = None
ins.save()
# 触发批次统计分析
ana_batch_thread(xbatchs=[ins.batch])
def bind_ftestwork(ticket: Ticket, transition, new_ticket_data: dict): def bind_ftestwork(ticket: Ticket, transition, new_ticket_data: dict):
ins = FtestWork.objects.get(id=new_ticket_data['t_id']) ins = FtestWork.objects.get(id=new_ticket_data['t_id'])
if ins.submit_time is not None: if ins.submit_time is not None:

View File

@ -17,7 +17,7 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from apps.wpm.models import SfLog from apps.wpm.models import SfLog
from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter, QctFilter, FtestFilter from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter, QctFilter, FtestFilter
from django.db import transaction from django.db import transaction
from apps.qm.services import ftestwork_submit from apps.qm.services import ftestwork_submit, ftestwork_revert
from apps.wpm.services_2 import ana_batch_thread from apps.wpm.services_2 import ana_batch_thread
from apps.wf.models import State from apps.wf.models import State
# Create your views here. # Create your views here.
@ -327,4 +327,20 @@ class FtestWorkViewSet(CustomModelViewSet):
ftestwork_submit(ins, request.user) ftestwork_submit(ins, request.user)
else: else:
raise ParseError('该检验工作已提交') raise ParseError('该检验工作已提交')
return Response()
@action(methods=['post'], detail=True, perms_map={'post': 'ftestwork.submit'}, serializer_class=Serializer)
@transaction.atomic
def revert(self, request, *args, **kwargs):
"""撤回检验工作
撤回检验工作
"""
ins:FtestWork = self.get_object()
if ins.submit_time:
if self.request.user != ins.submit_user:
raise ParseError('只能由提交人撤回')
ftestwork_revert(ins)
else:
raise ParseError('该检验工作未提交')
return Response() return Response()

View File

@ -45,5 +45,6 @@ class DeptFilterSet(filters.FilterSet):
model = Dept model = Dept
fields = { fields = {
'type': ['exact', 'in'], 'type': ['exact', 'in'],
'name': ['exact', 'in', 'contains'] 'name': ['exact', 'in', 'contains'],
"parent": ['exact', 'isnull'],
} }

View File

@ -1049,6 +1049,11 @@ class MlogbwStartTestSerializer(serializers.Serializer):
test_equip=test_equip test_equip=test_equip
) )
class MlogbOutPatchUpdateSerializer(CustomModelSerializer):
class Meta:
model = Mlogb
fields = ["batch"]
class MlogbOutUpdateSerializer(CustomModelSerializer): class MlogbOutUpdateSerializer(CustomModelSerializer):
mlogbdefect = MlogbDefectSerializer(many=True, required=False) mlogbdefect = MlogbDefectSerializer(many=True, required=False)
count_json = CountJsonSerializer(required=False, many=True) count_json = CountJsonSerializer(required=False, many=True)

View File

@ -172,13 +172,15 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
mgroup = mlog.mgroup mgroup = mlog.mgroup
process = mgroup.process process = mgroup.process
into_wm_mgroup = process.into_wm_mgroup stored_mgroup = process.into_wm_mgroup
need_store_notok = process.store_notok stored_notok = process.store_notok
belong_dept = mgroup.belong_dept belong_dept = mgroup.belong_dept
material_out: Material = mlog.material_out material_out: Material = mlog.material_out
material_in: Material = mlog.material_in material_in: Material = mlog.material_in
supplier = mlog.supplier # 外协 supplier = mlog.supplier # 外协
is_fix = mlog.is_fix is_fix = mlog.is_fix
if is_fix: # 如果是返工,直接放到工段下
stored_mgroup = True
m_ins_list = [] m_ins_list = []
m_ins_bl_list = [] m_ins_bl_list = []
@ -252,7 +254,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
Wpr.change_or_new(wpr=item.wpr, old_wm=wm, ftest=item.ftest) Wpr.change_or_new(wpr=item.wpr, old_wm=wm, ftest=item.ftest)
# 针对加工前不良的暂时额外处理 # 针对加工前不良的暂时额外处理
if need_store_notok: if stored_notok:
for item in m_ins_bl_list: for item in m_ins_bl_list:
material, batch, count, defect, mi_ = item material, batch, count, defect, mi_ = item
if count <= 0: if count <= 0:
@ -275,12 +277,10 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
stored_mgroup = into_wm_mgroup
stored_notok = need_store_notok
if mlogb_out_qs.exists(): if mlogb_out_qs.exists():
mlogb_out_qs = mlogb_out_qs.filter(need_inout=True) mlogb_out_qs = mlogb_out_qs.filter(need_inout=True)
m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok_full if mo.count_ok_full is not None else mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()] m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok_full if mo.count_ok_full is not None else mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()]
if need_store_notok: if stored_notok:
for item in mlogb_out_qs: for item in mlogb_out_qs:
mbd_qs = MlogbDefect.get_defect_qs_from_mlogb(item) mbd_qs = MlogbDefect.get_defect_qs_from_mlogb(item)
if item.qct is not None or mbd_qs.exists(): if item.qct is not None or mbd_qs.exists():
@ -309,7 +309,6 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if 'count_n_' in f.name and getattr(item, f.name) > 0: if 'count_n_' in f.name and getattr(item, f.name) > 0:
notok_sign = f.name.replace('count_n_', '') notok_sign = f.name.replace('count_n_', '')
m_outs_list.append( (item.material_out, item.batch if item.batch else mlog.batch, getattr(item, f.name), mlog.count_real_eweight, notok_sign, item)) m_outs_list.append( (item.material_out, item.batch if item.batch else mlog.batch, getattr(item, f.name), mlog.count_real_eweight, notok_sign, item))
stored_notok = True
# 这里有一个漏洞在产出物为兄弟件的情况下不合格品的数量是记录在mlog上的 # 这里有一个漏洞在产出物为兄弟件的情况下不合格品的数量是记录在mlog上的
# 而不是mlogb上以上的额外处理就没有效果了, 不过光子不记录不合格品 # 而不是mlogb上以上的额外处理就没有效果了, 不过光子不记录不合格品
else: else:
@ -339,7 +338,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
lookup['defect'] = notok_sign_or_defect lookup['defect'] = notok_sign_or_defect
elif notok_sign_or_defect is not None: elif notok_sign_or_defect is not None:
lookup['notok_sign'] = notok_sign_or_defect lookup['notok_sign'] = notok_sign_or_defect
if into_wm_mgroup: if stored_mgroup:
lookup['mgroup'] = mgroup lookup['mgroup'] = mgroup
else: else:
lookup['belong_dept'] = belong_dept lookup['belong_dept'] = belong_dept
@ -529,7 +528,6 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
# 再生成消耗 # 再生成消耗
m_ins_list = [] m_ins_list = []
m_ins_bl_list = [] m_ins_bl_list = []
into_wm_mgroup = process.into_wm_mgroup
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False) m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
if m_ins.exists(): if m_ins.exists():
m_ins = m_ins.filter(need_inout=True) m_ins = m_ins.filter(need_inout=True)
@ -553,7 +551,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
else: else:
# 针对光子的情况实际上必须需要wm_in # 针对光子的情况实际上必须需要wm_in
lookup = {'batch': mi_batch, 'material': mi_ma, 'mgroup': None, 'state': WMaterial.WM_OK} lookup = {'batch': mi_batch, 'material': mi_ma, 'mgroup': None, 'state': WMaterial.WM_OK}
if into_wm_mgroup: if stored_mgroup:
# 退回到本工段 # 退回到本工段
lookup['mgroup'] = mgroup lookup['mgroup'] = mgroup
else: else:
@ -785,7 +783,7 @@ def handover_submit(handover:Handover, user: User, now: Union[datetime.datetime,
if handover.type == Handover.H_NORMAL: if handover.type == Handover.H_NORMAL:
if mtype == Handover.H_MERGE and handover.new_wm: if mtype == Handover.H_MERGE and handover.new_wm:
wm_to = handover.new_wm wm_to = handover.new_wm
if wm_to.state != WMaterial.WM_OK or wm_to.material != wm_from.material or wm_to.defect != wm_from.defect: if wm_to.state != wm_from.state or wm_to.material != wm_from.material or wm_to.defect != wm_from.defect:
raise ParseError("正常合并到的车间库存状态或物料异常") raise ParseError("正常合并到的车间库存状态或物料异常")
else: else:
wm_to, _ = WMaterial.objects.get_or_create( wm_to, _ = WMaterial.objects.get_or_create(
@ -952,7 +950,7 @@ def handover_revert(handover:Handover, handler:User=None):
ticket:Ticket = handover.ticket ticket:Ticket = handover.ticket
if ticket: if ticket:
# 首先把ticket改回开始状态 # 首先把ticket改回开始状态
WfService.retreat(ticket=ticket, suggestion="交接单", handler=handler, next_handler=handover.create_by) WfService.retreat(ticket=ticket, suggestion="交接单", handler=handler, next_handler=handover.create_by)
mids = [] mids = []
# handover_type = handover.type # handover_type = handover.type
# handover_mtype = handover.mtype # handover_mtype = handover.mtype
@ -973,7 +971,7 @@ def handover_revert(handover:Handover, handler:User=None):
wm = item.wm wm = item.wm
wm_to = item.wm_to wm_to = item.wm_to
if wm is None or wm_to is None: if wm is None or wm_to is None:
raise ParseError('该交接单不支持撤2!') raise ParseError('该交接单不支持撤2!')
if wm == wm_to: if wm == wm_to:
# 此时是自己交给自己,不需要做任何操作 # 此时是自己交给自己,不需要做任何操作
pass pass
@ -1064,6 +1062,7 @@ def get_batch_dag(batch_number: str, method="full"):
} }
if method == "full": if method == "full":
raise ParseError("不支持获取全局关系链条")
# 完整DAG模式 - 收集所有相关批次和边(原逻辑) # 完整DAG模式 - 收集所有相关批次和边(原逻辑)
nodes_set = {batch_ins.id} nodes_set = {batch_ins.id}
edges = [] edges = []
@ -1120,33 +1119,33 @@ def get_batch_dag(batch_number: str, method="full"):
}) })
# 查询作为source的其他关系 # 查询作为source的其他关系
leftLogs = BatchLog.objects.filter(source_id__in=left_source_ids).exclude(id__in=exist_log_ids) # leftLogs = BatchLog.objects.filter(source_id__in=left_source_ids).exclude(id__in=exist_log_ids)
for log in leftLogs: # for log in leftLogs:
source = log.source.id # source = log.source.id
target = log.target.id # target = log.target.id
nodes_set.add(log.target.id) # nodes_set.add(log.target.id)
edges.append({ # edges.append({
'id': log.id, # 'id': log.id,
'source': source, # 'source': source,
'target': target, # 'target': target,
"handover": log.handover.id if log.handover else None, # "handover": log.handover.id if log.handover else None,
"mlog": log.mlog.id if log.mlog else None, # "mlog": log.mlog.id if log.mlog else None,
'label': r_dict.get(log.relation_type, ""), # 'label': r_dict.get(log.relation_type, ""),
}) # })
rightLogs = BatchLog.objects.filter(target_id__in=right_target_ids).exclude(id__in=exist_log_ids) # rightLogs = BatchLog.objects.filter(target_id__in=right_target_ids).exclude(id__in=exist_log_ids)
for log in rightLogs: # for log in rightLogs:
source = log.source.id # source = log.source.id
target = log.target.id # target = log.target.id
nodes_set.add(log.source.id) # nodes_set.add(log.source.id)
edges.append({ # edges.append({
'id': log.id, # 'id': log.id,
'source': source, # 'source': source,
'target': target, # 'target': target,
"handover": log.handover.id if log.handover else None, # "handover": log.handover.id if log.handover else None,
"mlog": log.mlog.id if log.mlog else None, # "mlog": log.mlog.id if log.mlog else None,
'label': r_dict.get(log.relation_type, ""), # 'label': r_dict.get(log.relation_type, ""),
}) # })
else: else:
raise ParseError("不支持的查询方法,请使用'full''direct'") raise ParseError("不支持的查询方法,请使用'full''direct'")

View File

@ -50,7 +50,8 @@ from .serializers import (
MlogQuickSerializer, MlogQuickSerializer,
MlogbwStartTestSerializer, MlogbwStartTestSerializer,
HandoverListSerializer, HandoverListSerializer,
BatchChangeSerializer BatchChangeSerializer,
MlogbOutPatchUpdateSerializer
) )
from .services import mlog_submit, handover_submit, mlog_revert, get_batch_dag, handover_revert from .services import mlog_submit, handover_submit, mlog_revert, get_batch_dag, handover_revert
from apps.wpm.services import mlog_submit_validate, generate_new_batch from apps.wpm.services import mlog_submit_validate, generate_new_batch
@ -446,9 +447,9 @@ class MlogViewSet(CustomModelViewSet):
raise ParseError("该日志存在审批!") raise ParseError("该日志存在审批!")
user = request.user user = request.user
if ins.submit_time is None: if ins.submit_time is None:
raise ParseError("日志未提交不可撤") raise ParseError("日志未提交不可撤")
if user != ins.submit_user: if user != ins.submit_user:
raise ParseError("非提交人不可撤!") raise ParseError("非提交人不可撤!")
now = timezone.now() now = timezone.now()
mlog_revert(ins, user, now) mlog_revert(ins, user, now)
return Response(MlogSerializer(instance=ins).data) return Response(MlogSerializer(instance=ins).data)
@ -836,7 +837,7 @@ class MlogbInViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, BulkDestroyMode
"batch": mlogbin.batch, "batch": mlogbin.batch,
"batch_ofrom": wm_in.batch_ofrom, "batch_ofrom": wm_in.batch_ofrom,
"material_ofrom": wm_in.material_ofrom, "material_ofrom": wm_in.material_ofrom,
"qct": Qct.get(material_out, "process", "out"), "qct": Qct.get(material_out, "fix" if mlog.is_fix else "process", "out"),
} }
if mtype == Process.PRO_DIV and material_in.tracking == Material.MA_TRACKING_SINGLE: if mtype == Process.PRO_DIV and material_in.tracking == Material.MA_TRACKING_SINGLE:
pass pass
@ -1020,18 +1021,22 @@ class MlogbInViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, BulkDestroyMode
class MlogbOutViewSet(BulkUpdateModelMixin, CustomGenericViewSet): class MlogbOutViewSet(BulkUpdateModelMixin, CustomGenericViewSet):
perms_map = {"put": "mlog.update"} perms_map = {"put": "mlog.update", "patch": "mlog.update"}
queryset = Mlogb.objects.filter(material_out__isnull=False) queryset = Mlogb.objects.filter(material_out__isnull=False)
serializer_class = MlogbOutUpdateSerializer serializer_class = MlogbOutUpdateSerializer
partial_update_serializer_class = MlogbOutPatchUpdateSerializer
def perform_update(self, serializer): def perform_update(self, serializer):
ins: Mlogb = serializer.instance if self.request.method == "PATCH":
mlog = MlogViewSet.lock_and_check_can_update(ins.mlog) serializer.save()
material_out = serializer.validated_data.get("material_out") else:
if material_out and material_out.tracking == Material.MA_TRACKING_SINGLE: ins: Mlogb = serializer.instance
raise ParseError("单件产品不支持直接修改") mlog = MlogViewSet.lock_and_check_can_update(ins.mlog)
ins: Mlogb = serializer.save() material_out = serializer.validated_data.get("material_out")
mlog.cal_mlog_count_from_mlogb() if material_out and material_out.tracking == Material.MA_TRACKING_SINGLE:
raise ParseError("单件产品不支持直接修改")
ins: Mlogb = serializer.save()
mlog.cal_mlog_count_from_mlogb()
class FmlogViewSet(CustomModelViewSet): class FmlogViewSet(CustomModelViewSet):
@ -1074,7 +1079,7 @@ class BatchStViewSet(CustomListModelMixin, ComplexQueryMixin, CustomGenericViewS
class MlogbwViewSet(CustomModelViewSet): class MlogbwViewSet(CustomModelViewSet):
perms_map = {"get": "*", "post": "mlog.update", "put": "mlog.update", "delete": "mlog.update"} perms_map = {"get": "*", "post": "mlog.update", "put": "mlog.update", "delete": "mlog.update", "patch": "mlog.update"}
queryset = Mlogbw.objects.all() queryset = Mlogbw.objects.all()
serializer_class = MlogbwCreateUpdateSerializer serializer_class = MlogbwCreateUpdateSerializer
list_serializer_class = MlogbwListSerializer list_serializer_class = MlogbwListSerializer

View File

@ -17,6 +17,7 @@ class WprFilter(filters.FilterSet):
"mb": ["exact", "isnull"], "mb": ["exact", "isnull"],
"wm": ["exact", "isnull"], "wm": ["exact", "isnull"],
"material__process": ["exact"], "material__process": ["exact"],
"material__name": ["exact", "contains"],
"state": ["exact"], "state": ["exact"],
"defects": ["exact"], "defects": ["exact"],
"number": ["exact"] "number": ["exact"]

View File

@ -1,3 +1,148 @@
## 3.0.2025122514
- feat: 新增功能
- mlogbw patch权限 [caoqianming]
- 固定资产入库流程apply [caoqianming]
- resignation ticket存入employee_name [caoqianming]
- 新增人员交接单及其修改 人员交接时候反存校验 [TianyangZhang]
- asm assetlogcreate [caoqianming]
- base 提交时可变动工单title [caoqianming]
- 车间库存支持传入count_all [caoqianming]
- wmaterial search时去除material__number [caoqianming]
- base ticketmixin 修改 ”perform_update“ bug [TianyangZhang]
- wmaterial添加mlog_date_start筛选条件 [caoqianming]
- 新增hrm --人员交接表 [TianyangZhang]
- asm初步接口 [caoqianming]
- base userfilter获取归属于该部门及以下部门的人 [caoqianming]
- 玻纤添加mioitemw检验导入表 [caoqianming]
- 修改mioitemw test的导入逻辑 [caoqianming]
- 光子六车间批次生产合格率修改 [caoqianming]
- 取消handover_submit无用校验 [caoqianming]
- 合批时校验批次是否已存在 [caoqianming]
- routepack删除时做一下校验 [caoqianming]
- 维修记录初步完成 [caoqianming]
- base ticketmixin传入other_data [caoqianming]
- base 模板字段改为textfield [caoqianming]
- 删除asm同步文件 [caoqianming]
- 修改hrm/urls --EMPneed [TianyangZhang]
- 新增模块固定资产 asm [TianyangZhang]
- 添加员工需求表 [caoqianming]
- route接口增加按product获取总图 [caoqianming]
- base wf增加ticket_count接口添加分类 [caoqianming]
- validate_dag检查检查未到达的物料 [caoqianming]
- 自动生成物料的逻辑优化 [caoqianming]
- cal_x_task_count默认使用target_quantity [caoqianming]
- base wf 捕获expr is None的错误 [caoqianming]
- validate_dag增加传入参数 [caoqianming]
- 改版交接支持拆合批 [caoqianming]
- translate_eval_formula 打印报错信息 [caoqianming]
- base 优化safe_get_or_create [caoqianming]
- base 增加statedetailserializer可返回节点操作人员 [caoqianming]
- 获取batchlog dag数据支持临近节点返回 [caoqianming]
- base ticket create支持transition非必传 [caoqianming]
- 供应商审核通过后即可添加供应商 [caoqianming]
- 校验SupplierAudit供应商名称已存在 [caoqianming]
- material list filter low_inm优化 [caoqianming]
- material list 如需获取库存数据需指定传参 [caoqianming]
- 添加部分索引 [caoqianming]
- base ticket create支持transition非必传 [caoqianming]
- 供应商审核通过后即可添加供应商 [caoqianming]
- 校验SupplierAudit供应商名称已存在 [caoqianming]
- material list filter low_inm优化 [caoqianming]
- material list 如需获取库存数据需指定传参 [caoqianming]
- 添加部分索引 [caoqianming]
- srm -model-Papersecret 增加 organization 申请部门字段 [TianyangZhang]
- 优化mlogbw list接口速度 [caoqianming]
- srm-patent修改字段类型 [TianyangZhang]
- resignation添加ticketrelate_name [caoqianming]
- base get_object加锁时注意is_deleted过滤采用base_manager [caoqianming]
- base wf 调用方法支持静态方法 [caoqianming]
- mlogbw关于wpr的校验修改以支持手动新增 [caoqianming]
- resignatioin提交时调用的方法 [caoqianming]
- ResignationSerializer create bug [caoqianming]
- base ticketmixin添加ticket_auto_submit_on_create [caoqianming]
- resignation添加ticketMixin [caoqianming]
- base wfmixin 修改时校验 [caoqianming]
- base ticketDetail添加create_by_name [caoqianming]
- 短信发送功能未开启 [caoqianming]
- 批次号格式错误的校验 [caoqianming]
- mioitemcreate时接收count_send [caoqianming]
- mioitemw增加筛选条件 [caoqianming]
- wpr_bxerp优化mlogbw的获取 [caoqianming]
- do_out报错更明确 [caoqianming]
- 优化ana batchwork [caoqianming]
- 改版交接支持new_wm [caoqianming]
- ofm-models borrowRecord 增加借阅数量 [TianyangZhang]
- ofm-models fix bug [TianyangZhang]
- feat : ofm -vehicle fix bug [TianyangZhang]
- ofm 修改车辆model 字段 [TianyangZhang]
- ofm-service fix bug [TianyangZhang]
- featofm-service 修改 bug [TianyangZhang]
- ofm -修改 view 字段 [TianyangZhang]
- ofm 修改 ofm 字段 并重新生成迁移文件 [TianyangZhang]
- base workflow添加分类字段 [caoqianming]
- ofm-views 修改 车辆字段 [TianyangZhang]
- ofm-vehicle 修改车辆审批申请 改完按时间段进行选择 [TianyangZhang]
- mioitem添加count_send字段 [caoqianming]
- 校验改版时选择的改版物料 [caoqianming]
- 导入物料明细支持直接从名称等匹配 [caoqianming]
- 增强新批次号校验 [caoqianming]
- 提供修改编号的接口 [caoqianming]
- supplieraudit采用新工作流挂载方式 [caoqianming]
- base 添加ticketmixin可集成到viewset下以支持工作流 [caoqianming]
- base 可跳过短信发送 [caoqianming]
- 反向操作时忽略明细校验 [caoqianming]
- 拦截new_batch的错误 [caoqianming]
- fix 修改 srm 的 views [TianyangZhang]
- base wfservice创建出工单时处理人为提交人 [caoqianming]
- featsrm fix serializer [TianyangZhang]
- base handle_ticket 完善transition校验 [caoqianming]
- DatasetRecord添加filter [caoqianming]
- handover添加selectfield [caoqianming]
- 交接记录返回material_changed_fname [caoqianming]
- 改版交接必须为合批操作 [caoqianming]
- base 创建数据时检验不包含id2 [caoqianming]
- fix srm serializer [TianyangZhang]
- srm-service 去掉 platform belong_dept [TianyangZhang]
- add new model platform '平台审批' [TianyangZhang]
- base 创建数据时检验不包含id [caoqianming]
- 添加供应商审核 [caoqianming]
- base 开始编写ticketMixin可自动挂载 [caoqianming]
- ResignationSerializer返回employee_id_number [caoqianming]
- base 添加EuModelViewSet [caoqianming]
- 离职申请支持删除 [caoqianming]
- Resignationserializer返回employee_name [caoqianming]
- base handle_ticket 默认参数 [caoqianming]
- 优化bind_resignation [caoqianming]
- base 优化wf create [caoqianming]
- ResignationViewSet添加RetrieveModelMixin [caoqianming]
- bind_resignation bug [caoqianming]
- 返回TicketSimpleSerializer [caoqianming]
- fix: 问题修复
- repair swaggger显示问题 [caoqianming]
- 修改 ofm - vehicle 中的出发里程 [TianyangZhang]
- handoverserializer 关于new_wm的处理 [caoqianming]
- handovermerge时new_state未定义 [caoqianming]
- 修改印章申请binging_seal [TianyangZhang]
- update_mb_item时考虑检验的存在 [caoqianming]
- hrm-用人需求修改标题模板 [TianyangZhang]
- 先调整asm以启动服务 [caoqianming]
- do_in bug [caoqianming]
- base ticketmixin先创建再handle [caoqianming]
- fix :修改提交审批报错 RelatedManager' object has no attribute 'belong_dept [TianyangZhang]
- fix : srm 修改 paperrecord 字段 cor_author 字段类型 [TianyangZhang]
- fixsrm 修改论文审批 反存 论文台账 主要修改model 字段类型 [TianyangZhang]
- srm 修改专利台账 [TianyangZhang]
- base wfmixin gen_ticket_data保存t_id转为str [caoqianming]
- fix : 修改ofm -views -vehicle && services [TianyangZhang]
- format_json_with_placeholders 处理decimal [caoqianming]
- base wf工作流分类接口detail错误 [caoqianming]
- do_in 可直接取用wm [caoqianming]
- material get_queryset忘记return qs [caoqianming]
- material增加count__gt等查询条件 [caoqianming]
- mioitem create时校验是否混批的bug [caoqianming]
- base handle_ticket处理ticket_title [caoqianming]
- bind_resignation bug [caoqianming]
- clean_data关于material的处理 [caoqianming]
## 3.0.2025120109 ## 3.0.2025120109
- feat: 新增功能 - feat: 新增功能
- 供应商审核通过后即可添加供应商 [caoqianming] - 供应商审核通过后即可添加供应商 [caoqianming]

View File

@ -35,7 +35,7 @@ sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
SYS_NAME = '星途工厂综合管理系统' SYS_NAME = '星途工厂综合管理系统'
SYS_VERSION = '3.0.2025120109' SYS_VERSION = '3.0.2025122514'
X_FRAME_OPTIONS = 'SAMEORIGIN' X_FRAME_OPTIONS = 'SAMEORIGIN'
# Application definition # Application definition