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.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 # Create your models here. class SfLog(CommonADModel): """值班记录 """ mgroup = models.ForeignKey( Mgroup, verbose_name='关联工段', on_delete=models.CASCADE) team = models.ForeignKey(Team, verbose_name='班组', on_delete=models.CASCADE, null=True, blank=True) shift = models.ForeignKey( Shift, verbose_name='当班班次', on_delete=models.CASCADE) leader = models.ForeignKey( 'system.user', verbose_name='班长', on_delete=models.CASCADE, null=True, blank=True) work_date = models.DateField('值班日期', null=True, blank=True) start_time = models.DateTimeField('值班开始') end_time = models.DateTimeField('值班结束') note = models.TextField('其他备注', null=True, blank=True) stlogs = models.ManyToManyField( 'wpm.stlog', verbose_name='关联异常记录', through='wpm.sflogexp', related_name='sflog_stlogs') last_test_time = models.DateTimeField('最后质检时间', null=True, blank=True) total_sec_now = models.PositiveIntegerField('总时长动', default=0) total_sec = models.PositiveIntegerField('总时长', default=43200) shut_sec = models.PositiveIntegerField('停机时长', default=0) pcoal_heat = models.FloatField('煤粉热值', null=True, blank=True) @property def get_ymd(self): """ 返回值班记录所属年月日 """ end_time_local = localtime(self.end_time) if end_time_local.hour == 0 and end_time_local.minute == 0 and end_time_local.second == 0: # 如果结束时间为00:00:00 end_time_local = localtime(self.start_time) return end_time_local.year, end_time_local.month, end_time_local.day class StLog(CommonADModel): """ 异常记录 """ title = models.CharField('异常名称', max_length=20, default='') is_shutdown = models.BooleanField('是否是停机', default=False) mgroup = models.ForeignKey( Mgroup, verbose_name='关联工段', on_delete=models.CASCADE) sflog = models.ForeignKey( SfLog, on_delete=models.SET_NULL, verbose_name='发生时所在值班', null=True, blank=True) sflogs = models.ManyToManyField( 'wpm.sflog', verbose_name='关联所有当班', through='wpm.sflogexp', related_name='stlog_sflogs') start_time = models.DateTimeField('发生时间') end_time = models.DateTimeField('结束时间', null=True, blank=True) duration_sec = models.PositiveIntegerField('持续时长(s)', null=True, blank=True) cate = models.CharField('原因类别', max_length=10, null=True, blank=True) reason = models.TextField('事件原因', default='', max_length=100) measure = models.TextField('处置措施', default='', max_length=100) handler = models.CharField('处理人', default='', max_length=100) class Meta: unique_together = ('mgroup', 'start_time') class SfLogExp(CommonADModel): """ 异常处理 """ sflog = models.ForeignKey( SfLog, on_delete=models.CASCADE, verbose_name='关联值班记录') stlog = models.ForeignKey( StLog, verbose_name='关联异常记录', on_delete=models.CASCADE) duration_sec = models.PositiveIntegerField('持续时长(s)', null=True, blank=True) note = models.TextField('处理备注', default='', blank=True) class Meta: unique_together = ('sflog', 'stlog') class WMaterial(CommonBDModel): """ belong_dept是所在车间 """ WM_OK = 10 WM_NOTOK = 20 WM_REPAIR = 30 WM_TEST = 40 WM_SCRAP = 50 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) count_eweight = models.FloatField('单数重量', default=0) notok_sign = models.CharField('不合格标记', max_length=10, null=True, blank=True) 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) class Mlog(CommonADModel): """ 生产日志 """ # 变成父级的字段 MLOG_ONETIME = 10 MLOG_STEP = 20 MTYPE_SELF = 10 MTYPE_OUT = 20 fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:一次填写;20:分步填写') 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) work_end_time = models.DateTimeField('生产结束时间', null=True, blank=True) hour_work = models.FloatField('预计工时', null=True, blank=True) reminder_interval_list = models.JSONField('提醒间隔', default=list, blank=True) stored_mgroup = models.BooleanField('入库到工段', default=False) stored_notok = models.BooleanField('不合格品是否已入库', default=False) 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, null=True, blank=True, related_name='mlog_mtask') mgroup = models.ForeignKey( Mgroup, verbose_name='工段', on_delete=models.CASCADE, null=True, blank=True) wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_wm_in') material_in = models.ForeignKey( Material, verbose_name='消耗物', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_material_in') material_out = models.ForeignKey( Material, verbose_name='产物', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_material_out') equipment = models.ForeignKey( Equipment, verbose_name='生产设备', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_equipment') equipment_2 = models.ForeignKey( Equipment, verbose_name='生产设备2', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_equipment_2') equipments = models.ManyToManyField( Equipment, verbose_name='多选生产设备', blank=True) index = models.PositiveSmallIntegerField('第几锅', default=0) shift = models.ForeignKey( Shift, verbose_name='关联班次', on_delete=models.SET_NULL, null=True, blank=True) batch = models.CharField('批次号', max_length=50, null=True, blank=True) count_use = models.PositiveIntegerField('领用数', default=0) count_real = models.PositiveIntegerField('实际生产数', default=0) count_real_eweight = models.FloatField('单数重量', default=0) count_break = models.PositiveIntegerField('加工碎料数', default=0) count_ok = models.PositiveIntegerField('合格数', default=0) count_notok = models.PositiveIntegerField('不合格数', default=0) count_break_t = models.PositiveIntegerField('检验碎料数', default=0) count_n_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) count_n_wq = models.PositiveIntegerField('弯曲', default=0) count_n_dl = models.PositiveIntegerField('断裂', default=0) count_n_pb = models.PositiveIntegerField('偏壁', default=0) count_n_dxt = models.PositiveIntegerField('大小头', default=0) count_n_js = models.PositiveIntegerField('结石', default=0) count_n_qx = models.PositiveIntegerField('气线', default=0) count_n_hs = models.PositiveIntegerField('划伤', default=0) count_n_cs = models.PositiveIntegerField('挫伤', default=0) count_n_bl = models.PositiveIntegerField('不亮', default=0) count_n_zz = models.PositiveIntegerField('杂质', default=0) count_n_d = models.PositiveIntegerField('短', default=0) count_n_zdd = models.PositiveIntegerField('锥度大', default=0) count_n_hw = models.PositiveIntegerField('横纹', default=0) count_n_yp = models.PositiveIntegerField('有皮', default=0) count_n_bp = models.PositiveIntegerField('爆皮', default=0) count_n_sc = models.PositiveIntegerField('色差', default=0) count_n_tydd = models.PositiveIntegerField('椭圆度大', default=0) count_n_sw = models.PositiveIntegerField('水雾', default=0) count_n_zjx = models.PositiveIntegerField('直径小', default=0) count_n_zjd = models.PositiveIntegerField('直径大', default=0) count_n_bhpcd = models.PositiveIntegerField('壁厚偏差大', default=0) count_n_xzp = models.PositiveIntegerField('箱中破', default=0) count_n_thhs = models.PositiveIntegerField('退火后碎', default=0) count_n_swen = models.PositiveIntegerField('水纹', default=0) count_n_bb = models.PositiveIntegerField('崩边', default=0) count_n_xbb = models.PositiveIntegerField('小崩边', default=0) count_n_wm = models.PositiveIntegerField('雾面', default=0) count_n_md = models.PositiveIntegerField('麻点', default=0) count_n_xh = models.PositiveIntegerField('线痕', default=0) count_n_ps = models.PositiveIntegerField('破损', default=0) count_n_wj = models.PositiveIntegerField('外经', default=0) 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) handle_user = models.ForeignKey( User, verbose_name='操作人', on_delete=models.CASCADE, related_name='mlog_handle_user', null=True, blank=True) # 成型人 handle_user_2 = models.ForeignKey( User, verbose_name='操作人2', on_delete=models.CASCADE, related_name='mlog_handle_user_2', null=True, blank=True) # 切料人 handle_users = models.ManyToManyField( User, verbose_name='操作人(多选)', blank=True) handle_leader = models.ForeignKey( User, verbose_name='班长', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_handle_leader') note = models.TextField('备注', default='', blank=True) material_outs = models.ManyToManyField( Material, verbose_name='多个产出', blank=True, through='wpm.mlogb', related_name='mlog_material_outs', through_fields=('mlog', 'material_out')) submit_time = models.DateTimeField('提交时间', null=True, blank=True) 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) @property def mlogb(self): return Mlogb.objects.filter(mlog=self).exclude(material_out=None) @property def mlogb_full(self): return Mlogb.objects.filter(mlog=self) @property def audit_ignore_fields(self): return ['create_by', 'update_by', 'create_time', 'update_time', 'id'] 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) wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, null=True, blank=True) material_in = models.ForeignKey( Material, verbose_name='投入物料', on_delete=models.CASCADE, related_name='mlogb_material_in', null=True, blank=True) material_out = models.ForeignKey( Material, verbose_name='产物', on_delete=models.CASCADE, related_name='mlogb_material_out', null=True, blank=True) count_use = models.PositiveIntegerField('领用数量', default=0) count_break = models.PositiveIntegerField('加工破碎数', default=0) count_break_t = models.PositiveIntegerField('检验碎料数', default=0) count_real = models.PositiveIntegerField('实际生产数', default=0) count_ok = models.PositiveIntegerField('合格数量', default=0) count_notok = models.PositiveIntegerField('不合格数', default=0) count_n_jgqbl = models.PositiveIntegerField('加工前不良', default=0) # 添加不合格字段后需要更改cal_mlog_count_from_mlogb count_n_hs = models.PositiveIntegerField('划伤', default=0) count_n_qp = models.PositiveIntegerField('气泡', default=0) count_n_swen = models.PositiveIntegerField('水纹', default=0) count_n_bb = models.PositiveIntegerField('崩边', default=0) count_n_xbb = models.PositiveIntegerField('小崩边', default=0) count_n_wm = models.PositiveIntegerField('雾面', default=0) count_n_md = models.PositiveIntegerField('麻点', default=0) count_n_xh = models.PositiveIntegerField('线痕', default=0) count_n_ps = models.PositiveIntegerField('破损', default=0) count_n_wj = models.PositiveIntegerField('外经', default=0) 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) count_notok_json = models.JSONField('不合格情况', default=list, blank=True) 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) send_date = models.DateField('送料日期') send_user = models.ForeignKey( User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user') send_mgroup = models.ForeignKey( 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) 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') count = models.PositiveIntegerField('送料数', default=0) count_eweight = models.FloatField('单数重量', default=0) recive_dept = models.ForeignKey( Dept, verbose_name='接收部门', on_delete=models.CASCADE, related_name='handover_recive_dept') recive_mgroup = models.ForeignKey(Mgroup, verbose_name='接收工段', on_delete=models.CASCADE, related_name='handover_recive_mgroup', null=True, blank=True) recive_user = models.ForeignKey( User, verbose_name='接收人', on_delete=models.CASCADE, related_name='handover_recive_user') wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL, null=True, blank=True, related_name='handover_wm') mlog = models.ForeignKey(Mlog, verbose_name='关联日志记录', on_delete=models.SET_NULL, null=True, blank=True, related_name='handover_mlog') doin_date = models.DateField('加料日期', null=True, blank=True) doout_date = models.DateField('出料日期', null=True, blank=True) submit_time = models.DateTimeField('提交时间', null=True, blank=True) submit_user = models.ForeignKey( User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='handover_submit_user') class AttLog(CommonADModel): """ 到岗记录 """ ATT_STATE_CHOICES = [ ('pending', '待定'), ('normal', '正常'), ('late', '迟到'), ('early_leave', '早退'), ('absent', '未到岗'), ('leave', '请假'), # 可以根据需要添加更多状态 ] sflog = models.ForeignKey( SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE) user = models.ForeignKey( 'system.user', verbose_name='到岗人', on_delete=models.CASCADE) post = models.ForeignKey( 'system.post', verbose_name='岗位', on_delete=models.CASCADE) state = models.CharField('状态', max_length=20, choices=ATT_STATE_CHOICES, default='pending', help_text=str(ATT_STATE_CHOICES)) note = models.TextField('备注信息', default='', blank=True) class OtherLog(CommonADModel): """ 其他生产日志 """ product = models.CharField('产品', max_length=10) handle_date = models.DateField('操作日期') count_real = models.PositiveIntegerField('实际生产数', default=0) count_ok = models.PositiveIntegerField('合格数', default=0) count_delivered = models.PositiveIntegerField('交付数', default=0)