Merge branch 'master' of https://e.coding.net/ctcdevteam/ehs/ehs_server
This commit is contained in:
commit
7aae49b378
|
@ -12,6 +12,8 @@ from apps.bi.services import check_sql_safe, format_json_with_placeholders
|
|||
from rest_framework.exceptions import ParseError
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from apps.utils.mixins import ListModelMixin
|
||||
import logging
|
||||
myLogger = logging.getLogger('log')
|
||||
# Create your views here.
|
||||
|
||||
|
||||
|
@ -101,6 +103,7 @@ class DatasetViewSet(CustomModelViewSet):
|
|||
results[name], results2[name] = format_sqldata(
|
||||
res[0], res[1])
|
||||
except Exception as e:
|
||||
myLogger.error(f'bi查询异常:{str(e)}-{dt.code}--{sql_f}')
|
||||
if raise_exception:
|
||||
raise ParseError(f'查询异常:{str(e)}')
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2024-08-28 08:51
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('enm', '0043_xscript'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='xscript',
|
||||
name='change_data',
|
||||
field=models.JSONField(blank=True, default=dict, null=True, verbose_name='变更数据'),
|
||||
),
|
||||
]
|
|
@ -8,6 +8,7 @@ class Xscript(BaseModel):
|
|||
name = models.CharField("脚本名称", max_length=50)
|
||||
code = models.TextField("脚本内容", null=True, blank=True)
|
||||
base_data = models.JSONField("基础数据", default=dict, null=True, blank=True)
|
||||
change_data = models.JSONField("变更数据", default=dict, null=True, blank=True)
|
||||
myschedule = models.ForeignKey('system.myschedule', verbose_name='周期', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
periodictask = models.ForeignKey(PeriodicTask, verbose_name='关联定时任务', on_delete=models.CASCADE, related_name='xscript_periodictask', null=True, blank=True)
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ class XscriptSerializer(CustomModelSerializer):
|
|||
class Meta:
|
||||
model = Xscript
|
||||
fields = "__all__"
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE + ['periodictask']
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE + ['periodictask', 'change_data']
|
||||
|
||||
def validate(self, attrs):
|
||||
code = attrs['code']
|
||||
|
|
|
@ -21,12 +21,9 @@ myLogger = logging.getLogger("log")
|
|||
def db_insert_mplogx_batch(rows):
|
||||
for row in rows:
|
||||
_, tag_val, tag_code, tag_update = row
|
||||
# if '散装' in tag_code or '袋装' in tag_code:
|
||||
# myLogger.info(f"db_ins_mplogx tag_val: {tag_val} tag_code: {tag_code}-------{str(type(tag_val))}")
|
||||
# mpoint = Mpoint.objects.get(code=tag_code)
|
||||
# tag_val = float(tag_val)
|
||||
# myLogger.info(f"db_ins_mpoint_id: {mpoint.id}-------db_ins_float_val: {tag_val}")
|
||||
insert_mplogx_item(tag_code, tag_val, timezone.make_aware(tag_update), {})
|
||||
if tag_update.tzinfo is None:
|
||||
tag_update = timezone.make_aware(tag_update)
|
||||
insert_mplogx_item(tag_code, tag_val, tag_update, {})
|
||||
|
||||
def translate_eval_formula(exp_str: str, year: int, month: int, day: int, hour: int):
|
||||
"""
|
||||
|
|
|
@ -27,6 +27,7 @@ from apps.wpm.tasks import get_total_sec_now, cal_exp_duration_sec
|
|||
from apps.utils.sql import DbConnection
|
||||
from apps.enm.services import db_insert_mplogx_batch
|
||||
from apps.enm.xscript import main
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
myLogger = logging.getLogger("log")
|
||||
|
||||
|
||||
|
@ -130,8 +131,7 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in
|
|||
dt = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=0, second=0, tzinfo=mytz) # 整点时间
|
||||
dt_hour_p= dt - datetime.timedelta(hours=1) # 上个整点
|
||||
dt_hour_n= dt + datetime.timedelta(hours=1) # 下个整点
|
||||
|
||||
if mpoint.material and mpoint.val_type in ['float', 'int']: # 如果计量的是物料 # 累计量 有的会清零,需要额外处理(还未做)
|
||||
if (mpoint.material or mpoint.type == Mpoint.MT_COMPUTE) and mpoint.val_type in ['float', 'int']: # 如果计量的是物料 # 累计量 有的会清零,需要额外处理(还未做)
|
||||
params = {"mpoint": mpoint, "type": "hour"}
|
||||
params["year"], params["month"], params["day"], params["hour"] = year, month, day, hour
|
||||
val = 0
|
||||
|
@ -141,7 +141,6 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in
|
|||
val = MpLogx.objects.filter(mpoint=mpoint, timex__gte=dt, timex__lt=dt_hour_n).aggregate(sum=Sum(f'val_{mpoint.val_type}'))["sum"]
|
||||
if val is None:
|
||||
val = 0
|
||||
myLogger.info(str(val), "-------val")
|
||||
else:
|
||||
mrs0 = MpLogx.objects.filter(mpoint=mpoint, timex__gte=dt_hour_p, timex__lte=dt).order_by("timex")
|
||||
mrs = MpLogx.objects.filter(mpoint=mpoint, timex__gte=dt, timex__lte=dt_hour_n).order_by("timex")
|
||||
|
@ -281,7 +280,7 @@ def cal_mpointstats(is_now=1, year=None, month=None, day=None, hour=None, m_code
|
|||
cal_mpointstat_hour(item.id, year, month, day, hour)
|
||||
|
||||
# 再统计计算测点
|
||||
mpoints_compute = Mpoint.objects.filter(type=Mpoint.MT_COMPUTE, enabled=True, material__isnull=False).exclude(formula="").order_by('report_sortstr', 'create_time')
|
||||
mpoints_compute = Mpoint.objects.filter(type=Mpoint.MT_COMPUTE, enabled=True).exclude(formula="").order_by('report_sortstr', 'create_time')
|
||||
# mpoints_other_group = []
|
||||
for item in mpoints_compute:
|
||||
# mpoints_other_group.append(cal_mpointstat_hour.s(item.id, year, month, day, hour))
|
||||
|
@ -688,34 +687,42 @@ def cal_enstat2(type: str, year_s: int, month_s: int, day_s: int, cascade=True):
|
|||
elif type == "day_s":
|
||||
enstat2, _ = EnStat2.objects.get_or_create(type="day_s", year_s=year_s, month_s=month_s, day_s=day_s, defaults={"year_s": year_s, "month_s": month_s, "day_s": day_s, "type": "day_s"})
|
||||
# enstat2 = EnStat2.objects.select_for_update().get(id=enstat2.id) # 加锁
|
||||
material_bulk_clinker = Material.objects.get(code="bulk_clinker") # 散装熟料
|
||||
material_bulk_cement = Material.objects.get(code="bulk_cement") # 散装水泥
|
||||
material_bag_cement = Material.objects.get(code="bag_cement") # 袋装水泥
|
||||
try:
|
||||
material_bulk_clinker = Material.objects.get(code="bulk_clinker") # 散装熟料
|
||||
enstat2.bulk_clinker_price = get_price_unit(material_bulk_clinker, year_s, month_s)
|
||||
except ObjectDoesNotExist:
|
||||
enstat2.bulk_clinker_price = 0
|
||||
try:
|
||||
material_bulk_cement = Material.objects.get(code="bulk_cement") # 散装水泥
|
||||
enstat2.bulk_cement_price = get_price_unit(material_bulk_cement, year_s, month_s)
|
||||
except ObjectDoesNotExist:
|
||||
enstat2.bulk_cement_price = 0
|
||||
try:
|
||||
material_bag_cement = Material.objects.get(code="bag_cement") # 袋装水泥
|
||||
enstat2.bag_cement_price = get_price_unit(material_bag_cement, year_s, month_s)
|
||||
except ObjectDoesNotExist:
|
||||
enstat2.bag_cement_price = 0
|
||||
|
||||
|
||||
enstat2.bulk_cement_price = get_price_unit(material_bulk_cement, year_s, month_s)
|
||||
enstat2.bulk_clinker_price = get_price_unit(material_bulk_clinker, year_s, month_s)
|
||||
enstat2.bag_cement_price = get_price_unit(material_bag_cement, year_s, month_s)
|
||||
|
||||
if type == "month_s":
|
||||
enstat2.bulk_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material=material_bulk_cement, year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"]
|
||||
enstat2.bulk_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material__code="bulk_cement", year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"]
|
||||
elif type == "day_s":
|
||||
enstat2.bulk_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material=material_bulk_cement, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"]
|
||||
enstat2.bulk_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material__code="bulk_cement", year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"]
|
||||
if enstat2.bulk_cement_val is None:
|
||||
enstat2.bulk_cement_val = 0
|
||||
|
||||
if type == "month_s":
|
||||
enstat2.bag_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material=material_bag_cement, year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"]
|
||||
enstat2.bag_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material__code='bag_cement', year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"]
|
||||
elif type == "day_s":
|
||||
enstat2.bag_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material=material_bag_cement, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"]
|
||||
enstat2.bag_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material__code='bag_cement', year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"]
|
||||
if enstat2.bag_cement_val is None:
|
||||
enstat2.bag_cement_val = 0
|
||||
|
||||
|
||||
if type == "month_s":
|
||||
enstat2.bulk_clinker_val = MpointStat.objects.filter(type="month_s", mpoint__material=material_bulk_clinker, year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"]
|
||||
enstat2.bulk_clinker_val = MpointStat.objects.filter(type="month_s", mpoint__material__code='bulk_clinker', year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"]
|
||||
elif type == "day_s":
|
||||
enstat2.bulk_clinker_val = MpointStat.objects.filter(type="day_s", mpoint__material=material_bulk_clinker, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"]
|
||||
enstat2.bulk_clinker_val = MpointStat.objects.filter(type="day_s", mpoint__material__code='bulk_clinker', year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"]
|
||||
if enstat2.bulk_clinker_val is None:
|
||||
enstat2.bulk_clinker_val = 0
|
||||
|
||||
|
|
|
@ -92,6 +92,17 @@ class XscriptViewSet(CustomModelViewSet):
|
|||
periodictask.save()
|
||||
return Response()
|
||||
|
||||
@action(methods=['put'], detail=True, perms_map={'put': 'xscript.update'})
|
||||
def change_data(self, request, pk=None):
|
||||
"""修改变动数据
|
||||
|
||||
修改变动数据
|
||||
"""
|
||||
obj: Xscript = self.get_object()
|
||||
obj.change_data = request.data.get('change_data', {})
|
||||
obj.save(update_fields=['change_data'])
|
||||
return Response()
|
||||
|
||||
@transaction.atomic
|
||||
def perform_destroy(self, instance):
|
||||
periodictask = instance.periodictask
|
||||
|
|
|
@ -3,6 +3,8 @@ from apps.utils.sql import DbConnection
|
|||
from datetime import datetime, timedelta
|
||||
from apps.enm.services import db_insert_mplogx_batch
|
||||
import requests
|
||||
import logging
|
||||
myLogger = logging.getLogger("log")
|
||||
|
||||
def main(xscript, mcodes_list):
|
||||
exec(xscript.code)
|
||||
|
|
|
@ -10,6 +10,7 @@ from apps.utils.serializers import CustomModelSerializer
|
|||
|
||||
from .models import MIO, MaterialBatch, MIOItem, WareHouse, MIOItemA, MaterialBatchA
|
||||
from django.db import transaction
|
||||
from server.settings import get_sysconfig
|
||||
|
||||
|
||||
class WareHourseSerializer(CustomModelSerializer):
|
||||
|
@ -104,7 +105,9 @@ class MIOItemCreateSerializer(CustomModelSerializer):
|
|||
if mio.state != MIO.MIO_CREATE:
|
||||
raise ValidationError('出入库记录非创建中不可新增')
|
||||
# 生产领料要校验是否进行检验
|
||||
if mio.type == MIO.MIO_TYPE_DO_OUT:
|
||||
# 某些客户此处无需校验
|
||||
check_test_when_do_out = get_sysconfig('mes.check_test_when_do_out', True)
|
||||
if check_test_when_do_out and mio.type == MIO.MIO_TYPE_DO_OUT:
|
||||
mis = MIOItem.objects.filter(batch=batch, material=material, mio__type__in=[MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN])
|
||||
if mis.exists() and (not mis.exclude(test_date=None).exists()):
|
||||
raise ValidationError('该批次的物料未经检验')
|
||||
|
@ -165,6 +168,7 @@ class MIODoSerializer(CustomModelSerializer):
|
|||
model = MIO
|
||||
fields = ['id', 'number', 'note', 'do_user',
|
||||
'belong_dept', 'type', 'inout_date', 'mgroup']
|
||||
extra_kwargs = {'inout_date': {'required': True}, 'do_user': {'required': True}}
|
||||
|
||||
def validate(self, attrs):
|
||||
if 'mgroup' in attrs and attrs['mgroup']:
|
||||
|
@ -190,6 +194,7 @@ class MIOSaleSerializer(CustomModelSerializer):
|
|||
class Meta:
|
||||
model = MIO
|
||||
fields = ['id', 'number', 'note', 'order', 'inout_date', 'customer']
|
||||
extra_kwargs = {'inout_date': {'required': True}}
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['type'] = MIO.MIO_TYPE_SALE_OUT
|
||||
|
@ -216,6 +221,7 @@ class MIOPurSerializer(CustomModelSerializer):
|
|||
class Meta:
|
||||
model = MIO
|
||||
fields = ['id', 'number', 'note', 'pu_order', 'inout_date', 'supplier']
|
||||
extra_kwargs = {'inout_date': {'required': True}}
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data['type'] = MIO.MIO_TYPE_PUR_IN
|
||||
|
@ -241,6 +247,7 @@ class MIOOtherSerializer(CustomModelSerializer):
|
|||
model = MIO
|
||||
fields = ['id', 'number', 'note', 'supplier',
|
||||
'customer', 'type', 'inout_date']
|
||||
extra_kwargs = {'inout_date': {'required': True}}
|
||||
|
||||
def create(self, validated_data):
|
||||
if validated_data['type'] not in [MIO.MIO_TYPE_OTHER_OUT, MIO.MIO_TYPE_OTHER_IN]:
|
||||
|
|
|
@ -5,7 +5,7 @@ from apps.mtm.models import Material, Shift, Mgroup, Process
|
|||
|
||||
@admin.register(Process)
|
||||
class ProcessAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'name', 'cate', 'sort', 'into_wm_mgroup', 'store_notok', 'batch_append_equip')
|
||||
list_display = ('id', 'name', 'cate', 'sort', 'into_wm_mgroup', 'store_notok', 'batch_append_equip', 'mlog_need_ticket')
|
||||
|
||||
|
||||
@admin.register(Material)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-02 09:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0039_alter_material_unit_price'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='process',
|
||||
name='mlog_need_ticket',
|
||||
field=models.BooleanField(default=False, verbose_name='日志提交是否需要审批'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-03 02:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0040_process_mlog_need_ticket'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='process',
|
||||
name='mstate_json',
|
||||
field=models.JSONField(blank=True, default=list, verbose_name='中间状态'),
|
||||
),
|
||||
]
|
|
@ -18,6 +18,8 @@ class Process(CommonBModel):
|
|||
into_wm_mgroup = models.BooleanField('交接到工段', default=False)
|
||||
store_notok = models.BooleanField('不合格品是否入库', default=False)
|
||||
batch_append_equip = models.BooleanField('批号追加设备', default=False)
|
||||
mlog_need_ticket = models.BooleanField('日志提交是否需要审批', default=False)
|
||||
mstate_json = models.JSONField('中间状态', default=list, blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '工序'
|
||||
|
|
|
@ -153,10 +153,14 @@ def bind_routepack(ticket: Ticket, transition, new_ticket_data: dict):
|
|||
raise ParseError('重复创建工单')
|
||||
if not Route.objects.filter(routepack=routepack).exists():
|
||||
raise ParseError('缺少步骤')
|
||||
first_route = Route.objects.filter(routepack=routepack).order_by('sort', 'process__sort', 'create_time').first()
|
||||
r_qs = Route.objects.filter(routepack=routepack).order_by('sort', 'process__sort', 'create_time')
|
||||
first_route = r_qs.first()
|
||||
last_route = r_qs.last()
|
||||
if first_route.batch_bind:
|
||||
first_route.batch_bind = False
|
||||
first_route.save(update_fields=['batch_bind'])
|
||||
if last_route.material_out != routepack.material:
|
||||
raise ParseError('最后一步产出与工艺包不一致')
|
||||
ticket_data = ticket.ticket_data
|
||||
ticket_data.update({
|
||||
't_model': 'routepack',
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-03 08:38
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('pm', '0019_auto_20240703_1618'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Mtaskb',
|
||||
fields=[
|
||||
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('count', models.PositiveIntegerField(default=0, verbose_name='任务数')),
|
||||
('handle_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mtaskb_handle_user', to=settings.AUTH_USER_MODEL, verbose_name='操作人')),
|
||||
('mtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='b_mtask', to='pm.mtask', verbose_name='关联任务')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
from django.db import models
|
||||
from apps.utils.models import CommonADModel, CommonBDModel
|
||||
from apps.utils.models import CommonADModel, CommonBDModel, BaseModel
|
||||
from apps.mtm.models import Material, Mgroup, RoutePack, Route
|
||||
|
||||
# Create your models here.
|
||||
|
@ -111,3 +111,14 @@ class Mtask(CommonADModel):
|
|||
def mlogs(self):
|
||||
from apps.wpm.models import Mlog
|
||||
return Mlog.objects.filter(mtask=self)
|
||||
|
||||
@property
|
||||
def mtaskb(self):
|
||||
return Mtaskb.objects.filter(mtask=self)
|
||||
|
||||
|
||||
class Mtaskb(BaseModel):
|
||||
mtask = models.ForeignKey(Mtask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='b_mtask')
|
||||
handle_user = models.ForeignKey(
|
||||
'system.user', verbose_name='操作人', on_delete=models.CASCADE, related_name='mtaskb_handle_user')
|
||||
count = models.PositiveIntegerField('任务数', default=0)
|
|
@ -3,11 +3,12 @@ from rest_framework.exceptions import ValidationError, ParseError
|
|||
import math
|
||||
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
from apps.pm.models import Mtask, Utask, SCHEDULE_TYPE
|
||||
from apps.pm.models import Mtask, Utask, SCHEDULE_TYPE, Mtaskb
|
||||
from apps.sam.models import OrderItem
|
||||
from apps.utils.serializers import CustomModelSerializer
|
||||
from apps.system.models import Dept
|
||||
from apps.wpm.models import Mlog
|
||||
from apps.utils.constants import EXCLUDE_FIELDS_BASE
|
||||
|
||||
|
||||
class UtaskSerializer(CustomModelSerializer):
|
||||
|
@ -54,6 +55,25 @@ class MlogSimpleSerializer(CustomModelSerializer):
|
|||
fields = ['id', 'shift_name', 'count_use',
|
||||
'count_ok', 'count_real', 'submit_time']
|
||||
|
||||
class MtaskbAddSerializer(CustomModelSerializer):
|
||||
handle_user_name = serializers.StringRelatedField(
|
||||
source='handle_user.name', read_only=True)
|
||||
class Meta:
|
||||
model = Mtaskb
|
||||
fields = ['id', 'handle_user', 'handle_user_name', 'count']
|
||||
|
||||
class MtaskbSerializer(CustomModelSerializer):
|
||||
handle_user_name = serializers.StringRelatedField(
|
||||
source='handle_user.name', read_only=True)
|
||||
class Meta:
|
||||
model = Mtaskb
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE
|
||||
|
||||
class MtaskbUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mtaskb
|
||||
fields = ['id', 'count']
|
||||
|
||||
class MtaskSerializer(CustomModelSerializer):
|
||||
material_out_ = MaterialSimpleSerializer(
|
||||
|
@ -66,6 +86,7 @@ class MtaskSerializer(CustomModelSerializer):
|
|||
source='submit_user.name', read_only=True)
|
||||
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
||||
mlogs = MlogSimpleSerializer(label='日志信息', many=True, required=False)
|
||||
mtaskb = MtaskbSerializer(label='子任务信息', many=True, required=False, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Mtask
|
||||
|
@ -109,4 +130,4 @@ class MtaskDaySerializer(serializers.Serializer):
|
|||
class MtaskAddInfoSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mtask
|
||||
fields = ['peifen_kg']
|
||||
fields = ['peifen_kg']
|
|
@ -311,6 +311,8 @@ class PmService:
|
|||
now = timezone.now()
|
||||
if mtask.state == Mtask.MTASK_ASSGINED:
|
||||
mlogs = Mlog.objects.filter(mtask=mtask)|Mlog.objects.filter(b_mlog__mtask=mtask)
|
||||
if not mlogs.exists():
|
||||
raise ParseError('该任务没有日志')
|
||||
if mlogs.filter(submit_time__isnull=True).exists():
|
||||
raise ParseError('存在未提交的日志')
|
||||
mtask.state = Mtask.MTASK_SUBMIT
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from apps.pm.views import (MtaskViewSet, UtaskViewSet)
|
||||
from apps.pm.views import (MtaskViewSet, UtaskViewSet, MtaskbViewSet)
|
||||
|
||||
API_BASE_URL = 'api/pm/'
|
||||
HTML_BASE_URL = 'pm/'
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('mtask', MtaskViewSet, basename='mtask')
|
||||
router.register('mtaskb', MtaskbViewSet, basename='mtaskb')
|
||||
router.register('utask', UtaskViewSet, basename='utask')
|
||||
urlpatterns = [
|
||||
path(API_BASE_URL, include(router.urls)),
|
||||
|
|
|
@ -8,9 +8,11 @@ from apps.utils.serializers import PkSerializer
|
|||
from apps.utils.viewsets import CustomModelViewSet
|
||||
|
||||
from .filters import MtaskFilter, UtaskFilter
|
||||
from .models import Mtask, Utask
|
||||
from .models import Mtask, Utask, Mtaskb
|
||||
from .serializers import (MtaskSerializer, SchedueSerializer, UtaskSerializer,
|
||||
MtaskDaySerializer, MtaskAddInfoSerializer, SchedueMtasksSerializer)
|
||||
MtaskDaySerializer, MtaskAddInfoSerializer,
|
||||
SchedueMtasksSerializer, MtaskbSerializer,
|
||||
MtaskbUpdateSerializer, MtaskbAddSerializer)
|
||||
from .services import PmService
|
||||
from django.utils import timezone
|
||||
|
||||
|
@ -129,7 +131,7 @@ class MtaskViewSet(CustomModelViewSet):
|
|||
serializer_class = MtaskSerializer
|
||||
filterset_class = MtaskFilter
|
||||
select_related_fields = ['material_in', 'material_out', 'mgroup']
|
||||
prefetch_related_fields = ['mlog_mtask']
|
||||
prefetch_related_fields = ['mlog_mtask', 'b_mtask']
|
||||
ordering_fields = ['start_date', 'mgroup__process__sort', 'create_time']
|
||||
ordering = ['-start_date', 'mgroup__process__sort', '-create_time']
|
||||
|
||||
|
@ -204,3 +206,38 @@ class MtaskViewSet(CustomModelViewSet):
|
|||
sr.is_valid(raise_exception=True)
|
||||
sr.save()
|
||||
return Response()
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post': 'mtaskb.create'}, serializer_class=MtaskbAddSerializer)
|
||||
@transaction.atomic
|
||||
def add_mtaskb(self, request, *args, **kwargs):
|
||||
mtask = self.get_object()
|
||||
if mtask.state != Mtask.MTASK_ASSGINED:
|
||||
raise ParseError('该任务不可分配')
|
||||
sr = MtaskbAddSerializer(data=request.data, many=True)
|
||||
sr.is_valid(raise_exception=True)
|
||||
vdata = sr.validated_data
|
||||
total = 0
|
||||
userIds = []
|
||||
for v in vdata:
|
||||
total += v['count']
|
||||
userIds.append(v['handle_user'].id)
|
||||
if total != mtask.count:
|
||||
raise ParseError('任务数量与分配数量不匹配')
|
||||
for v in vdata:
|
||||
mtaskb, _ = Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user'])
|
||||
mtaskb.count = v['count']
|
||||
mtaskb.save()
|
||||
dobjs = Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds)
|
||||
from apps.wpm.models import Mlog
|
||||
if Mlog.objects.filter(mtaskb__in=dobjs).exists():
|
||||
raise ParseError('已存在工作日志,无法修改分配')
|
||||
else:
|
||||
dobjs.delete()
|
||||
return Response()
|
||||
|
||||
class MtaskbViewSet(CustomModelViewSet):
|
||||
queryset = Mtaskb.objects.all()
|
||||
serializer_class = MtaskbSerializer
|
||||
update_serializer_class = MtaskbUpdateSerializer
|
||||
filterset_fields = {"mtask": ["exact"], "handle_user": ["exact"], "mtask__mgroup": ["exact"]}
|
||||
ordering = ['id']
|
|
@ -30,7 +30,10 @@ class FtestWorkFilter(filters.FilterSet):
|
|||
fields = {
|
||||
"material__process__name": ["exact", "contains"],
|
||||
"material": ["exact"],
|
||||
"wm": ["exact"],
|
||||
"mb": ["exact"],
|
||||
"batch": ["exact"],
|
||||
"type": ["exact"],
|
||||
"type2": ["exact"],
|
||||
"shift": ["exact"]
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2024-08-30 05:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('qm', '0021_ftestwork_mb'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ftestwork',
|
||||
name='count_sampling_ok',
|
||||
field=models.IntegerField(default=0, verbose_name='抽检合格数量'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-02 07:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('qm', '0022_ftestwork_count_sampling_ok'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ftestwork',
|
||||
name='need_update_wm',
|
||||
field=models.BooleanField(default=True, verbose_name='是否更新车间库存'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-11 08:28
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0041_process_mstate_json'),
|
||||
('qm', '0023_ftestwork_need_update_wm'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='ftestwork',
|
||||
name='shift',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.shift', verbose_name='班次'),
|
||||
),
|
||||
]
|
|
@ -1,7 +1,7 @@
|
|||
from django.db import models
|
||||
from apps.system.models import CommonAModel, CommonADModel, User
|
||||
from apps.utils.models import CommonBDModel, BaseModel
|
||||
from apps.mtm.models import Material, Mgroup, Team
|
||||
from apps.mtm.models import Material, Mgroup, Team, Shift
|
||||
from apps.wpm.models import SfLog, WMaterial
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
@ -56,6 +56,8 @@ class NotOkOption(models.TextChoices):
|
|||
z = "z", _("脏")
|
||||
zhg = "zhg", _("准合格")
|
||||
yz = "yz", _("圆准")
|
||||
|
||||
jgqbl = "jgqbl", _("加工前不良")
|
||||
|
||||
qt = "qt", _("其它")
|
||||
|
||||
|
@ -109,6 +111,7 @@ class FtestWork(CommonBDModel):
|
|||
"""
|
||||
type = models.CharField('检验类型', max_length=20, choices=FTEST_TYPE_CHOICES, default='prod')
|
||||
type2 = models.PositiveSmallIntegerField('检验类型2', choices=((10, '抽检'), (20, '全检')), default=10)
|
||||
shift = models.ForeignKey(Shift, verbose_name='班次', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
mb = models.ForeignKey('inm.materialbatch', verbose_name='关联仓库', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
test_date = models.DateField('检验日期')
|
||||
|
@ -117,8 +120,10 @@ class FtestWork(CommonBDModel):
|
|||
batch = models.CharField('生产批次', max_length=50)
|
||||
count = models.IntegerField('检验数量')
|
||||
count_sampling = models.IntegerField('抽检数量', default=0)
|
||||
count_sampling_ok = models.IntegerField('抽检合格数量', default=0)
|
||||
count_ok = models.IntegerField('合格数量', default=0)
|
||||
count_notok = models.IntegerField('不合格数量', default=0)
|
||||
need_update_wm = models.BooleanField('是否更新车间库存', default=True)
|
||||
count_notok_json = models.JSONField('不合格项数量统计', default=dict, null=False, blank=True)
|
||||
test_user = models.ForeignKey(
|
||||
User, verbose_name='操作人', on_delete=models.CASCADE, related_name='ftestwork_test_user', null=True, blank=True)
|
||||
|
|
|
@ -66,7 +66,7 @@ class QuaStatUpdateSerializer(CustomModelSerializer):
|
|||
class FtestWorkCreateUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = FtestWork
|
||||
fields = ['id', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_ok', 'count_notok', 'count_notok_json', 'test_user']
|
||||
fields = ['id', 'shift', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_sampling_ok', 'count_ok', 'count_notok', 'count_notok_json', 'test_user', 'need_update_wm']
|
||||
extra_kwargs = {'test_user': {'required': True}, 'type': {'required': True}}
|
||||
|
||||
def validate(self, attrs):
|
||||
|
@ -99,6 +99,8 @@ class FtestWorkCreateUpdateSerializer(CustomModelSerializer):
|
|||
attrs['batch'] = attrs['mb'].batch
|
||||
else:
|
||||
raise ValidationError('请选择车间/仓库库存')
|
||||
if attrs['test_user']:
|
||||
attrs['belong_dept'] = attrs['test_user'].belong_dept
|
||||
return attrs
|
||||
|
||||
|
||||
|
@ -107,6 +109,7 @@ class FtestWorkSerializer(CustomModelSerializer):
|
|||
source='material', read_only=True)
|
||||
material_cate = serializers.CharField(source='material.cate', read_only=True)
|
||||
mb_ = MaterialBatchDetailSerializer(source='mb', read_only=True)
|
||||
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = FtestWork
|
||||
|
|
|
@ -7,67 +7,68 @@ from django.utils import timezone
|
|||
|
||||
def ftestwork_submit(ins:FtestWork, user: User):
|
||||
wm:WMaterial = ins.wm
|
||||
if wm.state == WMaterial.WM_TEST:
|
||||
# 更新对应的车间库存
|
||||
wm.count = wm.count - ins.count
|
||||
if wm.count >= 0:
|
||||
# 已检测的数量
|
||||
wm.count_xtest = wm.count_xtest + ins.count
|
||||
wm.save()
|
||||
else:
|
||||
raise ParseError("超过待检数量")
|
||||
# 生成合格的
|
||||
count_ok = ins.count_ok
|
||||
if count_ok > 0:
|
||||
wm, new_create = WMaterial.objects.get_or_create(
|
||||
material=wm.material,
|
||||
batch=wm.batch,
|
||||
mgroup=wm.mgroup,
|
||||
belong_dept=wm.belong_dept,
|
||||
state=WMaterial.WM_OK,
|
||||
defaults={
|
||||
'count': count_ok,
|
||||
'material': wm.material,
|
||||
'batch': wm.batch,
|
||||
'mgroup': wm.mgroup,
|
||||
'belong_dept': wm.belong_dept,
|
||||
}
|
||||
)
|
||||
if not new_create:
|
||||
wm.count = wm.count + count_ok
|
||||
if ins.need_update_wm:
|
||||
if wm.state == WMaterial.WM_TEST:
|
||||
# 更新对应的车间库存
|
||||
wm.count = wm.count - ins.count
|
||||
if wm.count >= 0:
|
||||
# 已检测的数量
|
||||
wm.count_xtest = wm.count_xtest + ins.count
|
||||
wm.save()
|
||||
else:
|
||||
wm.count = wm.count - ins.count_notok
|
||||
if wm.count >= 0:
|
||||
wm.save()
|
||||
else:
|
||||
raise ParseError("超过待检数量")
|
||||
# 生成合格的
|
||||
count_ok = ins.count_ok
|
||||
if count_ok > 0:
|
||||
wm, new_create = WMaterial.objects.get_or_create(
|
||||
material=wm.material,
|
||||
batch=wm.batch,
|
||||
mgroup=wm.mgroup,
|
||||
belong_dept=wm.belong_dept,
|
||||
state=WMaterial.WM_OK,
|
||||
defaults={
|
||||
'count': count_ok,
|
||||
'material': wm.material,
|
||||
'batch': wm.batch,
|
||||
'mgroup': wm.mgroup,
|
||||
'belong_dept': wm.belong_dept,
|
||||
}
|
||||
)
|
||||
if not new_create:
|
||||
wm.count = wm.count + count_ok
|
||||
wm.save()
|
||||
else:
|
||||
raise ParseError("不合格数不可大于批次数量")
|
||||
|
||||
# 生成不合格的
|
||||
count_notok_json = ins.count_notok_json
|
||||
for k, v in count_notok_json.items():
|
||||
if v > 0:
|
||||
notok_sign = k.replace('count_n_', '')
|
||||
wm_n, new_create = WMaterial.objects.get_or_create(
|
||||
material=wm.material,
|
||||
batch=wm.batch,
|
||||
mgroup=wm.mgroup,
|
||||
belong_dept=wm.belong_dept,
|
||||
notok_sign=notok_sign,
|
||||
state=WMaterial.WM_NOTOK,
|
||||
defaults={
|
||||
'count': v,
|
||||
'material': wm.material,
|
||||
'batch': wm.batch,
|
||||
'mgroup': wm.mgroup,
|
||||
'belong_dept': wm.belong_dept,
|
||||
'notok_sign': notok_sign,
|
||||
'state': WMaterial.WM_NOTOK,
|
||||
}
|
||||
)
|
||||
if not new_create:
|
||||
wm_n.count = wm_n.count + v
|
||||
wm_n.save()
|
||||
wm.count = wm.count - ins.count_notok
|
||||
if wm.count >= 0:
|
||||
wm.save()
|
||||
else:
|
||||
raise ParseError("不合格数不可大于批次数量")
|
||||
|
||||
# 生成不合格的
|
||||
count_notok_json = ins.count_notok_json
|
||||
for k, v in count_notok_json.items():
|
||||
if v > 0:
|
||||
notok_sign = k.replace('count_n_', '')
|
||||
wm_n, new_create = WMaterial.objects.get_or_create(
|
||||
material=wm.material,
|
||||
batch=wm.batch,
|
||||
mgroup=wm.mgroup,
|
||||
belong_dept=wm.belong_dept,
|
||||
notok_sign=notok_sign,
|
||||
state=WMaterial.WM_NOTOK,
|
||||
defaults={
|
||||
'count': v,
|
||||
'material': wm.material,
|
||||
'batch': wm.batch,
|
||||
'mgroup': wm.mgroup,
|
||||
'belong_dept': wm.belong_dept,
|
||||
'notok_sign': notok_sign,
|
||||
'state': WMaterial.WM_NOTOK,
|
||||
}
|
||||
)
|
||||
if not new_create:
|
||||
wm_n.count = wm_n.count + v
|
||||
wm_n.save()
|
||||
ins.submit_user = user
|
||||
ins.submit_time = timezone.now()
|
||||
ins.save()
|
|
@ -0,0 +1,111 @@
|
|||
from apps.utils.viewsets import GenericViewSet
|
||||
from rest_framework.decorators import action
|
||||
from apps.em.models import Equipment
|
||||
from apps.wpm.models import Mlog, Handover
|
||||
from apps.mtm.models import Mgroup
|
||||
from django.utils import timezone
|
||||
from django.db.models import Sum
|
||||
from datetime import datetime, timedelta
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import Serializer
|
||||
from apps.inm.models import MIOItem, MIO
|
||||
|
||||
def tran_time_to_mstate(mstate_json, reminder_interval_list, work_start_time: datetime, now: datetime):
|
||||
if len(reminder_interval_list) != len(mstate_json):
|
||||
return '未运行'
|
||||
xval = 0
|
||||
for ind, val in enumerate(reminder_interval_list):
|
||||
xval += val
|
||||
if work_start_time + timedelta(minutes=xval) > now:
|
||||
return mstate_json[ind]['name']
|
||||
return '未运行'
|
||||
|
||||
class AnaViewSet(GenericViewSet):
|
||||
perms_map = {}
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer)
|
||||
def equip_last_mlog(self, request):
|
||||
"""设备最后生产日志
|
||||
|
||||
设备最后生产日志
|
||||
"""
|
||||
data = request.data
|
||||
now = timezone.now()
|
||||
mgroup: Mgroup = Mgroup.objects.get(name=data['mgroup_name'])
|
||||
# 子状态
|
||||
mstate_json = mgroup.process.mstate_json
|
||||
# 生产设备
|
||||
equip_qs = Equipment.objects.filter(mgroup=mgroup, type = 10)
|
||||
equip_qs_v = equip_qs.values('id', 'name', 'number', 'state').order_by('number')
|
||||
equip_qs_l = list(equip_qs_v)
|
||||
# 设备最后生产日志
|
||||
mlog_qs_0 = Mlog.objects.filter(equipment__in=equip_qs, mgroup=mgroup)
|
||||
mlog_qs = mlog_qs_0.exclude(work_end_time__lt=now)
|
||||
mlog_qs = mlog_qs.annotate(t_count_use=Sum('b_mlog__count_use'))
|
||||
mlog_qs = mlog_qs.order_by('work_start_time')
|
||||
mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time', 'work_end_time')
|
||||
mlog_qs_l = list(mlog_qs_v)
|
||||
mlog_dict = {item['equipment__id']: item for item in mlog_qs_l}
|
||||
|
||||
# 统计数据
|
||||
保温 = 0
|
||||
冷却 = 0
|
||||
未运行 = 0
|
||||
故障 = 0
|
||||
now = timezone.now()
|
||||
for item in equip_qs_l:
|
||||
item['mstate'] = '未运行'
|
||||
if item['id'] in mlog_dict:
|
||||
mlog_dict_v = mlog_dict[item['id']]
|
||||
item['t_count_use'] = mlog_dict_v['t_count_use']
|
||||
item['reminder_interval_list'] = mlog_dict_v['reminder_interval_list']
|
||||
item['work_start_time'] = timezone.localtime(mlog_dict_v['work_start_time']).strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_start_time'] else None
|
||||
item['work_end_time'] = timezone.localtime(mlog_dict_v['work_end_time']).strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_end_time'] else None
|
||||
item['mstate'] = tran_time_to_mstate(mstate_json, mlog_dict_v['reminder_interval_list'], mlog_dict_v['work_start_time'], now)
|
||||
|
||||
if item['state'] in [Equipment.EQUIP_STATE_SCRAP, Equipment.EQUIP_STATE_FIX]:
|
||||
item['mstate'] = '故障'
|
||||
|
||||
if item['mstate'] == '保温':
|
||||
保温 += 1
|
||||
elif item['mstate'] == '冷却':
|
||||
冷却 += 1
|
||||
elif item['mstate'] == '未运行':
|
||||
未运行 += 1
|
||||
elif item['mstate'] == '故障':
|
||||
故障 += 1
|
||||
ret = {"保温": 保温, "冷却": 冷却, "未运行": 未运行, "故障": 故障}
|
||||
ret['mstate_json'] = mstate_json
|
||||
ret['now'] = timezone.localtime(now).strftime('%Y-%m-%d %H:%M:%S')
|
||||
ret["rows"] = equip_qs_l
|
||||
return Response(ret)
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer)
|
||||
def put_prod(self, request):
|
||||
"""
|
||||
投产分析
|
||||
"""
|
||||
now = timezone.now()
|
||||
now_2 = now.replace(hour=2, minute=0, second=0, microsecond=0)
|
||||
mgroup: Mgroup = Mgroup.objects.get(name='退火')
|
||||
# 子状态
|
||||
mstate_json = mgroup.process.mstate_json
|
||||
ret = {}
|
||||
ret['今日退火投产预测'] = 0
|
||||
ret['明日退火投产预测'] = 0
|
||||
ret['rows'] = {}
|
||||
# 生产记录/今日退火投产预测
|
||||
# 昨日2点
|
||||
now_2_yesterday = now_2 - timedelta(days=1)
|
||||
|
||||
mlog_qs_0 = Mlog.objects.filter(mgroup=mgroup)
|
||||
mlog_qs = mlog_qs_0.exclude(work_end_time__lt=now_2_yesterday).annotate(t_count_use=Sum('b_mlog__count_use')).order_by('work_start_time')
|
||||
mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time', 'work_end_time')
|
||||
mlog_qs_l = list(mlog_qs_v)
|
||||
|
||||
for item in mlog_qs_l:
|
||||
if tran_time_to_mstate(mstate_json, item['reminder_interval_list'], item['work_start_time'], now) == '冷却':
|
||||
if item['work_end_time'] is None or item['work_end_time'] > now_2:
|
||||
ret['明日退火投产预测'] += item['t_count_use']
|
||||
ret['今日退火投产预测'] += item['t_count_use']
|
||||
|
||||
return Response(ret)
|
|
@ -50,7 +50,8 @@ class WMaterialFilter(filters.FilterSet):
|
|||
"mgroup__name": ["exact", "in"],
|
||||
"count": ["gte", "lte", "exact"],
|
||||
"notok_sign": ["exact", "in", "isnull"],
|
||||
"count_xtest": ["gte", "isnull"]
|
||||
"count_xtest": ["gte", "isnull"],
|
||||
"supplier": ["exact"],
|
||||
}
|
||||
|
||||
class MlogFilter(filters.FilterSet):
|
||||
|
@ -65,15 +66,20 @@ class MlogFilter(filters.FilterSet):
|
|||
"mtask__mgroup__belong_dept__name": ["exact", "contains", "in"],
|
||||
"mgroup__belong_dept__name": ["exact", "in", "contains"],
|
||||
"mgroup__name": ["exact", "in", "contains"],
|
||||
"submit_time": ["isnull"]
|
||||
"submit_time": ["isnull"],
|
||||
"fmlog": ["exact"]
|
||||
}
|
||||
|
||||
|
||||
class HandoverFilter(filters.FilterSet):
|
||||
mgroup = filters.CharFilter(label='MgroupId', method='filter_mgroup')
|
||||
dept = filters.CharFilter(label='DeptId', method='filter_dept')
|
||||
|
||||
def filter_mgroup(self, queryset, name, value):
|
||||
return queryset.filter(send_mgroup__id=value)|queryset.filter(recive_mgroup__id=value)
|
||||
|
||||
def filter_dept(self, queryset, name, value):
|
||||
return queryset.filter(send_dept__id=value)|queryset.filter(recive_dept__id=value)
|
||||
|
||||
class Meta:
|
||||
model = Handover
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.12 on 2024-08-30 01:17
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pum', '0008_auto_20240731_1829'),
|
||||
('wpm', '0062_auto_20240828_1052'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='wmaterial',
|
||||
name='supplier',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pum.supplier', verbose_name='外协供应商'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-02 06:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0063_wmaterial_supplier'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='count_pn_jgqbl',
|
||||
field=models.PositiveIntegerField(default=0, verbose_name='加工前不良'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlogb',
|
||||
name='count_pn_jgqbl',
|
||||
field=models.PositiveIntegerField(default=0, verbose_name='加工前不良'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-03 01:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wf', '0002_alter_state_filter_dept'),
|
||||
('wpm', '0064_auto_20240902_1411'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='oinfo_json',
|
||||
field=models.JSONField(blank=True, default=dict, verbose_name='其他信息'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='ticket',
|
||||
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mlog_ticket', to='wf.ticket', verbose_name='关联工单'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,28 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-03 06:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0065_auto_20240903_0904'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='test_file',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='检验文件'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlogb',
|
||||
name='count_notok_json',
|
||||
field=models.JSONField(blank=True, default=list, verbose_name='不合格情况'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlogb',
|
||||
name='note',
|
||||
field=models.TextField(blank=True, default='', verbose_name='备注'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,42 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-04 01:03
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0041_process_mstate_json'),
|
||||
('pm', '0020_mtaskb'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('wpm', '0066_auto_20240903_1401'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Fmlog',
|
||||
fields=[
|
||||
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('note', models.TextField(blank=True, default='', verbose_name='备注')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='fmlog_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('mgroup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fmlog_mgroup', to='mtm.mgroup', verbose_name='工段')),
|
||||
('mtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fmlog_mtask', to='pm.mtask', verbose_name='任务')),
|
||||
('route', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.route', verbose_name='生产路线')),
|
||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='fmlog_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='fmlog',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mlog_fmlog', to='wpm.fmlog', verbose_name='关联生产日志'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,37 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-04 07:49
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pm', '0020_mtaskb'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('wpm', '0067_auto_20240904_0903'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='mtaskb',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlog_mtaskb', to='pm.mtaskb', verbose_name='关联个人任务'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='test_time',
|
||||
field=models.DateTimeField(blank=True, null=True, verbose_name='检验时间'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='mlog',
|
||||
name='test_user',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlog_test_user', to=settings.AUTH_USER_MODEL, verbose_name='检验人'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='mlog',
|
||||
name='fill_way',
|
||||
field=models.PositiveSmallIntegerField(default=10, help_text='10:仅二级;20:二三级;30:一二级', verbose_name='填写方式'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,40 @@
|
|||
# Generated by Django 3.2.12 on 2024-09-05 02:57
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0068_auto_20240904_1549'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='handover',
|
||||
name='batch',
|
||||
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='批次号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='handover',
|
||||
name='type',
|
||||
field=models.PositiveSmallIntegerField(choices=[(10, '正常交接'), (20, '返修交接'), (30, '检验交接'), (40, '报废交接')], default=10, verbose_name='交接类型'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Handoverb',
|
||||
fields=[
|
||||
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
|
||||
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||
('count', models.PositiveIntegerField(default=0, verbose_name='送料数')),
|
||||
('handover', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.handover', verbose_name='关联交接记录')),
|
||||
('wm', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='handoverb_wm', to='wpm.wmaterial', verbose_name='关联车间库存')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,13 +1,14 @@
|
|||
from django.db import models
|
||||
from apps.utils.models import CommonADModel, CommonBDModel, BaseModel
|
||||
from apps.mtm.models import Mgroup, Team, Shift, Material, Route
|
||||
from apps.pm.models import Mtask
|
||||
from apps.pm.models import Mtask, Mtaskb
|
||||
from apps.system.models import User
|
||||
from django.utils.timezone import localtime
|
||||
from apps.em.models import Equipment
|
||||
from apps.system.models import Dept
|
||||
from datetime import timedelta
|
||||
from apps.pum.models import Supplier
|
||||
from django.db.models import Sum
|
||||
|
||||
# Create your models here.
|
||||
|
||||
|
@ -97,6 +98,7 @@ class WMaterial(CommonBDModel):
|
|||
state = models.PositiveSmallIntegerField('状态', default=10, choices=((10, '合格'), (20, '不合格'), (30, '返修'), (40, '检验'), (50, '报废')))
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='物料', on_delete=models.CASCADE, related_name='wm_m')
|
||||
supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
mgroup = models.ForeignKey(Mgroup, verbose_name='所在工段', on_delete=models.CASCADE, null=True, blank=True)
|
||||
batch = models.CharField('批次号', max_length=50)
|
||||
count = models.PositiveIntegerField('当前数量', default=0)
|
||||
|
@ -105,17 +107,29 @@ class WMaterial(CommonBDModel):
|
|||
material_origin = models.ForeignKey(Material, verbose_name='原始物料', on_delete=models.SET_NULL, null=True, blank=True, related_name='wm_mo')
|
||||
count_xtest = models.PositiveIntegerField('已检数量', null=True, blank=True)
|
||||
|
||||
@property
|
||||
def count_working(self):
|
||||
return int(Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count'] or 0)
|
||||
|
||||
class Fmlog(CommonADModel):
|
||||
route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
mtask = models.ForeignKey(Mtask, verbose_name='任务', on_delete=models.CASCADE, related_name='fmlog_mtask')
|
||||
mgroup = models.ForeignKey(Mgroup, verbose_name='工段', on_delete=models.CASCADE, related_name='fmlog_mgroup')
|
||||
note = models.TextField('备注', default='', blank=True)
|
||||
|
||||
class Mlog(CommonADModel):
|
||||
"""
|
||||
生产日志
|
||||
"""
|
||||
# 变成父级的字段
|
||||
MLOG_ONETIME = 10
|
||||
MLOG_STEP = 20
|
||||
MLOG_2 = 10
|
||||
MLOG_23 = 20
|
||||
MLOG_12 = 30
|
||||
MTYPE_SELF = 10
|
||||
MTYPE_OUT = 20
|
||||
fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:一次填写;20:分步填写')
|
||||
fmlog = models.ForeignKey(Fmlog, verbose_name='关联生产日志', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_fmlog')
|
||||
mtaskb = models.ForeignKey(Mtaskb, verbose_name='关联个人任务', on_delete=models.CASCADE, related_name='mlog_mtaskb', null=True, blank=True)
|
||||
fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:仅二级;20:二三级;30:一二级')
|
||||
mtype = models.PositiveSmallIntegerField('生产类型', default=10, help_text='10:自生产;20:外协生产', choices=((10, '自生产'), (20, '外协生产')))
|
||||
supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True)
|
||||
|
@ -154,6 +168,7 @@ class Mlog(CommonADModel):
|
|||
count_notok = models.PositiveIntegerField('不合格数', default=0)
|
||||
count_break_t = models.PositiveIntegerField('检验碎料数', default=0)
|
||||
|
||||
count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0)
|
||||
count_n_zw = models.PositiveIntegerField('炸纹', default=0)
|
||||
count_n_tw = models.PositiveIntegerField('条纹', default=0)
|
||||
count_n_qp = models.PositiveIntegerField('气泡', default=0)
|
||||
|
@ -191,8 +206,6 @@ class Mlog(CommonADModel):
|
|||
count_n_yd = models.PositiveIntegerField('圆度', default=0)
|
||||
count_n_txd = models.PositiveIntegerField('同心度', default=0)
|
||||
count_n_hd = models.PositiveIntegerField('厚度', default=0)
|
||||
|
||||
|
||||
count_n_qt = models.PositiveIntegerField('其他', default=0)
|
||||
|
||||
handle_date = models.DateField('操作日期', null=True, blank=True)
|
||||
|
@ -212,6 +225,14 @@ class Mlog(CommonADModel):
|
|||
submit_user = models.ForeignKey(
|
||||
User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_submit_user')
|
||||
|
||||
oinfo_json = models.JSONField('其他信息', default=dict, blank=True)
|
||||
ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单',
|
||||
on_delete=models.SET_NULL, related_name='mlog_ticket', null=True, blank=True, db_constraint=False)
|
||||
test_file = models.TextField('检验文件', null=True, blank=True)
|
||||
test_user = models.ForeignKey(
|
||||
User, verbose_name='检验人', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_test_user')
|
||||
test_time = models.DateTimeField('检验时间', null=True, blank=True)
|
||||
|
||||
@property
|
||||
def mlogb(self):
|
||||
return Mlogb.objects.filter(mlog=self).exclude(material_out=None)
|
||||
|
@ -229,6 +250,7 @@ class Mlog(CommonADModel):
|
|||
class Mlogb(BaseModel):
|
||||
mlog = models.ForeignKey(Mlog, verbose_name='关联日志',
|
||||
on_delete=models.CASCADE, related_name='b_mlog')
|
||||
note = models.TextField('备注', default='', blank=True)
|
||||
batch = models.CharField('批次号', max_length=50, null=True, blank=True)
|
||||
mtask = models.ForeignKey(Mtask, verbose_name='关联任务',
|
||||
on_delete=models.CASCADE, related_name='mlogb_mtask', null=True, blank=True)
|
||||
|
@ -245,6 +267,7 @@ class Mlogb(BaseModel):
|
|||
count_ok = models.PositiveIntegerField('合格数量', default=0)
|
||||
count_notok = models.PositiveIntegerField('不合格数', default=0)
|
||||
|
||||
count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0)
|
||||
# 添加不合格字段后需要更改cal_mlog_count_from_mlogb
|
||||
count_n_hs = models.PositiveIntegerField('划伤', default=0)
|
||||
count_n_qp = models.PositiveIntegerField('气泡', default=0)
|
||||
|
@ -260,6 +283,7 @@ class Mlogb(BaseModel):
|
|||
count_n_txd = models.PositiveIntegerField('同心度', default=0)
|
||||
count_n_hd = models.PositiveIntegerField('厚度', default=0)
|
||||
count_n_qt = models.PositiveIntegerField('其他', default=0)
|
||||
count_notok_json = models.JSONField('不合格情况', default=list, blank=True)
|
||||
|
||||
class Handover(CommonADModel):
|
||||
"""
|
||||
|
@ -268,7 +292,8 @@ class Handover(CommonADModel):
|
|||
H_NORMAL = 10
|
||||
H_REPAIR = 20
|
||||
H_TEST = 30
|
||||
type = models.PositiveSmallIntegerField('交接类型', choices=[(H_NORMAL, '正常交接'), (H_REPAIR, '返修交接'), (H_TEST, '检验交接')], default=H_NORMAL)
|
||||
H_SCRAP = 40
|
||||
type = models.PositiveSmallIntegerField('交接类型', choices=[(H_NORMAL, '正常交接'), (H_REPAIR, '返修交接'), (H_TEST, '检验交接'), (H_SCRAP, '报废交接')], default=H_NORMAL)
|
||||
send_date = models.DateField('送料日期')
|
||||
send_user = models.ForeignKey(
|
||||
User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user')
|
||||
|
@ -276,7 +301,7 @@ class Handover(CommonADModel):
|
|||
Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True)
|
||||
send_dept = models.ForeignKey(
|
||||
Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept')
|
||||
batch = models.CharField('批次号', max_length=50)
|
||||
batch = models.CharField('批次号', max_length=50, null=True, blank=True)
|
||||
material = models.ForeignKey(
|
||||
Material, verbose_name='物料', on_delete=models.CASCADE, related_name='h_ma')
|
||||
material_changed = models.ForeignKey(Material, verbose_name='变更后物料', on_delete=models.CASCADE, null=True, blank=True, related_name='h_ma_c')
|
||||
|
@ -298,6 +323,15 @@ class Handover(CommonADModel):
|
|||
submit_user = models.ForeignKey(
|
||||
User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='handover_submit_user')
|
||||
|
||||
@property
|
||||
def handoverb(self):
|
||||
return Handoverb.objects.filter(handover=self)
|
||||
|
||||
class Handoverb(BaseModel):
|
||||
handover = models.ForeignKey(Handover, verbose_name='关联交接记录', on_delete=models.CASCADE)
|
||||
wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL,
|
||||
null=True, blank=True, related_name='handoverb_wm')
|
||||
count = models.PositiveIntegerField('送料数', default=0)
|
||||
|
||||
class AttLog(CommonADModel):
|
||||
"""
|
||||
|
|
|
@ -4,12 +4,13 @@ from rest_framework import serializers
|
|||
from rest_framework.exceptions import ValidationError, ParseError
|
||||
from datetime import datetime
|
||||
|
||||
from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog
|
||||
from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog,
|
||||
Handover, Handoverb, Mlogb, AttLog, OtherLog, Fmlog)
|
||||
from apps.system.models import Dept, User
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
from apps.pm.models import Mtask
|
||||
from apps.pm.models import Mtask, Mtaskb
|
||||
from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change, cal_exp_duration_sec
|
||||
from apps.wpm.services import get_sflog, find_material_can_change
|
||||
from apps.wpm.services import get_sflog, find_material_can_change, generate_new_batch
|
||||
from apps.mtm.models import Mgroup, TeamMember, Shift, Material, Route
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
from django.db import transaction
|
||||
|
@ -17,7 +18,7 @@ from django.utils import timezone
|
|||
from django.core.cache import cache
|
||||
from django.utils.timezone import localdate
|
||||
from apps.qm.models import NotOkOption
|
||||
|
||||
from apps.wf.serializers import TicketSimpleSerializer
|
||||
|
||||
class OtherLogSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
|
@ -172,6 +173,7 @@ class SflogExpSerializer(CustomModelSerializer):
|
|||
|
||||
class WMaterialSerializer(CustomModelSerializer):
|
||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
||||
material_name = serializers.StringRelatedField(
|
||||
source='material', read_only=True)
|
||||
mgroup_name = serializers.StringRelatedField(source='mgroup.name', read_only=True)
|
||||
|
@ -179,6 +181,7 @@ class WMaterialSerializer(CustomModelSerializer):
|
|||
source='belong_dept.name', read_only=True)
|
||||
material_origin_name = serializers.StringRelatedField(source='material_origin', read_only=True)
|
||||
notok_sign_name = serializers.SerializerMethodField()
|
||||
count_working = serializers.CharField(read_only=True, label='在制数量')
|
||||
|
||||
def get_notok_sign_name(self, obj):
|
||||
return getattr(NotOkOption, obj.notok_sign, NotOkOption.qt).label if obj.notok_sign else None
|
||||
|
@ -211,7 +214,9 @@ class MlogbDetailSerializer(CustomModelSerializer):
|
|||
fields = '__all__'
|
||||
|
||||
class MlogSerializer(CustomModelSerializer):
|
||||
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)
|
||||
belong_dept = serializers.CharField(
|
||||
source='mgroup.belong_dept.id', read_only=True)
|
||||
belong_dept_name = serializers.CharField(
|
||||
|
@ -260,6 +265,8 @@ class MlogSerializer(CustomModelSerializer):
|
|||
source='handle_users', many=True, read_only=True)
|
||||
equipments_name = serializers.StringRelatedField(
|
||||
source='equipments', read_only=True, many=True)
|
||||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||||
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Mlog
|
||||
|
@ -271,21 +278,23 @@ class MlogSerializer(CustomModelSerializer):
|
|||
}
|
||||
|
||||
def create(self, validated_data):
|
||||
mtask: Mtask = validated_data.get('mtask', None)
|
||||
if mtask:
|
||||
validated_data['mgroup'] = mtask.mgroup
|
||||
validated_data['material_in'] = mtask.material_in
|
||||
material_out = mtask.material_out
|
||||
validated_data['material_out'] = material_out
|
||||
validated_data['handle_date'] = mtask.end_date
|
||||
else:
|
||||
mgroup = validated_data['mgroup']
|
||||
material_out = validated_data['material_out']
|
||||
if not (mgroup and material_out):
|
||||
raise ValidationError('缺少工段或产物!')
|
||||
material_out = validated_data['material_out']
|
||||
with transaction.atomic():
|
||||
mlogb = validated_data.pop('mlogb', [])
|
||||
instance: Mlog = super().create(validated_data)
|
||||
# 自动生成mlogb
|
||||
batch_in = instance.batch
|
||||
if instance.wm_in:
|
||||
batch_in = instance.wm_in.batch
|
||||
add_dict = {
|
||||
'mlog': instance, 'batch': batch_in, 'wm_in': instance.wm_in,
|
||||
'mtask': instance.mtask, 'material_in': instance.material_in,
|
||||
'count_use': instance.count_use, 'count_break': instance.count_break,
|
||||
'count_pn_jgqbl': instance.count_pn_jgqbl
|
||||
}
|
||||
Mlogb.objects.create(**add_dict)
|
||||
|
||||
# mlogb只用于组合件输出物填写
|
||||
brotherId_should_list = material_out.brothers
|
||||
if brotherId_should_list:
|
||||
if mlogb:
|
||||
|
@ -295,9 +304,29 @@ class MlogSerializer(CustomModelSerializer):
|
|||
mlog=instance, batch=instance.batch, mtask=instance.mtask, material_out=item['material_out'], count_ok=item['count_ok'])
|
||||
else:
|
||||
raise ValidationError('缺少产出物信息')
|
||||
else:
|
||||
# 生成产出物
|
||||
batch_out = validated_data.get('batch', None)
|
||||
if batch_out:
|
||||
pass
|
||||
else:
|
||||
batch_out = generate_new_batch(batch_in, instance)
|
||||
|
||||
add_dict_2 = {
|
||||
'mlog': instance, 'batch': batch_out,
|
||||
'mtask': instance.mtask, 'material_out': instance.material_out,
|
||||
'count_ok': instance.count_ok, 'count_notok': instance.count_notok,
|
||||
'count_break_t': instance.count_break_t
|
||||
}
|
||||
for f in Mlogb._meta.fields:
|
||||
if 'count_n_' in f.name:
|
||||
add_dict_2[f.name] = getattr(instance, f.name)
|
||||
Mlogb.objects.create(**add_dict_2)
|
||||
return instance
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if instance.fill_way == Mlog.MLOG_23:
|
||||
raise ParseError('不支持的填写类型')
|
||||
validated_data.pop('mtask', None)
|
||||
validated_data.pop('mgroup', None)
|
||||
if instance.mtask:
|
||||
|
@ -305,17 +334,70 @@ class MlogSerializer(CustomModelSerializer):
|
|||
# validated_data.pop('handle_user', None)
|
||||
with transaction.atomic():
|
||||
mlogb = validated_data.pop('mlogb', [])
|
||||
instance = super().update(instance, validated_data)
|
||||
if mlogb:
|
||||
instance: Mlog = super().update(instance, validated_data)
|
||||
if instance.fill_way == Mlog.MLOG_12:
|
||||
# 自动生成mlogb
|
||||
batch_in = instance.batch
|
||||
if instance.wm_in:
|
||||
batch_in = instance.wm_in.batch
|
||||
minx, _ = Mlogb.objects.get_or_create(
|
||||
mlog=instance,
|
||||
batch=batch_in,
|
||||
wm_in=instance.wm_in,
|
||||
mtask=instance.mtask,
|
||||
material_in=instance.material_in
|
||||
)
|
||||
minx.count_use = instance.count_use
|
||||
minx.count_break = instance.count_break
|
||||
minx.count_pn_jgqbl = instance.count_pn_jgqbl
|
||||
minx.save()
|
||||
|
||||
if mlogb and instance.fill_way == Mlog.MLOG_2:
|
||||
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).update(count_ok=0)
|
||||
for item in mlogb:
|
||||
Mlogb.objects.filter(mlog=instance, material_out=item['material_out']).update(
|
||||
count_ok=item['count_ok'])
|
||||
elif instance.fill_way == Mlog.MLOG_12:
|
||||
# 生成产出物
|
||||
batch_out = instance.batch
|
||||
if batch_out:
|
||||
pass
|
||||
else:
|
||||
batch_out = generate_new_batch(batch_in, instance)
|
||||
|
||||
mox, _ = Mlogb.objects.get_or_create(mlog=instance, batch=batch_out,
|
||||
mtask=instance.mtask, material_out=instance.material_out)
|
||||
mox.count_ok = instance.count_ok
|
||||
mox.count_notok = instance.count_notok
|
||||
mox.count_break_t = instance.count_break_t
|
||||
for f in Mlogb._meta.fields:
|
||||
if 'count_n_' in f.name:
|
||||
setattr(mox, f.name, getattr(instance, f.name))
|
||||
mox.save()
|
||||
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).exclude(id=mox.id).delete()
|
||||
return instance
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs['fill_way'] = Mlog.MLOG_ONETIME
|
||||
attrs['fill_way'] = Mlog.MLOG_2
|
||||
attrs['mtype'] = Mlog.MTYPE_SELF # 默认为自生产
|
||||
fmlog = attrs.get('fmlog', None)
|
||||
mtaskb = attrs.get('mtaskb', None)
|
||||
if fmlog:
|
||||
attrs['fill_way'] = Mlog.MLOG_12
|
||||
wm_in: WMaterial = attrs.get('wm_in', None)
|
||||
if wm_in:
|
||||
pass
|
||||
else:
|
||||
raise ParseError('未提供消耗的车间物料')
|
||||
attrs['route'] = fmlog.route
|
||||
attrs['mgroup'] = fmlog.mgroup
|
||||
attrs['mtask'] = fmlog.mtask
|
||||
if attrs['mtask'].mtaskb and mtaskb is None:
|
||||
raise ParseError('子任务不能为空')
|
||||
if mtaskb and mtaskb.mtask != fmlog.mtask:
|
||||
raise ParseError('子任务不一致')
|
||||
if wm_in.material != attrs['mtask'].material_in:
|
||||
raise ParseError('消耗物料与任务不一致')
|
||||
mtask = attrs.get('mtask', None)
|
||||
count_notok = 0
|
||||
for i in attrs:
|
||||
|
@ -330,17 +412,45 @@ class MlogSerializer(CustomModelSerializer):
|
|||
if mtask.start_date == mtask.end_date:
|
||||
attrs['handle_date'] = mtask.start_date
|
||||
else:
|
||||
if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date:
|
||||
pass
|
||||
else:
|
||||
raise ValidationError('操作日期错误')
|
||||
if attrs['work_end_time']:
|
||||
attrs['handle_date'] = attrs['work_end_time'].date()
|
||||
elif attrs['work_start_time']:
|
||||
attrs['handle_date'] = attrs['work_start_time'].date()
|
||||
# if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date:
|
||||
# pass
|
||||
# else:
|
||||
# if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date:
|
||||
# pass
|
||||
# else:
|
||||
# raise ValidationError('操作日期错误')
|
||||
mtaskb: Mtaskb = attrs.get('mtaskb', None)
|
||||
if mtaskb:
|
||||
mtask = mtaskb.mtask
|
||||
attrs['mtask'] = mtask
|
||||
attrs['handle_user'] = mtaskb.handle_user
|
||||
else:
|
||||
mtask: Mtask = attrs.get('mtask', None)
|
||||
if mtask:
|
||||
attrs['mgroup'] = mtask.mgroup
|
||||
attrs['material_in'] = mtask.material_in
|
||||
material_out = mtask.material_out
|
||||
attrs['material_out'] = material_out
|
||||
if mtask.start_date == mtask.end_date:
|
||||
attrs['handle_date'] = mtask.end_date
|
||||
else:
|
||||
mgroup = attrs['mgroup']
|
||||
material_out = attrs['material_out']
|
||||
if not (mgroup and material_out):
|
||||
raise ValidationError('缺少工段或产物!')
|
||||
return attrs
|
||||
|
||||
|
||||
class MlogInitSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mlog
|
||||
fields = ['id', 'work_start_time', 'mgroup', 'reminder_interval_list', 'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier']
|
||||
fields = ['id',
|
||||
'work_start_time', 'work_end_time', 'mgroup', 'reminder_interval_list',
|
||||
'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier', 'test_file', 'test_user', 'test_time', 'oinfo_json']
|
||||
extra_kwargs = {
|
||||
'work_start_time': {'required': True},
|
||||
'route':{'required': True},
|
||||
|
@ -357,17 +467,19 @@ class MlogInitSerializer(CustomModelSerializer):
|
|||
attrs['hour_work'] = route.hour_work
|
||||
attrs['material_in'] = route.material_in
|
||||
attrs['material_out'] = route.material_out
|
||||
attrs['fill_way'] = Mlog.MLOG_STEP
|
||||
attrs['fill_way'] = Mlog.MLOG_23
|
||||
if mtype == Mlog.MTYPE_OUT:
|
||||
supplier = attrs.get('supplier', None)
|
||||
if not supplier:
|
||||
raise ValidationError('外协必须选择外协单位')
|
||||
if attrs.get('work_end_time', None):
|
||||
attrs['handle_date'] = localdate(attrs['work_end_time'])
|
||||
return attrs
|
||||
|
||||
class MlogChangeSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mlog
|
||||
fields = ['id', 'work_end_time', 'handle_user', 'note']
|
||||
fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file', 'test_user', 'test_time']
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get('work_end_time', None):
|
||||
|
@ -378,12 +490,14 @@ class MlogChangeSerializer(CustomModelSerializer):
|
|||
class MlogbInSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mlogb
|
||||
fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use']
|
||||
fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_pn_jgqbl', 'count_break', 'note']
|
||||
extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}}
|
||||
|
||||
def validate(self, attrs):
|
||||
mlog: Mlog = attrs['mlog']
|
||||
mtask: Mtask = attrs['mtask']
|
||||
if mtask.state != Mtask.MTASK_ASSGINED:
|
||||
raise ValidationError('该任务非下达中不可选择')
|
||||
wm_in: WMaterial = attrs['wm_in']
|
||||
if wm_in.state != WMaterial.WM_OK:
|
||||
raise ValidationError('非合格品不可使用')
|
||||
|
@ -416,18 +530,41 @@ class MlogbInSerializer(CustomModelSerializer):
|
|||
class MlogbInUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mlogb
|
||||
fields = ['id', 'count_use', 'count_break']
|
||||
fields = ['id', 'count_use', 'count_break', 'count_pn_jgqbl', 'note']
|
||||
|
||||
class MlogbOutUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Mlogb
|
||||
fields = "__all__"
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break']
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_pn_jgqbl']
|
||||
|
||||
def validate(self, attrs):
|
||||
count_notok_json = attrs.get('count_notok_json', [])
|
||||
# count_notok_json字段处理
|
||||
if count_notok_json:
|
||||
# 先置0字段
|
||||
for i in attrs:
|
||||
if 'count_n_' in i:
|
||||
i = 0
|
||||
count_notok_dict = {}
|
||||
for item in count_notok_json:
|
||||
notok = item['notok']
|
||||
count = item['count']
|
||||
full_notok = f'count_n_{notok}'
|
||||
if not hasattr(Mlogb, full_notok):
|
||||
raise ValidationError(f'{notok}-该不合格项不存在')
|
||||
if full_notok in count_notok_dict:
|
||||
count_notok_dict[full_notok] = count_notok_dict[full_notok] + count
|
||||
else:
|
||||
count_notok_dict[full_notok] = count
|
||||
for k, v in count_notok_dict.items():
|
||||
attrs[k] = v
|
||||
|
||||
count_notok = 0
|
||||
for i in attrs:
|
||||
if 'count_n_' in i:
|
||||
if not hasattr(Mlogb, i):
|
||||
raise ValidationError(f'{i}不存在')
|
||||
count_notok = count_notok + attrs[i]
|
||||
attrs['count_notok'] = count_notok
|
||||
if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']:
|
||||
|
@ -448,6 +585,14 @@ class MlogRelatedSerializer(serializers.Serializer):
|
|||
class DeptBatchSerializer(serializers.Serializer):
|
||||
belong_dept_name = serializers.CharField(label='车间名称')
|
||||
|
||||
class HandoverbSerializer(CustomModelSerializer):
|
||||
batch = serializers.CharField(source='wm.batch', read_only=True)
|
||||
notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True)
|
||||
class Meta:
|
||||
model = Handoverb
|
||||
fields = "__all__"
|
||||
read_only_fields = EXCLUDE_FIELDS_BASE + ['handover']
|
||||
extra_kwargs = {'wm': {'required': True}}
|
||||
|
||||
class HandoverSerializer(CustomModelSerializer):
|
||||
# wm = serializers.PrimaryKeyRelatedField(
|
||||
|
@ -466,18 +611,28 @@ class HandoverSerializer(CustomModelSerializer):
|
|||
material_name = serializers.StringRelatedField(
|
||||
source='material', read_only=True)
|
||||
wm_notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True)
|
||||
handoverb = HandoverbSerializer(many=True)
|
||||
|
||||
def validate(self, attrs):
|
||||
if 'type' not in attrs:
|
||||
attrs['type'] = Handover.H_NORMAL
|
||||
wm:WMaterial = attrs['wm']
|
||||
material = wm.material
|
||||
wm:WMaterial = attrs.get('wm', None)
|
||||
handoverb = attrs.get('handoverb', [])
|
||||
if wm:
|
||||
attrs['handoverb'] = [{"wm": wm, "count": attrs["count"] }]
|
||||
handoverb = attrs['handoverb']
|
||||
attrs['batch'] = wm.batch
|
||||
elif handoverb:
|
||||
wm: WMaterial = handoverb[0]["wm"]
|
||||
if wm:
|
||||
pass
|
||||
else:
|
||||
raise ParseError('必须指定车间库存')
|
||||
attrs['material'] = wm.material
|
||||
attrs['batch'] = wm.batch
|
||||
attrs['send_dept'] = wm.belong_dept
|
||||
if attrs['wm'].mgroup:
|
||||
if wm.mgroup:
|
||||
attrs['send_mgroup'] = wm.mgroup
|
||||
if material.process and material.process.into_wm_mgroup and 'recive_mgroup' not in attrs:
|
||||
if attrs['material'].process and attrs['material'].process.into_wm_mgroup and 'recive_mgroup' not in attrs:
|
||||
raise ValidationError('必须指定交接工段')
|
||||
if 'recive_mgroup' in attrs and attrs['recive_mgroup']:
|
||||
attrs['recive_dept'] = attrs['recive_mgroup'].belong_dept
|
||||
|
@ -485,10 +640,24 @@ class HandoverSerializer(CustomModelSerializer):
|
|||
raise ValidationError('收料车间和收料工段必须有一个')
|
||||
if 'send_dept' not in attrs and 'send_mgroup' not in attrs:
|
||||
raise ValidationError('送料车间和送料工段必须有一个')
|
||||
if wm.notok_sign is not None and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]:
|
||||
raise ValidationError('物料不合格,不能进行正常/检验交接')
|
||||
if wm.count_xtest is not None:
|
||||
raise ValidationError('物料检验中,不能进行交接')
|
||||
t_count = 0
|
||||
for ind, item in enumerate(attrs['handoverb']):
|
||||
wm = item["wm"]
|
||||
t_count += item["count"]
|
||||
if wm.mgroup != attrs['send_mgroup']:
|
||||
raise ParseError(f'第{ind+1}物料与交接工段不一致')
|
||||
if attrs["material"] != wm.material:
|
||||
raise ParseError(f'第{ind+1}物料与交接物料不一致')
|
||||
if wm.notok_sign is not None and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]:
|
||||
raise ParseError(f'第{ind+1}物料不合格,不能进行正常/检验交接')
|
||||
if wm.count_xtest is not None:
|
||||
raise ParseError(f'第{ind+1}物料检验中,不能进行交接')
|
||||
attrs["count"] = t_count
|
||||
if attrs['type'] == Handover.H_REPAIR:
|
||||
recive_mgroup = attrs.get("recive_mgroup", None)
|
||||
if recive_mgroup is None:
|
||||
raise ParseError('返工交接需指定工段')
|
||||
attrs['material_changed'] = find_material_can_change(attrs['material'], recive_mgroup)
|
||||
return attrs
|
||||
|
||||
class Meta:
|
||||
|
@ -497,22 +666,36 @@ class HandoverSerializer(CustomModelSerializer):
|
|||
read_only_fields = EXCLUDE_FIELDS + ["mlog"]
|
||||
extra_kwargs = {
|
||||
"type": {"required": False},
|
||||
"wm": {"required": True},
|
||||
"wm": {"required": False},
|
||||
"send_dept": {"required": False},
|
||||
"recive_mgroup": {"required": False},
|
||||
"recive_dept": {"required": False},
|
||||
"material": {"required": False},
|
||||
"batch": {"required": False},
|
||||
"count": {"required": False},
|
||||
"count_eweight": {"required": False}
|
||||
}
|
||||
|
||||
def create(self, validated_data):
|
||||
type = validated_data['type']
|
||||
if type == Handover.H_REPAIR:
|
||||
recive_mgroup = validated_data.get("recive_mgroup", None)
|
||||
if recive_mgroup is None:
|
||||
raise ParseError('返工交接需指定工段')
|
||||
validated_data['material_changed'] = find_material_can_change(validated_data['material'], recive_mgroup)
|
||||
return super().create(validated_data)
|
||||
handoverb = validated_data.pop('handoverb', [])
|
||||
with transaction.atomic():
|
||||
ins = super().create(validated_data)
|
||||
for item in handoverb:
|
||||
Handoverb.objects.get_or_create(handover=ins, wm=item["wm"], count=item["count"])
|
||||
return ins
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
handoverb = validated_data.pop('handoverb', [])
|
||||
with transaction.atomic():
|
||||
super().update(instance, validated_data)
|
||||
wmIds = []
|
||||
for item in handoverb:
|
||||
wmIds.append(item["wm"].id)
|
||||
hb, _ = Handoverb.objects.get_or_create(handover=instance, wm=item["wm"])
|
||||
hb.count = item["count"]
|
||||
hb.save()
|
||||
Handoverb.objects.filter(handover=instance).exclude(wm__in=wmIds).delete()
|
||||
return instance
|
||||
|
||||
class HandoverUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
|
@ -520,6 +703,7 @@ class HandoverUpdateSerializer(CustomModelSerializer):
|
|||
fields = ['id', 'send_date', 'send_user', 'count', 'count_eweight', 'recive_user']
|
||||
|
||||
|
||||
|
||||
class GenHandoverSerializer(serializers.Serializer):
|
||||
mlogs = serializers.PrimaryKeyRelatedField(
|
||||
label='mlog的ID列表', queryset=Mlog.objects.all(), many=True)
|
||||
|
@ -570,3 +754,34 @@ class AttLogSerializer(CustomModelSerializer):
|
|||
class Meta:
|
||||
model = AttLog
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class FmlogSerializer(CustomModelSerializer):
|
||||
routepack_name = serializers.CharField(
|
||||
source='route.routepack.name', read_only=True)
|
||||
mtask_number = serializers.CharField(source='mtask.number', read_only=True)
|
||||
class Meta:
|
||||
model = Fmlog
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS
|
||||
|
||||
def validate(self, attrs):
|
||||
route: Route = attrs['route']
|
||||
mtask: Mtask = attrs['mtask']
|
||||
if mtask.state != Mtask.MTASK_ASSGINED:
|
||||
raise ParseError('该任务非下达中不可选择')
|
||||
mgroup: Mgroup = attrs['mgroup']
|
||||
if route.process != mgroup.process:
|
||||
raise ParseError('工序不匹配')
|
||||
if mtask.mgroup != mgroup:
|
||||
raise ParseError('工段不匹配')
|
||||
return attrs
|
||||
|
||||
class FmlogUpdateSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Fmlog
|
||||
fields = ['id', 'note']
|
||||
|
||||
|
||||
class MlogTCreateSerializer(CustomModelSerializer):
|
||||
pass
|
|
@ -4,7 +4,6 @@ from django.core.cache import cache
|
|||
from django.db.models import Sum
|
||||
from django.utils import timezone
|
||||
from typing import Union
|
||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
||||
|
||||
from rest_framework.exceptions import ParseError
|
||||
|
||||
|
@ -13,9 +12,25 @@ from apps.inm.models import MIO, MIOItem, MIOItemA
|
|||
from apps.pm.models import Mtask
|
||||
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack
|
||||
|
||||
from .models import SfLog, SfLogExp, WMaterial, Mlog, Mlogb, Handover
|
||||
from apps.mtm.models import Process
|
||||
from .models import SfLog, WMaterial, Mlog, Mlogb, Handover, Handoverb
|
||||
from apps.mtm.services import cal_material_count
|
||||
from apps.wf.models import Ticket
|
||||
from django.db import transaction
|
||||
from apps.utils.thread import MyThread
|
||||
|
||||
def generate_new_batch(old_batch: str, mlog: Mlog):
|
||||
new_batch = old_batch
|
||||
supplier = mlog.supplier
|
||||
process = mlog.mgroup.process
|
||||
if mlog.mtype == Mlog.MTYPE_OUT:
|
||||
supplier_number = supplier.number if supplier else ''
|
||||
if supplier_number:
|
||||
new_batch = f'{new_batch}-{supplier_number}'
|
||||
elif process.batch_append_equip:
|
||||
number = mlog.equipment.number if mlog.equipment else ''
|
||||
if number:
|
||||
new_batch = f'{new_batch}-{number}'
|
||||
return new_batch
|
||||
|
||||
def find_material_can_change(material: Material, mgroup_to: Mgroup):
|
||||
"""
|
||||
|
@ -204,10 +219,16 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
belong_dept = mgroup.belong_dept
|
||||
material_out = mlog.material_out
|
||||
material_in = mlog.material_in
|
||||
supplier = mlog.supplier # 外协
|
||||
if material_in: # 需要进行车间库存管理
|
||||
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
|
||||
if m_ins.exists():
|
||||
m_ins_list = [(mi.material_in, mi.batch, mi.count_use, mi.wm_in) for mi in m_ins.all()]
|
||||
m_ins_list = []
|
||||
m_ins_bl_list = []
|
||||
for mi in m_ins.all():
|
||||
m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in))
|
||||
if mi.count_pn_jgqbl > 0:
|
||||
m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl))
|
||||
else:
|
||||
m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)]
|
||||
for mi in m_ins_list:
|
||||
|
@ -238,6 +259,20 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
wm.count = wm.count - mi_count
|
||||
wm.update_by = user
|
||||
wm.save()
|
||||
# 针对加工前不良的暂时额外处理
|
||||
for item in m_ins_bl_list:
|
||||
material, batch, count_pn_jgqbl = item
|
||||
if count_pn_jgqbl> 0:
|
||||
lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK}
|
||||
wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept})
|
||||
wm.count = wm.count + count_pn_jgqbl
|
||||
if is_create:
|
||||
wm.create_by = user
|
||||
else:
|
||||
wm.update_by = user
|
||||
wm.save()
|
||||
|
||||
|
||||
if material_out: # 需要入车间库存
|
||||
into_wm_mgroup = material_out.process.into_wm_mgroup if material_out.process else False
|
||||
need_store_notok = material_out.process.store_notok if material_out.process else False
|
||||
|
@ -271,6 +306,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
wm.count = wm.count + mo_count
|
||||
wm.count_eweight = mo_count_eweight
|
||||
wm.update_by = user
|
||||
if supplier is not None:
|
||||
wm.supplier = supplier
|
||||
wm.save()
|
||||
|
||||
mlog.submit_time = now
|
||||
|
@ -299,7 +336,12 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
into_wm_mgroup = material_in.process.into_wm_mgroup if material_in.process else False
|
||||
m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False)
|
||||
if m_ins.exists():
|
||||
m_ins_list = [(mi.material_in, mi.batch, mi.count_use, mi.wm_in) for mi in m_ins.all()]
|
||||
m_ins_list = []
|
||||
m_ins_bl_list = []
|
||||
for mi in m_ins.all():
|
||||
m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in))
|
||||
if mi.count_pn_jgqbl > 0:
|
||||
m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl))
|
||||
else:
|
||||
m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)]
|
||||
for mi in m_ins_list:
|
||||
|
@ -321,6 +363,21 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
wm.count = wm.count + mi_count
|
||||
wm.update_by = user
|
||||
wm.save()
|
||||
# 针对加工前不良的暂时额外处理
|
||||
for item in m_ins_bl_list:
|
||||
material, batch, count_pn_jgqbl = item
|
||||
if count_pn_jgqbl> 0:
|
||||
lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK}
|
||||
wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept})
|
||||
wm.count = wm.count - count_pn_jgqbl
|
||||
if wm.count < 0:
|
||||
raise ParseError('加工前不良数量大于库存量')
|
||||
if is_create:
|
||||
wm.create_by = user
|
||||
else:
|
||||
wm.update_by = user
|
||||
wm.save()
|
||||
|
||||
if material_out: # 产物退回
|
||||
# 有多个产物的情况
|
||||
# 需要考虑不合格品退回的情况
|
||||
|
@ -339,6 +396,8 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
|
|||
|
||||
for mo in m_outs_list:
|
||||
mo_ma, mo_batch, mo_count, _, notok_sign = mo
|
||||
if mo_count == 0:
|
||||
continue
|
||||
wm_state = WMaterial.WM_OK if notok_sign is None else WMaterial.WM_NOTOK
|
||||
lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': notok_sign, 'state': wm_state}
|
||||
if stored_mgroup:
|
||||
|
@ -379,7 +438,7 @@ def cal_mlog_count_from_mlogb(mlog: Mlog):
|
|||
"""
|
||||
通过mlogb计算mlog count 合计
|
||||
"""
|
||||
if mlog.fill_way == Mlog.MLOG_STEP:
|
||||
if mlog.fill_way == Mlog.MLOG_23:
|
||||
a_dict = {
|
||||
"total_count_use": Sum('count_use'),
|
||||
"total_count_break": Sum('count_break'),
|
||||
|
@ -388,7 +447,7 @@ def cal_mlog_count_from_mlogb(mlog: Mlog):
|
|||
"total_count_ok": Sum('count_ok'),
|
||||
"total_count_notok": Sum('count_notok'),
|
||||
}
|
||||
f_names = [f.name for f in Mlogb._meta.fields if 'count_n' in f.name]
|
||||
f_names = [f.name for f in Mlogb._meta.fields if 'count_n_' in f.name]
|
||||
for f in f_names:
|
||||
a_dict[f'total_{f}'] = Sum(f)
|
||||
mlogb_summary = Mlogb.objects.filter(mlog=mlog).aggregate(
|
||||
|
@ -410,9 +469,9 @@ def cal_mtask_progress_from_mlog(mlog: Mlog):
|
|||
"""
|
||||
更新mlog关联的任务进度(可线程中执行)
|
||||
"""
|
||||
if mlog.fill_way == Mlog.MLOG_ONETIME and mlog.mtask:
|
||||
update_mtask(mlog.mtask, fill_way=Mlog.MLOG_ONETIME)
|
||||
elif mlog.fill_way == Mlog.MLOG_STEP:
|
||||
if mlog.fill_way in [Mlog.MLOG_2, Mlog.MLOG_12] and mlog.mtask:
|
||||
update_mtask(mlog.mtask, fill_way=mlog.fill_way)
|
||||
elif mlog.fill_way == Mlog.MLOG_23:
|
||||
cal_mlog_count_from_mlogb(mlog)
|
||||
m_outs_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
|
||||
caled_mtask = []
|
||||
|
@ -420,7 +479,7 @@ def cal_mtask_progress_from_mlog(mlog: Mlog):
|
|||
mtask = item.mtask
|
||||
if mtask in caled_mtask:
|
||||
continue
|
||||
update_mtask(mtask, fill_way=Mlog.MLOG_STEP)
|
||||
update_mtask(mtask, fill_way=mlog.fill_way)
|
||||
caled_mtask.append(mtask)
|
||||
|
||||
def cal_material_count_from_mlog(mlog: Mlog):
|
||||
|
@ -443,7 +502,7 @@ def cal_material_count_from_mlog(mlog: Mlog):
|
|||
|
||||
def update_mtask(mtask: Mtask, fill_way: int = 10):
|
||||
from apps.pm.models import Utask
|
||||
if fill_way == Mlog.MLOG_ONETIME:
|
||||
if fill_way == Mlog.MLOG_2:
|
||||
res = Mlog.objects.filter(mtask=mtask).exclude(submit_time=None).aggregate(sum_count_real=Sum(
|
||||
'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok'))
|
||||
mtask.count_real = res['sum_count_real'] if res['sum_count_real'] else 0
|
||||
|
@ -462,7 +521,7 @@ def update_mtask(mtask: Mtask, fill_way: int = 10):
|
|||
if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_SUBMIT).count() == 0:
|
||||
utask.state = Utask.UTASK_SUBMIT
|
||||
utask.save()
|
||||
elif fill_way == Mlog.MLOG_STEP:
|
||||
elif fill_way in [Mlog.MLOG_23, Mlog.MLOG_12]:
|
||||
# 已经提交的日志
|
||||
m_outs_qs_mtask = Mlogb.objects.filter(mtask=mtask, material_out__isnull=False, mlog__submit_time__isnull=False)
|
||||
res = m_outs_qs_mtask.aggregate(
|
||||
|
@ -502,90 +561,117 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime
|
|||
if handover.submit_time is not None:
|
||||
return
|
||||
now = timezone.now()
|
||||
handoverb_qs = Handoverb.objects.filter(handover=handover)
|
||||
need_add = True
|
||||
material = handover.material
|
||||
batch = handover.batch
|
||||
wm_from = handover.wm
|
||||
if wm_from is None:
|
||||
raise ParseError('找不到车间库存')
|
||||
if '混料' in material.name: # hard code
|
||||
need_add = False
|
||||
count_x = wm_from.count - handover.count
|
||||
if count_x < 0:
|
||||
raise ParseError('车间库存不足!')
|
||||
if handoverb_qs.exists():
|
||||
handoverb_list = [(item.wm, item.count) for item in handoverb_qs]
|
||||
else:
|
||||
wm_from.count = count_x
|
||||
wm_from.save()
|
||||
if need_add:
|
||||
if handover.type == Handover.H_NORMAL:
|
||||
if handover.recive_mgroup:
|
||||
handoverb_list = [(handover.wm, handover.count)]
|
||||
|
||||
recive_mgroup = handover.recive_mgroup
|
||||
recive_dept = handover.recive_dept
|
||||
for item in handoverb_list:
|
||||
wm_from, xcount = item
|
||||
batch = wm_from.batch
|
||||
if wm_from is None:
|
||||
raise ParseError('找不到车间库存')
|
||||
|
||||
count_x = wm_from.count - xcount
|
||||
if count_x < 0:
|
||||
raise ParseError('车间库存不足!')
|
||||
else:
|
||||
wm_from.count = count_x
|
||||
wm_from.save()
|
||||
if need_add:
|
||||
# 开始变动
|
||||
if handover.type == Handover.H_NORMAL:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=material,
|
||||
mgroup=handover.recive_mgroup,
|
||||
state=WMaterial.WM_OK,
|
||||
defaults={"batch": batch, "material": material, "mgroup": handover.recive_mgroup, "belong_dept": handover.recive_dept},
|
||||
mgroup=recive_mgroup,
|
||||
belong_dept=recive_dept,
|
||||
state=WMaterial.WM_OK
|
||||
)
|
||||
else:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=material,
|
||||
belong_dept=handover.recive_dept,
|
||||
mgroup=None,
|
||||
state=WMaterial.WM_OK,
|
||||
defaults={"batch": batch, "material": material, "belong_dept": handover.recive_dept}
|
||||
)
|
||||
elif handover.type == Handover.H_REPAIR:
|
||||
if handover.recive_mgroup:
|
||||
elif handover.type == Handover.H_REPAIR:
|
||||
if handover.recive_mgroup:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=handover.material_changed,
|
||||
mgroup=recive_mgroup,
|
||||
belong_dept=recive_dept,
|
||||
notok_sign=wm_from.notok_sign,
|
||||
material_origin=material,
|
||||
state=WMaterial.WM_REPAIR
|
||||
)
|
||||
else:
|
||||
raise ParseError("返工交接必须指定接收工段")
|
||||
elif handover.type == Handover.H_TEST:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=handover.material_changed,
|
||||
mgroup=handover.recive_mgroup,
|
||||
notok_sign=handover.wm.notok_sign,
|
||||
material_origin=handover.material,
|
||||
state=WMaterial.WM_REPAIR,
|
||||
material=material,
|
||||
mgroup=recive_mgroup,
|
||||
state=WMaterial.WM_TEST,
|
||||
belong_dept=recive_dept,
|
||||
defaults={
|
||||
"batch": batch,
|
||||
"material": handover.material_changed,
|
||||
"mgroup": handover.recive_mgroup,
|
||||
"notok_sign": handover.wm.notok_sign,
|
||||
"material_origin": handover.material,
|
||||
"belong_dept": handover.recive_dept,
|
||||
"state": WMaterial.WM_REPAIR
|
||||
"count_xtest": 0,
|
||||
},
|
||||
)
|
||||
elif handover.type == Handover.H_SCRAP:
|
||||
if recive_mgroup:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=material,
|
||||
mgroup=recive_mgroup,
|
||||
belong_dept=recive_dept,
|
||||
notok_sign=wm_from.notok_sign,
|
||||
state=WMaterial.WM_SCRAP
|
||||
)
|
||||
else:
|
||||
raise ParseError("不支持非工段报废")
|
||||
else:
|
||||
raise ParseError("返工交接必须指定接收工段")
|
||||
elif handover.type == Handover.H_TEST:
|
||||
if handover.recive_mgroup:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=material,
|
||||
mgroup=handover.recive_mgroup,
|
||||
state=WMaterial.WM_TEST,
|
||||
defaults={
|
||||
"batch": batch,
|
||||
"material": material,
|
||||
"mgroup": handover.recive_mgroup,
|
||||
"belong_dept": handover.recive_dept,
|
||||
"count_xtest": 0,
|
||||
"state": WMaterial.WM_TEST},
|
||||
)
|
||||
else:
|
||||
wm_to, _ = WMaterial.objects.get_or_create(
|
||||
batch=batch,
|
||||
material=material,
|
||||
belong_dept=handover.recive_dept,
|
||||
mgroup=None,
|
||||
state=WMaterial.WM_TEST,
|
||||
defaults={"batch": batch, "material": material, "belong_dept": handover.recive_dept, "count_xtest": 0, "state": WMaterial.WM_TEST},
|
||||
)
|
||||
else:
|
||||
raise ParseError("不支持交接类型")
|
||||
raise ParseError("不支持该交接类型")
|
||||
|
||||
wm_to.count = wm_to.count + handover.count
|
||||
wm_to.count_eweight = handover.count_eweight # 这行代码有隐患
|
||||
wm_to.save()
|
||||
wm_to.count = wm_to.count + xcount
|
||||
wm_to.count_eweight = handover.count_eweight # 这行代码有隐患
|
||||
wm_to.save()
|
||||
handover.submit_user = user
|
||||
handover.submit_time = now
|
||||
handover.save()
|
||||
|
||||
def mlog_submit_validate(ins: Mlog):
|
||||
if ins.submit_time:
|
||||
raise ParseError('该日志已提交!')
|
||||
if ins.mtask and ins.mtask.state == Mtask.MTASK_STOP:
|
||||
raise ParseError('该任务已停止!')
|
||||
if ins.fill_way == Mlog.MLOG_23:
|
||||
if not Mlogb.objects.filter(material_out__isnull=False, mlog=ins).exists():
|
||||
raise ParseError('该日志未指定产出!')
|
||||
if not Mlogb.objects.filter(material_in__isnull=False, mlog=ins).exists():
|
||||
raise ParseError('该日志未指定消耗!')
|
||||
if Mlogb.objects.filter(material_out__isnull=False, count_real=0, mlog=ins).exists():
|
||||
raise ParseError('产出数量不能为0!')
|
||||
|
||||
def bind_mlog(ticket: Ticket, transition, new_ticket_data: dict):
|
||||
ins = Mlog.objects.get(id=new_ticket_data['t_id'])
|
||||
mlog_submit_validate(ins) # 校验是否可submit
|
||||
ticket_data = ticket.ticket_data
|
||||
ticket_data.update({
|
||||
't_model': 'mlog',
|
||||
't_id': ins.id,
|
||||
})
|
||||
ticket.ticket_data = ticket_data
|
||||
ticket.create_by = ins.create_by
|
||||
ticket.save()
|
||||
if ins.ticket is None:
|
||||
ins.ticket = ticket
|
||||
ins.save()
|
||||
|
||||
def mlog_audit_end(ticket: Ticket):
|
||||
now = timezone.now()
|
||||
ins = Mlog.objects.get(id=ticket.ticket_data['t_id'])
|
||||
mlog_submit(ins, ticket.create_by, now)
|
||||
MyThread(target=cal_mtask_progress_from_mlog,args=(ins,)).start()
|
||||
MyThread(target=cal_material_count_from_mlog,args=(ins,)).start()
|
||||
|
|
|
@ -3,7 +3,9 @@ from rest_framework.routers import DefaultRouter
|
|||
|
||||
from apps.wpm.views import (SfLogViewSet, StLogViewSet, SfLogExpViewSet,
|
||||
WMaterialViewSet, MlogViewSet, HandoverViewSet,
|
||||
AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet, MlogbOutViewSet)
|
||||
AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet,
|
||||
MlogbOutViewSet, FmlogViewSet)
|
||||
from apps.wpm.datax import AnaViewSet
|
||||
|
||||
|
||||
API_BASE_URL = 'api/wpm/'
|
||||
|
@ -14,6 +16,7 @@ router.register('sflog', SfLogViewSet, basename='sflog')
|
|||
router.register('stlog', StLogViewSet, basename='stlog')
|
||||
router.register('sflogexp', SfLogExpViewSet, basename='sflogexp')
|
||||
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
|
||||
router.register('fmlog', FmlogViewSet, basename='fmlog')
|
||||
router.register('mlog', MlogViewSet, basename='mlog')
|
||||
router.register('mlogb', MlogbViewSet)
|
||||
router.register('mlogb/in', MlogbInViewSet)
|
||||
|
@ -21,6 +24,8 @@ router.register('mlogb/out', MlogbOutViewSet)
|
|||
router.register('handover', HandoverViewSet, basename='handover')
|
||||
router.register('attlog', AttlogViewSet, basename='attlog')
|
||||
router.register('otherlog', OtherLogViewSet, basename='otherlog')
|
||||
router.register('ana', AnaViewSet, basename='ana')
|
||||
|
||||
urlpatterns = [
|
||||
path(API_BASE_URL, include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -16,15 +16,17 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
|
|||
from apps.utils.mixins import BulkCreateModelMixin
|
||||
|
||||
from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter
|
||||
from .models import SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog
|
||||
from .models import SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog, Fmlog
|
||||
from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer, MlogRevertSerializer,
|
||||
MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer, HandoverUpdateSerializer,
|
||||
GenHandoverSerializer, GenHandoverWmSerializer, MlogAnaSerializer,
|
||||
AttLogSerializer, OtherLogSerializer, MlogInitSerializer, MlogChangeSerializer,
|
||||
MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, MlogbOutUpdateSerializer)
|
||||
MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer,
|
||||
MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer)
|
||||
from .services import mlog_submit, update_mtask, handover_submit, mlog_revert, cal_material_count_from_mlog, cal_mtask_progress_from_mlog
|
||||
from apps.utils.thread import MyThread
|
||||
from apps.monitor.services import create_auditlog, delete_auditlog
|
||||
from apps.wpm.services import mlog_submit_validate, generate_new_batch
|
||||
# Create your views here.
|
||||
|
||||
|
||||
|
@ -112,11 +114,17 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet):
|
|||
perms_map = {'get': '*'}
|
||||
queryset = WMaterial.objects.filter(count__gt=0)
|
||||
serializer_class = WMaterialSerializer
|
||||
select_related_fields = ['material', 'belong_dept', 'material__process']
|
||||
select_related_fields = ['material', 'belong_dept', 'material__process', 'supplier']
|
||||
search_fields = ['material__name',
|
||||
'material__number', 'material__specification', 'batch', 'material__model']
|
||||
filterset_class = WMaterialFilter
|
||||
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super().filter_queryset(queryset)
|
||||
if self.request.query_params.get('state_all'):
|
||||
return queryset
|
||||
return queryset.exclude(state=WMaterial.WM_SCRAP)
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=DeptBatchSerializer)
|
||||
@transaction.atomic
|
||||
def batchs(self, request):
|
||||
|
@ -141,7 +149,9 @@ class MlogViewSet(CustomModelViewSet):
|
|||
queryset = Mlog.objects.all()
|
||||
serializer_class = MlogSerializer
|
||||
select_related_fields = ['create_by', 'update_by', 'mtask',
|
||||
'handle_user', 'handle_user_2', 'equipment', 'equipment_2', 'material_in', 'material_out', 'supplier']
|
||||
'handle_user', 'handle_user_2', 'equipment',
|
||||
'equipment_2', 'material_in', 'material_out', 'route__routepack',
|
||||
'supplier', 'ticket', 'mgroup__process', 'test_user']
|
||||
prefetch_related_fields = ['handle_users',
|
||||
'material_outs', 'b_mlog', 'equipments']
|
||||
filterset_class = MlogFilter
|
||||
|
@ -204,15 +214,13 @@ class MlogViewSet(CustomModelViewSet):
|
|||
ins: Mlog = self.get_object()
|
||||
vdata_old = MlogSerializer(ins).data
|
||||
now = timezone.now()
|
||||
if ins.submit_time:
|
||||
raise ParseError('该日志已提交!')
|
||||
if ins.mtask and ins.mtask.state == Mtask.MTASK_STOP:
|
||||
raise ParseError('该任务已停止!')
|
||||
if ins.fill_way == Mlog.MLOG_STEP:
|
||||
if not Mlogb.objects.filter(material_out__isnull=False).exists():
|
||||
raise ParseError('该日志未指定产出!')
|
||||
if not Mlogb.objects.filter(material_in__isnull=False).exists():
|
||||
raise ParseError('该日志未指定消耗!')
|
||||
if ins.ticket:
|
||||
raise ParseError('该日志存在审批!')
|
||||
else:
|
||||
p: Process = ins.mgroup.process
|
||||
if p.mlog_need_ticket:
|
||||
raise ParseError('该日志需要审批!')
|
||||
mlog_submit_validate(ins)
|
||||
with transaction.atomic():
|
||||
mlog_submit(ins, self.request.user, now)
|
||||
vdata_new = MlogSerializer(ins).data
|
||||
|
@ -339,10 +347,11 @@ class HandoverViewSet(CustomModelViewSet):
|
|||
"""
|
||||
ins: Handover = self.get_object()
|
||||
user: User = self.request.user
|
||||
if user == ins.recive_user or user.belong_dept == ins.recive_user.belong_dept:
|
||||
pass
|
||||
else:
|
||||
raise ParseError('非接收人不可提交')
|
||||
if ins.type != Handover.H_SCRAP:
|
||||
if user == ins.recive_user or user.belong_dept == ins.recive_user.belong_dept:
|
||||
pass
|
||||
else:
|
||||
raise ParseError('非接收人不可提交')
|
||||
if ins.submit_time is None:
|
||||
handover_submit(ins, user, None)
|
||||
return Response()
|
||||
|
@ -468,8 +477,6 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
|
|||
def perform_create(self, serializer):
|
||||
ins: Mlogb = serializer.save()
|
||||
mlog: Mlog = ins.mlog
|
||||
process: Process = mlog.mgroup.process
|
||||
supplier = mlog.supplier
|
||||
# 创建输出
|
||||
if ins.mtask and ins.material_in:
|
||||
material_out = mlog.material_out
|
||||
|
@ -480,20 +487,26 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
|
|||
"mlog": ins.mlog,
|
||||
"material_out": ins.mlog.material_out
|
||||
}
|
||||
new_batch = ins.batch
|
||||
if mlog.mtype == Mlog.MTYPE_OUT:
|
||||
supplier_number = supplier.number if supplier else ''
|
||||
if supplier_number:
|
||||
new_batch = f'{new_batch}-{supplier_number}'
|
||||
elif process.batch_append_equip:
|
||||
number = mlog.equipment.number if mlog.equipment else ''
|
||||
if number:
|
||||
new_batch = f'{new_batch}-{number}'
|
||||
m_dict['batch'] = new_batch
|
||||
m_dict['batch'] = generate_new_batch(ins.batch, mlog)
|
||||
Mlogb.objects.get_or_create(**m_dict, defaults=m_dict)
|
||||
|
||||
|
||||
class MlogbOutViewSet(UpdateModelMixin, CustomGenericViewSet):
|
||||
perms_map = {"put": "mlog.update"}
|
||||
queryset = Mlogb.objects.filter(material_out__isnull=False)
|
||||
serializer_class = MlogbOutUpdateSerializer
|
||||
serializer_class = MlogbOutUpdateSerializer
|
||||
|
||||
|
||||
class FmlogViewSet(CustomModelViewSet):
|
||||
perms_map = {'get': '*', 'post': 'mlog.create', 'put': 'mlog.update', 'delete': 'mlog.delete'}
|
||||
queryset = Fmlog.objects.all()
|
||||
serializer_class = FmlogSerializer
|
||||
update_serializer_class = FmlogUpdateSerializer
|
||||
filterset_fields = ['mtask', 'mgroup', 'route']
|
||||
select_related_fields = ['mtask', 'mgroup', 'route', 'route__routepack']
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
ins = self.get_object()
|
||||
if Mlog.objects.filter(fmlog=ins).exists():
|
||||
raise ParseError('因存在二级日志不可删除')
|
||||
return super().destroy(request, *args, **kwargs)
|
|
@ -341,7 +341,7 @@ LOGGING = {
|
|||
##### 加载客户可自定义配置并提供操作方法 #####
|
||||
SYS_JSON_PATH = os.path.join(BASE_DIR, 'server/conf.json')
|
||||
|
||||
def get_sysconfig(key='', reload=False):
|
||||
def get_sysconfig(key='', default='raise_error', reload=False):
|
||||
"""获取系统配置可指定key字符串
|
||||
"""
|
||||
config = cache.get('system_config', None)
|
||||
|
@ -355,7 +355,13 @@ def get_sysconfig(key='', reload=False):
|
|||
if key:
|
||||
k_l = key.split('.')
|
||||
for k in k_l:
|
||||
config = config[k]
|
||||
try:
|
||||
config = config[k]
|
||||
except KeyError:
|
||||
if default == 'raise_error':
|
||||
raise
|
||||
else:
|
||||
return default
|
||||
return config
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue