Compare commits

...

50 Commits

Author SHA1 Message Date
liaodanlong
9f67dbe9aa 工序外协工单没有自动触发工单开始、结束的优化需求处理 2024-12-12 16:06:55 +08:00
liaodanlong
ab32f881c2 制造订单退回调整删除表面工艺再次确认后-没被删除的表面工艺的外协出入库单变成了草稿状态问题处理 2024-12-11 17:09:51 +08:00
liaodanlong
f32ca13dff 修改日志的使用库 2024-12-11 11:05:25 +08:00
liaodanlong
d1ba2cc3d4 Merge branch 'refs/heads/develop' into feature/delivery_status
# Conflicts:
#	sf_manufacturing/models/mrp_production.py
2024-12-11 10:07:34 +08:00
liaodanlong
4738b03a45 销售订单与制造订单关联 2024-12-11 10:03:20 +08:00
禹翔辉
e14e750bd9 Accept Merge Request #1610: (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/1610?initial=true
2024-12-09 16:08:52 +08:00
yuxianghui
1c4a6ca85e 开放返工入口 2024-12-09 16:07:34 +08:00
管欢
c922ae1571 Accept Merge Request #1609: (feature/manufactur_order -> 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/1609
2024-12-09 09:48:12 +08:00
guanhuan
ed6189a963 Merge remote-tracking branch 'origin/feature/manufactur_order' into feature/manufactur_order 2024-12-09 09:36:08 +08:00
guanhuan
a6979b213b 手动创建的采购单生成的内部调拨单没有源单据 2024-12-09 09:35:41 +08:00
马广威
f873ebe079 Accept Merge Request #1608: (release/release_2.6 -> 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/1608
2024-12-05 18:26:29 +08:00
mgw
ab692dfb25 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-12-05 18:25:08 +08:00
马广威
e50b601ccf Accept Merge Request #1607: (feature/制造功能优化 -> develop)
Merge Request: 对合并后的采购单修改匹配逻辑

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1607?initial=true
2024-12-05 18:15:09 +08:00
mgw
37c47b0a54 对合并后的采购单修改匹配逻辑 2024-12-05 18:14:19 +08:00
马广威
6f9cea2759 Accept Merge Request #1606: (feature/制造功能优化 -> develop)
Merge Request: 特殊表面工艺采购单还是有合并的情况-且重复了

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1606?initial=true
2024-12-05 17:03:08 +08:00
mgw
0601e123fb Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化 2024-12-05 17:01:36 +08:00
mgw
08e4541a96 特殊表面工艺采购单还是有合并的情况-且重复了 2024-12-05 17:01:10 +08:00
胡尧
66acc19e89 Accept Merge Request #1605: (feature/sale_order_route_pick -> develop)
Merge Request: 工艺设计新增工序只选择了参数时确认增加提示

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1605?initial=true
2024-12-05 16:56:20 +08:00
胡尧
5b94a0624c 工艺设计新增工序只选择了参数时确认增加提示 2024-12-05 16:55:51 +08:00
胡尧
1b5b2fd6f9 Accept Merge Request #1604: (feature/sale_order_route_pick -> develop)
Merge Request: 处理供应商相同的特殊表面工艺不能删除的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1604?initial=true
2024-12-05 16:36:55 +08:00
胡尧
54c502dd64 处理供应商相同的特殊表面工艺不能删除的问题 2024-12-05 16:36:33 +08:00
胡尧
e3db40ae25 Accept Merge Request #1603: (feature/sale_order_route_pick -> develop)
Merge Request: 解决删除表面工艺,多增加了采购单的bug

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1603
2024-12-05 15:09:49 +08:00
胡尧
52ab962ace 解决删除表面工艺,多增加了采购单的bug 2024-12-05 15:09:04 +08:00
胡尧
05247ee8d9 Accept Merge Request #1602: (feature/sale_order_route_pick -> develop)
Merge Request: 特殊表面工艺工单没有完成对应采购单时工单处于等待组件

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1602?initial=true
2024-12-05 13:42:33 +08:00
胡尧
dbf75684ee 特殊表面工艺工单没有完成对应采购单时工单处于等待组件 2024-12-05 13:42:07 +08:00
马广威
cb2319492b Accept Merge Request #1601: (feature/制造功能优化 -> develop)
Merge Request: 制造订单退回调整-删除表面工艺后对应的外协出入库单没有变成取消状态

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1601
2024-12-05 11:49:03 +08:00
mgw
731e6abc90 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化
# Conflicts:
#	sf_manufacturing/models/mrp_workorder.py
2024-12-05 11:48:07 +08:00
mgw
58b33b6c8d 制造订单退回调整-删除表面工艺后对应的外协出入库单没有变成取消状态 2024-12-05 11:05:43 +08:00
胡尧
43c8bbda71 Accept Merge Request #1600: (feature/sale_order_route_pick -> develop)
Merge Request: 解决表面工艺工单完成后,生产入库单未就绪的问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1600?initial=true
2024-12-05 09:32:00 +08:00
胡尧
e011e4cfd6 解决表面工艺工单完成后,生产入库单未就绪的问题 2024-12-05 09:31:06 +08:00
胡尧
c8fd2d69bd Accept Merge Request #1599: (feature/sale_order_route_pick -> develop)
Merge Request: 修改工艺外协工单

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1599?initial=true
2024-12-05 08:37:05 +08:00
胡尧
ef1f7b1d08 解决冲突 2024-12-05 08:36:48 +08:00
胡尧
5f12976d8f 修改表面工艺外协工单流程 2024-12-05 01:33:46 +08:00
胡尧
ef60f36c90 修改工艺外协工单 2024-12-04 20:42:34 +08:00
廖丹龙
c8ed45b1a7 Accept Merge Request #1598: (feature/manufactur_order -> 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/1598?initial=true
2024-12-04 16:43:58 +08:00
liaodanlong
57fe68bae8 Merge remote-tracking branch 'origin/feature/manufactur_order' into feature/manufactur_order 2024-12-04 16:42:13 +08:00
liaodanlong
aa32fdcd07 坯料长宽高修改 2024-12-04 16:41:42 +08:00
管欢
d0d59135e3 Accept Merge Request #1597: (feature/manufactur_order -> 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/1597
2024-12-04 16:39:44 +08:00
guanhuan
27ec5b1b74 多个制造订单菜单修复 2024-12-04 16:13:55 +08:00
禹翔辉
2c1caabce6 Accept Merge Request #1596: (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/1596
2024-12-04 15:41:11 +08:00
yuxianghui
8f3cd9ff36 Merge branch 'feature/隐藏返工入口' into feature/界面优化 2024-12-04 15:39:05 +08:00
yuxianghui
6366904c91 添加客供料入库单的合并选项 2024-12-04 15:37:58 +08:00
马广威
7f3e6de127 Accept Merge Request #1595: (feature/制造功能优化 -> develop)
Merge Request: 处理“制造订单退回调整删除特殊表面工艺后对应坯料的采购单也变成取消状态了”

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1595?initial=true
2024-12-04 12:24:18 +08:00
yuxianghui
5b43cceb94 计划模块的【制造订单生产计划】页面菜单名称改为【CNC产线计划排程】 2024-12-04 11:56:38 +08:00
mgw
d933416b2d 处理“制造订单退回调整删除特殊表面工艺后对应坯料的采购单也变成取消状态了” 2024-12-04 11:52:52 +08:00
yuxianghui
e260ef01f0 隐藏销售模块的 快速订单 菜单 2024-12-04 11:43:02 +08:00
廖丹龙
0fef3d7a63 Accept Merge Request #1594: (feature/manufactur_order -> 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/1594?initial=true
2024-12-04 10:49:12 +08:00
liaodanlong
dc5c0b1d1e Merge branch 'refs/heads/develop' into feature/manufactur_order 2024-12-04 10:46:38 +08:00
liaodanlong
9a1cde6abc 表面工艺采购单与调拨单拆分 2024-12-04 10:45:46 +08:00
liaodanlong
73ab43f16a 人工线下加工 2024-11-28 10:05:17 +08:00
15 changed files with 422 additions and 275 deletions

View File

@@ -44,7 +44,7 @@ class StockRuleInherit(models.Model):
po = self.env['purchase.order'].sudo().search([ po = self.env['purchase.order'].sudo().search([
('partner_id', '=', supplier.partner_id.id), ('partner_id', '=', supplier.partner_id.id),
('company_id', '=', procurement.company_id.id), # 保证公司一致 ('company_id', '=', procurement.company_id.id), # 保证公司一致
('origin', '=', procurement.origin), # 根据来源匹配 ('origin', 'like', procurement.origin), # 根据来源匹配
('state', '=', 'draft') # 状态为草稿 ('state', '=', 'draft') # 状态为草稿
], limit=1) ], limit=1)
logging.info("po=: %s", po) logging.info("po=: %s", po)

View File

@@ -15,3 +15,4 @@ from . import sf_technology_design
from . import sf_production_common from . import sf_production_common
from . import sale_order from . import sale_order
from . import quick_easy_order from . import quick_easy_order
from . import purchase_order

View File

@@ -8,6 +8,7 @@ import re
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, _
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
@@ -18,6 +19,7 @@ class MrpProduction(models.Model):
_inherit = 'mrp.production' _inherit = 'mrp.production'
_description = "制造订单" _description = "制造订单"
_order = 'create_date desc' _order = 'create_date desc'
sale_order_id = fields.Many2one('sale.order', string='销售订单', compute='_compute_sale_order_id', store=True)
deadline_of_delivery = fields.Date('订单交期', tracking=True, compute='_compute_deadline_of_delivery') deadline_of_delivery = fields.Date('订单交期', tracking=True, compute='_compute_deadline_of_delivery')
# tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘") # tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘")
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests") maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
@@ -34,6 +36,29 @@ class MrpProduction(models.Model):
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True) tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True) tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_sale_order_id(self):
for production in self:
# 初始化 sale_order_id 为 False
sale_order_id = False
# 使用正则表达式查找产品名称中的 'S' 开头的字母数字字符串
match = re.search(r'S\d+', production.product_id.with_context(lang='zh_CN').name) # 从字符串开始匹配
if match:
result = match.group(0)
try:
# 查找与匹配的字符串相符的销售订单
sale_order = self.env['sale.order'].search(
[('name', '=', result)], limit=1, order='id asc'
)
if sale_order:
production.sale_order_id = sale_order.id
else:
logging.warning("No sale order found for production {} with product {} (name match: {})".format(
production.id, production.product_id.name, result))
except Exception as e:
logging.error("Error while fetching sale order for production {}: {}".format(production.id, str(e)))
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id') @api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_deadline_of_delivery(self): def _compute_deadline_of_delivery(self):
for production in self: for production in self:
@@ -721,10 +746,16 @@ class MrpProduction(models.Model):
for product_id, pd in grouped_product_ids.items(): for product_id, pd in grouped_product_ids.items():
product_id_to_production_names[product_id] = [p.name for p in pd] product_id_to_production_names[product_id] = [p.name for p in pd]
for production in production_all: for production in production_all:
proc_workorders = []
process_parameter_workorder = self.env['mrp.workorder'].search( process_parameter_workorder = self.env['mrp.workorder'].search(
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id), [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
('is_subcontract', '=', True)], order='sequence asc') ('is_subcontract', '=', True), ('state', '!=', 'cancel')], order='sequence asc')
if process_parameter_workorder: if process_parameter_workorder:
# 将这些特殊表面工艺工单的采购单与调拨单置为失效
for workorder in process_parameter_workorder:
workorder._get_surface_technics_purchase_ids().write({'state': 'cancel'})
workorder.move_subcontract_workorder_ids.write({'state': 'cancel'})
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'cancel'})
consecutive_workorders = [] consecutive_workorders = []
sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.sequence) sorted_workorders = sorted(process_parameter_workorder, key=lambda w: w.sequence)
for i, workorder in enumerate(sorted_workorders): for i, workorder in enumerate(sorted_workorders):
@@ -737,10 +768,11 @@ class MrpProduction(models.Model):
else: else:
# 处理连续组,如果它不为空 # 处理连续组,如果它不为空
if consecutive_workorders: if consecutive_workorders:
proc_workorders.append(consecutive_workorders)
# 创建外协出入库单和采购订单 # 创建外协出入库单和采购订单
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production) # self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production, sorted_workorders)
self.env['purchase.order'].get_purchase_order(consecutive_workorders, production, # self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
product_id_to_production_names) # product_id_to_production_names)
if i < len(sorted_workorders) - 1: if i < len(sorted_workorders) - 1:
# 重置连续组,并添加当前工作订单 # 重置连续组,并添加当前工作订单
consecutive_workorders = [workorder] consecutive_workorders = [workorder]
@@ -751,17 +783,22 @@ class MrpProduction(models.Model):
i - 1].supplier_id.id: i - 1].supplier_id.id:
consecutive_workorders = [workorder] consecutive_workorders = [workorder]
else: else:
proc_workorders.append([workorder])
# 立即创建外协出入库单和采购订单 # 立即创建外协出入库单和采购订单
self.env['stock.picking'].create_outcontract_picking(workorder, production) # self.env['stock.picking'].create_outcontract_picking(workorder, production)
self.env['purchase.order'].get_purchase_order(workorder, production, # self.env['purchase.order'].get_purchase_order(workorder, production,
product_id_to_production_names) # product_id_to_production_names)
consecutive_workorders = [] consecutive_workorders = []
# 处理最后一个组,即使它可能只有一个工作订单 # 处理最后一个组,即使它可能只有一个工作订单
if consecutive_workorders: if consecutive_workorders:
self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production) proc_workorders.append(consecutive_workorders)
self.env['purchase.order'].get_purchase_order(consecutive_workorders, production, # self.env['stock.picking'].create_outcontract_picking(consecutive_workorders, production)
product_id_to_production_names) # self.env['purchase.order'].get_purchase_order(consecutive_workorders, production,
# product_id_to_production_names)
for workorders in reversed(proc_workorders):
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
# 工单排序 # 工单排序
def _reset_work_order_sequence1(self, k): def _reset_work_order_sequence1(self, k):
@@ -1424,6 +1461,26 @@ class MrpProduction(models.Model):
for production in self: for production in self:
production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工' production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工'
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_sale_order_count(self):
for production in self:
if production.sale_order_id:
production.sale_order_count = 1
else:
production.sale_order_count = 0
def action_view_sale_orders(self):
if self.sale_order_id:
action = {
'res_model': 'sale.order',
'type': 'ir.actions.act_window',
}
action.update({
'view_mode': 'form',
'res_id': self.sale_order_id.id,
})
return action
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
""" """

View File

@@ -23,12 +23,15 @@ class ResMrpWorkOrder(models.Model):
product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name') product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name')
product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True, product_tmpl_id_length = fields.Float(string='坯料长度(mm)', related='material_length', readonly=True, store=False)
string="坯料度(mm)") product_tmpl_id_width = fields.Float(string='坯料度(mm)', related='material_width', readonly=True, store=False)
product_tmpl_id_width = fields.Float(related='production_id.product_tmpl_id.width', readonly=True, store=True, product_tmpl_id_height = fields.Float(string='坯料高度(mm)', related='material_height', readonly=True, store=False)
string="坯料宽度(mm)") # product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True,
product_tmpl_id_height = fields.Float(related='production_id.product_tmpl_id.height', readonly=True, store=True, # string="坯料长度(mm)")
string="坯料高度(mm)") # product_tmpl_id_width = fields.Float(related='production_id.product_tmpl_id.width', readonly=True, store=True,
# string="坯料宽度(mm)")
# product_tmpl_id_height = fields.Float(related='production_id.product_tmpl_id.height', readonly=True, store=True,
# string="坯料高度(mm)")
product_tmpl_id_materials_id = fields.Many2one(related='production_id.product_tmpl_id.materials_id', readonly=True, product_tmpl_id_materials_id = fields.Many2one(related='production_id.product_tmpl_id.materials_id', readonly=True,
store=True, check_company=True, string="材料") store=True, check_company=True, string="材料")
product_tmpl_id_materials_type_id = fields.Many2one(related='production_id.product_tmpl_id.materials_type_id', product_tmpl_id_materials_type_id = fields.Many2one(related='production_id.product_tmpl_id.materials_type_id',
@@ -126,7 +129,7 @@ class ResMrpWorkOrder(models.Model):
Y10_axis = fields.Float(default=0) Y10_axis = fields.Float(default=0)
Z10_axis = fields.Float(default=0) Z10_axis = fields.Float(default=0)
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0) X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
test_results = fields.Selection([("合格", "合格")], default='合格', test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格',
string="检测结果", tracking=True) string="检测结果", tracking=True)
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序") cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序") cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
@@ -134,8 +137,10 @@ class ResMrpWorkOrder(models.Model):
glb_file = fields.Binary("glb模型文件", related='production_id.model_file') glb_file = fields.Binary("glb模型文件", related='production_id.model_file')
is_subcontract = fields.Boolean(string='是否外协') is_subcontract = fields.Boolean(string='是否外协')
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
picking_ids = fields.Many2many('stock.picking', string='外协出入库单')
# purchase_id = fields.Many2one('purchase.order', string='外协采购单') picking_ids = fields.Many2many('stock.picking', string='外协出入库单', compute='_compute_surface_technics_picking_ids')
purchase_id = fields.Many2many('purchase.order', string='外协采购单')
surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids') surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids')
surface_technics_purchase_count = fields.Integer("外协采购", compute='_compute_surface_technics_purchase_ids') surface_technics_purchase_count = fields.Integer("外协采购", compute='_compute_surface_technics_purchase_ids')
@@ -239,13 +244,11 @@ class ResMrpWorkOrder(models.Model):
previous_workorder = self.env['mrp.workorder'].search( previous_workorder = self.env['mrp.workorder'].search(
[('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
('production_id', '=', workorder.production_id.id)]) ('production_id', '=', workorder.production_id.id)])
if previous_workorder: # if previous_workorder:
if previous_workorder.supplier_id != workorder.supplier_id: # if previous_workorder.supplier_id != workorder.supplier_id:
# process_product = self.env['product.template']._get_process_parameters_product( # domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)]
# previous_workorder.surface_technics_parameters_id) # else:
domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)] domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)]
else:
domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)]
picking_ids = self.env['stock.picking'].search(domain, order='id asc') picking_ids = self.env['stock.picking'].search(domain, order='id asc')
workorder.surface_technics_picking_count = len(picking_ids) workorder.surface_technics_picking_count = len(picking_ids)
workorder.picking_ids = picking_ids.ids workorder.picking_ids = picking_ids.ids
@@ -314,24 +317,27 @@ class ResMrpWorkOrder(models.Model):
# if technology_design.is_auto is False: # if technology_design.is_auto is False:
# domain = [('origin', '=', self.production_id.name)] # domain = [('origin', '=', self.production_id.name)]
# else: # else:
domain = [('origin', '=', self.production_id.name), ('purchase_type', '=', 'consignment'), purchase_orders_id = self._get_surface_technics_purchase_ids()
('state', '!=', 'cancel')]
purchase_orders = self.env['purchase.order'].search(domain)
purchase_orders_id = None
for po in purchase_orders:
for line in po.order_line:
if line.product_id.server_product_process_parameters_id == self.surface_technics_parameters_id:
if line.product_qty == 1:
purchase_orders_id = line.order_id.id
result = { result = {
"type": "ir.actions.act_window", "type": "ir.actions.act_window",
"res_model": "purchase.order", "res_model": "purchase.order",
"res_id": purchase_orders_id, "res_id": purchase_orders_id.id,
# "domain": [['id', 'in', self.purchase_id]], # "domain": [['id', 'in', self.purchase_id]],
"name": _("Purchase Orders"), "name": _("Purchase Orders"),
'view_mode': 'form', 'view_mode': 'form',
} }
return result return result
def _get_surface_technics_purchase_ids(self):
domain = [('origin', '=', self.production_id.name), ('purchase_type', '=', 'consignment')]
purchase_orders = self.env['purchase.order'].search(domain)
purchase_orders_id = self.env['purchase.order']
for po in purchase_orders:
for line in po.order_line:
if line.product_id.server_product_process_parameters_id == self.surface_technics_parameters_id:
if line.product_qty == 1:
purchase_orders_id = line.order_id
return purchase_orders_id
supplier_id = fields.Many2one('res.partner', string='外协供应商') supplier_id = fields.Many2one('res.partner', string='外协供应商')
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True) equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True)
@@ -1029,47 +1035,47 @@ class ResMrpWorkOrder(models.Model):
'production_id.programming_state') 'production_id.programming_state')
def _compute_state(self): def _compute_state(self):
# super()._compute_state() # super()._compute_state()
for workorder in self: # for workorder in self:
if workorder.sequence != 1: # if workorder.sequence != 1:
previous_workorder = self.env['mrp.workorder'].search( # previous_workorder = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id), # [('production_id', '=', workorder.production_id.id),
('sequence', '=', workorder.sequence - 1)]) # ('sequence', '=', workorder.sequence - 1)])
if workorder.state == 'pending': # if workorder.state == 'pending':
if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]): # if all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
if workorder.production_id.reservation_state == 'assigned' and workorder.production_id.schedule_state == '已排': # if workorder.production_id.reservation_state == 'assigned' and workorder.production_id.schedule_state == '已排':
if ((workorder.sequence == 1 and not workorder.blocked_by_workorder_ids) # if ((workorder.sequence == 1 and not workorder.blocked_by_workorder_ids)
or (workorder.blocked_by_workorder_ids.state in ('done', 'cancel') # or (workorder.blocked_by_workorder_ids.state in ('done', 'cancel')
and workorder.blocked_by_workorder_ids.test_results not in ['报废', '返工']) # and workorder.blocked_by_workorder_ids.test_results not in ['报废', '返工'])
or (previous_workorder.state in ('done', 'cancel') # or (previous_workorder.state in ('done', 'cancel')
and not workorder.blocked_by_workorder_ids # and not workorder.blocked_by_workorder_ids
and previous_workorder.test_results not in ['报废', '返工']) # and previous_workorder.test_results not in ['报废', '返工'])
): # ):
workorder.state = 'ready' # workorder.state = 'ready'
continue # continue
if workorder.production_id.schedule_state == '未排' and workorder.state in ('waiting', 'ready'): # if workorder.production_id.schedule_state == '未排' and workorder.state in ('waiting', 'ready'):
if workorder.sequence != 1: # if workorder.sequence != 1:
workorder.state = 'pending' # workorder.state = 'pending'
continue # continue
if workorder.state not in ('waiting', 'ready'): # if workorder.state not in ('waiting', 'ready'):
continue # continue
if workorder.state in ( # if workorder.state in (
'waiting') and workorder.sequence == 1 and workorder.production_id.schedule_state == '已排': # 'waiting') and workorder.sequence == 1 and workorder.production_id.schedule_state == '已排':
workorder.state = 'ready' # workorder.state = 'ready'
continue # continue
if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]): # if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
workorder.state = 'pending' # workorder.state = 'pending'
if workorder.state in ['waiting']: # if workorder.state in ['waiting']:
if previous_workorder.state == 'waiting': # if previous_workorder.state == 'waiting':
workorder.state = 'pending' # workorder.state = 'pending'
if workorder.sequence == 1 and workorder.state == 'pending': # if workorder.sequence == 1 and workorder.state == 'pending':
workorder.state = 'waiting' # workorder.state = 'waiting'
continue # continue
if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'): # if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
continue # continue
if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting' and workorder.production_id.schedule_state == '已排': # if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting' and workorder.production_id.schedule_state == '已排':
workorder.state = 'ready' # workorder.state = 'ready'
elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready': # elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
workorder.state = 'waiting' # workorder.state = 'waiting'
for workorder in self: for workorder in self:
# 如果工单的工序没有进行排序则跳出循环 # 如果工单的工序没有进行排序则跳出循环
@@ -1094,7 +1100,16 @@ class ResMrpWorkOrder(models.Model):
and workorder.production_id.schedule_state == '已排' and workorder.production_id.schedule_state == '已排'
and len(workorder.production_id.picking_ids.filtered( and len(workorder.production_id.picking_ids.filtered(
lambda w: w.state not in ['done', 'cancel'])) == 0): lambda w: w.state not in ['done', 'cancel'])) == 0):
workorder.state = 'ready' if workorder.is_subcontract is True:
purchase_orders_id = self._get_surface_technics_purchase_ids()
if purchase_orders_id.state == 'purchase':
workorder.state = 'ready'
continue
else:
workorder.state = 'waiting'
continue
else:
workorder.state = 'ready'
continue continue
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]========================== # ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework' if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
@@ -1120,21 +1135,26 @@ class ResMrpWorkOrder(models.Model):
if workorder.is_subcontract is False: if workorder.is_subcontract is False:
workorder.state = 'ready' workorder.state = 'ready'
else: else:
production_programming = self.env['mrp.production'].search( # production_programming = self.env['mrp.production'].search(
[('origin', '=', self.production_id.origin)], order='name asc') # [('origin', '=', self.production_id.origin)], order='name asc')
production_no_remanufacture = production_programming.filtered( # production_no_remanufacture = production_programming.filtered(
lambda a: a.is_remanufacture is False) # lambda a: a.is_remanufacture is False)
production_list = [production.name for production in production_programming] # production_list = [production.name for production in production_programming]
purchase_orders = self.env['purchase.order'].search( # purchase_orders = self.env['purchase.order'].search(
[('origin', 'ilike', ','.join(production_list))]) # [('origin', 'ilike', ','.join(production_list))])
for line in purchase_orders.order_line: # for line in purchase_orders.order_line:
if ( # if (
line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id # line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id
and line.product_qty == len(production_no_remanufacture)): # and line.product_qty == len(production_no_remanufacture)):
if all(pur_order.state == 'purchase' for pur_order in purchase_orders): # if all(pur_order.state == 'purchase' for pur_order in purchase_orders):
workorder.state = 'ready' # workorder.state = 'ready'
else: # else:
workorder.state = 'waiting' # workorder.state = 'waiting'
purchase_orders_id = self._get_surface_technics_purchase_ids()
if purchase_orders_id:
workorder.state = 'ready' if purchase_orders_id.state == 'purchase' else 'waiting'
else:
workorder.state = 'waiting'
# re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id), # re_work = self.env['mrp.workorder'].search([('production_id', '=', workorder.production_id.id),
# ('processing_panel', '=', workorder.processing_panel), # ('processing_panel', '=', workorder.processing_panel),
@@ -1197,6 +1217,10 @@ class ResMrpWorkOrder(models.Model):
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): def button_start(self):
# 判断工单状态是否为等待组件
if self.state in ['waiting', 'pending']:
raise UserError('制造订单【%s】缺少组件信息!' % self.production_id.name)
if self.routing_type == 'CNC加工': if self.routing_type == 'CNC加工':
self.env['sf.production.plan'].sudo().search([('name', '=', self.production_id.name)]).write({ self.env['sf.production.plan'].sudo().search([('name', '=', self.production_id.name)]).write({
'state': 'processing', 'state': 'processing',
@@ -1204,9 +1228,6 @@ class ResMrpWorkOrder(models.Model):
}) })
if self.sequence == 1: if self.sequence == 1:
# 判断工单状态是否为等待组件
if self.state == 'waiting':
raise UserError('制造订单【%s】缺少组件信息!' % self.production_id.name)
# 判断是否有坯料的序列号信息 # 判断是否有坯料的序列号信息
boolean = False boolean = False
if self.production_id.move_raw_ids: if self.production_id.move_raw_ids:
@@ -1243,19 +1264,33 @@ class ResMrpWorkOrder(models.Model):
# 表面工艺外协出库单 # 表面工艺外协出库单
if self.routing_type == '表面工艺': if self.routing_type == '表面工艺':
if self.is_subcontract is True: if self.is_subcontract is True:
move_out = self.env['stock.move'].search( move_out = self.move_subcontract_workorder_ids[1]
[('location_id', '=', self.env['stock.location'].search( # move_out = self.env['stock.move'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), # [('location_id', '=', self.env['stock.location'].search(
('location_dest_id', '=', self.env['stock.location'].search( # [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
[('barcode', 'ilike', 'VL-SPOC')]).id), # ('location_dest_id', '=', self.env['stock.location'].search(
('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])]) # [('barcode', 'ilike', 'VL-SPOC')]).id),
# ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
for mo in move_out: for mo in move_out:
pick = self.env['stock.picking'].search([('id', '=', mo.picking_id.id), ('name', 'ilike', 'OCOUT'), if mo.state != 'done':
('partner_id', '=', self.supplier_id.id)]) mo.write({'state': 'assigned', 'production_id': False})
if pick: if not mo.move_line_ids:
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
self.env['stock.move.line'].create(mo.get_move_line(self.production_id, self)) self.env['stock.move.line'].create(mo.get_move_line(self.production_id, self))
# product_qty = mo.product_uom._compute_quantity(
# mo.product_uom_qty, mo.product_id.uom_id, rounding_method='HALF-UP')
# available_quantity = self.env['stock.quant']._get_available_quantity(
# mo.product_id,
# mo.location_id,
# lot_id=mo.move_line_ids.lot_id,
# strict=False,
# )
# mo._update_reserved_quantity(
# product_qty,
# available_quantity,
# mo.location_id,
# lot_id=mo.move_line_ids.lot_id,
# strict=False,
# )
# move_out._action_assign() # move_out._action_assign()
if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress': if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress':
@@ -1360,6 +1395,13 @@ class ResMrpWorkOrder(models.Model):
picks = record.picking_ids.filtered(lambda p: p.state not in ('done')) picks = record.picking_ids.filtered(lambda p: p.state not in ('done'))
if picks: if picks:
raise UserError('请先完成该工单的工艺外协再进行操作') raise UserError('请先完成该工单的工艺外协再进行操作')
# 表面工艺外协,最后一张工单
workorders = self.production_id.workorder_ids
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence')
if self == subcontract_workorders[-1]:
# 给下一个库存移动就绪
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
# self.production_id.button_mark_done()
tem_date_planned_finished = record.date_planned_finished tem_date_planned_finished = record.date_planned_finished
tem_date_finished = record.date_finished tem_date_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type) logging.info('routing_type:%s' % record.routing_type)
@@ -1402,13 +1444,13 @@ class ResMrpWorkOrder(models.Model):
move_raw_id.quantity_done = move_raw_id.product_uom_qty move_raw_id.quantity_done = move_raw_id.product_uom_qty
record.process_state = '已完工' record.process_state = '已完工'
record.production_id.process_state = '已完工' record.production_id.process_state = '已完工'
if record.routing_type in ['表面工艺']: # if record.routing_type in ['表面工艺']:
raw_move = self.env['stock.move'].sudo().search( # raw_move = self.env['stock.move'].sudo().search(
[('origin', '=', record.production_id.name), # [('origin', '=', record.production_id.name),
('procure_method', 'in', ['make_to_order', 'make_to_stock']), # ('procure_method', 'in', ['make_to_order', 'make_to_stock']),
('state', '!=', 'done')]) # ('state', '!=', 'done')])
if raw_move: # if raw_move:
raw_move.write({'state': 'done'}) # raw_move.write({'state': 'done'})
record.production_id.button_mark_done1() record.production_id.button_mark_done1()
# record.production_id.state = 'done' # record.production_id.state = 'done'
@@ -1528,6 +1570,8 @@ class ResMrpWorkOrder(models.Model):
'default_confirm_button': '确认解除', 'default_confirm_button': '确认解除',
# 'default_feeder_station_start_id': feeder_station_start_id, # 'default_feeder_station_start_id': feeder_station_start_id,
}} }}
move_subcontract_workorder_ids = fields.One2many('stock.move', 'subcontract_workorder_id', string='组件')
class CNCprocessing(models.Model): class CNCprocessing(models.Model):

View File

@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from odoo import api, fields, models, _
from odoo.tools import OrderedSet
# _get_surface_technics_purchase_ids
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
def button_confirm(self):
super().button_confirm()
workorders = self.env['mrp.workorder'].search([('purchase_id', '=', self.id)])
for workorder in workorders:
if workorder.routing_type == '表面工艺' and workorder.is_subcontract is True:
move_out = workorder.move_subcontract_workorder_ids[1]
# move_out = self.env['stock.move'].search(
# [('location_id', '=', self.env['stock.location'].search(
# [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
# ('location_dest_id', '=', self.env['stock.location'].search(
# [('barcode', 'ilike', 'VL-SPOC')]).id),
# ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
for mo in move_out:
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
self.env['stock.move.line'].create(mo.get_move_line(workorder.production_id, workorder))
return True

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import fields, models from odoo import fields, models, api, _
from odoo.exceptions import ValidationError
class sf_technology_design(models.Model): class sf_technology_design(models.Model):
@@ -29,3 +30,11 @@ class sf_technology_design(models.Model):
def unlink_technology_design(self): def unlink_technology_design(self):
self.active = False self.active = False
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get('route_id'):
raise ValidationError(_("工序不能为空"))
return super(sf_technology_design, self).create(vals_list)

View File

@@ -636,74 +636,89 @@ class StockPicking(models.Model):
def button_validate(self): def button_validate(self):
res = super().button_validate() res = super().button_validate()
if res is True and self.picking_type_id.sequence_code == 'OCOUT': picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
# if self.id == move_out.picking_id.id: if res is True and self.picking_type_id.id == picking_type_in:
# if move_out.move_line_ids.workorder_id.state == 'progress': # 如果是最后一张外协入库单,则设置库存位置的预留数量
move_in = self.env['stock.move'].search( move_in = self.move_ids
[('location_dest_id', '=', self.env['stock.location'].search( if move_in:
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), workorder = move_in.subcontract_workorder_id
('location_id', '=', self.env['stock.location'].search( workorders = workorder.production_id.workorder_ids
[('barcode', 'ilike', 'VL-SPOC')]).id), subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence')
('origin', '=', self.origin), ('state', 'not in', ['cancel', 'done'])]) if workorder == subcontract_workorders[-1]:
production = self.env['mrp.production'].search([('name', '=', self.origin)]) self.env['stock.quant']._update_reserved_quantity(
for mi in move_in: move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
pick = self.env['stock.picking'].search([('id', '=', mi.picking_id.id), ('name', 'ilike', 'OCIN'), lot_id=move_in.move_line_ids.lot_id,
('partner_id', '=', self.partner_id.id)]) package_id=False, owner_id=False, strict=False
# if pick: )
# if mi.state != 'done': workorder.button_finish()
# mi.write({'state': 'assigned'}) picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id
# self.env['stock.move.line'].create(mi.get_move_line(production, None)) if res and self.picking_type_id.id == picking_type_out:
move_out = self.move_ids
if move_out:
workorder = move_out.subcontract_workorder_id
workorder.button_start()
return res return res
# 创建 外协出库入单 # 创建 外协出库入单
def create_outcontract_picking(self, sorted_workorders_arr, item): def create_outcontract_picking(self, workorders, item, sorted_workorders):
domain = [('origin', '=', item.name), ('name', 'ilike', 'OCOUT')] for workorder in workorders:
if len(sorted_workorders_arr) > 1: if workorder.move_subcontract_workorder_ids:
sorted_workorders_arr = sorted_workorders_arr[0] workorder.move_subcontract_workorder_ids.write({'state': 'waiting'})
else: workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'waiting'})
domain += [ else:
('surface_technics_parameters_id', '=', sorted_workorders_arr[0].surface_technics_parameters_id.id)] # 创建一个新的补货组
stock_picking = self.env['stock.picking'].search(domain) procurement_group_id = self.env['procurement.group'].create({
if not stock_picking: 'name': workorder.name,
for sorted_workorders in sorted_workorders_arr: 'partner_id': self.partner_id.id,
# pick_ids = [] })
if not sorted_workorders.picking_ids: move_dest_id = False
# outcontract_stock_move = self.env['stock.move'].search([('production_id', '=', item.id)]) # 如果当前工单是是制造订单的最后一个工单
# if not outcontract_stock_move: if workorder == item.workorder_ids[-1]:
# 创建一个新的补货组 move_dest_id = item.move_raw_ids[0].id
procurement_group_id = self.env['procurement.group'].create({ else:
'name': sorted_workorders.name, # 从sorted_workorders中找到上一工单的move
'partner_id': self.partner_id.id, if sorted_workorders.index(workorder) > 0:
}) move_dest_id = \
new_picking = True sorted_workorders[sorted_workorders.index(workorder) - 1].move_subcontract_workorder_ids[1].id
location_id = self.env['stock.location'].search( new_picking = True
[('barcode', 'ilike', 'VL-SPOC')]).id, outcontract_picking_type_in = self.env.ref(
location_dest_id = self.env['stock.location'].search( 'sf_manufacturing.outcontract_picking_in').id,
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id, outcontract_picking_type_out = self.env.ref(
outcontract_picking_type_in = self.env.ref( 'sf_manufacturing.outcontract_picking_out').id,
'sf_manufacturing.outcontract_picking_in').id, moves_in = self.env['stock.move'].sudo().create(
outcontract_picking_type_out = self.env.ref( self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in,
'sf_manufacturing.outcontract_picking_out').id, procurement_group_id.id, move_dest_id))
moves_in = self.env['stock.move'].sudo().create( picking_in = self.create(
self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id, moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
outcontract_picking_type_in, procurement_group_id.id)) # pick_ids.append(picking_in.id)
picking_in = self.create( moves_in.write(
moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/')) {'picking_id': picking_in.id, 'state': 'waiting'})
# pick_ids.append(picking_in.id) moves_in._assign_picking_post_process(new=new_picking)
moves_in.write( moves_out = self.env['stock.move'].sudo().create(
{'picking_id': picking_in.id, 'state': 'waiting'}) self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out,
moves_in._assign_picking_post_process(new=new_picking) procurement_group_id.id, moves_in.id))
moves_out = self.env['stock.move'].sudo().create( workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
self.env['stock.move']._get_stock_move_values_Res(item, location_dest_id, location_id, picking_out = self.create(
outcontract_picking_type_out, procurement_group_id.id, moves_in.id)) moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
picking_out = self.create( # pick_ids.append(picking_out.id)
moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/')) moves_out.write(
# pick_ids.append(picking_out.id) {'picking_id': picking_out.id, 'state': 'waiting'})
moves_out.write( moves_out._assign_picking_post_process(new=new_picking)
{'picking_id': picking_out.id, 'state': 'waiting'})
moves_out._assign_picking_post_process(new=new_picking) @api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
def _compute_state(self):
super(StockPicking, self)._compute_state()
for picking in self:
# 外协出库单根据工单状态,采购单状态来确定
picking_type_id = self.env.ref('sf_manufacturing.outcontract_picking_out').id
if picking.picking_type_id.id == picking_type_id:
if picking.move_ids:
workorder = picking.move_ids[0].subcontract_workorder_id
if picking.state == 'assigned':
if workorder.state in ['pending',
'waiting'] or workorder._get_surface_technics_purchase_ids().state in [
'draft', 'sent']:
picking.state = 'waiting'
class ReStockMove(models.Model): class ReStockMove(models.Model):
@@ -713,16 +728,18 @@ class ReStockMove(models.Model):
materiel_width = fields.Float(string='物料宽度', digits=(16, 4)) materiel_width = fields.Float(string='物料宽度', digits=(16, 4))
materiel_height = fields.Float(string='物料高度', digits=(16, 4)) materiel_height = fields.Float(string='物料高度', digits=(16, 4))
def _get_stock_move_values_Res(self, item, location_src_id, location_dest_id, picking_type_id, group_id, move_dest_ids=False): def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
route = self.env['stock.route'].sudo().search([('name', '=', '表面工艺外协')]) route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
stock_rule = self.env['stock.rule'].sudo().search(
[('route_id', '=', route_id), ('picking_type_id', '=', picking_type_id)])
move_values = { move_values = {
'name': '', 'name': '',
'company_id': item.company_id.id, 'company_id': item.company_id.id,
'product_id': item.bom_id.bom_line_ids.product_id.id, 'product_id': item.bom_id.bom_line_ids.product_id.id,
'product_uom': item.bom_id.bom_line_ids.product_uom_id.id, 'product_uom': item.bom_id.bom_line_ids.product_uom_id.id,
'product_uom_qty': 1.0, 'product_uom_qty': 1.0,
'location_id': location_src_id, 'location_id': stock_rule.location_src_id.id,
'location_dest_id': location_dest_id, 'location_dest_id': stock_rule.location_dest_id.id,
'origin': item.name, 'origin': item.name,
'group_id': group_id, 'group_id': group_id,
'move_dest_ids': [(6, 0, [move_dest_ids])] if move_dest_ids else False, 'move_dest_ids': [(6, 0, [move_dest_ids])] if move_dest_ids else False,
@@ -749,7 +766,7 @@ class ReStockMove(models.Model):
'picking_type_id': picking_type_id, 'picking_type_id': picking_type_id,
'location_id': self.mapped('location_id').id, 'location_id': self.mapped('location_id').id,
'location_dest_id': self.mapped('location_dest_id').id, 'location_dest_id': self.mapped('location_dest_id').id,
'state': 'confirmed', 'state': 'waiting',
} }
def get_move_line(self, production_id, sorted_workorders): def get_move_line(self, production_id, sorted_workorders):
@@ -965,7 +982,7 @@ class ReStockMove(models.Model):
合并制造订单的完成move单据 合并制造订单的完成move单据
""" """
res = super(ReStockMove, self)._merge_moves_fields() res = super(ReStockMove, self)._merge_moves_fields()
if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨', '生产入库']: if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨', '生产入库', '客供料入库']:
production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc') production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc')
productions = self.env['mrp.production'].search( productions = self.env['mrp.production'].search(
[('origin', '=', production.origin), ('product_id', '=', production.product_id.id)]) [('origin', '=', production.origin), ('product_id', '=', production.product_id.id)])
@@ -988,10 +1005,14 @@ class ReStockMove(models.Model):
production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc') production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc')
productions = self.env['mrp.production'].search( productions = self.env['mrp.production'].search(
[('origin', '=', production.origin), ('product_id', '=', production.product_id.id)]) [('origin', '=', production.origin), ('product_id', '=', production.product_id.id)])
res['origin'] = ','.join(productions.mapped('name')) if productions.mapped('name'):
res['origin'] = ','.join(productions.mapped('name'))
res['retrospect_ref'] = production.product_id.name res['retrospect_ref'] = production.product_id.name
return res return res
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True,
index='btree_not_null')
class ReStockQuant(models.Model): class ReStockQuant(models.Model):
_inherit = 'stock.quant' _inherit = 'stock.quant'

View File

@@ -43,6 +43,7 @@
<field name="activity_ids" string="下一个活动" widget="list_activity" optional="hide"/> <field name="activity_ids" string="下一个活动" widget="list_activity" optional="hide"/>
</xpath> </xpath>
<xpath expr="//field[@name='origin']" position="replace"> <xpath expr="//field[@name='origin']" position="replace">
<field name="sale_order_id" optional="show"/>
<field name="origin" optional="hide"/> <field name="origin" optional="hide"/>
</xpath> </xpath>
<xpath expr="//field[@name='components_availability']" position="replace"> <xpath expr="//field[@name='components_availability']" position="replace">
@@ -123,6 +124,7 @@
<field name="tool_state" <field name="tool_state"
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/> attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
<field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/> <field name="tool_state_remark" string="备注" attrs="{'invisible': [('tool_state', '!=', '1')]}"/>
<field name="sale_order_id" readonly="1"/>
<field name="deadline_of_delivery" readonly="1"/> <field name="deadline_of_delivery" readonly="1"/>
<field name="tool_state_remark2" invisible="1"/> <field name="tool_state_remark2" invisible="1"/>
</xpath> </xpath>
@@ -584,6 +586,7 @@
<searchpanel> <searchpanel>
<field name="state" icon="fa-filter" enable_counters="1"/> <field name="state" icon="fa-filter" enable_counters="1"/>
<field name="delivery_status" icon="fa-filter" enable_counters="1"/> <field name="delivery_status" icon="fa-filter" enable_counters="1"/>
<field name="production_type" icon="fa-filter" enable_counters="1"/>
</searchpanel> </searchpanel>
</xpath> </xpath>
<filter name='todo' position="replace"/> <filter name='todo' position="replace"/>
@@ -738,7 +741,7 @@
<!-- parent="mrp.menu_mrp_manufacturing"--> <!-- parent="mrp.menu_mrp_manufacturing"-->
<!-- sequence="1"/>--> <!-- sequence="1"/>-->
<menuitem id="menu_mrp_production_action" <menuitem id="mrp.menu_mrp_production_action"
name="制造订单" name="制造订单"
parent="mrp.menu_mrp_manufacturing" parent="mrp.menu_mrp_manufacturing"
action="mrp.mrp_production_action" action="mrp.mrp_production_action"

View File

@@ -200,7 +200,7 @@
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> -->
<!-- <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"--> <!-- <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"-->
<!-- attrs="{'invisible': ['|','|','|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done'),('is_rework','=',True),'&amp;',('rfid_code','in',['',False]),('state','=','done')]}"/>--> <!-- attrs="{'invisible': ['|','|','|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done'),('is_rework','=',True),'&amp;',('rfid_code','in',['',False]),('state','=','done')]}"/>-->
<button name="button_rework_pre" type="object" string="异常反馈" invisible="1" <button name="button_rework_pre" type="object" string="异常反馈"
class="btn-primary" class="btn-primary"
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/> attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/>
<button name="unbind_tray" type="object" string="解绑托盘" <button name="unbind_tray" type="object" string="解绑托盘"

View File

@@ -66,30 +66,30 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
# 工单采购单外协出入库单皆需取消 # 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)] domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id: if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id)] domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id), ('state', '!=', 'cancel')]
else: else:
domain += [('technology_design_id', '=', special.id)] domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
workorder = self.env['mrp.workorder'].search(domain) workorder = self.env['mrp.workorder'].search(domain)
previous_workorder = self.env['mrp.workorder'].search( # previous_workorder = self.env['mrp.workorder'].search(
[('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), # [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
('production_id', '=', workorder.production_id.id)]) # ('production_id', '=', workorder.production_id.id)])
if previous_workorder: # if previous_workorder:
if previous_workorder.supplier_id != workorder.supplier_id: # if previous_workorder.supplier_id != workorder.supplier_id:
is_cancel = True # is_cancel = True
else: # else:
is_cancel = True # is_cancel = True
if workorder.state != 'cancel' and is_cancel is True: # if workorder.state != 'cancel' and is_cancel is True:
workorder.write({'state': 'cancel'}) # workorder.write({'state': 'cancel'})
workorder.picking_ids.write({'state': 'cancel'}) # workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'}) # workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search( # purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.name)]) # [('origin', '=', workorder.production_id.name)])
for line in purchase_order.order_line: # for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id: # if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'}) # purchase_order.write({'state': 'cancel'})
else: else:
workorder = self.env['mrp.workorder'].search( workorder = self.env['mrp.workorder'].search(
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id)]) [('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id), ('state', '!=', 'cancel')])
if not workorder: if not workorder:
if special.route_id.routing_type == '表面工艺': if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search( product_production_process = self.env['product.template'].search(
@@ -110,11 +110,12 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
workorder.blocked_by_workorder_ids = None workorder.blocked_by_workorder_ids = None
else: else:
if workorder.blocked_by_workorder_ids: if workorder.blocked_by_workorder_ids:
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0] workorder.blocked_by_workorder_ids = workorder.blocked_by_workorder_ids[0]
productions._reset_work_order_sequence() productions._reset_work_order_sequence()
if self.production_id.product_id.categ_id.type == '成品': # 退回时不对外协出入库单和采购单做处理
productions._reset_subcontract_pick_purchase() # if self.production_id.product_id.categ_id.type == '成品':
productions.get_subcontract_pick_purchase() # productions._reset_subcontract_pick_purchase()
# productions.get_subcontract_pick_purchase()
productions.is_adjust = True productions.is_adjust = True
for item in productions: for item in productions:
workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted( workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(

View File

@@ -59,35 +59,33 @@ class ProductionTechnologyWizard(models.TransientModel):
for special in special_design: for special in special_design:
workorders_values = [] workorders_values = []
if special.active is False: if special.active is False:
is_cancel = False # is_cancel = False
# 工单采购单外协出入库单皆需取消 # 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)] domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id: if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id)] domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id), ('state', '!=', 'cancel')]
else: else:
domain += [('technology_design_id', '=', special.id)] domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
workorder = self.env['mrp.workorder'].search(domain) workorder = self.env['mrp.workorder'].search(domain)
previous_workorder = self.env['mrp.workorder'].search( # previous_workorder = self.env['mrp.workorder'].search(
[('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'), # [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
('production_id', '=', workorder.production_id.id)]) # ('production_id', '=', workorder.production_id.id)])
if previous_workorder: # if previous_workorder:
if previous_workorder.supplier_id != workorder.supplier_id: # if previous_workorder.supplier_id != workorder.supplier_id:
is_cancel = True # is_cancel = True
else: # if workorder.state != 'cancel' and is_cancel is True:
is_cancel = True workorder.write({'state': 'cancel'})
if workorder.state != 'cancel' and is_cancel is True: workorder.picking_ids.write({'state': 'cancel'})
workorder.write({'state': 'cancel'}) workorder.picking_ids.move_ids.write({'state': 'cancel'})
workorder.picking_ids.write({'state': 'cancel'}) purchase_order = self.env['purchase.order'].search(
workorder.picking_ids.move_ids.write({'state': 'cancel'}) [('origin', '=', workorder.production_id.name), ('purchase_type', '=', 'consignment')])
purchase_order = self.env['purchase.order'].search( for line in purchase_order.order_line:
[('origin', '=', workorder.production_id.name)]) if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
for line in purchase_order.order_line: purchase_order.write({'state': 'cancel'})
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'})
else: else:
if special.production_id.workorder_ids: if special.production_id.workorder_ids:
workorder = self.env['mrp.workorder'].search( workorder = self.env['mrp.workorder'].search(
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id)]) [('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id), ('state', '!=', 'cancel')])
if not workorder: if not workorder:
if special.route_id.routing_type == '表面工艺': if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search( product_production_process = self.env['product.template'].search(
@@ -100,7 +98,7 @@ class ProductionTechnologyWizard(models.TransientModel):
else: else:
workorders_values.append( workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(special.production_id, special)) self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values}) special.production_id.write({'workorder_ids': workorders_values})
else: else:
if len(workorder.blocked_by_workorder_ids) > 1: if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1: if workorder.sequence == 1:

View File

@@ -257,7 +257,7 @@
<record id="sf_production_plan_action" model="ir.actions.act_window"> <record id="sf_production_plan_action" model="ir.actions.act_window">
<field name="name">制造订单生产计划</field> <field name="name">CNC产线计划排程</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">sf.production.plan</field> <field name="res_model">sf.production.plan</field>
<field name="view_mode">gantt,tree,form</field> <field name="view_mode">gantt,tree,form</field>

View File

@@ -25,7 +25,7 @@ class SfQualityCncTest(models.Model):
('pass', '合格'), ('pass', '合格'),
('fail', '不合格')], string='判定结果') ('fail', '不合格')], string='判定结果')
number = fields.Integer('数量', default=1) number = fields.Integer('数量', default=1)
test_results = fields.Selection([("合格", "合格")], string="检测结果") test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], string="检测结果")
reason = fields.Selection( reason = fields.Selection(
[("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"), [("programming", "编程"), ("cutter", "刀具"), ("clamping", "装夹"), ("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因") ("technology", "工艺"), ("customer redrawing", "客户改图")], string="原因")

View File

@@ -247,45 +247,27 @@ class RePurchaseOrder(models.Model):
raise UserError('请对【产品】中的【税】进行选择') raise UserError('请对【产品】中的【税】进行选择')
def get_purchase_order(self, consecutive_process_parameters, production, product_id_to_production_names): def get_purchase_order(self, consecutive_process_parameters, production, product_id_to_production_names):
server_product_process = []
production_process = product_id_to_production_names.get(
production.product_id.id)
purchase_order = self.env['purchase.order'].search(
[('state', '=', 'draft'), ('origin', '=', production.name),
('purchase_type', '=', 'consignment')], order='name asc')
for pp in consecutive_process_parameters: for pp in consecutive_process_parameters:
server_template = self.env['product.template'].search( server_product_process = []
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id), purchase_order = pp._get_surface_technics_purchase_ids()
('detailed_type', '=', 'service')]) if purchase_order:
if not purchase_order: purchase_order.write({'state': 'draft'})
else:
server_template = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
('detailed_type', '=', 'service')])
server_product_process.append((0, 0, { server_product_process.append((0, 0, {
'product_id': server_template.product_variant_id.id, 'product_id': server_template.product_variant_id.id,
'product_qty': 1, 'product_qty': 1,
'product_uom': server_template.uom_id.id 'product_uom': server_template.uom_id.id
})) }))
for purchase in purchase_order: purchase_order = self.env['purchase.order'].sudo().create({
for po in purchase.order_line: 'partner_id': server_template.seller_ids[0].partner_id.id,
if po.product_id == server_template.product_variant_id: 'origin': production.name,
continue 'state': 'draft',
if server_template.server_product_process_parameters_id != po.product_id.server_product_process_parameters_id: 'purchase_type': 'consignment',
purchase_order_line = self.env['purchase.order.line'].search( 'order_line': server_product_process})
[('product_id', '=', server_template.product_variant_id.id), pp.purchase_id = [(6, 0, [purchase_order.id])]
('product_qty', '=', 1.0), ('id', '=', purchase.id)], limit=1,
order='id desc')
if not purchase_order_line:
server_product_process.append((0, 0, {
'product_id': server_template.product_variant_id.id,
'product_qty': 1,
'product_uom': server_template.uom_id.id
}))
if server_product_process:
self.env['purchase.order'].sudo().create({
'partner_id': server_template.seller_ids[0].partner_id.id,
'origin': production.name,
'state': 'draft',
'purchase_type': 'consignment',
'order_line': server_product_process})
# self.env.cr.commit() # self.env.cr.commit()
@api.onchange('order_line') @api.onchange('order_line')

View File

@@ -128,9 +128,9 @@
<!-- action="account.res_partner_action_customer"--> <!-- action="account.res_partner_action_customer"-->
<!-- groups="sales_team.group_sale_salesman"--> <!-- groups="sales_team.group_sale_salesman"-->
<!-- sequence="40"/>--> <!-- sequence="40"/>-->
<menuitem sequence="21" name="快速订单" id="menu_quick_easy_order" <!-- <menuitem sequence="21" name="快速订单" id="menu_quick_easy_order"-->
action="action_quick_easy_order" <!-- action="action_quick_easy_order"-->
parent="sale.sale_order_menu" <!-- parent="sale.sale_order_menu"-->
groups="sales_team.group_sale_salesman,sf_base.group_sale_salemanager,sf_base.group_sale_director"/> <!-- groups="sales_team.group_sale_salesman,sf_base.group_sale_salemanager,sf_base.group_sale_director"/>-->
</data> </data>
</odoo> </odoo>