General remarks concerning cleaning commits preparing the stock migration ========================================================================= Small update / cleaning before moving and migrating. This commit contains the cleaning of stock_picking_type and stock_picking models. The first cleaning performed is to clean methods having a browse record or a list of records replacing ids parameter. Those are converted into classic old API methods using cr, uid, ids. This eases the migration as they are then migrated into multi methods. Another cleaning concerns naming things. Some methods are renamed to ease the code readability. Some parameters are also renamed as well as some variables. This kind of change is performed only when the readability is improved. Otherwise the code is kept as it is to avoid rewriting too much of the code. Finally unnecessary stuff is also removed. This concerns dead code (methods not used in community nor in enterprise) and unnecessary code splitting (tools methods called once without real added value are directly put into their called method). - stock.move: no specific changes; note that a method called only in mrp has been moved to mrp. - product: no specific changes - config settings: no specific changes - wizards: no specific changes stock.quant main changes ======================== - ``apply_removal_strategy`` method updated to return only the removal strategy instead of having a mix of several things (overrides updated) - ``quants_get_**`` methods renamed to ease code understanding - quants_unreserve from stock.quant to stock.move model because its primary record is a move, not quants stock.inventory and stock.inventory.line main changes ===================================================== - stock.inventory: ``move_ids_exist`` field remove. Unused. stock.picking and stock.picking.type main changes ================================================= - stock.picking: ``move_lines_related`` is removed. Indeed it is used only to display a slightly different view of moves contained inside a picking. However this field causes a lot of issues when migrated into the new API. The view is updated to keep the same look and feel while avoiding an unnecessary field. - stock.picking.type: complete_name field is removed. Using display_name is sufficient for the existing use cases. stock.warehouse and stock.orderpoint main changes ================================================= - stock.warehouse: removed ``resupply_from_wh``, unused field stock.pack.operation main changes ================================= - stock.pack.operation: ``processed_boolean`` fields renamed to ``is_done`` to match its use in the code. stock.location main changes =========================== Note that in this commit a strange override in create has been replaced by a cleaner override in default_get in order to have something more understandable procurement main changes ======================== - in this commit some code located in procurement has been moved to the orderpoint model. Indeed those methods take an orderpoint as main argument, making it more orderpoint methods than procurement methods - ``_prepare_orderpoint_procurement`` method has been merged with its strange override in stock_calendar to have something a bit more modular
116 lines
6.3 KiB
Python
116 lines
6.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from datetime import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
from openerp.osv import osv, fields
|
|
from openerp.tools.translate import _
|
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
|
from openerp import SUPERUSER_ID
|
|
|
|
class procurement_rule(osv.osv):
|
|
_inherit = 'procurement.rule'
|
|
|
|
def _get_action(self, cr, uid, context=None):
|
|
return [('manufacture', _('Manufacture'))] + super(procurement_rule, self)._get_action(cr, uid, context=context)
|
|
|
|
|
|
class procurement_order(osv.osv):
|
|
_inherit = 'procurement.order'
|
|
_columns = {
|
|
'bom_id': fields.many2one('mrp.bom', 'BoM', ondelete='cascade', select=True),
|
|
'property_ids': fields.many2many('mrp.property', 'procurement_property_rel', 'procurement_id','property_id', 'Properties'),
|
|
'production_id': fields.many2one('mrp.production', 'Manufacturing Order'),
|
|
}
|
|
|
|
def propagate_cancels(self, cr, uid, ids, context=None):
|
|
for procurement in self.browse(cr, uid, ids, context=context):
|
|
if procurement.rule_id.action == 'manufacture' and procurement.production_id:
|
|
self.pool.get('mrp.production').action_cancel(cr, uid, [procurement.production_id.id], context=context)
|
|
return super(procurement_order, self).propagate_cancels(cr, uid, ids, context=context)
|
|
|
|
def _run(self, cr, uid, ids, context=None):
|
|
procurement = self.browse(cr, uid, ids[0], context=context)
|
|
if procurement.rule_id and procurement.rule_id.action == 'manufacture':
|
|
#make a manufacturing order for the procurement
|
|
return self.make_mo(cr, uid, [procurement.id], context=context)[procurement.id]
|
|
return super(procurement_order, self)._run(cr, uid, ids, context=context)
|
|
|
|
def _check(self, cr, uid, ids, context=None):
|
|
procurement = self.browse(cr, uid, ids[0], context=context)
|
|
if procurement.production_id and procurement.production_id.state == 'done': # TOCHECK: no better method?
|
|
return True
|
|
return super(procurement_order, self)._check(cr, uid, ids, context=context)
|
|
|
|
def check_bom_exists(self, cr, uid, ids, context=None):
|
|
""" Finds the bill of material for the product from procurement order.
|
|
@return: True or False
|
|
"""
|
|
for procurement in self.browse(cr, uid, ids, context=context):
|
|
properties = [x.id for x in procurement.property_ids]
|
|
bom_id = self.pool.get('mrp.bom')._bom_find(cr, uid, product_id=procurement.product_id.id,
|
|
properties=properties, context=context)
|
|
if not bom_id:
|
|
return False
|
|
return True
|
|
|
|
def _get_date_planned(self, cr, uid, procurement, context=None):
|
|
format_date_planned = datetime.strptime(procurement.date_planned,
|
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
|
date_planned = format_date_planned - relativedelta(days=procurement.product_id.produce_delay or 0.0)
|
|
date_planned = date_planned - relativedelta(days=procurement.company_id.manufacturing_lead)
|
|
return date_planned
|
|
|
|
def _prepare_mo_vals(self, cr, uid, procurement, context=None):
|
|
res_id = procurement.move_dest_id and procurement.move_dest_id.id or False
|
|
newdate = self._get_date_planned(cr, uid, procurement, context=context)
|
|
bom_obj = self.pool.get('mrp.bom')
|
|
if procurement.bom_id:
|
|
bom_id = procurement.bom_id.id
|
|
routing_id = procurement.bom_id.routing_id.id
|
|
else:
|
|
properties = [x.id for x in procurement.property_ids]
|
|
bom_id = bom_obj._bom_find(cr, uid, product_id=procurement.product_id.id,
|
|
properties=properties, context=dict(context, company_id=procurement.company_id.id))
|
|
bom = bom_obj.browse(cr, uid, bom_id, context=context)
|
|
routing_id = bom.routing_id.id
|
|
return {
|
|
'origin': procurement.origin,
|
|
'product_id': procurement.product_id.id,
|
|
'product_qty': procurement.product_qty,
|
|
'product_uom': procurement.product_uom.id,
|
|
'location_src_id': procurement.rule_id.location_src_id.id or procurement.location_id.id,
|
|
'location_dest_id': procurement.location_id.id,
|
|
'bom_id': bom_id,
|
|
'routing_id': routing_id,
|
|
'date_planned': newdate.strftime('%Y-%m-%d %H:%M:%S'),
|
|
'move_prod_id': res_id,
|
|
'company_id': procurement.company_id.id,
|
|
}
|
|
|
|
def make_mo(self, cr, uid, ids, context=None):
|
|
""" Make Manufacturing(production) order from procurement
|
|
@return: New created Production Orders procurement wise
|
|
"""
|
|
res = {}
|
|
production_obj = self.pool.get('mrp.production')
|
|
procurement_obj = self.pool.get('procurement.order')
|
|
for procurement in procurement_obj.browse(cr, uid, ids, context=context):
|
|
if self.check_bom_exists(cr, uid, [procurement.id], context=context):
|
|
#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)
|
|
vals = self._prepare_mo_vals(cr, uid, procurement, context=context)
|
|
produce_id = production_obj.create(cr, SUPERUSER_ID, vals, context=dict(context, force_company=procurement.company_id.id))
|
|
res[procurement.id] = produce_id
|
|
self.write(cr, uid, [procurement.id], {'production_id': produce_id})
|
|
self.production_order_create_note(cr, uid, procurement, context=context)
|
|
production_obj.action_compute(cr, uid, [produce_id], properties=[x.id for x in procurement.property_ids])
|
|
production_obj.signal_workflow(cr, uid, [produce_id], 'button_confirm')
|
|
else:
|
|
res[procurement.id] = False
|
|
self.message_post(cr, uid, [procurement.id], body=_("No BoM exists for this product!"), context=context)
|
|
return res
|
|
|
|
def production_order_create_note(self, cr, uid, procurement, context=None):
|
|
body = _("Manufacturing Order <em>%s</em> created.") % (procurement.production_id.name,)
|
|
self.message_post(cr, uid, [procurement.id], body=body, context=context)
|