Merge branch 'master' of https://e.coding.net/ctcdevteam/ehs/ehs_server
合并
This commit is contained in:
commit
8183073026
|
@ -20,6 +20,8 @@ db.sqlite3
|
|||
server/conf*.py
|
||||
server/conf.ini
|
||||
server/conf*.json
|
||||
config/conf*.py
|
||||
config/conf*.json
|
||||
sh/*
|
||||
temp/*
|
||||
nohup.out
|
||||
|
|
|
@ -151,11 +151,20 @@ class MpLogxViewSet(CustomListModelMixin, CustomGenericViewSet):
|
|||
serializer_class = MpLogxSerializer
|
||||
filterset_fields = {
|
||||
"timex": ["exact", "gte", "lte", "year", "month", "day"],
|
||||
"mpoint": ["exact"],
|
||||
"mpoint": ["exact", "in"],
|
||||
"mpoint__ep_monitored": ["exact"]
|
||||
}
|
||||
ordering_fields = ["timex"]
|
||||
ordering = ["-timex"]
|
||||
|
||||
@action(methods=["get"], detail=False, perms_map={"get": "*"})
|
||||
def to_wide(self, request, *args, **kwargs):
|
||||
"""转换为宽表
|
||||
|
||||
转换为宽表
|
||||
"""
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
|
||||
|
||||
class MpointStatViewSet(BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin, CustomGenericViewSet):
|
||||
"""
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
from django.db import models
|
||||
from apps.system.models import CommonADModel
|
||||
from apps.system.models import CommonADModel, BaseModel
|
||||
|
||||
# Create your models here.
|
||||
class Conversation(CommonADModel):
|
||||
"""
|
||||
TN: 对话
|
||||
"""
|
||||
title = models.CharField(max_length=200, default='新对话',verbose_name='对话标题')
|
||||
title = models.CharField(max_length=200, default='新对话',verbose_name='对话标题')
|
||||
|
||||
class Message(BaseModel):
|
||||
"""
|
||||
TN: 消息
|
||||
"""
|
||||
conversation = models.ForeignKey(Conversation, on_delete=models.CASCADE, verbose_name='对话')
|
||||
content = models.TextField(verbose_name='消息内容')
|
||||
role = models.CharField("角色", max_length=10, help_text="system/user")
|
||||
|
|
|
@ -186,8 +186,8 @@ class RouteSerializer(CustomModelSerializer):
|
|||
raise ParseError('未提供操作工序')
|
||||
if process.parent is not None:
|
||||
raise ParseError('操作工序不可为子工序')
|
||||
if process.mtype == Process.PRO_DIV and attrs.get('div_number', 1) <= 1:
|
||||
raise ParseError('切分数量必须大于1')
|
||||
if process.mtype == Process.PRO_DIV and attrs.get('div_number', 1) < 1:
|
||||
raise ParseError('切分数量必须大于等于1')
|
||||
return super().validate(attrs)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2025-04-23 05:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('qm', '0049_alter_ptest_sample_number'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='defect',
|
||||
name='cate',
|
||||
field=models.CharField(help_text="['尺寸', '外观', '内质', '性能']", max_length=50, verbose_name='分类'),
|
||||
),
|
||||
]
|
|
@ -14,9 +14,10 @@ class Defect(CommonAModel):
|
|||
DEFECT_OK = 10
|
||||
DEFECT_OK_B = 20
|
||||
DEFECT_NOTOK = 30
|
||||
cate_list = ["尺寸", "外观", "内质", "性能"]
|
||||
name = models.CharField(max_length=50, verbose_name="名称")
|
||||
code = models.CharField(max_length=50, verbose_name="标识", null=True, blank=True)
|
||||
cate = models.CharField(max_length=50, verbose_name="分类", choices=(("尺寸", "尺寸"), ("外观", "外观"), ("内质", "内质")))
|
||||
cate = models.CharField(max_length=50, verbose_name="分类", help_text=str(cate_list))
|
||||
okcate= models.PositiveSmallIntegerField(verbose_name="不合格分类",
|
||||
choices=((DEFECT_OK, "合格"), (DEFECT_OK_B, "合格B类"), (DEFECT_NOTOK, "不合格")),
|
||||
default=DEFECT_NOTOK)
|
||||
|
|
|
@ -15,6 +15,12 @@ class DefectSerializer(CustomModelSerializer):
|
|||
model = Defect
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS
|
||||
|
||||
def validate(self, attrs):
|
||||
cate = attrs["cate"]
|
||||
if cate not in Defect.cate_list:
|
||||
raise ParseError("缺陷类别错误")
|
||||
return attrs
|
||||
|
||||
# def create(self, validated_data):
|
||||
# code = validated_data["code"]
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.12 on 2025-04-22 07:45
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0056_mgroup_batch_append_code'),
|
||||
('wpm', '0112_auto_20250422_1430'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='team',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.team', verbose_name='班组'),
|
||||
),
|
||||
]
|
|
@ -252,6 +252,7 @@ class Mlog(CommonADModel):
|
|||
count_n_qt = models.DecimalField('其他', default=0, max_digits=11, decimal_places=1)
|
||||
|
||||
handle_date = models.DateField('操作日期', null=True, blank=True)
|
||||
team = models.ForeignKey(Team, verbose_name='班组', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
handle_user = models.ForeignKey(
|
||||
User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True) # 成型人
|
||||
handle_user_2 = models.ForeignKey(
|
||||
|
@ -613,7 +614,7 @@ class BatchSt(BaseModel):
|
|||
|
||||
class Meta:
|
||||
unique_together = [("batch", "version")]
|
||||
|
||||
|
||||
@classmethod
|
||||
def g_create(cls, batch:str, mio=None, handover=None, mlog=None, material_start=None):
|
||||
"""
|
||||
|
@ -622,13 +623,14 @@ class BatchSt(BaseModel):
|
|||
if mio is None and handover is None and mlog is None:
|
||||
return cls.objects.get_or_create(batch=batch)
|
||||
else:
|
||||
latest_version = 0
|
||||
version = 1
|
||||
# 带有来源的批次获取,需检查批次号是否可用
|
||||
if cls.objects.filter(batch=batch, version=0).exists():
|
||||
if cls.objects.filter(batch=batch, version=1).exists():
|
||||
latest_version = BatchSt.objects.filter(batch=batch).aggregate(Max("version"))["version__max"]
|
||||
version = latest_version + 1
|
||||
if mio is None and handover is None and mlog is None:
|
||||
raise ParseError("mio or handover or mlog must be provided")
|
||||
ins = cls.objects.create(batch=batch, mio=mio, handover=handover, mlog=mlog, material_start=material_start, version=latest_version+1)
|
||||
ins = cls.objects.create(batch=batch, mio=mio, handover=handover, mlog=mlog, material_start=material_start, version=version)
|
||||
return ins, True
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -234,6 +234,7 @@ class MlogbSerializer(CustomModelSerializer):
|
|||
|
||||
|
||||
class MlogListSerializer(CustomModelSerializer):
|
||||
team_name = serializers.CharField(source="team.name", read_only=True)
|
||||
mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True)
|
||||
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
||||
# routepack_name = serializers.CharField(source='route.routepack.name', read_only=True)
|
||||
|
@ -291,6 +292,7 @@ class MlogbDetailSerializer(CustomModelSerializer):
|
|||
fields = '__all__'
|
||||
|
||||
class MlogSerializer(CustomModelSerializer):
|
||||
team_name = serializers.CharField(source="team.name", read_only=True)
|
||||
mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True)
|
||||
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
||||
# routepack_name = serializers.CharField(source='route.routepack.name', read_only=True)
|
||||
|
@ -748,7 +750,7 @@ class MlogbInUpdateSerializer(CustomModelSerializer):
|
|||
mlogbdefect = MlogbDefectSerializer(many=True, required=False)
|
||||
class Meta:
|
||||
model = Mlogb
|
||||
fields = ['id', 'count_use', 'count_pn_jgqbl', 'note', 'mlogbdefect']
|
||||
fields = ['id', 'count_use', 'count_pn_jgqbl', 'note', 'mlogbdefect', "need_inout"]
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs["count_use"] < 0 or attrs["count_pn_jgqbl"] < 0:
|
||||
|
@ -858,6 +860,16 @@ class MlogbOutUpdateSerializer(CustomModelSerializer):
|
|||
mlogbdefect = validated_data.pop("mlogbdefect", None)
|
||||
with transaction.atomic():
|
||||
ins:Mlogb = super().update(instance, validated_data)
|
||||
if ins.need_inout is False:
|
||||
if ins.mlogb_from:
|
||||
if Mlogb.objects.filter(mlog=ins.mlog, material_out__isnull=False, mlogb_from=ins.mlogb_from).count() == 1:
|
||||
ins_from =Mlogb.objects.filter(mlog=ins.mlog, material_out__isnull=False, mlogb_from=ins.mlogb_from).first()
|
||||
ins_from.need_inout = False
|
||||
ins_from.save(update_fields=["need_inout"])
|
||||
else:
|
||||
raise ParseError("对应消耗的产出有多个, 需手动指定消耗是否出库")
|
||||
else:
|
||||
raise ParseError("该产出需入库!")
|
||||
if mlogbdefect is not None and ins.material_out.tracking == Material.MA_TRACKING_BATCH:
|
||||
MlogbDefect.objects.filter(mlogb=ins).delete()
|
||||
mlogb_defect_objects = [
|
||||
|
|
|
@ -190,6 +190,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
m_ins_list = []
|
||||
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
|
||||
if m_ins.exists():
|
||||
m_ins = m_ins.filter(need_inout=True)
|
||||
m_ins_list = [(mi.material_in, mi.batch if mi.batch else mi.batch, mi.count_use, None, mi) for mi in m_ins.all()]
|
||||
for item in m_ins:
|
||||
mbd_qs = MlogbDefect.get_defect_qs_from_mlogb(item)
|
||||
|
@ -260,7 +261,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
|
||||
stored_notok = need_store_notok
|
||||
stored_mgroup = need_store_notok
|
||||
if mlogb_out_qs.exists():
|
||||
if mlogb_out_qs.exists():
|
||||
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()]
|
||||
if need_store_notok:
|
||||
for item in mlogb_out_qs:
|
||||
|
@ -402,6 +404,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
# 需要考虑不合格品退回的情况
|
||||
mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
|
||||
if mlogb_out_qs.exists():
|
||||
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()]
|
||||
|
@ -497,6 +500,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
into_wm_mgroup = process.into_wm_mgroup
|
||||
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
|
||||
if m_ins.exists():
|
||||
m_ins = m_ins.filter(need_inout=True)
|
||||
for mi in m_ins.all():
|
||||
m_ins_list.append((mi.material_in, mi.batch, mi.count_use, None, mi))
|
||||
for item in m_ins:
|
||||
|
|
|
@ -5,7 +5,7 @@ from apps.inm.models import MIOItem
|
|||
from apps.qm.models import FtestWork
|
||||
from django.utils import timezone
|
||||
from datetime import datetime
|
||||
from server.conf import BASE_PROJECT_CODE
|
||||
from django.conf import settings
|
||||
import json
|
||||
from apps.utils.tools import MyJSONEncoder
|
||||
import decimal
|
||||
|
@ -17,6 +17,7 @@ def get_alldata_with_batch_and_store(batch: str):
|
|||
获取某个批次的整体生产数据并保存
|
||||
"""
|
||||
need_update = False
|
||||
BASE_PROJECT_CODE = getattr(settings, "BASE_PROJECT_CODE", None)
|
||||
if BASE_PROJECT_CODE == "gzerp":
|
||||
need_update = True
|
||||
last_time, data = get_alldata_with_batch(batch)
|
||||
|
|
|
@ -174,13 +174,13 @@ class MlogViewSet(CustomModelViewSet):
|
|||
select_related_fields = ['create_by', 'update_by', 'mtask', 'mtaskb',
|
||||
'handle_user', 'handle_user_2', 'equipment', 'mgroup__belong_dept',
|
||||
'equipment_2', 'material_in', 'material_out', 'route__routepack',
|
||||
'supplier', 'ticket', 'mgroup__process', 'test_user', 'handle_leader', 'test_user']
|
||||
'supplier', 'ticket', 'mgroup__process', 'test_user', 'handle_leader', 'test_user', 'team']
|
||||
prefetch_related_fields = ['handle_users',
|
||||
'material_outs', 'b_mlog', 'equipments']
|
||||
filterset_class = MlogFilter
|
||||
search_fields = ['material_in__name',
|
||||
'material_in__number', 'material_in__specification', 'batch', 'material_in__model',
|
||||
'material_out__name', 'material_out__number', 'material_out__specification', 'material_out__model',]
|
||||
'material_out__name', 'material_out__number', 'material_out__specification', 'material_out__model']
|
||||
|
||||
def add_info_for_item(self, data):
|
||||
if data.get("oinfo_json", {}):
|
||||
|
@ -624,8 +624,11 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
|
|||
{"count_real": d_count_real, "count_ok": d_count_ok}))
|
||||
for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"):
|
||||
wpr_ = mlogbwin.wpr
|
||||
for i in range(div_number):
|
||||
Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr_.number}-{i+1}', defaults={"mlogbw_from": mlogbwin})
|
||||
if div_number == 1:
|
||||
Mlogbw.objects.get_or_create(wpr=wpr_, mlogb=mlogbout, defaults={"number": wpr_.number, "mlogbw_from": mlogbwin})
|
||||
else:
|
||||
for i in range(div_number):
|
||||
Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr_.number}-{i+1}', defaults={"mlogbw_from": mlogbwin})
|
||||
elif material_in.tracking == Material.MA_TRACKING_BATCH and material_out.tracking == Material.MA_TRACKING_BATCH:
|
||||
d_count_real = mlogbin.count_use * div_number
|
||||
d_count_ok = d_count_real
|
||||
|
|
34
changelog.md
34
changelog.md
|
@ -1,3 +1,37 @@
|
|||
## 2.6.2025042311
|
||||
- feat: 新增功能
|
||||
- 切分工序切分数量支持1 [caoqianming]
|
||||
- mlog增加team字段 [caoqianming]
|
||||
- mlog的need_inout逻辑 [caoqianming]
|
||||
- 批次关系链时创建新批次支持使用已有批次号 [caoqianming]
|
||||
- mlogb添加test_user/need_inout字段用于处理抽检逻辑 [caoqianming]
|
||||
- 工艺步骤返回组合而成的name [caoqianming]
|
||||
- 校验只有合并时才能提供新批次号 [caoqianming]
|
||||
- 交接查询可查询子批次号 [caoqianming]
|
||||
- 日志完善负值校验 [caoqianming]
|
||||
- 批号追加工段标识 [caoqianming]
|
||||
- base增加PositiveDecimalField [caoqianming]
|
||||
- 改版交接需要触发统计数量 [caoqianming]
|
||||
- 物料统计数量接口 [caoqianming]
|
||||
- update_material_count时更新组合件数量 [caoqianming]
|
||||
- 采购和其他入库可入已有批次 [caoqianming]
|
||||
- 交接需要校验物料是否一致 [caoqianming]
|
||||
- 返工可选择不合格品/根据工艺路线决定返工后是合格不合格还是返修完成 [caoqianming]
|
||||
- 检验项和缺陷项删除的时候同步删除qct [caoqianming]
|
||||
- fmlog添加工艺步骤字段及相应返回数据 [caoqianming]
|
||||
- fix: 问题修复
|
||||
- mlog的need_inout逻辑 [caoqianming]
|
||||
- count_working获取逻辑优化 [caoqianming]
|
||||
- mlogbin解决负值校验存在的bug [caoqianming]
|
||||
- 日志和交接记录操作数正值校验 [caoqianming]
|
||||
- inm校验非正数 [caoqianming]
|
||||
- 其他入库时batchst.g_create传参错误 [caoqianming]
|
||||
- : 交接记录提交时校验count>0 [caoqianming]
|
||||
- 正常交接后的物料状态不变 [caoqianming]
|
||||
- 存在fmlog时将route带给mlog并进行物料校验 [caoqianming]
|
||||
- do_in保证production_dept赋值 [caoqianming]
|
||||
- 订单检索条件错误 [caoqianming]
|
||||
- fmlog填写mtask或route即可 [caoqianming]
|
||||
## 2.6.2025041613
|
||||
- feat: 新增功能
|
||||
- 添加count_json_from字段及相应逻辑 [caoqianming]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
SECRET_KEY = 'xx'
|
||||
DEBUG = False
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': 'xx',
|
||||
'USER': 'postgres',
|
||||
'PASSWORD': 'xx',
|
||||
'HOST': 'xx',
|
||||
'PORT': '5432',
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
from . import conf
|
||||
from config import conf
|
||||
from celery import Celery
|
||||
from celery.app.control import Control, Inspect
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ from datetime import datetime, timedelta
|
|||
import os
|
||||
import json
|
||||
import sys
|
||||
from .conf import *
|
||||
from config.conf import *
|
||||
from django.core.cache import cache
|
||||
import logging
|
||||
|
||||
|
@ -35,7 +35,7 @@ sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
|
|||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
SYS_NAME = '星途工厂综合管理系统'
|
||||
SYS_VERSION = '2.6.2025041613'
|
||||
SYS_VERSION = '2.6.2025042311'
|
||||
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||
|
||||
# Application definition
|
||||
|
@ -369,7 +369,7 @@ LOGGING = {
|
|||
}
|
||||
|
||||
##### 加载客户可自定义配置并提供操作方法 #####
|
||||
SYS_JSON_PATH = os.path.join(BASE_DIR, 'server/conf.json')
|
||||
SYS_JSON_PATH = os.path.join(BASE_DIR, 'config/conf.json')
|
||||
|
||||
def get_sysconfig(key='', default='raise_error', reload=False):
|
||||
"""获取系统配置可指定key字符串
|
||||
|
|
Loading…
Reference in New Issue