117 lines
5.9 KiB
Python
117 lines
5.9 KiB
Python
from collections import defaultdict
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import api, fields, models, SUPERUSER_ID, _
|
|
from odoo.osv import expression
|
|
from odoo.addons.stock.models.stock_rule import ProcurementException
|
|
from odoo.tools import float_compare, OrderedSet
|
|
|
|
|
|
class ReStockRule(models.Model):
|
|
_inherit = 'stock.rule'
|
|
|
|
def _run_manufacture(self, procurements):
|
|
productions_values_by_company = defaultdict(list)
|
|
errors = []
|
|
for procurement, rule in procurements:
|
|
if float_compare(procurement.product_qty, 0, precision_rounding=procurement.product_uom.rounding) <= 0:
|
|
# If procurement contains negative quantity, don't create a MO that would be for a negative value.
|
|
continue
|
|
bom = rule._get_matching_bom(procurement.product_id, procurement.company_id, procurement.values)
|
|
|
|
productions_values_by_company[procurement.company_id.id].append(rule._prepare_mo_vals(*procurement, bom))
|
|
|
|
if errors:
|
|
raise ProcurementException(errors)
|
|
|
|
for company_id, productions_values in productions_values_by_company.items():
|
|
# create the MO as SUPERUSER because the current user may not have the rights to do it (mto product launched by a sale for example)
|
|
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
|
productions_values)
|
|
self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
|
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
|
print(productions.product_id.processing_panel)
|
|
# 查出产品的加工面板并对根据面板的数量循环生成工序
|
|
for k in (productions.product_id.processing_panel.split(',')):
|
|
print(productions.product_id.model_type_id.routing_tmpl_id)
|
|
for j in productions.product_id.model_type_id.routing_tmpl_id:
|
|
productions._create_workorder()
|
|
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
|
(
|
|
p.move_dest_ids.procure_method != 'make_to_order' and not p.move_raw_ids and not p.workorder_ids)).action_confirm()
|
|
|
|
for production in productions:
|
|
origin_production = production.move_dest_ids and production.move_dest_ids[
|
|
0].raw_material_production_id or False
|
|
orderpoint = production.orderpoint_id
|
|
if orderpoint and orderpoint.create_uid.id == SUPERUSER_ID and orderpoint.trigger == 'manual':
|
|
production.message_post(
|
|
body=_('This production order has been created from Replenishment Report.'),
|
|
message_type='comment',
|
|
subtype_xmlid='mail.mt_note')
|
|
elif orderpoint:
|
|
production.message_post_with_view(
|
|
'mail.message_origin_link',
|
|
values={'self': production, 'origin': orderpoint},
|
|
subtype_id=self.env.ref('mail.mt_note').id)
|
|
elif origin_production:
|
|
production.message_post_with_view(
|
|
'mail.message_origin_link',
|
|
values={'self': production, 'origin': origin_production},
|
|
subtype_id=self.env.ref('mail.mt_note').id)
|
|
return True
|
|
|
|
|
|
class ResMrpWorkOrder(models.Model):
|
|
_inherit = 'mrp.workorder'
|
|
|
|
workcenter_id = fields.Many2one('mrp.workcenter', required=False)
|
|
processing_panel = fields.Char('加工面')
|
|
|
|
def _action_confirm(self):
|
|
workorders_by_production = defaultdict(lambda: self.env['mrp.workorder'])
|
|
for workorder in self:
|
|
workorders_by_production[workorder.production_id] |= workorder
|
|
|
|
for production, workorders in workorders_by_production.items():
|
|
workorders_by_bom = defaultdict(lambda: self.env['mrp.workorder'])
|
|
bom = self.env['mrp.bom']
|
|
moves = production.move_raw_ids | production.move_finished_ids
|
|
|
|
for workorder in workorders:
|
|
bom = workorder.operation_id.bom_id or workorder.production_id.bom_id
|
|
previous_workorder = workorders_by_bom[bom][-1:]
|
|
previous_workorder.next_work_order_id = workorder.id
|
|
workorders_by_bom[bom] |= workorder
|
|
|
|
moves.filtered(lambda m: m.operation_id == workorder.operation_id).write({
|
|
'workorder_id': workorder.id
|
|
})
|
|
|
|
exploded_boms, dummy = production.bom_id.explode(production.product_id, 1,
|
|
picking_type=production.bom_id.picking_type_id)
|
|
exploded_boms = {b[0]: b[1] for b in exploded_boms}
|
|
for move in moves:
|
|
if move.workorder_id:
|
|
continue
|
|
bom = move.bom_line_id.bom_id
|
|
while bom and bom not in workorders_by_bom:
|
|
bom_data = exploded_boms.get(bom, {})
|
|
bom = bom_data.get('parent_line') and bom_data['parent_line'].bom_id or False
|
|
if bom in workorders_by_bom:
|
|
move.write({
|
|
'workorder_id': workorders_by_bom[bom][-1:].id
|
|
})
|
|
else:
|
|
move.write({
|
|
'workorder_id': workorders_by_bom[production.bom_id][-1:].id
|
|
})
|
|
|
|
for workorders in workorders_by_bom.values():
|
|
if not workorders:
|
|
continue
|
|
if workorders[0].state == 'pending':
|
|
workorders[0].state = 'ready' if workorders[0].production_availability == 'assigned' else 'waiting'
|
|
for workorder in workorders:
|
|
workorder._start_nextworkorder()
|