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

@@ -13,3 +13,5 @@ from . import agv_scheduling
from . import res_config_setting
from . import sf_technology_design
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('名称')
# 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',
'成品工序模板(自动化产线加工')
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['purchase.order'].get_purchase_order(workorder, production,
# product_id_to_production_names)
# product_id_to_production_names)
consecutive_workorders = []
# 处理最后一个组,即使它可能只有一个工作订单

View File

@@ -86,9 +86,12 @@ class ResMrpRoutingWorkcenter(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('production_id'):
route_ids = []
technology_design = self.env['sf.technology.design'].search(
[('production_id', '=', self._context.get('production_id'))])
route_ids = [t.route_id.id for t in technology_design]
domain = [('id', 'not in', route_ids)]
for t in technology_design.filtered(lambda a: a.routing_tag == 'special'):
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 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_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True,
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_length = fields.Float(string='坯料长度(mm)', related='material_length', readonly=True, store=False)
product_tmpl_id_width = fields.Float(string='坯料度(mm)', related='material_width', readonly=True, store=False)
product_tmpl_id_height = fields.Float(string='坯料高度(mm)', related='material_height', readonly=True, store=False)
# product_tmpl_id_length = fields.Float(related='production_id.product_tmpl_id.length', readonly=True, store=True,
# 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,
store=True, check_company=True, string="材料")
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')
is_subcontract = fields.Boolean(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_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(
[('sequence', '=', workorder.sequence - 1), ('routing_type', '=', '表面工艺'),
('production_id', '=', workorder.production_id.id)])
if previous_workorder:
if previous_workorder.supplier_id != workorder.supplier_id:
process_product = self.env['product.template']._get_process_parameters_product(
previous_workorder.surface_technics_parameters_id)
domain += [('partner_id', '=', process_product.partner_id.id)]
else:
domain += [('surface_technics_parameters_id', '=', workorder.surface_technics_parameters_id.id)]
# if previous_workorder:
# if previous_workorder.supplier_id != workorder.supplier_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')
workorder.surface_technics_picking_count = len(picking_ids)
workorder.picking_ids = picking_ids.ids
@@ -269,65 +272,72 @@ class ResMrpWorkOrder(models.Model):
@api.depends('state', 'production_id.name')
def _compute_surface_technics_purchase_ids(self):
for order in self:
if order.routing_type == '表面工艺':
if order.production_id.production_type == '自动化产线加工':
domain = [('programming_no', '=', order.production_id.programming_no)]
else:
domain = [('origin', '=', order.production_id.origin)]
production_programming = self.env['mrp.production'].search(domain, order='name asc')
production_list = [production.name for production in production_programming]
production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False)
if order.routing_type == '表面工艺' and order.state not in ['cancel']:
# if order.production_id.production_type == '自动化产线加工':
# domain = [('programming_no', '=', order.production_id.programming_no)]
# else:buzhdiao
# domain = [('origin', '=', order.production_id.origin)]
# production_programming = self.env['mrp.production'].search(domain, order='name asc')
# production_list = [production.name for production in production_programming]
# production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False)
# technology_design = self.env['sf.technology.design'].search(
# [('process_parameters_id', '=', order.surface_technics_parameters_id.id),
# ('production_id', '=', order.production_id.id)])
# if technology_design.is_auto is False:
# domain = [('origin', '=', order.production_id.name)]
# 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_num = 0
if not purchase:
order.surface_technics_purchase_count = 0
for line in purchase.order_line:
if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id:
if line.product_qty == len(production_no_remanufacture):
purchase_num += 1
order.surface_technics_purchase_count = purchase_num
for po in purchase:
for line in po.order_line:
if line.product_id.server_product_process_parameters_id == order.surface_technics_parameters_id:
if line.product_qty == 1:
purchase_num += 1
order.surface_technics_purchase_count = purchase_num
else:
order.surface_technics_purchase_count = 0
def action_view_surface_technics_purchase(self):
self.ensure_one()
if self.routing_type == '表面工艺':
if self.production_id.production_type == '自动化产线加工':
domain = [('programming_no', '=', self.production_id.programming_no)]
else:
domain = [('origin', '=', self.production_id.origin)]
production_programming = self.env['mrp.production'].search(domain, order='name asc')
production_list = [production.name for production in production_programming]
production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False)
# if self.routing_type == '表面工艺':
# if self.production_id.production_type == '自动化产线加工':
# domain = [('programming_no', '=', self.production_id.programming_no)]
# else:
# domain = [('origin', '=', self.production_id.origin)]
# production_programming = self.env['mrp.production'].search(domain, order='name asc')
# production_list = [production.name for production in production_programming]
# production_no_remanufacture = production_programming.filtered(lambda a: a.is_remanufacture is False)
# technology_design = self.env['sf.technology.design'].search(
# [('process_parameters_id', '=', self.surface_technics_parameters_id.id),
# ('production_id', '=', self.production_id.id)])
# if technology_design.is_auto is False:
# domain = [('origin', '=', self.production_id.name)]
# else:
domain = [('origin', '=', ','.join(production_list)), ('purchase_type', '=', 'consignment')]
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
purchase_orders_id = self._get_surface_technics_purchase_ids()
result = {
"type": "ir.actions.act_window",
"res_model": "purchase.order",
"res_id": purchase_orders_id,
"res_id": purchase_orders_id.id,
# "domain": [['id', 'in', self.purchase_id]],
"name": _("Purchase Orders"),
'view_mode': 'form',
}
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='外协供应商')
equipment_id = fields.Many2one('maintenance.equipment', string='加工设备', tracking=True)
@@ -1025,47 +1035,47 @@ class ResMrpWorkOrder(models.Model):
'production_id.programming_state')
def _compute_state(self):
# super()._compute_state()
for workorder in self:
if workorder.sequence != 1:
previous_workorder = self.env['mrp.workorder'].search(
[('production_id', '=', workorder.production_id.id),
('sequence', '=', workorder.sequence - 1)])
if workorder.state == 'pending':
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.sequence == 1 and not workorder.blocked_by_workorder_ids)
or (workorder.blocked_by_workorder_ids.state in ('done', 'cancel')
and workorder.blocked_by_workorder_ids.test_results not in ['报废', '返工'])
or (previous_workorder.state in ('done', 'cancel')
and not workorder.blocked_by_workorder_ids
and previous_workorder.test_results not in ['报废', '返工'])
):
workorder.state = 'ready'
continue
if workorder.production_id.schedule_state == '未排' and workorder.state in ('waiting', 'ready'):
if workorder.sequence != 1:
workorder.state = 'pending'
continue
if workorder.state not in ('waiting', 'ready'):
continue
if workorder.state in (
'waiting') and workorder.sequence == 1 and workorder.production_id.schedule_state == '已排':
workorder.state = 'ready'
continue
if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
workorder.state = 'pending'
if workorder.state in ['waiting']:
if previous_workorder.state == 'waiting':
workorder.state = 'pending'
if workorder.sequence == 1 and workorder.state == 'pending':
workorder.state = 'waiting'
continue
if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
continue
if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting' and workorder.production_id.schedule_state == '已排':
workorder.state = 'ready'
elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
workorder.state = 'waiting'
# for workorder in self:
# if workorder.sequence != 1:
# previous_workorder = self.env['mrp.workorder'].search(
# [('production_id', '=', workorder.production_id.id),
# ('sequence', '=', workorder.sequence - 1)])
# if workorder.state == 'pending':
# 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.sequence == 1 and not workorder.blocked_by_workorder_ids)
# or (workorder.blocked_by_workorder_ids.state in ('done', 'cancel')
# and workorder.blocked_by_workorder_ids.test_results not in ['报废', '返工'])
# or (previous_workorder.state in ('done', 'cancel')
# and not workorder.blocked_by_workorder_ids
# and previous_workorder.test_results not in ['报废', '返工'])
# ):
# workorder.state = 'ready'
# continue
# if workorder.production_id.schedule_state == '未排' and workorder.state in ('waiting', 'ready'):
# if workorder.sequence != 1:
# workorder.state = 'pending'
# continue
# if workorder.state not in ('waiting', 'ready'):
# continue
# if workorder.state in (
# 'waiting') and workorder.sequence == 1 and workorder.production_id.schedule_state == '已排':
# workorder.state = 'ready'
# continue
# if not all([wo.state in ('done', 'cancel') for wo in workorder.blocked_by_workorder_ids]):
# workorder.state = 'pending'
# if workorder.state in ['waiting']:
# if previous_workorder.state == 'waiting':
# workorder.state = 'pending'
# if workorder.sequence == 1 and workorder.state == 'pending':
# workorder.state = 'waiting'
# continue
# if workorder.production_id.reservation_state not in ('waiting', 'confirmed', 'assigned'):
# continue
# if workorder.production_id.reservation_state == 'assigned' and workorder.state == 'waiting' and workorder.production_id.schedule_state == '已排':
# workorder.state = 'ready'
# elif workorder.production_id.reservation_state != 'assigned' and workorder.state == 'ready':
# workorder.state = 'waiting'
for workorder in self:
# 如果工单的工序没有进行排序则跳出循环
@@ -1090,13 +1100,21 @@ class ResMrpWorkOrder(models.Model):
and workorder.production_id.schedule_state == '已排'
and len(workorder.production_id.picking_ids.filtered(
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
# ================= 如果制造订单刀具状态为[无效刀、缺刀] 或者 制造订单状态为[返工]==========================
if (workorder.production_id.tool_state in ['1', '2'] or workorder.production_id.state == 'rework'
or workorder.production_id.schedule_state != '已排'
or len(
workorder.production_id.picking_ids.filtered(lambda w: w.state not in ['done', 'cancel'])) != 0
or workorder.production_id.reservation_state not in ['assigned']
or workorder.production_id.workorder_ids.filtered(
lambda wk: wk.sequence == workorder.sequence - 1).test_results in ['报废', '返工']):
if workorder.state != 'waiting':
@@ -1117,21 +1135,26 @@ class ResMrpWorkOrder(models.Model):
if workorder.is_subcontract is False:
workorder.state = 'ready'
else:
production_programming = self.env['mrp.production'].search(
[('origin', '=', self.production_id.origin)], order='name asc')
production_no_remanufacture = production_programming.filtered(
lambda a: a.is_remanufacture is False)
production_list = [production.name for production in production_programming]
purchase_orders = self.env['purchase.order'].search(
[('origin', 'ilike', ','.join(production_list))])
for line in purchase_orders.order_line:
if (
line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id
and line.product_qty == len(production_no_remanufacture)):
if all(pur_order.state == 'purchase' for pur_order in purchase_orders):
workorder.state = 'ready'
else:
workorder.state = 'waiting'
# production_programming = self.env['mrp.production'].search(
# [('origin', '=', self.production_id.origin)], order='name asc')
# production_no_remanufacture = production_programming.filtered(
# lambda a: a.is_remanufacture is False)
# production_list = [production.name for production in production_programming]
# purchase_orders = self.env['purchase.order'].search(
# [('origin', 'ilike', ','.join(production_list))])
# for line in purchase_orders.order_line:
# if (
# line.product_id.server_product_process_parameters_id == workorder.surface_technics_parameters_id
# and line.product_qty == len(production_no_remanufacture)):
# if all(pur_order.state == 'purchase' for pur_order in purchase_orders):
# workorder.state = 'ready'
# else:
# 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),
# ('processing_panel', '=', workorder.processing_panel),
@@ -1194,6 +1217,10 @@ class ResMrpWorkOrder(models.Model):
# 重写工单开始按钮方法
def button_start(self):
# 判断工单状态是否为等待组件
if self.state in ['waiting', 'pending']:
raise UserError('制造订单【%s】缺少组件信息!' % self.production_id.name)
if self.routing_type == 'CNC加工':
self.env['sf.production.plan'].sudo().search([('name', '=', self.production_id.name)]).write({
'state': 'processing',
@@ -1201,9 +1228,6 @@ class ResMrpWorkOrder(models.Model):
})
if self.sequence == 1:
# 判断工单状态是否为等待组件
if self.state == 'waiting':
raise UserError('制造订单【%s】缺少组件信息!' % self.production_id.name)
# 判断是否有坯料的序列号信息
boolean = False
if self.production_id.move_raw_ids:
@@ -1240,15 +1264,33 @@ class ResMrpWorkOrder(models.Model):
# 表面工艺外协出库单
if self.routing_type == '表面工艺':
if self.is_subcontract is True:
move_out = self.env['stock.move'].search(
[('location_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
('location_dest_id', '=', self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id),
('origin', '=', self.production_id.name)])
if move_out.state != 'done':
move_out.write({'state': 'assigned', 'production_id': False})
self.env['stock.move.line'].create(move_out.get_move_line(self.production_id, self))
move_out = self.move_subcontract_workorder_ids[1]
# move_out = self.env['stock.move'].search(
# [('location_id', '=', self.env['stock.location'].search(
# [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id),
# ('location_dest_id', '=', self.env['stock.location'].search(
# [('barcode', 'ilike', 'VL-SPOC')]).id),
# ('origin', '=', self.production_id.name), ('state', 'not in', ['cancel', 'done'])])
for mo in move_out:
if mo.state != 'done':
mo.write({'state': 'assigned', 'production_id': False})
if not mo.move_line_ids:
self.env['stock.move.line'].create(mo.get_move_line(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()
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'))
if picks:
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_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type)
@@ -1371,7 +1420,7 @@ class ResMrpWorkOrder(models.Model):
# record.recreateManufacturingOrWorkerOrder()
is_production_id = False
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 (
len(done_workorder) == len(record.production_id.workorder_ids)):
is_production_id = True
@@ -1388,19 +1437,20 @@ class ResMrpWorkOrder(models.Model):
# workorder.rfid_code_old = rfid_code
# workorder.rfid_code = False
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)
for move_raw_id in record.production_id.move_raw_ids:
move_raw_id.quantity_done = move_raw_id.product_uom_qty
record.process_state = '已完工'
record.production_id.process_state = '已完工'
if record.routing_type in ['表面工艺']:
raw_move = self.env['stock.move'].sudo().search(
[('origin', '=', record.production_id.name),
('procure_method', 'in', ['make_to_order', 'make_to_stock']),
('state', '!=', 'done')])
if raw_move:
raw_move.write({'state': 'done'})
# if record.routing_type in ['表面工艺']:
# raw_move = self.env['stock.move'].sudo().search(
# [('origin', '=', record.production_id.name),
# ('procure_method', 'in', ['make_to_order', 'make_to_stock']),
# ('state', '!=', 'done')])
# if raw_move:
# raw_move.write({'state': 'done'})
record.production_id.button_mark_done1()
# record.production_id.state = 'done'
@@ -1520,6 +1570,8 @@ class ResMrpWorkOrder(models.Model):
'default_confirm_button': '确认解除',
# '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):

View File

@@ -859,12 +859,12 @@ class ResProductMo(models.Model):
raise UserError('请先配置模型类型内的坯料冗余')
vals = {
'name': '%s-%s-%s' % ('P', order_id.name, i),
'model_long': item['model_long'] + embryo_redundancy_id.long,
'model_width': item['model_width'] + embryo_redundancy_id.width,
'model_height': item['model_height'] + embryo_redundancy_id.height,
'model_volume': (item['model_long'] + embryo_redundancy_id.long) * (
'model_long': self.format_float(item['model_long'] + embryo_redundancy_id.long),
'model_width': self.format_float(item['model_width'] + embryo_redundancy_id.width),
'model_height': self.format_float(item['model_height'] + embryo_redundancy_id.height),
'model_volume': self.format_float((item['model_long'] + embryo_redundancy_id.long) * (
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,
'model_processing_panel': item['processing_panel_detail'],
'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,
'quality_standard', item['quality_standard_mimetype'])
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):
type_ids = []

View File

@@ -0,0 +1,71 @@
from datetime import datetime
from odoo import models
import logging
import base64
import hashlib
_logger = logging.getLogger(__name__)
class QuickEasyOrder(models.Model):
_inherit = 'quick.easy.order'
def distribute_to_factory(self, obj):
"""
多供货方式,重写派单到工厂
:return:
"""
try:
_logger.info('---------派单到工厂-------')
res = {'bfm_process_order_list': []}
for item in obj:
attachment = item.upload_model_file[0]
base64_data = base64.b64encode(attachment.datas)
base64_datas = base64_data.decode('utf-8')
barcode = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
# logging.info('model_file-size: %s' % len(item.model_file))
res['bfm_process_order_list'].append({
'model_long': item.model_length,
'model_width': item.model_width,
'model_height': item.model_height,
'model_volume': item.model_volume,
'model_machining_precision': item.machining_precision,
'model_name': attachment.name,
'model_data': base64_datas,
'model_file': base64.b64encode(item.model_file).decode('utf-8'),
'texture_code': item.material_id.materials_no,
'texture_type_code': item.material_model_id.materials_no,
# 'surface_process_code': self.env['jikimo.surface.process']._json_surface_process_code(item),
'process_parameters_code': self.env[
'sf.production.process.parameter']._json_production_process_item_code(
item),
'price': item.price,
'number': item.quantity,
'total_amount': item.price,
'remark': '',
'manual_quotation': True,
'barcode': barcode,
'part_number': item.part_drawing_number,
'machining_drawings_name': '',
'quality_standard_name': '',
'machining_drawings_mimetype': '',
'quality_standard_mimetype': '',
'machining_drawings': item.machining_drawings,
'quality_standard': '',
'part_name': '',
})
company_id = self.env.ref('base.main_company').sudo()
product_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_default').sudo().with_context(active_test=False).product_variant_id
# user_id = request.env.ref('base.user_admin').sudo()
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
str(datetime.now()), '现结', '支付宝', state='draft')
order_id.default_code = obj.name
i = 1
for item in res['bfm_process_order_list']:
product = self.env['product.template'].sudo().product_create(product_id, item, order_id,
obj.name, i)
order_id.with_user(self.env.ref("base.user_admin")).sale_order_create_line(product, item)
return order_id
except Exception as e:
return UserError('工厂创建销售订单和产品失败,请联系管理员')

View File

@@ -0,0 +1,166 @@
import logging
import json
from odoo import models, fields, api
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class SaleOrder(models.Model):
_inherit = 'sale.order'
state = fields.Selection([
('draft', "报价"),
('sent', "报价已发送"),
('supply method', "供货方式待确认"),
('sale', "销售订单"),
('done', "已锁定"),
('cancel', "已取消"),
])
def confirm_to_supply_method(self):
self.state = 'supply method'
def action_confirm(self):
# 判断是否所有产品都选择了供货方式
filter_line = self.order_line.filtered(lambda line: not line.supply_method)
if filter_line:
raise UserError('当前订单内(%s)产品未选择路线,请选择后重试' % ','.join(filter_line.mapped('product_id.name')))
for line in self.order_line:
bom_type = ''
# 根据供货方式修改成品模板
if line.supply_method == 'automation':
bom_type = 'normal'
product_template_id = self.env.ref('sf_dlm.product_template_sf').sudo().product_tmpl_id
elif line.supply_method == 'outsourcing':
bom_type = 'subcontract'
product_template_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_outsourcing').sudo()
elif line.supply_method == 'purchase':
product_template_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_purchase').sudo()
elif line.supply_method == 'manual':
bom_type = 'normal'
product_template_id = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_manual_processing').sudo()
# 复制成品模板上的属性
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
product = line.product_id
# 拼接方法需要的item结构
item = {
'texture_code': product.materials_id.materials_no,
'texture_type_code': product.materials_type_id.materials_no,
'model_long': product.length,
'model_width': product.width,
'model_height': product.height,
'price': product.list_price,
'embryo_redundancy_id': line.embryo_redundancy_id,
}
# 获取成品名结尾-n的n
product_seria = int(product.name.split('-')[-1])
# 成品供货方式为采购则不生成bom
if line.supply_method != 'purchase':
bom_data = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).get_bom(product)
_logger.info('bom_data:%s' % bom_data)
if bom_data:
bom = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).bom_create(product, 'normal', False)
bom.with_user(self.env.ref("base.user_admin")).bom_create_line_has(bom_data)
else:
# 当成品上带有客供料选项时,生成坯料时选择“客供料”路线
if line.embryo_redundancy_id:
# 将成品模板的内容复制到成品上
customer_provided_embryo = self.env.ref('jikimo_sale_multiple_supply_methods.product_template_embryo_customer_provided').sudo()
# 创建坯料客供料的批量不需要创建bom
material_customer_provided_embryo = self.env['product.template'].sudo().no_bom_product_create(
customer_provided_embryo.with_context(active_test=False).product_variant_id,
item,
order_id, 'material_customer_provided', product_seria, product)
# 成品配置bom
product_bom_material_customer_provided = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create(
product, bom_type, 'product')
product_bom_material_customer_provided.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
material_customer_provided_embryo)
elif line.product_id.materials_type_id.gain_way == '自加工':
self_machining_id = self.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo()
# 创建坯料
self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create(
self_machining_id,
item,
order_id, 'self_machining', product_seria, product)
# 创建坯料的bom
self_machining_bom = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create(
self_machining_embryo, 'normal', False)
# 创建坯料里bom的组件
self_machining_bom_line = self_machining_bom.with_user(
self.env.ref("base.user_admin")).bom_create_line(
self_machining_embryo)
if not self_machining_bom_line:
raise UserError('该订单模型的材料型号暂未有原材料,请先配置再进行分配')
# 产品配置bom
product_bom_self_machining = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create(
product, bom_type, 'product')
product_bom_self_machining.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
self_machining_embryo)
elif line.product_id.materials_type_id.gain_way == '外协':
outsource_id = self.env.ref('sf_dlm.product_embryo_sf_outsource').sudo()
# 创建坯料
outsource_embryo = self.env['product.template'].sudo().no_bom_product_create(outsource_id,
item,
order_id,
'subcontract',
product_seria, product)
if outsource_embryo == -3:
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
# 创建坯料的bom
outsource_bom = self.env['mrp.bom'].with_user(self.env.ref("base.user_admin")).bom_create(
outsource_embryo,
'subcontract', True)
# 创建坯料的bom的组件
outsource_bom_line = outsource_bom.with_user(
self.env.ref("base.user_admin")).bom_create_line(outsource_embryo)
if not outsource_bom_line:
raise UserError('该订单模型的材料型号暂未有原材料,请先配置再进行分配')
# 产品配置bom
product_bom_outsource = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create(product, bom_type, 'product')
product_bom_outsource.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
outsource_embryo)
elif line.product_id.materials_type_id.gain_way == '采购':
purchase_id = self.env.ref('sf_dlm.product_embryo_sf_purchase').sudo()
purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id,
item,
order_id,
'purchase', product_seria,
product)
if purchase_embryo == -3:
raise UserError('该订单模型的材料型号暂未设置获取方式和供应商,请先配置再进行分配')
else:
# 产品配置bom
product_bom_purchase = self.env['mrp.bom'].with_user(
self.env.ref("base.user_admin")).bom_create(product, bom_type, 'product')
product_bom_purchase.with_user(self.env.ref("base.user_admin")).bom_create_line_has(
purchase_embryo)
return super(SaleOrder, self).action_confirm()
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
# 供货方式
supply_method = fields.Selection([
('automation', "自动化产线加工"),
('manual', "人工线下加工"),
('purchase', "外购"),
('outsourcing', "委外加工"),
], string='供货方式')
def write(self, vals):
if 'supply_method' in vals:
for line in self:
if vals['supply_method'] == 'automation' and line.manual_quotation:
raise UserError('当前(%s)产品为人工编程产品,不能选择自动化产线加工' % ','.join(line.mapped('product_id.name')))
return super(SaleOrderLine, self).write(vals)

View File

@@ -10,8 +10,14 @@ class SfProductionProcessParameter(models.Model):
@api.model
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if self._context.get('route_id'):
parameter = []
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 super()._name_search(name, args, operator, limit, name_get_uid)

View File

@@ -1,5 +1,6 @@
# -*- 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):
@@ -29,3 +30,11 @@ class sf_technology_design(models.Model):
def unlink_technology_design(self):
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)])
# 如果订单为空,则获取来源制造订单的销售单
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:
sale_order = self.env['sale.order'].sudo().search([('name', '=', mrp_production.origin)])
else:
mrp_production = production
if sale_order:
# sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(company_id).create({
'name': production.name,
'order_deadline': sale_order.deadline_of_delivery,
'production_id': production.id,
'date_planned_start': production.date_planned_start,
'origin': mrp_production.origin,
'product_qty': production.product_qty,
'product_id': production.product_id.id,
'state': 'draft',
})
technology_design_values = []
# if sale_order:
# sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(company_id).create({
'name': production.name,
'order_deadline': sale_order.deadline_of_delivery,
'production_id': production.id,
'date_planned_start': production.date_planned_start,
'origin': mrp_production.origin,
'product_qty': production.product_qty,
'product_id': production.product_id.id,
'state': 'draft',
})
all_production = productions
grouped_product_ids = {k: list(g) for k, g in groupby(all_production, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -310,6 +310,7 @@ class StockRule(models.Model):
# 为同一个product_id创建一个生产订单名称列表
product_id_to_production_names[product_id] = [production.name for production in all_production]
for production_item in productions:
technology_design_values = []
production_programming = self.env['mrp.production'].search(
[('product_id.id', '=', production_item.product_id.id),
('origin', '=', production_item.origin)],
@@ -317,77 +318,76 @@ class StockRule(models.Model):
if production_item.product_id.id in product_id_to_production_names:
# 同一个产品多个制造订单对应一个编程单和模型库
# 只调用一次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:
production_item.fetchCNC(
', '.join(product_id_to_production_names[production_item.product_id.id]))
else:
production_item.write({'programming_no': production_programming.programming_no,
'programming_state': '编程中'})
if not technology_design_values:
i = 0
if production_item.product_id.categ_id.type == '成品':
# 根据加工面板的面数及成品工序模板生成工序设计
if production_item.production_type == '自动化产线加工':
model = 'sf.product.model.type.routing.sort'
domain = [
('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
else:
model = 'sf.manual.product.model.type.routing.sort'
domain = [('manual_product_model_type_id', '=',
production_item.product_id.product_model_type_id.id)]
product_routing_workcenter = self.env[model].search(domain, order='sequence asc')
if production_item.production_type == '自动化产线加工':
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:
i = 0
if production_item.product_id.categ_id.type == '成品':
# 根据加工面板的面数及成品工序模板生成工序设计
if production_item.production_type == '自动化产线加工':
model = 'sf.product.model.type.routing.sort'
domain = [
('product_model_type_id', '=', production_item.product_id.product_model_type_id.id)]
else:
model = 'sf.manual.product.model.type.routing.sort'
domain = [('manual_product_model_type_id', '=',
production_item.product_id.product_model_type_id.id)]
product_routing_workcenter = self.env[model].search(domain, order='sequence asc')
if production_item.production_type == '自动化产线加工':
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(False, route, i, False))
elif production_item.product_id.categ_id.type == '坯料':
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
[('embryo_model_type_id', '=', production_item.product_id.embryo_model_type_id.id)],
order='sequence asc'
)
for route_embryo in embryo_routing_workcenter:
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
else:
for route in product_routing_workcenter:
i += 1
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i,
False))
surface_technics_arr = []
route_workcenter_arr = []
for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
if item.route_workcenter_id.surface_technics_id.id:
for process_param in production_item.product_id.model_process_parameters_ids:
if item.route_workcenter_id.surface_technics_id == process_param.process_id:
surface_technics_arr.append(
item.route_workcenter_id.surface_technics_id.id)
route_workcenter_arr.append(item.route_workcenter_id.id)
if surface_technics_arr:
production_process = self.env['sf.production.process'].search(
[('id', 'in', surface_technics_arr)],
order='sequence asc'
)
for p in production_process:
logging.info('production_process:%s' % p.name)
process_parameter = production_item.product_id.model_process_parameters_ids.filtered(
lambda pm: pm.process_id.id == p.id)
if process_parameter:
i += 1
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))
productions.technology_design_ids = technology_design_values
self.env['sf.technology.design'].json_technology_design_str(False, route, i, False))
elif production_item.product_id.categ_id.type == '坯料':
embryo_routing_workcenter = self.env['sf.embryo.model.type.routing.sort'].search(
[('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
technology_design_values.append(
self.env['sf.technology.design'].json_technology_design_str(False, route_embryo, i,
False))
surface_technics_arr = []
route_workcenter_arr = []
for item in production_item.product_id.product_model_type_id.surface_technics_routing_tmpl_ids:
if item.route_workcenter_id.surface_technics_id.id:
for process_param in production_item.product_id.model_process_parameters_ids:
if item.route_workcenter_id.surface_technics_id == process_param.process_id:
surface_technics_arr.append(
item.route_workcenter_id.surface_technics_id.id)
route_workcenter_arr.append(item.route_workcenter_id.id)
if surface_technics_arr:
production_process = self.env['sf.production.process'].search(
[('id', 'in', surface_technics_arr)],
order='sequence asc'
)
for p in production_process:
logging.info('production_process:%s' % p.name)
process_parameter = production_item.product_id.model_process_parameters_ids.filtered(
lambda pm: pm.process_id.id == p.id)
if process_parameter:
i += 1
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'})
return True
@@ -423,6 +423,8 @@ class ProductionLot(models.Model):
"""Generate `lot_names` from a string."""
if first_lot.__contains__(display_name):
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.
caught_initial_number = regex_findall(r"\d+", first_lot)
@@ -633,80 +635,79 @@ class StockPicking(models.Model):
return '%s%s' % (rescode, num)
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()
if res is True and self.picking_type_id.barcode == 'OCIN':
if self.id == move_out.picking_id.id:
# if move_out.move_line_ids.workorder_id.state == 'progress':
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)])
production = self.env['mrp.production'].search([('name', '=', self.origin)])
if move_in.state != 'done':
move_in.write({'state': 'assigned'})
self.env['stock.move.line'].create(move_in.get_move_line(production, None))
picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
if res is True and self.picking_type_id.id == picking_type_in:
# 如果是最后一张外协入库单,则设置库存位置的预留数量
move_in = self.move_ids
if move_in:
workorder = move_in.subcontract_workorder_id
workorders = workorder.production_id.workorder_ids
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True).sorted('sequence')
if workorder == subcontract_workorders[-1]:
self.env['stock.quant']._update_reserved_quantity(
move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty, lot_id=move_in.move_line_ids.lot_id,
package_id=False, owner_id=False, strict=False
)
return res
# 创建 外协出库入单
def create_outcontract_picking(self, sorted_workorders_arr, item):
if len(sorted_workorders_arr) > 1:
sorted_workorders_arr = sorted_workorders_arr[0]
stock_picking = self.env['stock.picking'].search([('origin', '=', item.name), ('name', 'ilike', 'OCOUT')])
if not stock_picking or sorted_workorders_arr:
for sorted_workorders in sorted_workorders_arr:
# pick_ids = []
if not sorted_workorders.picking_ids:
# outcontract_stock_move = self.env['stock.move'].search([('production_id', '=', item.id)])
# if not outcontract_stock_move:
new_picking = True
location_id = self.env['stock.location'].search(
[('barcode', 'ilike', 'VL-SPOC')]).id,
location_dest_id = self.env['stock.location'].search(
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id,
outcontract_picking_type_in = self.env.ref(
'sf_manufacturing.outcontract_picking_in').id,
outcontract_picking_type_out = self.env.ref(
'sf_manufacturing.outcontract_picking_out').id,
moves_out = self.env['stock.move'].sudo().create(
self.env['stock.move']._get_stock_move_values_Res(item, location_dest_id, location_id,
outcontract_picking_type_out))
picking_out = self.create(
moves_out._get_new_picking_values_Res(item, sorted_workorders, '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)
moves_in = self.env['stock.move'].sudo().create(
self.env['stock.move']._get_stock_move_values_Res(item, location_id, location_dest_id,
outcontract_picking_type_in))
picking_in = self.create(
moves_in._get_new_picking_values_Res(item, sorted_workorders, 'WH/OCIN/'))
# pick_ids.append(picking_in.id)
moves_in.write(
{'picking_id': picking_in.id, 'state': 'waiting'})
moves_in._assign_picking_post_process(new=new_picking)
def create_outcontract_picking(self, workorders, item, sorted_workorders):
for workorder in workorders:
if workorder.move_subcontract_workorder_ids:
workorder.move_subcontract_workorder_ids.write({'state': 'draft'})
workorder.move_subcontract_workorder_ids.picking_id.write({'state': 'draft'})
else:
# 创建一个新的补货组
procurement_group_id = self.env['procurement.group'].create({
'name': workorder.name,
'partner_id': self.partner_id.id,
})
move_dest_id = False
# 如果当前工单是是制造订单的最后一个工单
if workorder == item.workorder_ids[-1]:
move_dest_id = item.move_raw_ids[0].id
else:
# 从sorted_workorders中找到上一工单的move
if sorted_workorders.index(workorder) > 0:
move_dest_id = sorted_workorders[sorted_workorders.index(workorder) - 1].move_subcontract_workorder_ids[1].id
new_picking = True
outcontract_picking_type_in = self.env.ref(
'sf_manufacturing.outcontract_picking_in').id,
outcontract_picking_type_out = self.env.ref(
'sf_manufacturing.outcontract_picking_out').id,
moves_in = self.env['stock.move'].sudo().create(
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_in, procurement_group_id.id, move_dest_id))
picking_in = self.create(
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
# pick_ids.append(picking_in.id)
moves_in.write(
{'picking_id': picking_in.id, 'state': 'waiting'})
moves_in._assign_picking_post_process(new=new_picking)
moves_out = self.env['stock.move'].sudo().create(
self.env['stock.move']._get_stock_move_values_Res(item, outcontract_picking_type_out, procurement_group_id.id, moves_in.id))
workorder.write({'move_subcontract_workorder_ids': [(6, 0, [moves_in.id, moves_out.id])]})
picking_out = self.create(
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):
@@ -716,17 +717,20 @@ class ReStockMove(models.Model):
materiel_width = 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):
route = self.env['stock.route'].sudo().search([('name', '=', '表面工艺外协')])
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
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 = {
'name': '',
'company_id': item.company_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_qty': 1.0,
'location_id': location_src_id,
'location_dest_id': location_dest_id,
'location_id': stock_rule.location_src_id.id,
'location_dest_id': stock_rule.location_dest_id.id,
'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)],
'date_deadline': datetime.now(),
'picking_type_id': picking_type_id,
@@ -750,7 +754,7 @@ class ReStockMove(models.Model):
'picking_type_id': picking_type_id,
'location_id': self.mapped('location_id').id,
'location_dest_id': self.mapped('location_dest_id').id,
'state': 'confirmed',
'state': 'waiting',
}
def get_move_line(self, production_id, sorted_workorders):
@@ -966,7 +970,7 @@ class ReStockMove(models.Model):
合并制造订单的完成move单据
"""
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')
productions = self.env['mrp.production'].search(
[('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')
productions = self.env['mrp.production'].search(
[('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
return res
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True, index='btree_not_null')
class ReStockQuant(models.Model):