Merge branch 'refs/heads/develop' into feature/delivery_status

# Conflicts:
#	sf_manufacturing/models/mrp_production.py
This commit is contained in:
liaodanlong
2024-12-11 10:07:34 +08:00
40 changed files with 619 additions and 412 deletions

View File

@@ -536,3 +536,7 @@ div:has(.o_required_modifier) > label::before {
position: unset; position: unset;
} }
// 修复搜索面板checkbox样式
.o_search_panel .form-check .form-check-label span {
position: relative;
}

View File

@@ -190,7 +190,7 @@ def _create(self, data_list):
# 如果该用户组被限制创建或更新操作 # 如果该用户组被限制创建或更新操作
if rec['is_create_or_update']: if rec['is_create_or_update']:
raise UserError( raise UserError(
_("You are restricted from performing this operation. Please contact the administrator.")) _("您没有执行此操作的权限。请联系管理员"))
else: else:
# 如果 'access.right' 模型不存在,可以在这里定义备选逻辑 # 如果 'access.right' 模型不存在,可以在这里定义备选逻辑
# 例如,记录日志、发送通知或者简单地跳过这部分逻辑 # 例如,记录日志、发送通知或者简单地跳过这部分逻辑

View File

@@ -6,12 +6,11 @@
'author': 'fox', 'author': 'fox',
'website': '', 'website': '',
'category': '', 'category': '',
'depends': ['sf_dlm', 'sale_stock', 'sf_sale'], 'depends': ['sf_dlm', 'sale_stock', 'sf_sale', 'sale'],
"data": [ "data": [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'data/stock_routes.xml', 'data/stock_routes.xml',
'data/product_data.xml', 'data/product_data.xml',
'views/sale_order_views.xml',
# 'views/product_product_views.xml', # 'views/product_product_views.xml',
],'assets': { ],'assets': {
# 'web.assets_backend': [ # 'web.assets_backend': [

View File

@@ -1,2 +1 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import main

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import product_template from . import product_template
from . import sale_order
from . import mrp_bom from . import mrp_bom

View File

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

View File

@@ -37,6 +37,7 @@
'views/agv_setting_views.xml', 'views/agv_setting_views.xml',
'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',
], ],
'assets': { 'assets': {

View File

@@ -1,2 +1,3 @@
from . import controllers from . import controllers
from . import workpiece from . import workpiece
from . import main

View File

@@ -13,3 +13,5 @@ from . import agv_scheduling
from . import res_config_setting from . import res_config_setting
from . import sf_technology_design from . import sf_technology_design
from . import sf_production_common from . import sf_production_common
from . import sale_order
from . import quick_easy_order

View File

@@ -7,7 +7,7 @@ class ModelType(models.Model):
name = fields.Char('名称') name = fields.Char('名称')
# embryo_tolerance = fields.Char('坯料容余') # embryo_tolerance = fields.Char('坯料容余')
embryo_tolerance_id = fields.Many2one('sf.embryo.redundancy', string='坯料') embryo_tolerance_id = fields.Many2one('sf.embryo.redundancy', string='坯料')
product_routing_tmpl_ids = fields.One2many('sf.product.model.type.routing.sort', 'product_model_type_id', product_routing_tmpl_ids = fields.One2many('sf.product.model.type.routing.sort', 'product_model_type_id',
'成品工序模板(自动化产线加工') '成品工序模板(自动化产线加工')
embryo_routing_tmpl_ids = fields.One2many('sf.embryo.model.type.routing.sort', 'embryo_model_type_id', embryo_routing_tmpl_ids = fields.One2many('sf.embryo.model.type.routing.sort', 'embryo_model_type_id',

View File

@@ -788,7 +788,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 = []
# 处理最后一个组,即使它可能只有一个工作订单 # 处理最后一个组,即使它可能只有一个工作订单

View File

@@ -86,9 +86,12 @@ class ResMrpRoutingWorkcenter(models.Model):
@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('production_id'): if self._context.get('production_id'):
route_ids = []
technology_design = self.env['sf.technology.design'].search( technology_design = self.env['sf.technology.design'].search(
[('production_id', '=', self._context.get('production_id'))]) [('production_id', '=', self._context.get('production_id'))])
route_ids = [t.route_id.id for t in technology_design] for t in technology_design.filtered(lambda a: a.routing_tag == 'special'):
domain = [('id', 'not in', route_ids)] if not t.process_parameters_id:
route_ids.append(t.route_id.surface_technics_id.id)
domain = [('id', 'not in', route_ids), ('routing_tag', '=', 'special')]
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)

View File

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

View File

@@ -859,12 +859,12 @@ class ResProductMo(models.Model):
raise UserError('请先配置模型类型内的坯料冗余') raise UserError('请先配置模型类型内的坯料冗余')
vals = { vals = {
'name': '%s-%s-%s' % ('P', order_id.name, i), 'name': '%s-%s-%s' % ('P', order_id.name, i),
'model_long': item['model_long'] + embryo_redundancy_id.long, 'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long),
'model_width': item['model_width'] + embryo_redundancy_id.width, 'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width),
'model_height': item['model_height'] + embryo_redundancy_id.height, 'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height),
'model_volume': (item['model_long'] + embryo_redundancy_id.long) * ( 'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * (
item['model_width'] + embryo_redundancy_id.width) * ( item['model_width'] + embryo_redundancy_id.width) * (
item['model_height'] + embryo_redundancy_id.height), item['model_height'] + embryo_redundancy_id.height)),
'product_model_type_id': model_type.id, 'product_model_type_id': model_type.id,
'model_processing_panel': item['processing_panel_detail'], 'model_processing_panel': item['processing_panel_detail'],
'model_machining_precision': item['model_machining_precision'], 'model_machining_precision': item['model_machining_precision'],
@@ -907,6 +907,20 @@ class ResProductMo(models.Model):
self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id, self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id,
'quality_standard', item['quality_standard_mimetype']) 'quality_standard', item['quality_standard_mimetype'])
return copy_product_id return copy_product_id
def format_float(self, value):
# 将浮点数转换为字符串
value_str = str(value)
# 检查小数点的位置
if '.' in value_str:
# 获取小数部分
decimal_part = value_str.split('.')[1]
# 判断小数位数是否超过2位
if len(decimal_part) > 2:
# 超过2位则保留2位小数
return "{:.2f}".format(value)
# 否则保持原来的位数
return float(value_str)
def _get_ids(self, param): def _get_ids(self, param):
type_ids = [] type_ids = []

View File

@@ -43,6 +43,8 @@ class SaleOrder(models.Model):
# 复制成品模板上的属性 # 复制成品模板上的属性
line.product_id.product_tmpl_id.copy_template(product_template_id) line.product_id.product_tmpl_id.copy_template(product_template_id)
# 将模板上的single_manufacturing属性复制到成品上
line.product_id.single_manufacturing = product_template_id.single_manufacturing
order_id = self order_id = self
product = line.product_id product = line.product_id

View File

@@ -10,8 +10,14 @@ class SfProductionProcessParameter(models.Model):
@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'):
parameter = []
routing = self.env['mrp.routing.workcenter'].search([('id', '=', self._context.get('route_id'))]) routing = self.env['mrp.routing.workcenter'].search([('id', '=', self._context.get('route_id'))])
domain = [('process_id', '=', routing.surface_technics_id.id)] technology_design = self.env['sf.technology.design'].search(
[('production_id', '=', self._context.get('production_id')), ('routing_tag', '=', 'special'),
('route_id', '=', self._context.get('route_id'))])
for t in technology_design:
if t.process_parameters_id:
parameter.append(t.process_parameters_id.id)
domain = [('process_id', '=', routing.surface_technics_id.id), ('id', 'not in', parameter)]
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)

View File

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

View File

@@ -283,24 +283,24 @@ class StockRule(models.Model):
sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)])
# 如果订单为空,则获取来源制造订单的销售单 # 如果订单为空,则获取来源制造订单的销售单
if not sale_order: if not sale_order:
mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)], limit=1) mrp_production = self.env['mrp.production'].sudo().search([('name', '=', production.origin)],
limit=1)
if mrp_production: if mrp_production:
sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)])
else: else:
mrp_production = production mrp_production = production
if sale_order: # if sale_order:
# sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(company_id).create({ self.env['sf.production.plan'].sudo().with_company(company_id).create({
'name': production.name, 'name': production.name,
'order_deadline': sale_order.deadline_of_delivery, 'order_deadline': sale_order.deadline_of_delivery,
'production_id': production.id, 'production_id': production.id,
'date_planned_start': production.date_planned_start, 'date_planned_start': production.date_planned_start,
'origin': mrp_production.origin, 'origin': mrp_production.origin,
'product_qty': production.product_qty, 'product_qty': production.product_qty,
'product_id': production.product_id.id, 'product_id': production.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
technology_design_values = []
all_production = productions all_production = productions
grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -310,6 +310,7 @@ class StockRule(models.Model):
# 为同一个product_id创建一个生产订单名称列表 # 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in all_production] product_id_to_production_names[product_id] = [production.name for production in all_production]
for production_item in productions: for production_item in productions:
technology_design_values = []
production_programming = self.env['mrp.production'].search( production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id), [('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)], ('origin', '=', production_item.origin)],
@@ -317,77 +318,76 @@ class StockRule(models.Model):
if production_item.product_id.id in product_id_to_production_names: if production_item.product_id.id in product_id_to_production_names:
# 同一个产品多个制造订单对应一个编程单和模型库 # 同一个产品多个制造订单对应一个编程单和模型库
# 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递 # 只调用一次fetchCNC并将所有生产订单的名称作为字符串传递
if not production_item.programming_no and production.production_type == '自动化产线加工': if not production_item.programming_no and production_item.production_type == '自动化产线加工':
if not production_programming.programming_no: if not production_programming.programming_no:
production_item.fetchCNC( production_item.fetchCNC(
', '.join(product_id_to_production_names[production_item.product_id.id])) ', '.join(product_id_to_production_names[production_item.product_id.id]))
else: else:
production_item.write({'programming_no': production_programming.programming_no, production_item.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'}) 'programming_state': '编程中'})
if not technology_design_values: i = 0
i = 0 if production_item.product_id.categ_id.type == '成品':
if production_item.product_id.categ_id.type == '成品': # 根据加工面板的面数及成品工序模板生成工序设计
# 根据加工面板的面数及成品工序模板生成工序设计 if production_item.production_type == '自动化产线加工':
if production_item.production_type == '自动化产线加工': model = 'sf.product.model.type.routing.sort'
model = 'sf.product.model.type.routing.sort' domain = [
domain = [ ('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)] else:
else: model = 'sf.manual.product.model.type.routing.sort'
model = 'sf.manual.product.model.type.routing.sort' domain = [('manual_product_model_type_id', '=',
domain = [('manual_product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
production_item.product_id.product_model_type_id.id)] product_routing_workcenter = self.env[model].search(domain, order='sequence asc')
product_routing_workcenter = self.env[model].search(domain, order='sequence asc') if production_item.production_type == '自动化产线加工':
if production_item.production_type == '自动化产线加工': for k in (production_item.product_id.model_processing_panel.split(',')):
for k in (production_item.product_id.model_processing_panel.split(',')):
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
else:
for route in product_routing_workcenter: for route in product_routing_workcenter:
i += 1 i += 1
technology_design_values.append( technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route, i, False)) self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
elif production_item.product_id.categ_id.type == '坯料': else:
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search( for route in product_routing_workcenter:
[('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
order='sequence asc'
)
for route_embryo in embryo_routing_workcenter:
i += 1 i += 1
technology_design_values.append( technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i, self.env['sf.technology.design'].json_technology_design_str(False, route, i, False))
False)) elif production_item.product_id.categ_id.type == '坯料':
surface_technics_arr = [] embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
route_workcenter_arr = [] [('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids: order='sequence asc'
if item.route_workcenter_id.surface_technics_id.id: )
for process_param in production_item.product_id.model_process_parameters_ids: for route_embryo in embryo_routing_workcenter:
if item.route_workcenter_id.surface_technics_id == process_param.process_id: i += 1
surface_technics_arr.append( technology_design_values.append(
item.route_workcenter_id.surface_technics_id.id) self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i,
route_workcenter_arr.append(item.route_workcenter_id.id) False))
if surface_technics_arr: surface_technics_arr = []
production_process = self.env['sf.production.process'].search( route_workcenter_arr = []
[('id', 'in', surface_technics_arr)], for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
order='sequence asc' if item.route_workcenter_id.surface_technics_id.id:
) for process_param in production_item.product_id.model_process_parameters_ids:
for p in production_process: if item.route_workcenter_id.surface_technics_id == process_param.process_id:
logging.info('production_process:%s' % p.name) surface_technics_arr.append(
process_parameter = production_item.product_id.model_process_parameters_ids.filtered( item.route_workcenter_id.surface_technics_id.id)
lambda pm: pm.process_id.id == p.id) route_workcenter_arr.append(item.route_workcenter_id.id)
if process_parameter: if surface_technics_arr:
i += 1 production_process = self.env['sf.production.process'].search(
route_production_process = self.env[ [('id', 'in', surface_technics_arr)],
'mrp.routing.workcenter'].search( order='sequence asc'
[('surface_technics_id', '=', p.id), )
('id', 'in', route_workcenter_arr)]) for p in production_process:
technology_design_values.append( logging.info('production_process:%s' % p.name)
self.env['sf.technology.design'].json_technology_design_str(False, process_parameter = production_item.product_id.model_process_parameters_ids.filtered(
route_production_process, lambda pm: pm.process_id.id == p.id)
i, if process_parameter:
process_parameter)) i += 1
productions.technology_design_ids = technology_design_values route_production_process = self.env[
'mrp.routing.workcenter'].search(
[('surface_technics_id', '=', p.id),
('id', 'in', route_workcenter_arr)])
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False,
route_production_process,
i,
process_parameter))
production_item.technology_design_ids = technology_design_values
productions.write({'state': 'technology_to_confirmed'}) productions.write({'state': 'technology_to_confirmed'})
return True return True
@@ -423,6 +423,8 @@ class ProductionLot(models.Model):
"""Generate `lot_names` from a string.""" """Generate `lot_names` from a string."""
if first_lot.__contains__(display_name): if first_lot.__contains__(display_name):
first_lot = first_lot[(len(display_name) + 1):] first_lot = first_lot[(len(display_name) + 1):]
else:
first_lot = first_lot[-3:]
# We look if the first lot contains at least one digit. # We look if the first lot contains at least one digit.
caught_initial_number = regex_findall(r"\d+", first_lot) caught_initial_number = regex_findall(r"\d+", first_lot)
@@ -633,80 +635,79 @@ class StockPicking(models.Model):
return '%s%s' % (rescode, num) return '%s%s' % (rescode, num)
def button_validate(self): def button_validate(self):
if self.picking_type_id.barcode == 'OCOUT':
move_out = self.env['stock.move'].search(
[('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin)])
move_in = self.env['stock.move'].search(
[('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.origin), ('picking_id', '=', self.id)])
if self.location_id == move_in.location_id and self.location_dest_id == move_in.location_dest_id:
if move_out.origin == move_in.origin:
move_in.write({'production_id': False})
if move_out.picking_id.state != 'done':
raise UserError(
_('该入库单对应的单号为%s的出库单还未完成,不能进行验证操作!' % move_out.picking_id.name))
res = super().button_validate() res = super().button_validate()
if res is True and self.picking_type_id.barcode == 'OCIN': picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
if self.id == move_out.picking_id.id: if res is True and self.picking_type_id.id == picking_type_in:
# if move_out.move_line_ids.workorder_id.state == 'progress': # 如果是最后一张外协入库单,则设置库存位置的预留数量
move_in = self.env['stock.move'].search( move_in = self.move_ids
[('location_dest_id', '=', self.env['stock.location'].search( if move_in:
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id), workorder = move_in.subcontract_workorder_id
('location_id', '=', self.env['stock.location'].search( workorders = workorder.production_id.workorder_ids
[('barcode', 'ilike', 'VL-SPOC')]).id), subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence')
('origin', '=', self.origin)]) if workorder == subcontract_workorders[-1]:
production = self.env['mrp.production'].search([('name', '=', self.origin)]) self.env['stock.quant']._update_reserved_quantity(
if move_in.state != 'done': move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty, lot_id=move_in.move_line_ids.lot_id,
move_in.write({'state': 'assigned'}) package_id=False, owner_id=False, strict=False
self.env['stock.move.line'].create(move_in.get_move_line(production, None)) )
return res return res
# 创建 外协出库入单 # 创建 外协出库入单
def create_outcontract_picking(self, sorted_workorders_arr, item): def create_outcontract_picking(self, workorders, item, sorted_workorders):
if len(sorted_workorders_arr) > 1: for workorder in workorders:
sorted_workorders_arr = sorted_workorders_arr[0] if workorder.move_subcontract_workorder_ids:
stock_picking = self.env['stock.picking'].search([('origin', '=', item.name), ('name', 'ilike', 'OCOUT')]) workorder.move_subcontract_workorder_ids.write({'state': 'draft'})
if not stock_picking or sorted_workorders_arr: workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'draft'})
for sorted_workorders in sorted_workorders_arr: else:
# pick_ids = [] # 创建一个新的补货组
if not sorted_workorders.picking_ids: procurement_group_id = self.env['procurement.group'].create({
# outcontract_stock_move = self.env['stock.move'].search([('production_id', '=', item.id)]) 'name': workorder.name,
# if not outcontract_stock_move: 'partner_id': self.partner_id.id,
new_picking = True })
location_id = self.env['stock.location'].search( move_dest_id = False
[('barcode', 'ilike', 'VL-SPOC')]).id, # 如果当前工单是是制造订单的最后一个工单
location_dest_id = self.env['stock.location'].search( if workorder == item.workorder_ids[-1]:
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id, move_dest_id = item.move_raw_ids[0].id
outcontract_picking_type_in = self.env.ref( else:
'sf_manufacturing.outcontract_picking_in').id, # 从sorted_workorders中找到上一工单的move
outcontract_picking_type_out = self.env.ref( if sorted_workorders.index(workorder) > 0:
'sf_manufacturing.outcontract_picking_out').id, move_dest_id = sorted_workorders[sorted_workorders.index(workorder) - 1].move_subcontract_workorder_ids[1].id
moves_out = self.env['stock.move'].sudo().create( new_picking = True
self.env['stock.move']._get_stock_move_values_Res(item, location_dest_id, location_id, outcontract_picking_type_in = self.env.ref(
outcontract_picking_type_out)) 'sf_manufacturing.outcontract_picking_in').id,
picking_out = self.create( outcontract_picking_type_out = self.env.ref(
moves_out._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCOUT/')) 'sf_manufacturing.outcontract_picking_out').id,
# pick_ids.append(picking_out.id) moves_in = self.env['stock.move'].sudo().create(
moves_out.write( self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in, procurement_group_id.id, move_dest_id))
{'picking_id': picking_out.id, 'state': 'waiting'}) picking_in = self.create(
moves_out._assign_picking_post_process(new=new_picking) moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
moves_in = self.env['stock.move'].sudo().create( # pick_ids.append(picking_in.id)
self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id, moves_in.write(
outcontract_picking_type_in)) {'picking_id': picking_in.id, 'state': 'waiting'})
picking_in = self.create( moves_in._assign_picking_post_process(new=new_picking)
moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/')) moves_out = self.env['stock.move'].sudo().create(
# pick_ids.append(picking_in.id) self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out, procurement_group_id.id, moves_in.id))
moves_in.write( workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
{'picking_id': picking_in.id, 'state': 'waiting'}) picking_out = self.create(
moves_in._assign_picking_post_process(new=new_picking) moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
# pick_ids.append(picking_out.id)
moves_out.write(
{'picking_id': picking_out.id, 'state': 'waiting'})
moves_out._assign_picking_post_process(new=new_picking)
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
def _compute_state(self):
super(StockPicking, self)._compute_state()
for picking in self:
# 外协出库单根据工单状态,采购单状态来确定
picking_type_id = self.env.ref('sf_manufacturing.outcontract_picking_out').id
if picking.picking_type_id.id == picking_type_id:
if picking.move_ids:
workorder = picking.move_ids[0].subcontract_workorder_id
if picking.state == 'assigned':
if workorder.state in ['pending', 'waiting'] or workorder._get_surface_technics_purchase_ids().state in ['draft', 'sent']:
picking.state = 'waiting'
class ReStockMove(models.Model): class ReStockMove(models.Model):
@@ -716,17 +717,20 @@ class ReStockMove(models.Model):
materiel_width = fields.Float(string='物料宽度', digits=(16, 4)) materiel_width = fields.Float(string='物料宽度', digits=(16, 4))
materiel_height = fields.Float(string='物料高度', digits=(16, 4)) materiel_height = fields.Float(string='物料高度', digits=(16, 4))
def _get_stock_move_values_Res(self, item, location_src_id, location_dest_id, picking_type_id): def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
route = self.env['stock.route'].sudo().search([('name', '=', '表面工艺外协')]) route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
stock_rule = self.env['stock.rule'].sudo().search([('route_id', '=', route_id), ('picking_type_id', '=', picking_type_id)])
move_values = { move_values = {
'name': '', 'name': '',
'company_id': item.company_id.id, 'company_id': item.company_id.id,
'product_id': item.bom_id.bom_line_ids.product_id.id, 'product_id': item.bom_id.bom_line_ids.product_id.id,
'product_uom': item.bom_id.bom_line_ids.product_uom_id.id, 'product_uom': item.bom_id.bom_line_ids.product_uom_id.id,
'product_uom_qty': 1.0, 'product_uom_qty': 1.0,
'location_id': location_src_id, 'location_id': stock_rule.location_src_id.id,
'location_dest_id': location_dest_id, 'location_dest_id': stock_rule.location_dest_id.id,
'origin': item.name, 'origin': item.name,
'group_id': group_id,
'move_dest_ids': [(6, 0, [move_dest_ids])] if move_dest_ids else False,
# 'route_ids': False if not route else [(4, route.id)], # 'route_ids': False if not route else [(4, route.id)],
'date_deadline': datetime.now(), 'date_deadline': datetime.now(),
'picking_type_id': picking_type_id, 'picking_type_id': picking_type_id,
@@ -750,7 +754,7 @@ class ReStockMove(models.Model):
'picking_type_id': picking_type_id, 'picking_type_id': picking_type_id,
'location_id': self.mapped('location_id').id, 'location_id': self.mapped('location_id').id,
'location_dest_id': self.mapped('location_dest_id').id, 'location_dest_id': self.mapped('location_dest_id').id,
'state': 'confirmed', 'state': 'waiting',
} }
def get_move_line(self, production_id, sorted_workorders): def get_move_line(self, production_id, sorted_workorders):
@@ -966,7 +970,7 @@ class ReStockMove(models.Model):
合并制造订单的完成move单据 合并制造订单的完成move单据
""" """
res = super(ReStockMove, self)._merge_moves_fields() res = super(ReStockMove, self)._merge_moves_fields()
if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨', '生产入库']: if self[0].origin and self.picking_type_id.name in ['生产发料', '内部调拨', '生产入库', '客供料入库']:
production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc') production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc')
productions = self.env['mrp.production'].search( productions = self.env['mrp.production'].search(
[('origin', '=', production.origin), ('product_id', '=', production.product_id.id)]) [('origin', '=', production.origin), ('product_id', '=', production.product_id.id)])
@@ -989,9 +993,12 @@ class ReStockMove(models.Model):
production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc') production = self.env['mrp.production'].search([('name', '=', self[0].origin)], limit=1, order='id asc')
productions = self.env['mrp.production'].search( productions = self.env['mrp.production'].search(
[('origin', '=', production.origin), ('product_id', '=', production.product_id.id)]) [('origin', '=', production.origin), ('product_id', '=', production.product_id.id)])
res['origin'] = ','.join(productions.mapped('name')) if productions.mapped('name'):
res['origin'] = ','.join(productions.mapped('name'))
res['retrospect_ref'] = production.product_id.name res['retrospect_ref'] = production.product_id.name
return res return res
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True, index='btree_not_null')
class ReStockQuant(models.Model): class ReStockQuant(models.Model):

View File

@@ -52,6 +52,7 @@ access_mrp_routing_workcenter_manager_group_sf_mrp_user,mrp.routing.workcenter.m
access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_manager_group_sf_mrp_user,mrp.bom.manager,mrp.model_mrp_bom,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_bom_line_manager_group_sf_mrp_user,mrp.bom.line.manager,mrp.model_mrp_bom_line,sf_base.group_sf_mrp_user,1,1,1,0 access_mrp_bom_line_manager_group_sf_mrp_user,mrp.bom.line.manager,mrp.model_mrp_bom_line,sf_base.group_sf_mrp_user,1,1,1,0
access_mrp_bom_line_group_plan_director,mrp_bom_line_group_plan_director,mrp.model_mrp_bom_line,sf_base.group_plan_director,1,1,1,0 access_mrp_bom_line_group_plan_director,mrp_bom_line_group_plan_director,mrp.model_mrp_bom_line,sf_base.group_plan_director,1,1,1,0
access_mrp_bom_line_group_sf_stock_user,mrp_bom_line_group_sf_stock_user,mrp.model_mrp_bom_line,sf_base.group_sf_stock_user,1,1,1,0
access_mrp_bom_line_group_sale_director,mrp_bom_line_group_sale_director,mrp.model_mrp_bom_line,sf_base.group_sale_director,1,1,1,0 access_mrp_bom_line_group_sale_director,mrp_bom_line_group_sale_director,mrp.model_mrp_bom_line,sf_base.group_sale_director,1,1,1,0
access_mrp_bom_line_group_sale_salemanager,mrp_bom_line_group_sale_salemanager,mrp.model_mrp_bom_line,sf_base.group_sale_salemanager,1,0,1,0 access_mrp_bom_line_group_sale_salemanager,mrp_bom_line_group_sale_salemanager,mrp.model_mrp_bom_line,sf_base.group_sale_salemanager,1,0,1,0
access_mrp_bom_line_group_purchase_director,mrp_bom_line_group_purchase_director,mrp.model_mrp_bom_line,sf_base.group_purchase_director,1,1,1,0 access_mrp_bom_line_group_purchase_director,mrp_bom_line_group_purchase_director,mrp.model_mrp_bom_line,sf_base.group_purchase_director,1,1,1,0
@@ -116,7 +117,7 @@ access_mrp_production_group_quality,mrp_production,model_mrp_production,sf_base.
access_mrp_production_group_quality_director,mrp_production,model_mrp_production,sf_base.group_quality_director,1,1,0,0 access_mrp_production_group_quality_director,mrp_production,model_mrp_production,sf_base.group_quality_director,1,1,0,0
access_mrp_workorder_group_quality,mrp_workorder,model_mrp_workorder,sf_base.group_quality,1,1,0,0 access_mrp_workorder_group_quality,mrp_workorder,model_mrp_workorder,sf_base.group_quality,1,1,0,0
access_mrp_workorder_group_quality_director,mrp_workorder,model_mrp_workorder,sf_base.group_quality_director,1,1,0,0 access_mrp_workorder_group_quality_director,mrp_workorder,model_mrp_workorder,sf_base.group_quality_director,1,1,0,0
access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,0,0 access_mrp_workorder,mrp_workorder,model_mrp_workorder,sf_base.group_plan_dispatch,1,1,1,0
access_sf_production_line_group_plan_dispatch,sf.production.line,model_sf_production_line,sf_base.group_plan_dispatch,1,0,0,0 access_sf_production_line_group_plan_dispatch,sf.production.line,model_sf_production_line,sf_base.group_plan_dispatch,1,0,0,0
access_sf_production_line_group_plan_director,sf.production.line,model_sf_production_line,sf_base.group_plan_director,1,1,1,0 access_sf_production_line_group_plan_director,sf.production.line,model_sf_production_line,sf_base.group_plan_director,1,1,1,0
access_sf_production_line,sf.production.line,model_sf_production_line,sf_maintenance.sf_group_equipment_user,1,1,1,0 access_sf_production_line,sf.production.line,model_sf_production_line,sf_maintenance.sf_group_equipment_user,1,1,1,0
@@ -166,10 +167,12 @@ access_sf_agv_scheduling_group_sf_mrp_manager,sf_agv_scheduling_group_sf_mrp_man
access_sf_agv_scheduling_group_sf_equipment_user,sf_agv_scheduling_group_sf_equipment_user,model_sf_agv_scheduling,sf_base.group_sf_equipment_user,1,1,1,0 access_sf_agv_scheduling_group_sf_equipment_user,sf_agv_scheduling_group_sf_equipment_user,model_sf_agv_scheduling,sf_base.group_sf_equipment_user,1,1,1,0
access_sf_technology_design_group_plan_dispatch,sf_technology_design_group_plan_dispatch,model_sf_technology_design,sf_base.group_plan_dispatch,1,1,1,0 access_sf_technology_design_group_plan_dispatch,sf_technology_design_group_plan_dispatch,model_sf_technology_design,sf_base.group_plan_dispatch,1,1,1,0
access_sf_technology_design_group_sf_mrp_manager,sf_technology_design_group_sf_mrp_manager,model_sf_technology_design,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_technology_design_group_sf_mrp_manager,sf_technology_design_group_sf_mrp_manager,model_sf_technology_design,sf_base.group_sf_mrp_manager,1,0,0,0
access_sf_technology_design_group_production_engineer,sf_technology_design_group_production_engineer,model_sf_technology_design,sf_base.group_production_engineer,1,1,1,0 access_sf_technology_design_group_production_engineer,sf_technology_design_group_production_engineer,model_sf_technology_design,sf_base.group_production_engineer,1,1,1,0
access_sf_technology_design_group_sf_equipment_user,sf_technology_design_group_sf_equipment_user,model_sf_technology_design,sf_base.group_sf_equipment_user,1,0,0,0
access_sf_technology_design_group_sf_order_user,sf_technology_design_group_sf_order_user,model_sf_technology_design,sf_base.group_sf_order_user,1,0,0,0
access_sf_production_technology_wizard_group_plan_dispatch,sf_production_technology_wizard_group_plan_dispatch,model_sf_production_technology_wizard,sf_base.group_plan_dispatch,1,1,1,0 access_sf_production_technology_wizard_group_plan_dispatch,sf_production_technology_wizard_group_plan_dispatch,model_sf_production_technology_wizard,sf_base.group_plan_dispatch,1,1,1,0
access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_production_technology_wizard_group_sf_mrp_manager,sf_production_technology_wizard_group_sf_mrp_manager,model_sf_production_technology_wizard,sf_base.group_sf_mrp_manager,1,0,0,0
access_sf_production_technology_wizard_group_production_engineer,sf_production_technology_wizard_group_production_engineer,model_sf_production_technology_wizard,sf_base.group_production_engineer,1,1,1,0 access_sf_production_technology_wizard_group_production_engineer,sf_production_technology_wizard_group_production_engineer,model_sf_production_technology_wizard,sf_base.group_production_engineer,1,1,1,0
access_sf_production_technology_re_adjust_wizard_group_plan_dispatch,sf_production_technology_re_adjust_wizard_group_plan_dispatch,model_sf_production_technology_re_adjust_wizard,sf_base.group_plan_dispatch,1,1,1,0 access_sf_production_technology_re_adjust_wizard_group_plan_dispatch,sf_production_technology_re_adjust_wizard_group_plan_dispatch,model_sf_production_technology_re_adjust_wizard,sf_base.group_plan_dispatch,1,1,1,0
access_sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,model_sf_production_technology_re_adjust_wizard,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,sf_production_technology_re_adjust_wizard_group_sf_mrp_manager,model_sf_production_technology_re_adjust_wizard,sf_base.group_sf_mrp_manager,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
52 access_mrp_bom_line_manager_group_sf_mrp_user mrp.bom.line.manager mrp.model_mrp_bom_line sf_base.group_sf_mrp_user 1 1 1 0
53 access_mrp_bom_line_group_plan_director mrp_bom_line_group_plan_director mrp.model_mrp_bom_line sf_base.group_plan_director 1 1 1 0
54 access_mrp_bom_line_group_sale_director access_mrp_bom_line_group_sf_stock_user mrp_bom_line_group_sale_director mrp_bom_line_group_sf_stock_user mrp.model_mrp_bom_line sf_base.group_sale_director sf_base.group_sf_stock_user 1 1 1 0
55 access_mrp_bom_line_group_sale_director mrp_bom_line_group_sale_director mrp.model_mrp_bom_line sf_base.group_sale_director 1 1 1 0
56 access_mrp_bom_line_group_sale_salemanager mrp_bom_line_group_sale_salemanager mrp.model_mrp_bom_line sf_base.group_sale_salemanager 1 0 1 0
57 access_mrp_bom_line_group_purchase_director mrp_bom_line_group_purchase_director mrp.model_mrp_bom_line sf_base.group_purchase_director 1 1 1 0
58 access_mrp_bom_byproduct_manager_group_sf_mrp_user mrp.bom.byproduct manager mrp.model_mrp_bom_byproduct sf_base.group_sf_mrp_user 1 1 1 0
117 access_mrp_workorder_group_quality mrp_workorder model_mrp_workorder sf_base.group_quality 1 1 0 0
118 access_mrp_workorder_group_quality_director mrp_workorder model_mrp_workorder sf_base.group_quality_director 1 1 0 0
119 access_mrp_workorder mrp_workorder model_mrp_workorder sf_base.group_plan_dispatch 1 1 0 1 0
120 access_sf_production_line_group_plan_dispatch sf.production.line model_sf_production_line sf_base.group_plan_dispatch 1 0 0 0
121 access_sf_production_line_group_plan_director sf.production.line model_sf_production_line sf_base.group_plan_director 1 1 1 0
122 access_sf_production_line sf.production.line model_sf_production_line sf_maintenance.sf_group_equipment_user 1 1 1 0
123 access_mrp_workcenter mrp_workcenter model_mrp_workcenter sf_base.group_plan_dispatch 1 1 1 0
167 access_sf_production_technology_re_adjust_wizard_group_production_engineer access_sf_production_technology_re_adjust_wizard_group_plan_dispatch sf_production_technology_re_adjust_wizard_group_production_engineer sf_production_technology_re_adjust_wizard_group_plan_dispatch model_sf_production_technology_re_adjust_wizard sf_base.group_production_engineer sf_base.group_plan_dispatch 1 1 1 0
168 access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user access_sf_production_technology_re_adjust_wizard_group_sf_mrp_manager sf_manual_product_model_type_routing_sort sf_production_technology_re_adjust_wizard_group_sf_mrp_manager model_sf_manual_product_model_type_routing_sort model_sf_production_technology_re_adjust_wizard sf_base.group_sf_mrp_user sf_base.group_sf_mrp_manager 1 0 1 0 1 0
169 access_sf_manual_product_model_type_routing_sort_manager access_sf_production_technology_re_adjust_wizard_group_production_engineer sf_manual_product_model_type_routing_sort sf_production_technology_re_adjust_wizard_group_production_engineer model_sf_manual_product_model_type_routing_sort model_sf_production_technology_re_adjust_wizard sf_base.group_sf_mrp_manager sf_base.group_production_engineer 1 1 1 1 0
170 access_sf_manual_product_model_type_routing_sort_group_plan_dispatch access_sf_manual_product_model_type_routing_sort_group_sf_mrp_user sf_manual_product_model_type_routing_sort_group_plan_dispatch sf_manual_product_model_type_routing_sort model_sf_manual_product_model_type_routing_sort sf_base.group_plan_dispatch sf_base.group_sf_mrp_user 1 0 0 0
171 access_sf_detection_result_manager access_sf_manual_product_model_type_routing_sort_manager sf_detection_result_manager sf_manual_product_model_type_routing_sort model_sf_detection_result model_sf_manual_product_model_type_routing_sort sf_base.group_sf_mrp_manager 1 1 1 1
172 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
173 access_sf_detection_result_manager sf_detection_result_manager model_sf_detection_result 1 1 1 1
174
175
176
177
178

View File

@@ -31,7 +31,7 @@
<form string="模型类型"> <form string="模型类型">
<group> <group>
<field name="name" required="1"/> <field name="name" required="1"/>
<field name="embryo_tolerance_id" required="1" string="坯料容余(mm)"/> <field name="embryo_tolerance_id" required="1"/>
</group> </group>
<group> <group>
<field name='product_routing_tmpl_ids'> <field name='product_routing_tmpl_ids'>

View File

@@ -370,7 +370,8 @@
attrs="{'readonly': [('id', '!=', False)]}" options="{'no_create': True}"/> attrs="{'readonly': [('id', '!=', False)]}" options="{'no_create': True}"/>
<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}" options="{'no_create': True}"/> string="参数" context="{'route_id':route_id,'production_id': production_id}"
options="{'no_create': True}"/>
<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'"
@@ -740,5 +741,19 @@
<!-- parent="mrp.menu_mrp_manufacturing"--> <!-- parent="mrp.menu_mrp_manufacturing"-->
<!-- sequence="1"/>--> <!-- sequence="1"/>-->
<menuitem id="mrp.menu_mrp_production_action"
name="制造订单"
parent="mrp.menu_mrp_manufacturing"
action="mrp.mrp_production_action"
groups="sf_base.group_plan_dispatch,sf_base.group_sf_mrp_manager"
sequence="1"/>
<menuitem id="stock_picking_type_menu"
name="驾驶舱"
parent="stock.menu_stock_root"
action="stock.stock_picking_type_action"
groups="sf_base.group_sf_stock_user"
sequence="0"/>
</data> </data>
</odoo> </odoo>

View File

@@ -139,7 +139,7 @@
<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"
attrs="{'invisible': [('surface_technics_purchase_count', '=', 0),('routing_type', '!=', '表面工艺')]}"> attrs="{'invisible': [('surface_technics_purchase_count', '=', 0)]}">
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_value"> <span class="o_stat_value">
<field name="surface_technics_purchase_count"/> <field name="surface_technics_purchase_count"/>

View File

@@ -1,17 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<record id="view_order_form_inherit_sf" model="ir.ui.view">
<field name="name">view.sale.order.form.inherit.sf</field>
<field name="inherit_id" ref="sale_stock.view_order_form_inherit_sale_stock_qty"/>
<field name="model">sale.order</field>
<field name="arch" type="xml">
<xpath expr="//page/field[@name='order_line']/form/group/group/div[@name='ordered_qty']/widget[@name='qty_at_date_widget']" position="replace">
</xpath>
<xpath expr="//page/field[@name='order_line']/tree/widget[@name='qty_at_date_widget']" position="replace">
</xpath>
</field>
</record>
<record id="view_order_form_inherit_supply_method" model="ir.ui.view"> <record id="view_order_form_inherit_supply_method" model="ir.ui.view">
<field name="name">view.sale.order.form.inherit.supply.method</field> <field name="name">view.sale.order.form.inherit.supply.method</field>
<field name="inherit_id" ref="sf_sale.view_sale_order_form_inherit_sf"/> <field name="inherit_id" ref="sf_sale.view_sale_order_form_inherit_sf"/>
@@ -102,7 +90,5 @@
<record id="sale.res_partner_menu" model="ir.ui.menu"> <record id="sale.res_partner_menu" model="ir.ui.menu">
<field name="groups_id" eval="[(4, ref('sf_base.group_production_engineer'))]"/> <field name="groups_id" eval="[(4, ref('sf_base.group_production_engineer'))]"/>
</record> </record>
</odoo> </odoo>

View File

@@ -51,5 +51,10 @@
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="stock.action_picking_tree_all" model="ir.actions.act_window">
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('stock.vpicktree')})]"/>
</record>
</data> </data>
</odoo> </odoo>

View File

@@ -49,8 +49,8 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
if ro.route_id.routing_type == '表面工艺': if ro.route_id.routing_type == '表面工艺':
domain += [('process_parameters_id', '=', ro.process_parameters_id.id)] domain += [('process_parameters_id', '=', ro.process_parameters_id.id)]
elif ro.route_id.routing_tag == 'special' and ro.is_auto is False: elif ro.route_id.routing_tag == 'special' and ro.is_auto is False:
display_name = ro.route_id.display_name # display_name = ro.route_id.display_name
domain += [('name', 'ilike', display_name)] domain += [('id', '=', ro.id)]
elif ro.panel is not False: elif ro.panel is not False:
domain += [('panel', '=', ro.panel)] domain += [('panel', '=', ro.panel)]
td_upd = self.env['sf.technology.design'].sudo().search(domain) td_upd = self.env['sf.technology.design'].sudo().search(domain)
@@ -62,25 +62,34 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
for special in special_design: for special in special_design:
workorders_values = [] workorders_values = []
if special.active is False: if special.active is False:
is_cancel = False
# 工单采购单外协出入库单皆需取消 # 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)] domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id: if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id)] domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id), ('state', '!=', 'cancel')]
else: else:
domain += [('name', '=', special.route_id.name)] domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
workorder = self.env['mrp.workorder'].search(domain) workorder = self.env['mrp.workorder'].search(domain)
if workorder.state != 'cancel': # previous_workorder = self.env['mrp.workorder'].search(
workorder.write({'state': 'cancel'}) # [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
workorder.picking_ids.write({'state': 'cancel'}) # ('production_id', '=', workorder.production_id.id)])
workorder.picking_ids.move_ids.write({'state': 'cancel'}) # if previous_workorder:
purchase_order = self.env['purchase.order'].search( # if previous_workorder.supplier_id != workorder.supplier_id:
[('origin', '=', workorder.production_id.origin)]) # is_cancel = True
for line in purchase_order.order_line: # else:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id: # is_cancel = True
purchase_order.write({'state': 'cancel'}) # if workorder.state != 'cancel' and is_cancel is True:
# workorder.write({'state': 'cancel'})
# workorder.picking_ids.write({'state': 'cancel'})
# workorder.picking_ids.move_ids.write({'state': 'cancel'})
# purchase_order = self.env['purchase.order'].search(
# [('origin', '=', workorder.production_id.name)])
# for line in purchase_order.order_line:
# if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
# purchase_order.write({'state': 'cancel'})
else: else:
workorder = self.env['mrp.workorder'].search( workorder = self.env['mrp.workorder'].search(
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id)]) [('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id), ('state', '!=', 'cancel')])
if not workorder: if not workorder:
if special.route_id.routing_type == '表面工艺': if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search( product_production_process = self.env['product.template'].search(
@@ -95,19 +104,23 @@ class ProductionTechnologyReAdjustWizard(models.TransientModel):
self.env['mrp.workorder'].json_workorder_str(special.production_id, special)) self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values}) special.production_id.write({'workorder_ids': workorders_values})
else: else:
logging.info(workorder.blocked_by_workorder_ids)
if len(workorder.blocked_by_workorder_ids) > 1: if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1: if workorder.sequence == 1:
workorder.blocked_by_workorder_ids = None workorder.blocked_by_workorder_ids = None
else: else:
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0] if workorder.blocked_by_workorder_ids:
workorder.blocked_by_workorder_ids = workorder.blocked_by_workorder_ids[0]
productions._reset_work_order_sequence() productions._reset_work_order_sequence()
if self.production_id.product_id.categ_id.type == '成品': # 退回时不对外协出入库单和采购单做处理
productions._reset_subcontract_pick_purchase() # if self.production_id.product_id.categ_id.type == '成品':
productions.get_subcontract_pick_purchase() # productions._reset_subcontract_pick_purchase()
# productions.get_subcontract_pick_purchase()
productions.is_adjust = True productions.is_adjust = True
for item in productions: for item in productions:
workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted( workorders = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(
key=lambda a: a.sequence) key=lambda a: a.sequence)
if workorders[0].state in ['pending']: if workorders[0].state in ['pending']:
if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': if workorders[
0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
workorders[0].state = 'waiting' workorders[0].state = 'waiting'

View File

@@ -53,9 +53,59 @@ class ProductionTechnologyWizard(models.TransientModel):
td_upd = self.env['sf.technology.design'].sudo().search(domain) td_upd = self.env['sf.technology.design'].sudo().search(domain)
if td_upd: if td_upd:
ro.write({'sequence': td_upd.sequence, 'active': td_upd.active}) ro.write({'sequence': td_upd.sequence, 'active': td_upd.active})
# special = production.technology_design_ids.filtered( special_design = self.env['sf.technology.design'].sudo().search(
# lambda td: td.is_auto is False and td.process_parameters_id is not False) [('routing_tag', '=', 'special'), ('production_id', '=', production.id),
# # if special: ('is_auto', '=', False), ('active', 'in', [True, False])])
for special in special_design:
workorders_values = []
if special.active is False:
# is_cancel = False
# 工单采购单外协出入库单皆需取消
domain = [('production_id', '=', special.production_id.id)]
if special.process_parameters_id:
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id), ('state', '!=', 'cancel')]
else:
domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
workorder = self.env['mrp.workorder'].search(domain)
# previous_workorder = self.env['mrp.workorder'].search(
# [('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
# ('production_id', '=', workorder.production_id.id)])
# if previous_workorder:
# if previous_workorder.supplier_id != workorder.supplier_id:
# is_cancel = True
# if workorder.state != 'cancel' and is_cancel is True:
workorder.write({'state': 'cancel'})
workorder.picking_ids.write({'state': 'cancel'})
workorder.picking_ids.move_ids.write({'state': 'cancel'})
purchase_order = self.env['purchase.order'].search(
[('origin', '=', workorder.production_id.name), ('purchase_type', '=', 'consignment')])
for line in purchase_order.order_line:
if line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id:
purchase_order.write({'state': 'cancel'})
else:
if special.production_id.workorder_ids:
workorder = self.env['mrp.workorder'].search(
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id), ('state', '!=', 'cancel')])
if not workorder:
if special.route_id.routing_type == '表面工艺':
product_production_process = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', special.process_parameters_id.id)])
workorders_values.append(
self.env[
'mrp.workorder']._json_workorder_surface_process_str(special.production_id, special,
product_production_process.seller_ids[
0].partner_id.id))
else:
workorders_values.append(
self.env['mrp.workorder'].json_workorder_str(special.production_id, special))
special.production_id.write({'workorder_ids': workorders_values})
else:
if len(workorder.blocked_by_workorder_ids) > 1:
if workorder.sequence == 1:
workorder.blocked_by_workorder_ids = None
else:
if workorder.blocked_by_workorder_ids:
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0]
productions._create_workorder(False) productions._create_workorder(False)
if self.production_id.product_id.categ_id.type == '成品': if self.production_id.product_id.categ_id.type == '成品':
productions.get_subcontract_pick_purchase() productions.get_subcontract_pick_purchase()
@@ -65,4 +115,4 @@ class ProductionTechnologyWizard(models.TransientModel):
key=lambda a: a.sequence) key=lambda a: a.sequence)
if workorder[0].state in ['pending']: if workorder[0].state in ['pending']:
if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程': if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
workorders[0].state = 'waiting' workorder[0].state = 'waiting'

View File

@@ -4,6 +4,7 @@ import logging
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from datetime import datetime from datetime import datetime
from odoo import models, api, fields, _ from odoo import models, api, fields, _
from odoo.tools import groupby
class ReworkWizard(models.TransientModel): class ReworkWizard(models.TransientModel):
@@ -37,6 +38,30 @@ class ReworkWizard(models.TransientModel):
tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state') tool_state = fields.Selection(string='功能刀具状态', related='production_id.tool_state')
@api.onchange('hidden_workorder_ids')
def _onchange_hidden_workorder_ids(self):
for item in self:
if item.hidden_workorder_ids not in ['', None, False]:
hidden_workorder_list = item.hidden_workorder_ids.split(',')
# 获取加工面对应需要返工的工单
rw_ids = item.workorder_ids.filtered(
lambda w: str(w.ids[0]) in hidden_workorder_list and w.processing_panel not in ['', None, False])
grouped_rw_ids = {key: list(group) for key, group in groupby(rw_ids, key=lambda w: w.processing_panel)}
for panel, panel_rw_ids in grouped_rw_ids.items():
work_ids = item.workorder_ids.filtered(lambda w: w.state == 'done' and w.processing_panel == panel)
if len(work_ids) == 3 and len(panel_rw_ids) != 3:
for work_id in work_ids:
if work_id not in panel_rw_ids:
hidden_workorder_list.append(str(work_id.ids[0]))
elif len(work_ids) == 2 and len(panel_rw_ids) < 2 and panel_rw_ids[0].name == 'CNC加工':
if rw_ids.filtered(lambda w: (w.sequence < panel_rw_ids[0].sequence
and w.processing_panel != panel_rw_ids[0].processing_panel)):
hidden_workorder_list.append(str(work_ids.filtered(
lambda w: (w.processing_panel == panel_rw_ids[0].processing_panel
and w.name == '装夹预调')).ids[0]))
hidden_workorder_list.sort()
item.hidden_workorder_ids = ','.join(hidden_workorder_list)
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
@@ -57,8 +82,17 @@ class ReworkWizard(models.TransientModel):
# 限制判断 # 限制判断
# 1、当制造订单内ZM面的工单都已完成时返工勾选工序时只能勾选上ZM面的所有工序进行返工 # 1、当制造订单内ZM面的工单都已完成时返工勾选工序时只能勾选上ZM面的所有工序进行返工
# 2、当FM工单在CNC工单进行选择返工并将已全部完成的ZM面工序全部勾选上时FM工单上所有的已完成的工单装夹预调工单也必须进行勾选 # 2、当FM工单在CNC工单进行选择返工并将已全部完成的ZM面工序全部勾选上时FM工单上所有的已完成的工单装夹预调工单也必须进行勾选
done_panel_workorder_ids = self.workorder_ids.filtered( # 获取已完成的标准工单
lambda w: w.state == 'done' and w.processing_panel is not False) # 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:

View File

@@ -32,6 +32,12 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
domain += [('state', 'in', ['confirmed', 'pending_cam'])] domain += [('state', 'in', ['confirmed', 'pending_cam'])]
productions = request.env['mrp.production'].with_user( productions = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search(domain) request.env.ref("base.user_admin")).search(domain)
productions_technology_to_confirmed = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search(
[('programming_no', '=', ret['programming_no']), ('state', 'in', ['technology_to_confirmed'])])
if productions_technology_to_confirmed:
res = {'status': -2, 'message': '查询到待工艺确认的制造订单'}
return json.JSONEncoder().encode(res)
if productions: if productions:
# 拉取所有加工面的程序文件 # 拉取所有加工面的程序文件
for r in ret['processing_panel'].split(','): for r in ret['processing_panel'].split(','):

View File

@@ -231,26 +231,39 @@ class sf_production_plan(models.Model):
if not record.production_line_id: if not record.production_line_id:
raise ValidationError("未选择生产线") raise ValidationError("未选择生产线")
else: else:
# 自动化产线加工
if record.production_id.workorder_ids: if record.production_id.workorder_ids:
last_cnc_start = record.date_planned_start if record.date_planned_start else datetime.now() # 自动化产线加工
for item in record.production_id.workorder_ids: if record.production_id.production_type == '自动化产线加工':
if item.name == 'CNC加工': # 找到第一张CNC加工工单
# 将同一个面的所有工单筛选出来 first_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[0]
workorder_list = record.production_id.workorder_ids.filtered(lambda x: x.processing_panel == item.processing_panel) date_start = record.date_planned_start if record.date_planned_start else datetime.now()
routing_workcenter = record.env['mrp.routing.workcenter'].sudo().search( routing_workcenter = first_cnc_workorder.technology_design_id.route_id
[('name', '=', 'CNC加工')], limit=1) # 设置一个小的开始时间
# 设置一个小的开始时间 first_cnc_workorder.date_planned_start = datetime.now() - timedelta(days=100)
item.date_planned_start = datetime.now() - timedelta(days=100) first_cnc_workorder.date_planned_finished = date_start + timedelta(
item.date_planned_finished = last_cnc_start + timedelta( minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
minutes=routing_workcenter.time_cycle) first_cnc_workorder.date_planned_start = date_start
item.date_planned_start = last_cnc_start record.sudo().production_id.plan_start_processing_time = first_cnc_workorder.date_planned_start
record.sudo().production_id.plan_start_processing_time = item.date_planned_start first_cnc_workorder.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
item.duration_expected = routing_workcenter.time_cycle record.calculate_plan_time(first_cnc_workorder, record.production_id.workorder_ids)
pre_duration , next_duration = record.calculate_plan_time(item, workorder_list) # 找到最后一张CNC加工工单
record.date_planned_finished = item.date_planned_finished last_cnc_workorder = record.production_id.workorder_ids.filtered(lambda x: x.name == 'CNC加工')[-1]
# 计算下一个cnc工单的开始时间 record.date_planned_finished = last_cnc_workorder.date_planned_finished
last_cnc_start = workorder_list[-1].date_planned_finished + timedelta(minutes=pre_duration) else:
# 没有工单也能排程 # 人工线下加工只排第一张工单
item = record.production_id.workorder_ids[0]
wo_start = record.date_planned_start if record.date_planned_start else datetime.now()
routing_workcenter = item.technology_design_id.route_id
item.date_planned_start = datetime.now() - timedelta(days=100)
item.date_planned_finished = wo_start + timedelta(
minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
item.date_planned_start = wo_start
record.sudo().production_id.plan_start_processing_time = item.date_planned_start
item.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
record.calculate_plan_time(item, record.production_id.workorder_ids)
last_cnc_workorder = record.production_id.workorder_ids[-1]
record.date_planned_finished = last_cnc_workorder.date_planned_finished
record.state = 'done' record.state = 'done'
# record.production_id.schedule_state = '已排' # record.production_id.schedule_state = '已排'
record.sudo().production_id.schedule_state = '已排' record.sudo().production_id.schedule_state = '已排'
@@ -306,44 +319,40 @@ class sf_production_plan(models.Model):
def calculate_plan_time(self, item, workorder_list): def calculate_plan_time(self, item, workorder_list):
""" """
根据CNC工单的时间去计算之前的其他工单的开始结束时间 根据CNC工单的时间去计算之前的其他工单的开始结束时间
param:
item: 基准工单(根据该工单的开始结束时间去计算其他工单的开始结束时间)
workorder_list: 需排程的工单列表
""" """
item_position = 0 item_position = 0
for index, workorder in enumerate(workorder_list): for index, workorder in enumerate(workorder_list):
if workorder.id == item.id: if workorder.id == item.id:
item_position = index item_position = index
break break
routing_workcenters = self.env['mrp.routing.workcenter'].sudo().search([])
# 记录所有前序工序时长
previous_workorder_duration = 0
for i in range(item_position, -1, -1): for i in range(item_position, -1, -1):
if i < 1: if i < 1:
break break
current_workorder = workorder_list[i] current_workorder = workorder_list[i]
next_workorder = workorder_list[i - 1] next_workorder = workorder_list[i - 1]
routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0] routing_workcenter = next_workorder.technology_design_id.route_id
# 设置一个小的开始时间 # 设置一个小的开始时间
next_workorder.date_planned_start = datetime.now() - timedelta(days=100) next_workorder.date_planned_start = datetime.now() - timedelta(days=100)
next_workorder.date_planned_finished = current_workorder.date_planned_start next_workorder.date_planned_finished = current_workorder.date_planned_start
next_workorder.date_planned_start = next_workorder.date_planned_finished - timedelta( next_workorder.date_planned_start = next_workorder.date_planned_finished - timedelta(
minutes=routing_workcenter.time_cycle) minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
next_workorder.duration_expected = routing_workcenter.time_cycle next_workorder.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
previous_workorder_duration += routing_workcenter.time_cycle
# 记录所有后续工序时长
next_workorder_duration = 0
for i in range(item_position, len(workorder_list) - 1): for i in range(item_position, len(workorder_list) - 1):
if i > len(workorder_list) - 1: if i > len(workorder_list) - 1:
break break
current_workorder = workorder_list[i] current_workorder = workorder_list[i]
next_workorder = workorder_list[i + 1] next_workorder = workorder_list[i + 1]
routing_workcenter = routing_workcenters.filtered(lambda x: x.name == next_workorder.name)[0] routing_workcenter = next_workorder.technology_design_id.route_id
# 设置一个小的开始时间 # 设置一个小的开始时间
next_workorder.date_planned_start = datetime.now() - timedelta(days=100) next_workorder.date_planned_start = datetime.now() - timedelta(days=100)
next_workorder.date_planned_finished = current_workorder.date_planned_finished + timedelta( next_workorder.date_planned_finished = current_workorder.date_planned_finished + timedelta(
minutes=routing_workcenter.time_cycle) minutes=routing_workcenter.time_cycle + routing_workcenter.reserved_duration)
next_workorder.date_planned_start = current_workorder.date_planned_finished next_workorder.date_planned_start = current_workorder.date_planned_finished
next_workorder.duration_expected = routing_workcenter.time_cycle next_workorder.duration_expected = routing_workcenter.time_cycle + routing_workcenter.reserved_duration
next_workorder_duration += routing_workcenter.time_cycle
return previous_workorder_duration, next_workorder_duration
def calculate_plan_time_after(self, item, workorder_id_list): def calculate_plan_time_after(self, item, workorder_id_list):
""" """

View File

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

View File

@@ -15907,7 +15907,7 @@ msgstr "内部参考"
#: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view #: model_terms:ir.ui.view,arch_db:account.account_journal_dashboard_kanban_view
#, python-format #, python-format
msgid "Internal Transfer" msgid "Internal Transfer"
msgstr "内部转账" msgstr "厂内出入库"
#. module: account #. module: account
#: model:ir.model.fields,field_description:account.field_res_config_settings__transfer_account_id #: model:ir.model.fields,field_description:account.field_res_config_settings__transfer_account_id
@@ -16133,7 +16133,7 @@ msgstr "库存概览"
#. module: stock #. module: stock
#: model:ir.actions.act_window,name:stock.stock_picking_type_action #: model:ir.actions.act_window,name:stock.stock_picking_type_action
msgid "Internal Transfers" msgid "Internal Transfers"
msgstr "厂内出入库" msgstr "库存概览"
#. module: stock #. module: stock
#: model:ir.model.fields,field_description:stock.field_stock_quant__inventory_quantity_set #: model:ir.model.fields,field_description:stock.field_stock_quant__inventory_quantity_set

View File

@@ -11,6 +11,7 @@ access_quality_point_group_sf_mrp_manager,quality_point_group_sf_mrp_manager,qua
access_quality_check_group_quality,quality_check_group_quality,quality.model_quality_check,sf_base.group_quality,1,1,1,0 access_quality_check_group_quality,quality_check_group_quality,quality.model_quality_check,sf_base.group_quality,1,1,1,0
access_quality_check_group_quality_director,quality_check_group_quality_director,quality.model_quality_check,sf_base.group_quality_director,1,1,1,0 access_quality_check_group_quality_director,quality_check_group_quality_director,quality.model_quality_check,sf_base.group_quality_director,1,1,1,0
access_quality_check_group_plan_dispatch,quality_check_group_plan_dispatch,quality.model_quality_check,sf_base.group_plan_dispatch,1,0,0,0 access_quality_check_group_plan_dispatch,quality_check_group_plan_dispatch,quality.model_quality_check,sf_base.group_plan_dispatch,1,0,0,0
access_quality_check_group_sf_stock_user,quality_check_group_sf_stock_user,quality.model_quality_check,sf_base.group_sf_stock_user,1,0,0,0
access_quality_check_group_plan_director,quality_check_group_plan_director,quality.model_quality_check,sf_base.group_plan_director,1,0,0,0 access_quality_check_group_plan_director,quality_check_group_plan_director,quality.model_quality_check,sf_base.group_plan_director,1,0,0,0
access_quality_check_group_purchase,quality_check_group_purchase,quality.model_quality_check,sf_base.group_purchase,1,0,0,0 access_quality_check_group_purchase,quality_check_group_purchase,quality.model_quality_check,sf_base.group_purchase,1,0,0,0
access_quality_check_group_purchase_director,quality_check_group_purchase_director,quality.model_quality_check,sf_base.group_purchase_director,1,0,0,0 access_quality_check_group_purchase_director,quality_check_group_purchase_director,quality.model_quality_check,sf_base.group_purchase_director,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
11 access_quality_check_group_quality_director quality_check_group_quality_director quality.model_quality_check sf_base.group_quality_director 1 1 1 0
12 access_quality_check_group_plan_dispatch quality_check_group_plan_dispatch quality.model_quality_check sf_base.group_plan_dispatch 1 0 0 0
13 access_quality_check_group_plan_director access_quality_check_group_sf_stock_user quality_check_group_plan_director quality_check_group_sf_stock_user quality.model_quality_check sf_base.group_plan_director sf_base.group_sf_stock_user 1 0 0 0
14 access_quality_check_group_plan_director quality_check_group_plan_director quality.model_quality_check sf_base.group_plan_director 1 0 0 0
15 access_quality_check_group_purchase quality_check_group_purchase quality.model_quality_check sf_base.group_purchase 1 0 0 0
16 access_quality_check_group_purchase_director quality_check_group_purchase_director quality.model_quality_check sf_base.group_purchase_director 1 0 0 0
17 access_quality_check_group_sf_equipment_user quality_check_group_sf_equipment_user quality.model_quality_check sf_base.group_sf_equipment_user 1 0 0 0

View File

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

View File

@@ -117,7 +117,7 @@ access_sf_detection_result_group_sale_director,sf_detection_result_group_sale_di
access_stock_scrap_group_sale_salemanager,stock_scrap_group_sale_salemanager,stock.model_stock_scrap,sf_base.group_sale_salemanager,1,0,0,0 access_stock_scrap_group_sale_salemanager,stock_scrap_group_sale_salemanager,stock.model_stock_scrap,sf_base.group_sale_salemanager,1,0,0,0
access_stock_scrap_group_sale_director,stock_scrap_group_sale_director,stock.model_stock_scrap,sf_base.group_sale_director,1,0,0,0 access_stock_scrap_group_sale_director,stock_scrap_group_sale_director,stock.model_stock_scrap,sf_base.group_sale_director,1,0,0,0
access_account_move_group_plan_dispatch,account_move_group_plan_dispatch,account.model_account_move,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
117
118
119
120
121
122
123

View File

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

View File

@@ -25,7 +25,7 @@
'data': [ 'data': [
# 'security/ir.model.access.csv', # 'security/ir.model.access.csv',
'views/stock_picking.xml', 'views/stock_picking.xml',
'views/stock_product_template.xml' 'views/stock_product_template.xml',
], ],
# only loaded in demonstration mode # only loaded in demonstration mode
'demo': [ 'demo': [

View File

@@ -221,5 +221,6 @@ class MrpProduction(models.Model):
logging.info('调用CAM工单程序用刀计划创建方法') logging.info('调用CAM工单程序用刀计划创建方法')
self.env['sf.cam.work.order.program.knife.plan'].sudo().create_cam_work_plan(cnc_ids) self.env['sf.cam.work.order.program.knife.plan'].sudo().create_cam_work_plan(cnc_ids)
if not invalid_tool and not missing_tool_1: if not invalid_tool and not missing_tool_1:
self.sudo().write({'tool_state': '0'})
logging.info('校验cnc用刀正常!') logging.info('校验cnc用刀正常!')
logging.info('工单cnc程序用刀校验完成') logging.info('工单cnc程序用刀校验完成')

View File

@@ -602,7 +602,7 @@ var GanttRow = Widget.extend({
// pill._color = self._getColor(pill[self.colorField]); // pill._color = self._getColor(pill[self.colorField]);
// 设置pill背景颜色2 修改时间2024年6月25日17:09:43 // 设置pill背景颜色2 修改时间2024年6月25日17:09:43
let isDelay = false let isDelay = false
if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工 if(pill.state != 'processing' && pill.state != 'finished' && pill.order_deadline) { // 判断待加工
isDelay = pill.order_deadline.isBefore(new Date()) isDelay = pill.order_deadline.isBefore(new Date())
} }
if(isDelay) { if(isDelay) {