345 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			345 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
| import re
 | |
| 
 | |
| from rest_framework import exceptions
 | |
| from django.db import models
 | |
| from django.db.models.base import Model
 | |
| import django.utils.timezone as timezone
 | |
| from django.db.models.query import QuerySet
 | |
| from apps.inm.models import FIFO, WareHouse
 | |
| from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
 | |
| from apps.qm.models import TestRecord
 | |
| from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
 | |
| from apps.wf.models import Ticket
 | |
| from utils.model import SoftModel, BaseModel
 | |
| from simple_history.models import HistoricalRecords
 | |
| from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial
 | |
| from apps.em.models import Equipment
 | |
| 
 | |
| 
 | |
| class WMaterial(BaseModel):
 | |
|     """
 | |
|     车间生产物料
 | |
|     """
 | |
|     subproduction_plan = models.ForeignKey(
 | |
|         SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE)
 | |
|     material = models.ForeignKey(
 | |
|         Material, verbose_name='关联物料', on_delete=models.CASCADE)
 | |
|     batch = models.CharField('批次号', max_length=100, null=True, blank=True)
 | |
|     count = models.PositiveIntegerField('当前数量', default=0)
 | |
| 
 | |
| 
 | |
| class WProduct(CommonAModel):
 | |
|     """
 | |
|     动态半成品/成品表
 | |
|     """
 | |
|     WPR_ACT_STATE_TORETEST = 6
 | |
|     WPR_ACT_STATE_DOWAIT = 8
 | |
|     WPR_ACT_STATE_DOING = 10
 | |
|     WPR_ACT_STATE_TOTEST = 20
 | |
|     WPR_ACT_STATE_TOCOMBTEST = 26
 | |
|     WPR_ACT_STATE_OK = 30
 | |
|     WPR_ACT_STATE_INM = 40
 | |
|     WPR_ACT_STATE_NOTOK = 50
 | |
|     WPR_ACT_STATE_TOFINALTEST = 60
 | |
|     WPR_ACT_STATE_SCRAP = 70
 | |
|     WPR_ACT_STATE_SELLED = 80
 | |
|     act_state_choices = (
 | |
|         (WPR_ACT_STATE_TORETEST, '待复检'),
 | |
|         (WPR_ACT_STATE_DOWAIT, '操作准备中'),
 | |
|         (WPR_ACT_STATE_DOING, '操作进行中'),
 | |
|         (WPR_ACT_STATE_TOTEST, '待检验'),
 | |
|         (WPR_ACT_STATE_TOCOMBTEST, '待夹层检验'),
 | |
|         (WPR_ACT_STATE_OK, '已合格'),
 | |
|         (WPR_ACT_STATE_INM, '已入库'),
 | |
|         (WPR_ACT_STATE_NOTOK, '不合格'),
 | |
|         (WPR_ACT_STATE_TOFINALTEST, '待成品检验'),
 | |
|         (WPR_ACT_STATE_SCRAP, '已报废'),
 | |
|         (WPR_ACT_STATE_SELLED, '已售出'),
 | |
|     )
 | |
|     SCRAP_REASON_QIPAO = 10
 | |
|     SCRAP_REASON_PODIAN = 20
 | |
|     SCRAP_REASON_HUA = 30
 | |
|     SCRAP_REASON_OTHER = 40
 | |
|     scrap_reason_choices = (
 | |
|         (10, '气泡'),
 | |
|         (20, '破点'),
 | |
|         (30, '划伤'),
 | |
|         (40, '其他')
 | |
|     )
 | |
| 
 | |
|     NG_BACK_WORK = 10
 | |
|     NG_BACK_FIX = 20
 | |
|     NG_SCRAP = 30
 | |
|     NG_ACCEPT = 40
 | |
|     NG_PERMIT = 50
 | |
|     NG_DOWN = 60
 | |
|     NG_BACK_FROM = 70
 | |
|     NG_RECALL = 80
 | |
| 
 | |
|     ng_choices = (
 | |
|         (NG_BACK_WORK, '返工'),
 | |
|         (NG_BACK_FIX, '返修'),
 | |
|         (NG_SCRAP, '报废'),
 | |
|         (NG_ACCEPT, '让步接收'),
 | |
|         (NG_PERMIT, '偏离许可'),
 | |
|         (NG_DOWN, '降级使用'),
 | |
|         (NG_BACK_FROM, '退回供方'),
 | |
|         (NG_RECALL, '召回')
 | |
|     )
 | |
|     number = models.CharField(
 | |
|         '物品编号', unique=True, null=True, blank=True, max_length=50)
 | |
|     material = models.ForeignKey(
 | |
|         Material, verbose_name='所属物料状态', on_delete=models.CASCADE,
 | |
|         related_name='wp_material')
 | |
|     pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
 | |
|                                  on_delete=models.CASCADE, related_name='wp_pre_step')
 | |
|     step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
 | |
|                              related_name='wp_step')
 | |
|     act_state = models.IntegerField(
 | |
|         '进行状态', default=0, choices=act_state_choices)
 | |
|     is_hidden = models.BooleanField('是否隐藏', default=False)
 | |
|     child = models.ForeignKey('self', blank=True, null=True,
 | |
|                               on_delete=models.CASCADE, related_name='wp_child')
 | |
|     remark = models.CharField('备注', max_length=200, null=True, blank=True)
 | |
|     subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
 | |
|                                            related_name='wproduct_subplan')
 | |
| 
 | |
|     scrap_reason = models.IntegerField(
 | |
|         '报废原因', choices=scrap_reason_choices, null=True, blank=True)
 | |
|     ng_sign = models.PositiveSmallIntegerField(
 | |
|         '不合格标记', choices=ng_choices, null=True, blank=True)
 | |
| 
 | |
|     warehouse = models.ForeignKey(
 | |
|         WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
 | |
| 
 | |
|     operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
 | |
|                                   on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation')
 | |
|     coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
 | |
|                                    on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_coperation')
 | |
|     test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
 | |
|                              on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_test')
 | |
|     ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
 | |
|                                on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket')
 | |
|     
 | |
|     need_to_order = models.BooleanField('是否要指派订单', default=False)
 | |
|     to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
 | |
|     is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
 | |
|     remark_mtest = models.TextField('军检备注', null=True, blank=True)
 | |
|     last_test_result = models.BooleanField('最后一次检验结果', null=True, blank=True)
 | |
| 
 | |
|     @property
 | |
|     def last_process_test(self):
 | |
|         """
 | |
|         最后提交的工序自检
 | |
|         """
 | |
|         return self.test_wproduct.filter(type=TestRecord.TEST_PROCESS, is_submited=True).order_by('-id').first()
 | |
| 
 | |
| 
 | |
| class WprouctTicket(CommonAModel):
 | |
|     """
 | |
|     玻璃审批工单
 | |
|     """
 | |
| 
 | |
|     number = models.CharField('物品编号', null=True, blank=True, max_length=50)
 | |
|     wproduct = models.ForeignKey(
 | |
|         WProduct, verbose_name='关联产品', on_delete=models.CASCADE)
 | |
|     material = models.ForeignKey(
 | |
|         Material, verbose_name='所在物料状态', on_delete=models.CASCADE)
 | |
|     step = models.ForeignKey(
 | |
|         Step, verbose_name='所在步骤/发现步骤', on_delete=models.CASCADE)
 | |
|     subproduction_plan = models.ForeignKey(
 | |
|         SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE)
 | |
| 
 | |
|     resp_process = models.ForeignKey(
 | |
|         Process, verbose_name='责任工序', on_delete=models.CASCADE, null=True, blank=True)
 | |
|     ticket = models.ForeignKey(
 | |
|         'wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket')
 | |
|     decision = models.PositiveSmallIntegerField(
 | |
|         '最终决定', choices=WProduct.ng_choices, null=True, blank=True)
 | |
| 
 | |
| 
 | |
| class WproductFlow(CommonAModel):
 | |
|     """
 | |
|     动态产品表日志
 | |
|     """
 | |
|     wproduct = models.ForeignKey(
 | |
|         WProduct, on_delete=models.CASCADE, verbose_name='关联产品', null=True, blank=True)
 | |
|     number = models.CharField('物品编号', null=True, blank=True, max_length=50)
 | |
|     material = models.ForeignKey(
 | |
|         Material, verbose_name='所属物料状态', on_delete=models.CASCADE, related_name='wpf_material')
 | |
|     pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True,
 | |
|                                  on_delete=models.CASCADE, related_name='wpf_pre_step')
 | |
|     step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True,
 | |
|                              related_name='wpf_step')
 | |
|     act_state = models.IntegerField(
 | |
|         '进行状态', default=0, choices=WProduct.act_state_choices)
 | |
|     is_hidden = models.BooleanField('是否隐藏', default=False)
 | |
|     child = models.ForeignKey('self', blank=True, null=True,
 | |
|                               on_delete=models.CASCADE, related_name='wpf_child')
 | |
|     remark = models.CharField('备注', max_length=200, null=True, blank=True)
 | |
|     subproduction_plan = models.ForeignKey(
 | |
|         SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
 | |
| 
 | |
|     scrap_reason = models.IntegerField(
 | |
|         '报废原因', choices=WProduct.scrap_reason_choices, null=True, blank=True)
 | |
|     ng_sign = models.PositiveSmallIntegerField(
 | |
|         '不合格标记', choices=WProduct.ng_choices, null=True, blank=True)
 | |
| 
 | |
|     warehouse = models.ForeignKey(
 | |
|         WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
 | |
|     operation = models.ForeignKey('wpm.operation', verbose_name='当前操作',
 | |
|                                   on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_operation')
 | |
|     coperation = models.ForeignKey('wpm.operation', verbose_name='创建所关联操作',
 | |
|                                    on_delete=models.SET_NULL, null=True, blank=True, related_name='wpf_coperation')
 | |
|     test = models.ForeignKey('qm.testrecord', verbose_name='当前检验',
 | |
|                              on_delete=models.SET_NULL, null=True, blank=True)
 | |
|     ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单',
 | |
|                                on_delete=models.SET_NULL, null=True, blank=True)
 | |
| 
 | |
|     need_to_order = models.BooleanField('是否要指派订单', default=False)
 | |
|     to_order = models.ForeignKey('sam.order', verbose_name='指派的订单', null=True, blank=True, on_delete = models.CASCADE)
 | |
|     is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True)
 | |
|     remark_mtest = models.TextField('军检备注', null=True, blank=True)
 | |
|     last_test_result = models.BooleanField('最后一次检验结果', null=True, blank=True)
 | |
| 
 | |
|     is_lastlog = models.BooleanField('是否该子计划下的最后一条日志', default=True)
 | |
|     change_str = models.CharField('变动描述', default='', max_length=1000)
 | |
| 
 | |
| 
 | |
| class Pick(CommonADModel):
 | |
|     """
 | |
|     领料记录
 | |
|     """
 | |
|     PICK_FROM_WAREHOUSE = 10
 | |
|     PICK_FROM_WPRODUCT = 20
 | |
|     type_choice = (
 | |
|         (PICK_FROM_WAREHOUSE, '仓库领取'),
 | |
|         (PICK_FROM_WPRODUCT, '半成品领取'),
 | |
|     )
 | |
|     subproduction_plan = models.ForeignKey(
 | |
|         SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE)
 | |
|     type = models.PositiveSmallIntegerField(
 | |
|         choices=type_choice, default=PICK_FROM_WAREHOUSE)
 | |
|     fifo = models.ForeignKey(
 | |
|         FIFO, verbose_name='关联的出入库记录', on_delete=models.CASCADE, null=True, blank=True)
 | |
| 
 | |
| 
 | |
| class PickWproduct(BaseModel):
 | |
|     """
 | |
|     领取半成品时详情
 | |
|     """
 | |
|     pick = models.ForeignKey(Pick, verbose_name='关联领料',
 | |
|                              on_delete=models.CASCADE)
 | |
|     wproduct = models.ForeignKey(
 | |
|         WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='pw_wproduct')
 | |
|     number = models.CharField('物品编号', null=True, blank=True, max_length=50)
 | |
|     material = models.ForeignKey(
 | |
|         Material, verbose_name='领取时的物料状态', on_delete=models.CASCADE)
 | |
|     subproduction_plan = models.ForeignKey(
 | |
|         SubProductionPlan, verbose_name='领取时所属子生产计划', on_delete=models.CASCADE)
 | |
| 
 | |
| 
 | |
| class Operation(CommonADModel):
 | |
|     """
 | |
|     生产操作
 | |
|     """
 | |
|     step = models.ForeignKey(Step, verbose_name='操作步骤',
 | |
|                              on_delete=models.CASCADE, null=True, blank=True)
 | |
|     remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
 | |
|     is_submited = models.BooleanField('是否提交', default=False)
 | |
| 
 | |
| 
 | |
| class OperationWproduct(BaseModel):
 | |
|     """
 | |
|     生产操作半成品关联表
 | |
|     """
 | |
|     operation = models.ForeignKey(
 | |
|         Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation')
 | |
|     wproduct = models.ForeignKey(
 | |
|         WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct')
 | |
|     number = models.CharField('物品编号', null=True, blank=True, max_length=50)
 | |
|     material = models.ForeignKey(
 | |
|         Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
 | |
|     subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE,
 | |
|                                            related_name='ow_subplan')
 | |
|     ng_sign = models.PositiveSmallIntegerField(
 | |
|         '当时的不合格标记', choices=WProduct.ng_choices, null=True, blank=True)
 | |
|     place = models.CharField('摆放位置', null=True, blank=True, max_length=200)
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = (
 | |
|             ('operation', 'wproduct')
 | |
|         )
 | |
| 
 | |
| 
 | |
| class OperationMaterial(BaseModel):
 | |
|     """
 | |
|     生产操作物料消耗产出表
 | |
|     """
 | |
|     type = models.IntegerField(
 | |
|         '类型', default=0, choices=SubprodctionMaterial.type_choices)
 | |
|     operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE,
 | |
|                                   related_name='om_operation')
 | |
| 
 | |
|     material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE,
 | |
|                                  null=True, blank=True, related_name='om_material')
 | |
|     count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True)
 | |
| 
 | |
|     wmaterial = models.ForeignKey(
 | |
|         WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
 | |
|     subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE,
 | |
|                                                null=True, blank=True)
 | |
| 
 | |
|     subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE,
 | |
|                                            null=True, blank=True)
 | |
|     batch = models.CharField('批次号', max_length=100, null=True, blank=True)
 | |
|     use_scrap = models.BooleanField('是否使用的边角料', default=False)
 | |
| 
 | |
|     # 以下为冷加工下料清单所用字段
 | |
|     from_material = models.ForeignKey(Material, verbose_name='源物料', on_delete=models.CASCADE,
 | |
|                                       null=True, blank=True, related_name='om_fmaterial')
 | |
|     from_batch = models.CharField('源批次', max_length=100, null=True, blank=True)
 | |
|     count_cut = models.PositiveIntegerField('切裁片数', default=0)
 | |
|     count_real = models.PositiveIntegerField('生产片数', default=0)
 | |
|     count_ok = models.PositiveIntegerField('成品数量', default=0)
 | |
|     count_qipao = models.PositiveIntegerField('气泡甩片', default=0)
 | |
|     count_podian = models.PositiveIntegerField('破点甩片', default=0)
 | |
|     count_hua = models.PositiveIntegerField('划伤甩片', default=0)
 | |
|     count_other = models.PositiveIntegerField('其他甩片', default=0)
 | |
| 
 | |
|     class Meta:
 | |
|         unique_together = (
 | |
|             ('operation', 'material', 'batch')
 | |
|         )
 | |
| 
 | |
| 
 | |
| class OperationRecord(BaseModel):
 | |
|     """
 | |
|     记录表格
 | |
|     """
 | |
|     form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格',
 | |
|                              on_delete=models.CASCADE, related_name='or_form')
 | |
|     operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE,
 | |
|                                   related_name='or_operation')
 | |
|     is_filled = models.BooleanField('是否填写', default=True)
 | |
| 
 | |
| 
 | |
| class OperationRecordItem(BaseModel):
 | |
|     """
 | |
|     记录表格字段值
 | |
|     """
 | |
|     form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE,
 | |
|                                    related_name='ori_form_field')
 | |
|     field_value = models.JSONField('录入值', null=True, blank=True)
 | |
|     operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE,
 | |
|                                          related_name='item_operation_record')
 | |
| 
 | |
| 
 | |
| class OperationEquip(BaseModel):
 | |
|     operation = models.ForeignKey(
 | |
|         Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation')
 | |
|     equip = models.ForeignKey(Equipment, verbose_name='生产设备',
 | |
|                               on_delete=models.CASCADE, related_name='oe_equip')
 | |
|     state = models.PositiveSmallIntegerField('当前设备状态', choices=Equipment.state_choices, default=Equipment.EQUIP_STATE_OK)
 | |
|     remark = models.TextField('备注', null=True, blank=True)
 |