工艺外协代码

This commit is contained in:
liaodanlong
2025-04-29 13:39:36 +08:00
parent 95e2c2db0d
commit 95c25ac7b8
16 changed files with 472 additions and 425 deletions

View File

@@ -9,8 +9,7 @@ class MrpProduction(models.Model):
@api.depends('state')
def _compute_pr_mp_count(self):
for item in self:
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name)])
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')])
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', item.name), ('is_subcontract', '!=', 'True')])
if pr_ids:
item.pr_mp_count = len(pr_ids)
else:
@@ -21,8 +20,7 @@ class MrpProduction(models.Model):
采购请求
"""
self.ensure_one()
# pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name),('is_subcontract', '!=', True)])
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name)])
pr_ids = self.env['purchase.request'].sudo().search([('origin', 'like', self.name),('is_subcontract', '!=', True)])
action = {
'res_model': 'purchase.request',
'type': 'ir.actions.act_window',

View File

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

View File

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

View File

@@ -900,40 +900,40 @@ class MrpProduction(models.Model):
for workorder in production.workorder_ids:
workorder.duration_expected = workorder._get_duration_expected()
# def _create_subcontract_purchase_request(self, purchase_request_line):
# sorted_list = sorted(purchase_request_line, key=itemgetter('name'))
# grouped_purchase_request_line = {
# k: list(g)
# for k, g in groupby(sorted_list, key=itemgetter('name'))
# }
# for name, request_line in grouped_purchase_request_line.items():
# request_line_sorted_list = sorted(request_line, key=itemgetter('product_id'))
# grouped_purchase_request_line_sorted_list = {
# k: list(g)
# for k, g in groupby(request_line_sorted_list, key=itemgetter('product_id'))
# }
# purchase_request_model = self.env["purchase.request"]
# origin = ", ".join({item['production_name'] for item in request_line_sorted_list if item.get('production_name')})
# pr = purchase_request_model.create({
# "origin": origin,
# "company_id": self.company_id.id,
# "picking_type_id": self.env.ref('stock.picking_type_in').id,
# "group_id": request_line[0].get('group_id'),
# "requested_by": self.env.context.get("uid", self.env.uid),
# "assigned_to": False,
# "bom_id": self[0].bom_id.id,
# "is_subcontract":True,
# })
# self[0].bom_id.bom_line_ids.product_id.route_ids = [(4,self.env.ref(
# 'sf_stock.stock_route_process_outsourcing').id)]
# for product_id, request_line_list in grouped_purchase_request_line_sorted_list.items():
# cur_request_line = request_line_list[0]
# cur_request_line['product_qty'] = len(request_line_list)
# cur_request_line['request_id'] = pr.id
# cur_request_line['origin'] = ", ".join({item['production_name'] for item in request_line_list if item.get('production_name')})
# cur_request_line.pop('group_id', None)
# cur_request_line.pop('production_name', None)
# self.env["purchase.request.line"].create(cur_request_line)
def _create_subcontract_purchase_request(self, purchase_request_line):
sorted_list = sorted(purchase_request_line, key=itemgetter('name'))
grouped_purchase_request_line = {
k: list(g)
for k, g in groupby(sorted_list, key=itemgetter('name'))
}
for name, request_line in grouped_purchase_request_line.items():
request_line_sorted_list = sorted(request_line, key=itemgetter('product_id'))
grouped_purchase_request_line_sorted_list = {
k: list(g)
for k, g in groupby(request_line_sorted_list, key=itemgetter('product_id'))
}
purchase_request_model = self.env["purchase.request"]
origin = ", ".join({item['production_name'] for item in request_line_sorted_list if item.get('production_name')})
pr = purchase_request_model.create({
"origin": origin,
"company_id": self.company_id.id,
"picking_type_id": self.env.ref('stock.picking_type_in').id,
"group_id": request_line[0].get('group_id'),
"requested_by": self.env.context.get("uid", self.env.uid),
"assigned_to": False,
"bom_id": self[0].bom_id.id,
"is_subcontract":True,
})
self[0].bom_id.bom_line_ids.product_id.route_ids = [(4,self.env.ref(
'sf_stock.stock_route_process_outsourcing').id)]
for product_id, request_line_list in grouped_purchase_request_line_sorted_list.items():
cur_request_line = request_line_list[0]
cur_request_line['product_qty'] = len(request_line_list)
cur_request_line['request_id'] = pr.id
cur_request_line['origin'] = ", ".join({item['production_name'] for item in request_line_list if item.get('production_name')})
cur_request_line.pop('group_id', None)
cur_request_line.pop('production_name', None)
self.env["purchase.request.line"].create(cur_request_line)
# 外协出入库单处理
def get_subcontract_pick_purchase(self):
@@ -961,14 +961,14 @@ class MrpProduction(models.Model):
if not sorted_workorders:
return
for workorders in reversed(sorted_workorders):
self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
# purchase_request_line = purchase_request_line + self.env['purchase.order'].get_purchase_request(
# workorders, production)
# all_workorders += workorders
# self._create_subcontract_purchase_request(purchase_request_line)
# for workorder in all_workorders:
# workorder._compute_pr_mp_count()
# self.env['stock.picking'].create_outcontract_picking(workorders, production, sorted_workorders)
# self.env['purchase.order'].get_purchase_order(workorders, production, product_id_to_production_names)
purchase_request_line = purchase_request_line + self.env['purchase.order'].get_purchase_request(
workorders, production)
all_workorders += workorders
self._create_subcontract_purchase_request(purchase_request_line)
for workorder in all_workorders:
workorder._compute_pr_mp_count()
# 工单排序
def _reset_work_order_sequence1(self, k):
for rec in self:

View File

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

View File

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

View File

@@ -70,21 +70,21 @@ class ResMrpWorkOrder(models.Model):
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
tracking=True)
back_button_display = fields.Boolean(default=False, compute='_compute_back_button_display', store=True)
# pr_mp_count = fields.Integer('采购申请单数量', compute='_compute_pr_mp_count', store=True)
#
# @api.depends('state')
# def _compute_pr_mp_count(self):
# for item in self:
# if not item.is_subcontract:
# item.pr_mp_count = 0
# continue
# pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', item.production_id.name), ('is_subcontract', '=', 'True'),
# ('state', '!=', 'rejected')])
# if pr_ids:
# item.pr_mp_count = len(pr_ids)
# else:
# item.pr_mp_count = 0
pr_mp_count = fields.Integer('采购申请单数量', compute='_compute_pr_mp_count', store=True)
@api.depends('state')
def _compute_pr_mp_count(self):
for item in self:
if not item.is_subcontract:
item.pr_mp_count = 0
continue
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', item.production_id.name), ('is_subcontract', '=', 'True'),
('state', '!=', 'rejected')])
if pr_ids:
item.pr_mp_count = len(pr_ids)
else:
item.pr_mp_count = 0
@api.depends('state')
def _compute_back_button_display(self):
for record in self:
@@ -443,12 +443,11 @@ class ResMrpWorkOrder(models.Model):
def _compute_surface_technics_purchase_ids(self):
for order in self:
if order.routing_type == '表面工艺' and order.state not in ['cancel']:
# domain = [('group_id', '=', self.production_id.procurement_group_id.id),
# ('purchase_type', '=', 'consignment'), ('state', '!=', 'cancel')]
domain = [('purchase_type', '=', 'consignment'),
('origin', 'like', '%' + self.production_id.name + '%'),
('state', '!=', 'cancel')]
# domain = [('purchase_type', '=', 'consignment'),
# ('origin', 'like', '%' + self.production_id.name + '%'),
# ('state', '!=', 'cancel')]
purchase = self.env['purchase.order'].search(domain)
order.surface_technics_purchase_count = 0
if not purchase:
@@ -461,30 +460,30 @@ class ResMrpWorkOrder(models.Model):
else:
order.surface_technics_purchase_count = 0
# def action_view_pr_mrp_workorder(self):
# """
# 采购请求
# """
# self.ensure_one()
# pr_ids = self.env['purchase.request'].sudo().search(
# [('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
# ('state', '!=', 'rejected')])
# action = {
# 'res_model': 'purchase.request',
# 'type': 'ir.actions.act_window',
# }
# if len(pr_ids) == 1:
# action.update({
# 'view_mode': 'form',
# 'res_id': pr_ids[0].id,
# })
# else:
# action.update({
# 'name': _("从 %s生成采购请求单", self.name),
# 'domain': [('id', 'in', pr_ids)],
# 'view_mode': 'tree,form',
# })
# return action
def action_view_pr_mrp_workorder(self):
"""
采购请求
"""
self.ensure_one()
pr_ids = self.env['purchase.request'].sudo().search(
[('origin', 'like', self.production_id.name), ('is_subcontract', '=', 'True'),
('state', '!=', 'rejected')])
action = {
'res_model': 'purchase.request',
'type': 'ir.actions.act_window',
}
if len(pr_ids) == 1:
action.update({
'view_mode': 'form',
'res_id': pr_ids[0].id,
})
else:
action.update({
'name': _("%s生成采购请求单", self.name),
'domain': [('id', 'in', pr_ids)],
'view_mode': 'tree,form',
})
return action
def action_view_surface_technics_purchase(self):
self.ensure_one()
# if self.routing_type == '表面工艺':
@@ -513,7 +512,7 @@ class ResMrpWorkOrder(models.Model):
return result
def _get_surface_technics_purchase_ids(self):
domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment'), ('state', '!=', 'cancel')]
domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment'), ('is_subcontract', '=', 'True'), ('state', '!=', 'cancel')]
# domain = [('origin', 'like', '%' + self.production_id.name + '%'), ('purchase_type', '=', 'consignment')]
# domain = [('group_id', '=', self.production_id.procurement_group_id.id), ('purchase_type', '=', 'consignment')]
purchase_orders = self.env['purchase.order'].search(domain, order='id desc')

View File

@@ -59,6 +59,86 @@ class PurchaseOrder(models.Model):
production_id = self.env['mrp.production'].search([('origin', 'in', origins)])
purchase.production_count = len(production_id)
def process_replenish(self,production,total_qty):
record = self
bom_line_id = production.bom_id.bom_line_ids
replenish = self.env['stock.warehouse.orderpoint'].search([
('product_id', '=', bom_line_id.product_id.id),
(
'location_id', '=', self.env.ref('sf_stock.stock_location_outsourcing_material_receiving_area').id),
# ('state', 'in', ['draft', 'confirmed'])
], limit=1)
if not replenish:
replenish_model = self.env['stock.warehouse.orderpoint']
replenish = replenish_model.create({
'product_id': bom_line_id.product_id.id,
'location_id': self.env.ref(
'sf_stock.stock_location_outsourcing_material_receiving_area').id,
'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
'group_id': record.group_id.id,
'qty_to_order': total_qty,
'origin': record.name,
})
else:
replenish.write({
'product_id': bom_line_id.product_id.id,
'location_id': self.env.ref(
'sf_stock.stock_location_outsourcing_material_receiving_area').id,
'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
'group_id': record.group_id.id,
'qty_to_order': total_qty + replenish.qty_to_order,
'origin': record.name + ',' + replenish.origin,
})
replenish.action_replenish()
def outsourcing_service_replenishment(self):
record = self
if record.purchase_type != 'consignment':
return
grouped_lines = {}
for line in record.order_line:
if line.related_product.id not in grouped_lines:
grouped_lines[line.related_product.id] = []
grouped_lines[line.related_product.id].append(line)
for product_id,lines in grouped_lines.items():
production = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
if not production:
continue
total_qty = sum(line.product_qty for line in lines)
record.process_replenish(production,total_qty)
for product_id,lines in grouped_lines.items():
productions = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
if not productions:
continue
# production.bom_id.bom_line_ids.product_id
location_id = self.env['stock.location'].search([('name', '=', '制造前')])
quants = self.env['stock.quant'].search([
('product_id', '=', productions.bom_id.bom_line_ids.product_id.id),
('location_id', '=', location_id.id)
])
total_qty = sum(quants.mapped('quantity')) # 计算该位置的总库存量
is_available = total_qty > 0
if not is_available:
continue
for production_id in productions:
work_ids = production_id.workorder_ids.filtered(
lambda wk: wk.state not in ['done', 'rework', 'cancel'])
if not work_ids:
continue
min_sequence_wk = min(work_ids, key=lambda wk: wk.sequence)
if min_sequence_wk.is_subcontract:
picking_id = production_id.picking_ids.filtered(
lambda wk: wk.location_id.name == '制造前' and wk.location_dest_id.name == '外协加工区')
move_out = picking_id.move_ids
for mo in move_out:
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
self.env['stock.move.line'].create(
mo.get_move_line(production_id, min_sequence_wk))
# product = self.env['mrp.production'].search([('product_id', '=', product_id)], limit=1)
# match = re.search(r'(S\d{5}-\d)',product.name)
# pass
def button_confirm(self):
for record in self:
for line in record.order_line:
@@ -66,37 +146,7 @@ class PurchaseOrder(models.Model):
raise UserError('请对【产品】中的【数量】进行输入')
if line.price_unit <= 0:
raise UserError('请对【产品】中的【单价】进行输入')
# if record.purchase_type == 'consignment':
# bom_line_id = record.order_line[0].purchase_request_lines.request_id.bom_id.bom_line_ids
# replenish = self.env['stock.warehouse.orderpoint'].search([
# ('product_id', '=', bom_line_id.product_id.id),
# (
# 'location_id', '=', self.env.ref('sf_stock.stock_location_outsourcing_material_receiving_area').id),
# # ('state', 'in', ['draft', 'confirmed'])
# ], limit=1)
# if not replenish:
# replenish_model = self.env['stock.warehouse.orderpoint']
# replenish = replenish_model.create({
# 'product_id': bom_line_id.product_id.id,
# 'location_id': self.env.ref(
# 'sf_stock.stock_location_outsourcing_material_receiving_area').id,
# 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
# 'group_id': record.group_id.id,
# 'qty_to_order': 1,
# 'origin': record.name,
# })
# else:
# replenish.write({
# 'product_id': bom_line_id.product_id.id,
# 'location_id': self.env.ref(
# 'sf_stock.stock_location_outsourcing_material_receiving_area').id,
# 'route_id': self.env.ref('sf_stock.stock_route_process_outsourcing').id,
# 'group_id': record.group_id.id,
# 'qty_to_order': 1 + replenish.qty_to_order,
# 'origin': record.name + ',' + replenish.origin,
# })
# replenish.action_replenish()
record.outsourcing_service_replenishment()
return super(PurchaseOrder, self).button_confirm()

View File

@@ -1,30 +1,30 @@
# # -*- coding: utf-8 -*-
# import base64
# import datetime
# import logging
# import json
# import os
# import re
# import traceback
# from operator import itemgetter
#
# import requests
# from itertools import groupby
# from collections import defaultdict, namedtuple
#
# from odoo import api, fields, models, SUPERUSER_ID, _
# from odoo.exceptions import UserError, ValidationError
# from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
#
#
# class PurchaseRequestLine(models.Model):
# _inherit = 'purchase.request'
# is_subcontract = fields.Boolean(string='是否外协',default=False)
# class PurchaseRequestLine(models.Model):
# _inherit = 'purchase.request.line'
# is_subcontract = fields.Boolean(string='是否外协')
#
#
# class PurchaseRequest(models.Model):
# _inherit = 'purchase.request'
# bom_id = fields.Many2one('mrp.bom')
# -*- coding: utf-8 -*-
import base64
import datetime
import logging
import json
import os
import re
import traceback
from operator import itemgetter
import requests
from itertools import groupby
from collections import defaultdict, namedtuple
from odoo import api, fields, models, SUPERUSER_ID, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
class PurchaseRequestLine(models.Model):
_inherit = 'purchase.request'
is_subcontract = fields.Boolean(string='是否外协',default=False)
class PurchaseRequestLine(models.Model):
_inherit = 'purchase.request.line'
is_subcontract = fields.Boolean(string='是否外协')
class PurchaseRequest(models.Model):
_inherit = 'purchase.request'
bom_id = fields.Many2one('mrp.bom')

View File

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

View File

@@ -383,7 +383,7 @@
<field name="process_parameters_id"
attrs="{'readonly': [('id', '!=', False),('routing_tag', '=', 'standard')]}"
string="参数" context="{'route_id':route_id,'production_id': production_id}"
options="{'no_create': True}"/>
options="{'no_create': True}" domain="[('routing_id', '=', 'route_id')]"/>
<field name="panel" readonly="1"/>
<field name="routing_tag" readonly="1" widget="badge"
decoration-success="routing_tag == 'standard'"

View File

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

View File

@@ -144,17 +144,17 @@
statusbar_visible="pending,waiting,ready,progress,to be detected,done,rework"/>
</xpath>
<xpath expr="//div[@name='button_box']" position="inside">
<!-- <button type="object" name="action_view_pr_mrp_workorder" class="oe_stat_button"-->
<!-- icon="fa-credit-card"-->
<!-- groups="base.group_user,sf_base.group_sf_order_user"-->
<!-- attrs="{'invisible': [('pr_mp_count', '=', 0)]}">-->
<!-- <div class="o_field_widget o_stat_info">-->
<!-- <span class="o_stat_value">-->
<!-- <field name="pr_mp_count"/>-->
<!-- </span>-->
<!-- <span class="o_stat_text">采购申请</span>-->
<!-- </div>-->
<!-- </button>-->
<button type="object" name="action_view_pr_mrp_workorder" class="oe_stat_button"
icon="fa-credit-card"
groups="base.group_user,sf_base.group_sf_order_user"
attrs="{'invisible': [('pr_mp_count', '=', 0)]}">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value">
<field name="pr_mp_count"/>
</span>
<span class="o_stat_text">采购申请</span>
</div>
</button>
<button type="object" name="action_view_surface_technics_purchase" class="oe_stat_button"
icon="fa-credit-card"
groups="base.group_user,sf_base.group_sf_order_user"

View File

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

View File

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

View File

@@ -346,10 +346,10 @@ class RePurchaseOrder(models.Model):
if purchase.order_line[0].product_id.categ_id.name == '坯料':
if purchase.order_line[0].product_id.materials_type_id.gain_way == '外协':
purchase.purchase_type = 'outsourcing'
# request_lines = self.order_line.mapped('purchase_request_lines')
# # 检查是否存在 is_subcontract 为 True 的行
# if any(line.is_subcontract for line in request_lines):
# purchase.purchase_type = 'consignment'
request_lines = self.order_line.mapped('purchase_request_lines')
# 检查是否存在 is_subcontract 为 True 的行
if any(line.is_subcontract for line in request_lines):
purchase.purchase_type = 'consignment'
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '预警'), ('overdue', '已逾期')],
@@ -384,27 +384,27 @@ class RePurchaseOrder(models.Model):
if not line.taxes_id:
raise UserError('请对【产品】中的【税】进行选择')
# def get_purchase_request(self, consecutive_process_parameters, production):
# result = []
# for pp in consecutive_process_parameters:
# server_template = self.env['product.template'].search(
# [('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
# ('detailed_type', '=', 'service')])
# # route_ids
# result.append({
# "product_id": server_template.product_variant_id.id,
# "name": production.procurement_group_id.name,
# "date_required": fields.Datetime.now(),
# "product_uom_id":server_template.uom_id.id,
# "product_qty": 1,
# "request_id": False,
# "move_dest_ids": False,
# "orderpoint_id": False,
# 'is_subcontract':True,
# 'group_id':production.procurement_group_id.id,
# 'production_name':pp.production_id.name,
# })
# return result
def get_purchase_request(self, consecutive_process_parameters, production):
result = []
for pp in consecutive_process_parameters:
server_template = self.env['product.template'].search(
[('server_product_process_parameters_id', '=', pp.surface_technics_parameters_id.id),
('detailed_type', '=', 'service')])
# route_ids
result.append({
"product_id": server_template.product_variant_id.id,
"name": production.procurement_group_id.name,
"date_required": fields.Datetime.now(),
"product_uom_id":server_template.uom_id.id,
"product_qty": 1,
"request_id": False,
"move_dest_ids": False,
"orderpoint_id": False,
'is_subcontract':True,
'group_id':production.procurement_group_id.id,
'production_name':pp.production_id.name,
})
return result
def get_purchase_order(self, consecutive_process_parameters, production, product_id_to_production_names):
for pp in consecutive_process_parameters: