From 14cc990846f98e7474e10d669bb3c41122e81c2a Mon Sep 17 00:00:00 2001 From: jke-openerp Date: Tue, 22 Oct 2013 08:54:46 +0200 Subject: [PATCH] [IMP] Task Warehouse configuration - Add buy route/rule in purchase and manufacture route/rule in mrp + field default resupply in warehouse form auto hide/display bzr revid: jke@openerp.com-20131022065446-sxsqy1y9wg8kdzrz --- addons/mrp/__openerp__.py | 1 + addons/mrp/mrp_stock_data.yml | 10 ++ addons/mrp/mrp_view.xml | 11 ++ addons/mrp/stock.py | 87 ++++++++++- addons/purchase/__openerp__.py | 2 + addons/purchase/purchase_data.xml | 21 ++- addons/purchase/purchase_stock_data.yml | 6 + addons/purchase/purchase_stock_demo.yml | 13 ++ addons/purchase/stock.py | 95 ++++++++++++ addons/purchase/stock_view.xml | 13 ++ addons/stock/__openerp__.py | 3 +- addons/stock/static/src/js/CheckHide.js | 35 +++++ .../stock/static/src/js/stock_picking_type.js | 1 + addons/stock/stock.py | 43 ++++-- addons/stock/stock_location_data.xml | 139 ------------------ addons/stock/stock_view.xml | 6 +- 16 files changed, 318 insertions(+), 168 deletions(-) create mode 100644 addons/mrp/mrp_stock_data.yml create mode 100644 addons/purchase/purchase_stock_data.yml create mode 100644 addons/purchase/purchase_stock_demo.yml create mode 100644 addons/stock/static/src/js/CheckHide.js delete mode 100644 addons/stock/stock_location_data.xml diff --git a/addons/mrp/__openerp__.py b/addons/mrp/__openerp__.py index 9779147dab3..0b8aa101a9d 100644 --- a/addons/mrp/__openerp__.py +++ b/addons/mrp/__openerp__.py @@ -58,6 +58,7 @@ Dashboard / Reports for MRP will include: 'security/ir.model.access.csv', 'mrp_workflow.xml', 'mrp_data.xml', + 'mrp_stock_data.yml', 'wizard/mrp_product_produce_view.xml', 'wizard/change_production_qty_view.xml', 'wizard/mrp_price_view.xml', diff --git a/addons/mrp/mrp_stock_data.yml b/addons/mrp/mrp_stock_data.yml new file mode 100644 index 00000000000..6e48e256e10 --- /dev/null +++ b/addons/mrp/mrp_stock_data.yml @@ -0,0 +1,10 @@ +- + Set "can_manufacture_for_resupply" at true for warehouse0 by default +- + !python {model: stock.warehouse}: | + main_warehouse = self.browse(cr, uid, ref('stock.warehouse0'), context=context) + main_warehouse.can_manufacture_for_resupply = True + manufacture_pull_vals= self._get_manufacture_pull_rule(cr, uid, main_warehouse, context=context) + pull_id = self.pool.get('procurement.rule').create(cr, uid, manufacture_pull_vals, context=context) + self.write(cr,uid,main_warehouse.id,{'manufacture_pull_id':pull_id, 'can_manufacture_for_resupply':True},context=context) + diff --git a/addons/mrp/mrp_view.xml b/addons/mrp/mrp_view.xml index 010e9077bc6..23663a18f54 100644 --- a/addons/mrp/mrp_view.xml +++ b/addons/mrp/mrp_view.xml @@ -1028,5 +1028,16 @@ + + + Stock Warehouse Inherited + stock.warehouse + + + + + + + diff --git a/addons/mrp/stock.py b/addons/mrp/stock.py index b2b248c785c..f670fdfc219 100644 --- a/addons/mrp/stock.py +++ b/addons/mrp/stock.py @@ -21,6 +21,7 @@ from openerp.osv import fields from openerp.osv import osv +from openerp.tools.translate import _ class StockMove(osv.osv): @@ -179,4 +180,88 @@ class split_in_production_lot(osv.osv_memory): return new_moves -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: +class stock_warehouse(osv.osv): + _inherit = 'stock.warehouse' + _columns = { + 'can_manufacture_for_resupply': fields.boolean('Can manufacture for resupply this warehouse'), + 'manufacture_pull_id': fields.many2one('procurement.rule', 'Manufacture rule'), + } + _defaults= { + 'can_manufacture_for_resupply': False, + 'manufacture_pull_id' : False + } + + def _get_manufacture_pull_rule(self, cr, uid, warehouse, context=None): + if not warehouse.can_manufacture_for_resupply: + return False +# + route_obj = self.pool.get('stock.location.route') + data_obj = self.pool.get('ir.model.data') + try: + manufacture_route_id = data_obj.get_object_reference(cr, uid, 'stock', 'route_warehouse0_manufacture')[1] + except: + manufacture_route_id = route_obj.search(cr, uid, [('name', 'like', _('Manufacture'))], context=context) + manufacture_route_id = manufacture_route_id and manufacture_route_id[0] or False + if not manufacture_route_id: + raise osv.except_osv(_('Error!'), _('Can\'t find any generic Manufacture route.')) + + dest_loc = warehouse.in_type_id + return { + 'name': warehouse.name + ': ' + _(' Manufacture') + ' -> ' + dest_loc.name, + 'location_id': warehouse.wh_input_stock_loc_id.id, + 'route_id': manufacture_route_id, + 'action': 'move', + 'picking_type_id': dest_loc.id, + 'procure_method': 'make_to_order', + 'active': True, + } + + def create_routes(self, cr, uid, ids, warehouse, context=None): + pull_obj = self.pool.get('procurement.rule') + res = super(stock_warehouse, self).create_routes(cr, uid, ids, warehouse, context=context) + manufacture_pull_vals = self._get_manufacture_pull_rule(cr, uid, warehouse, context=context) + if manufacture_pull_vals: + manufacture_pull_id = pull_obj.create(cr, uid, manufacture_pull_vals, context=context) + res['manufacture_pull_id'] = manufacture_pull_id + else: + res['manufacture_pull_id'] = False + return res + + + def write(self, cr, uid, ids, vals, context=None): + pull_obj = self.pool.get('procurement.rule') + if isinstance(ids, (int, long)): + ids = [ids] + + #only if update and checkbox have changed ! + if not vals.get("can_manufacture_for_resupply",None) is None: + + if vals.get("can_manufacture_for_resupply",False): + for warehouse in self.browse(cr, uid, ids, context=context): + if not warehouse.manufacture_pull_id: + warehouse.can_manufacture_for_resupply = True + manufacture_pull_vals = self._get_manufacture_pull_rule(cr, uid, warehouse, context=context) + manufacture_pull_id = pull_obj.create(cr, uid, manufacture_pull_vals, context=context) + vals['manufacture_pull_id'] = manufacture_pull_id + else: + for warehouse in self.browse(cr, uid, ids, context=context): + if warehouse.manufacture_pull_id: + manufacture_pull_id = pull_obj.unlink(cr, uid, warehouse.manufacture_pull_id.id, context=context) + vals['manufacture_pull_id'] = False + + return super(stock_warehouse,self).write(cr, uid, ids, vals, context=None) + + def get_all_routes_for_wh(self, cr, uid, warehouse, context=None): + all_routes = super(stock_warehouse,self).get_all_routes_for_wh(cr,uid,warehouse,context=context) + if warehouse.can_manufacture_for_resupply and warehouse.manufacture_pull_id and warehouse.manufacture_pull_id.route_id: + all_routes += [warehouse.manufacture_pull_id.route_id.id] + return all_routes + + def _get_all_products_to_resupply(self, cr, uid, warehouse, context=None): + res = super(stock_warehouse,self)._get_all_products_to_resupply(cr, uid, warehouse, context=context) + for product_id in res: + for route in self.pool.get('product.product').browse(cr, uid, product_id, context=context).route_ids: + if warehouse.manufacture_pull_id and warehouse.manufacture_pull_id.route_id and route.id == warehouse.manufacture_pull_id.route_id.id: + res.remove(product_id) + break + return res diff --git a/addons/purchase/__openerp__.py b/addons/purchase/__openerp__.py index a8342b803a8..552bf7aa374 100644 --- a/addons/purchase/__openerp__.py +++ b/addons/purchase/__openerp__.py @@ -64,6 +64,7 @@ Dashboard / Reports for Purchase Management will include: 'report/purchase_report_view.xml', 'board_purchase_view.xml', 'edi/purchase_order_action_data.xml', + 'purchase_stock_data.yml', 'res_config_view.xml', ], 'test': [ @@ -86,6 +87,7 @@ Dashboard / Reports for Purchase Management will include: 'demo': [ 'purchase_order_demo.yml', 'purchase_demo.xml', + 'purchase_stock_demo.yml', ], 'installable': True, 'auto_install': False, diff --git a/addons/purchase/purchase_data.xml b/addons/purchase/purchase_data.xml index d82acaf8497..27ff2b1c49f 100644 --- a/addons/purchase/purchase_data.xml +++ b/addons/purchase/purchase_data.xml @@ -68,21 +68,26 @@ + --> Buy 5 + - - WH: Buy - buy - - - - + + + diff --git a/addons/purchase/purchase_stock_data.yml b/addons/purchase/purchase_stock_data.yml new file mode 100644 index 00000000000..9bb265164f0 --- /dev/null +++ b/addons/purchase/purchase_stock_data.yml @@ -0,0 +1,6 @@ +- + !python {model: stock.warehouse}: | + main_warehouse = self.browse(cr, uid, ref('stock.warehouse0'), context=context) + buy_pull_vals= self._get_buy_pull_rule(cr, uid, main_warehouse, context=context) + pull_id = self.pool.get('procurement.rule').create(cr, uid, buy_pull_vals, context=context) + self.write(cr,uid,main_warehouse.id,{'buy_pull_id':pull_id},context=context) diff --git a/addons/purchase/purchase_stock_demo.yml b/addons/purchase/purchase_stock_demo.yml new file mode 100644 index 00000000000..b503a631200 --- /dev/null +++ b/addons/purchase/purchase_stock_demo.yml @@ -0,0 +1,13 @@ +- + !python {model: stock.warehouse}: | + pull_obj = self.pool.get('procurement.rule') + wh_to_assign = ['stock_warehouse_shop0','stock_warehouse_shop1','warehouse_icecream'] + for wh_ref in wh_to_assign: + warehouse = self.browse(cr, uid, ref('stock.' + wh_ref), context=context) + buy_pull_vals= self._get_buy_pull_rule(cr, uid, warehouse, context=context) + pull_id = self.pool.get('procurement.rule').create(cr, uid, buy_pull_vals, context=context) + self.write(cr,uid,warehouse.id,{'buy_pull_id':pull_id},context=context) + + + + diff --git a/addons/purchase/stock.py b/addons/purchase/stock.py index 34d8c8df595..6e00676468b 100644 --- a/addons/purchase/stock.py +++ b/addons/purchase/stock.py @@ -21,6 +21,8 @@ from openerp.osv import fields, osv from openerp import netsvc +from openerp.tools.translate import _ + class stock_move(osv.osv): _inherit = 'stock.move' _columns = { @@ -56,3 +58,96 @@ class stock_picking(osv.osv): # Here is how it should work: # On a draft invoice, allows to select purchase_orders (many2many_tags) # This fills in automatically PO lines or from related receptions if any + +class stock_warehouse(osv.osv): + _inherit = 'stock.warehouse' + _columns = { + 'can_buy_for_resupply': fields.boolean('Can buy for resupply this warehouse'), + 'buy_pull_id': fields.many2one('procurement.rule', 'BUY rule'), + } + _defaults= { + 'can_buy_for_resupply': True, + 'buy_pull_id' : False + } + + def _get_buy_pull_rule(self, cr, uid, warehouse, context=None): + if not warehouse.can_buy_for_resupply: + return False +# + route_obj = self.pool.get('stock.location.route') + data_obj = self.pool.get('ir.model.data') + try: + buy_route_id = data_obj.get_object_reference(cr, uid, 'stock', 'route_warehouse0_buy')[1] + except: + buy_route_id = route_obj.search(cr, uid, [('name', 'like', _('Buy'))], context=context) + buy_route_id = buy_route_id and buy_route_id[0] or False + if not buy_route_id: + raise osv.except_osv(_('Error!'), _('Can\'t find any generic Buy route.')) + + dest_loc = warehouse.in_type_id + return { + 'name': warehouse.name + ': ' + _(' Buy') + ' -> ' + dest_loc.name, + 'location_id': warehouse.wh_input_stock_loc_id.id, + 'route_id': buy_route_id, + 'action': 'move', + 'picking_type_id': dest_loc.id, + 'procure_method': 'make_to_order', + 'active': True, + } + + def create_routes(self, cr, uid, ids, warehouse, context=None): + pull_obj = self.pool.get('procurement.rule') + res = super(stock_warehouse, self).create_routes(cr, uid, ids, warehouse, context=context) + buy_pull_vals = self._get_buy_pull_rule(cr, uid, warehouse, context=context) + if buy_pull_vals: + buy_pull_id = pull_obj.create(cr, uid, buy_pull_vals, context=context) + res['buy_pull_id'] = buy_pull_id + else: + res['buy_pull_id'] = False + return res + + + def write(self, cr, uid, ids, vals, context=None): + pull_obj = self.pool.get('procurement.rule') + if isinstance(ids, (int, long)): + ids = [ids] + + #only if update and checkbox have changed ! + if not vals.get("can_buy_for_resupply",None) is None: + + if vals.get("can_buy_for_resupply",False): + for warehouse in self.browse(cr, uid, ids, context=context): + if not warehouse.buy_pull_id: + warehouse.can_buy_for_resupply = True + buy_pull_vals = self._get_buy_pull_rule(cr, uid, warehouse, context=context) + buy_pull_id = pull_obj.create(cr, uid, buy_pull_vals, context=context) + vals['buy_pull_id'] = buy_pull_id + else: + for warehouse in self.browse(cr, uid, ids, context=context): + if warehouse.buy_pull_id: + buy_pull_id = pull_obj.unlink(cr, uid, warehouse.buy_pull_id.id, context=context) + vals['buy_pull_id'] = False + + return super(stock_warehouse,self).write(cr, uid, ids, vals, context=None) + +# def change_route(self, cr, uid, ids, warehouse, new_reception_step=False, new_delivery_step=False, context=None): +# pull_obj = self.pool.get('procurement.rule') +# res = super(stock_warehouse, self).change_route(cr, uid, ids, warehouse, new_reception_step, new_delivery_step, context) +# buy_pull_vals = self._get_buy_pull_rule(cr, uid, warehouse, context=context) +# pull_obj.write(cr, uid, warehouse.buy_pull_id.id, buy_pull_vals, context=context) +# return res + + def get_all_routes_for_wh(self, cr, uid, warehouse, context=None): + all_routes = super(stock_warehouse,self).get_all_routes_for_wh(cr,uid,warehouse,context=context) + if warehouse.can_buy_for_resupply and warehouse.buy_pull_id and warehouse.buy_pull_id.route_id: + all_routes += [warehouse.buy_pull_id.route_id.id] + return all_routes + + def _get_all_products_to_resupply(self, cr, uid, warehouse, context=None): + res = super(stock_warehouse,self)._get_all_products_to_resupply(cr, uid, warehouse, context=context) + for product_id in res: + for route in self.pool.get('product.product').browse(cr, uid, product_id, context=context).route_ids: + if warehouse.buy_pull_id and warehouse.buy_pull_id.route_id and route.id == warehouse.buy_pull_id.route_id.id: + res.remove(product_id) + break + return res \ No newline at end of file diff --git a/addons/purchase/stock_view.xml b/addons/purchase/stock_view.xml index 18ad626b84b..b612433266b 100644 --- a/addons/purchase/stock_view.xml +++ b/addons/purchase/stock_view.xml @@ -51,6 +51,19 @@ + + + Stock Warehouse Inherited + stock.warehouse + + + + + + + + + On Incoming Shipments diff --git a/addons/stock/__openerp__.py b/addons/stock/__openerp__.py index 998810b42d6..2ff8f902638 100644 --- a/addons/stock/__openerp__.py +++ b/addons/stock/__openerp__.py @@ -65,7 +65,7 @@ Dashboard / Reports for Warehouse Management will include: 'stock_orderpoint.yml', 'stock_demo.yml', 'stock_location_demo_cpu1.xml', - 'stock_location_demo_cpu3.yml', + 'stock_location_demo_cpu3.yml', ], 'data': [ 'security/stock_security.xml', @@ -114,6 +114,7 @@ Dashboard / Reports for Warehouse Management will include: 'static/lib/justgage.js', 'static/src/js/stock_picking_type.js', 'static/src/js/widgets.js', + 'static/src/js/CheckHide.js', ], 'qweb': ['static/src/xml/picking.xml'], } diff --git a/addons/stock/static/src/js/CheckHide.js b/addons/stock/static/src/js/CheckHide.js new file mode 100644 index 00000000000..e1e280491a1 --- /dev/null +++ b/addons/stock/static/src/js/CheckHide.js @@ -0,0 +1,35 @@ +function openerp_wh_hide(openerp) { + var module = openerp.stock; + var _t = openerp.web._t; + + openerp.web.form.FieldMany2ManyCheckBoxes.include({ + render_value: function(){ + this._super(); + var self = this; + setTimeout(function () { + self.ShowHide(); + }, 0); + }, + from_dom: function(){ + this._super(); + this.ShowHide(); + }, + ShowHide: function() { + var bShow = false; + this.$("input").each(function() { + bShow = bShow || ($(this).attr("checked") ? true : false) + }); + if (bShow) { + $(".resupply_ids").show(); + } + else { + $(".resupply_ids").hide(); + } + } + + }); + + openerp.web.form.custom_widgets.add("m2m_hide_resupply","openerp.stock.manageResupply"); + + //var a = false; $(".m2m_whids div").find(':checkbox').each( function(){ a = a | $(this)[0].checked; } ); alert(a); +} diff --git a/addons/stock/static/src/js/stock_picking_type.js b/addons/stock/static/src/js/stock_picking_type.js index 5b87ba891dc..38b975b112d 100644 --- a/addons/stock/static/src/js/stock_picking_type.js +++ b/addons/stock/static/src/js/stock_picking_type.js @@ -65,5 +65,6 @@ openerp.stock = function(openerp) { openerp.stock = openerp.stock || {}; openerp_picking_widgets(openerp); + openerp_wh_hide(openerp); }; diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 0ccc19799ca..a53900cef59 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2315,8 +2315,8 @@ class stock_warehouse(osv.osv): 'delivery_steps': 'ship_only', } _sql_constraints = [ - ('warehouse_name_uniq', 'unique (name, company_id)', 'The name of the warehouse must be unique per company!'), - ('warehouse_code_uniq', 'unique (code, company_id)', 'The code of the warehouse must be unique per company !'), + ('warehouse_name_uniq', 'unique(name, company_id)', 'The name of the warehouse must be unique per company!'), + ('warehouse_code_uniq', 'unique(code, company_id)', 'The code of the warehouse must be unique per company !'), ] def _get_partner_locations(self, cr, uid, ids, context=None): @@ -2464,14 +2464,14 @@ class stock_warehouse(osv.osv): #create route selectable on the product to resupply the warehouse from another one self._create_resupply_routes(cr, uid, warehouse, warehouse.resupply_wh_ids, warehouse.default_resupply_wh_id, context=context) - #set routes and mto pull rule on warehouse - return self.write(cr, uid, warehouse.id, { - 'route_ids': wh_route_ids, - 'mto_pull_id': mto_pull_id, - 'reception_route_id': reception_route_id, - 'delivery_route_id': delivery_route_id, - 'crossdock_route_id': crossdock_route_id, - }, context=context) + #return routes and mto pull rule for warehouse + return { + 'route_ids': wh_route_ids, + 'mto_pull_id': mto_pull_id, + 'reception_route_id': reception_route_id, + 'delivery_route_id': delivery_route_id, + 'crossdock_route_id': crossdock_route_id, + } def change_route(self, cr, uid, ids, warehouse, new_reception_step=False, new_delivery_step=False, context=None): picking_type_obj = self.pool.get('stock.picking.type') @@ -2527,6 +2527,7 @@ class stock_warehouse(osv.osv): def create(self, cr, uid, vals, context=None): if context is None: context = {} + if vals is None: vals = {} data_obj = self.pool.get('ir.model.data') @@ -2654,7 +2655,8 @@ class stock_warehouse(osv.osv): warehouse.refresh() #create routes and push/pull rules - self.create_routes(cr, uid, new_id, warehouse, context=context) + ret = self.create_routes(cr, uid, new_id, warehouse, context=context) + self.write(cr, uid, warehouse.id, ret , context=context) return new_id def _format_rulename(self, cr, uid, obj, from_loc, dest_loc, context=None): @@ -2674,7 +2676,7 @@ class stock_warehouse(osv.osv): 'crossdock': (_('Cross-Dock'), [(warehouse.wh_input_stock_loc_id, warehouse.wh_output_stock_loc_id, warehouse.int_type_id.id), (warehouse.wh_output_stock_loc_id, customer_loc, warehouse.out_type_id.id)]), 'ship_only': (_('Ship Only'), [(warehouse.lot_stock_id, customer_loc, warehouse.out_type_id.id)]), 'pick_ship': (_('Pick + Ship'), [(warehouse.lot_stock_id, warehouse.wh_output_stock_loc_id, warehouse.pick_type_id.id), (warehouse.wh_output_stock_loc_id, customer_loc, warehouse.out_type_id.id)]), - 'pick_pack_ship': (_('Pick + Pack + Ship'), [(warehouse.lot_stock_id, warehouse.wh_pack_stock_loc_id, warehouse.int_type_id.id), (warehouse.wh_pack_stock_loc_id, warehouse.wh_output_stock_loc_id, warehouse.pack_type_id.id), (warehouse.wh_output_stock_loc_id, customer_loc, warehouse.out_type_id.id)]), + 'pick_pack_ship': (_('Pick + Pack + Ship'), [(warehouse.lot_stock_id, warehouse.wh_pack_stock_loc_id, warehouse.int_type_id.id), (warehouse.wh_pack_stock_loc_id, warehouse.wh_output_stock_loc_id, warehouse.pack_type_id.id), (warehouse.wh_output_stock_loc_id, customer_loc, warehouse.out_type_id.id)]), } def write(self, cr, uid, ids, vals, context=None): @@ -2682,8 +2684,7 @@ class stock_warehouse(osv.osv): context = {} if isinstance(ids, (int, long)): ids = [ids] - if context is None: - context = {} + seq_obj = self.pool.get('ir.sequence') location_obj = self.pool.get('stock.location') route_obj = self.pool.get('stock.location.route') @@ -3162,6 +3163,16 @@ class stock_warehouse_orderpoint(osv.osv): return True + def _check_uniq_name(self, cr, uid, ids, context=None): + if not context: + context = {} + + for name in self.browse(cr, uid, ids, context=context): + if rule.product_id.uom_id.category_id.id != rule.product_uom.category_id.id: + return False + + return True + _columns = { 'name': fields.char('Name', size=32, required=True), 'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the orderpoint without removing it."), @@ -3192,10 +3203,10 @@ class stock_warehouse_orderpoint(osv.osv): 'company_id': lambda self, cr, uid, context: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.warehouse.orderpoint', context=context) } _sql_constraints = [ - ('qty_multiple_check', 'CHECK( qty_multiple > 0 )', 'Qty Multiple must be greater than zero.'), + ('qty_multiple_check', 'CHECK( qty_multiple > 0 )', 'Qty Multiple must be greater than zero.'), ] _constraints = [ - (_check_product_uom, 'You have to select a product unit of measure in the same category than the default unit of measure of the product', ['product_id', 'product_uom']), + (_check_product_uom, 'You have to select a product unit of measure in the same category than the default unit of measure of the product', ['product_id', 'product_uom']), ] def default_get(self, cr, uid, fields, context=None): diff --git a/addons/stock/stock_location_data.xml b/addons/stock/stock_location_data.xml deleted file mode 100644 index 1501597f482..00000000000 --- a/addons/stock/stock_location_data.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 9bfe83c2092..324e6f48a74 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -667,13 +667,13 @@ - - + + - +