[FIX] web: m2o search facet do no set `default_*` context key for "name_search" values
[odoo/odoo.git] / addons / delivery / stock.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 from openerp.osv import fields,osv
23 from openerp.tools.translate import _
24
25 import openerp.addons.decimal_precision as dp
26
27 # Overloaded stock_picking to manage carriers :
28 class stock_picking(osv.osv):
29     _inherit = 'stock.picking'
30
31     def _cal_weight(self, cr, uid, ids, name, args, context=None):
32         res = {}
33         for picking in self.browse(cr, uid, ids, context=context):
34             total_weight = total_weight_net = 0.00
35
36             for move in picking.move_lines:
37                 total_weight += move.weight
38                 total_weight_net += move.weight_net
39
40             res[picking.id] = {
41                                 'weight': total_weight,
42                                 'weight_net': total_weight_net,
43                               }
44         return res
45
46
47     def _get_picking_line(self, cr, uid, ids, context=None):
48         result = {}
49         for line in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
50             result[line.picking_id.id] = True
51         return result.keys()
52
53
54     _columns = {
55         'carrier_id':fields.many2one("delivery.carrier","Carrier"),
56         'volume': fields.float('Volume'),
57         'weight': fields.function(_cal_weight, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_weight',
58                   store={
59                  'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['move_lines'], 40),
60                  'stock.move': (_get_picking_line, ['picking_id', 'product_id','product_uom_qty','product_uom'], 40),
61                  }),
62         'weight_net': fields.function(_cal_weight, type='float', string='Net Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_weight',
63                   store={
64                  'stock.picking': (lambda self, cr, uid, ids, c={}: ids, ['move_lines'], 40),
65                  'stock.move': (_get_picking_line, ['picking_id', 'product_id','product_uom_qty','product_uom'], 40),
66                  }),
67         'carrier_tracking_ref': fields.char('Carrier Tracking Ref'),
68         'number_of_packages': fields.integer('Number of Packages'),
69         'weight_uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True,readonly="1",help="Unit of measurement for Weight",),
70     }
71
72     def _prepare_shipping_invoice_line(self, cr, uid, picking, invoice, context=None):
73         """Prepare the invoice line to add to the shipping costs to the shipping's
74            invoice.
75
76             :param browse_record picking: the stock picking being invoiced
77             :param browse_record invoice: the stock picking's invoice
78             :return: dict containing the values to create the invoice line,
79                      or None to create nothing
80         """
81         carrier_obj = self.pool.get('delivery.carrier')
82         grid_obj = self.pool.get('delivery.grid')
83         if not picking.carrier_id or \
84             any(inv_line.product_id.id == picking.carrier_id.product_id.id
85                 for inv_line in invoice.invoice_line):
86             return None
87         grid_id = carrier_obj.grid_get(cr, uid, [picking.carrier_id.id],
88                 picking.partner_id.id, context=context)
89         if not grid_id:
90             raise osv.except_osv(_('Warning!'),
91                     _('The carrier %s (id: %d) has no delivery grid!') \
92                             % (picking.carrier_id.name,
93                                 picking.carrier_id.id))
94         quantity = sum([line.product_uom_qty for line in picking.move_lines])
95         price = grid_obj.get_price_from_picking(cr, uid, grid_id,
96                 invoice.amount_untaxed, picking.weight, picking.volume,
97                 quantity, context=context)
98         account_id = picking.carrier_id.product_id.property_account_income.id
99         if not account_id:
100             account_id = picking.carrier_id.product_id.categ_id\
101                     .property_account_income_categ.id
102
103         taxes = picking.carrier_id.product_id.taxes_id
104         partner = picking.partner_id or False
105         if partner:
106             account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, partner.property_account_position, account_id)
107             taxes_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, partner.property_account_position, taxes)
108         else:
109             taxes_ids = [x.id for x in taxes]
110
111         return {
112             'name': picking.carrier_id.name,
113             'invoice_id': invoice.id,
114             'uos_id': picking.carrier_id.product_id.uos_id.id,
115             'product_id': picking.carrier_id.product_id.id,
116             'account_id': account_id,
117             'price_unit': price,
118             'quantity': 1,
119             'invoice_line_tax_id': [(6, 0, taxes_ids)],
120         }
121
122     def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
123         invoice_obj = self.pool.get('account.invoice')
124         invoice_line_obj = self.pool.get('account.invoice.line')
125         invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
126         invoice = invoice_obj.browse(cr, uid, invoice_id, context=context)
127         invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
128         if invoice_line:
129             invoice_line_obj.create(cr, uid, invoice_line)
130         return invoice_id
131
132     def _get_default_uom(self, cr, uid, context=None):
133         uom_categ_id = self.pool.get('ir.model.data').xmlid_to_res_id(cr, uid, 'product.product_uom_categ_kgm')
134         return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id), ('factor', '=', 1)])[0]
135
136     _defaults = {
137         'weight_uom_id': lambda self, cr, uid, c: self._get_default_uom(cr, uid, c),
138     }
139
140
141 class stock_move(osv.osv):
142     _inherit = 'stock.move'
143
144     def _cal_move_weight(self, cr, uid, ids, name, args, context=None):
145         res = {}
146         uom_obj = self.pool.get('product.uom')
147         for move in self.browse(cr, uid, ids, context=context):
148             weight = weight_net = 0.00
149             if move.product_id.weight > 0.00:
150                 converted_qty = move.product_qty
151                 weight = (converted_qty * move.product_id.weight)
152
153                 if move.product_id.weight_net > 0.00:
154                     weight_net = (converted_qty * move.product_id.weight_net)
155
156             res[move.id] =  {
157                             'weight': weight,
158                             'weight_net': weight_net,
159                             }
160         return res
161
162     _columns = {
163         'weight': fields.function(_cal_move_weight, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight',
164                   store={
165                  'stock.move': (lambda self, cr, uid, ids, c=None: ids, ['product_id', 'product_uom_qty', 'product_uom'], 30),
166                  }),
167         'weight_net': fields.function(_cal_move_weight, type='float', string='Net weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight',
168                   store={
169                  'stock.move': (lambda self, cr, uid, ids, c=None: ids, ['product_id', 'product_uom_qty', 'product_uom'], 30),
170                  }),
171         'weight_uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True,readonly="1",help="Unit of Measure (Unit of Measure) is the unit of measurement for Weight",),
172         }
173
174     def action_confirm(self, cr, uid, ids, context=None):
175         """
176             Pass the carrier to the picking from the sales order
177             (Should also work in case of Phantom BoMs when on explosion the original move is deleted)
178         """
179         procs_to_check = []
180         for move in self.browse(cr, uid, ids, context=context):
181             if move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.carrier_id:
182                 procs_to_check += [move.procurement_id]
183         res = super(stock_move, self).action_confirm(cr, uid, ids, context=context)
184         pick_obj = self.pool.get("stock.picking")
185         for proc in procs_to_check:
186             pickings = list(set([x.picking_id.id for x in proc.move_ids if x.picking_id and not x.picking_id.carrier_id]))
187             if pickings:
188                 pick_obj.write(cr, uid, pickings, {'carrier_id': proc.sale_line_id.order_id.carrier_id.id}, context=context)
189         return res
190
191
192     def _get_default_uom(self, cr, uid, context=None):
193         uom_categ_id = self.pool.get('ir.model.data').xmlid_to_res_id(cr, uid, 'product.product_uom_categ_kgm')
194         return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id),('factor','=',1)])[0]
195
196     _defaults = {
197         'weight_uom_id': lambda self, cr, uid, c: self._get_default_uom(cr, uid, c),
198     }
199
200
201 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: