diff --git a/move.py b/move.py index c714ac9ec8..21b39a4ca4 100644 --- a/move.py +++ b/move.py @@ -26,16 +26,10 @@ class Move(OSV): to_location = fields.Many2One( "stock.location", "To Location", select=1, required=True, states=STATES, domain="[('type', '!=', 'warehouse')]",) - incoming_packing_in = fields.Many2One( - "stock.packing.in", "Supplier Packing", states=STATES, select=1) - inventory_packing_in = fields.Many2One( - "stock.packing.in", "Inventory Supplier Packing", states=STATES, - select=1) - outgoing_packing_out = fields.Many2One( - "stock.packing.out", "Customer Packing", states=STATES, select=1) - inventory_packing_out = fields.Many2One( - "stock.packing.out", "Inventory Customer Packing", states=STATES, - select=1) + packing_in = fields.Many2One('stock.packing.in', 'Supplier Packing', + readonly=True, select=1) + packing_out = fields.Many2One('stock.packing.out', 'Customer Packing', + readonly=True, select=1) planned_date = fields.Date("Planned Date", states=STATES,) effective_date = fields.Date("Effective Date", readonly=True) state = fields.Selection([ @@ -57,47 +51,16 @@ class Move(OSV): self._sql_constraints += [ ('check_move_qty_pos', 'CHECK(quantity >= 0.0)', 'Move quantity must be positive'), - ] - self._constraints += [ - ('check_locations', - 'Invalid locations', []), + ('check_from_to_locations', + 'CHECK(from_location != to_location)', + 'Source and destination location must be different'), + ('check_packing_in_out', + 'CHECK(NOT(packing_in IS NOT NULL ' \ + 'AND packing_out IS NOT NULL))', + 'Move can not be in both Supplier and Customer Packing'), ] self._order[0] = ('id', 'DESC') - def check_locations(self, cursor, user, ids, context=None): - for move in self.browse(cursor, user, ids, context=context): - if move.from_location.id == move.to_location.id: - return False - if move.incoming_packing_in: - if move.incoming_packing_in.warehouse.input_location.id \ - != move.to_location.id: - return False - if move.from_location.type and move.from_location.type \ - not in ('supplier', 'customer'): - return False - for packing_move in move.incoming_packing_in.incoming_moves: - if packing_move.from_location.id != move.from_location.id: - return False - if move.inventory_packing_in and \ - move.inventory_packing_in.warehouse.input_location.id \ - != move.from_location.id: - return False - if move.inventory_packing_out and \ - move.inventory_packing_out.warehouse.output_location.id \ - != move.to_location.id: - return False - if move.outgoing_packing_out: - if move.outgoing_packing_out.warehouse.output_location.id \ - != move.from_location.id: - return False - if move.to_location.type and \ - move.to_location.type not in ('supplier', 'customer'): - return False - for packing_move in move.outgoing_packing_out.outgoing_moves: - if packing_move.to_location.id != move.to_location.id: - return False - return True - def default_to_location(self, cursor, user, context=None): if context and context.get('warehouse') and context.get('type'): wh_location = self.pool.get('stock.location').browse( @@ -191,12 +154,6 @@ class Move(OSV): Move() -class CreatePackingWarn(WizardOSV): - _name = 'stock.move.create_packing.warn' - -CreatePackingWarn() - - class CreatePacking(Wizard): 'Create Packing' _name = 'stock.move.create_packing' @@ -221,7 +178,7 @@ class CreatePacking(Wizard): # Collect moves by incoming location moves_by_location = {} for move in moves: - if move.incoming_packing_in or move.inventory_packing_in: + if move.packing_in: raise ExceptWizard( 'UserError', 'Moves cannot be already in a packing.') if move.state != 'waiting': @@ -235,15 +192,14 @@ class CreatePacking(Wizard): moves_by_location[location].append(move.id) # Fetch warehouse for these locations - wh_location_ids = location_obj.search( - cursor, user, - [('input_location', 'in', - [l for l in moves_by_location]), - ('type', '=', 'warehouse')], context=context) + wh_location_ids = location_obj.search(cursor, user, [ + ('input_location', 'in', moves_by_location.keys()), + ('type', '=', 'warehouse'), + ], context=context) wh_locations = location_obj.browse( cursor, user, wh_location_ids, context=context) loc2wh = dict( - [( whl.input_location.id, whl.id) for whl in wh_locations]) + [(whl.input_location.id, whl.id) for whl in wh_locations]) packing_ids = [] for location, move_ids in moves_by_location.iteritems(): @@ -253,10 +209,10 @@ class CreatePacking(Wizard): 'UserError', 'Moves must have a final destination '\ 'who is an input location of a wharehouse.') - pid = packing_obj.create( - cursor, user, - {'incoming_moves': [('set',move_ids)], 'warehouse': whl}, - context=context) + pid = packing_obj.create(cursor, user, { + 'incoming_moves': [('set', move_ids)], + 'warehouse': whl, + }, context=context) packing_ids.append(pid) @@ -269,10 +225,8 @@ class CreatePacking(Wizard): model_data = model_data_obj.browse(cursor, user, model_data_ids[0], context=context) res = act_window_obj.read(cursor, user, model_data.db_id, - context=context) - res["domain"]= str([('id', 'in', packing_ids)]) - + context=context) + res["domain"] = str([('id', 'in', packing_ids)]) return res CreatePacking() - diff --git a/move.xml b/move.xml index 0d26aa2133..6102a42d5d 100644 --- a/move.xml +++ b/move.xml @@ -110,9 +110,7 @@ Moves from suppliers to proceed stock.move form - [('from_location.type', '=', 'supplier'), - ('state','in',['draft','waiting']),('incoming_packing_in','=',False), - ('inventory_packing_in','=',False)] + [('from_location.type', '=', 'supplier'), ('state','in',['draft','waiting']), ('_packing_in','=',False)] @@ -177,22 +175,6 @@ action="act_move_form_cust_proceed" id="menu_move_form_cust_proceed"/> - - - - stock.move.create_packing.warn - form - - - - - - Create Packing stock.move.create_packing @@ -204,6 +186,5 @@ - diff --git a/packing.py b/packing.py index 9e7540929a..dffcacc5de 100644 --- a/packing.py +++ b/packing.py @@ -16,27 +16,32 @@ class PackingIn(OSV): effective_date =fields.DateTime('Effective Date', readonly=True) planned_date = fields.DateTime('Planned Date', readonly=True) - warehouse = fields.Many2One( - 'stock.location', "Warehouse", required=True, states=STATES, - domain="[('type', '=', 'warehouse')]",) - incoming_moves = fields.One2Many( - 'stock.move', 'incoming_packing_in', 'Incoming Moves', - states={'readonly': "state in ('received', 'done')",}, - context="{'warehouse': warehouse, "\ - "'packing_state': state, 'type':'incoming'}") - inventory_moves = fields.One2Many( - 'stock.move', 'inventory_packing_in', 'Inventory Moves', - states={'readonly': "state in ('draft', 'waiting')",}, - context="{'warehouse': warehouse, "\ - "'packing_state': state, 'type':'inventory_in'}") + warehouse = fields.Many2One('stock.location', "Warehouse", + required=True, states=STATES, domain="[('type', '=', 'warehouse')]") + incoming_moves = fields.Function('get_incoming_moves', type='one2many', + relation='stock.move', string='Incoming Moves', + fnct_inv='set_incoming_moves', + states={ + 'readonly': "state in ('received', 'done')", + }, context="{'warehouse': warehouse, "\ + "'packing_state': state, 'type':'incoming'}") + inventory_moves = fields.Function('get_inventory_moves', type='one2many', + relation='stock.move', string='Inventory Moves', + fnct_inv='set_inventory_moves', + states={ + 'readonly': "state in ('draft', 'waiting')", + }, context="{'warehouse': warehouse, "\ + "'packing_state': state, 'type':'inventory_in'}") + moves = fields.One2Many('stock.move', 'packing_in', 'Moves', + readonly=True) code = fields.Char("Code", size=None, select=1, readonly=True,) - state = fields.Selection( - [('draft', 'Draft'), - ('done', 'Done'), - ('cancel', 'Cancel'), - ('waiting', 'Waiting'), - ('received', 'Received')], - 'State', readonly=True) + state = fields.Selection([ + ('draft', 'Draft'), + ('done', 'Done'), + ('cancel', 'Cancel'), + ('waiting', 'Waiting'), + ('received', 'Received'), + ], 'State', readonly=True) def __init__(self): super(PackingIn, self).__init__() @@ -46,13 +51,98 @@ class PackingIn(OSV): 'set_state_draft', 'set_state_cancel', 'set_state_received', - 'create_inventory_moves', ] self._order[0] = ('id', 'DESC') def default_state(self, cursor, user, context=None): return 'draft' + def get_incoming_moves(self, cursor, user, ids, name, arg, context=None): + res = {} + for packing in self.browse(cursor, user, ids, context=context): + res[packing.id] = [] + for move in packing.moves: + if move.to_location.id == packing.warehouse.input_location.id: + res[packing.id].append(move.id) + return res + + def set_incoming_moves(self, cursor, user, packing_id, name, value, arg, + context=None): + move_obj = self.pool.get('stock.move') + packing = self.browse(cursor, user, packing_id, context=context) + for act in value: + if act[0] == 'create': + if 'to_location' in act[1]: + if act[1]['to_location'] != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Incoming Moves must ' \ + 'have input location as destination location!') + elif act[0] == 'write': + if 'to_location' in act[2]: + if act[2]['to_location'] != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Incoming Moves must ' \ + 'have input location as destination location!') + elif act[0] == 'add': + move = move_obj.browse(cursor, user, act[1], context=context) + if move.to_location.id != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Incoming Moves must ' \ + 'have input location as destination location!') + elif act[0] == 'set': + moves = move_obj.browse(cursor, user, act[1], context=context) + for move in moves: + if move.to_location.id != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Incoming Moves must ' \ + 'have input location as destination location!') + self.write(cursor, user, packing_id, { + 'moves': value, + }, context=context) + + def get_inventory_moves(self, cursor, user, ids, name, arg, context=None): + res = {} + for packing in self.browse(cursor, user, ids, context=context): + res[packing.id] = [] + for move in packing.moves: + if move.from_location.id == packing.warehouse.input_location.id: + res[packing.id].append(move.id) + return res + + def set_inventory_moves(self, cursor, user, packing_id, name, value, arg, + context=None): + move_obj = self.pool.get('stock.move') + packing = self.browse(cursor, user, packing_id, context=context) + for act in value: + if act[0] == 'create': + if 'from_location' in act[1]: + if act[1]['from_location'] != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have input location as source location!') + elif act[0] == 'write': + if 'from_location' in act[2]: + if act[2]['from_location'] != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have input location as source location!') + elif act[0] == 'add': + move = move_obj.browse(cursor, user, act[1], context=context) + if move.from_location.id != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have input location as source location!') + elif act[0] == 'set': + moves = move_obj.browse(cursor, user, act[1], context=context) + for move in moves: + if move.from_location.id != \ + packing.warehouse.input_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have input location as source location!') + self.write(cursor, user, packing_id, { + 'moves': value, + }, context=context) + def set_state_done(self, cursor, user, packing_id, context=None): move_obj = self.pool.get('stock.move') packing = self.browse(cursor, user, packing_id, context=context) @@ -88,8 +178,6 @@ class PackingIn(OSV): cursor, user, [m.id for m in packing.incoming_moves], context) self.write( cursor, user, packing_id, {'state':'received'}, context=context) - self.create_inventory_moves( - cursor, user, [packing_id], context=context) def set_state_draft(self, cursor, user, packing_id, context=None): move_obj = self.pool.get('stock.move') @@ -107,37 +195,28 @@ class PackingIn(OSV): return super(PackingIn, self).create( cursor, user, values, context=context) - def _store_location(self, cursor, user, incoming_move, context=None): - return incoming_move.incoming_packing_in.warehouse.storage_location.id + def _get_inventory_moves(self, cursor, user, incoming_move, context=None): + res = {} + if incoming_move.quantity <= 0.0: + return None + res['product'] = incoming_move.product.id + res['uom'] = incoming_move.uom.id + res['quantity'] = incoming_move.quantity + res['from_location'] = incoming_move.to_location.id + res['to_location'] = incoming_move.packing_in.warehouse.\ + storage_location.id + res['state'] = 'waiting' + return res - def create_inventory_moves(self, cursor, user, ids, context=None): - move_obj = self.pool.get('stock.move') - for packing in self.browse(cursor, user, ids, context=context): - product_balance = {} - for move in packing.inventory_moves: - key = (move.product.id, move.uom.id, move.from_location.id) - if key in product_balance: - product_balance[key] += move.quantity - else: - product_balance[key] = move.quantity - - for move in packing.incoming_moves: - key = (move.product.id, move.uom.id, move.to_location.id) - if key in product_balance and \ - product_balance[key] >= move.quantity: - product_balance[key] -= move.quantity - else: - values = { - 'product': move.product.id, - 'uom': move.uom.id, - 'quantity': move.quantity, - 'from_location': move.to_location.id, - 'to_location': self._store_location( - cursor, user, move, context=context), - 'inventory_packing_in': packing.id, - 'state': 'waiting', - } - move_obj.create(cursor, user, values, context=context) + def create_inventory_moves(self, cursor, user, packing_id, context=None): + packing = self.browse(cursor, user, packing_id, context=context) + for incoming_move in packing.incoming_moves: + vals = self._get_inventory_moves(cursor, user, incoming_move, + context=context) + if vals: + self.write(cursor, user, packing.id, { + 'inventory_moves': [('create', vals)] + }, context=context) PackingIn() @@ -150,33 +229,39 @@ class PackingOut(OSV): effective_date =fields.DateTime('Effective Date', readonly=True) planned_date = fields.DateTime('Planned Date', readonly=True) - warehouse = fields.Many2One( - 'stock.location', "Warehouse", required=True, - states={'readonly': "state != 'draft'",}, - domain="[('type', '=', 'warehouse')]",) - customer_location = fields.Many2One( - 'stock.location', "Customer Location", required=True, - states={'readonly': "state != 'draft'",}, - domain="[('type', '=', 'customer')]",) - outgoing_moves = fields.One2Many( - 'stock.move', 'outgoing_packing_out', 'Outgoing Moves', - states={'readonly':"state != 'ready'",}, - context="{'warehouse': warehouse, "\ - "'packing_state': state, 'type':'outgoing',}") - inventory_moves = fields.One2Many( - 'stock.move', 'inventory_packing_out', 'Inventory Moves', - states={'readonly':"state in ('ready', 'done')",}, - context="{'warehouse': warehouse, "\ - "'packing_state': state, 'type':'inventory_out',}") - code = fields.Char("Code", size=None, select=1, readonly=True,) - state = fields.Selection( - [('draft', 'Draft'), - ('done', 'Done'), - ('cancel', 'Cancel'), - ('assigned', 'Assigned'), - ('ready', 'Ready'), - ('waiting', 'Waiting')], - 'State', readonly=True) + warehouse = fields.Many2One('stock.location', "Warehouse", required=True, + states={ + 'readonly': "state != 'draft'", + }, domain="[('type', '=', 'warehouse')]") + customer_location = fields.Many2One('stock.location', "Customer Location", + required=True, states={ + 'readonly': "state != 'draft'", + }, domain="[('type', '=', 'customer')]") + outgoing_moves = fields.Function('get_outgoing_moves', type='one2many', + relation='stock.move', string='Outgoing Moves', + fnct_inv='set_outgoing_moves', + states={ + 'readonly':"state != 'ready'", + }, context="{'warehouse': warehouse, "\ + "'packing_state': state, 'type':'outgoing',}") + inventory_moves = fields.Function('get_inventory_moves', type='one2many', + relation='stock.move', string='Inventory Moves', + fnct_inv='set_inventory_moves', + states={ + 'readonly':"state in ('ready', 'done')", + }, context="{'warehouse': warehouse, "\ + "'packing_state': state, 'type':'inventory_out',}") + moves = fields.One2Many('stock.move', 'packing_in', 'Moves', + readonly=True) + code = fields.Char("Code", size=None, select=1, readonly=True) + state = fields.Selection([ + ('draft', 'Draft'), + ('done', 'Done'), + ('cancel', 'Cancel'), + ('assigned', 'Assigned'), + ('ready', 'Ready'), + ('waiting', 'Waiting'), + ], 'State', readonly=True) def __init__(self): super(PackingOut, self).__init__() @@ -195,6 +280,94 @@ class PackingOut(OSV): def default_state(self, cursor, user, context=None): return 'draft' + def get_outgoing_moves(self, cursor, user, ids, name, arg, context=None): + res = {} + for packing in self.browse(cursor, user, ids, context=context): + res[packing.id] = [] + for move in packing.moves: + if move.from_location.id == \ + packing.warehouse.output_location.id: + res[packing.id].append(move.id) + return res + + def set_outgoing_moves(self, cursor, user, packing_id, name, value, arg, + context=None): + move_obj = self.pool.get('stock.move') + packing = self.browse(cursor, user, packing_id, context=context) + for act in value: + if act[0] == 'create': + if 'from_location' in act[1]: + if act[1]['from_location'] != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Outgoing Moves must ' \ + 'have output location as source location!') + elif act[0] == 'write': + if 'from_location' in act[2]: + if act[2]['from_location'] != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Outgoing Moves must ' \ + 'have output location as source location!') + elif act[0] == 'add': + move = move_obj.browse(cursor, user, act[1], context=context) + if move.from_location.id != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Outgoing Moves must ' \ + 'have output location as source location!') + elif act[0] == 'set': + moves = move_obj.browse(cursor, user, act[1], context=context) + for move in moves: + if move.from_location.id != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Outgoing Moves must ' \ + 'have output location as source location!') + self.write(cursor, user, packing_id, { + 'moves': value, + }, context=context) + + def get_inventory_moves(self, cursor, user, ids, name, arg, context=None): + res = {} + for packing in self.browse(cursor, user, ids, context=context): + res[packing.id] = [] + for move in packing.moves: + if move.to_location.id == \ + packing.warehouse.output_location.id: + res[packing.id].append(move.id) + return res + + def set_inventory_moves(self, cursor, user, packing_id, name, value, arg, + context=None): + move_obj = self.pool.get('stock.move') + packing = self.browse(cursor, user, packing_id, context=context) + for act in value: + if act[0] == 'create': + if 'to_location' in act[1]: + if act[1]['to_location'] != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have output location as destination location!') + elif act[0] == 'write': + if 'to_location' in act[2]: + if act[2]['to_location'] != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have output location as destination location!') + elif act[0] == 'add': + move = move_obj.browse(cursor, user, act[1], context=context) + if move.to_location.id != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have output location as destination location!') + elif act[0] == 'set': + moves = move_obj.browse(cursor, user, act[1], context=context) + for move in moves: + if move.to_location.id != \ + packing.warehouse.output_location.id: + raise ExceptORM('UserError', 'Inventory Moves must ' \ + 'have output location as destination location!') + self.write(cursor, user, packing_id, { + 'moves': value, + }, context=context) + def set_state_assigned(self, cursor, user, packing_id, context=None): self.write(cursor, user, packing_id, {'state':'assigned'}, context=context) diff --git a/packing.xml b/packing.xml index 50dafd226a..42c9fa9305 100644 --- a/packing.xml +++ b/packing.xml @@ -329,7 +329,7 @@ Received function - set_state_received() + set_state_received() create_inventory_moves()