diff --git a/stock_reserve_sale/model/sale.py b/stock_reserve_sale/model/sale.py index 5fe8e3ef5..8341b8405 100644 --- a/stock_reserve_sale/model/sale.py +++ b/stock_reserve_sale/model/sale.py @@ -19,102 +19,134 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api +from openerp.exceptions import except_orm from openerp.tools.translate import _ -class sale_order(orm.Model): +class SaleOrder(models.Model): _inherit = 'sale.order' - def _stock_reservation(self, cr, uid, ids, fields, args, context=None): - result = {} - for order_id in ids: - result[order_id] = {'has_stock_reservation': False, - 'is_stock_reservable': False} - for sale in self.browse(cr, uid, ids, context=context): + @api.multi + @api.depends('state', + 'order_line.reservation_ids', + 'order_line.is_stock_reservable') + def _stock_reservation(self): + for sale in self: + has_stock_reservation = False + is_stock_reservable = False for line in sale.order_line: if line.reservation_ids: - result[sale.id]['has_stock_reservation'] = True + has_stock_reservation = True if line.is_stock_reservable: - result[sale.id]['is_stock_reservable'] = True + is_stock_reservable = True if sale.state not in ('draft', 'sent'): - result[sale.id]['is_stock_reservable'] = False - return result + is_stock_reservable = False + sale.is_stock_reservable = is_stock_reservable + sale.has_stock_reservation = has_stock_reservation - _columns = { - 'has_stock_reservation': fields.function( - _stock_reservation, - type='boolean', - readonly=True, - multi='stock_reservation', - string='Has Stock Reservations'), - 'is_stock_reservable': fields.function( - _stock_reservation, - type='boolean', - readonly=True, - multi='stock_reservation', - string='Can Have Stock Reservations'), - } + has_stock_reservation = fields.Boolean( + compute='_stock_reservation', + readonly=True, + multi='stock_reservation', + store=True, + string='Has Stock Reservations') + is_stock_reservable = fields.Boolean( + compute='_stock_reservation', + readonly=True, + multi='stock_reservation', + store=True, + string='Can Have Stock Reservations') - def release_all_stock_reservation(self, cr, uid, ids, context=None): - sales = self.browse(cr, uid, ids, context=context) - line_ids = [line.id for sale in sales for line in sale.order_line] - line_obj = self.pool.get('sale.order.line') - line_obj.release_stock_reservation(cr, uid, line_ids, context=context) + @api.multi + def release_all_stock_reservation(self): + line_ids = [line.id for order in self for line in order.order_line] + lines = self.env['sale.order.line'].browse(line_ids) + lines.release_stock_reservation() return True - def action_button_confirm(self, cr, uid, ids, context=None): - self.release_all_stock_reservation(cr, uid, ids, context=context) - return super(sale_order, self).action_button_confirm( - cr, uid, ids, context=context) + @api.multi + def action_button_confirm(self): + self.release_all_stock_reservation() + return super(SaleOrder, self).action_button_confirm() - def action_cancel(self, cr, uid, ids, context=None): - self.release_all_stock_reservation(cr, uid, ids, context=context) - return super(sale_order, self).action_cancel( - cr, uid, ids, context=context) + @api.multi + def action_cancel(self): + self.release_all_stock_reservation() + return super(SaleOrder, self).action_cancel() -class sale_order_line(orm.Model): +class SaleOrderLine(models.Model): _inherit = 'sale.order.line' - def _is_stock_reservable(self, cr, uid, ids, fields, args, context=None): - result = {}.fromkeys(ids, False) - for line in self.browse(cr, uid, ids, context=context): - if line.state != 'draft': - continue - if line.type == 'make_to_order': - continue - if (not line.product_id or line.product_id.type == 'service'): - continue - if not line.reservation_ids: - result[line.id] = True - return result + @api.multi + def _get_line_rule(self): + """ Get applicable rule for this product - _columns = { - 'reservation_ids': fields.one2many( - 'stock.reservation', - 'sale_line_id', - string='Stock Reservation'), - 'is_stock_reservable': fields.function( - _is_stock_reservable, - type='boolean', - readonly=True, - string='Can be reserved'), - } + Reproduce get suitable rule from procurement + to predict source location """ + ProcurementRule = self.env['procurement.rule'] + product = self.product_id + product_route_ids = [x.id for x in product.route_ids + + product.categ_id.total_route_ids] + rules = ProcurementRule.search([('route_id', 'in', product_route_ids)], + order='route_sequence, sequence', + limit=1) - def copy_data(self, cr, uid, id, default=None, context=None): - if default is None: - default = {} - default['reservation_ids'] = False - return super(sale_order_line, self).copy_data( - cr, uid, id, default=default, context=context) + if not rules: + warehouse = self.order_id.warehouse_id + wh_routes = warehouse.route_ids + wh_route_ids = [route.id for route in wh_routes] + domain = ['|', ('warehouse_id', '=', warehouse.id), + ('warehouse_id', '=', False), + ('route_id', 'in', wh_route_ids)] - def release_stock_reservation(self, cr, uid, ids, context=None): - lines = self.browse(cr, uid, ids, context=context) - reserv_ids = [reserv.id for line in lines + rules = ProcurementRule.search(domain, + order='route_sequence, sequence') + + if rules: + return rules[0] + return False + + @api.multi + def _get_procure_method(self): + """ Get procure_method depending on product routes """ + rule = self._get_line_rule() + if rule: + return rule.procure_method + return False + + @api.multi + @api.depends('state', + 'product_id.route_ids', + 'product_id.type') + def _is_stock_reservable(self): + for line in self: + reservable = False + if (not (line.state != 'draft' + or line._get_procure_method() == 'make_to_order' + or not line.product_id + or line.product_id.type == 'service') + and not line.reservation_ids): + reservable = True + line.is_stock_reservable = reservable + + reservation_ids = fields.One2many( + 'stock.reservation', + 'sale_line_id', + string='Stock Reservation', + copy=False) + is_stock_reservable = fields.Boolean( + compute='_is_stock_reservable', + readonly=True, + string='Can be reserved') + + @api.multi + def release_stock_reservation(self): + reserv_ids = [reserv.id for line in self for reserv in line.reservation_ids] - reserv_obj = self.pool.get('stock.reservation') - reserv_obj.release(cr, uid, reserv_ids, context=context) + reservations = self.env['stock.reservation'].browse(reserv_ids) + reservations.release() return True def product_id_change(self, cr, uid, ids, @@ -133,7 +165,7 @@ class sale_order_line(orm.Model): fiscal_position=False, flag=False, context=None): - result = super(sale_order_line, self).product_id_change( + result = super(SaleOrderLine, self).product_id_change( cr, uid, ids, pricelist, product, qty=qty, uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id, lang=lang, update_tax=update_tax, date_order=date_order, @@ -158,7 +190,8 @@ class sale_order_line(orm.Model): } return result - def write(self, cr, uid, ids, vals, context=None): + @api.multi + def write(self, vals): block_on_reserve = ('product_id', 'product_uom', 'product_uos', @@ -170,31 +203,29 @@ class sale_order_line(orm.Model): test_block = keys.intersection(block_on_reserve) test_update = keys.intersection(update_on_reserve) if test_block: - for line in self.browse(cr, uid, ids, context=context): + for line in self: if not line.reservation_ids: continue - raise orm.except_orm( + raise except_orm( _('Error'), _('You cannot change the product or unit of measure ' 'of lines with a stock reservation. ' 'Release the reservation ' 'before changing the product.')) - res = super(sale_order_line, self).write(cr, uid, ids, - vals, - context=context) + res = super(SaleOrderLine, self).write(vals) if test_update: - for line in self.browse(cr, uid, ids, context=context): + for line in self: if not line.reservation_ids: continue if len(line.reservation_ids) > 1: - raise orm.except_orm( + raise except_orm( _('Error'), _('Several stock reservations are linked with the ' 'line. Impossible to adjust their quantity. ' 'Please release the reservation ' 'before changing the quantity.')) - line.reservation_ids[0].write( + line.reservation_ids.write( {'price_unit': line.price_unit, 'product_qty': line.product_uom_qty, 'product_uos_qty': line.product_uos_qty, diff --git a/stock_reserve_sale/model/stock_reserve.py b/stock_reserve_sale/model/stock_reserve.py index 0ea5fb958..db68449bb 100644 --- a/stock_reserve_sale/model/stock_reserve.py +++ b/stock_reserve_sale/model/stock_reserve.py @@ -19,32 +19,24 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api -class stock_reservation(orm.Model): +class StockReservation(models.Model): _inherit = 'stock.reservation' - _columns = { - 'sale_line_id': fields.many2one( - 'sale.order.line', - string='Sale Order Line', - ondelete='cascade'), - 'sale_id': fields.related( - 'sale_line_id', 'order_id', - type='many2one', - relation='sale.order', - string='Sale Order') - } + sale_line_id = fields.Many2one( + 'sale.order.line', + string='Sale Order Line', + ondelete='cascade', + copy=False) + sale_id = fields.Many2one( + 'sale.order', + string='Sale Order', + related='sale_line_id.order_id') - def release(self, cr, uid, ids, context=None): - self.write(cr, uid, ids, {'sale_line_id': False}, context=context) - return super(stock_reservation, self).release( - cr, uid, ids, context=context) - - def copy_data(self, cr, uid, id, default=None, context=None): - if default is None: - default = {} - default['sale_line_id'] = False - return super(stock_reservation, self).copy_data( - cr, uid, id, default=default, context=context) + @api.multi + def release(self): + for rec in self: + rec.sale_line_id = False + return super(StockReservation, self).release() diff --git a/stock_reserve_sale/wizard/sale_stock_reserve.py b/stock_reserve_sale/wizard/sale_stock_reserve.py index 7aac6d605..b5961caeb 100644 --- a/stock_reserve_sale/wizard/sale_stock_reserve.py +++ b/stock_reserve_sale/wizard/sale_stock_reserve.py @@ -19,92 +19,85 @@ # ############################################################################## -from openerp.osv import orm, fields +from openerp import models, fields, api -class sale_stock_reserve(orm.TransientModel): +class SaleStockReserve(models.TransientModel): _name = 'sale.stock.reserve' - _columns = { - 'location_id': fields.many2one( - 'stock.location', - 'Source Location', - required=True), - 'location_dest_id': fields.many2one( - 'stock.location', - 'Reservation Location', - required=True, - help="Location where the system will reserve the " - "products."), - 'date_validity': fields.date( - "Validity Date", - help="If a date is given, the reservations will be released " - "at the end of the validity."), - 'note': fields.text('Notes'), - } + @api.model + def _default_location_id(self): + return self.env['stock.reservation']._default_location_id() - def _default_location_id(self, cr, uid, context=None): - reserv_obj = self.pool.get('stock.reservation') - return reserv_obj._default_location_id(cr, uid, context=context) + @api.model + def _default_location_dest_id(self): + return self.env['stock.reservation']._default_location_dest_id() - def _default_location_dest_id(self, cr, uid, context=None): - reserv_obj = self.pool.get('stock.reservation') - return reserv_obj._default_location_dest_id(cr, uid, context=context) + location_id = fields.Many2one( + 'stock.location', + 'Source Location', + required=True, + default=_default_location_id) + location_dest_id = fields.Many2one( + 'stock.location', + 'Reservation Location', + required=True, + help="Location where the system will reserve the " + "products.", + default=_default_location_dest_id) + date_validity = fields.Date( + "Validity Date", + help="If a date is given, the reservations will be released " + "at the end of the validity.") + note = fields.Text('Notes') - _defaults = { - 'location_id': _default_location_id, - 'location_dest_id': _default_location_dest_id, - } - def _prepare_stock_reservation(self, cr, uid, form, line, context=None): + @api.one + def _prepare_stock_reservation(self, line): product_uos = line.product_uos.id if line.product_uos else False return {'product_id': line.product_id.id, 'product_uom': line.product_uom.id, 'product_qty': line.product_uom_qty, - 'date_validity': form.date_validity, + 'date_validity': self.date_validity, 'name': "{} ({})".format(line.order_id.name, line.name), - 'location_id': form.location_id.id, - 'location_dest_id': form.location_dest_id.id, - 'note': form.note, + 'location_id': self.location_id.id, + 'location_dest_id': self.location_dest_id.id, + 'note': self.note, 'product_uos_qty': line.product_uos_qty, 'product_uos': product_uos, 'price_unit': line.price_unit, 'sale_line_id': line.id, } - def stock_reserve(self, cr, uid, ids, line_ids, context=None): - assert len(ids) == 1, "Expected 1 ID, got %r" % ids - reserv_obj = self.pool.get('stock.reservation') - line_obj = self.pool.get('sale.order.line') + @api.multi + def stock_reserve(self, line_ids): + assert len(self.ids) == 1, "Expected 1 ID, got %r" % self.ids - form = self.browse(cr, uid, ids[0], context=context) - lines = line_obj.browse(cr, uid, line_ids, context=context) + lines = self.env['sale.order.line'].browse(line_ids) for line in lines: if not line.is_stock_reservable: continue - vals = self._prepare_stock_reservation(cr, uid, form, line, - context=context) - reserv_id = reserv_obj.create(cr, uid, vals, context=context) - reserv_obj.reserve(cr, uid, [reserv_id], context=context) + vals = self._prepare_stock_reservation(line)[0] + reserv = self.env['stock.reservation'].create(vals) + reserv.reserve() return True - def button_reserve(self, cr, uid, ids, context=None): - assert len(ids) == 1, "Expected 1 ID, got %r" % ids - if context is None: - context = {} + @api.multi + def button_reserve(self): + env = self.env + assert len(self.ids) == 1, "Expected 1 ID, got %r" % self.ids close = {'type': 'ir.actions.act_window_close'} - active_model = context.get('active_model') - active_ids = context.get('active_ids') + active_model = env.context.get('active_model') + active_ids = env.context.get('active_ids') if not (active_model and active_ids): return close if active_model == 'sale.order': - sale_obj = self.pool.get('sale.order') - sales = sale_obj.browse(cr, uid, active_ids, context=context) + sales = env['sale.order'].browse(active_ids) line_ids = [line.id for sale in sales for line in sale.order_line] if active_model == 'sale.order.line': line_ids = active_ids - self.stock_reserve(cr, uid, ids, line_ids, context=context) + self.stock_reserve(line_ids) return close