1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
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.
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.
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/>.
20 ##############################################################################
22 from openerp.osv import fields,osv
23 from openerp.tools.translate import _
25 import openerp.addons.decimal_precision as dp
27 # Overloaded stock_picking to manage carriers :
28 class stock_picking(osv.osv):
29 _inherit = 'stock.picking'
31 def _cal_weight(self, cr, uid, ids, name, args, context=None):
33 for picking in self.browse(cr, uid, ids, context=context):
34 total_weight = total_weight_net = 0.00
36 for move in picking.move_lines:
37 total_weight += move.weight
38 total_weight_net += move.weight_net
41 'weight': total_weight,
42 'weight_net': total_weight_net,
47 def _get_picking_line(self, cr, uid, ids, context=None):
49 for line in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
50 result[line.picking_id.id] = True
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',
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),
62 'weight_net': fields.function(_cal_weight, type='float', string='Net Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_weight',
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),
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",),
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
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
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):
87 grid_id = carrier_obj.grid_get(cr, uid, [picking.carrier_id.id],
88 picking.partner_id.id, context=context)
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
100 account_id = picking.carrier_id.product_id.categ_id\
101 .property_account_income_categ.id
103 taxes = picking.carrier_id.product_id.taxes_id
104 partner = picking.partner_id or False
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)
109 taxes_ids = [x.id for x in taxes]
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,
119 'invoice_line_tax_id': [(6, 0, taxes_ids)],
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)
129 invoice_line_obj.create(cr, uid, invoice_line)
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]
137 'weight_uom_id': lambda self, cr, uid, c: self._get_default_uom(cr, uid, c),
141 class stock_move(osv.osv):
142 _inherit = 'stock.move'
144 def _cal_move_weight(self, cr, uid, ids, name, args, context=None):
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)
153 if move.product_id.weight_net > 0.00:
154 weight_net = (converted_qty * move.product_id.weight_net)
158 'weight_net': weight_net,
163 'weight': fields.function(_cal_move_weight, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight',
165 'stock.move': (lambda self, cr, uid, ids, c=None: ids, ['product_id', 'product_uom_qty', 'product_uom'], 30),
167 'weight_net': fields.function(_cal_move_weight, type='float', string='Net weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight',
169 'stock.move': (lambda self, cr, uid, ids, c=None: ids, ['product_id', 'product_uom_qty', 'product_uom'], 30),
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",),
174 def action_confirm(self, cr, uid, ids, context=None):
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)
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]))
188 pick_obj.write(cr, uid, pickings, {'carrier_id': proc.sale_line_id.order_id.carrier_id.id}, context=context)
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]
197 'weight_uom_id': lambda self, cr, uid, c: self._get_default_uom(cr, uid, c),
201 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: