diff --git a/addons/stock_location/__init__.py b/addons/stock_location/__init__.py index 1b86a7eb0c3..7a3970f9f44 100644 --- a/addons/stock_location/__init__.py +++ b/addons/stock_location/__init__.py @@ -20,5 +20,6 @@ ############################################################################## import stock +import mrp_pull # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/stock_location/__openerp__.py b/addons/stock_location/__openerp__.py index b13769b3458..72698b9c390 100644 --- a/addons/stock_location/__openerp__.py +++ b/addons/stock_location/__openerp__.py @@ -37,9 +37,9 @@ This module may be useful for different purposes: * Manage products to be rent. """, 'author': 'Tiny', - 'depends': ['stock'], + 'depends': ['mrp','stock'], 'init_xml': [], - 'update_xml': ['stock_view.xml', 'security/ir.model.access.csv'], + 'update_xml': ['stock_view.xml', 'security/ir.model.access.csv', 'mrp_pull_workflow.xml'], 'demo_xml': [], 'installable': True, 'test':[ diff --git a/addons/stock_location/mrp_pull.py b/addons/stock_location/mrp_pull.py new file mode 100755 index 00000000000..9f79923c34f --- /dev/null +++ b/addons/stock_location/mrp_pull.py @@ -0,0 +1,131 @@ +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2009 Tiny SPRL (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import fields,osv +import tools +import ir +import pooler +import netsvc +from mx import DateTime +import time +from tools.translate import _ + +class mrp_procurement(osv.osv): + _inherit = 'mrp.procurement' + def check_buy(self, cr, uid, ids, context=None): + for procurement in self.browse(cr, uid, ids): + for line in procurement.product_id.flow_pull_ids: + print line.location_src_id.name, line.location_id.name, line.type_proc + if line.location_id==procurement.location_id: + return line.type_proc=='buy' + return super(mrp_procurement, self).check_buy(cr, uid, ids) + + def check_produce(self, cr, uid, ids, context=None): + for procurement in self.browse(cr, uid, ids): + for line in procurement.product_id.flow_pull_ids: + if line.location_id==procurement.location_id: + return line.type_proc=='produce' + return super(mrp_procurement, self).check_produce(cr, uid, ids) + + def check_move(self, cr, uid, ids, context=None): + for procurement in self.browse(cr, uid, ids): + for line in procurement.product_id.flow_pull_ids: + if line.location_id==procurement.location_id: + if not line.location_src_id: + self.write(cr, uid, procurement.id, {'message': _('No source location defined to generate the picking !')}) + return (line.type_proc=='move') and (line.location_src_id) + return False + + def action_move_create(self, cr, uid, ids,context=None): + proc_obj = self.pool.get('mrp.procurement') + move_obj = self.pool.get('stock.move') + location_obj = self.pool.get('stock.location') + wf_service = netsvc.LocalService("workflow") + + for proc in proc_obj.browse(cr, uid, ids, context=context): + line = None + for line in proc.product_id.flow_pull_ids: + if line.location_id==proc.location_id: + break + assert line, 'Line can not be False if we are on this state of the workflow' + origin = (proc.origin or proc.name or '').split(':')[0] +':'+line.name + picking_id = self.pool.get('stock.picking').create(cr, uid, { + 'origin': origin, + 'company_id': line.company_id and line.company_id.id or False, + 'type': line.picking_type, + 'move_type': 'one', + 'address_id': line.partner_address_id.id, + 'note': line.name, # TODO: note on procurement ? + 'invoice_state': 'none', + }) + move_id = self.pool.get('stock.move').create(cr, uid, { + 'name': line.name, + 'picking_id': picking_id, + 'company_id': line.company_id and line.company_id.id or False, + 'product_id': proc.product_id.id, + 'date_planned': proc.date_planned, + 'product_qty': proc.product_qty, + 'product_uom': proc.product_uom.id, + 'product_uos_qty': (proc.product_uos and proc.product_uos_qty)\ + or proc.product_qty, + 'product_uos': (proc.product_uos and proc.product_uos.id)\ + or proc.product_uom.id, + 'address_id': line.partner_address_id.id, + 'location_id': line.location_src_id.id, + 'location_dest_id': line.location_id.id, + 'move_dest_id': proc.move_id and proc.move_id.id or False, # to verif, about history ? + 'tracking_id': False, + 'cancel_cascade': line.cancel_cascade, + 'state': 'confirmed', + 'note': line.name, # TODO: same as above + }) + if proc.move_id and proc.move_id.state in ('confirmed'): + self.pool.get('stock.move').write(cr,uid, [proc.move_id.id], { + 'state':'waiting' + }, context=context) + proc_id = self.pool.get('mrp.procurement').create(cr, uid, { + 'name': line.name, + 'origin': origin, + 'company_id': line.company_id and line.company_id.id or False, + 'date_planned': proc.date_planned, + 'product_id': proc.product_id.id, + 'product_qty': proc.product_qty, + 'product_uom': proc.product_uom.id, + 'product_uos_qty': (proc.product_uos and proc.product_uos_qty)\ + or proc.product_qty, + 'product_uos': (proc.product_uos and proc.product_uos.id)\ + or proc.product_uom.id, + 'location_id': line.location_src_id.id, + 'procure_method': line.procure_method, + 'move_id': move_id, + }) + wf_service = netsvc.LocalService("workflow") + wf_service.trg_validate(uid, 'stock.picking', picking_id, 'button_confirm', cr) + wf_service.trg_validate(uid, 'mrp.procurement', proc_id, 'button_confirm', cr) + if proc.move_id: + self.pool.get('stock.move').write(cr, uid, [proc.move_id.id], + {'location_id':proc.location_id.id}) + + self.write(cr, uid, [proc.id], {'state':'running','message':_('Moved from other location')}) + + return False + + +mrp_procurement() diff --git a/addons/stock_location/mrp_pull_workflow.xml b/addons/stock_location/mrp_pull_workflow.xml new file mode 100755 index 00000000000..d1cad552115 --- /dev/null +++ b/addons/stock_location/mrp_pull_workflow.xml @@ -0,0 +1,23 @@ + + + + + + + + move + function + action_move_create() + + + + + + check_move() + + + + + + + diff --git a/addons/stock_location/stock.py b/addons/stock_location/stock.py index 3249dbef255..5dbbd7be9ab 100644 --- a/addons/stock_location/stock.py +++ b/addons/stock_location/stock.py @@ -28,6 +28,7 @@ class stock_location_path(osv.osv): _name = "stock.location.path" _columns = { 'name': fields.char('Operation', size=64), + 'company_id': fields.many2one('res.company', 'Company'), 'product_id' : fields.many2one('product.product', 'Products', ondelete='cascade', select=1), 'location_from_id' : fields.many2one('stock.location', 'Source Location', ondelete='cascade', select=1), 'location_dest_id' : fields.many2one('stock.location', 'Destination Location', ondelete='cascade', select=1), @@ -48,16 +49,53 @@ class stock_location_path(osv.osv): } stock_location_path() +class product_pulled_flow(osv.osv): + _name = 'product.pulled.flow' + _description = "Pulled Flows." + _columns = { + 'name': fields.char('Name', size=64, required=True, help="This field will fill the packing Origin and the name of its moves"), + 'cancel_cascade': fields.boolean('Cancel Cascade', help="Allow you to cancel moves related to the product pull flow"), + 'location_id': fields.many2one('stock.location','Location', required=True, help="Is the destination location that needs supplying"), + 'location_src_id': fields.many2one('stock.location','Location Source', help="Location used by Destination Location to supply"), + 'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procure Method', required=True, help="'Make to Stock': When needed, take from the stock or wait until re-supplying. 'Make to Order': When needed, purchase or produce for the procurement request."), + 'type_proc': fields.selection([('produce','Produce'),('buy','Buy'),('move','Move')], 'Type of Procurement', required=True), + 'company_id': fields.many2one('res.company', 'Company', help="Is used to know to which company belong packings and moves"), + 'partner_address_id': fields.many2one('res.partner.address', 'Partner Address'), + 'picking_type': fields.selection([('out','Sending Goods'),('in','Getting Goods'),('internal','Internal'),('delivery','Delivery')], 'Shipping Type', required=True, select=True, help="Depending on the company, choose whatever you want to receive or send products"), + 'product_id':fields.many2one('product.product','Product'), + } + _defaults = { + 'cancel_cascade': lambda *arg: False, + 'procure_method': lambda *args: 'make_to_stock', + 'type_proc': lambda *args: 'move', + 'picking_type':lambda *args:'out', + } +product_pulled_flow() + class product_product(osv.osv): _inherit = 'product.product' _columns = { + 'flow_pull_ids': fields.one2many('product.pulled.flow', 'product_id', 'Pulled Flows'), 'path_ids': fields.one2many('stock.location.path', 'product_id', - 'Location Paths', + 'Pushed Flow', help="These rules set the right path of the product in the "\ "whole location tree.") } product_product() +class stock_move(osv.osv): + _inherit = 'stock.move' + _columns = { + 'cancel_cascade': fields.boolean('Cancel Cascade', help='If checked, when this move is cancelled, cancel the linked move too') + } + def action_cancel(self,cr,uid,ids,context={ }): + for m in self.browse(cr, uid, ids, context=context): + if m.cancel_cascade and m.move_dest_id: + self.action_cancel(cr, uid, [m.move_dest_id.id], context=context) + res = super(stock_move,self).action_cancel(cr,uid,ids,context) + return res +stock_move() + class stock_location(osv.osv): _inherit = 'stock.location' def chained_location_get(self, cr, uid, location, partner=None, product=None, context={}): diff --git a/addons/stock_location/stock_view.xml b/addons/stock_location/stock_view.xml index f7ba12fe480..be8ac097406 100644 --- a/addons/stock_location/stock_view.xml +++ b/addons/stock_location/stock_view.xml @@ -8,7 +8,6 @@ tree - @@ -24,7 +23,7 @@
- + @@ -40,19 +39,49 @@ form - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + +