Compare commits

..

42 Commits

Author SHA1 Message Date
胡尧
61baa49d85 Merge branch 'feature/6694' into feature/merge-6694 2025-05-15 09:22:44 +08:00
胡尧
063c7a94c5 Accept Merge Request #2121: (feature/rollback-develop1 -> develop)
Merge Request: 修复误回退的代码

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2121?initial=true
2025-05-15 09:15:54 +08:00
胡尧
b783af6ef3 修复误回退的代码 2025-05-15 09:15:27 +08:00
胡尧
22cbe1bd9d 回退代码 2025-05-15 09:13:51 +08:00
胡尧
cc196e25da Accept Merge Request #2120: (feature/rollback-develop1 -> develop)
Merge Request: 退回至未合并工艺外协代码

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2120?initial=true
2025-05-15 09:03:49 +08:00
胡尧
961754428b 退回至未合并工艺外协代码 2025-05-15 09:02:31 +08:00
廖丹龙
7e47a85167 Accept Merge Request #2119: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2119
2025-05-14 17:53:14 +08:00
liaodanlong
2644df4fd5 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 17:45:42 +08:00
廖丹龙
e14aa35d90 Accept Merge Request #2118: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2118
2025-05-14 17:00:42 +08:00
liaodanlong
9392819375 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 16:58:05 +08:00
liaodanlong
ea3d9e5375 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 16:46:29 +08:00
胡尧
7db0a44420 Accept Merge Request #2117: (feature/6694 -> develop)
Merge Request: 修改中控日志接口授权为none

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2117?initial=true
2025-05-14 16:09:30 +08:00
liaodanlong
238840b647 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-14 14:54:36 +08:00
廖丹龙
51e25d8847 Accept Merge Request #2116: (feature/tool_standard_library_process -> 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/2116
2025-05-14 14:14:02 +08:00
liaodanlong
c6f06a4c32 外协调拨单就绪条件修改 2025-05-14 14:12:06 +08:00
liaodanlong
5b61a801c5 空值判断 2025-05-14 13:57:57 +08:00
廖丹龙
2893524902 Accept Merge Request #2115: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2115?initial=true
2025-05-14 12:22:10 +08:00
liaodanlong
ed55e36f45 sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数 2025-05-14 11:49:14 +08:00
廖丹龙
c811f26104 Accept Merge Request #2114: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2114
2025-05-14 11:11:29 +08:00
liaodanlong
3763b60758 sf-制造-产品-表单详情中-工艺参数显示内容=未归档,未绑定产品的工艺参数 2025-05-14 10:48:01 +08:00
廖丹龙
976907bd92 Accept Merge Request #2112: (feature/tool_standard_library_process -> 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/2112
2025-05-14 10:35:47 +08:00
liaodanlong
50c3b31ece 外协采购单使用采购申请创建出来的采购单 2025-05-14 10:24:21 +08:00
liaodanlong
8afc8bb3a6 外协调拨单只有当制造订单状态变为已编程才能就绪 2025-05-14 10:03:26 +08:00
廖丹龙
a0427d424f Accept Merge Request #2111: (feature/tool_standard_library_process -> develop)
Merge Request: sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对

Created By: @廖丹龙
Reviewed By: @胡尧
Approved By: @胡尧 
Accepted By: @廖丹龙
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2111
2025-05-13 16:35:45 +08:00
liaodanlong
3148ce5a15 外协调拨单不同产品的调拨单混合到一起了 2025-05-13 15:49:02 +08:00
liaodanlong
8e726e1bf6 sf-制造-工艺外协的采购订单确认后,外协的调拨单的作业详情的预留数量跟完成数量不对 2025-05-13 15:01:54 +08:00
liaodanlong
4c0f9cfb39 外协工单零件图号零件名称 2025-05-13 11:04:45 +08:00
廖丹龙
86d3bd38c5 Accept Merge Request #2110: (feature/tool_standard_library_process -> 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/2110
2025-05-13 10:25:20 +08:00
liaodanlong
a8e4c7d9a0 调拨单报错问题处理 2025-05-13 10:24:09 +08:00
liaodanlong
7501832637 调拨单就绪问题处理 2025-05-13 10:01:58 +08:00
liaodanlong
ce0ead4da6 sf-工序-手动创建工艺可选参数及产品问题 2025-05-12 17:13:52 +08:00
廖丹龙
343e2f9f24 Accept Merge Request #2109: (feature/tool_standard_library_process -> 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/2109
2025-05-12 15:42:10 +08:00
liaodanlong
6d3793ee30 调拨单就绪问题处理 2025-05-12 15:21:10 +08:00
廖丹龙
43f7e97c28 Accept Merge Request #2108: (feature/tool_standard_library_process -> 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/2108
2025-05-12 15:12:06 +08:00
liaodanlong
9e6f3fa864 Merge branch 'refs/heads/develop' into feature/tool_standard_library_process
# Conflicts:
#	sf_manufacturing/models/purchase_order.py
2025-05-12 15:03:25 +08:00
liaodanlong
ed50d7c9a7 调拨单就绪问题处理 2025-05-12 14:55:19 +08:00
liaodanlong
89e23050e6 打印错误日志堆栈信息 2025-05-12 14:54:43 +08:00
胡尧
b7f912453f Accept Merge Request #2107: (feature/6694 -> develop)
Merge Request: 解决代码问题

Created By: @胡尧
Accepted By: @胡尧
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/2107?initial=true
2025-05-12 14:48:07 +08:00
liaodanlong
1040844b0a 采购申请跳转处理 2025-05-12 11:01:51 +08:00
liaodanlong
36a13c04de 采购申请数量与产品数量不一致问题 2025-05-12 10:55:21 +08:00
liaodanlong
f4318bd997 Merge remote-tracking branch 'origin/feature/tool_standard_library_process' into feature/tool_standard_library_process 2025-05-12 10:25:09 +08:00
liaodanlong
d47a30977c 已归档的表面工艺可选参数不进行产品创建 2025-05-12 10:24:22 +08:00
78 changed files with 934 additions and 1760 deletions

View File

@@ -119,24 +119,13 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
this.listherHeaderBodyNum() this.listherHeaderBodyNum()
}) })
const treeModifiers = this.getFieldModifiers(this.props.archInfo.__rawArch); const treeModifiers = this.getFieldModifiers(this.props.archInfo.__rawArch);
if(treeModifiers) { if(treeModifiers) {
if(treeModifiers.merge_fields) { this.props.merge_key = treeModifiers.merge_key;
this.props.merge_key = treeModifiers.merge_key; this.props.merge_fields = treeModifiers.merge_fields.split(',');
this.props.merge_fields = treeModifiers.merge_fields.split(','); const data = this.setColumns(this.props.merge_key);
const data = this.setColumns(this.props.merge_key); owl.onMounted(() => {
owl.onMounted(() => { this.mergeColumns(this.props.merge_fields, data)
this.mergeColumns(this.props.merge_fields, data) })
})
}
if(treeModifiers.pacthResize) {
owl.onPatched(() => {
this.columnWidths = null;
this.freezeColumnWidths();
})
}
} }
return this._super(...arguments); return this._super(...arguments);
}, },

View File

@@ -8,21 +8,17 @@
'category': 'purchase', 'category': 'purchase',
'depends': ['sf_manufacturing', 'purchase_request'], 'depends': ['sf_manufacturing', 'purchase_request'],
'data': [ 'data': [
'security/ir.model.access.csv',
'views/sale_order_view.xml', 'views/sale_order_view.xml',
'views/mrp_production.xml', 'views/mrp_production.xml',
'views/purchase_request_view.xml', 'views/purchase_request_view.xml',
'wizard/purchase_request_line_make_purchase_order_view.xml', 'wizard/purchase_request_line_make_purchase_order_view.xml',
'views/purchase_request_line_view.xml', 'views/purchase_request_line_view.xml',
'views/stock_picking_views.xml',
'wizard/purchase_request_wizard_views.xml',
'views/purchase_request_menu_views.xml',
], ],
'assets': { 'assets': {
'web.assets_backend': [ 'web.assets_backend': [
'jikimo_purchase_request/static/src/**/*' 'jikimo_purchase_request/static/src/**/*'
], ],
}, },
'application': True, 'application': True,
'installable': True, 'installable': True,
'auto_install': False, 'auto_install': False,

View File

@@ -410,7 +410,7 @@ msgstr "显示名称"
#: model_terms:ir.ui.view,arch_db:purchase_request.view_purchase_request_form #: model_terms:ir.ui.view,arch_db:purchase_request.view_purchase_request_form
#: model_terms:ir.ui.view,arch_db:purchase_request.view_purchase_request_search #: model_terms:ir.ui.view,arch_db:purchase_request.view_purchase_request_search
msgid "Done" msgid "Done"
msgstr "关闭" msgstr "完成"
#. module: purchase_request #. module: purchase_request
#: model:ir.model.fields,field_description:purchase_request.field_purchase_request_line__move_dest_ids #: model:ir.model.fields,field_description:purchase_request.field_purchase_request_line__move_dest_ids
@@ -1043,7 +1043,7 @@ msgstr "询价单"
#. module: purchase_request #. module: purchase_request
#: model:ir.model.fields,field_description:purchase_request.field_purchase_request_line__purchased_qty #: model:ir.model.fields,field_description:purchase_request.field_purchase_request_line__purchased_qty
msgid "RFQ/PO Qty" msgid "RFQ/PO Qty"
msgstr "已订购数" msgstr ""
#. module: purchase_request #. module: purchase_request
#. odoo-python #. odoo-python

View File

@@ -5,4 +5,3 @@ from . import sale_order
from . import mrp_production from . import mrp_production
from . import purchase_order from . import purchase_order
from . import stock_rule from . import stock_rule
from . import stock_picking

View File

@@ -18,8 +18,10 @@ class MrpProduction(models.Model):
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name)]) # pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name)])
# item.pr_mp_count = len(pr_ids) # item.pr_mp_count = len(pr_ids)
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品 # 由于采购申请合并了所有销售订单行的采购,所以不区分产品
mrp_names = self.env['mrp.production'].search([('origin', '=', item.origin)]).mapped('name') first_mp = self.env['mrp.production'].search(
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'in', mrp_names)]) [('origin', '=', item.origin)], limit=1, order='id asc')
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', first_mp.name), ('is_subcontract', '!=', 'True')])
item.pr_mp_count = len(pr_ids) item.pr_mp_count = len(pr_ids)
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')]) # pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')])
@@ -28,17 +30,10 @@ class MrpProduction(models.Model):
采购请求 采购请求
""" """
self.ensure_one() self.ensure_one()
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name),('is_subcontract', '!=', True)]) first_mp = self.env['mrp.production'].search(
# if self.product_id.product_tmpl_id.single_manufacturing == True and not self.is_remanufacture: [('origin', '=', self.origin)], limit=1, order='id asc')
# first_order = self.env['mrp.production'].search( pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', '=', self.origin), ('product_id', '=', self.product_id.id)], limit=1, order='id asc') [('origin', 'like', first_mp.name), ('is_subcontract', '!=', 'True')])
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', first_order.name)])
# else:
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name)])
# 由于采购申请合并了所有销售订单行的采购,所以不区分产品
mrp_names = self.env['mrp.production'].search([('origin', '=', self.origin)]).mapped('name')
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'in', mrp_names)])
action = { action = {
'res_model': 'purchase.request', 'res_model': 'purchase.request',
@@ -52,7 +47,7 @@ class MrpProduction(models.Model):
else: else:
action.update({ action.update({
'name': _("%s生成采购请求单", self.name), 'name': _("%s生成采购请求单", self.name),
'domain': [('id', 'in', pr_ids)], 'domain': [('id', 'in', pr_ids.ids)],
'view_mode': 'tree,form', 'view_mode': 'tree,form',
}) })
return action return action

View File

@@ -13,7 +13,11 @@ class ProductTemplate(models.Model):
template_id.purchase_request = product_id.purchase_request template_id.purchase_request = product_id.purchase_request
return template_id return template_id
class ProdcutProduct(models.Model):
_inherit = 'product.product'
def copy_template(self, product_template_id): def copy_template(self, product_template_id):
""" 复制成品模板时,复制采购申请 """ """ 复制成品模板时,复制采购申请 """
super(ProductTemplate, self).copy_template(product_template_id) super(ProdcutProduct, self).copy_template(product_template_id)
self.purchase_request = product_template_id.purchase_request self.purchase_request = product_template_id.purchase_request

View File

@@ -1,5 +1,4 @@
from odoo import api, fields, models, _ from odoo import api, fields, models, _
from odoo.tools import float_compare
class PurchaseOrder(models.Model): class PurchaseOrder(models.Model):
@@ -15,42 +14,3 @@ class PurchaseOrder(models.Model):
('cancel', '取消'), ('cancel', '取消'),
('rejected', '已驳回') ('rejected', '已驳回')
], string='Status', readonly=True, index=True, copy=False, default='draft', tracking=True) ], string='Status', readonly=True, index=True, copy=False, default='draft', tracking=True)
def button_confirm(self):
res = super(PurchaseOrder, self).button_confirm()
# 取消反向调拨单
reverse_move_ids = self.env['stock.move'].search([
('origin', '=', self.name),
('purchase_line_id', '=', False),
('state', '!=', 'done')
])
if reverse_move_ids:
reverse_move_ids.picking_id.action_cancel()
return res
def button_cancel(self):
"""
将取消的采购订单关联的库存移动撤销
"""
move_ids = self.order_line.move_dest_ids.filtered(lambda move: move.state != 'done' and not move.scrapped)
res =super(PurchaseOrder, self).button_cancel()
if move_ids.mapped('created_purchase_request_line_id'):
move_ids.write({'state': 'waiting', 'is_done': False})
return res
def write(self, vals):
res = super(PurchaseOrder, self).write(vals)
if 'state' in vals and vals['state'] == 'purchase':
purchase_request = self.order_line.purchase_request_lines.request_id
if purchase_request:
finished = True
# 判断该采购申请所有明细行是否都完成
for purchase_request_line in purchase_request.line_ids:
finished_qty = sum(purchase_request_line.purchase_lines.filtered(lambda line: line.state == 'purchase').mapped('product_qty'))
if float_compare(finished_qty ,purchase_request_line.product_qty, precision_rounding=purchase_request_line.product_id.uom_id.rounding) < 0:
finished = False
break
if finished:
purchase_request.button_done()
return res

View File

@@ -1,15 +1,13 @@
import re import re
import ast import ast
from odoo import models, fields, api, _ from odoo import models, fields, api
from itertools import groupby
from odoo.tools import float_compare
class PurchaseRequest(models.Model): class PurchaseRequest(models.Model):
_inherit = 'purchase.request' _inherit = 'purchase.request'
_description = '采购申请' _description = '采购申请'
# 为state添加取消状态 # 为state添加取消状态
state = fields.Selection( state = fields.Selection(
selection_add=[('cancel', '已取消')], selection_add=[('cancel', '已取消')],
ondelete={'cancel': 'set default'} # 添加 ondelete 策略 ondelete={'cancel': 'set default'} # 添加 ondelete 策略
@@ -31,57 +29,6 @@ class PurchaseRequest(models.Model):
action['context'] = origin_context action['context'] = origin_context
return action return action
def button_done(self):
product_qty_map = {key: sum(line.product_qty for line in group) for key, group in
groupby(self.line_ids, key=lambda x: x.product_id.id)}
lines = self.mapped("line_ids.purchase_lines.order_id")
# 采购单产品和数量
product_summary = {}
product_rounding = {}
if lines:
for line in lines:
for line_item in line.order_line:
if line_item.state == 'purchase':
product_id = line_item.product_id.id
qty = line_item.product_qty
product_rounding[product_id] = line_item.product_id.uom_id.rounding
if product_id in product_summary:
product_summary[product_id] += qty
else:
product_summary[product_id] = qty
# 校验产品数量
discrepancies = []
for product_id, qty in product_qty_map.items():
if product_id in product_summary:
if float_compare(product_summary[product_id], qty, precision_rounding=product_rounding[product_id]) < 0:
discrepancies.append((product_id, qty, product_summary[product_id]))
else:
discrepancies.append((product_id, qty, 0))
if discrepancies:
# 弹出提示框
message = "产品与采购数量不一致:\n"
for product_id, required_qty, order_qty in discrepancies:
product_name = self.env['product.product'].browse(product_id).display_name # 获取产品名称
message += f"产品 {product_name},需求数量 {required_qty},关联采购订单确认的数量 {order_qty}\n"
# 添加确认框
message += "确认关闭?"
return {
'name': _('采购申请'),
'type': 'ir.actions.act_window',
'views': [(self.env.ref(
'jikimo_purchase_request.purchase_request_wizard_wizard_form_view').id,
'form')],
'res_model': 'purchase.request.wizard',
'target': 'new',
'context': {
'default_purchase_request_id': self.id,
'default_message': message,
}}
return super(PurchaseRequest, self).button_done()
class PurchaseRequestLine(models.Model): class PurchaseRequestLine(models.Model):
_inherit = 'purchase.request.line' _inherit = 'purchase.request.line'
_description = '采购申请明细' _description = '采购申请明细'
@@ -100,8 +47,7 @@ class PurchaseRequestLine(models.Model):
('outsourcing', "委外加工"), ('outsourcing', "委外加工"),
], string='供货方式', compute='_compute_supply_method', store=True) ], string='供货方式', compute='_compute_supply_method', store=True)
purchase_request_count = fields.Integer(string='采购申请数量', compute='_compute_purchase_request_count', purchase_request_count = fields.Integer(string='采购申请数量', compute='_compute_purchase_request_count', readonly=True)
readonly=True)
purchase_count = fields.Integer(string="采购订单数量", compute="_compute_purchase_count", readonly=True) purchase_count = fields.Integer(string="采购订单数量", compute="_compute_purchase_count", readonly=True)
@api.depends("purchase_lines") @api.depends("purchase_lines")
@@ -146,7 +92,7 @@ class PurchaseRequestLine(models.Model):
continue continue
if record.product_id.categ_id.name == '坯料': if record.product_id.categ_id.name == '坯料':
product_name = '' product_name = ''
match = re.search(r'(S\d{5}-\d+)', record.product_id.name) match = re.search(r'(S\d{5}-\d)', record.product_id.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)
@@ -170,7 +116,7 @@ class PurchaseRequestLine(models.Model):
for pr in self: for pr in self:
qty_to_buy = sum(pr.mapped("product_qty")) qty_to_buy = sum(pr.mapped("product_qty"))
if pr.purchase_count > 0: if pr.purchase_count > 0:
qty_to_buy -= sum(pr.mapped("purchase_lines").filtered(lambda po: po.state != 'cancel').mapped( qty_to_buy -= sum(pr.mapped("purchase_lines").filtered(lambda po: po.state != 'cancel').mapped(
"product_qty")) "product_qty"))
pr.qty_to_buy = qty_to_buy > 0.0 pr.qty_to_buy = qty_to_buy > 0.0
pr.pending_qty_to_receive = qty_to_buy pr.pending_qty_to_receive = qty_to_buy

View File

@@ -1,47 +0,0 @@
from odoo import fields, api, models, _
class StockPicking(models.Model):
_inherit = "stock.picking"
purchase_request_count = fields.Integer('采购订单数量', compute='_compute_purchase_request')
@api.depends('name')
def _compute_purchase_request(self):
for record in self:
purchase_request_ids = self.env['purchase.request'].search([('origin', '=', record.name)])
record.purchase_request_count = len(purchase_request_ids)
def action_view_purchase_request(self):
self.ensure_one()
purchase_request_ids = self.env['purchase.request'].search([('origin', '=', self.name)])
action = {
'res_model': 'purchase.request',
'type': 'ir.actions.act_window',
}
if len(purchase_request_ids) == 1:
action.update({
'view_mode': 'form',
'res_id': purchase_request_ids[0].id,
})
else:
action.update({
'name': _("%s生成采购请求单", self.name),
'domain': [('id', 'in', purchase_request_ids.ids)],
'view_mode': 'tree,form',
})
return action
def _action_done(self):
res = super(StockPicking, self)._action_done()
# 将新产生的backorder对应上原来的采购申请明细行
backorder_ids = self.backorder_ids
if backorder_ids:
purchase_request_lines = self.move_ids.move_orig_ids.purchase_line_id.purchase_request_lines
if purchase_request_lines:
purchase_request_lines.move_dest_ids = [
(4, x.id) for x in backorder_ids.move_ids if x.product_id.id == purchase_request_lines.product_id.id
]
return res

View File

@@ -48,8 +48,8 @@ class StockRule(models.Model):
# 如果补货组相同,并且产品相同,则合并 # 如果补货组相同,并且产品相同,则合并
procurements_dict = defaultdict() procurements_dict = defaultdict()
for procurement, rule in procurements: for procurement, rule in procurements:
if (procurement.product_id.id, procurement.values['group_id'], rule.id) not in procurements_dict: if (procurement.product_id, procurement.values['group_id'], rule) not in procurements_dict:
procurements_dict[(procurement.product_id.id, procurement.values['group_id'], rule.id)] = { procurements_dict[(procurement.product_id, procurement.values['group_id'], rule)] = {
'product_id': procurement.product_id, 'product_id': procurement.product_id,
'product_qty': procurement.product_qty, 'product_qty': procurement.product_qty,
'product_uom': procurement.product_uom, 'product_uom': procurement.product_uom,
@@ -61,8 +61,7 @@ class StockRule(models.Model):
'rule': rule 'rule': rule
} }
else: else:
procurements_dict[(procurement.product_id.id, procurement.values['group_id'], rule.id)]['product_qty'] += procurement.product_qty procurements_dict[(procurement.product_id, procurement.values['group_id'], rule)]['product_qty'] += procurement.product_qty
procurements_dict[(procurement.product_id.id, procurement.values['group_id'], rule.id)]['values']['move_dest_ids'] |= procurement.values['move_dest_ids']
new_procurements = [] new_procurements = []
for k, p in procurements_dict.items(): for k, p in procurements_dict.items():
new_procurements.append(( new_procurements.append((
@@ -79,4 +78,12 @@ class StockRule(models.Model):
) )
res = super(StockRule, self)._run_buy(new_procurements) res = super(StockRule, self)._run_buy(new_procurements)
# 判断是否根据规则生成新的采购申请单据,如果生成则修改状态为 approved
origins = list(set([procurement[0].origin for procurement in procurements]))
for origin in origins:
pr_ids = self.env["purchase.request"].sudo().search(
[('origin', 'like', origin), ('rule_new_add', '=', True), ('state', '=', 'draft')])
if pr_ids:
pr_ids.write({'need_validation': False})
pr_ids.write({"state": "approved", 'need_validation': True, 'rule_new_add': False})
return res return res

View File

@@ -1,2 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_purchase_request_wizard_group_user,purchase.request.wizard,model_purchase_request_wizard,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_purchase_request_wizard_group_user purchase.request.wizard model_purchase_request_wizard base.group_user 1 1 1 1

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="menu_purhcase_request" model="ir.ui.menu">
<field name="name">采购申请</field>
<field name="parent_id" ref="purchase.menu_purchase_root" />
<field name="sequence">2</field>
</record>
<record id="purchase_request.menu_purchase_request_pro_mgt" model="ir.ui.menu">
<field name="sequence">1</field>
<field name="parent_id" ref="jikimo_purchase_request.menu_purhcase_request"/>
</record>
<record id="purchase_request.menu_purchase_request_line" model="ir.ui.menu">
<field name="sequence">10</field>
<field name="parent_id" ref="jikimo_purchase_request.menu_purhcase_request"/>
</record>
</data>
</odoo>

View File

@@ -15,26 +15,6 @@
<field name="part_number"/> <field name="part_number"/>
<field name="part_name"/> <field name="part_name"/>
</xpath> </xpath>
<xpath expr="//button[@name='button_done']" position="attributes">
<attribute name="class"/>
</xpath>
<xpath expr="//button[@name='button_in_progress']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//button[@name='%(purchase_request.action_purchase_request_line_make_purchase_order)d']" position="attributes">
<attribute name="class">oe_highlight</attribute>
</xpath>
</field>
</record>
<record id="view_purchase_request_tree_sf" model="ir.ui.view">
<field name="name">purchase.request.sf.tree</field>
<field name="model">purchase.request</field>
<field name="inherit_id" ref="purchase_request.view_purchase_request_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='activity_ids']" position="attributes">
<attribute name="optional">hide</attribute>
</xpath>
</field> </field>
</record> </record>
@@ -83,9 +63,4 @@
</xpath> </xpath>
</field> </field>
</record> </record>
<record model="ir.actions.act_window" id="purchase_request.purchase_request_form_action">
<field name="name">Purchase Requests</field>
<field name="context"></field>
</record>
</odoo> </odoo>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="stock_pikcing_inherited_form_jikimo_purchase_request" model="ir.ui.view">
<field name="name">stock.pikcing.inherited.form.jikimo.purchase.request</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']/button" position="before">
<button class="oe_stat_button" name="action_view_purchase_request" type="object" icon="fa-credit-card"
attrs="{'invisible': [('purchase_request_count', '=', 0)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="purchase_request_count"/>
</span>
<span class="o_stat_text">采购申请</span>
</div>
</button>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,4 +1,3 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from . import purchase_request_line_make_purchase_order from . import purchase_request_line_make_purchase_order
from . import purchase_request_wizard

View File

@@ -119,11 +119,3 @@ class PurchaseRequestLineMakePurchaseOrderItem(models.TransientModel):
_inherit = "purchase.request.line.make.purchase.order.item" _inherit = "purchase.request.line.make.purchase.order.item"
supply_method = fields.Selection(related='line_id.supply_method', string='供货方式') supply_method = fields.Selection(related='line_id.supply_method', string='供货方式')
wiz_id = fields.Many2one(
comodel_name="purchase.request.line.make.purchase.order",
string="Wizard",
required=False,
ondelete="cascade",
readonly=True,
)

View File

@@ -1,12 +0,0 @@
from odoo import models, fields, api
class PurchaseRequestWizard(models.TransientModel):
_name = 'purchase.request.wizard'
_description = '采购申请向导'
purchase_request_id = fields.Many2one('purchase.request', string='采购申请')
message = fields.Char(string='提示', readonly=True)
def confirm(self):
return self.purchase_request_id.write({"state": "done"})

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="purchase_request_wizard_wizard_form_view">
<field name="name">purchase.request.wizard.form.view</field>
<field name="model">purchase.request.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<div>
<div style="white-space: pre-wrap;">
<field name="message"/>
</div>
</div>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
</odoo>

View File

@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
{ {
'name': "机企猫 采购申请审批流程", 'name': "机企猫 采购审批流程",
'summary': """ 'summary': """
采购申请审批流程""", Short (1 phrase/line) summary of the module's purpose, used as
subtitle on modules listing or apps.openerp.com""",
'description': """ 'description': """
Long description of module's purpose Long description of module's purpose

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import models from . import models
from . import stock_rule

View File

@@ -22,9 +22,3 @@ class PurchaseRequest(models.Model):
self.state = 'approved' self.state = 'approved'
return res return res
@api.model
def _get_under_validation_exceptions(self):
res = super(PurchaseRequest, self)._get_under_validation_exceptions()
res.append("state")
return res

View File

@@ -1,16 +0,0 @@
from odoo import models, api
class StockRule(models.Model):
_inherit = 'stock.rule'
def _run_buy(self, procurements):
res = super(StockRule, self)._run_buy(procurements)
# 判断是否根据规则生成新的采购申请单据,如果生成则修改状态为 approved
origins = list(set([procurement[0].origin for procurement in procurements]))
for origin in origins:
pr_ids = self.env["purchase.request"].sudo().search(
[('origin', 'like', origin), ('rule_new_add', '=', True), ('state', '=', 'draft')])
if pr_ids:
pr_ids.write({'need_validation': False})
pr_ids.write({"state": "approved", 'need_validation': True, 'rule_new_add': False})
return res

View File

@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
{ {
'name': "机企猫 采购审批流程", 'name': "机企猫 采购申请审批流程",
'summary': """ 'summary': """
采购审批流程""", 采购申请审批流程""",
'description': """ 'description': """
采购审批流程""", 采购申请审批流程""",
'author': "My Company", 'author': "My Company",
'website': "https://www.yourcompany.com", 'website': "https://www.yourcompany.com",

View File

@@ -6,6 +6,10 @@ class ProductTemplate(models.Model):
is_manual_processing = fields.Boolean(string='人工线下加工') is_manual_processing = fields.Boolean(string='人工线下加工')
is_customer_provided = fields.Boolean(string='客供料') is_customer_provided = fields.Boolean(string='客供料')
class ProductProduct(models.Model):
_inherit = 'product.product'
def copy_template(self, product_template_id): def copy_template(self, product_template_id):
if not isinstance(product_template_id, ProductTemplate): if not isinstance(product_template_id, ProductTemplate):
raise ValueError('%s必须是ProductTemplate类型' % product_template_id) raise ValueError('%s必须是ProductTemplate类型' % product_template_id)

View File

@@ -133,7 +133,6 @@ class QualityCheck(models.Model):
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=False, store=True) part_name = fields.Char('零件名称', related='product_id.part_name', readonly=False, store=True)
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=False, store=True) part_number = fields.Char('零件图号', related='product_id.part_number', readonly=False, store=True)
material_name = fields.Char('材料名称', compute='_compute_material_name') material_name = fields.Char('材料名称', compute='_compute_material_name')
model_id = fields.Char('模型ID', related='product_id.model_id')
# # 总数量值为调拨单_产品明细_数量 # # 总数量值为调拨单_产品明细_数量
# total_qty = fields.Float('总数量', compute='_compute_total_qty', readonly=True) # total_qty = fields.Float('总数量', compute='_compute_total_qty', readonly=True)
@@ -142,7 +141,7 @@ class QualityCheck(models.Model):
# # 出厂检验报告编号 # # 出厂检验报告编号
# report_number = fields.Char('出厂检验报告编号', compute='_compute_report_number', readonly=True) # report_number = fields.Char('出厂检验报告编号', compute='_compute_report_number', readonly=True)
# 总数量值为调拨单_产品明细_数量 # 总数量值为调拨单_产品明细_数量
total_qty = fields.Char('总数量', compute='_compute_total_qty', store=True) total_qty = fields.Char('总数量', compute='_compute_total_qty')
column_nums = fields.Integer('测量值列数', default=1) column_nums = fields.Integer('测量值列数', default=1)
@@ -154,9 +153,9 @@ class QualityCheck(models.Model):
for move in record.picking_id.move_ids_without_package: for move in record.picking_id.move_ids_without_package:
if move.product_id == record.product_id: if move.product_id == record.product_id:
total_qty = int(move.product_uom_qty) total_qty = int(move.product_uom_qty)
record.total_qty = total_qty if total_qty > 0 else 0 record.total_qty = total_qty if total_qty > 0 else ''
else: else:
record.total_qty = 0 record.total_qty = ''
# 检验数 # 检验数
check_qty = fields.Integer('检验数', default=lambda self: self._get_default_check_qty()) check_qty = fields.Integer('检验数', default=lambda self: self._get_default_check_qty())
@@ -339,7 +338,7 @@ class QualityCheck(models.Model):
# 4. 获取报告动作并生成PDF此时二维码将包含正确的文档ID # 4. 获取报告动作并生成PDF此时二维码将包含正确的文档ID
report_action = self.env.ref('sf_quality.action_report_quality_inspection') report_action = self.env.ref('sf_quality.action_report_quality_inspection')
pdf_content, v = report_action._render_qweb_pdf( pdf_content, _ = report_action._render_qweb_pdf(
report_ref=report_action.report_name, report_ref=report_action.report_name,
res_ids=self.ids res_ids=self.ids
) )
@@ -736,9 +735,8 @@ class QualityCheck(models.Model):
def _compute_qty_to_test(self): def _compute_qty_to_test(self):
for qc in self: for qc in self:
if qc.is_lot_tested_fractionally: if qc.is_lot_tested_fractionally:
rounding = qc.product_id.uom_id.rounding if qc.product_id.uom_id else 0.01
qc.qty_to_test = float_round(qc.qty_line * qc.testing_percentage_within_lot / 100, qc.qty_to_test = float_round(qc.qty_line * qc.testing_percentage_within_lot / 100,
precision_rounding=rounding, rounding_method="UP") precision_rounding=self.product_id.uom_id.rounding, rounding_method="UP")
else: else:
qc.qty_to_test = qc.qty_line qc.qty_to_test = qc.qty_line

View File

@@ -493,9 +493,6 @@
<field name="picking_id"/> <field name="picking_id"/>
<field name="lot_id"/> <field name="lot_id"/>
<field name="team_id"/> <field name="team_id"/>
<field name="part_number"/>
<field name="part_name"/>
<field name="model_id"/>
<filter string="In Progress" name="progress" domain="[('quality_state', '=', 'none')]"/> <filter string="In Progress" name="progress" domain="[('quality_state', '=', 'none')]"/>
<filter string="Passed" name="passed" domain="[('quality_state', '=', 'pass')]"/> <filter string="Passed" name="passed" domain="[('quality_state', '=', 'pass')]"/>
<filter string="Failed" name="failed" domain="[('quality_state', '=', 'fail')]"/> <filter string="Failed" name="failed" domain="[('quality_state', '=', 'fail')]"/>

View File

@@ -23,8 +23,8 @@ class QualityCheckWizard(models.TransientModel):
lot_name = fields.Char(related='current_check_id.lot_name') lot_name = fields.Char(related='current_check_id.lot_name')
lot_line_id = fields.Many2one(related='current_check_id.lot_line_id') lot_line_id = fields.Many2one(related='current_check_id.lot_line_id')
qty_line = fields.Float(related='current_check_id.qty_line') qty_line = fields.Float(related='current_check_id.qty_line')
qty_to_test = fields.Float(related='current_check_id.qty_to_test', string='待检') qty_to_test = fields.Float(related='current_check_id.qty_to_test')
qty_tested = fields.Float(related='current_check_id.qty_tested', string='已检', readonly=False) qty_tested = fields.Float(related='current_check_id.qty_tested', readonly=False)
measure = fields.Float(related='current_check_id.measure', readonly=False) measure = fields.Float(related='current_check_id.measure', readonly=False)
measure_on = fields.Selection(related='current_check_id.measure_on') measure_on = fields.Selection(related='current_check_id.measure_on')
quality_state = fields.Selection(related='current_check_id.quality_state') quality_state = fields.Selection(related='current_check_id.quality_state')

View File

@@ -195,18 +195,10 @@ class PrintingUtils(models.AbstractModel):
text_y = margin + 20 # 文字位置靠近底部 text_y = margin + 20 # 文字位置靠近底部
c.drawString(text_x, text_y, text) c.drawString(text_x, text_y, text)
# 设置字体
if font_found:
c.setFont('SimSun', 12) # 增大字体大小到14pt
else:
# 如果没有找到中文字体,使用默认字体
c.setFont('Helvetica', 120)
logging.warning("未找到中文字体,将使用默认字体")
if buttom_text: if buttom_text:
# 在下方中间添加文字 # 在下方中间添加文字
text = buttom_text text = button_text
text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 12) # 准确计算文字宽度 text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 10) # 准确计算文字宽度
text_x = (page_width - text_width) / 2 # 文字居中对齐 text_x = (page_width - text_width) / 2 # 文字居中对齐
text_y = margin + 20 # 文字位置靠近底部 text_y = margin + 20 # 文字位置靠近底部
c.drawString(text_x, text_y, text) c.drawString(text_x, text_y, text)

View File

@@ -35,19 +35,16 @@ def api_log(name=None, requester=None):
end_time = datetime.now() end_time = datetime.now()
response_time = (end_time - start_time).total_seconds() response_time = (end_time - start_time).total_seconds()
# 获取响应状态
status = result.get('code') if 'code' in result else result.get('ErrorCode') if 'ErrorCode' in result else 200
# 创建日志记录 # 创建日志记录
log_vals = { log_vals = {
'name': name or func.__name__, 'name': name or func.__name__,
'path': path, 'path': path,
'method': method.upper(), 'method': method,
'request_data': json.dumps(request_data, ensure_ascii=False), 'request_data': json.dumps(request_data, ensure_ascii=False),
'response_data': json.dumps(result, ensure_ascii=False), 'response_data': json.dumps(result, ensure_ascii=False),
'remote_addr': remote_addr, 'remote_addr': remote_addr,
'response_time': response_time, 'response_time': response_time,
'status': 200 if status == 0 else status, 'status': result.get('code') or result.get('ErrorCode') or 500,
'requester': requester, 'requester': requester,
'responser': '智能工厂' 'responser': '智能工厂'
} }

View File

@@ -59,7 +59,7 @@ class ApiRequestLog(models.Model):
self.sudo().create({ self.sudo().create({
'name': name, 'name': name,
'path': url, 'path': url,
'method': method.upper(), 'method': method,
'request_data': request_body, 'request_data': request_body,
'response_data': response_body, 'response_data': response_body,
'remote_addr': None, 'remote_addr': None,

View File

@@ -5,15 +5,13 @@
<field name="model">api.request.log</field> <field name="model">api.request.log</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="create_date"/>
<field name="name"/> <field name="name"/>
<field name="path"/> <field name="path"/>
<field name="method"/> <field name="method"/>
<field name="remote_addr"/> <field name="remote_addr"/>
<field name="response_time" sum="0"/> <field name="response_time"/>
<field name="requester"/> <field name="status"/>
<field name="responser"/>
<field name="create_date" string="请求时间"/>
<field name="status" sum="0"/>
</tree> </tree>
</field> </field>
</record> </record>
@@ -34,8 +32,6 @@
<group> <group>
<field name="response_time"/> <field name="response_time"/>
<field name="status"/> <field name="status"/>
<field name="requester"/>
<field name="responser"/>
<field name="create_date" string="请求时间"/> <field name="create_date" string="请求时间"/>
</group> </group>
</group> </group>
@@ -52,23 +48,6 @@
</field> </field>
</record> </record>
<record model="ir.ui.view" id="view_api_request_log_search">
<field name="name">api.request.log.search</field>
<field name="model">api.request.log</field>
<field name="arch" type="xml">
<search string="API请求日志">
<field name="name"/>
<field name="requester"/>
<field name="responser"/>
<group>
<filter name="name" context="{'group_by':'name'}"/>
<filter name="requester" context="{'group_by':'requester'}"/>
<filter name="responser" context="{'group_by':'responser'}"/>
</group>
</search>
</field>
</record>
<record id="action_api_request_log" model="ir.actions.act_window"> <record id="action_api_request_log" model="ir.actions.act_window">
<field name="name">API请求日志</field> <field name="name">API请求日志</field>
<field name="res_model">api.request.log</field> <field name="res_model">api.request.log</field>

View File

@@ -17,7 +17,7 @@ class ResProductCategory(models.Model):
class ResProductProduct(models.Model): class ResProductProduct(models.Model):
_inherit = 'product.product' _inherit = 'product.product'
# single_manufacturing = fields.Boolean(string="单个制造") single_manufacturing = fields.Boolean(string="单个制造")
is_bfm = fields.Boolean('业务平台是否自动创建', default=False) is_bfm = fields.Boolean('业务平台是否自动创建', default=False)

View File

@@ -1,16 +1,16 @@
# import logging import logging
# from odoo import fields, models, api from odoo import fields, models, api
# from odoo.exceptions import UserError from odoo.exceptions import UserError
# from odoo.tools import str2bool from odoo.tools import str2bool
# class ResMrpRoutingWorkcenter(models.Model): class ResMrpRoutingWorkcenter(models.Model):
# _inherit = 'mrp.routing.workcenter' _inherit = 'mrp.routing.workcenter'
# def init(self): def init(self):
# super(ResMrpRoutingWorkcenter, self).init() super(ResMrpRoutingWorkcenter, self).init()
# # 在模块初始化时触发计算字段的更新 # 在模块初始化时触发计算字段的更新
# records = self.search([]) records = self.search([])
# if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_workcenter',default='False')): if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_workcenter',default='False')):
# return return
# records.optional_process_parameters_date() records.optional_process_parameters_date()
# self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_workcenter', True) self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_workcenter', True)

View File

@@ -1,85 +1,87 @@
# # -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# import logging import logging
# from odoo import fields, models, api from odoo import fields, models, api
# from odoo.exceptions import UserError from odoo.exceptions import UserError
# from odoo.tools import str2bool from odoo.tools import str2bool
# class SfProductionProcessParameter(models.Model): class SfProductionProcessParameter(models.Model):
# _inherit = 'sf.production.process.parameter' _inherit = 'sf.production.process.parameter'
# @api.model @api.model
# def create(self, vals): def create(self, vals):
# # if vals.get('code', '/') == '/' or vals.get('code', '/') is False: # if vals.get('code', '/') == '/' or vals.get('code', '/') is False:
# # vals['code'] = '101'+self.routing_id.code +self.env['ir.sequence'].next_by_code('sf.production.process.parameter') # vals['code'] = '101'+self.routing_id.code +self.env['ir.sequence'].next_by_code('sf.production.process.parameter')
# if vals.get('routing_id'): if vals.get('routing_id'):
# # vals['gain_way'] = '外协' # vals['gain_way'] = '外协'
# routing_id = self.env['mrp.routing.workcenter'].browse(vals.get('routing_id')) routing_id = self.env['mrp.routing.workcenter'].browse(vals.get('routing_id'))
# if routing_id.surface_technics_id and not vals.get('process_id'): if routing_id.surface_technics_id and not vals.get('process_id'):
# vals['process_id'] = routing_id.surface_technics_id.id vals['process_id'] = routing_id.surface_technics_id.id
# if vals.get('code', '/') == '/' or vals.get('code', '/') is False: if vals.get('code', '/') == '/' or vals.get('code', '/') is False:
# vals['code'] = '101' + routing_id.code + self.env['ir.sequence'].next_by_code( vals['code'] = '101' + routing_id.code + self.env['ir.sequence'].next_by_code(
# 'sf.production.process.parameter') 'sf.production.process.parameter')
# obj = super(SfProductionProcessParameter, self).create(vals) obj = super(SfProductionProcessParameter, self).create(vals)
# return obj return obj
# def create_service_product(self): def create_service_product(self):
# service_categ = self.env.ref( if not self.active:
# 'sf_dlm.product_category_surface_technics_sf').sudo() return
service_categ = self.env.ref(
'sf_dlm.product_category_surface_technics_sf').sudo()
# product_name = f"{self.process_id.name}_{self.name}" product_name = f"{self.process_id.name}_{self.name}"
# product_id = self.env['product.template'].search( product_id = self.env['product.template'].search(
# [("name", '=', product_name)]) [("name", '=', product_name)])
# if product_id: if product_id:
# product_id.server_product_process_parameters_id = self.id product_id.server_product_process_parameters_id = self.id
# else: else:
# res_partner = self.env['res.partner'].search([('name','=','湖南傲派自动化设备有限公司')]) res_partner = self.env['res.partner'].search([('name','=','湖南傲派自动化设备有限公司')])
# self.env['product.template'].create({ self.env['product.template'].create({
# 'detailed_type': 'service', 'detailed_type': 'service',
# 'name': product_name, 'name': product_name,
# 'invoice_policy': 'delivery', 'invoice_policy': 'delivery',
# 'categ_id': service_categ.id, 'categ_id': service_categ.id,
# 'description': f"基于{self.name}创建的服务产品", 'description': f"基于{self.name}创建的服务产品",
# 'sale_ok': True, # 可销售 'sale_ok': True, # 可销售
# 'purchase_ok': True, # 可采购 'purchase_ok': True, # 可采购
# 'server_product_process_parameters_id': self.id, 'server_product_process_parameters_id': self.id,
# 'seller_ids': [(0, 0, { 'seller_ids': [(0, 0, {
# # 'delay': 1, # 'delay': 1,
# 'partner_id': res_partner.id, 'partner_id': res_partner.id,
# 'price': 1, })], 'price': 1, })],
# }) })
# def create_work_center(self): def create_work_center(self):
# production_process_parameter = self production_process_parameter = self
# if not production_process_parameter.process_id: if not production_process_parameter.process_id:
# return return
# if not production_process_parameter.routing_id: if not production_process_parameter.routing_id:
# workcenter_id = self.env['mrp.routing.workcenter'].search( workcenter_id = self.env['mrp.routing.workcenter'].search(
# [("surface_technics_id", '=', production_process_parameter.process_id.id)]) [("surface_technics_id", '=', production_process_parameter.process_id.id)])
# if not workcenter_id: if not workcenter_id:
# outsourcing_work_center = self.env['mrp.workcenter'].search( outsourcing_work_center = self.env['mrp.workcenter'].search(
# [("name", '=', '外协工作中心')]) [("name", '=', '外协工作中心')])
# routing_id = self.env['mrp.routing.workcenter'].create({ routing_id = self.env['mrp.routing.workcenter'].create({
# 'workcenter_ids': [(6, 0, outsourcing_work_center.ids)], 'workcenter_ids': [(6, 0, outsourcing_work_center.ids)],
# 'routing_tag': 'special', 'routing_tag': 'special',
# 'routing_type': '表面工艺', 'routing_type': '表面工艺',
# 'is_outsource': True, 'is_outsource': True,
# 'surface_technics_id': production_process_parameter.process_id.id, 'surface_technics_id': production_process_parameter.process_id.id,
# 'name': production_process_parameter.process_id.name, 'name': production_process_parameter.process_id.name,
# }) })
# production_process_parameter.routing_id = routing_id.id production_process_parameter.routing_id = routing_id.id
# else: else:
# production_process_parameter.routing_id = workcenter_id.id production_process_parameter.routing_id = workcenter_id.id
# def init(self): def init(self):
# super(SfProductionProcessParameter, self).init() super(SfProductionProcessParameter, self).init()
# # 在模块初始化时触发计算字段的更新 # 在模块初始化时触发计算字段的更新
# records = self.search([]) records = self.search([])
# if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_process', if str2bool(self.env['ir.config_parameter'].get_param('sf.production.process.parameter.is_init_process',
# default='False')): default='False')):
# return return
# for record in records: for record in records:
# if not record.outsourced_service_products: if not record.outsourced_service_products:
# record.create_service_product() record.create_service_product()
# record.create_work_center() record.create_work_center()
# self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_process', True) self.env['ir.config_parameter'].set_param('sf.production.process.parameter.is_init_process', True)

View File

@@ -41,7 +41,9 @@
attrs="{'invisible': [('categ_type', 'not in', ['成品','坯料', '原材料'])],'readonly': [('id', '!=', False)]}"/> attrs="{'invisible': [('categ_type', 'not in', ['成品','坯料', '原材料'])],'readonly': [('id', '!=', False)]}"/>
<field name="server_product_process_parameters_id" string="工艺参数" <field name="server_product_process_parameters_id" string="工艺参数"
options="{'no_create': True}" options="{'no_create': True}"
attrs="{'invisible': ['|',('detailed_type', '!=', 'service'),('detailed_type', '=', False)]}"/> attrs="{'invisible': ['|',('detailed_type', '!=', 'service'),('detailed_type', '=', False)]}"
domain="[('active', '=', 'True'),('outsourced_service_products', '!=', 'True')]"
/>
<field name="cutting_tool_material_id" class="custom_required" <field name="cutting_tool_material_id" class="custom_required"
options="{'no_create': True}" options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}" attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"

View File

@@ -48,7 +48,7 @@
'views/mrp_workorder_batch_replan.xml', 'views/mrp_workorder_batch_replan.xml',
'views/purchase_order_view.xml', 'views/purchase_order_view.xml',
'views/product_template_views.xml', 'views/product_template_views.xml',
# 'views/stock_warehouse_orderpoint.xml', 'views/stock_warehouse_orderpoint.xml',
], ],
'assets': { 'assets': {

View File

@@ -445,7 +445,32 @@ class Manufacturing_Connect(http.Controller):
shelfinfo = list(filter(lambda x: x.get('DeviceId') == DeciveId, shelfinfo = list(filter(lambda x: x.get('DeviceId') == DeciveId,
request.env['sf.shelf.location'].sudo().get_sf_shelf_location_info( request.env['sf.shelf.location'].sudo().get_sf_shelf_location_info(
DeciveId))) DeciveId)))
request.env['sf.shelf.location.datasync'].sudo().set_shelf_location(shelfinfo) total_data = request.env['sf.shelf.location.datasync'].sudo().get_total_data()
for item in shelfinfo:
logging.info('货架已获取信息:%s' % item)
shelf_barcode = request.env['sf.shelf.location.datasync'].sudo().find_our_code(
total_data, item['Postion'])
location_id = request.env['sf.shelf.location'].sudo().search(
[('barcode', '=', shelf_barcode)],
limit=1)
if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = request.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.sudo().tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
# 修改功能刀具状态
if item.get('State') == '报警':
if tool.functional_tool_status != item.get('State'):
tool.write({
'functional_tool_status': item['State']
})
else:
location_id.product_sn_id = False
if item['RfidCode']:
logging.info('Rfid为【%s】的功能刀具在系统中不存在!' % item['RfidCode'])
else: else:
equipment_id = request.env['maintenance.equipment'].sudo().search([('name', '=', DeciveId)]) equipment_id = request.env['maintenance.equipment'].sudo().search([('name', '=', DeciveId)])
if equipment_id: if equipment_id:

View File

@@ -27,7 +27,7 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
bfm_process_order_list = json.loads(kw['bfm_process_order_list']) bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create( order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'], company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], kw['remark'], state='draft', kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], state='draft',
model_display_version=kw.get('model_display_version')) model_display_version=kw.get('model_display_version'))
i = 1 i = 1
# 给sale_order的default_code字段赋值 # 给sale_order的default_code字段赋值
@@ -45,9 +45,6 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False product.product_tmpl_id.is_customer_provided = True if item['embryo_redundancy_id'] else False
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
i += 1 i += 1
if kw.get('contract_file_name') and kw.get('contract_file') and kw.get('contract_code'):
order_id.create_sale_documents(kw.get('contract_file_name'), kw.get('contract_file'))
order_id.write({'contract_code': kw.get('contract_code'), 'contract_date': kw.get('contract_date')})
res['factory_order_no'] = order_id.name res['factory_order_no'] = order_id.name
order_id.confirm_to_supply_method() order_id.confirm_to_supply_method()
except Exception as e: except Exception as e:

View File

@@ -18,4 +18,4 @@ from . import quick_easy_order
from . import purchase_order from . import purchase_order
from . import quality_check from . import quality_check
from . import purchase_request_line from . import purchase_request_line
# from . import stock_warehouse_orderpoint from . import stock_warehouse_orderpoint

View File

@@ -279,7 +279,7 @@ class MrpProduction(models.Model):
production_id.part_name = production_id.product_id.part_name production_id.part_name = production_id.product_id.part_name
elif production_id.product_id.categ_id.type == '坯料': elif production_id.product_id.categ_id.type == '坯料':
product_name = '' product_name = ''
match = re.search(r'(S\d{5}-\d+)', production_id.product_id.name) match = re.search(r'(S\d{5}-\d)', production_id.product_id.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)
@@ -636,17 +636,13 @@ class MrpProduction(models.Model):
# 增加触发时间参数 # 增加触发时间参数
def update_programming_state(self, trigger_time=None, reprogramming_reason=None): def update_programming_state(self, trigger_time=None, reprogramming_reason=None):
try: try:
reason = ""
manufacturing_type = None manufacturing_type = None
if self.is_scrap: if self.is_scrap:
manufacturing_type = 'scrap' manufacturing_type = 'scrap'
reason = "报废"
elif self.tool_state == '2': elif self.tool_state == '2':
manufacturing_type = 'invalid_tool_rework' manufacturing_type = 'invalid_tool_rework'
reason = "无效功能刀具"
elif self.is_rework: elif self.is_rework:
manufacturing_type = 'rework' manufacturing_type = 'rework'
reason = "返工"
res = {'programming_no': self.programming_no, res = {'programming_no': self.programming_no,
'manufacturing_type': manufacturing_type, 'manufacturing_type': manufacturing_type,
'trigger_time': trigger_time, 'trigger_time': trigger_time,
@@ -661,16 +657,6 @@ class MrpProduction(models.Model):
result = json.loads(ret['result']) result = json.loads(ret['result'])
logging.info('update_programming_state-ret:%s' % result) logging.info('update_programming_state-ret:%s' % result)
if result['status'] == 1: if result['status'] == 1:
self.programming_record_ids.create({
'number': len(self.programming_record_ids) + 1,
'production_id': self.id,
'reason': reason,
'programming_method': False,
'current_programming_count': False,
'target_production_id': False,
'apply_time': fields.Datetime.now(),
'send_time': False,
})
self.write({'is_rework': True}) self.write({'is_rework': True})
else: else:
raise UserError(ret['message']) raise UserError(ret['message'])
@@ -801,17 +787,6 @@ class MrpProduction(models.Model):
if ret['status'] == 1: if ret['status'] == 1:
self.write( self.write(
{'programming_no': ret['programming_no'], 'programming_state': '编程中', 'work_state': '编程中'}) {'programming_no': ret['programming_no'], 'programming_state': '编程中', 'work_state': '编程中'})
# 生成编程记录
self.programming_record_ids.create({
'number': len(self.programming_record_ids) + 1,
'production_id': self.id,
'reason': '首次下发',
'programming_method': False,
'current_programming_count': False,
'target_production_id': False,
'apply_time': fields.Datetime.now(),
'send_time': False,
})
else: else:
raise UserError(ret['message']) raise UserError(ret['message'])
except Exception as e: except Exception as e:
@@ -925,41 +900,43 @@ class MrpProduction(models.Model):
for workorder in production.workorder_ids: for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected() workorder.duration_expected = workorder._get_duration_expected()
# def _create_subcontract_purchase_request(self, purchase_request_line): def _create_subcontract_purchase_request(self, purchase_request_line):
# sorted_list = sorted(purchase_request_line, key=itemgetter('name')) sorted_list = sorted(purchase_request_line, key=itemgetter('name'))
# grouped_purchase_request_line = { grouped_purchase_request_line = {
# k: list(g) k: list(g)
# for k, g in groupby(sorted_list, key=itemgetter('name')) for k, g in groupby(sorted_list, key=itemgetter('name'))
# } }
# for name, request_line in grouped_purchase_request_line.items(): for name, request_line in grouped_purchase_request_line.items():
# request_line_sorted_list = sorted(request_line, key=itemgetter('product_id')) request_line_sorted_list = sorted(request_line, key=itemgetter('product_id'))
# grouped_purchase_request_line_sorted_list = { grouped_purchase_request_line_sorted_list = {
# k: list(g) k: list(g)
# for k, g in groupby(request_line_sorted_list, key=itemgetter('product_id')) for k, g in groupby(request_line_sorted_list, key=itemgetter('product_id'))
# } }
# purchase_request_model = self.env["purchase.request"] purchase_request_model = self.env["purchase.request"]
# origin = ", ".join({item['production_name'] for item in request_line_sorted_list if item.get('production_name')}) origin = ", ".join({item['production_name'] for item in request_line_sorted_list if item.get('production_name')})
# pr = purchase_request_model.create({ pr = purchase_request_model.create({
# "origin": origin, "origin": origin,
# "company_id": self.company_id.id, "company_id": self.company_id.id,
# "picking_type_id": self.env.ref('stock.picking_type_in').id, "picking_type_id": self.env.ref('stock.picking_type_in').id,
# "group_id": request_line[0].get('group_id'), "group_id": request_line[0].get('group_id'),
# "requested_by": self.env.context.get("uid", self.env.uid), "requested_by": self.env.context.get("uid", self.env.uid),
# "assigned_to": False, "assigned_to": False,
# "bom_id": self[0].bom_id.id, "bom_id": self[0].bom_id.id,
# "is_subcontract":True, "is_subcontract":True,
# }) })
# self[0].bom_id.bom_line_ids.product_id.route_ids = [(4,self.env.ref( self[0].bom_id.bom_line_ids.product_id.route_ids = [(4,self.env.ref(
# 'sf_stock.stock_route_process_outsourcing').id)] 'sf_stock.stock_route_process_outsourcing').id)]
# for product_id, request_line_list in grouped_purchase_request_line_sorted_list.items(): for product_id, request_line_list in grouped_purchase_request_line_sorted_list.items():
# cur_request_line = request_line_list[0] cur_request_line = request_line_list[0]
# # cur_request_line['product_qty'] = cur_request_line['product_qty'] if cur_request_line['product_qty'] == 1:
# cur_request_line['request_id'] = pr.id cur_request_line['product_qty'] = len(request_line_list)
# cur_request_line['origin'] = ", ".join({item['production_name'] for item in request_line_list if item.get('production_name')}) # cur_request_line['product_qty'] = cur_request_line['product_qty']
# cur_request_line.pop('group_id', None) cur_request_line['request_id'] = pr.id
# cur_request_line.pop('production_name', None) cur_request_line['origin'] = ", ".join({item['production_name'] for item in request_line_list if item.get('production_name')})
# self.env["purchase.request.line"].create(cur_request_line) cur_request_line.pop('group_id', None)
# pr.button_approved() cur_request_line.pop('production_name', None)
self.env["purchase.request.line"].create(cur_request_line)
pr.button_approved()
# 外协出入库单处理 # 外协出入库单处理
def get_subcontract_pick_purchase(self): def get_subcontract_pick_purchase(self):
@@ -987,14 +964,14 @@ class MrpProduction(models.Model):
if not sorted_workorders: if not sorted_workorders:
return return
for workorders in reversed(sorted_workorders): for workorders in reversed(sorted_workorders):
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_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) # self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
# purchase_request_line = purchase_request_line + self.env['purchase.order'].get_purchase_request( purchase_request_line = purchase_request_line + self.env['purchase.order'].get_purchase_request(
# workorders, production) workorders, production)
# all_workorders += workorders all_workorders += workorders
# self._create_subcontract_purchase_request(purchase_request_line) self._create_subcontract_purchase_request(purchase_request_line)
# for workorder in all_workorders: for workorder in all_workorders:
# workorder._compute_pr_mp_count() workorder._compute_pr_mp_count()
# 工单排序 # 工单排序
def _reset_work_order_sequence1(self, k): def _reset_work_order_sequence1(self, k):
for rec in self: for rec in self:
@@ -1797,6 +1774,7 @@ class MrpProduction(models.Model):
""" """
检查前置条件:制造订单【状态】=“待排程、待加工”,制造订单的【编程状态】=“已编程”。 检查前置条件:制造订单【状态】=“待排程、待加工”,制造订单的【编程状态】=“已编程”。
""" """
print('申请编程')
if len(self) > 1: if len(self) > 1:
raise UserError('仅支持选择单个制造订单进行编程申请,请重新选择') raise UserError('仅支持选择单个制造订单进行编程申请,请重新选择')
for production in self: for production in self:
@@ -1865,7 +1843,6 @@ class sf_programming_record(models.Model):
target_production_id = fields.Char('目标制造单号') target_production_id = fields.Char('目标制造单号')
apply_time = fields.Datetime('申请时间') apply_time = fields.Datetime('申请时间')
send_time = fields.Datetime('下发时间') send_time = fields.Datetime('下发时间')
apply_uid = fields.Many2one('res.users', '申请人', default=lambda self: self.env.user)
class sf_detection_result(models.Model): class sf_detection_result(models.Model):

View File

@@ -1,7 +1,7 @@
import logging import logging
from odoo import fields, models, api from odoo import fields, models, api
from odoo.exceptions import UserError from odoo.exceptions import UserError
# from odoo.tools import str2bool from odoo.tools import str2bool
class ResMrpRoutingWorkcenter(models.Model): class ResMrpRoutingWorkcenter(models.Model):
@@ -25,20 +25,20 @@ class ResMrpRoutingWorkcenter(models.Model):
workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True) workcenter_ids = fields.Many2many('mrp.workcenter', 'rel_workcenter_route', required=True)
bom_id = fields.Many2one('mrp.bom', required=False) bom_id = fields.Many2one('mrp.bom', required=False)
surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺") surface_technics_id = fields.Many2one('sf.production.process', string="表面工艺")
# optional_process_parameters = fields.One2many('sf.production.process.parameter','routing_id',string='可选工艺参数') optional_process_parameters = fields.One2many('sf.production.process.parameter','routing_id',string='可选工艺参数')
reserved_duration = fields.Float('预留时长', default=30, tracking=True) reserved_duration = fields.Float('预留时长', default=30, tracking=True)
is_outsource = fields.Boolean('外协', default=False) is_outsource = fields.Boolean('外协', default=False)
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录') individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录')
# @api.onchange('surface_technics_id') @api.onchange('surface_technics_id')
# def optional_process_parameters_date(self): def optional_process_parameters_date(self):
# for record in self: for record in self:
# if not record.surface_technics_id: if not record.surface_technics_id:
# continue continue
# parameter_ids = self.env['sf.production.process.parameter'].search([ parameter_ids = self.env['sf.production.process.parameter'].search([
# ('process_id', '=', record.surface_technics_id.id), ('process_id', '=', record.surface_technics_id.id),
# ]) ])
# record.optional_process_parameters = parameter_ids.ids record.optional_process_parameters = parameter_ids.ids
# @api.model # @api.model
# def _auto_init(self): # def _auto_init(self):

View File

@@ -21,16 +21,16 @@ class ResWorkcenter(models.Model):
related='equipment_id.production_line_id', store=True) related='equipment_id.production_line_id', store=True)
is_process_outsourcing = fields.Boolean('工艺外协') is_process_outsourcing = fields.Boolean('工艺外协')
users_ids = fields.Many2many("res.users", 'users_workcenter', tracking=True) users_ids = fields.Many2many("res.users", 'users_workcenter', tracking=True)
# @api.constrains('name') @api.constrains('name')
# def _check_unique_name_code(self): def _check_unique_name_code(self):
# for record in self: for record in self:
# # 检查是否已经存在相同的 name 和 code 组合 # 检查是否已经存在相同的 name 和 code 组合
# existing = self.search([ existing = self.search([
# ('name', '=', record.name), ('name', '=', record.name),
# ('id', '!=', record.id) # 排除当前记录 ('id', '!=', record.id) # 排除当前记录
# ]) ])
# if existing: if existing:
# raise ValueError('记录已存在') raise ValueError('记录已存在')
def write(self, vals): def write(self, vals):
if 'users_ids' in vals: if 'users_ids' in vals:
old_users = self.users_ids old_users = self.users_ids

View File

@@ -70,21 +70,21 @@ class ResMrpWorkOrder(models.Model):
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效', delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
tracking=True) tracking=True)
back_button_display = fields.Boolean(default=False, compute='_compute_back_button_display', store=True) back_button_display = fields.Boolean(default=False, compute='_compute_back_button_display', store=True)
# pr_mp_count = fields.Integer('采购申请单数量', compute='_compute_pr_mp_count', store=True) pr_mp_count = fields.Integer('采购申请单数量', compute='_compute_pr_mp_count', store=True)
# @api.depends('state') @api.depends('state')
# def _compute_pr_mp_count(self): def _compute_pr_mp_count(self):
# for item in self: for item in self:
# if not item.is_subcontract: if not item.is_subcontract:
# item.pr_mp_count = 0 item.pr_mp_count = 0
# continue continue
# pr_ids = self.env['purchase.request'].sudo().search( pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', item.production_id.name), ('is_subcontract', '=', 'True'), [('origin', 'like', item.production_id.name), ('is_subcontract', '=', 'True'),
# ('state', '!=', 'rejected')]) ('state', '!=', 'rejected')])
# if pr_ids: if pr_ids:
# item.pr_mp_count = len(pr_ids) item.pr_mp_count = len(pr_ids)
# else: else:
# item.pr_mp_count = 0 item.pr_mp_count = 0
@api.depends('state') @api.depends('state')
def _compute_back_button_display(self): def _compute_back_button_display(self):
@@ -130,14 +130,8 @@ class ResMrpWorkOrder(models.Model):
record.back_button_display = False record.back_button_display = False
else: else:
next_workorder = sorted_workorders[position + 1] next_workorder = sorted_workorders[position + 1]
# 持续获取下一个工单,直到找到一个不是返工的工单 next_state = next_workorder.state
while next_workorder and next_workorder.state == 'rework': if (next_state == 'ready' or (
position += 1
if position + 1 < len(sorted_workorders):
next_workorder = sorted_workorders[position + 1]
else:
next_workorder = None
if next_workorder and (next_workorder.state == 'ready' or (
next_workorder.state == 'waiting' and next_workorder.is_subcontract)) and cur_workorder.state == 'done': next_workorder.state == 'waiting' and next_workorder.is_subcontract)) and cur_workorder.state == 'done':
record.back_button_display = True record.back_button_display = True
else: else:
@@ -227,30 +221,22 @@ class ResMrpWorkOrder(models.Model):
# finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0 # finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0
else: else:
next_workorder = sorted_workorders[position + 1] next_workorder = sorted_workorders[position + 1]
# 持续获取下一个工单,直到找到一个不是返工的工单 next_state = next_workorder.state
while next_workorder and next_workorder.state == 'rework': if next_state not in ['pending', 'waiting', 'ready']:
position += 1 raise UserError('下工序已经开始,无法回退')
if position + 1 < len(sorted_workorders): if next_workorder.is_subcontract:
next_workorder = sorted_workorders[position + 1] next_workorder.picking_ids.write({'state': 'waiting'})
next_workorder.state = 'pending'
self.time_ids.date_end = None
cur_workorder.state = 'progress'
cur_workorder.production_id.state = 'progress'
quality_check = self.env['quality.check'].search(
[('workorder_id', '=', self.id)])
for check_order in quality_check:
if check_order.point_id.is_inspect:
check_order.quality_state = 'waiting'
else: else:
next_workorder = None check_order.quality_state = 'none'
if next_workorder:
next_state = next_workorder.state
if next_state not in ['pending', 'waiting', 'ready']:
raise UserError('下工序已经开始,无法回退')
if next_workorder.is_subcontract:
next_workorder.picking_ids.write({'state': 'waiting'})
next_workorder.state = 'pending'
self.time_ids.date_end = None
cur_workorder.state = 'progress'
cur_workorder.production_id.state = 'progress'
quality_check = self.env['quality.check'].search(
[('workorder_id', '=', self.id)])
for check_order in quality_check:
if check_order.point_id.is_inspect:
check_order.quality_state = 'waiting'
else:
check_order.quality_state = 'none'
def _compute_working_users(self): def _compute_working_users(self):
super()._compute_working_users() super()._compute_working_users()
@@ -454,51 +440,41 @@ class ResMrpWorkOrder(models.Model):
action['context'] = dict(self._context, default_origin=self.name) action['context'] = dict(self._context, default_origin=self.name)
return action return action
@api.depends('state', 'production_id.name')
def _compute_surface_technics_purchase_ids(self): def _compute_surface_technics_purchase_ids(self):
for order in self: for order in self:
if order.routing_type == '表面工艺' and order.state not in ['cancel']: pr_ids = self.env['purchase.request'].sudo().search(
domain = [('purchase_type', '=', 'consignment'), [('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
('origin', 'like', '%' + self.production_id.name + '%'), ('state', '!=', 'rejected')])
('state', '!=', 'cancel')] if pr_ids.purchase_count:
# domain = [('purchase_type', '=', 'consignment'), order.surface_technics_purchase_count = pr_ids.purchase_count
# ('origin', 'like', '%' + self.production_id.name + '%'),
# ('state', '!=', 'cancel')]
purchase = self.env['purchase.order'].search(domain)
order.surface_technics_purchase_count = 0
if not purchase:
order.surface_technics_purchase_count = 0
for po in purchase:
if any(
line.product_id and line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id
for line in po.order_line):
order.surface_technics_purchase_count = 1
else: else:
order.surface_technics_purchase_count = 0 order.surface_technics_purchase_count = 0
# def action_view_pr_mrp_workorder(self): def action_view_pr_mrp_workorder(self):
# """ """
# 采购请求 采购请求
# """ """
# self.ensure_one() self.ensure_one()
# pr_ids = self.env['purchase.request'].sudo().search( pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'), [('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
# ('state', '!=', 'rejected')]) ('state', '!=', 'rejected')])
# action = { action = {
# 'res_model': 'purchase.request', 'res_model': 'purchase.request',
# 'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
# } }
# if len(pr_ids) == 1: if len(pr_ids) == 1:
# action.update({ action.update({
# 'view_mode': 'form', 'view_mode': 'form',
# 'res_id': pr_ids[0].id, 'res_id': pr_ids[0].id,
# }) })
# else: else:
# action.update({ action.update({
# 'name': _("从 %s生成采购请求单", self.name), 'name': _("%s生成采购请求单", self.name),
# 'domain': [('id', 'in', pr_ids)], 'domain': [('id', 'in', pr_ids)],
# 'view_mode': 'tree,form', 'view_mode': 'tree,form',
# }) })
# return action return action
def action_view_surface_technics_purchase(self): def action_view_surface_technics_purchase(self):
self.ensure_one() self.ensure_one()
@@ -516,16 +492,19 @@ 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:
purchase_orders_id = self._get_surface_technics_purchase_ids() pr_ids = self.env['purchase.request'].sudo().search(
result = { [('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
"type": "ir.actions.act_window", ('state', '!=', 'rejected')])
"res_model": "purchase.order", # purchase_orders_id = self._get_surface_technics_purchase_ids()
"res_id": purchase_orders_id.id, # result = {
# "domain": [['id', 'in', self.purchase_id]], # "type": "ir.actions.act_window",
"name": _("Purchase Orders"), # "res_model": "purchase.order",
'view_mode': 'form', # "res_id": purchase_orders_id.id,
} # # "domain": [['id', 'in', self.purchase_id]],
return result # "name": _("Purchase Orders"),
# 'view_mode': 'form',
# }
return pr_ids.action_view_purchase_order()
def _get_surface_technics_purchase_ids(self): def _get_surface_technics_purchase_ids(self):
domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment'), domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment'),
@@ -752,25 +731,21 @@ class ResMrpWorkOrder(models.Model):
# self.workpiece_delivery_ids[0].write({'rfid_code': self.rfid_code}) # self.workpiece_delivery_ids[0].write({'rfid_code': self.rfid_code})
def get_plan_workorder(self, production_line): def get_plan_workorder(self, production_line):
tomorrow = (date.today() + timedelta(days=1)).strftime("%Y-%m-%d") tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d")
tomorrow_start = f"{tomorrow} 00:00:00" tomorrow_start = tomorrow + ' 00:00:00'
tomorrow_end = f"{tomorrow} 23:59:59" tomorrow_end = tomorrow + ' 23:59:59'
logging.info('tomorrow:%s' % tomorrow) logging.info('tomorrow:%s' % tomorrow)
sql = """ sql = """
SELECT * SELECT *
FROM mrp_workorder FROM mrp_workorder
WHERE state!='rework' WHERE state!='rework'
AND (date_planned_start + interval '8 hours') >= %s::timestamp to_char(date_planned_start::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')>= %s
AND (date_planned_finished + interval '8 hours') <= %s::timestamp AND to_char(date_planned_finished::timestamp + '8 hour','YYYY-MM-DD HH:mm:SS')<= %s
""" """
params = [tomorrow_start, tomorrow_end] params = [tomorrow_start, tomorrow_end]
if production_line: if production_line:
line = self.env['sf.production.line'].search(
[('name', '=', production_line)], limit=1)
if not line:
raise ValueError(f"生产线'{production_line}'不存在")
sql += "AND production_line_id = %s" sql += "AND production_line_id = %s"
params.append(line.id) params.append(production_line)
self.env.cr.execute(sql, params) self.env.cr.execute(sql, params)
ids = [t[0] for t in self.env.cr.fetchall()] ids = [t[0] for t in self.env.cr.fetchall()]
return [('id', 'in', ids)] return [('id', 'in', ids)]
@@ -1263,12 +1238,12 @@ class ResMrpWorkOrder(models.Model):
}] }]
return workorders_values_str return workorders_values_str
# def check_lot_exists(self, picking_id, lot_id): def check_lot_exists(self, picking_id, lot_id):
# return bool( return bool(
# picking_id.move_ids.move_line_ids.filtered( picking_id.move_ids.move_line_ids.filtered(
# lambda line: line.lot_id.id == lot_id lambda line: line.lot_id.id == lot_id
# ) )
# ) )
def _process_compute_state(self): def _process_compute_state(self):
sorted_workorders = sorted(self, key=lambda x: x.sequence) sorted_workorders = sorted(self, key=lambda x: x.sequence)
@@ -1301,20 +1276,27 @@ class ResMrpWorkOrder(models.Model):
# for move_line in move.move_line_ids # for move_line in move.move_line_ids
# ) # )
if (workorder.production_id.production_type == '人工线下加工' if (workorder.production_id.production_type == '人工线下加工'
and workorder.production_id.schedule_state == ''): and workorder.production_id.programming_state == '编程'):
# and workorder.production_id.programming_state == '已编程' # and workorder.production_id.programming_state == '已编程'
if workorder.is_subcontract is True: if workorder.is_subcontract is True:
if workorder.production_id.state == 'rework': if workorder.production_id.state == 'rework':
workorder.state = 'waiting' workorder.state = 'waiting'
continue continue
purchase_orders_id = self._get_surface_technics_purchase_ids() purchase_orders_id = self._get_surface_technics_purchase_ids()
if purchase_orders_id.state == 'purchase': purchase_count = 0
for purchase_order in purchase_orders_id:
for purchase_order_line in purchase_order.order_line:
if purchase_order_line.product_id.server_product_process_parameters_id.id == workorder.surface_technics_parameters_id.id:
purchase_count = purchase_order_line.product_qty
if purchase_orders_id.state == 'purchase' and purchase_count>=workorder.production_id.product_qty:
workorder.state = 'ready' workorder.state = 'ready'
# picking_id = workorder.production_id.picking_ids.filtered( picking_id = workorder.production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区') lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
# move_out = picking_id.move_ids move_out = picking_id.move_ids
move_out = workorder.move_subcontract_workorder_ids[1] # move_out = workorder.move_subcontract_workorder_ids[1]
for mo in move_out: for mo in move_out:
if workorder.production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done': if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False}) mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids: if not mo.move_line_ids:
@@ -1330,6 +1312,7 @@ class ResMrpWorkOrder(models.Model):
else: else:
workorder.state = 'ready' workorder.state = 'ready'
continue 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'
or workorder.production_id.schedule_state != '已排' or workorder.production_id.schedule_state != '已排'
@@ -1345,19 +1328,18 @@ class ResMrpWorkOrder(models.Model):
if workorder.is_subcontract is False: if workorder.is_subcontract is False:
workorder.state = 'ready' workorder.state = 'ready'
else: else:
if len(workorder.production_id.picking_ids.filtered( if workorder.production_id.programming_state == '已编程':
lambda w: w.state not in ['done',
'cancel'])) == 0 and workorder.production_id.programming_state == '已编程':
purchase_orders_id = self._get_surface_technics_purchase_ids() purchase_orders_id = self._get_surface_technics_purchase_ids()
if purchase_orders_id: if purchase_orders_id:
if purchase_orders_id.state == 'purchase': if purchase_orders_id.state == 'purchase':
workorder.state = 'ready' workorder.state = 'ready'
move_out = workorder.move_subcontract_workorder_ids[1] picking_id = workorder.production_id.picking_ids.filtered(
# picking_id = workorder.production_id.picking_ids.filtered( lambda
# lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
# wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区') move_out = picking_id.move_ids
# move_out = picking_id.move_ids
for mo in move_out: for mo in move_out:
if workorder.production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done': if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False}) mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids: if not mo.move_line_ids:
@@ -1406,7 +1388,16 @@ class ResMrpWorkOrder(models.Model):
boolean = True boolean = True
if not boolean: if not boolean:
raise UserError('制造订单【%s】缺少组件的序列号信息!' % self.production_id.name) raise UserError('制造订单【%s】缺少组件的序列号信息!' % self.production_id.name)
self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name self.pro_code = False # 默认值
if (
self.production_id
and self.production_id.move_raw_ids
and len(self.production_id.move_raw_ids) > 0
and self.production_id.move_raw_ids[0].move_line_ids
and len(self.production_id.move_raw_ids[0].move_line_ids) > 0
and self.production_id.move_raw_ids[0].move_line_ids[0].lot_id
):
self.pro_code = self.production_id.move_raw_ids[0].move_line_ids[0].lot_id.name
# cnc校验 # cnc校验
if self.production_id.production_type == '自动化产线加工': if self.production_id.production_type == '自动化产线加工':
cnc_workorder = self.search( cnc_workorder = self.search(
@@ -1430,10 +1421,9 @@ 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.move_subcontract_workorder_ids[1] picking_id = self.production_id.picking_ids.filtered(
# picking_id = self.production_id.picking_ids.filtered( lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
# lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区') move_out = picking_id.move_ids
# move_out = picking_id.move_ids
# move_out = self.move_subcontract_workorder_ids[1] # move_out = self.move_subcontract_workorder_ids[1]
# move_out = self.env['stock.move'].search( # move_out = self.env['stock.move'].search(
# [('location_id', '=', self.env['stock.location'].search( # [('location_id', '=', self.env['stock.location'].search(
@@ -1442,6 +1432,8 @@ class ResMrpWorkOrder(models.Model):
# [('barcode', 'ilike', 'VL-SPOC')]).id), # [('barcode', 'ilike', 'VL-SPOC')]).id),
# ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])]) # ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
for mo in move_out: for mo in move_out:
if self.production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
continue
if mo.state != 'done': if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False}) mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids: if not mo.move_line_ids:
@@ -1574,7 +1566,8 @@ class ResMrpWorkOrder(models.Model):
lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence') lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
if self == subcontract_workorders[-1]: if self == subcontract_workorders[-1]:
# 给下一个库存移动就绪 # 给下一个库存移动就绪
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done() if self.move_subcontract_workorder_ids:
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
# self.production_id.button_mark_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
@@ -1600,17 +1593,25 @@ class ResMrpWorkOrder(models.Model):
len(done_workorder) == len( len(done_workorder) == len(
record.production_id.workorder_ids.filtered(lambda wo: wo.state != 'cancel'))): record.production_id.workorder_ids.filtered(lambda wo: wo.state != 'cancel'))):
is_production_id = True is_production_id = True
if record.routing_type in ['解除装夹'] or (
record.is_rework is True and record.routing_type in ['装夹预调']):
for workorder in record.production_id.workorder_ids:
if workorder.processing_panel == record.processing_panel:
rfid_code = workorder.rfid_code
if record.is_rework is not True:
workorder.write({'rfid_code_old': rfid_code, 'rfid_code': False})
elif workorder.routing_type != '装夹预调' and workorder.state != 'rework':
workorder.write({'rfid_code_old': False, 'rfid_code': False})
elif workorder.routing_type == '装夹预调' and workorder.state != 'rework':
workorder.write({'rfid_code_old': rfid_code, 'rfid_code': False})
self.env['stock.lot'].sudo().search([('rfid', '=', rfid_code)]).write(
{'tool_material_status': '可用'})
if workorder.rfid_code:
raise ValidationError(f'{workorder.name}】工单解绑失败,请重新点击完成按钮!!!')
# workorder.rfid_code_old = rfid_code
# workorder.rfid_code = False
logging.info('workorder.rfid_code:%s' % workorder.rfid_code)
if record.routing_type in ['解除装夹']:
rfid_code = record.rfid_code
work_ids = record.production_id.workorder_ids.filtered(
lambda wo: wo.processing_panel == record.processing_panel and wo.state != 'rework')
work_ids.write({'rfid_code_old': rfid_code, 'rfid_code': False})
self.env['stock.lot'].sudo().search([('rfid', '=', rfid_code)]).write(
{'tool_material_status': '可用'})
if any(wo.rfid_code for wo in work_ids):
raise ValidationError(f'{record.name}】工单解绑失败,请重新点击完成按钮!!!')
logging.info('work_ids.rfid_code:%s' % [wo.rfid_code for wo in work_ids])
if is_production_id is True: if is_production_id is True:
logging.info('product_qty:%s' % record.production_id.product_qty) logging.info('product_qty:%s' % record.production_id.product_qty)
for move_raw_id in record.production_id.move_raw_ids: for move_raw_id in record.production_id.move_raw_ids:

View File

@@ -795,7 +795,7 @@ class ResProductMo(models.Model):
for record in self: for record in self:
if record.categ_id.name == '坯料': if record.categ_id.name == '坯料':
product_name = '' product_name = ''
match = re.search(r'(S\d{5}-\d+)', record.name) match = re.search(r'(S\d{5}-\d)', record.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)

View File

@@ -59,83 +59,85 @@ class PurchaseOrder(models.Model):
production_id = self.env['mrp.production'].search([('origin', 'in', origins)]) production_id = self.env['mrp.production'].search([('origin', 'in', origins)])
purchase.production_count = len(production_id) purchase.production_count = len(production_id)
# def process_replenish(self,production,total_qty): def process_replenish(self,production,total_qty):
# record = self record = self
# bom_line_id = production.bom_id.bom_line_ids bom_line_id = production.bom_id.bom_line_ids
# replenish = self.env['stock.warehouse.orderpoint'].search([ replenish = self.env['stock.warehouse.orderpoint'].search([
# ('product_id', '=', bom_line_id.product_id.id), ('product_id', '=', bom_line_id.product_id.id),
# ( (
# 'location_id', '=', self.env.ref('sf_stock.stock_location_outsourcing_material_receiving_area').id), 'location_id', '=', self.env.ref('sf_stock.stock_location_outsourcing_material_receiving_area').id),
# # ('state', 'in', ['draft', 'confirmed']) # ('state', 'in', ['draft', 'confirmed'])
# ], limit=1) ], limit=1)
# if not replenish: if not replenish:
# replenish_model = self.env['stock.warehouse.orderpoint'] replenish_model = self.env['stock.warehouse.orderpoint']
# replenish = replenish_model.create({ replenish = replenish_model.create({
# 'product_id': bom_line_id.product_id.id, 'product_id': bom_line_id.product_id.id,
# 'location_id': self.env.ref( 'location_id': self.env.ref(
# 'sf_stock.stock_location_outsourcing_material_receiving_area').id, 'sf_stock.stock_location_outsourcing_material_receiving_area').id,
# 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id, 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
# 'group_id': record.group_id.id, 'group_id': record.group_id.id,
# 'qty_to_order': total_qty, 'qty_to_order': total_qty,
# 'origin': record.name, 'origin': record.name,
# }) })
# else: else:
# replenish.write({ replenish.write({
# 'product_id': bom_line_id.product_id.id, 'product_id': bom_line_id.product_id.id,
# 'location_id': self.env.ref( 'location_id': self.env.ref(
# 'sf_stock.stock_location_outsourcing_material_receiving_area').id, 'sf_stock.stock_location_outsourcing_material_receiving_area').id,
# 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id, 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
# 'group_id': record.group_id.id, 'group_id': record.group_id.id,
# 'qty_to_order': total_qty + replenish.qty_to_order, 'qty_to_order': total_qty + replenish.qty_to_order,
# 'origin': record.name + ',' + replenish.origin, 'origin': record.name + ',' + replenish.origin,
# }) })
# replenish.action_replenish() replenish.action_replenish()
# def outsourcing_service_replenishment(self): def outsourcing_service_replenishment(self):
# record = self record = self
# if record.purchase_type != 'consignment': if record.purchase_type != 'consignment':
# return return
# grouped_lines = {} grouped_lines = {}
# for line in record.order_line: for line in record.order_line:
# if line.related_product.id not in grouped_lines: if line.related_product.id not in grouped_lines:
# grouped_lines[line.related_product.id] = [] grouped_lines[line.related_product.id] = []
# grouped_lines[line.related_product.id].append(line) grouped_lines[line.related_product.id].append(line)
# for product_id,lines in grouped_lines.items(): for product_id,lines in grouped_lines.items():
# production = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1) production = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
# if not production: if not production:
# continue continue
# total_qty = sum(line.product_qty for line in lines) total_qty = sum(line.product_qty for line in lines)
# record.process_replenish(production,total_qty) record.process_replenish(production,total_qty)
# for product_id,lines in grouped_lines.items(): for product_id,lines in grouped_lines.items():
# productions = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1) productions = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
# if not productions: if not productions:
# continue continue
# # production.bom_id.bom_line_ids.product_id # production.bom_id.bom_line_ids.product_id
# location_id = self.env['stock.location'].search([('name', '=', '制造前')]) location_id = self.env['stock.location'].search([('name', '=', '制造前')])
# quants = self.env['stock.quant'].search([ quants = self.env['stock.quant'].search([
# ('product_id', '=', productions.bom_id.bom_line_ids.product_id.id), ('product_id', '=', productions.bom_id.bom_line_ids.product_id.id),
# ('location_id', '=', location_id.id) ('location_id', '=', location_id.id)
# ]) ])
# total_qty = sum(quants.mapped('quantity')) # 计算该位置的总库存量 total_qty = sum(quants.mapped('quantity')) # 计算该位置的总库存量
# is_available = total_qty > 0 is_available = total_qty > 0
# if not is_available: if not is_available:
# raise UserError('请先完成坯料入库') raise UserError('请先完成坯料入库')
# for production_id in productions: for production_id in productions:
# work_ids = production_id.workorder_ids.filtered( work_ids = production_id.workorder_ids.filtered(
# lambda wk: wk.state not in ['done', 'rework', 'cancel']) lambda wk: wk.state not in ['done', 'rework', 'cancel'])
# if not work_ids: if not work_ids:
# continue continue
# min_sequence_wk = min(work_ids, key=lambda wk: wk.sequence) min_sequence_wk = min(work_ids, key=lambda wk: wk.sequence)
# if min_sequence_wk.is_subcontract: if min_sequence_wk.is_subcontract and min_sequence_wk.state == 'ready':
# picking_id = production_id.picking_ids.filtered( picking_id = production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区') lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
# move_out = picking_id.move_ids move_out = picking_id.move_ids
# for mo in move_out: for mo in move_out:
# if mo.state != 'done': if production_id.bom_id.bom_line_ids.product_id.id != mo.product_id.id:
# mo.write({'state': 'assigned', 'production_id': False}) continue
# if not mo.move_line_ids: if mo.state != 'done':
# self.env['stock.move.line'].create( mo.write({'state': 'assigned', 'production_id': False})
# mo.get_move_line(production_id, min_sequence_wk)) if not mo.move_line_ids:
self.env['stock.move.line'].create(
mo.get_move_line(production_id, min_sequence_wk))
# product = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1) # product = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
# match = re.search(r'(S\d{5}-\d)',product.name) # match = re.search(r'(S\d{5}-\d)',product.name)
# pass # pass
@@ -146,12 +148,14 @@ class PurchaseOrder(models.Model):
raise UserError('请对【产品】中的【数量】进行输入') raise UserError('请对【产品】中的【数量】进行输入')
if line.price_unit <= 0: if line.price_unit <= 0:
raise UserError('请对【产品】中的【单价】进行输入') raise UserError('请对【产品】中的【单价】进行输入')
# record.outsourcing_service_replenishment() record.outsourcing_service_replenishment()
res = super(PurchaseOrder, self).button_confirm() res = super(PurchaseOrder, self).button_confirm()
for line in self.order_line: for line in self.order_line:
# 将产品不追踪序列号的行项目设置qty_done # 将产品不追踪序列号的行项目设置qty_done
if not line.move_ids:
continue
if line.move_ids and line.move_ids[0].product_id.tracking == 'none': if line.move_ids and line.move_ids[0].product_id.tracking == 'none':
line.move_ids[0].quantity_done = line.move_ids[0].product_qty line.move_ids[0].quantity_done = line.move_ids[0].product_qty
return res return res
@@ -208,7 +212,7 @@ class PurchaseOrderLine(models.Model):
continue continue
if record.product_id.categ_id.name == '坯料': if record.product_id.categ_id.name == '坯料':
product_name = '' product_name = ''
match = re.search(r'(S\d{5}-\d+)', record.product_id.name) match = re.search(r'(S\d{5}-\d)', record.product_id.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)
@@ -224,6 +228,24 @@ class PurchaseOrderLine(models.Model):
) )
record.part_number = filtered_order_line.product_id.part_number record.part_number = filtered_order_line.product_id.part_number
record.part_name = filtered_order_line.product_id.part_name record.part_name = filtered_order_line.product_id.part_name
elif record.order_id.purchase_type == 'consignment':
product_name = ''
match = re.search(r'(S\d{5}-\d)', record.related_product.name)
# 如果匹配成功,提取结果
if match:
product_name = match.group(0)
sale_order_name = ''
match_sale = re.search(r'S(\d+)', record.related_product.name)
if match_sale:
sale_order_name = match_sale.group(0)
sale_order = self.env['sale.order'].sudo().search(
[('name', '=', sale_order_name)])
if sale_order:
filtered_order_line = sale_order.order_line.filtered(
lambda order_line: re.search(f'{product_name}$', order_line.product_id.name)
)
record.part_number = filtered_order_line.product_id.part_number
record.part_name = filtered_order_line.product_id.part_name
else: else:
record.part_number = record.product_id.part_number record.part_number = record.product_id.part_number
record.part_name = record.product_id.part_name record.part_name = record.product_id.part_name

View File

@@ -1,30 +1,30 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# import base64 import base64
# import datetime import datetime
# import logging import logging
# import json import json
# import os import os
# import re import re
# import traceback import traceback
# from operator import itemgetter from operator import itemgetter
# 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.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 PurchaseRequestLine(models.Model): class PurchaseRequestLine(models.Model):
# _inherit = 'purchase.request' _inherit = 'purchase.request'
# is_subcontract = fields.Boolean(string='是否外协',default=False) is_subcontract = fields.Boolean(string='是否外协',default=False)
# class PurchaseRequestLine(models.Model): class PurchaseRequestLine(models.Model):
# _inherit = 'purchase.request.line' _inherit = 'purchase.request.line'
# is_subcontract = fields.Boolean(string='是否外协') is_subcontract = fields.Boolean(string='是否外协')
# class PurchaseRequest(models.Model): class PurchaseRequest(models.Model):
# _inherit = 'purchase.request' _inherit = 'purchase.request'
# bom_id = fields.Many2one('mrp.bom') bom_id = fields.Many2one('mrp.bom')

View File

@@ -56,7 +56,7 @@ class SaleOrder(models.Model):
'jikimo_sale_multiple_supply_methods.product_template_manual_processing').sudo() 'jikimo_sale_multiple_supply_methods.product_template_manual_processing').sudo()
# 复制成品模板上的属性 # 复制成品模板上的属性
line.product_id.product_tmpl_id.copy_template(product_template_id) line.product_id.copy_template(product_template_id)
# 将模板上的single_manufacturing属性复制到成品上 # 将模板上的single_manufacturing属性复制到成品上
# line.product_id.single_manufacturing = product_template_id.single_manufacturing # line.product_id.single_manufacturing = product_template_id.single_manufacturing
# line.product_id.tracking = product_template_id.tracking # line.product_id.tracking = product_template_id.tracking
@@ -76,7 +76,7 @@ class SaleOrder(models.Model):
'embryo_redundancy_id': line.embryo_redundancy_id, 'embryo_redundancy_id': line.embryo_redundancy_id,
} }
product_name = '' product_name = ''
match = re.search(r'(S\d{5}-\d+)', product.name) match = re.search(r'(S\d{5}-\d*)', product.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)
@@ -190,30 +190,7 @@ class SaleOrder(models.Model):
'target': 'new', 'target': 'new',
'res_id': wizard.id, 'res_id': wizard.id,
} }
def create_sale_documents(self, contract_file_name, contract_file):
# 创建ir.attachment记录
attachment = self.env['ir.attachment'].sudo().create({
'name': contract_file_name,
'type': 'binary',
'datas': contract_file,
'res_model': 'sale.order',
})
# 获取默认的文档文件夹
workspace = self.env.ref('sf_sale.documents_sales_contracts_folder_1').id
# 创建 documents.document 记录
document = self.env['documents.document'].sudo().create({
'name': contract_file_name,
'attachment_id': attachment.id,
'folder_id': workspace,
'res_model': 'sale.order',
'res_id': self.id,
})
self.write({
'contract_document_id': document.id
})
class SaleOrderLine(models.Model): class SaleOrderLine(models.Model):
_inherit = 'sale.order.line' _inherit = 'sale.order.line'

View File

@@ -7,74 +7,73 @@ from odoo.exceptions import UserError, ValidationError
class SfProductionProcessParameter(models.Model): class SfProductionProcessParameter(models.Model):
_inherit = 'sf.production.process.parameter' _inherit = 'sf.production.process.parameter'
# service_products = fields.Many2one( service_products = fields.Many2one(
# 'product.template', 'product.template',
# string='外协服务产品',compute='_compute_service_products',inverse='_inverse_service_products', string='外协服务产品',compute='_compute_service_products',inverse='_inverse_service_products',
# store=True store=True
# ) )
# outsourced_service_products = fields.One2many( outsourced_service_products = fields.One2many(
# 'product.template', # 另一个模型的名称 'product.template', # 另一个模型的名称
# 'server_product_process_parameters_id', # 对应的 Many2one 字段名称 'server_product_process_parameters_id', # 对应的 Many2one 字段名称
# string='外协服务产品' string='外协服务产品'
# ) )
# is_product_button = fields.Boolean(compute='_compute_is_product_button',default=False) is_product_button = fields.Boolean(compute='_compute_is_product_button',default=False)
# is_delete_button = fields.Boolean(compute='_compute_is_delete_button', default=False) is_delete_button = fields.Boolean(compute='_compute_is_delete_button', default=False)
# routing_id = fields.Many2one('mrp.routing.workcenter', string="工序") routing_id = fields.Many2one('mrp.routing.workcenter', string="工序")
def _inverse_service_products(self):
for record in self:
if record.service_products:
# 确保关联关系正确
record.outsourced_service_products = record.service_products.ids if record.service_products else False
else:
record.outsourced_service_products = False
@api.depends('outsourced_service_products')
def _compute_service_products(self):
for record in self:
# 假设取第一条作为主明细
record.service_products = record.outsourced_service_products[0].id if record.outsourced_service_products else False
# @api.depends('outsourced_service_products') def name_get(self):
# def _compute_service_products(self): result = []
# for record in self: for record in self:
# # 假设取第一条作为主明细 name = f"{record.process_id.name} - {record.name}" # 自定义显示格式
# record.service_products = record.outsourced_service_products.ids if record.outsourced_service_products else False result.append((record.id, name))
return result
@api.constrains('outsourced_service_products')
def _validate_partner_limit(self):
for record in self:
if len(record.outsourced_service_products) > 1:
raise ValidationError("工艺参数不能与多个产品关联")
# def _inverse_service_products(self): @api.onchange('outsourced_service_products')
# for record in self: def _onchange_validate_partner_limit(self):
# if record.service_products: for record in self:
# # 确保关联关系正确 if len(record.outsourced_service_products) > 1:
# record.outsourced_service_products = record.service_products.ids if record.service_products else False raise ValidationError("工艺参数不能与多个产品关联")
# else: @api.depends('outsourced_service_products')
# record.outsourced_service_products = False def _compute_is_product_button(self):
# def name_get(self): for record in self:
# result = [] if record.outsourced_service_products:
# for record in self: record.is_product_button = True
# name = f"{record.process_id.name} - {record.name}" # 自定义显示格式 else:
# result.append((record.id, name)) record.is_product_button = False
# return result
# @api.constrains('outsourced_service_products')
# def _validate_partner_limit(self):
# for record in self:
# if len(record.outsourced_service_products) > 1:
# raise ValidationError("工艺参数不能与多个产品关联")
# @api.onchange('outsourced_service_products') def has_wksp_prefix(self):
# def _onchange_validate_partner_limit(self): """
# for record in self: 判断字符串是否以WKSP开头不区分大小写
# if len(record.outsourced_service_products) > 1: :param text: 要检查的字符串
# raise ValidationError("工艺参数不能与多个产品关联") :return: True/False
# @api.depends('outsourced_service_products') """
# def _compute_is_product_button(self): return self.code.upper().startswith('101'+self.routing_id.code)
# for record in self: @api.depends('outsourced_service_products','code')
# if record.outsourced_service_products: def _compute_is_delete_button(self):
# record.is_product_button = True for record in self:
# else: if record.outsourced_service_products and record.has_wksp_prefix():
# record.is_product_button = False record.is_delete_button = False
elif record.outsourced_service_products:
# def has_wksp_prefix(self): record.is_delete_button = True
# """ else:
# 判断字符串是否以WKSP开头不区分大小写 record.is_delete_button = True
# :param text: 要检查的字符串
# :return: True/False
# """
# return self.code.upper().startswith('101'+self.routing_id.code)
# @api.depends('outsourced_service_products','code')
# def _compute_is_delete_button(self):
# for record in self:
# if record.outsourced_service_products and record.has_wksp_prefix():
# record.is_delete_button = False
# elif record.outsourced_service_products:
# record.is_delete_button = True
# else:
# record.is_delete_button = True
@api.model @api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None): def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('route_id'): if self._context.get('route_id'):
@@ -90,19 +89,19 @@ class SfProductionProcessParameter(models.Model):
return self._search(domain, limit=limit, access_rights_uid=name_get_uid) return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
return super()._name_search(name, args, operator, limit, name_get_uid) return super()._name_search(name, args, operator, limit, name_get_uid)
# def action_create_service_product(self): def action_create_service_product(self):
# if self.id: # 如果是已存在的记录 if self.id: # 如果是已存在的记录
# self.write({}) # 空写入会触发保存 self.write({}) # 空写入会触发保存
# else: # 如果是新记录 else: # 如果是新记录
# self = self.create(self._convert_to_write(self.read()[0])) self = self.create(self._convert_to_write(self.read()[0]))
# return { return {
# 'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
# 'name': '向导名称', 'name': '向导名称',
# 'res_model': 'product.creation.wizard', 'res_model': 'product.creation.wizard',
# 'view_mode': 'form', 'view_mode': 'form',
# 'target': 'new', 'target': 'new',
# 'context': {'default_process_parameter_id': self.id}, # 传递当前记录ID 'context': {'default_process_parameter_id': self.id}, # 传递当前记录ID
# } }
# #
# return { # return {
# 'name': '创建服务产品', # 'name': '创建服务产品',
@@ -116,6 +115,6 @@ class SfProductionProcessParameter(models.Model):
# }, # },
# } # }
# def action_hide_service_products(self): def action_hide_service_products(self):
# # self.outsourced_service_products.active = False # self.outsourced_service_products.active = False
# self.active = False self.active = False

View File

@@ -564,13 +564,6 @@ class StockPicking(models.Model):
part_numbers = fields.Char(string="零件图号", compute='_compute_part_info', store=True, index=True) part_numbers = fields.Char(string="零件图号", compute='_compute_part_info', store=True, index=True)
part_names = fields.Char(string="零件名称", compute='_compute_part_info', store=True, index=True) part_names = fields.Char(string="零件名称", compute='_compute_part_info', store=True, index=True)
model_id = fields.Char('模型ID', compute='_compute_model_id', store=True, index=True)
@api.depends('move_ids_without_package.model_id')
def _compute_model_id(self):
for picking in self:
model_id = picking.move_ids_without_package.mapped('model_id')
picking.model_id = ','.join(filter(None, model_id))
@api.depends('move_ids_without_package.part_number', 'move_ids_without_package.part_name') @api.depends('move_ids_without_package.part_number', 'move_ids_without_package.part_name')
def _compute_part_info(self): def _compute_part_info(self):
@@ -638,84 +631,62 @@ class StockPicking(models.Model):
move.action_clear_lines_show_details() move.action_clear_lines_show_details()
move.action_show_details() move.action_show_details()
res = super().button_validate() res = super().button_validate()
# lot_ids = None lot_ids = None
# product_ids = self.move_ids.mapped('product_id') product_ids = self.move_ids.mapped('product_id')
# if not self.move_ids[0].product_id.single_manufacturing and self.move_ids[0].product_id.tracking == 'none': if not self.move_ids[0].product_id.single_manufacturing and self.move_ids[0].product_id.tracking == 'none':
# lot_ids = self.move_ids.move_line_ids.mapped('lot_id') lot_ids = self.move_ids.move_line_ids.mapped('lot_id')
# production_ids = self.sale_order_id.mrp_production_ids if self.sale_order_id else self.env['mrp.production'] production_ids = self.sale_order_id.mrp_production_ids if self.sale_order_id else self.env['mrp.production']
# if res and self.location_id.name == '外协收料区' and self.location_dest_id.name == '制造前': if res and self.location_id.name == '外协收料区' and self.location_dest_id.name == '制造前':
# # 如果是最后一张外协入库单,则设置库存位置的预留数量
# for production_id in production_ids:
# if lot_ids:
# lot_id = production_id.move_raw_ids.move_line_ids.lot_id
# # picking_ids = production_id.picking_ids.filtered(
# # lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
# if lot_id in lot_ids:
# workorder_id = production_id.workorder_ids.filtered(
# lambda a: a.state == 'progress' and a.is_subcontract)
# if not workorder_id:
# continue
# workorder_id.button_finish()
# else:
# workorder_id = production_id.workorder_ids.filtered(lambda a: a.state == 'progress' and a.is_subcontract)
# if not workorder_id:
# continue
# workorder_id.button_finish()
# # lot_id = workorder.production_id.move_raw_ids.move_line_ids.lot_id
# # picking_ids = workorder.production_id.picking_ids.filtered(
# # lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
# # if move_in:
# # workorder = move_in.subcontract_workorder_id
# # workorders = workorder.production_id.workorder_ids
# # subcontract_workorders = workorders.filtered(
# # lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
# # # if workorder == subcontract_workorders[-1]:
# # # self.env['stock.quant']._update_reserved_quantity(
# # # move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
# # # lot_id=move_in.move_line_ids.lot_id,
# # # package_id=False, owner_id=False, strict=False
# # # )
# # workorder.button_finish()
# if res and self.location_id.name == '制造前' and self.location_dest_id.name == '外协加工区':
# for production_id in production_ids:
# if lot_ids:
# lot_id = production_id.move_raw_ids.move_line_ids.lot_id
# # picking_ids = production_id.picking_ids.filtered(
# # lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
# if lot_id in lot_ids:
# workorder_id = production_id.workorder_ids.filtered(
# lambda a: a.state == 'progress' and a.is_subcontract)
# if not workorder_id:
# continue
# workorder_id.button_finish()
# else:
# workorder_id = production_id.workorder_ids.filtered(lambda a: a.state == 'ready' and a.is_subcontract)
# if not workorder_id:
# continue
# workorder_id.button_start()
picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
if res is True and self.picking_type_id.id == picking_type_in:
# 如果是最后一张外协入库单,则设置库存位置的预留数量 # 如果是最后一张外协入库单,则设置库存位置的预留数量
move_in = self.move_ids for production_id in production_ids:
if move_in: if lot_ids:
workorder = move_in.subcontract_workorder_id lot_id = production_id.move_raw_ids.move_line_ids.lot_id
workorders = workorder.production_id.workorder_ids # picking_ids = production_id.picking_ids.filtered(
subcontract_workorders = workorders.filtered( # lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence') if lot_id in lot_ids:
# if workorder == subcontract_workorders[-1]: workorder_id = production_id.workorder_ids.filtered(
# self.env['stock.quant']._update_reserved_quantity( lambda a: a.state == 'progress' and a.is_subcontract)
# move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty, if not workorder_id:
# lot_id=move_in.move_line_ids.lot_id, continue
# package_id=False, owner_id=False, strict=False workorder_id.button_finish()
# ) else:
workorder.button_finish() workorder_id = production_id.workorder_ids.filtered(lambda a: a.state == 'progress' and a.is_subcontract)
picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id if not workorder_id:
if res and self.picking_type_id.id == picking_type_out: continue
move_out = self.move_ids workorder_id.button_finish()
if move_out: # lot_id = workorder.production_id.move_raw_ids.move_line_ids.lot_id
workorder = move_out.subcontract_workorder_id # picking_ids = workorder.production_id.picking_ids.filtered(
workorder.button_start() # lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
# if move_in:
# workorder = move_in.subcontract_workorder_id
# workorders = workorder.production_id.workorder_ids
# subcontract_workorders = workorders.filtered(
# lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
# # if workorder == subcontract_workorders[-1]:
# # self.env['stock.quant']._update_reserved_quantity(
# # move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
# # lot_id=move_in.move_line_ids.lot_id,
# # package_id=False, owner_id=False, strict=False
# # )
# workorder.button_finish()
if res and self.location_id.name == '制造前' and self.location_dest_id.name == '外协加工区':
for production_id in production_ids:
if lot_ids:
lot_id = production_id.move_raw_ids.move_line_ids.lot_id
# picking_ids = production_id.picking_ids.filtered(
# lambda wk: wk.location_id.name == '外协收料区' and wk.location_dest_id.name == '制造前')
if lot_id in lot_ids:
workorder_id = production_id.workorder_ids.filtered(
lambda a: a.state == 'progress' and a.is_subcontract)
if not workorder_id:
continue
workorder_id.button_finish()
else:
workorder_id = production_id.workorder_ids.filtered(lambda a: a.state == 'ready' and a.is_subcontract)
if not workorder_id:
continue
workorder_id.button_start()
if self.location_id.name == '成品存货区' and self.location_dest_id.name == '客户': if self.location_id.name == '成品存货区' and self.location_dest_id.name == '客户':
sale_id = self.env['sale.order'].sudo().search( sale_id = self.env['sale.order'].sudo().search(
[('name', '=', self.origin)]) [('name', '=', self.origin)])
@@ -846,7 +817,6 @@ class ReStockMove(models.Model):
materiel_height = fields.Float(string='物料高度', digits=(16, 4)) materiel_height = fields.Float(string='物料高度', digits=(16, 4))
part_number = fields.Char(string='零件图号', compute='_compute_part_info', store=True) part_number = fields.Char(string='零件图号', compute='_compute_part_info', store=True)
part_name = fields.Char(string='零件名称', compute='_compute_part_info', store=True) part_name = fields.Char(string='零件名称', compute='_compute_part_info', store=True)
model_id = fields.Char('模型ID', related='product_id.model_id')
@api.depends('product_id') @api.depends('product_id')
def _compute_part_info(self): def _compute_part_info(self):
@@ -857,7 +827,7 @@ class ReStockMove(models.Model):
move.part_name = move.product_id.part_name move.part_name = move.product_id.part_name
elif move.product_id.categ_id.type == '坯料': elif move.product_id.categ_id.type == '坯料':
product_name = '' product_name = ''
match = re.search(r'(S\d{5}-\d+)', move.product_id.name) match = re.search(r'(S\d{5}-\d)', move.product_id.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)
@@ -889,7 +859,7 @@ class ReStockMove(models.Model):
continue continue
product_name = '' product_name = ''
logging.info('制造订单的产品 %s', production_id.product_id.name) logging.info('制造订单的产品 %s', production_id.product_id.name)
match = re.search(r'(S\d{5}-\d+)', production_id.product_id.name) match = re.search(r'(S\d{5}-\d)', production_id.product_id.name)
# 如果匹配成功,提取结果 # 如果匹配成功,提取结果
if match: if match:
product_name = match.group(0) product_name = match.group(0)
@@ -960,6 +930,8 @@ class ReStockMove(models.Model):
} }
def get_move_line(self, production_id, sorted_workorders): def get_move_line(self, production_id, sorted_workorders):
# if not self.move_ids[0].product_id.single_manufacturing and self.move_ids[0].product_id.tracking == 'none':
qty = production_id.product_qty
return { return {
'move_id': self.id, 'move_id': self.id,
'product_id': self.product_id.id, 'product_id': self.product_id.id,
@@ -967,7 +939,7 @@ class ReStockMove(models.Model):
'location_id': self.picking_id.location_id.id, 'location_id': self.picking_id.location_id.id,
'location_dest_id': self.picking_id.location_dest_id.id, 'location_dest_id': self.picking_id.location_dest_id.id,
'picking_id': self.picking_id.id, 'picking_id': self.picking_id.id,
'reserved_uom_qty': self.product_uom_qty, 'reserved_uom_qty': qty,
'lot_id': production_id.move_line_raw_ids.lot_id.id, 'lot_id': production_id.move_line_raw_ids.lot_id.id,
'company_id': self.env.company.id, 'company_id': self.env.company.id,
# 'workorder_id': '' if not sorted_workorders else sorted_workorders.id, # 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,

View File

@@ -383,7 +383,7 @@
<field name="process_parameters_id" <field name="process_parameters_id"
attrs="{'readonly': [('id', '!=', False),('routing_tag', '=', 'standard')]}" attrs="{'readonly': [('id', '!=', False),('routing_tag', '=', 'standard')]}"
string="参数" context="{'route_id':route_id,'production_id': production_id}" string="参数" context="{'route_id':route_id,'production_id': production_id}"
options="{'no_create': True}"/> options="{'no_create': True}" domain="[('routing_id', '=', 'route_id')]"/>
<field name="panel" readonly="1"/> <field name="panel" readonly="1"/>
<field name="routing_tag" readonly="1" widget="badge" <field name="routing_tag" readonly="1" widget="badge"
decoration-success="routing_tag == 'standard'" decoration-success="routing_tag == 'standard'"
@@ -427,7 +427,6 @@
<field name="programming_method"/> <field name="programming_method"/>
<field name="current_programming_count"/> <field name="current_programming_count"/>
<field name="target_production_id"/> <field name="target_production_id"/>
<field name="apply_uid"/>
<field name="apply_time"/> <field name="apply_time"/>
<field name="send_time"/> <field name="send_time"/>
</tree> </tree>
@@ -603,7 +602,6 @@
<field name="part_number"/> <field name="part_number"/>
<field name="sale_order_id"/> <field name="sale_order_id"/>
<field name="deadline_of_delivery" icon="fa-calendar" enable_counters="1" filter_domain="[('deadline_of_delivery', 'ilike', self)]"/> <field name="deadline_of_delivery" icon="fa-calendar" enable_counters="1" filter_domain="[('deadline_of_delivery', 'ilike', self)]"/>
<field name="model_id"/>
</xpath> </xpath>
<xpath expr="//field[@name='product_variant_attributes']" position="attributes"> <xpath expr="//field[@name='product_variant_attributes']" position="attributes">
<attribute name="invisible">1</attribute> <attribute name="invisible">1</attribute>

View File

@@ -22,7 +22,7 @@
<field name="is_repeat"/> <field name="is_repeat"/>
<field name="reserved_duration"/> <field name="reserved_duration"/>
</field> </field>
<!-- <xpath expr="//notebook/page[1]" position="before"> <xpath expr="//notebook/page[1]" position="before">
<page string="可选工艺参数"> <page string="可选工艺参数">
<field name="optional_process_parameters"> <field name="optional_process_parameters">
<tree editable="bottom"> <tree editable="bottom">
@@ -30,9 +30,9 @@
<field name="is_delete_button" invisible="1"/> <field name="is_delete_button" invisible="1"/>
<field name="code" attrs="{'readonly': True}"/> <field name="code" attrs="{'readonly': True}"/>
<field name="name" required="1"/> <field name="name" required="1"/>
<field name="service_products" domain="[('detailed_type', '=', 'service'),('server_product_process_parameters_id', '=', False)]"/> --> <field name="service_products" domain="[('detailed_type', '=', 'service'),('server_product_process_parameters_id', '=', False)]"/>
<!-- 按钮列 --> <!-- 按钮列 -->
<!-- <button name="action_create_service_product" string="创建服务产品" type="object" <button name="action_create_service_product" string="创建服务产品" type="object"
class="btn-primary" class="btn-primary"
attrs="{'invisible': [('is_product_button', '=', True)]}" context="{'default_process_parameter_id':id}"/> attrs="{'invisible': [('is_product_button', '=', True)]}" context="{'default_process_parameter_id':id}"/>
<button name="action_hide_service_products" string="删除" type="object" <button name="action_hide_service_products" string="删除" type="object"
@@ -41,7 +41,7 @@
</tree> </tree>
</field> </field>
</page> </page>
</xpath> --> </xpath>
</field> </field>
</record> </record>
</data> </data>

View File

@@ -144,7 +144,7 @@
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/> statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
</xpath> </xpath>
<xpath expr="//div[@name='button_box']" position="inside"> <xpath expr="//div[@name='button_box']" position="inside">
<!-- <button type="object" name="action_view_pr_mrp_workorder" class="oe_stat_button" <button type="object" name="action_view_pr_mrp_workorder" class="oe_stat_button"
icon="fa-credit-card" icon="fa-credit-card"
groups="base.group_user,sf_base.group_sf_order_user" groups="base.group_user,sf_base.group_sf_order_user"
attrs="{'invisible': [('pr_mp_count', '=', 0)]}"> attrs="{'invisible': [('pr_mp_count', '=', 0)]}">
@@ -154,7 +154,7 @@
</span> </span>
<span class="o_stat_text">采购申请</span> <span class="o_stat_text">采购申请</span>
</div> </div>
</button> --> </button>
<button type="object" name="action_view_surface_technics_purchase" class="oe_stat_button" <button type="object" name="action_view_surface_technics_purchase" class="oe_stat_button"
icon="fa-credit-card" icon="fa-credit-card"
groups="base.group_user,sf_base.group_sf_order_user" groups="base.group_user,sf_base.group_sf_order_user"
@@ -677,9 +677,8 @@
<field name="inherit_id" ref="mrp.view_mrp_production_work_order_search"/> <field name="inherit_id" ref="mrp.view_mrp_production_work_order_search"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="product_id" position="after"> <field name="product_id" position="after">
<field name="part_number" string="零件图号"/> <field name="part_number" string="成品零件图号"/>
<field name="part_name" string="零件名称"/> <field name="model_id" string="模型id"/>
<field name="model_id" string="模型ID"/>
</field> </field>
<xpath expr="//filter[@name='progress']" position="after"> <xpath expr="//filter[@name='progress']" position="after">
<filter string="待检测" name="state" domain="[('state','=','to be detected')]"/> <filter string="待检测" name="state" domain="[('state','=','to be detected')]"/>

View File

@@ -12,18 +12,5 @@
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="product_template_search_inherit_sf_manufacturing" model="ir.ui.view">
<field name="name">product.template.search</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_search_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='categ_id']" position="after">
<field name="part_number" string="零件图号"/>
<field name="part_name" string="零件名称"/>
<field name="model_id" string="模型ID"/>
</xpath>
</field>
</record>
</data> </data>
</odoo> </odoo>

View File

@@ -73,7 +73,6 @@
<xpath expr="//field[@name='picking_type_id']" position="after"> <xpath expr="//field[@name='picking_type_id']" position="after">
<field name="part_numbers" string="零件图号" filter_domain="[('part_numbers', 'ilike', self)]"/> <field name="part_numbers" string="零件图号" filter_domain="[('part_numbers', 'ilike', self)]"/>
<field name="part_names" string="零件名称" filter_domain="[('part_names', 'ilike', self)]"/> <field name="part_names" string="零件名称" filter_domain="[('part_names', 'ilike', self)]"/>
<field name="model_id" string="模型ID" filter_domain="[('model_id', 'ilike', self)]"/>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -77,11 +77,11 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
if workorders[ if workorders[
0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': 0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
workorders[0].state = 'waiting' workorders[0].state = 'waiting'
# pr_ids = self.env['purchase.request'].sudo().search( pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', item.name), ('is_subcontract', '=', 'True'), ('state', '!=', 'rejected')]) [('origin', 'like', item.name), ('is_subcontract', '=', 'True'), ('state', '!=', 'rejected')])
# if not pr_ids: if not pr_ids:
# continue continue
# if not all(pr.state == 'draft' for pr in pr_ids): if not all(pr.state == 'draft' for pr in pr_ids):
# # 如果发现有记录的 state 不是 'draft',抛出异常 # 如果发现有记录的 state 不是 'draft',抛出异常
# raise UserError("有采购申请的状态不是 '草稿'") raise UserError("有采购申请的状态不是 '草稿'")
# pr_ids.state = 'rejected' pr_ids.state = 'rejected'

View File

@@ -46,10 +46,10 @@ class ProductionWizard(models.TransientModel):
mrp_workorder_list = self.mrp_production_id.workorder_ids.filtered(lambda kw: kw.rfid_code) mrp_workorder_list = self.mrp_production_id.workorder_ids.filtered(lambda kw: kw.rfid_code)
for workorder in mrp_workorder_list: for workorder in mrp_workorder_list:
rfid_code = workorder.rfid_code rfid_code = workorder.rfid_code
workorder.filtered(lambda wo: wo.routing_type == '装夹预调' and wo.rfid_code and wo.state != 'rework').write( workorder.filtered(lambda wo: wo.routing_type == '装夹预调' and wo.rfid_code is not False).write(
{'rfid_code_old': rfid_code, 'rfid_code': False}) {'rfid_code_old': rfid_code, 'rfid_code': False})
workorder.filtered(lambda wo: (wo.routing_type != '装夹预调' and workorder.filtered(lambda wo: (wo.routing_type != '装夹预调' and
(wo.rfid_code_old or wo.rfid_code) and wo.state != 'rework')).write( (wo.rfid_code_old is not False or wo.rfid_code is not False))).write(
{'rfid_code_old': False, 'rfid_code': False}) {'rfid_code_old': False, 'rfid_code': False})
if self.is_remanufacture is True: if self.is_remanufacture is True:

View File

@@ -125,28 +125,13 @@ class ReworkWizard(models.TransientModel):
# 1、单独返工CNC工单则不解绑托盘RFID如单独返工装夹预调工单则自动解绑托盘RFID # 1、单独返工CNC工单则不解绑托盘RFID如单独返工装夹预调工单则自动解绑托盘RFID
# 2、返工CNC工单和装夹预调工单则自动解绑RFID # 2、返工CNC工单和装夹预调工单则自动解绑RFID
clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调') clamp_workorder_ids = rework_workorder_ids.filtered(lambda rp: rp.routing_type == '装夹预调')
# for order in rework_workorder_ids:
# order.write({
# 'rfid_code_old': order.rfid_code,
# 'rfid_code': False
# })
# 返工工单状态设置为【返工】
rework_workorder_ids.write({'state': 'rework'})
if clamp_workorder_ids: if clamp_workorder_ids:
for clamp_workorder_id in clamp_workorder_ids: for clamp_workorder_id in clamp_workorder_ids:
# 清除返工的装夹预调工单以及其他同面返工工单的RFID并保存rfid记录 self.production_id.workorder_ids.filtered(
self.production_id.workorder_ids.filtered(lambda wk: ( lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write(
wk.processing_panel == clamp_workorder_id.processing_panel {'rfid_code': None})
and wk.state == 'rework' and wk.rfid_code)).write( # 返工工单状态设置为【返工】
{'rfid_code_old': clamp_workorder_id.rfid_code, 'rfid_code': None}) rework_workorder_ids.write({'state': 'rework'})
# 清除返工的装夹预调工单同面的非返工工单的RFID
self.production_id.workorder_ids.filtered(lambda wk: (
wk.processing_panel == clamp_workorder_id.processing_panel and wk.state != 'rework')).write(
{'rfid_code_old': None, 'rfid_code': None})
# 清除其他返工工单的RFID
for work in rework_workorder_ids.filtered(lambda wk: wk.rfid_code):
work.write({'rfid_code_old': work.rfid_code, 'rfid_code': None})
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单 # 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
workorders_values = [] workorders_values = []
for work in rework_workorder_ids: for work in rework_workorder_ids:
@@ -173,12 +158,8 @@ class ReworkWizard(models.TransientModel):
# ====新工单绑定rfid=== # ====新工单绑定rfid===
for new_work_id in new_work_ids: for new_work_id in new_work_ids:
if new_work_id.routing_type in ['CNC加工', '解除装夹']: if new_work_id.routing_type in ['CNC加工', '解除装夹']:
# 获取new_work_id同一个加工面已经绑定rfid的非返工的装夹预调工单 new_work_id.write({'rfid_code': self.production_id.workorder_ids.filtered(
work_id = self.production_id.workorder_ids.filtered( lambda wk: wk.sequence == new_work_id.sequence - 1).rfid_code})
lambda wk: (wk.processing_panel == new_work_id.processing_panel and wk.rfid_code
and wk.routing_type == '装夹预调' and wk.state != 'rework'))
if work_id:
new_work_id.write({'rfid_code': work_id.rfid_code})
self.production_id.detection_result_ids.filtered( self.production_id.detection_result_ids.filtered(
lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'}) lambda ap1: ap1.handle_result == '待处理').write({'handle_result': '已处理'})
panels = [] # 返工的加工面 panels = [] # 返工的加工面
@@ -232,13 +213,11 @@ class ReworkWizard(models.TransientModel):
self.production_id.get_new_program(panel_name) self.production_id.get_new_program(panel_name)
if self.reprogramming_num >= 0 and self.programming_state == '已下发': if self.reprogramming_num >= 0 and self.programming_state == '已下发':
# ============= 处理CNC加工加工工单的 CNC程序和cmm程序 信息============= # ============= 处理CNC加工加工工单的 CNC程序和cmm程序 信息=============
for cnc_work in new_work_ids.filtered( for cnc_work in new_work_ids.filtered(lambda wk: wk.name == 'CNC加工' or wk.name == '人工线下加工'):
lambda wk: wk.name == 'CNC加工' or wk.name == '人工线下加工'):
ret = {'programming_list': []} ret = {'programming_list': []}
old_cnc_rework = max(self.production_id.workorder_ids.filtered( old_cnc_rework = max(self.production_id.workorder_ids.filtered(
lambda crw: crw.processing_panel == cnc_work.processing_panel lambda crw: crw.processing_panel == cnc_work.processing_panel
and crw.state == 'rework' and ( and crw.state == 'rework' and (crw.routing_type == 'CNC加工' or crw.routing_type == '人工线下加工')),
crw.routing_type == 'CNC加工' or crw.routing_type == '人工线下加工')),
key=lambda w: w.create_date key=lambda w: w.create_date
) )
# 获取当前工单的CNC程序和cmm程序 # 获取当前工单的CNC程序和cmm程序
@@ -280,8 +259,7 @@ class ReworkWizard(models.TransientModel):
new_cnc_workorder = self.production_id.workorder_ids.filtered( new_cnc_workorder = self.production_id.workorder_ids.filtered(
lambda ap1: ap1.processing_panel == cnc_work.processing_panel lambda ap1: ap1.processing_panel == cnc_work.processing_panel
and ap1.state not in ( and ap1.state not in (
'rework', 'done') and ( 'rework', 'done') and (ap1.routing_type == 'CNC加工' or ap1.routing_type == '人工线下加工')
ap1.routing_type == 'CNC加工' or ap1.routing_type == '人工线下加工')
) )
if not new_cnc_workorder.cnc_ids: if not new_cnc_workorder.cnc_ids:
new_cnc_workorder.write({ new_cnc_workorder.write({
@@ -290,8 +268,6 @@ class ReworkWizard(models.TransientModel):
'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program( 'cmm_ids': new_cnc_workorder.cmm_ids.sudo()._json_cmm_program(
cnc_work.processing_panel, ret), cnc_work.processing_panel, ret),
'cnc_worksheet': old_cnc_rework.cnc_worksheet}) 'cnc_worksheet': old_cnc_rework.cnc_worksheet})
# 复制装夹图纸
new_cnc_workorder.processing_drawing = old_cnc_rework.processing_drawing
# ========== 处理装夹预调 【装夹图纸】 数据 ================ # ========== 处理装夹预调 【装夹图纸】 数据 ================
for new_pre_work in new_pre_workorder_ids: for new_pre_work in new_pre_workorder_ids:
pre_rework = max(self.production_id.workorder_ids.filtered( pre_rework = max(self.production_id.workorder_ids.filtered(
@@ -318,8 +294,7 @@ class ReworkWizard(models.TransientModel):
'is_rework': False}) 'is_rework': False})
# ==================申请重新编程======================= # ==================申请重新编程=======================
if self.is_reprogramming is True: if self.is_reprogramming is True:
self.production_id.update_programming_state( self.production_id.update_programming_state(trigger_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
trigger_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
self.production_id.write( self.production_id.write(
{'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'}) {'programming_state': '编程中', 'work_state': '编程中', 'state': 'progress'})
# ================= 返工完成,制造订单状态置为加工中 ============== # ================= 返工完成,制造订单状态置为加工中 ==============
@@ -340,7 +315,7 @@ class ReworkWizard(models.TransientModel):
for p in production_id.detection_result_ids.filtered( for p in production_id.detection_result_ids.filtered(
lambda ap1: ap1.handle_result == '待处理'): lambda ap1: ap1.handle_result == '待处理'):
if p.processing_panel is not False and p.processing_panel not in panel_arr: if p.processing_panel is not False and p.processing_panel not in panel_arr:
if len(panel_arr) > 0: if len(panel_arr)>0:
panel_arr += ','.join(p.processing_panel) panel_arr += ','.join(p.processing_panel)
else: else:
panel_arr = p.processing_panel panel_arr = p.processing_panel

View File

@@ -126,11 +126,6 @@
<field name="model">mrp.production</field> <field name="model">mrp.production</field>
</record> </record>
<record id="bussiness_purchase_request" model="jikimo.message.bussiness.node">
<field name="name">采购申请待处理通知</field>
<field name="model">purchase.request</field>
</record>
<record id="bussiness_outsourcing" model="jikimo.message.bussiness.node"> <record id="bussiness_outsourcing" model="jikimo.message.bussiness.node">
<field name="name">委外加工采购单提醒</field> <field name="name">委外加工采购单提醒</field>
<field name="model">purchase.order</field> <field name="model">purchase.order</field>
@@ -161,13 +156,9 @@
<field name="model">purchase.order</field> <field name="model">purchase.order</field>
</record> </record>
<!-- <record id="bussiness_quality_check" model="jikimo.message.bussiness.node">--> <record id="bussiness_quality_check" model="jikimo.message.bussiness.node">
<!-- <field name="name">待质检提醒</field>--> <field name="name">待质检提醒</field>
<!-- <field name="model">product.product</field>--> <field name="model">product.product</field>
<!-- </record>-->
<record id="bussiness_quality_check_none" model="jikimo.message.bussiness.node">
<field name="name">待质检</field>
<field name="model">quality.check</field>
</record> </record>
</data> </data>

View File

@@ -210,8 +210,8 @@
<field name="msgtype">markdown</field> <field name="msgtype">markdown</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 功能刀具寿命到期提醒: <field name="content">### 功能刀具寿命到期提醒:
单号:拆解单[{{code}}]({{request_url}}) 单号:拆解单[{{code}}]({{tool_expired_remind_special_url}})
事项:{{name}}寿命已到期,需拆解</field> 事项:{{functional_tool_id.tool_name_id.name}}寿命已到期,需拆解</field>
</record> </record>
<record id="template_tool_assembly_remind" model="jikimo.message.template"> <record id="template_tool_assembly_remind" model="jikimo.message.template">
@@ -339,18 +339,6 @@
事项:请确认委外采购单并处理。</field> 事项:请确认委外采购单并处理。</field>
</record> </record>
<record id="template_purchase_request" model="jikimo.message.template">
<field name="name">采购申请待处理通知</field>
<field name="model_id" ref="purchase_request.model_purchase_request"/>
<field name="model">purchase.request</field>
<field name="bussiness_node_id" ref="bussiness_purchase_request"/>
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 采购申请待处理提醒:
单号:[{{name}}]({{request_url}})
事项:您有一张新的采购申请单待处理。</field>
</record>
<record id="template_purchase_remind" model="jikimo.message.template"> <record id="template_purchase_remind" model="jikimo.message.template">
<field name="name">外购订单采购单提醒</field> <field name="name">外购订单采购单提醒</field>
<field name="model_id" ref="purchase.model_purchase_order"/> <field name="model_id" ref="purchase.model_purchase_order"/>
@@ -414,28 +402,16 @@
</field> </field>
</record> </record>
<!-- <record id="template_quality_check" model="jikimo.message.template">--> <record id="template_quality_check" model="jikimo.message.template">
<!-- <field name="name">待质检提醒</field>-->
<!-- <field name="model_id" ref="product.model_product_product"/>-->
<!-- <field name="model">product.product</field>-->
<!-- <field name="bussiness_node_id" ref="bussiness_quality_check"/>-->
<!-- <field name="msgtype">markdown</field>-->
<!-- <field name="urgency">normal</field>-->
<!-- <field name="content">### 待质检提醒:-->
<!--单号:产品[{{name}}]({{url}})-->
<!--事项:有{{num}}个质检单需要处理。</field>-->
<!-- </record>-->
<!-- </data>-->
<record id="template_quality_check_none" model="jikimo.message.template">
<field name="name">待质检提醒</field> <field name="name">待质检提醒</field>
<field name="model_id" ref="quality.model_quality_check"/> <field name="model_id" ref="product.model_product_product"/>
<field name="model">quality.check</field> <field name="model">product.product</field>
<field name="bussiness_node_id" ref="bussiness_quality_check_none"/> <field name="bussiness_node_id" ref="bussiness_quality_check"/>
<field name="msgtype">markdown</field> <field name="msgtype">markdown</field>
<field name="urgency">normal</field> <field name="urgency">normal</field>
<field name="content">### 待质检提醒: <field name="content">### 待质检提醒:
单号:[{{name}}]({{url}}) 单号:产品[{{name}}]({{url}})
事项:有个质检单需要处理({{type_name}})</field> 事项:有{{num}}个质检单需要处理。</field>
</record> </record>
</data> </data>

View File

@@ -14,4 +14,3 @@ from . import sf_message_mrp_production_wizard
from . import sf_message_mrp_production_adjust_wizard from . import sf_message_mrp_production_adjust_wizard
from . import sf_message_product from . import sf_message_product
from . import sf_message_quality_check from . import sf_message_quality_check
from . import sf_message_purchase_request

View File

@@ -1,5 +1,4 @@
from odoo import models, api from odoo import models, api
from urllib.parse import urlencode
class SFMessagefunctionalToolDismantle(models.Model): class SFMessagefunctionalToolDismantle(models.Model):
@@ -19,39 +18,12 @@ class SFMessagefunctionalToolDismantle(models.Model):
obj.add_queue('功能刀具寿命到期') obj.add_queue('功能刀具寿命到期')
return result return result
def _get_message(self, message_queue_ids): def get_special_url(self,id,tmplate_name,special_name,model_id):
contents = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '功能刀具寿命到期':
content = message_queue_id.message_template_id.content
td_line = self.search([('id', '=', int(message_queue_id.res_id))])
url = self.request_url(int(message_queue_id.res_id))
content = content.replace('{{code}}', td_line.code).replace(
'{{request_url}}', url).replace('{{name}}', td_line.name)
contents.append(content)
return contents, message_queue_ids
def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('sf_tool_management.sf_functional_tool_dismantle_view_act').id
menu_id = self.env.ref('sf_tool_management.menu_sf_functional_tool_dismantle').id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id,
'model': 'sf.functional.tool.dismantle',
'view_type': 'form'}
# 拼接查询参数
tool_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + tool_string
return full_url
def get_special_url(self, id, tmplate_name, special_name, model_id):
menu_id = 0 menu_id = 0
action_id = 0 action_id = 0
if tmplate_name == '调拨入库' and special_name == 'tool_expired_remind_special_url': if tmplate_name=='调拨入库' and special_name== 'tool_expired_remind_special_url':
menu_id = self.env.ref('mrp.menu_mrp_root').id menu_id = self.env.ref('mrp.menu_mrp_root').id
action_id = self.env.ref('sf_tool_management.sf_functional_tool_dismantle_view_act').id action_id = self.env.ref('sf_tool_management.sf_functional_tool_dismantle_view_act').id
return super(SFMessagefunctionalToolDismantle, self).get_url(id, menu_id, action_id, model_id) return super(SFMessagefunctionalToolDismantle, self).get_url(id, menu_id, action_id,model_id)
else: else:
return super(SFMessagefunctionalToolDismantle, self).get_special_url(id, tmplate_name, special_name, return super(SFMessagefunctionalToolDismantle, self).get_special_url(id, tmplate_name, special_name, model_id)
model_id)

View File

@@ -29,18 +29,18 @@ class SFMessageProduct(models.Model):
'{{number}}', str(production_num)).replace( '{{number}}', str(production_num)).replace(
'{{request_url}}', url) '{{request_url}}', url)
contents.append(content) contents.append(content)
# if message_queue_id.message_template_id.name == '待质检提醒': if message_queue_id.message_template_id.name == '待质检提醒':
# content = message_queue_id.message_template_id.content content = message_queue_id.message_template_id.content
# product_product = self.env['product.product'].sudo().search([('id', '=', int(message_queue_id.res_id))]) product_product = self.env['product.product'].sudo().search([('id', '=', int(message_queue_id.res_id))])
# quality_check_num = self.env['quality.check'].sudo().search_count( quality_check_num = self.env['quality.check'].sudo().search_count(
# [('product_id', '=', product_product.id), ('quality_state', '=', 'none')]) [('product_id', '=', product_product.id), ('quality_state', '=', 'none')])
# if quality_check_num >= 1: if quality_check_num >= 1:
# url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
# action_id = self.env.ref('quality_control.quality_check_action_report').id action_id = self.env.ref('quality_control.quality_check_action_report').id
# url_with_id = f"{url}/web#view_type=list&action={action_id}" url_with_id = f"{url}/web#view_type=list&action={action_id}"
# content = content.replace('{{name}}', product_product.name).replace('{{url}}', url_with_id).replace( content = content.replace('{{name}}', product_product.name).replace('{{url}}', url_with_id).replace(
# '{{num}}', str(quality_check_num)) '{{num}}', str(quality_check_num))
# contents.append(content) contents.append(content)
return contents, message_queue_ids return contents, message_queue_ids
def get_request_url(self, routing_type): def get_request_url(self, routing_type):

View File

@@ -1,46 +0,0 @@
import logging
import re
from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessagePurchaseRequest(models.Model):
_name = 'purchase.request'
_description = "采购申请"
_inherit = ['purchase.request', 'jikimo.message.dispatch']
def write(self, vals):
original_state = {}
for item in self:
original_state.update({f'{item.id}': item.state})
res = super(SFMessagePurchaseRequest, self).write(vals)
for item in self:
if vals.get('state') == 'approved' and original_state.get(f'{item.id}') != 'approved':
item.add_queue('采购申请待处理通知')
return res
def _get_message(self, message_queue_ids):
contents = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '采购申请待处理通知':
content = message_queue_id.message_template_id.content
url = self.request_url(int(message_queue_id.res_id))
request_line = self.env['purchase.request'].search([('id', '=', int(message_queue_id.res_id))])
content = content.replace('{{name}}', request_line.name).replace(
'{{request_url}}', url)
contents.append(content)
return contents, message_queue_ids
def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('purchase_request.purchase_request_form_action').id
menu_id = self.env.ref('purchase_request.menu_purchase_request_act').id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id,
'model': 'purchase.request',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from urllib.parse import urlencode
class SFMessageQualityCheck(models.Model): class SFMessageQualityCheck(models.Model):
@@ -11,73 +10,25 @@ class SFMessageQualityCheck(models.Model):
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
result = super().create(vals_list) result = super().create(vals_list)
# try: try:
# # 判断是否为web页面创建请求 # 判断是否为web页面创建请求
# is_web_request = self.env.context.get('is_web_request', False) is_web_request = self.env.context.get('is_web_request', False)
# if not is_web_request: if not is_web_request:
# for obj in result: for obj in result:
# jikimo_message_queue = self.get_message_queue(obj.product_id.id) jikimo_message_queue = self.get_message_queue(obj.product_id.id)
# if not jikimo_message_queue: if not jikimo_message_queue:
# obj.product_id.add_queue('待质检提醒') obj.product_id.add_queue('待质检提醒')
# except Exception as e: except Exception as e:
# logging.info('add_queue待质检提醒 error:%s' % e) logging.info('add_queue待质检提醒 error:%s' % e)
qc_ids = result.filtered(lambda qc: qc.quality_state == 'none')
if qc_ids:
message_template_id = self.env['jikimo.message.template'].sudo().search([('name', '=', '待质检提醒')])
for qc in qc_ids:
queue_id = self.env['jikimo.message.queue'].sudo().search(
[('message_template_id', '=', message_template_id[-1].id), ('res_id', '=', qc.id)])
if not queue_id and '制造' not in [pt.name for pt in qc.point_id.picking_type_ids]:
qc.add_queue('待质检')
return result return result
# def get_message_queue(self, res_id):
# def get_message_queue(self, res_id): business_node_id = self.env.ref('sf_message.bussiness_quality_check').id
# business_node_id = self.env.ref('sf_message.bussiness_quality_check').id message_template = self.env["jikimo.message.template"].sudo().search([
# message_template = self.env["jikimo.message.template"].sudo().search([ ("name", "=", '待质检提醒'),
# ("name", "=", '待质检提醒'), ("bussiness_node_id", "=", business_node_id)
# ("bussiness_node_id", "=", business_node_id) ], limit=1)
# ], limit=1) jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search(
# jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search( [('res_id', '=', res_id), ("message_status", "in", ("pending", "sent")),
# [('res_id', '=', res_id), ("message_status", "in", ("pending", "sent")), ('message_template_id', '=', message_template.id)])
# ('message_template_id', '=', message_template.id)]) return jikimo_message_queue
# return jikimo_message_queue
def write(self, vals):
original_state = {}
for item in self:
original_state.update({f'{item.id}': item.quality_state})
res = super(SFMessageQualityCheck, self).write(vals)
for item in self:
if vals.get('quality_state') == 'none' and original_state.get(f'{item.id}') != 'none':
message_template_id = self.env['jikimo.message.template'].sudo().search([('name', '=', '待质检提醒')])
queue_id = self.env['jikimo.message.queue'].sudo().search(
[('message_template_id', '=', message_template_id[-1].id), ('res_id', '=', item.id)])
if not queue_id and '制造' not in [pt.name for pt in item.point_id.picking_type_ids]:
item.add_queue('待质检')
return res
def _get_message(self, message_queue_ids):
contents = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '待质检提醒':
content = message_queue_id.message_template_id.content
qc_line = self.search([('id', '=', int(message_queue_id.res_id))])
url = self.request_url(int(message_queue_id.res_id))
content = content.replace('{{name}}', qc_line.name).replace(
'{{url}}', url).replace('{{type_name}}', qc_line.point_id.title)
contents.append(content)
return contents, message_queue_ids
def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('quality_control.quality_check_action_main').id
menu_id = self.env.ref('quality_control.menu_quality_checks').id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id,
'model': 'quality.check',
'view_type': 'form'}
# 拼接查询参数
query_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + query_string
return full_url

View File

@@ -3,6 +3,9 @@ import logging
import os import os
import json import json
import base64 import base64
import traceback
from odoo import http, fields, models from odoo import http, fields, models
from odoo.http import request from odoo.http import request
from odoo.addons.sf_base.controllers.controllers import MultiInheritController from odoo.addons.sf_base.controllers.controllers import MultiInheritController
@@ -24,7 +27,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
res = {'status': 1, 'message': '成功'} res = {'status': 1, 'message': '成功'}
datas = request.httprequest.data datas = request.httprequest.data
model_id = None model_id = None
part_number = None
ret = json.loads(datas) ret = json.loads(datas)
ret = json.loads(ret['result']) ret = json.loads(ret['result'])
logging.info('下发编程单:%s' % ret) logging.info('下发编程单:%s' % ret)
@@ -60,6 +62,7 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no']) res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no'])
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
for production in productions: for production in productions:
model_id = production.product_id.model_id # 一个编程单的制造订单对应同一个模型
production.write({'programming_state': '已编程', 'work_state': '已编程', 'is_rework': False}) production.write({'programming_state': '已编程', 'work_state': '已编程', 'is_rework': False})
for panel in ret['processing_panel'].split(','): for panel in ret['processing_panel'].split(','):
# 查询状态为进行中且工序类型为CNC加工的工单 # 查询状态为进行中且工序类型为CNC加工的工单
@@ -76,10 +79,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
cnc_workorder_has.write( cnc_workorder_has.write(
{'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret), {'cnc_ids': cnc_workorder_has.cnc_ids.sudo()._json_cnc_processing(panel, ret),
'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)}) 'cmm_ids': cnc_workorder_has.cmm_ids.sudo()._json_cmm_program(panel, ret)})
# 一个编程单的制造订单对应同一个模型
model_id = productions[0].product_id.model_id
part_number = productions[0].product_id.part_number
for panel in ret['processing_panel'].split(','): for panel in ret['processing_panel'].split(','):
# 查询状态为进行中且工序类型为CNC加工的工单 # 查询状态为进行中且工序类型为CNC加工的工单
cnc_workorder = productions.workorder_ids.filtered( cnc_workorder = productions.workorder_ids.filtered(
@@ -99,12 +98,7 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
logging.info('panel_file_path:%s' % panel_file_path) logging.info('panel_file_path:%s' % panel_file_path)
# 向编程单中添加二维码 # 向编程单中添加二维码
request.env['printing.utils'].add_qr_code_to_pdf( request.env['printing.utils'].add_qr_code_to_pdf(panel_file_path, model_id, "模型ID%s" % model_id)
panel_file_path,
model_id,
"模型ID%s" % model_id,
"零件图号:%s" % part_number if part_number else None
)
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())}) cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
pre_workorder = productions.workorder_ids.filtered( pre_workorder = productions.workorder_ids.filtered(
lambda ap: ap.routing_type in ['装夹预调', '人工线下加工'] and ap.state not in ['done', 'rework' lambda ap: ap.routing_type in ['装夹预调', '人工线下加工'] and ap.state not in ['done', 'rework'
@@ -143,114 +137,94 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
for production in productions: for production in productions:
logging.info('production====:%s' % production.name) logging.info('production====:%s' % production.name)
record_ids_obj = production.programming_record_ids.filtered( record_ids_obj = production.programming_record_ids.filtered(
lambda r: r.send_time is False) lambda r: r.current_programming_count == ret['reprogramming_num'])
logging.info('record_ids_obj====:%s' % record_ids_obj) logging.info('record_ids_obj====:%s' % record_ids_obj)
if record_ids_obj: if record_ids_obj:
record_ids_obj = record_ids_obj.sorted('id')[0]
logging.info('record_ids_obj.reason====:%s' % record_ids_obj.reason) logging.info('record_ids_obj.reason====:%s' % record_ids_obj.reason)
record_ids_obj.write({ record_ids_obj.write(
'current_programming_count': ret['reprogramming_num'], {'send_time': ret['send_time'], 'target_production_id': productions_reprogram})
'send_time': ret['send_time'],
'target_production_id': productions_reprogram,
'programming_method': ret['programme_way']
})
logging.info('已更新编程记录:%s' % record_ids_obj) logging.info('已更新编程记录:%s' % record_ids_obj)
correct_record_ids_obj = record_ids_obj correct_record_ids_obj = record_ids_obj
correct_production_id = production.id correct_production_id = production.id
# 更新重新编程记录 if ret['reprogramming_num'] == 0:
logging.info('首次下发')
production.programming_record_ids.create({
'number': 1,
'production_id': production.id,
'reason': '首次下发',
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': False,
'send_time': ret['send_time'],
})
logging.info('已创建首次下发的编程记录:%s' % production.name)
elif ret['reset_flag']:
logging.info('重置状态')
production.programming_record_ids.create({
'number': len(production.programming_record_ids) + 1,
'production_id': production.id,
'reason': '重置状态',
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': False,
'send_time': ret['send_time'],
})
logging.info('已创建重置状态的编程记录:%s' % production.name)
elif ret['manufacturing_type'] == 'rework':
logging.info('返工')
rework_record_ids_obj = production.programming_record_ids.create({
'number': len(production.programming_record_ids) + 1,
'production_id': production.id,
'reason': '返工',
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': ret['trigger_time'],
'send_time': ret['send_time'],
})
logging.info('已创建返工的编程记录:%s' % production.name)
logging.info('rework_record_ids_obj====:%s' % rework_record_ids_obj)
# rework_production_id = production.id
# logging.info('rework_production_id====:%s' % rework_production_id)
elif ret['manufacturing_type'] == 'scrap':
production.programming_record_ids.create({
'number': len(production.programming_record_ids) + 1,
'production_id': production.id,
'reason': '报废',
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': ret['trigger_time'],
'send_time': ret['send_time'],
})
elif ret['manufacturing_type'] == 'invalid_tool_rework':
logging.info('无效功能刀具')
production.programming_record_ids.create({
'number': len(production.programming_record_ids) + 1,
'production_id': production.id,
'reason': '无效功能刀具',
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': ret['trigger_time'],
'send_time': ret['send_time'],
})
logging.info('已创建无效功能刀具的编程记录:%s' % production.name)
elif ret['reprogramming_reason']:
production.programming_record_ids.create({
'number': len(production.programming_record_ids) + 1,
'production_id': production.id,
'reason': ret['reprogramming_reason'],
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': ret['trigger_time'],
'send_time': ret['send_time'],
})
else: else:
if ret['reset_flag']: logging.info('无对应状态,不需更新编程记录')
logging.info('重置状态')
production.programming_record_ids.create({
'number': len(production.programming_record_ids) + 1,
'production_id': production.id,
'reason': '重置状态',
'programming_method': ret['programme_way'],
'current_programming_count': ret['reprogramming_num'],
'target_production_id': productions_reprogram,
'apply_time': False,
'send_time': ret['send_time'],
})
else:
logging.info('无对应状态,不需更新编程记录')
# if ret['reprogramming_num'] == 0:
# logging.info('首次下发')
# production.programming_record_ids.create({
# 'number': 1,
# 'production_id': production.id,
# 'reason': '首次下发',
# 'programming_method': ret['programme_way'],
# 'current_programming_count': ret['reprogramming_num'],
# 'target_production_id': productions_reprogram,
# 'apply_time': False,
# 'send_time': ret['send_time'],
# })
# logging.info('已创建首次下发的编程记录:%s' % production.name)
# elif ret['reset_flag']:
# logging.info('重置状态')
# production.programming_record_ids.create({
# 'number': len(production.programming_record_ids) + 1,
# 'production_id': production.id,
# 'reason': '重置状态',
# 'programming_method': ret['programme_way'],
# 'current_programming_count': ret['reprogramming_num'],
# 'target_production_id': productions_reprogram,
# 'apply_time': False,
# 'send_time': ret['send_time'],
# })
# logging.info('已创建重置状态的编程记录:%s' % production.name)
# elif ret['manufacturing_type'] == 'rework':
# logging.info('返工')
# rework_record_ids_obj = production.programming_record_ids.create({
# 'number': len(production.programming_record_ids) + 1,
# 'production_id': production.id,
# 'reason': '返工',
# 'programming_method': ret['programme_way'],
# 'current_programming_count': ret['reprogramming_num'],
# 'target_production_id': productions_reprogram,
# 'apply_time': ret['trigger_time'],
# 'send_time': ret['send_time'],
# })
# logging.info('已创建返工的编程记录:%s' % production.name)
# logging.info('rework_record_ids_obj====:%s' % rework_record_ids_obj)
# # rework_production_id = production.id
# # logging.info('rework_production_id====:%s' % rework_production_id)
# elif ret['manufacturing_type'] == 'scrap':
# production.programming_record_ids.create({
# 'number': len(production.programming_record_ids) + 1,
# 'production_id': production.id,
# 'reason': '报废',
# 'programming_method': ret['programme_way'],
# 'current_programming_count': ret['reprogramming_num'],
# 'target_production_id': productions_reprogram,
# 'apply_time': ret['trigger_time'],
# 'send_time': ret['send_time'],
# })
# elif ret['manufacturing_type'] == 'invalid_tool_rework':
# logging.info('无效功能刀具')
# production.programming_record_ids.create({
# 'number': len(production.programming_record_ids) + 1,
# 'production_id': production.id,
# 'reason': '无效功能刀具',
# 'programming_method': ret['programme_way'],
# 'current_programming_count': ret['reprogramming_num'],
# 'target_production_id': productions_reprogram,
# 'apply_time': ret['trigger_time'],
# 'send_time': ret['send_time'],
# })
# logging.info('已创建无效功能刀具的编程记录:%s' % production.name)
# elif ret['reprogramming_reason']:
# production.programming_record_ids.create({
# 'number': len(production.programming_record_ids) + 1,
# 'production_id': production.id,
# 'reason': ret['reprogramming_reason'],
# 'programming_method': ret['programme_way'],
# 'current_programming_count': ret['reprogramming_num'],
# 'target_production_id': productions_reprogram,
# 'apply_time': ret['trigger_time'],
# 'send_time': ret['send_time'],
# })
for production in productions: for production in productions:
logging.info('production====:%s' % production.name) logging.info('production====:%s' % production.name)
@@ -269,7 +243,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
'current_programming_count': correct_record_ids_obj.current_programming_count, 'current_programming_count': correct_record_ids_obj.current_programming_count,
'target_production_id': correct_record_ids_obj.target_production_id, 'target_production_id': correct_record_ids_obj.target_production_id,
'apply_time': correct_record_ids_obj.apply_time, 'apply_time': correct_record_ids_obj.apply_time,
'apply_uid': correct_record_ids_obj.apply_uid.id,
'send_time': correct_record_ids_obj.send_time, 'send_time': correct_record_ids_obj.send_time,
}) })
logging.info('已创建正确的制造订单的编程记录:%s' % production.name) logging.info('已创建正确的制造订单的编程记录:%s' % production.name)
@@ -303,7 +276,8 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
except Exception as e: except Exception as e:
res = {'status': -1, 'message': '系统解析失败'} res = {'status': -1, 'message': '系统解析失败'}
request.cr.rollback() request.cr.rollback()
logging.info('get_cnc_processing_create error:%s' % e) traceback_error = traceback.format_exc()
logging.error("get_cnc_processing_create error:%s" % traceback_error)
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)

View File

@@ -1149,7 +1149,7 @@ class sfProductionProcessParameter(models.Model):
'processing_mm': item['processing_mm'], 'processing_mm': item['processing_mm'],
'gain_way':'外协', 'gain_way':'外协',
}) })
# production_process_parameter.create_service_product() production_process_parameter.create_service_product()
else: else:
production_process_parameter.gain_way = '外协' production_process_parameter.gain_way = '外协'
production_process_parameter.name = item['name'] production_process_parameter.name = item['name']
@@ -1161,9 +1161,9 @@ class sfProductionProcessParameter(models.Model):
[('materials_no', 'in', item['materials_model_ids_codes'])]) [('materials_no', 'in', item['materials_model_ids_codes'])])
production_process_parameter.active = item['active'] production_process_parameter.active = item['active']
production_process_parameter.processing_mm = item['processing_mm'] production_process_parameter.processing_mm = item['processing_mm']
# if not production_process_parameter.outsourced_service_products: if not production_process_parameter.outsourced_service_products:
# production_process_parameter.create_service_product() production_process_parameter.create_service_product()
# production_process_parameter.create_work_center() production_process_parameter.create_work_center()
else: else:
raise ValidationError("表面工艺可选参数认证未通过") raise ValidationError("表面工艺可选参数认证未通过")

View File

@@ -15,7 +15,6 @@ class sf_production_plan(models.Model):
# _order = 'state desc, write_date desc' # _order = 'state desc, write_date desc'
part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True) part_name = fields.Char('零件名称', related='product_id.part_name', readonly=True)
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
model_id = fields.Char('模型ID', related='product_id.model_id')
state = fields.Selection([ state = fields.Selection([
('draft', '待排程'), ('draft', '待排程'),
('done', '已排程'), ('done', '已排程'),

View File

@@ -170,7 +170,6 @@
<field name="part_number"/> <field name="part_number"/>
<field name="order_deadline" filter_domain="[('order_deadline', 'ilike', self)]"/> <field name="order_deadline" filter_domain="[('order_deadline', 'ilike', self)]"/>
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="model_id"/>
<filter string="待排程" name="draft" domain="[('state','=','draft')]"/> <filter string="待排程" name="draft" domain="[('state','=','draft')]"/>
<filter string="已排程" name="done" domain="[('state','=','done')]"/> <filter string="已排程" name="done" domain="[('state','=','done')]"/>
<filter string="加工中" name="processing" domain="[('state','=','processing')]"/> <filter string="加工中" name="processing" domain="[('state','=','processing')]"/>

View File

@@ -13,7 +13,7 @@
'author': 'jikimo', 'author': 'jikimo',
'website': 'https://sf.cs.jikimo.com', 'website': 'https://sf.cs.jikimo.com',
# 此处依赖sf_manufacturing是因为我要重写其中的一个字段operation_id的string故需要sf_manufacturing先安装 # 此处依赖sf_manufacturing是因为我要重写其中的一个字段operation_id的string故需要sf_manufacturing先安装
'depends': ['quality_control', 'web_widget_model_viewer', 'sf_manufacturing','jikimo_attachment_viewer', 'jikimo_confirm_dialog'], 'depends': ['quality_control', 'web_widget_model_viewer', 'sf_manufacturing','jikimo_attachment_viewer'],
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'data/check_standards.xml', 'data/check_standards.xml',

View File

@@ -5,7 +5,6 @@ from odoo import fields, models, api
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from datetime import datetime from datetime import datetime
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo.tools import float_round, float_compare
class QualityCheck(models.Model): class QualityCheck(models.Model):
@@ -141,163 +140,3 @@ class QualityCheck(models.Model):
return "零件特采发送成功" return "零件特采发送成功"
else: else:
raise ValidationError("零件特采发送失败") raise ValidationError("零件特采发送失败")
@api.model_create_multi
def create(self, vals_list):
for val in vals_list:
if 'point_id' in val and 'measure_on' not in val:
# 如果没有控制方式字段,则从检查点读取质量方式
point_id = self.env['quality.point'].browse(val['point_id'])
val.update({'measure_on': point_id.measure_on})
return super(QualityCheck, self).create(vals_list)
@api.depends('total_qty','testing_percentage_within_lot', 'is_lot_tested_fractionally')
def _compute_workorder_qty_to_test(self):
for qc in self:
if qc.is_lot_tested_fractionally:
rounding = qc.product_id.uom_id.rounding if qc.product_id.uom_id else 0.01
qc.workorder_qty_to_test = float_round(float(qc.total_qty) * qc.testing_percentage_within_lot / 100,
precision_rounding=rounding, rounding_method="UP")
else:
qc.workorder_qty_to_test = qc.total_qty
@api.depends('picking_id', 'workorder_id')
def _compute_total_qty(self):
super(QualityCheck, self)._compute_total_qty()
for qc in self:
if not qc.picking_id and qc.workorder_id:
qc.total_qty = qc.workorder_id.production_id.product_qty
@api.depends('workorder_qty_to_test')
def _compute_workorder_qty_tested(self):
for qc in self:
qc.workorder_qty_tested = qc.workorder_qty_to_test
workorder_qty_to_test = fields.Float('应检', compute='_compute_workorder_qty_to_test', store=True)
workorder_qty_tested = fields.Float('已检', compute='_compute_workorder_qty_tested', store=True)
workorder_qty_test_failed = fields.Float('不合格数')
@api.onchange('total_qty', 'workorder_qty_test_failed', 'workorder_qty_to_test', 'workorder_qty_tested')
def _onchage_qty(self):
for record in self:
if record.total_qty and record.workorder_qty_to_test and record.workorder_qty_to_test > float(record.total_qty):
record.workorder_qty_to_test = float(record.total_qty)
return {
'warning': {
'title': '警告',
'message': '待检数量不能超过总数量'
}
}
if record.workorder_qty_to_test and record.workorder_qty_tested and record.workorder_qty_tested > record.workorder_qty_to_test:
record.workorder_qty_tested = record.workorder_qty_to_test
return {
'warning': {
'title': '警告',
'message': '已检数量不能超过待检数量'
}
}
if record.workorder_qty_tested and record.workorder_qty_test_failed and record.workorder_qty_test_failed > record.workorder_qty_tested:
record.workorder_qty_test_failed = record.workorder_qty_tested
return {
'warning': {
'title': '警告',
'message': '不合格数量不能超过已检数量'
}
}
total_qty_readonly = fields.Boolean(compute='_compute_total_qty_readonly', store=True)
def _compute_total_qty_readonly(self):
report_test_type_id = self.env.ref('sf_quality.test_type_factory_inspection').id
for record in self:
if (record.measure_on != 'move_line' or record.workorder_id is False) and record.point_id.test_type_id.id != report_test_type_id:
record.total_qty_readonly = True
else:
record.total_qty_readonly = False
def preview_doc(self):
"""预览出厂检验报告"""
self.ensure_one()
picking_qty = sum(self.picking_id.move_ids.filtered(lambda m: m.product_id == self.product_id).mapped('product_uom_qty'))
if not self._check_total_qty(picking_qty) and self.quality_state in ['waiting', 'none']:
return {
'type': 'ir.actions.client',
'tag': 'jikimo_confirm_dialog',
'params': {
'active_id': self.id,
'message': f"拣货调拨单号{self.picking_id.name}需求数量为{picking_qty},当前质量检查单产品数量为{self.total_qty},数量不一致,是否确认继续?",
'next_model': self._name,
'next_method': 'preview_doc_confirm',
'context': self.env.context
}
}
action = self.env.ref("sf_quality.action_report_quality_inspection_preview").read()[0]
return action
def preview_doc_confirm(self):
self.ensure_one()
action = self.env.ref("sf_quality.action_report_quality_inspection_preview").read()[0]
action['context'] = {
'active_id': self.id,
'active_ids': [self.id]
}
return action
def _check_total_qty(self, compare_qty):
"""
检查质量检查单的总数量是否匹配
"""
self.ensure_one()
return float_compare(float(self.total_qty), compare_qty, self.picking_id.product_id.uom_id.rounding) == 0
def preview_do_publish(self):
self.ensure_one()
self._check_part_number()
self._check_measure_line()
self._check_check_qty_and_total_qty()
picking_qty = sum(self.picking_id.move_ids.filtered(lambda m: m.product_id == self.product_id).mapped('product_uom_qty'))
if not self._check_total_qty(picking_qty):
return {
'type': 'ir.actions.client',
'tag': 'jikimo_confirm_dialog',
'params': {
'active_id': self.id,
'message': f"拣货调拨单号{self.picking_id.name}需求数量为{picking_qty},当前质量检查单产品数量为{self.total_qty},数量不一致,是否确认继续?",
'next_model': self._name,
'next_method': 'preview_do_publish_confirm',
'context': self.env.context,
}
}
else:
return self.do_publish()
def preview_do_publish_confirm(self):
self.ensure_one()
return {
'name': '发布确认',
'type': 'ir.actions.act_window',
'res_model': 'quality.check.publish.wizard',
'view_mode': 'form',
'views': [[False, 'form']],
'target': 'new',
'context': {
'default_check_id': self.id,
'default_product_name': self.product_id.name,
'default_total_qty': self.total_qty,
'default_check_qty': self.check_qty,
'default_measure_count': self.column_nums,
'default_item_count': len(self.measure_line_ids),
'default_old_report_name': self.old_report_name,
'default_publish_status': self.publish_status,
'is_web_request': True
}
}

View File

@@ -73,59 +73,20 @@
<xpath expr="//header" position="inside"> <xpath expr="//header" position="inside">
<field name="is_out_check" invisible="1"/> <field name="is_out_check" invisible="1"/>
<field name="publish_status" invisible="1"/> <field name="publish_status" invisible="1"/>
<button name="preview_doc" <button name="%(sf_quality.action_report_quality_inspection_preview)d"
string="预览" string="预览"
type="object" type="action"
class="oe_highlight" attrs="{'invisible': [('is_out_check', '=', False)]}"/> class="oe_highlight" attrs="{'invisible': [('is_out_check', '=', False)]}"/>
<!-- --><!-- 如果还需要打印按钮 --> <!-- --><!-- 如果还需要打印按钮 -->
<!-- <button name="%(sf_quality.action_report_quality_inspection)d" --> <!-- <button name="%(sf_quality.action_report_quality_inspection)d" -->
<!-- string="打印报告" --> <!-- string="打印报告" -->
<!-- type="action"/> --> <!-- type="action"/> -->
<!-- <button name="do_preview" string="预览" type="object" class="btn-primary" attrs="{'invisible': [('is_out_check', '=', False)]}"/> --> <!-- <button name="do_preview" string="预览" type="object" class="btn-primary" attrs="{'invisible': [('is_out_check', '=', False)]}"/> -->
<button name="preview_do_publish" string="发布" type="object" class="btn-primary" attrs="{'invisible': ['|', ('is_out_check', '=', False), ('publish_status', '!=', 'draft')]}"/> <button name="do_publish" string="发布" type="object" class="btn-primary" attrs="{'invisible': ['|', ('is_out_check', '=', False), ('publish_status', '!=', 'draft')]}"/>
<!-- <button name="get_report_url" string="ceshi" type="object" class="btn-primary"/> --> <!-- <button name="get_report_url" string="ceshi" type="object" class="btn-primary"/> -->
<!-- <button name="upload_factory_report" string="upload_factory_report" type="object" class="btn-primary"/> --> <!-- <button name="upload_factory_report" string="upload_factory_report" type="object" class="btn-primary"/> -->
<button name="do_cancel_publish" string="取消发布" type="object" class="btn-primary" confirm="确定取消发布吗?" attrs="{'invisible': ['|',('is_out_check', '=', False), ('publish_status', '!=', 'published')]}"/> <button name="do_cancel_publish" string="取消发布" type="object" class="btn-primary" confirm="确定取消发布吗?" attrs="{'invisible': ['|',('is_out_check', '=', False), ('publish_status', '!=', 'published')]}"/>
<button name="preview_do_publish" string="重新发布" type="object" class="btn-primary" attrs="{'invisible': ['|', ('is_out_check', '=', False), ('publish_status', '!=', 'canceled')]}"/> <button name="do_re_publish" string="重新发布" type="object" class="btn-primary" attrs="{'invisible': ['|', ('is_out_check', '=', False), ('publish_status', '!=', 'canceled')]}"/>
</xpath>
<xpath expr="//field[@name='total_qty']" position="before">
<field name="total_qty_readonly" invisible="1"/>
</xpath>
<xpath expr="//field[@name='total_qty']" position="attributes">
<attribute name="attrs">{
'invisible': ['&amp;', '|', ('measure_on', '!=', 'product'), ('is_out_check', '=', False), '|', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False)],
'readonly': [('total_qty_readonly', '=', True)],
'on_change': ['|', ('measure_on', '!=', 'move_line'), ('workorder_id', '=', False)]
}</attribute>
</xpath>
<xpath expr="//field[@name='total_qty']" position="after">
<label for="workorder_qty_to_test"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), '&amp;', ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
<div class="o_row"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), '&amp;', ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}">
<field name="workorder_qty_to_test" attrs="{'readonly': 0, 'on_chnage': 1}"/>
<field name="uom_id"/>
</div>
<label for="workorder_qty_tested"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), '&amp;', ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
<div class="o_row"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), '&amp;', ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}">
<field name="workorder_qty_tested" attrs="{'readonly': [('quality_state', '!=', 'none')], 'on_chnage': 1}"/>
<field name="uom_id"/>
</div>
<label for="workorder_qty_test_failed"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), '&amp;', ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}"/>
<div class="o_row"
attrs="{'invisible': ['|', ('measure_on', '!=', 'move_line'), '&amp;', ('workorder_id', '=', False), ('is_lot_tested_fractionally', '=', False)]}">
<field name="workorder_qty_test_failed" attrs="{'readonly': [('quality_state', '!=', 'none')], 'on_chnage': 1}"/>
<field name="uom_id"/>
</div>
</xpath>
<xpath expr="//label[@for='qty_tested']" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False), '&amp;', ('measure_on', '=', 'move_line'), ('workorder_id', '!=', False)]}</attribute>
</xpath>
<xpath expr="//div[@class='o_row'][.//field[@name='qty_tested']]" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', ('measure_on', '!=', 'move_line'), ('is_lot_tested_fractionally', '=', False), '&amp;', ('measure_on', '=', 'move_line'), ('workorder_id', '!=', False)]}</attribute>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -17,7 +17,6 @@
'wizard/sale_order_wizard_views.xml', 'wizard/sale_order_wizard_views.xml',
'wizard/purchase_order_wizard_views.xml', 'wizard/purchase_order_wizard_views.xml',
'data/cron_data.xml', 'data/cron_data.xml',
'data/documents_data.xml',
'views/sale_team.xml', 'views/sale_team.xml',
'views/sale_order_view.xml', 'views/sale_order_view.xml',
'views/res_partner_view.xml', 'views/res_partner_view.xml',

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- 创建采购合同文件夹 -->
<record id="documents_sales_contracts_folder" model="documents.folder">
<field name="name">销售合同</field>
<field name="description">存放销售合同相关文件</field>
<field name="sequence">8</field>
</record>
<record id="documents_sales_contracts_folder_1" model="documents.folder">
<field name="name">下单凭证</field>
<field name="parent_folder_id" ref="documents_sales_contracts_folder"/>
</record>
</data>
</odoo>

View File

@@ -63,15 +63,9 @@ class ReSaleOrder(models.Model):
model_display_version = fields.Char('模型展示版本', default="v1") model_display_version = fields.Char('模型展示版本', default="v1")
contract_code = fields.Char('合同编号')
contract_date = fields.Date('合同日期')
contract_document_id = fields.Many2one('documents.document', string='合同文件')
contract_file = fields.Binary(related='contract_document_id.datas', string='合同文件内容')
contract_file_name = fields.Char(related='contract_document_id.attachment_id.name', string='文件名')
# 业务平台分配工厂后在智能工厂先创建销售订单 # 业务平台分配工厂后在智能工厂先创建销售订单
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address, def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
deadline_of_delivery, payments_way, pay_way, order_number, remark, state='sale', deadline_of_delivery, payments_way, pay_way, order_number, state='sale',
model_display_version='v1'): model_display_version='v1'):
now_time = datetime.datetime.now() now_time = datetime.datetime.now()
partner = self.get_customer() partner = self.get_customer()
@@ -90,7 +84,6 @@ class ReSaleOrder(models.Model):
'pay_way': pay_way, 'pay_way': pay_way,
'order_code': order_number, 'order_code': order_number,
'model_display_version': model_display_version, 'model_display_version': model_display_version,
'remark': remark,
} }
if deadline_of_delivery: if deadline_of_delivery:
# deadline_of_delivery字段存在为false字符串情况 # deadline_of_delivery字段存在为false字符串情况
@@ -201,15 +194,18 @@ class ReSaleOrder(models.Model):
@api.depends('order_line.purchase_line_ids.order_id') @api.depends('order_line.purchase_line_ids.order_id')
def _compute_purchase_order_count(self): def _compute_purchase_order_count(self):
for order in self: for order in self:
order.purchase_order_count = len(order._get_sale_to_purchase('outsourcing')) order.purchase_order_count = len(order._get_purchase_orders().filtered(
order.consignment_purchase_order_count = len(order._get_sale_to_purchase_1('outsourcing')) lambda po: po.purchase_type not in ['outsourcing']))
order.consignment_purchase_order_count = len(order._get_purchase_orders().filtered(
lambda po: po.purchase_type in ['outsourcing']))
def action_view_purchase_orders(self): def action_view_purchase_orders(self):
""" """
采购 采购
""" """
self.ensure_one() self.ensure_one()
purchase_order_ids = self._get_sale_to_purchase('outsourcing') purchase_order_ids = self._get_purchase_orders().filtered(
lambda po: po.purchase_type not in ['outsourcing']).ids
action = { action = {
'res_model': 'purchase.order', 'res_model': 'purchase.order',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
@@ -227,20 +223,13 @@ class ReSaleOrder(models.Model):
}) })
return action return action
def _get_sale_to_purchase(self, purchase_type):
"""查询满足条件的采购订单"""
purchase_order_ids = self._get_purchase_orders().filtered(
lambda po: po.purchase_type not in ['outsourcing']).ids
order_ids = self.env['purchase.order'].sudo().search(
[('origin', '=', self.name), ('purchase_type', '!=', purchase_type)]).ids
return list(set(purchase_order_ids) | set(order_ids))
def action_view_consignment_purchase_orders(self): def action_view_consignment_purchase_orders(self):
""" """
委外加工 委外加工
""" """
self.ensure_one() self.ensure_one()
outsourcing_purchase_order_ids = self._get_sale_to_purchase_1('outsourcing') outsourcing_purchase_order_ids = self._get_purchase_orders().filtered(
lambda po: po.purchase_type in ['outsourcing']).ids
action = { action = {
'res_model': 'purchase.order', 'res_model': 'purchase.order',
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
@@ -258,14 +247,6 @@ class ReSaleOrder(models.Model):
}) })
return action return action
def _get_sale_to_purchase_1(self, purchase_type):
"""查询满足条件的采购订单"""
purchase_order_ids = self._get_purchase_orders().filtered(
lambda po: po.purchase_type == purchase_type).ids
order_ids = self.env['purchase.order'].sudo().search(
[('origin', '=', self.name), ('purchase_type', '=', purchase_type)]).ids
return list(set(purchase_order_ids) | set(order_ids))
class ResaleOrderLine(models.Model): class ResaleOrderLine(models.Model):
_inherit = 'sale.order.line' _inherit = 'sale.order.line'
@@ -365,10 +346,10 @@ class RePurchaseOrder(models.Model):
if purchase.order_line[0].product_id.categ_id.name == '坯料': if purchase.order_line[0].product_id.categ_id.name == '坯料':
if purchase.order_line[0].product_id.materials_type_id.gain_way == '外协': if purchase.order_line[0].product_id.materials_type_id.gain_way == '外协':
purchase.purchase_type = 'outsourcing' purchase.purchase_type = 'outsourcing'
# request_lines = self.order_line.mapped('purchase_request_lines') request_lines = self.order_line.mapped('purchase_request_lines')
# # 检查是否存在 is_subcontract 为 True 的行 # 检查是否存在 is_subcontract 为 True 的行
# if any(line.is_subcontract for line in request_lines): if any(line.is_subcontract for line in request_lines):
# purchase.purchase_type = 'consignment' purchase.purchase_type = 'consignment'
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')], delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
@@ -377,13 +358,12 @@ class RePurchaseOrder(models.Model):
@api.depends('partner_id') @api.depends('partner_id')
def _compute_user_id(self): def _compute_user_id(self):
for item in self: if not self.user_id:
if not item.user_id: if self.partner_id:
if item.partner_id: self.user_id = self.partner_id.purchase_user_id.id
item.user_id = item.partner_id.purchase_user_id.id # self.state = 'purchase'
# self.state = 'purchase' else:
else: self.user_id = self.env.user.id
item.user_id = item.env.user.id
@api.constrains('order_line') @api.constrains('order_line')
def check_order_line(self): def check_order_line(self):
@@ -404,28 +384,28 @@ class RePurchaseOrder(models.Model):
if not line.taxes_id: if not line.taxes_id:
raise UserError('请对【产品】中的【税】进行选择') raise UserError('请对【产品】中的【税】进行选择')
# def get_purchase_request(self, consecutive_process_parameters, production): def get_purchase_request(self, consecutive_process_parameters, production):
# result = [] result = []
# for pp in consecutive_process_parameters: for pp in consecutive_process_parameters:
# server_template = self.env['product.template'].search( server_template = self.env['product.template'].search(
# [('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id), [('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
# ('detailed_type', '=', 'service')]) ('detailed_type', '=', 'service')])
# # route_ids # route_ids
# result.append({ result.append({
# "product_id": server_template.product_variant_id.id, "product_id": server_template.product_variant_id.id,
# 'related_product': production.product_id.id, 'related_product': production.product_id.id,
# "name": production.procurement_group_id.name, "name": production.procurement_group_id.name,
# "date_required": fields.Datetime.now(), "date_required": fields.Datetime.now(),
# "product_uom_id":server_template.uom_id.id, "product_uom_id":server_template.uom_id.id,
# "product_qty": production.product_qty, "product_qty": production.product_qty,
# "request_id": False, "request_id": False,
# "move_dest_ids": False, "move_dest_ids": False,
# "orderpoint_id": False, "orderpoint_id": False,
# 'is_subcontract':True, 'is_subcontract':True,
# 'group_id':production.procurement_group_id.id, 'group_id':production.procurement_group_id.id,
# 'production_name':pp.production_id.name, 'production_name':pp.production_id.name,
# }) })
# return result return result
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):
for pp in consecutive_process_parameters: for pp in consecutive_process_parameters:

View File

@@ -198,20 +198,7 @@
</div> </div>
<field name="date_order" attrs="{'invisible': [('state', 'in', ['done', 'cancel'])], 'required': True}" nolabel="1"/> <field name="date_order" attrs="{'invisible': [('state', 'in', ['done', 'cancel'])], 'required': True}" nolabel="1"/>
</xpath> </xpath>
<xpath expr="//notebook/page[@name='customer_signature']" position="after">
<page string="合同" name="contract_documents"
attrs="{'invisible': [('contract_document_id', '=', False)]}">
<group>
<group>
<field name="contract_document_id" invisible="1"/>
<field name="contract_file_name" invisible="1"/>
<field name="contract_file"
widget="adaptive_viewer"
filename="contract_file_name"/>
</group>
</group>
</page>
</xpath>
</field> </field>
</record> </record>

View File

@@ -58,6 +58,20 @@ class FunctionalCuttingToolEntity(models.Model):
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools', safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
string='功能刀具安全库存', readonly=True) string='功能刀具安全库存', readonly=True)
@api.onchange('functional_tool_status')
def _onchange_functional_tool_status(self):
for item in self:
if item:
if item.functional_tool_status == '报警':
self.create_tool_dismantle()
def set_functional_tool_status(self):
# self.write({
# 'functional_tool_status': '报警'
# })
self.functional_tool_status = '报警'
self.create_tool_dismantle()
def create_tool_dismantle(self): def create_tool_dismantle(self):
for item in self: for item in self:
# 创建报警刀具拆解单 # 创建报警刀具拆解单
@@ -136,17 +150,6 @@ class FunctionalCuttingToolEntity(models.Model):
else: else:
# 原刀从线边出库 # 原刀从线边出库
item.tool_in_out_stock_location_1(location_id, tool_room_id) item.tool_in_out_stock_location_1(location_id, tool_room_id)
# 系统中该刀在线边刀架其他位置,需先清除这个位置的刀具信息
shelf_location_id = self.env['sf.shelf.location'].sudo().search([
('product_sn_id', '=', item.barcode_id.id)])
if shelf_location_id:
shelf_location_id.write(
{'product_id': None,
'product_sn_id': None,
'tool_rfid': None,
"tool_name_id": None,
'product_num': 0,
'location_status': '空闲'})
# 新刀入库到线边 # 新刀入库到线边
item.create_stock_move(pre_manufacturing_id, location_id) item.create_stock_move(pre_manufacturing_id, location_id)
item.current_shelf_location_id = location_id.id item.current_shelf_location_id = location_id.id

View File

@@ -42,6 +42,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form create="0" edit="0" delete="0"> <form create="0" edit="0" delete="0">
<header> <header>
<button name="set_functional_tool_status" string="报警" type="object" invisible="1"/>
<!-- <button name="enroll_functional_tool_entity" string="功能刀具注册" type="object"--> <!-- <button name="enroll_functional_tool_entity" string="功能刀具注册" type="object"-->
<!-- class="btn-primary"/>--> <!-- class="btn-primary"/>-->
<field name="functional_tool_status" widget="statusbar" statusbar_visible="正常,报警,已拆除"/> <field name="functional_tool_status" widget="statusbar" statusbar_visible="正常,报警,已拆除"/>

View File

@@ -107,47 +107,37 @@ class MrsShelfLocationDataSync(models.Model):
equipment_id.register_equipment_tool() equipment_id.register_equipment_tool()
shelfinfo = self.env['sf.shelf.location'].get_sf_shelf_location_info() shelfinfo = self.env['sf.shelf.location'].get_sf_shelf_location_info()
self.set_shelf_location(shelfinfo) total_data = self.get_total_data()
print('shelfinfo:', shelfinfo)
for item in shelfinfo:
logging.info('货架已获取信息:%s' % item)
shelf_barcode = self.find_our_code(total_data, item['Postion'])
location_id = self.env['sf.shelf.location'].search([('barcode', '=', shelf_barcode)], limit=1)
if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
# 修改功能刀具状态
if item.get('State') == '报警':
if tool.functional_tool_status != item.get('State'):
tool.write({
'functional_tool_status': item['State']
})
else:
location_id.product_sn_id = False
if item['RfidCode']:
logging.info('Rfid为【%s】的功能刀具在系统中不存在!' % item['RfidCode'])
else:
stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1)
if stock_lot_obj:
location_id.product_sn_id = stock_lot_obj.id
else:
location_id.product_sn_id = False
except Exception as e: except Exception as e:
logging.info("库区信息同步失败:%s" % e) logging.info("库区信息同步失败:%s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员") raise ValidationError("数据错误导致同步失败,请联系管理员")
def set_shelf_location(self, shelfinfo):
print('shelfinfo:', shelfinfo)
total_data = self.get_total_data()
for item in shelfinfo:
logging.info('货架已获取信息:%s' % item)
shelf_barcode = self.env['sf.shelf.location.datasync'].sudo().find_our_code(
total_data, item['Postion'])
location_id = self.env['sf.shelf.location'].sudo().search(
[('barcode', '=', shelf_barcode)],
limit=1)
if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.sudo().tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
if item.get('State') == '报警' and tool.functional_tool_status != '报警':
# 创建报警刀具拆解单和刀具报警记录
tool.create_tool_dismantle()
# 修改功能刀具标准状态值和已使用寿命值、功能刀具状态
if 'LifeStd' in item and 'LifeUse' in item:
tool.sudo().write({
'max_lifetime_value': item['LifeStd'],
'used_value': item['LifeUse'],
'functional_tool_status': item['State'],
})
else:
location_id.product_sn_id = False
if item['RfidCode']:
logging.info('Rfid为【%s】的功能刀具在系统中不存在!' % item['RfidCode'])
else:
stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1)
if stock_lot_obj:
location_id.product_sn_id = stock_lot_obj.id
else:
location_id.product_sn_id = False