Compare commits

..

30 Commits

Author SHA1 Message Date
liaodanlong
186ac391ea 并发创建制造订单的工单 2025-01-21 15:53:09 +08:00
黄焱
53ceed4649 Accept Merge Request #1782: (feature/前端样式修改 -> develop)
Merge Request: 放弃保存 -> 不保存

Created By: @黄焱
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1782?initial=true
2025-01-17 14:22:56 +08:00
hyyy
e39e9d8812 放弃保存 -> 不保存 2025-01-17 14:17:46 +08:00
胡尧
0a01afc863 Accept Merge Request #1781: (feature/增加质检模块 -> develop)
Merge Request: 修复采购单没有接收产品的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1781?initial=true
2025-01-17 12:55:39 +08:00
胡尧
98b338f33a 修复采购单没有接收产品的问题 2025-01-17 12:55:09 +08:00
胡尧
3c12b05b94 Accept Merge Request #1780: (feature/增加质检模块 -> develop)
Merge Request: 修复采购单没有接收产品的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1780?initial=true
2025-01-17 11:27:40 +08:00
胡尧
b619c15231 修复采购单没有接收产品的问题 2025-01-17 11:27:04 +08:00
禹翔辉
bccdd93884 Accept Merge Request #1779: (feature/制造订单状态优化_1 -> develop)
Merge Request: 制造订单状态优化

Created By: @禹翔辉
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1779?initial=true
2025-01-17 11:07:54 +08:00
yuxianghui
41cdeb7fd9 制造订单状态优化 2025-01-17 11:06:17 +08:00
马广威
57ab276c37 Accept Merge Request #1778: (feature/制造功能优化 -> develop)
Merge Request: 调整扫码字段位置

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1778?initial=true
2025-01-17 10:01:16 +08:00
mgw
f3e64b007e 调整扫码字段位置 2025-01-17 09:59:46 +08:00
mgw
eed89836e1 调整扫码字段位置 2025-01-17 09:36:37 +08:00
马广威
9efa4636d9 Accept Merge Request #1777: (feature/制造功能优化 -> develop)
Merge Request: 恢复屏蔽

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1777?initial=true
2025-01-16 17:40:09 +08:00
mgw
0b2b9c2bf5 恢复屏蔽 2025-01-16 17:39:34 +08:00
马广威
cc5036ce64 Accept Merge Request #1776: (feature/制造功能优化 -> develop)
Merge Request: 调整扫码字段的位置

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1776?initial=true
2025-01-16 17:11:59 +08:00
mgw
2dc54792f4 调整扫码字段的位置 2025-01-16 17:10:55 +08:00
禹翔辉
5db877a54c Accept Merge Request #1775: (feature/质检单优化_1 -> develop)
Merge Request: 优化工单的质量检查跳转按钮

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1775
2025-01-16 15:58:53 +08:00
yuxianghui
6bff1f2f64 优化工单的质量检查跳转按钮 2025-01-16 15:56:11 +08:00
禹翔辉
0aaa3bd5ba Accept Merge Request #1774: (feature/质检单优化_1 -> develop)
Merge Request: 处理制造订单再次返工时,点击返工按钮报错

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1774
2025-01-16 15:42:18 +08:00
yuxianghui
39d6c8ae24 处理制造订单再次返工时,点击返工按钮报错 2025-01-16 15:41:07 +08:00
禹翔辉
2c56011502 Accept Merge Request #1773: (feature/质检单优化_1 -> develop)
Merge Request: Merge branch 'feature/制造订单状态优化' into feature/质检单优化_1

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1773
2025-01-16 14:53:50 +08:00
yuxianghui
1e71fc1b08 Merge branch 'feature/制造订单状态优化' into feature/质检单优化_1 2025-01-16 14:51:51 +08:00
yuxianghui
add528f0f3 1、质检单有关后置三元检测的字段和页签添加工单没有后置三元检测时隐藏的条件;2、工单添加质检单跳转按钮 2025-01-16 14:51:04 +08:00
马广威
b8cff4445d Accept Merge Request #1772: (feature/制造功能优化 -> develop)
Merge Request: Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1772?initial=true
2025-01-16 14:33:39 +08:00
mgw
a2d51ce04e Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2025-01-16 14:32:47 +08:00
mgw
109a093f86 调整审批状态 2025-01-16 14:32:21 +08:00
管欢
c7265bdb46 Accept Merge Request #1771: (feature/加工能力显示重叠 -> develop)
Merge Request: 修复设备档案页面数据显示

Created By: @管欢
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @管欢
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1771
2025-01-16 12:50:47 +08:00
廖丹龙
f93edef2d3 Accept Merge Request #1770: (feature/customer_supply -> develop)
Merge Request: 修改采购单非询价状态只读

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1770
2025-01-16 12:42:28 +08:00
liaodanlong
5c780c7b82 客供料合并 2025-01-16 11:35:37 +08:00
liaodanlong
303fcd0430 修改采购单非询价状态只读 2025-01-16 11:24:21 +08:00
15 changed files with 341 additions and 197 deletions

View File

@@ -62,7 +62,7 @@ patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
const dom1 = buttonsDom.children('.o_form_button_save') const dom1 = buttonsDom.children('.o_form_button_save')
const dom2 = buttonsDom.children('.o_form_button_cancel') const dom2 = buttonsDom.children('.o_form_button_cancel')
dom1.append('保存') dom1.append('保存')
dom2.append('放弃保存') dom2.append('保存')
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)

View File

@@ -21,13 +21,23 @@ class jikimo_purchase_tier_validation(models.Model):
def button_confirm(self): def button_confirm(self):
for record in self: for record in self:
if record.need_validation and record.validation_status != 'validated': # if record.need_validation and record.validation_status != 'validated':
raise ValidationError(_('此操作需要至少对一条记录进行审批。\n请发起审批申请。')) # raise ValidationError(_('此操作需要至少对一条记录进行审批。\n请发起审批申请。'))
if record.state in ['to approve']: if record.state in ['to approve']:
raise ValidationError(_('请先完成审批。')) raise ValidationError(_('请先完成审批。'))
# if record.state == 'approved':
# record.state = 'purchase'
res = super(jikimo_purchase_tier_validation, self).button_confirm()
for record in self:
if record.state == 'approved': if record.state == 'approved':
record.state = 'purchase' record.order_line._validate_analytic_distribution()
return super().button_confirm() record._add_supplier_to_product()
# Deal with double validation process
if record._approval_allowed():
record.button_approve()
if record.partner_id not in record.message_partner_ids:
record.message_subscribe([record.partner_id.id])
return res
# def button_confirm(self): # def button_confirm(self):
# self = self.with_context(skip_validation=True) # self = self.with_context(skip_validation=True)
@@ -87,15 +97,14 @@ class jikimo_purchase_tier_validation(models.Model):
def _validate_tier(self, tiers=False): def _validate_tier(self, tiers=False):
res = super(jikimo_purchase_tier_validation, self)._validate_tier(tiers) res = super(jikimo_purchase_tier_validation, self)._validate_tier(tiers)
tier_reviews = tiers or self.review_ids
# 检查是否所有审批都已通过 # 检查是否所有审批都已通过
all_approved = all( all_approved = all(
tier_review.status == 'approved' tier_review.status == 'approved'
for tier_review in tier_reviews for tier_review in self.review_ids
) )
if all_approved and tier_reviews: # 确保有审批记录 if self.review_ids and all_approved: # 确保有审批记录
self.state = 'approved' self.state = 'approved'
return res return res

View File

@@ -7,6 +7,7 @@
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/> <field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//notebook/page[last()]" position="after"> <xpath expr="//notebook/page[last()]" position="after">
<field name="routing_type" invisible="1"/>
<page string="异常记录" name="workorder_exception" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"> <page string="异常记录" name="workorder_exception" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}">
<field name="exception_ids" nolabel="1" readonly="1"> <field name="exception_ids" nolabel="1" readonly="1">
<tree create="false" delete="false" edit="false"> <tree create="false" delete="false" edit="false">

View File

@@ -1,20 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import asyncio
import base64 import base64
import cProfile
import concurrent
import datetime import datetime
import io
import logging import logging
import json import json
import os import os
import pstats
import re import re
import threading
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import requests import requests
from itertools import groupby from itertools import groupby
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models, SUPERUSER_ID, _, tools
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
class MrpProduction(models.Model): class MrpProduction(models.Model):
_inherit = 'mrp.production' _inherit = 'mrp.production'
_description = "制造订单" _description = "制造订单"
@@ -350,7 +357,7 @@ class MrpProduction(models.Model):
if any((wo.test_results == '返工' and wo.state == 'done' and if any((wo.test_results == '返工' and wo.state == 'done' and
(production.programming_state in ['已编程'] or wo.individuation_page_PTD is True)) (production.programming_state in ['已编程'] or wo.individuation_page_PTD is True))
or (wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程']) or (wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程'])
for wo in production.workorder_ids): for wo in production.workorder_ids) or production.is_rework is True:
production.state = 'rework' production.state = 'rework'
if any(wo.test_results == '报废' and wo.state == 'done' for wo in production.workorder_ids): if any(wo.test_results == '报废' and wo.state == 'done' for wo in production.workorder_ids):
production.state = 'scrap' production.state = 'scrap'
@@ -759,64 +766,105 @@ class MrpProduction(models.Model):
# if self.product_id.tracking == 'serial': # if self.product_id.tracking == 'serial':
# self._set_qty_producing() # self._set_qty_producing()
# 重载根据工序生成工单的程序如果产品BOM中没有工序时 # 重载根据工序生成工单的程序如果产品BOM中没有工序时
# 根据产品对应的模板类型中工序,去生成工单; # 根据产品对应的模板类型中工序,去生成工单;
# CNC加工工序的选取规则 # CNC加工工序的选取规则
# 如果自动报价有带过来预分配的机床, # 如果自动报价有带过来预分配的机床,
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制; # 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def process_production(self):
workorders_values = []
# production = self.env['mrp.production'].browse(production_id)
product_qty = self.product_uom_id._compute_quantity(self.product_qty,
self.bom_id.product_uom_id)
exploded_boms, dummy = self.bom_id.explode(self.product_id,
product_qty / self.bom_id.product_qty,
picking_type=self.bom_id.picking_type_id)
for bom, bom_data in exploded_boms:
# If the operations of the parent BoM and phantom BoM are the same, don't recreate work orders.
if not (bom.operation_ids and (not bom_data['parent_line'] or bom_data[
'parent_line'].bom_id.operation_ids != bom.operation_ids)):
continue
for operation in bom.operation_ids:
if operation._skip_operation_line(bom_data['product']):
continue
workorders_values += [{
'name': operation.name,
'production_id': self.id,
'workcenter_id': operation.workcenter_id.id,
'product_uom_id': self.product_uom_id.id,
'operation_id': operation.id,
'state': 'pending',
}]
if self.product_id.categ_id.type in ['成品', '坯料']:
# # 根据工序设计生成工单
technology_design_ids = sorted(self.technology_design_ids, key=lambda x: x.sequence)
for route in technology_design_ids:
workorder_has = self.env['mrp.workorder'].search(
[('technology_design_id', '=', route.id), ('production_id', '=', self.id)])
if not workorder_has:
if route.route_id.routing_type not in ['表面工艺']:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(self, route))
else:
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(
self, route, product_production_process.seller_ids[0].partner_id.id))
return workorders_values
def _set_workorder_duration_expected(self):
try:
# 在每个线程中创建独立的 ORM 环境
with api.Environment.manage():
new_cr = self.pool.cursor()
self = self.with_env(self.env(cr=new_cr))
# program_ids = self.sudo().env['loyalty.program'].browse(program_ids.ids)
# 使用独立的环境来处理数据库事务
# 在独立的环境中对 workorder 进行操作
production = self.sudo().env['mrp.production'].browse(self.id)
workorders_values = production.process_production()
production.write({'workorder_ids': workorders_values})
for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected()
# 可以进行其他与工作单相关的操作
# workorder_env.write({'...'})
return production
except Exception as e:
logging.error(f"Error processing workorder {workorder.id}: {e}")
# workorders_values = self.process_production(self)
# print('_set_workorder_duration_expected wqio ', self)
# self.write({'workorder_ids': workorders_values})
# for workorder in self.workorder_ids:
# workorder.duration_expected = workorder._get_duration_expected()
def _create_workorder3(self, item): def _create_workorder3(self, item):
for production in self: with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
if not production.bom_id or not production.product_id: futures = []
continue for production in self:
workorders_values = [] if not production.bom_id or not production.product_id:
product_qty = production.product_uom_id._compute_quantity(production.product_qty,
production.bom_id.product_uom_id)
exploded_boms, dummy = production.bom_id.explode(production.product_id,
product_qty / production.bom_id.product_qty,
picking_type=production.bom_id.picking_type_id)
for bom, bom_data in exploded_boms:
# If the operations of the parent BoM and phantom BoM are the same, don't recreate work orders.
if not (bom.operation_ids and (not bom_data['parent_line'] or bom_data[
'parent_line'].bom_id.operation_ids != bom.operation_ids)):
continue continue
for operation in bom.operation_ids: # 提交每个生产任务到线程池
if operation._skip_operation_line(bom_data['product']): futures.append(executor.submit(production._set_workorder_duration_expected))
continue
workorders_values += [{ # 等待所有线程完成任务
'name': operation.name, results = []
'production_id': production.id, for future in futures:
'workcenter_id': operation.workcenter_id.id, try:
'product_uom_id': production.product_uom_id.id, result = future.result()
'operation_id': operation.id, if result:
'state': 'pending', results.append(result)
}]
if production.product_id.categ_id.type in ['成品', '坯料']: except Exception as e:
# # 根据工序设计生成工单 logging.error(f"Error processing production: {e}")
technology_design_ids = sorted(production.technology_design_ids, key=lambda x: x.sequence) return results
for route in technology_design_ids:
workorder_has = self.env['mrp.workorder'].search(
[('technology_design_id', '=', route.id), ('production_id', '=', production.id)])
if not workorder_has:
if route.route_id.routing_type not in ['表面工艺']:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(production, route))
else:
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(
production, route, product_production_process.seller_ids[0].partner_id.id))
production.workorder_ids = workorders_values
for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected()
# 外协出入库单处理 # 外协出入库单处理
def get_subcontract_pick_purchase(self): def get_subcontract_pick_purchase(self,productions):
production_all = self.sorted(lambda x: x.id) production_all = productions.sorted(lambda x: x.id)
product_id_to_production_names = {} product_id_to_production_names = {}
grouped_product_ids = {k: list(g) for k, g in grouped_product_ids = {k: list(g) for k, g in
groupby(production_all, key=lambda x: x.product_id.id)} groupby(production_all, key=lambda x: x.product_id.id)}
@@ -825,9 +873,10 @@ class MrpProduction(models.Model):
sorted_workorders = None sorted_workorders = None
for production in production_all: for production in production_all:
proc_workorders = [] proc_workorders = []
process_parameter_workorder = self.env['mrp.workorder'].search( process_parameter_workorder=production.workorder_ids.filtered(lambda w: w.surface_technics_parameters_id and w.is_subcontract and w.state!='cancel')
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id), # process_parameter_workorder = self.env['mrp.workorder'].search(
('is_subcontract', '=', True), ('state', '!=', 'cancel')], order='sequence asc') # [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
# ('is_subcontract', '=', True), ('state', '!=', 'cancel')], order='sequence asc')
if process_parameter_workorder: if process_parameter_workorder:
# 将这些特殊表面工艺工单的采购单与调拨单置为失效 # 将这些特殊表面工艺工单的采购单与调拨单置为失效
for workorder in process_parameter_workorder: for workorder in process_parameter_workorder:
@@ -942,48 +991,49 @@ class MrpProduction(models.Model):
if purchase_order_line: if purchase_order_line:
line.unlink() line.unlink()
def _reset_work_order_sequence(self): def _process_reset_work_order_sequence(self,rec):
workorder_ids = rec.workorder_ids
technology_design_ids = rec.technology_design_ids
if workorder_ids.filtered(lambda item: item.state in ('返工', 'rework')):
# 获取返工后新生成的工单
work_ids = workorder_ids.filtered(lambda item: item.sequence == 0)
# 对工单进行逐个插入
for work_id in work_ids:
order_rework_ids = rec.workorder_ids.filtered(
lambda item: (item.sequence > 0 and work_id.name == item.name
and work_id.processing_panel == item.processing_panel))
order_rework_ids = sorted(order_rework_ids, key=lambda item: item.sequence, reverse=True)
work_id.sequence = order_rework_ids[0].sequence + 1
# 对该工单之后的工单工序进行加一
work_order_ids = rec.workorder_ids.filtered(
lambda item: item.sequence >= work_id.sequence and item.id != work_id.id)
for work in work_order_ids:
work.sequence = work.sequence + 1
else:
# 将工艺设计生成的工单序号赋值给工单的序号
for work in workorder_ids:
td_ids = technology_design_ids.filtered(
lambda item: (item.route_id.name in work.name and item.process_parameters_id
and item.process_parameters_id == work.surface_technics_parameters_id) or
(item.route_id.name == work.name and item.panel
and item.panel == work.processing_panel))
if work.name == '人工线下加工':
td_ids = technology_design_ids.filtered(lambda item: (item.route_id.name in work.name))
if td_ids:
work.sequence = td_ids[0].sequence
cancel_work_ids = workorder_ids.filtered(lambda item: item.state in ('已取消', 'cancel'))
if cancel_work_ids:
sequence = max(workorder_ids.filtered(lambda item: item.state not in ('已取消', 'cancel')),
key=lambda w: w.sequence).sequence
for cw in cancel_work_ids:
cw.sequence = sequence + 1
def _reset_work_order_sequence(self,productions):
""" """
工单工序排序方法(新) 工单工序排序方法(新)
""" """
for rec in self: for rec in productions:
workorder_ids = rec.workorder_ids self._process_reset_work_order_sequence(rec)
technology_design_ids = rec.technology_design_ids
if workorder_ids.filtered(lambda item: item.state in ('返工', 'rework')):
# 获取返工后新生成的工单
work_ids = workorder_ids.filtered(lambda item: item.sequence == 0)
# 对工单进行逐个插入
for work_id in work_ids:
order_rework_ids = rec.workorder_ids.filtered(
lambda item: (item.sequence > 0 and work_id.name == item.name
and work_id.processing_panel == item.processing_panel))
order_rework_ids = sorted(order_rework_ids, key=lambda item: item.sequence, reverse=True)
work_id.sequence = order_rework_ids[0].sequence + 1
# 对该工单之后的工单工序进行加一
work_order_ids = rec.workorder_ids.filtered(
lambda item: item.sequence >= work_id.sequence and item.id != work_id.id)
for work in work_order_ids:
work.sequence = work.sequence + 1
else:
# 将工艺设计生成的工单序号赋值给工单的序号
for work in workorder_ids:
td_ids = technology_design_ids.filtered(
lambda item: (item.route_id.name in work.name and item.process_parameters_id
and item.process_parameters_id == work.surface_technics_parameters_id) or
(item.route_id.name == work.name and item.panel
and item.panel == work.processing_panel))
if work.name == '人工线下加工':
td_ids = technology_design_ids.filtered(lambda item: (item.route_id.name in work.name))
if td_ids:
work.sequence = td_ids[0].sequence
cancel_work_ids = workorder_ids.filtered(lambda item: item.state in ('已取消', 'cancel'))
if cancel_work_ids:
sequence = max(workorder_ids.filtered(lambda item: item.state not in ('已取消', 'cancel')),
key=lambda w: w.sequence).sequence
for cw in cancel_work_ids:
cw.sequence = sequence + 1
def _reset_work_order_sequence_1(self): def _reset_work_order_sequence_1(self):
""" """
工单工序排序方法(旧) 工单工序排序方法(旧)
@@ -1079,9 +1129,9 @@ class MrpProduction(models.Model):
# 创建工单并进行排序 # 创建工单并进行排序
def _create_workorder(self, item): def _create_workorder(self, item):
self._create_workorder3(item) productions = self._create_workorder3(item)
self._reset_work_order_sequence() self._reset_work_order_sequence(productions)
return True return productions
def production_process(self, pro_plan): def production_process(self, pro_plan):
type_map = {'装夹预调': False, 'CNC加工': False, '解除装夹': False} type_map = {'装夹预调': False, 'CNC加工': False, '解除装夹': False}
@@ -1256,9 +1306,9 @@ class MrpProduction(models.Model):
'default_production_id': self.id, 'default_production_id': self.id,
'default_workorder_ids': workorder_ids.ids if workorder_ids.ids != [] else self.workorder_ids.ids, 'default_workorder_ids': workorder_ids.ids if workorder_ids.ids != [] else self.workorder_ids.ids,
'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '', 'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '',
'default_reprogramming_num': cloud_programming.get('reprogramming_num'), 'default_reprogramming_num': cloud_programming.get('reprogramming_num') if cloud_programming else '',
'default_programming_state': cloud_programming.get('programming_state'), 'default_programming_state': cloud_programming.get('programming_state') if cloud_programming else '',
'default_is_reprogramming': True if cloud_programming.get('programming_state') in ['已下发'] else False 'default_is_reprogramming': True if cloud_programming and (cloud_programming.get('programming_state') in ['已下发']) else False
} }
} }
@@ -1526,15 +1576,16 @@ class MrpProduction(models.Model):
product_id = self.env['product.product'].browse(vals['product_id']) product_id = self.env['product.product'].browse(vals['product_id'])
is_self_process = product_id.materials_type_id and product_id.materials_type_id.gain_way and product_id.materials_type_id.gain_way != '自加工' is_self_process = product_id.materials_type_id and product_id.materials_type_id.gain_way and product_id.materials_type_id.gain_way != '自加工'
is_customer_provided = product_id.is_customer_provided is_customer_provided = product_id.is_customer_provided
if not is_custemer_group_id.get(is_customer_provided) and is_self_process: key = f"{is_self_process}_{is_customer_provided}"
is_custemer_group_id[is_customer_provided] = self.env["procurement.group"].create({'name': vals.get('name')}).id if not is_custemer_group_id.get(key):
is_custemer_group_id[key] = self.env["procurement.group"].create({'name': vals.get('name')}).id
# if not (is_first_customer or is_first_not_customer) and is_self_process: # if not (is_first_customer or is_first_not_customer) and is_self_process:
# is_first = True # is_first = True
# group_id = self.env["procurement.group"].create({'name': vals.get('name')}).id # group_id = self.env["procurement.group"].create({'name': vals.get('name')}).id
if not vals.get('procurement_group_id'): if not vals.get('procurement_group_id'):
if product_id.product_tmpl_id.single_manufacturing: if product_id.product_tmpl_id.single_manufacturing:
if product_id.categ_id.name == '成品' and is_self_process: if product_id.categ_id.name == '成品':
vals['procurement_group_id'] = is_custemer_group_id[is_customer_provided] vals['procurement_group_id'] = is_custemer_group_id[key]
continue continue
if product_id.id not in product_group_id.keys(): if product_id.id not in product_group_id.keys():
procurement_group_vals = self._prepare_procurement_group_vals(vals) procurement_group_vals = self._prepare_procurement_group_vals(vals)
@@ -1544,7 +1595,7 @@ class MrpProduction(models.Model):
else: else:
vals['procurement_group_id'] = product_group_id[product_id.id] vals['procurement_group_id'] = product_group_id[product_id.id]
else: else:
vals['procurement_group_id'] = is_custemer_group_id[is_customer_provided] vals['procurement_group_id'] = is_custemer_group_id[key]
return super(MrpProduction, self).create(vals_list) return super(MrpProduction, self).create(vals_list)
@api.depends('procurement_group_id.stock_move_ids.created_purchase_line_id.order_id', @api.depends('procurement_group_id.stock_move_ids.created_purchase_line_id.order_id',
@@ -1755,3 +1806,5 @@ class sf_processing_panel(models.Model):
name = fields.Char('加工面') name = fields.Char('加工面')
active = fields.Boolean('有效', default=True) active = fields.Boolean('有效', default=True)

View File

@@ -1503,7 +1503,7 @@ class ResMrpWorkOrder(models.Model):
store=True) store=True)
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录', store=True, individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录', store=True,
compute='_compute_individuation_page_ids') compute='_compute_individuation_page_ids')
individuation_page_PTD = fields.Boolean('个性化记录(后置三元检测PTD)', default=False) individuation_page_PTD = fields.Boolean('个性化记录(是否显示后置三元检测[PTD]页签)', default=False)
@api.depends('name') @api.depends('name')
def _compute_routing_workcenter_id(self): def _compute_routing_workcenter_id(self):

View File

@@ -126,9 +126,10 @@
<field name="model">mrp.workorder</field> <field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/> <field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form position="inside"> <xpath expr="//form" position="inside">
<field name="_barcode_scanned" widget="barcode_handler" invisible="1"/> <!-- 其他可见字段 -->
</form> <field name="_barcode_scanned" widget="barcode_handler"/>
</xpath>
<!-- <xpath expr="//form" position="inside"> --> <!-- <xpath expr="//form" position="inside"> -->
<!-- <script src="sf_manufacturing/static/src/js/customRFID.js"/> --> <!-- <script src="sf_manufacturing/static/src/js/customRFID.js"/> -->
<!-- </xpath> --> <!-- </xpath> -->
@@ -311,7 +312,7 @@
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
<page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'> <page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
<group> <group>
<field name="_barcode_scanned" widget="barcode_handler"/> <!-- <field name="_barcode_scanned" widget="barcode_handler"/> -->
<group string="托盘"> <group string="托盘">
<field name="tray_serial_number" readonly="1" string="序列号"/> <field name="tray_serial_number" readonly="1" string="序列号"/>
</group> </group>
@@ -538,9 +539,9 @@
<!-- <field name="is_fetchcnc"--> <!-- <field name="is_fetchcnc"-->
<!-- attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>--> <!-- attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>-->
<field name="reason" <field name="reason"
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/> attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")],"readonly":[("state","in",("done", "rework"))]}'/>
<field name="detailed_reason" <field name="detailed_reason"
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/> attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")],"readonly":[("state","in",("done", "rework"))]}'/>
<!-- <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>--> <!-- <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>-->
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}' <field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
widget="pdf_viewer" readonly="1"/> widget="pdf_viewer" readonly="1"/>

View File

@@ -4,8 +4,14 @@
<record model="ir.ui.view" id="view_purchase_order_line_form_inherit_sf1"> <record model="ir.ui.view" id="view_purchase_order_line_form_inherit_sf1">
<field name="name">purchase.order.form.inherit.sf</field> <field name="name">purchase.order.form.inherit.sf</field>
<field name="model">purchase.order</field> <field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/> <field name="inherit_id" ref="purchase_order_approved.purchase_order_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="order_line" position="attributes">
<attribute
name="attrs"
>{'readonly': [('state', '!=', 'draft')]}
</attribute>
</field>
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="after"> <xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="after">
<field name="related_product" optional="show"/> <field name="related_product" optional="show"/>
<field name="part_number" optional="show"/> <field name="part_number" optional="show"/>

View File

@@ -1,7 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Part of YiZuo. See LICENSE file for full copyright and licensing details. # Part of YiZuo. See LICENSE file for full copyright and licensing details.
import logging import cProfile
from itertools import groupby import io
import pstats
from concurrent.futures import ThreadPoolExecutor
from odoo import models, api, fields, _ from odoo import models, api, fields, _
@@ -13,6 +15,71 @@ class ProductionTechnologyWizard(models.TransientModel):
origin = fields.Char(string='源单据') origin = fields.Char(string='源单据')
is_technology_confirm = fields.Boolean(default=True) is_technology_confirm = fields.Boolean(default=True)
def _process_production(self,productions,technology_designs):
for production in productions:
# self._process_production_special_design(production,technology_designs)
with ThreadPoolExecutor(max_workers=4) as executor:
executor.submit(self._process_production_special_design, production,technology_designs)
def _process_production_special_design(self,production,technology_designs):
if production != self.production_id:
self.env['sf.technology.design'].sudo().unified_procedure_multiple_work_orders(technology_designs,
production)
# 特殊表面工艺
special_design = self.env['sf.technology.design'].sudo().search(
[('routing_tag', '=', 'special'), ('production_id', '=', production.id),
('is_auto', '=', False), ('active', 'in', [True, False])])
for special in special_design:
workorders_values = []
if special.active is False:
# is_cancel = False
# 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id),
('state', '!=', 'cancel')]
else:
domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
workorder = self.env['mrp.workorder'].search(domain)
# previous_workorder = self.env['mrp.workorder'].search(
# [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
# ('production_id', '=', workorder.production_id.id)])
# if previous_workorder:
# if previous_workorder.supplier_id != workorder.supplier_id:
# is_cancel = True
# if workorder.state != 'cancel' and is_cancel is True:
workorder.write({'state': 'cancel'})
workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.name), ('purchase_type', '=', 'consignment')])
for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'})
else:
if special.production_id.workorder_ids:
workorder = self.env['mrp.workorder'].search(
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id),
('state', '!=', 'cancel')])
if not workorder:
if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(special.production_id, special,
product_production_process.seller_ids[
0].partner_id.id))
else:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values})
else:
if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1:
workorder.blocked_by_workorder_ids = None
else:
if workorder.blocked_by_workorder_ids:
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0]
def confirm(self): def confirm(self):
if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']: if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']:
domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'), domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'),
@@ -23,72 +90,24 @@ class ProductionTechnologyWizard(models.TransientModel):
[('production_id', '=', self.production_id.id), ('active', 'in', [True, False])]) [('production_id', '=', self.production_id.id), ('active', 'in', [True, False])])
# technology_designs = self.production_id.technology_design_ids # technology_designs = self.production_id.technology_design_ids
productions = self.env['mrp.production'].search(domain) productions = self.env['mrp.production'].search(domain)
for production in productions: pr = cProfile.Profile()
if production != self.production_id: pr.enable()
self.env['sf.technology.design'].sudo().unified_procedure_multiple_work_orders(technology_designs, self._process_production(productions,technology_designs)
production) productions = productions._create_workorder(False)
# 特殊表面工艺
special_design = self.env['sf.technology.design'].sudo().search(
[('routing_tag', '=', 'special'), ('production_id', '=', production.id),
('is_auto', '=', False), ('active', 'in', [True, False])])
for special in special_design:
workorders_values = []
if special.active is False:
# is_cancel = False
# 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id), ('state', '!=', 'cancel')]
else:
domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
workorder = self.env['mrp.workorder'].search(domain)
# previous_workorder = self.env['mrp.workorder'].search(
# [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
# ('production_id', '=', workorder.production_id.id)])
# if previous_workorder:
# if previous_workorder.supplier_id != workorder.supplier_id:
# is_cancel = True
# if workorder.state != 'cancel' and is_cancel is True:
workorder.write({'state': 'cancel'})
workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.name), ('purchase_type', '=', 'consignment')])
for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'})
else:
if special.production_id.workorder_ids:
workorder = self.env['mrp.workorder'].search(
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id), ('state', '!=', 'cancel')])
if not workorder:
if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(special.production_id, special,
product_production_process.seller_ids[
0].partner_id.id))
else:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values})
else:
if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1:
workorder.blocked_by_workorder_ids = None
else:
if workorder.blocked_by_workorder_ids:
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0]
productions._create_workorder(False)
if self.production_id.product_id.categ_id.type == '成品': if self.production_id.product_id.categ_id.type == '成品':
productions.get_subcontract_pick_purchase() self.production_id.get_subcontract_pick_purchase(productions)
productions.is_adjust = False
for item in productions: for item in productions:
item.is_adjust = False
workorder = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted( workorder = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(
key=lambda a: a.sequence) key=lambda a: a.sequence)
if workorder[0].state in ['pending']: if workorder[0].state in ['pending']:
if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
workorder[0].state = 'waiting' workorder[0].state = 'waiting'
pr.disable() # 停止性能分析
# 将结果输出到 StringIO
s = io.StringIO()
ps = pstats.Stats(pr, stream=s)
ps.strip_dirs().sort_stats('cumulative').print_stats()
analysis_output = s.getvalue()
return productions return productions

View File

@@ -281,7 +281,8 @@ class ReworkWizard(models.TransientModel):
{'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True}) {'programming_state': '编程中', 'work_state': '编程中', 'is_rework': True})
# ================================================= # =================================================
if self.production_id.state == 'progress': if self.production_id.state == 'progress':
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'}) if self.programming_state:
self.production_id.write({'programming_state': '已编程', 'work_state': '已编程'})
if self.reprogramming_num >= 1 and self.programming_state == '已编程': if self.reprogramming_num >= 1 and self.programming_state == '已编程':
productions_not_delivered = self.env['mrp.production'].search( productions_not_delivered = self.env['mrp.production'].search(
[('programming_no', '=', self.production_id.programming_no), [('programming_no', '=', self.production_id.programming_no),

View File

@@ -18,6 +18,7 @@
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/view.xml', 'views/view.xml',
'views/quality_cnc_test_view.xml', 'views/quality_cnc_test_view.xml',
'views/mrp_workorder.xml',
'views/quality_check_view.xml' 'views/quality_check_view.xml'
], ],

View File

@@ -4,3 +4,4 @@
from . import custom_quality from . import custom_quality
from . import quality from . import quality
from . import quality_cnc_test from . import quality_cnc_test
from . import mrp_workorder

View File

@@ -0,0 +1,28 @@
from odoo import api, fields, models
class ResMrpWorkOrder(models.Model):
_inherit = 'mrp.workorder'
check_ids_state = fields.Selection([('none', '待处理'), ('pass', '通过的'), ('fail', '失败的')], store=True,
compute='_compute_check_ids_state')
@api.depends('check_ids.quality_state')
def _compute_check_ids_state(self):
for mw in self:
if mw.check_ids:
if all(check_id.quality_state == 'pass' for check_id in mw.check_ids):
mw.check_ids_state = 'pass'
elif any(check_id.quality_state == 'fail' for check_id in mw.check_ids):
mw.check_ids_state = 'fail'
else:
mw.check_ids_state = 'none'
def action_open_quality_check_work_sf(self):
return {
'res_model': 'quality.check',
'type': 'ir.actions.act_window',
'name': '质量检查',
'domain': [('workorder_id', '=', self.id)],
'view_mode': 'tree,form',
}

View File

@@ -17,6 +17,7 @@ class QualityCheck(models.Model):
('fail', '失败的')], string='状态', tracking=True, store=True, ('fail', '失败的')], string='状态', tracking=True, store=True,
default='none', copy=False, compute='_compute_quality_state') default='none', copy=False, compute='_compute_quality_state')
individuation_page_PTD = fields.Boolean('个性化记录(是否显示后置三元检测[PTD]页签)', related='workorder_id.individuation_page_PTD')
work_state = fields.Selection(related='workorder_id.state', string='工单状态') work_state = fields.Selection(related='workorder_id.state', string='工单状态')
processing_panel = fields.Char(related='workorder_id.processing_panel', string='加工面') processing_panel = fields.Char(related='workorder_id.processing_panel', string='加工面')
@@ -26,7 +27,7 @@ class QualityCheck(models.Model):
model_file = fields.Binary(related='workorder_id.glb_file', string='加工模型') model_file = fields.Binary(related='workorder_id.glb_file', string='加工模型')
detection_report = fields.Binary(related='workorder_id.detection_report', readonly=True, string='检测报告') detection_report = fields.Binary(related='workorder_id.detection_report', readonly=True, string='检测报告')
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], string="检测结果", test_results = fields.Selection([("合格", "合格"), ("返工", "返工")], string="检测结果",
default='合格') default='合格')
reason = fields.Selection( reason = fields.Selection(
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"), [("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"),
@@ -61,7 +62,7 @@ class QualityCheck(models.Model):
def do_pass(self): def do_pass(self):
self.ensure_one() self.ensure_one()
super().do_pass() super().do_pass()
if self.workorder_id: if self.workorder_id and self.individuation_page_PTD is True:
# 1将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】 # 1将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】
if self.test_results in ['返工', '报废']: if self.test_results in ['返工', '报废']:
raise ValidationError('请重新选择【判定结果】-【检测结果】') raise ValidationError('请重新选择【判定结果】-【检测结果】')
@@ -73,7 +74,7 @@ class QualityCheck(models.Model):
def do_fail(self): def do_fail(self):
self.ensure_one() self.ensure_one()
super().do_fail() super().do_fail()
if self.workorder_id: if self.workorder_id and self.individuation_page_PTD is True:
# 1将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】 # 1将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】
if not self.test_results: if not self.test_results:
raise ValidationError('请填写【判定结果】里的信息') raise ValidationError('请填写【判定结果】里的信息')

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="mrp_workorder_quality_form_view_inherit" model="ir.ui.view">
<field name="name">mrp.workorder.view.form.inherit.quality</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<field name="check_ids_state" invisible="1"/>
<button name="action_open_quality_check_work_sf" groups="quality.group_quality_user" attrs="{'invisible': ['|',('check_ids_state', '!=', 'none'), ('check_ids', '=', [])]}" type="object" class="oe_stat_button" icon="fa-check">
<span class="o_stat_text">质量检查</span>
</button>
<button name="action_open_quality_check_work_sf" groups="quality.group_quality_user" attrs="{'invisible': ['|',('check_ids_state', '!=', 'pass'), ('check_ids', '=', [])]}" type="object" class="oe_stat_button text-success" icon="fa-check">
<span class="o_stat_text text-success">质量检查</span>
</button>
<button name="action_open_quality_check_work_sf" groups="quality.group_quality_user" attrs="{'invisible': ['|',('check_ids_state', '!=', 'fail'), ('check_ids', '=', [])]}" type="object" class="oe_stat_button text-danger" icon="fa-check">
<span class="o_stat_text text-danger">质量检查</span>
</button>
</div>
</field>
</record>
</odoo>

View File

@@ -8,22 +8,23 @@
<xpath expr="//field[@name='alert_ids']" position="after"> <xpath expr="//field[@name='alert_ids']" position="after">
<field name="production_id" invisible="1"/> <field name="production_id" invisible="1"/>
<field name="work_state" invisible="1"/> <field name="work_state" invisible="1"/>
<field name="production_line_id" attrs="{'invisible': [('production_id', '=', False)]}"/> <field name="individuation_page_PTD" invisible="1"/>
<field name="equipment_id" attrs="{'invisible': [('production_id', '=', False)]}"/> <field name="production_line_id" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
<field name="equipment_id" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1" <field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': ['|', ('model_file', '=', False), ('production_id', '=', False)]}"/> attrs="{'invisible': ['|', '|',('model_file', '=', False), ('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
</xpath> </xpath>
<xpath expr="//field[@name='partner_id']" position="after"> <xpath expr="//field[@name='partner_id']" position="after">
<field name="processing_panel" attrs="{'invisible': [('production_id', '=', False)]}"/> <field name="processing_panel" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
<field name="workorder_id" string="工单号" readonly="1" <field name="workorder_id" string="工单号" readonly="1"
attrs="{'invisible': [('production_id', '=', False)]}"/> attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
<field name="is_inspect" attrs="{'invisible': [('production_id', '=', False)]}"/> <field name="is_inspect" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
</xpath> </xpath>
<xpath expr="//page[@name='notes']" position="before"> <xpath expr="//page[@name='notes']" position="before">
<page string="检测报告" attrs="{'invisible': [('production_id', '=', False)]}"> <page string="检测报告" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
<field name="detection_report" string="" widget="pdf_viewer"/> <field name="detection_report" string="" widget="pdf_viewer"/>
</page> </page>
<page string="判定结果" attrs="{'invisible': [('production_id', '=', False)]}"> <page string="判定结果" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
<group> <group>
<group> <group>
<field name="test_results" attrs="{'readonly': [('quality_state','in', ['pass', 'fail'])]}"/> <field name="test_results" attrs="{'readonly': [('quality_state','in', ['pass', 'fail'])]}"/>
@@ -34,14 +35,14 @@
</group> </group>
</group> </group>
</page> </page>
<page string="2D图纸" attrs="{'invisible': [('production_id', '=', False)]}"> <page string="2D图纸" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
<field name="machining_drawings" string="" widget="adaptive_viewer"/> <field name="machining_drawings" string="" widget="adaptive_viewer"/>
</page> </page>
<page string="客户质量标准" attrs="{'invisible': [('production_id', '=', False)]}"> <page string="客户质量标准" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
<field name="quality_standard" string="" widget="adaptive_viewer"/> <field name="quality_standard" string="" widget="adaptive_viewer"/>
</page> </page>
<page string="其他" <page string="其他"
attrs="{'invisible': ['|', ('quality_state', 'not in', ['pass', 'fail']), ('production_id', '=', False)]}"> attrs="{'invisible': ['|','|', ('quality_state', 'not in', ['pass', 'fail']), ('production_id', '=', False),('individuation_page_PTD', '=', False)]}">
<group> <group>
<field name="write_uid" widget='many2one_avatar_user' string="判定人" readonly="1"/> <field name="write_uid" widget='many2one_avatar_user' string="判定人" readonly="1"/>
<field name="write_date" string="判定时间" readonly="1"/> <field name="write_date" string="判定时间" readonly="1"/>