Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/制造功能优化

This commit is contained in:
mgw
2024-12-18 16:56:53 +08:00
19 changed files with 352 additions and 56 deletions

View File

@@ -24,6 +24,7 @@
'wizard/production_wizard_views.xml', 'wizard/production_wizard_views.xml',
'wizard/production_technology_wizard_views.xml', 'wizard/production_technology_wizard_views.xml',
'wizard/production_technology_re_adjust_wizard_views.xml', 'wizard/production_technology_re_adjust_wizard_views.xml',
'wizard/mrp_workorder_batch_replan_wizard_views.xml',
'views/mrp_views_menus.xml', 'views/mrp_views_menus.xml',
'views/agv_scheduling_views.xml', 'views/agv_scheduling_views.xml',
'views/stock_lot_views.xml', 'views/stock_lot_views.xml',
@@ -38,6 +39,7 @@
'views/sf_maintenance_equipment.xml', 'views/sf_maintenance_equipment.xml',
'views/res_config_settings_views.xml', 'views/res_config_settings_views.xml',
'views/sale_order_views.xml', 'views/sale_order_views.xml',
'views/mrp_workorder_batch_replan.xml',
], ],
'assets': { 'assets': {

View File

@@ -8,6 +8,7 @@ import re
import requests import requests
from itertools import groupby from itertools import groupby
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
@@ -18,6 +19,7 @@ class MrpProduction(models.Model):
_inherit = 'mrp.production' _inherit = 'mrp.production'
_description = "制造订单" _description = "制造订单"
_order = 'create_date desc' _order = 'create_date desc'
sale_order_id = fields.Many2one('sale.order', string='销售订单', compute='_compute_sale_order_id', store=True)
deadline_of_delivery = fields.Date('订单交期', tracking=True, compute='_compute_deadline_of_delivery') deadline_of_delivery = fields.Date('订单交期', tracking=True, compute='_compute_deadline_of_delivery')
# tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘") # tray_ids = fields.One2many('sf.tray', 'production_id', string="托盘")
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests") maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Number of maintenance requests")
@@ -34,6 +36,29 @@ class MrpProduction(models.Model):
tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True) tool_state_remark = fields.Text(string='功能刀具状态备注(缺刀)', compute='_compute_tool_state_remark', store=True)
tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True) tool_state_remark2 = fields.Text(string='功能刀具状态备注(无效刀)', readonly=True)
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_sale_order_id(self):
for production in self:
# 初始化 sale_order_id 为 False
sale_order_id = False
# 使用正则表达式查找产品名称中的 'S' 开头的字母数字字符串
match = re.search(r'S\d+', production.product_id.with_context(lang='zh_CN').name) # 从字符串开始匹配
if match:
result = match.group(0)
try:
# 查找与匹配的字符串相符的销售订单
sale_order = self.env['sale.order'].search(
[('name', '=', result)], limit=1, order='id asc'
)
if sale_order:
production.sale_order_id = sale_order.id
else:
logging.warning("No sale order found for production {} with product {} (name match: {})".format(
production.id, production.product_id.name, result))
except Exception as e:
logging.error("Error while fetching sale order for production {}: {}".format(production.id, str(e)))
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id') @api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_deadline_of_delivery(self): def _compute_deadline_of_delivery(self):
for production in self: for production in self:
@@ -378,16 +403,37 @@ class MrpProduction(models.Model):
if process_parameters: if process_parameters:
raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters))) raise UserError(_("【工艺设计】-【参数】为%s的在【产品】中不存在,请先创建", ", ".join(process_parameters)))
if production_confirmed: if production_confirmed:
return { production_count = self.env['mrp.production'].search_count([
'name': _('退回调整'), ('origin', '=', self.origin),
'type': 'ir.actions.act_window', ('product_id', '=', self.product_id.id),
'view_mode': 'form', ('state', '=', 'confirmed')
'res_model': 'sf.production.technology.re_adjust.wizard', ])
'target': 'new', if production_count > 1:
'context': { return {
'default_production_id': self.id, 'name': _('退回调整'),
'default_origin': self.origin, 'type': 'ir.actions.act_window',
}} 'views': [(self.env.ref(
'sf_manufacturing.sf_production_technology_re_adjust_wizard_form_view').id,
'form')],
'res_model': 'sf.production.technology.re_adjust.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_origin': self.origin,
}}
else:
return {
'name': _('退回调整'),
'type': 'ir.actions.act_window',
'views': [(self.env.ref(
'sf_manufacturing.sf_production_technology_re_adjust_wizard_confirm_form_view').id,
'form')],
'res_model': 'sf.production.technology.re_adjust.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_origin': self.origin,
}}
# 工艺确认 # 工艺确认
def technology_confirm(self): def technology_confirm(self):
@@ -441,16 +487,37 @@ class MrpProduction(models.Model):
error_panel.append(design.panel) error_panel.append(design.panel)
else: else:
if not error_panel and not process_parameters: if not error_panel and not process_parameters:
return { production_count = self.env['mrp.production'].search_count([
'name': _('工艺确认'), ('origin', '=', self.origin),
'type': 'ir.actions.act_window', ('product_id', '=', self.product_id.id),
'view_mode': 'form', ('state', '=', 'technology_to_confirmed')
'res_model': 'sf.production.technology.wizard', ])
'target': 'new', if production_count > 1:
'context': { return {
'default_production_id': self.id, 'name': _('工艺确认'),
'default_origin': self.origin, 'type': 'ir.actions.act_window',
}} 'views': [(self.env.ref(
'sf_manufacturing.sf_production_technology_wizard_form_view').id,
'form')],
'res_model': 'sf.production.technology.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_origin': self.origin,
}}
else:
return {
'name': _('工艺确认'),
'type': 'ir.actions.act_window',
'views': [(self.env.ref(
'sf_manufacturing.sf_production_technology_wizard_confirm_form_view').id,
'form')],
'res_model': 'sf.production.technology.wizard',
'target': 'new',
'context': {
'default_production_id': self.id,
'default_origin': self.origin,
}}
if error_panel: if error_panel:
raise UserError(_("【加工面】为%s的标准工序顺序有误,请调整后重试", ", ".join(error_panel))) raise UserError(_("【加工面】为%s的标准工序顺序有误,请调整后重试", ", ".join(error_panel)))
return True return True
@@ -762,7 +829,7 @@ class MrpProduction(models.Model):
# 立即创建外协出入库单和采购订单 # 立即创建外协出入库单和采购订单
# self.env['stock.picking'].create_outcontract_picking(workorder, production) # self.env['stock.picking'].create_outcontract_picking(workorder, production)
# self.env['purchase.order'].get_purchase_order(workorder, production, # self.env['purchase.order'].get_purchase_order(workorder, production,
# product_id_to_production_names) # product_id_to_production_names)
consecutive_workorders = [] consecutive_workorders = []
# 处理最后一个组,即使它可能只有一个工作订单 # 处理最后一个组,即使它可能只有一个工作订单
@@ -774,6 +841,7 @@ class MrpProduction(models.Model):
for workorders in reversed(proc_workorders): for workorders in reversed(proc_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)
# 工单排序 # 工单排序
def _reset_work_order_sequence1(self, k): def _reset_work_order_sequence1(self, k):
for rec in self: for rec in self:
@@ -888,7 +956,7 @@ class MrpProduction(models.Model):
# 对工单进行逐个插入 # 对工单进行逐个插入
for work_id in work_ids: for work_id in work_ids:
for order_id in rec.workorder_ids.filtered(lambda item: item.sequence > 0): for order_id in rec.workorder_ids.filtered(lambda item: item.sequence > 0):
if work_id.name == order_id.name: if work_id.name == order_id.name and work_id.processing_panel == order_id.processing_panel:
work_id.sequence = order_id.sequence + 1 work_id.sequence = order_id.sequence + 1
break break
# 对该工单之后的工单工序进行加一 # 对该工单之后的工单工序进行加一
@@ -1170,7 +1238,9 @@ class MrpProduction(models.Model):
lambda wk: (wk.name == result_id.routing_type and wk.processing_panel == result_id.processing_panel lambda wk: (wk.name == result_id.routing_type and wk.processing_panel == result_id.processing_panel
and wk.state == 'done')).id and wk.state == 'done')).id
for result_id in result_ids] for result_id in result_ids]
workorder_ids = self.workorder_ids.filtered(
lambda wk: wk.technology_design_id.routing_tag == 'standard' and wk.state not in ['rework', 'cancel'])
logging.info('标准工艺工单【%s' % workorder_ids)
return { return {
'name': _('返工'), 'name': _('返工'),
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
@@ -1179,7 +1249,7 @@ class MrpProduction(models.Model):
'target': 'new', 'target': 'new',
'context': { 'context': {
'default_production_id': self.id, 'default_production_id': self.id,
'default_workorder_ids': self.workorder_ids.ids, 'default_workorder_ids': workorder_ids.ids if workorder_ids.ids != [] else self.workorder_ids.ids,
'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '', 'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '',
'default_reprogramming_num': cloud_programming['reprogramming_num'], 'default_reprogramming_num': cloud_programming['reprogramming_num'],
'default_programming_state': cloud_programming['programming_state'], 'default_programming_state': cloud_programming['programming_state'],
@@ -1435,6 +1505,26 @@ class MrpProduction(models.Model):
for production in self: for production in self:
production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工' production.production_type = '自动化产线加工' if not production.product_id.is_manual_processing else '人工线下加工'
@api.depends('procurement_group_id.mrp_production_ids.move_dest_ids.group_id.sale_id')
def _compute_sale_order_count(self):
for production in self:
if production.sale_order_id:
production.sale_order_count = 1
else:
production.sale_order_count = 0
def action_view_sale_orders(self):
if self.sale_order_id:
action = {
'res_model': 'sale.order',
'type': 'ir.actions.act_window',
}
action.update({
'view_mode': 'form',
'res_id': self.sale_order_id.id,
})
return action
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
""" """
@@ -1495,7 +1585,9 @@ class MrpProduction(models.Model):
def action_view_purchase_orders(self): def action_view_purchase_orders(self):
self.ensure_one() self.ensure_one()
if self.product_id.product_tmpl_id.single_manufacturing == True: if self.is_remanufacture:
production = self
elif self.product_id.product_tmpl_id.single_manufacturing == True:
production = self.env['mrp.production'].search( production = self.env['mrp.production'].search(
[('origin', '=', self.origin), ('product_id', '=', self.product_id.id)], limit=1, order='id asc') [('origin', '=', self.origin), ('product_id', '=', self.product_id.id)], limit=1, order='id asc')
else: else:

View File

@@ -129,7 +129,7 @@ class ResMrpWorkOrder(models.Model):
Y10_axis = fields.Float(default=0) Y10_axis = fields.Float(default=0)
Z10_axis = fields.Float(default=0) Z10_axis = fields.Float(default=0)
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0) X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
test_results = fields.Selection([("合格", "合格")], default='合格', test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格',
string="检测结果", tracking=True) string="检测结果", tracking=True)
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序") cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序") cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")

View File

@@ -656,8 +656,8 @@ class StockPicking(models.Model):
def create_outcontract_picking(self, workorders, item, sorted_workorders): def create_outcontract_picking(self, workorders, item, sorted_workorders):
for workorder in workorders: for workorder in workorders:
if workorder.move_subcontract_workorder_ids: if workorder.move_subcontract_workorder_ids:
workorder.move_subcontract_workorder_ids.write({'state': 'draft'}) workorder.move_subcontract_workorder_ids.write({'state': 'waiting'})
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'draft'}) workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'waiting'})
else: else:
# 创建一个新的补货组 # 创建一个新的补货组
procurement_group_id = self.env['procurement.group'].create({ procurement_group_id = self.env['procurement.group'].create({
@@ -993,7 +993,8 @@ class ReStockMove(models.Model):
production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc') production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc')
productions = self.env['mrp.production'].search( productions = self.env['mrp.production'].search(
[('origin', '=', production.origin), ('product_id', '=', production.product_id.id)]) [('origin', '=', production.origin), ('product_id', '=', production.product_id.id)])
res['origin'] = ','.join(productions.mapped('name')) if productions.mapped('name'):
res['origin'] = ','.join(productions.mapped('name'))
res['retrospect_ref'] = production.product_id.name res['retrospect_ref'] = production.product_id.name
return res return res

View File

@@ -182,3 +182,5 @@ access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user,sf_manual_pro
access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1 access_sf_manual_product_model_type_routing_sort_manager,sf_manual_product_model_type_routing_sort,model_sf_manual_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,1
access_sf_manual_product_model_type_routing_sort_group_plan_dispatch,sf_manual_product_model_type_routing_sort_group_plan_dispatch,model_sf_manual_product_model_type_routing_sort,sf_base.group_plan_dispatch,1,0,0,0 access_sf_manual_product_model_type_routing_sort_group_plan_dispatch,sf_manual_product_model_type_routing_sort_group_plan_dispatch,model_sf_manual_product_model_type_routing_sort,sf_base.group_plan_dispatch,1,0,0,0
access_sf_detection_result_manager,sf_detection_result_manager,model_sf_detection_result,,1,1,1,1 access_sf_detection_result_manager,sf_detection_result_manager,model_sf_detection_result,,1,1,1,1
access_mrp_workorder_batch_replan_wizard_group_plan_dispatch,mrp_workorder_batch_replan_wizard_group_plan_dispatch,model_mrp_workorder_batch_replan_wizard,sf_base.group_plan_dispatch,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
182
183
184
185
186

View File

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

View File

@@ -0,0 +1,18 @@
<odoo>
<data>
<record id="mrp_production_workorder_tree_editable_view_inherit" model="ir.ui.view">
<field name="name">>mrp.workorder.tree.editable.inherit</field>
<field name="model">mrp.workorder</field>
<field name="inherit_id" ref="mrp.mrp_production_workorder_tree_editable_view"/>
<field name="arch" type="xml">
<xpath expr="//tree/field[1]" position="before">
<header>
<button string="重新安排" name="%(sf_manufacturing.mrp_workorder_batch_replan_wizard)d" type="action"
class="treeHeaderBtn"
invisible="context.get('workorder_type') not in ('工件装夹中心','1#自动生产线','工件拆卸中心')"/>
</header>
</xpath>
</field>
</record>
</data>
</odoo>

View File

@@ -104,8 +104,7 @@
<!-- <field name="target">fullscreen</field>--> <!-- <field name="target">fullscreen</field>-->
<field name="target">current</field> <field name="target">current</field>
<field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field> <field name="domain">[('state', '!=', 'cancel'),('schedule_state', '=', '已排')]</field>
<field name="context">{'search_default_product': 1, 'search_default_workcenter_id': <field name="context">{'search_default_product': 1, 'search_default_workcenter_id': active_id}
active_id,'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1,'search_default_filter_order_normal':1}
</field> </field>
<field name="help" type="html"> <field name="help" type="html">
<p class="o_view_nocontent_workorder"> <p class="o_view_nocontent_workorder">
@@ -200,7 +199,7 @@
<!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> --> <!-- attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked'),('state','=','done')]}"/> -->
<!-- <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"--> <!-- <button name="button_workpiece_delivery" type="object" string="工件配送" class="btn-primary"-->
<!-- attrs="{'invisible': ['|','|','|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done'),('is_rework','=',True),'&amp;',('rfid_code','in',['',False]),('state','=','done')]}"/>--> <!-- attrs="{'invisible': ['|','|','|','|',('routing_type','!=','装夹预调'),('is_delivery','=',True),('state','!=','done'),('is_rework','=',True),'&amp;',('rfid_code','in',['',False]),('state','=','done')]}"/>-->
<button name="button_rework_pre" type="object" string="异常反馈" invisible="1" <button name="button_rework_pre" type="object" string="异常反馈"
class="btn-primary" class="btn-primary"
attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/> attrs="{'invisible': ['|','|',('routing_type','!=','装夹预调'),('state','!=','progress'),('is_rework','=',True)]}"/>
<button name="unbind_tray" type="object" string="解绑托盘" <button name="unbind_tray" type="object" string="解绑托盘"

View File

@@ -3,3 +3,4 @@ from . import rework_wizard
from . import production_wizard from . import production_wizard
from . import production_technology_wizard from . import production_technology_wizard
from . import production_technology_re_adjust_wizard from . import production_technology_re_adjust_wizard
from . import mrp_workorder_batch_replan_wizard

View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
import logging
from datetime import datetime, timedelta
from odoo import models, api, fields, _
class MrpWorkorderBatchReplanWizard(models.TransientModel):
_name = 'mrp.workorder.batch.replan.wizard'
_description = '制造订单批量重新安排向导'
def _get_date_planned_start(self):
planned_start_date = datetime.now() + timedelta(hours=2)
logging.info('计划开始加工时间: %s', planned_start_date)
return planned_start_date
def _get_default_workorder_count(self):
active_ids = self.env.context.get('active_ids', [])
return len(active_ids)
def _get_default_workorder_type(self):
active_ids = self.env.context.get('active_ids', [])
if active_ids:
workorders = self.env['mrp.workorder'].browse(active_ids)
if workorders:
routing_type = set(workorders.mapped('routing_type'))
return '/'.join(sorted(routing_type)) if routing_type else None
return None
workorder_type = fields.Char(string='工单类型', default=_get_default_workorder_type, readonly=True)
workorder_count = fields.Integer(string='工单数量',
default=_get_default_workorder_count,
readonly=True)
workorder_id = fields.Many2many('mrp.workorder', string=u'工单')
def confirm(self):
routing_type = set(self.workorder_id.mapped('routing_type'))
if len(routing_type) > 1:
raise models.ValidationError("批量重新安排工单类型必须一致。")
show_json_popover = self.workorder_id.mapped('show_json_popover')
if any(not value for value in show_json_popover):
raise models.ValidationError("所选工单必须都为逾期状态")
failed_workorders = {}
for workorder_info in self.workorder_id:
try:
workorder_info.action_replan()
except Exception as e:
reason = str(e)
if reason in failed_workorders:
failed_workorders[reason].append(
workorder_info.production_id.name)
else:
failed_workorders[reason] = [workorder_info.production_id.name]
if failed_workorders:
error_messages = "\n".join(
[f"制造订单: {', '.join(workorder_names)}, 原因: {reason}" for reason, workorder_names in
failed_workorders.items()])
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': f"以下工单重新安排失败:\n{error_messages}",
'sticky': False,
'color': 'red',
'next': {
'type': 'ir.actions.act_window_close'
}
},
}

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="mrp_workorder_batch_replan_wizard_form" model="ir.ui.view">
<field name="name">mrp.workorder.batch.replan.wizard.form.view</field>
<field name="model">mrp.workorder.batch.replan.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<field name="workorder_type"/>
<field name="workorder_count"/>
</group>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight"/>
<button string="取消" class="btn-primary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="mrp_workorder_batch_replan_wizard" model="ir.actions.act_window">
<field name="name">重新安排工单</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">mrp.workorder.batch.replan.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="mrp_workorder_batch_replan_wizard_form"/>
<field name="target">new</field>
<field name="context">{'default_workorder_id': active_ids}</field>
</record>
</odoo>

View File

@@ -21,6 +21,26 @@
</field> </field>
</record> </record>
<record model="ir.ui.view" id="sf_production_technology_re_adjust_wizard_confirm_form_view">
<field name="name">sf.production.technology.re_adjust.wizard.form.view</field>
<field name="model">sf.production.technology.re_adjust.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="production_id" invisible="1"/>
<field name="origin" invisible="1"/>
<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>
<record id="action_sf_production_technology_re_adjust_wizard" model="ir.actions.act_window"> <record id="action_sf_production_technology_re_adjust_wizard" model="ir.actions.act_window">
<field name="name">工艺退回调整</field> <field name="name">工艺退回调整</field>
<field name="res_model">sf.production.technology.re_adjust.wizard</field> <field name="res_model">sf.production.technology.re_adjust.wizard</field>

View File

@@ -14,7 +14,7 @@ class ProductionTechnologyWizard(models.TransientModel):
is_technology_confirm = fields.Boolean(default=False) is_technology_confirm = fields.Boolean(default=False)
def confirm(self): def confirm(self):
if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type == '成品': if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']:
domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'), domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'),
('product_id', '=', self.production_id.product_id.id)] ('product_id', '=', self.production_id.product_id.id)]
else: else:

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<record model="ir.ui.view" id="sf_production_technology_wizard_form_view"> <record model="ir.ui.view" id="sf_production_technology_wizard_form_view">
<field name="name">sf.production.technology.wizard.form.view</field> <field name="name">sf.production.technology.wizard.form.view</field>
<field name="model">sf.production.technology.wizard</field> <field name="model">sf.production.technology.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
@@ -13,7 +13,28 @@
对当前制造订单,同一销售订单相同产品所生成的制造订单统一进行工艺调整与确认 对当前制造订单,同一销售订单相同产品所生成的制造订单统一进行工艺调整与确认
</div> </div>
<footer> <footer>
<button string="确认" name="confirm" type="object" class="oe_highlight" confirm="是否确认工艺调整"/> <button string="确认" name="confirm" type="object" class="oe_highlight"
confirm="是否确认工艺调整"/>
<button string="取消" class="btn btn-secondary" special="cancel"/>
</footer>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="sf_production_technology_wizard_confirm_form_view">
<field name="name">sf.production.technology.wizard.form.view</field>
<field name="model">sf.production.technology.wizard</field>
<field name="arch" type="xml">
<form>
<sheet>
<field name="production_id" invisible="1"/>
<field name="origin" invisible="1"/>
<div>
是否确认工艺调整
</div>
<footer>
<button string="确认" name="confirm" type="object" class="oe_highlight"/>
<button string="取消" class="btn btn-secondary" special="cancel"/> <button string="取消" class="btn btn-secondary" special="cancel"/>
</footer> </footer>
</sheet> </sheet>

View File

@@ -62,6 +62,36 @@ class ReworkWizard(models.TransientModel):
hidden_workorder_list.sort() hidden_workorder_list.sort()
item.hidden_workorder_ids = ','.join(hidden_workorder_list) item.hidden_workorder_ids = ','.join(hidden_workorder_list)
def efficacy_rework_wo(self, wk_ids):
"""限制判断 """
# 判断检测结果待处理所对应的工单是否勾选
result_ids = self.production_id.detection_result_ids.filtered(lambda dr: dr.handle_result == '待处理')
work_id_list = []
if result_ids:
work_id_list = [self.workorder_ids.filtered(
lambda wk: (wk.name == result_id.routing_type and wk.processing_panel == result_id.processing_panel
and wk.state == 'done')).id
for result_id in result_ids]
if len(wk_ids.filtered(lambda wk: wk.id in work_id_list)) != len(work_id_list):
raise ValidationError('存在【检测结果】为【待处理】所对应的工单未进行勾选!!!')
# 获取已完成的标准工单
grouped_rw_ids = {key: list(group) for key, group in groupby(wk_ids, key=lambda w: w.processing_panel)}
for panel, panel_rw_ids in grouped_rw_ids.items():
# 1、当制造订单内ZM面的工单都已完成时返工勾选工序时只能勾选上ZM面的所有工序进行返工
work_ids = self.workorder_ids.filtered(lambda w: w.state == 'done' and w.processing_panel == panel)
if len(work_ids) == 3 and len(panel_rw_ids) != 3:
raise ValidationError(
'因为[%s]面的工单已全部完成,如果要对[%s]面的工单进行返工,请勾选这个面的所有工单。' % (panel, panel))
# 2、当FM工单在CNC工单进行选择返工并将已全部完成的ZM面工序全部勾选上时FM工单上所有的已完成的工单装夹预调工单也必须进行勾选
if not wk_ids.filtered(lambda wk: wk.name == '装夹预调' and wk.processing_panel == panel):
if wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel):
sequence_max = wk_ids.filtered(lambda wk: wk.name == 'CNC加工' and wk.processing_panel == panel).sequence
for wk_id in wk_ids.filtered(lambda wk: wk.sequence < sequence_max):
if len(wk_ids.filtered(lambda wk: wk.processing_panel == wk_id.processing_panel)) == 3:
raise ValidationError(
'由于在[%s]面之前存在整个面进行了勾选的情况,所以在勾选了[%s]面的【CNC加工】工单的时请勾选[%s]面的装夹预调工单!' % (
panel, panel, panel))
def confirm(self): def confirm(self):
if self.routing_type in ['装夹预调', 'CNC加工']: if self.routing_type in ['装夹预调', 'CNC加工']:
self.is_clamp_measure = False self.is_clamp_measure = False
@@ -79,20 +109,8 @@ class ReworkWizard(models.TransientModel):
if self.hidden_workorder_ids: if self.hidden_workorder_ids:
hidden_workorder_list = self.hidden_workorder_ids.split(',') hidden_workorder_list = self.hidden_workorder_ids.split(',')
rework_workorder_ids = self.workorder_ids.filtered(lambda w: str(w.id) in hidden_workorder_list) rework_workorder_ids = self.workorder_ids.filtered(lambda w: str(w.id) in hidden_workorder_list)
# 限制判断 # 调用效验方法
# 1、当制造订单内ZM面的工单都已完成时返工勾选工序时只能勾选上ZM面的所有工序进行返工 self.efficacy_rework_wo(rework_workorder_ids)
# 2、当FM工单在CNC工单进行选择返工并将已全部完成的ZM面工序全部勾选上时FM工单上所有的已完成的工单装夹预调工单也必须进行勾选
# 获取已完成的标准工单
# done_normative_workorder_ids = self.workorder_ids.filtered(
# lambda w: w.state == 'done' and w.processing_panel is not False)
# # 获取需要返工的标准工单
# rework_normative_workorder_ids = rework_workorder_ids.filtered(
# lambda w: w.processing_panel is not False)
# if rework_normative_workorder_ids:
# for rw in rework_normative_workorder_ids:
# if len(done_normative_workorder_ids.filtered(
# lambda w: w.processing_panel == rw.processing_panel)) == 3:
# pass
else: else:
raise ValidationError('请选择返工工单!!!') raise ValidationError('请选择返工工单!!!')
if rework_workorder_ids: if rework_workorder_ids:
@@ -106,7 +124,7 @@ class ReworkWizard(models.TransientModel):
for clamp_workorder_id in clamp_workorder_ids: for clamp_workorder_id in clamp_workorder_ids:
self.production_id.workorder_ids.filtered( self.production_id.workorder_ids.filtered(
lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write( lambda wk: wk.processing_panel == clamp_workorder_id.processing_panel).write(
{'rfid_code': False}) {'rfid_code': None})
# 返工工单状态设置为【返工】 # 返工工单状态设置为【返工】
rework_workorder_ids.write({'state': 'rework'}) rework_workorder_ids.write({'state': 'rework'})
# 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单 # 查询返工工单对应的工艺设计记录,并调用方法拼接数据,用于创建新的工单
@@ -119,7 +137,7 @@ class ReworkWizard(models.TransientModel):
and item.panel == work.processing_panel)) and item.panel == work.processing_panel))
if route: if route:
work_list = self.env['mrp.workorder'].json_workorder_str(self.production_id, route[0]) work_list = self.env['mrp.workorder'].json_workorder_str(self.production_id, route[0])
work_list[2].update({'tag_type': '重新加工'}) work_list[2].update({'tag_type': '重新加工', 'sequence': 0})
workorders_values.append(work_list) workorders_values.append(work_list)
# 创建新工单,并进行返工配置的相关操作 # 创建新工单,并进行返工配置的相关操作
if workorders_values: if workorders_values:

View File

@@ -14,7 +14,7 @@
<field name="processing_panel_id" invisible="1"/> <field name="processing_panel_id" invisible="1"/>
<field name="hidden_workorder_ids" class="css_not_available_msg"/> <field name="hidden_workorder_ids" class="css_not_available_msg"/>
<group> <group>
<field name="hidden_workorder_ids"/> <field name="hidden_workorder_ids" invisible="1"/>
<field options="{'no_create': True,'no_open': True}" readonly="1" name="workorder_ids" <field options="{'no_create': True,'no_open': True}" readonly="1" name="workorder_ids"
widget="jikimo_subtree_selector_field" widget="jikimo_subtree_selector_field"
jikimo_selector="True" replace_context="hidden_workorder_ids" string="工序" jikimo_selector="True" replace_context="hidden_workorder_ids" string="工序"

View File

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

View File

@@ -169,6 +169,9 @@
<field name="manual_quotation" /> <field name="manual_quotation" />
<field name="is_incoming_material"/> <field name="is_incoming_material"/>
</xpath> </xpath>
<xpath expr="//field[@name='date_order']" position="attributes">
<attribute name="string">下单时间</attribute>
</xpath>
</field> </field>
</record> </record>
@@ -215,8 +218,14 @@
<attribute name="string">订单号</attribute> <attribute name="string">订单号</attribute>
</field> </field>
<field name="create_date" position="attributes"> <field name="create_date" position="attributes">
<attribute name="string">下单时间</attribute> <attribute name="string">下单日期</attribute>
</field> </field>
<xpath expr="//field[@name='activity_ids']" position="attributes">
<attribute name="optional">hide</attribute>
</xpath>
<xpath expr="//field[@name='create_date']" position="after">
<field name="deadline_of_delivery"/>
</xpath>
<!-- <field name="state" position="after"> <!-- <field name="state" position="after">
<field name="check_status" widget="badge" <field name="check_status" widget="badge"
decoration-success="check_status == 'approved'" decoration-success="check_status == 'approved'"
@@ -258,6 +267,15 @@
<field name="amount_total" position="after"> <field name="amount_total" position="after">
<field name="delivery_warning" invisible="1"/> <field name="delivery_warning" invisible="1"/>
</field> </field>
<xpath expr="//field[@name='date_order']" position="after">
<field name="deadline_of_delivery"/>
</xpath>
<xpath expr="//field[@name='activity_ids']" position="attributes">
<attribute name="optional">hide</attribute>
</xpath>
<xpath expr="//field[@name='invoice_status']" position="after">
<field name="state"/>
</xpath>
</field> </field>
</record> </record>
@@ -293,7 +311,7 @@
<record id="sale.action_orders" model="ir.actions.act_window"> <record id="sale.action_orders" model="ir.actions.act_window">
<field name="search_view_id" ref="sale_order_view_search_inherit_sale_message"/> <field name="search_view_id" ref="sale_order_view_search_inherit_sale_message"/>
<field name="context">{ 'search_default_filter_order_warning':1,'search_default_filter_order_overdue':1} <field name="context">{}
</field> </field>
</record> </record>
</data> </data>

View File

@@ -23,7 +23,7 @@
<t t-if="record.workorder_count.raw_value &gt; 0"> <t t-if="record.workorder_count.raw_value &gt; 0">
<button class="btn btn-primary" name="action_work_order" type="object" <button class="btn btn-primary" name="action_work_order" type="object"
attrs="{'invisible': [('name', '=', '功能刀具组装中心')]}" attrs="{'invisible': [('name', '=', '功能刀具组装中心')]}"
context="{'search_default_ready': 1, 'search_default_progress': 1}"> context="{'search_default_ready': 1, 'search_default_progress': 1, 'workorder_type': name}">
<span>工单</span> <span>工单</span>
</button> </button>
</t> </t>