[MERGE] forward port of branch 7.0 up to 9b1cdea
[odoo/odoo.git] / addons / stock / wizard / stock_return_picking.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 import time
23
24 from openerp.osv import osv,fields
25 from openerp.tools.translate import _
26 import openerp.addons.decimal_precision as dp
27
28 class stock_return_picking_memory(osv.osv_memory):
29     _name = "stock.return.picking.memory"
30     _rec_name = 'product_id'
31
32     _columns = {
33         'product_id' : fields.many2one('product.product', string="Product", required=True),
34         'quantity' : fields.float("Quantity", digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
35         'wizard_id' : fields.many2one('stock.return.picking', string="Wizard"),
36         'move_id' : fields.many2one('stock.move', "Move"),
37         'prodlot_id': fields.related('move_id', 'prodlot_id', type='many2one', relation='stock.production.lot', string='Serial Number', readonly=True),
38
39     }
40
41
42
43 class stock_return_picking(osv.osv_memory):
44     _name = 'stock.return.picking'
45     _description = 'Return Picking'
46     _columns = {
47         'product_return_moves' : fields.one2many('stock.return.picking.memory', 'wizard_id', 'Moves'),
48         'invoice_state': fields.selection([('2binvoiced', 'To be refunded/invoiced'), ('none', 'No invoicing')], 'Invoicing',required=True),
49     }
50
51     def default_get(self, cr, uid, fields, context=None):
52         """
53          To get default values for the object.
54          @param self: The object pointer.
55          @param cr: A database cursor
56          @param uid: ID of the user currently logged in
57          @param fields: List of fields for which we want default values
58          @param context: A standard dictionary
59          @return: A dictionary with default values for all field in ``fields``
60         """
61         result1 = []
62         if context is None:
63             context = {}
64         res = super(stock_return_picking, self).default_get(cr, uid, fields, context=context)
65         record_id = context and context.get('active_id', False) or False
66         pick_obj = self.pool.get('stock.picking')
67         pick = pick_obj.browse(cr, uid, record_id, context=context)
68         if pick:
69             if 'invoice_state' in fields:
70                 if pick.invoice_state=='invoiced':
71                     res.update({'invoice_state': '2binvoiced'})
72                 else:
73                     res.update({'invoice_state': 'none'})
74             return_history = self.get_return_history(cr, uid, record_id, context)       
75             for line in pick.move_lines:
76                 qty = line.product_qty - return_history.get(line.id, 0)
77                 if qty > 0:
78                     result1.append({'product_id': line.product_id.id, 'quantity': qty,'move_id':line.id, 'prodlot_id': line.prodlot_id and line.prodlot_id.id or False})
79             if 'product_return_moves' in fields:
80                 res.update({'product_return_moves': result1})
81         return res
82
83     def view_init(self, cr, uid, fields_list, context=None):
84         """
85          Creates view dynamically and adding fields at runtime.
86          @param self: The object pointer.
87          @param cr: A database cursor
88          @param uid: ID of the user currently logged in
89          @param context: A standard dictionary
90          @return: New arch of view with new columns.
91         """
92         if context is None:
93             context = {}
94         res = super(stock_return_picking, self).view_init(cr, uid, fields_list, context=context)
95         record_id = context and context.get('active_id', False)
96         if record_id:
97             pick_obj = self.pool.get('stock.picking')
98             pick = pick_obj.browse(cr, uid, record_id, context=context)
99             if pick.state not in ['done','confirmed','assigned']:
100                 raise osv.except_osv(_('Warning!'), _("You may only return pickings that are Confirmed, Available or Done!"))
101             valid_lines = 0
102             return_history = self.get_return_history(cr, uid, record_id, context)
103             for m  in pick.move_lines:
104                 if m.state == 'done' and m.product_qty * m.product_uom.factor > return_history.get(m.id, 0):
105                     valid_lines += 1
106             if not valid_lines:
107                 raise osv.except_osv(_('Warning!'), _("No products to return (only lines in Done state and not fully returned yet can be returned)!"))
108         return res
109     
110     def get_return_history(self, cr, uid, pick_id, context=None):
111         """ 
112          Get  return_history.
113          @param self: The object pointer.
114          @param cr: A database cursor
115          @param uid: ID of the user currently logged in
116          @param pick_id: Picking id
117          @param context: A standard dictionary
118          @return: A dictionary which of values.
119         """
120         pick_obj = self.pool.get('stock.picking')
121         pick = pick_obj.browse(cr, uid, pick_id, context=context)
122         return_history = {}
123         for m  in pick.move_lines:
124             if m.state == 'done':
125                 return_history[m.id] = 0
126                 for rec in m.move_history_ids2:
127                     # only take into account 'product return' moves, ignoring any other
128                     # kind of upstream moves, such as internal procurements, etc.
129                     # a valid return move will be the exact opposite of ours:
130                     #     (src location, dest location) <=> (dest location, src location))
131                     if rec.location_dest_id.id == m.location_id.id \
132                         and rec.location_id.id == m.location_dest_id.id:
133                         return_history[m.id] += (rec.product_qty * rec.product_uom.factor)
134         return return_history
135
136     def create_returns(self, cr, uid, ids, context=None):
137         """ 
138          Creates return picking.
139          @param self: The object pointer.
140          @param cr: A database cursor
141          @param uid: ID of the user currently logged in
142          @param ids: List of ids selected
143          @param context: A standard dictionary
144          @return: A dictionary which of fields with values.
145         """
146         if context is None:
147             context = {} 
148         record_id = context and context.get('active_id', False) or False
149         move_obj = self.pool.get('stock.move')
150         pick_obj = self.pool.get('stock.picking')
151         uom_obj = self.pool.get('product.uom')
152         data_obj = self.pool.get('stock.return.picking.memory')
153         act_obj = self.pool.get('ir.actions.act_window')
154         model_obj = self.pool.get('ir.model.data')
155         pick = pick_obj.browse(cr, uid, record_id, context=context)
156         data = self.read(cr, uid, ids[0], context=context)
157         date_cur = time.strftime('%Y-%m-%d %H:%M:%S')
158         set_invoice_state_to_none = True
159         returned_lines = 0
160         
161 #        Create new picking for returned products
162
163         seq_obj_name = 'stock.picking'
164         new_type = 'internal'
165         if pick.type =='out':
166             new_type = 'in'
167             seq_obj_name = 'stock.picking.in'
168         elif pick.type =='in':
169             new_type = 'out'
170             seq_obj_name = 'stock.picking.out'
171         new_pick_name = self.pool.get('ir.sequence').get(cr, uid, seq_obj_name)
172         new_picking = pick_obj.copy(cr, uid, pick.id, {
173                                         'name': _('%s-%s-return') % (new_pick_name, pick.name),
174                                         'move_lines': [], 
175                                         'state':'draft', 
176                                         'type': new_type,
177                                         'date':date_cur, 
178                                         'invoice_state': data['invoice_state'],
179         })
180         
181         val_id = data['product_return_moves']
182         for v in val_id:
183             data_get = data_obj.browse(cr, uid, v, context=context)
184             mov_id = data_get.move_id.id
185             if not mov_id:
186                 raise osv.except_osv(_('Warning !'), _("You have manually created product lines, please delete them to proceed"))
187             new_qty = data_get.quantity
188             move = move_obj.browse(cr, uid, mov_id, context=context)
189             new_location = move.location_dest_id.id
190             returned_qty = move.product_qty
191             for rec in move.move_history_ids2:
192                 returned_qty -= rec.product_qty
193
194             if returned_qty != new_qty:
195                 set_invoice_state_to_none = False
196             if new_qty:
197                 returned_lines += 1
198                 new_move=move_obj.copy(cr, uid, move.id, {
199                                             'product_qty': new_qty,
200                                             'product_uos_qty': uom_obj._compute_qty(cr, uid, move.product_uom.id, new_qty, move.product_uos.id),
201                                             'picking_id': new_picking, 
202                                             'state': 'draft',
203                                             'location_id': new_location, 
204                                             'location_dest_id': move.location_id.id,
205                                             'date': date_cur,
206                                             'prodlot_id': data_get.prodlot_id.id,
207                 })
208                 move_obj.write(cr, uid, [move.id], {'move_history_ids2':[(4,new_move)]}, context=context)
209         if not returned_lines:
210             raise osv.except_osv(_('Warning!'), _("Please specify at least one non-zero quantity."))
211
212         if set_invoice_state_to_none:
213             pick_obj.write(cr, uid, [pick.id], {'invoice_state':'none'}, context=context)
214         pick_obj.signal_button_confirm(cr, uid, [new_picking])
215         pick_obj.force_assign(cr, uid, [new_picking], context)
216         # Update view id in context, lp:702939
217         model_list = {
218                 'out': 'stock.picking.out',
219                 'in': 'stock.picking.in',
220                 'internal': 'stock.picking',
221         }
222         return {
223             'domain': "[('id', 'in', ["+str(new_picking)+"])]",
224             'name': _('Returned Picking'),
225             'view_type':'form',
226             'view_mode':'tree,form',
227             'res_model': model_list.get(new_type, 'stock.picking'),
228             'type':'ir.actions.act_window',
229             'context':context,
230         }
231
232
233 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: