167.24.2
by office at chricar
[ADD] purchase_landed_costs |
1 |
# -*- coding: utf-8 -*-
|
2 |
##############################################################################
|
|
3 |
#
|
|
4 |
# OpenERP, Open Source Management Solution
|
|
5 |
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
|
423
by ferdinand
[FIX] Copyright |
6 |
# Copyright (C) 2010-2012 Camptocamp Austria (<http://www.camptocamp.at>)
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
7 |
#
|
8 |
# This program is free software: you can redistribute it and/or modify
|
|
9 |
# it under the terms of the GNU Affero General Public License as
|
|
10 |
# published by the Free Software Foundation, either version 3 of the
|
|
11 |
# License, or (at your option) any later version.
|
|
12 |
#
|
|
13 |
# This program is distributed in the hope that it will be useful,
|
|
14 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16 |
# GNU Affero General Public License for more details.
|
|
17 |
#
|
|
18 |
# You should have received a copy of the GNU Affero General Public License
|
|
19 |
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20 |
#
|
|
21 |
##############################################################################
|
|
22 |
||
23 |
from osv import osv, fields |
|
24 |
import decimal_precision as dp |
|
25 |
from tools.translate import _ |
|
167.44.37
by Gerhard Könighofer
improved logging, improved import structure |
26 |
import logging |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
27 |
|
28 |
class landed_cost_position(osv.osv): |
|
29 |
_name = "landed.cost.position" |
|
30 |
||
31 |
_columns = \ |
|
167.24.4
by office at chricar
[FIX] tpyos |
32 |
{ 'product_id' : fields.many2one('product.product','Landed Cost Name', required=True, domain=[('landed_cost_type','!=', False)]), |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
33 |
'amount' : fields.float |
34 |
( 'Amount' |
|
35 |
, required=True |
|
36 |
, digits_compute=dp.get_precision('Purchase Price') |
|
37 |
, help="""Landed cost for stock valuation. It will be added to the price of the supplier price."""), |
|
38 |
'amount_currency': fields.float('Amount Currency', help="The amount expressed in an optional other currency."), |
|
39 |
'currency_id': fields.many2one('res.currency', 'Secondary Currency', help="Optional other currency."), |
|
889
by ferdinand
[FIX] make partner mandatory |
40 |
'partner_id': fields.many2one('res.partner', 'Partner', help="The supplier of this cost component.", required="True"), |
167.24.24
by office at chricar
[FIX] text |
41 |
'price_type': fields.selection( [('per_unit','Per Quantity'), ('value','Absolute Value')], 'Amount Type', required=True, \ |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
42 |
help="Defines if the amount is to be calculated for each quantity or an absolute value"), |
167.24.4
by office at chricar
[FIX] tpyos |
43 |
'purchase_order_line_id': fields.many2one('purchase.order.line', 'Purchase Order Line'), |
44 |
'purchase_order_id': fields.many2one('purchase.order', 'Purchase Order'), |
|
45 |
'move_line_id': fields.many2one('stock.move', 'Picking Line'), |
|
46 |
'picking_id': fields.many2one('stock.picking', 'Picking'), |
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
47 |
}
|
48 |
||
167.24.23
by office at chricar
[ADD] on chagen trigger |
49 |
def onchange_product_id(self, cr, uid, ids, product_id, context=None): |
50 |
if product_id: |
|
51 |
prod_obj=self.pool.get('product.product') |
|
52 |
prod=prod_obj.browse(cr,uid,[product_id])[0] |
|
53 |
v = {'price_type':prod.landed_cost_type} |
|
54 |
return {'value': v} |
|
55 |
return {} |
|
56 |
||
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
57 |
landed_cost_position() |
58 |
||
59 |
#----------------------------------------------------------
|
|
60 |
# Purchase Line INHERIT
|
|
61 |
#----------------------------------------------------------
|
|
62 |
class purchase_order_line(osv.osv): |
|
63 |
_inherit = "purchase.order.line" |
|
64 |
||
65 |
def _landing_cost(self, cr, uid, ids, name, args, context): |
|
66 |
if not ids : return {} |
|
67 |
result = {} |
|
68 |
# landed costss for the line
|
|
69 |
for line in self.browse(cr, uid, ids): |
|
886.1.1
by ferdinand
[REF] landed costs on order (not lines) |
70 |
landed_costs = 0.0 |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
71 |
if line.landed_cost_line_ids: |
72 |
for costs in line.landed_cost_line_ids: |
|
73 |
if costs.price_type == 'value': |
|
74 |
landed_costs += costs.amount |
|
75 |
else: |
|
76 |
landed_costs += costs.amount * line.product_qty |
|
167.24.6
by office at chricar
[FIX] better usability |
77 |
result[line.id] = landed_costs |
78 |
return result |
|
79 |
||
80 |
def _landing_cost_order(self, cr, uid, ids, name, args, context): |
|
81 |
if not ids : return {} |
|
82 |
result = {} |
|
934.2.2
by David Cormier
Uses distribution method of landed cost instead of product if specified |
83 |
# landed costs for the line
|
167.24.6
by office at chricar
[FIX] better usability |
84 |
for line in self.browse(cr, uid, ids): |
886.1.1
by ferdinand
[REF] landed costs on order (not lines) |
85 |
landed_costs = 0.0 |
934.2.2
by David Cormier
Uses distribution method of landed cost instead of product if specified |
86 |
# distribution of landed costs of PO
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
87 |
if line.order_id.landed_cost_line_ids: |
934.2.2
by David Cormier
Uses distribution method of landed cost instead of product if specified |
88 |
landed_costs += line.order_id.landed_cost_base_value / line.order_id.amount_total * line.price_subtotal + \ |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
89 |
line.order_id.landed_cost_base_quantity / line.order_id.quantity_total * line.product_qty |
90 |
result[line.id] = landed_costs |
|
167.24.6
by office at chricar
[FIX] better usability |
91 |
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
92 |
return result |
93 |
||
934.2.3
by David Cormier
Adds helper method to calculate percentage of landed cost to be put on po line |
94 |
def _landing_cost_factor(self, cr, uid, ids, name, args, context): |
95 |
"""
|
|
96 |
Calculates the percentage of landing costs that should be put on this order line
|
|
97 |
"""
|
|
98 |
for line in self.browse(cr, uid, ids): |
|
99 |
if line.landed_cost_line_ids: |
|
100 |
pass
|
|
101 |
||
167.24.6
by office at chricar
[FIX] better usability |
102 |
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
103 |
def _landed_cost(self, cr, uid, ids, name, args, context): |
104 |
if not ids : return {} |
|
105 |
result = {} |
|
106 |
# landed costss for the line
|
|
107 |
for line in self.browse(cr, uid, ids): |
|
886.1.1
by ferdinand
[REF] landed costs on order (not lines) |
108 |
landed_costs = 0.0 |
167.24.6
by office at chricar
[FIX] better usability |
109 |
landed_costs += line.price_subtotal + line.landing_costs + line.landing_costs_order |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
110 |
result[line.id] = landed_costs |
111 |
||
112 |
return result |
|
113 |
||
114 |
_columns = \ |
|
167.24.4
by office at chricar
[FIX] tpyos |
115 |
{
|
116 |
'landed_cost_line_ids': fields.one2many('landed.cost.position', 'purchase_order_line_id', 'Landed Costs Positions'), |
|
117 |
'landing_costs' : fields.function(_landing_cost, digits_compute=dp.get_precision('Account'), string='Landing Costs'), |
|
167.24.6
by office at chricar
[FIX] better usability |
118 |
'landing_costs_order' : fields.function(_landing_cost_order, digits_compute=dp.get_precision('Account'), string='Landing Costs from Order'), |
167.24.4
by office at chricar
[FIX] tpyos |
119 |
'landed_costs' : fields.function(_landed_cost, digits_compute=dp.get_precision('Account'), string='Landed Costs'), |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
120 |
}
|
121 |
||
122 |
purchase_order_line() |
|
123 |
||
124 |
class purchase_order(osv.osv): |
|
125 |
_inherit = "purchase.order" |
|
167.47.3
by Gerhard Könighofer
_name-bug fixed |
126 |
_logger = logging.getLogger(__name__) |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
127 |
|
128 |
def _landed_cost_base_value(self, cr, uid, ids, name, args, context): |
|
129 |
if not ids : return {} |
|
130 |
result = {} |
|
131 |
landed_costs_base_value = 0.0 |
|
132 |
for line in self.browse(cr, uid, ids): |
|
133 |
if line.landed_cost_line_ids: |
|
134 |
for costs in line.landed_cost_line_ids: |
|
934.2.2
by David Cormier
Uses distribution method of landed cost instead of product if specified |
135 |
if costs.price_type == 'value': |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
136 |
landed_costs_base_value += costs.amount |
137 |
result[line.id] = landed_costs_base_value |
|
138 |
return result |
|
139 |
||
140 |
def _landed_cost_base_quantity(self, cr, uid, ids, name, args, context): |
|
141 |
if not ids : return {} |
|
142 |
result = {} |
|
143 |
landed_costs_base_quantity = 0.0 |
|
144 |
for line in self.browse(cr, uid, ids): |
|
145 |
if line.landed_cost_line_ids: |
|
146 |
for costs in line.landed_cost_line_ids: |
|
934.2.2
by David Cormier
Uses distribution method of landed cost instead of product if specified |
147 |
if costs.price_type == 'per_unit': |
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
148 |
landed_costs_base_quantity += costs.amount |
149 |
result[line.id] = landed_costs_base_quantity |
|
150 |
return result |
|
151 |
||
152 |
def _quantity_total(self, cr, uid, ids, name, args, context): |
|
153 |
if not ids : return {} |
|
154 |
result = {} |
|
155 |
quantity_total = 0.0 |
|
156 |
for line in self.browse(cr, uid, ids): |
|
157 |
if line.order_line: |
|
158 |
for pol in line.order_line: |
|
159 |
if pol.product_qty > 0.0: |
|
160 |
quantity_total += pol.product_qty |
|
161 |
result[line.id] = quantity_total |
|
162 |
return result |
|
163 |
||
167.24.4
by office at chricar
[FIX] tpyos |
164 |
def _landed_cost(self, cr, uid, ids, name, args, context): |
165 |
if not ids : return {} |
|
166 |
result = {} |
|
167 |
landed_costs = 0.0 |
|
168 |
# landed costss for the line
|
|
169 |
for line in self.browse(cr, uid, ids): |
|
886.1.1
by ferdinand
[REF] landed costs on order (not lines) |
170 |
landed_costs += line.landing_cost_lines + line.landed_cost_base_value + line.landed_cost_base_quantity + line.amount_untaxed |
167.24.4
by office at chricar
[FIX] tpyos |
171 |
result[line.id] = landed_costs |
172 |
||
173 |
return result |
|
174 |
||
167.24.5
by office at chricar
[FIX] calculation landed cost |
175 |
def _landing_cost_lines(self, cr, uid, ids, name, args, context): |
176 |
if not ids : return {} |
|
177 |
result = {} |
|
178 |
landed_cost_lines = 0.0 |
|
179 |
for line in self.browse(cr, uid, ids): |
|
180 |
if line.order_line: |
|
181 |
for pol in line.order_line: |
|
182 |
if pol.product_qty > 0.0: |
|
183 |
landed_cost_lines += pol.landing_costs |
|
184 |
result[line.id] = landed_cost_lines |
|
185 |
return result |
|
186 |
||
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
187 |
|
188 |
_columns = \ |
|
167.24.4
by office at chricar
[FIX] tpyos |
189 |
{
|
190 |
'landed_cost_line_ids': fields.one2many('landed.cost.position', 'purchase_order_id', 'Landed Costs'), |
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
191 |
'landed_cost_base_value' : fields.function(_landed_cost_base_value, digits_compute=dp.get_precision('Account'), string='Landed Costs Base Value'), |
192 |
'landed_cost_base_quantity' : fields.function(_landed_cost_base_quantity, digits_compute=dp.get_precision('Account'), string='Landed Costs Base Quantity'), |
|
167.24.5
by office at chricar
[FIX] calculation landed cost |
193 |
'landing_cost_lines' : fields.function(_landing_cost_lines, digits_compute=dp.get_precision('Account'), string='Landing Cost Lines'), |
194 |
'landed_cost' : fields.function(_landed_cost, digits_compute=dp.get_precision('Account'), string='Landed Costs Total Untaxed'), |
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
195 |
'quantity_total' : fields.function(_quantity_total, digits_compute=dp.get_precision('Product UoM'), string='Total Quantity'), |
196 |
}
|
|
197 |
||
198 |
def _prepare_order_line_move(self, cr, uid, order, order_line, picking_id, context=None): |
|
199 |
res = super(purchase_order,self)._prepare_order_line_move( cr, uid, order, order_line, picking_id, context) |
|
167.24.17
by office at chricar
[FIX] calculation landed cost |
200 |
res['price_unit_net'] = res['price_unit'] |
167.24.13
by office at chricar
[FIX] correct value for stock move |
201 |
res['price_unit'] = order_line.landed_costs / order_line.product_qty |
167.24.8
by office at chricar
[FREF] landing costs for pick |
202 |
return res |
203 |
||
204 |
def _prepare_order_picking(self, cr, uid, order, context=None): |
|
205 |
res = super(purchase_order,self)._prepare_order_picking( cr, uid, order, context) |
|
167.24.9
by office at chricar
[REF] landing costs for pick copied |
206 |
|
207 |
return res |
|
208 |
||
934.2.3
by David Cormier
Adds helper method to calculate percentage of landed cost to be put on po line |
209 |
def _get_product_account_expense_id(self, product): |
210 |
"""
|
|
211 |
Returns the product's account expense id if present
|
|
212 |
or it's parent categories account expense id otherwise
|
|
213 |
"""
|
|
214 |
if product.property_account_expense.id: |
|
215 |
return product.property_account_expense.id |
|
216 |
return product.categ_id.property_account_expense_categ.id |
|
217 |
||
218 |
||
167.24.9
by office at chricar
[REF] landing costs for pick copied |
219 |
def _create_pickings(self, cr, uid, order, order_lines, picking_id=False, context=None): |
220 |
res = super(purchase_order,self)._create_pickings(cr, uid, order, order_lines, picking_id, context) |
|
221 |
pick_id = int(res[0]) |
|
886.1.2
by ferdinand
[REF] landed cost invoices |
222 |
# landing costs Invoices from PO
|
223 |
#cost_obj = self.pool.get('landed.cost.position')
|
|
224 |
invoice_obj = self.pool.get('account.invoice') |
|
225 |
invoice_line_obj = self.pool.get('account.invoice.line') |
|
226 |
journal_obj = self.pool.get('account.journal') |
|
227 |
journal_ids = journal_obj.search(cr, uid, [('type', '=','purchase'),('company_id', '=', order.company_id.id)], limit=1) |
|
167.24.9
by office at chricar
[REF] landing costs for pick copied |
228 |
for order_cost in order.landed_cost_line_ids: |
886.1.2
by ferdinand
[REF] landed cost invoices |
229 |
vals_inv = { |
230 |
'partner_id' : order_cost.partner_id.id |
|
888
by ferdinand
[FIX] missing fields in form |
231 |
#,'amount' : order_cost.amount
|
232 |
#,'amount_currency' : order_cost.amount_currency
|
|
886.1.2
by ferdinand
[REF] landed cost invoices |
233 |
,'currency_id' : order_cost.currency_id.id or order.company_id.currency_id.id |
234 |
,'account_id' : order_cost.partner_id.property_account_payable.id |
|
235 |
,'type' : 'in_invoice' |
|
236 |
,'origin' : order.name |
|
237 |
,'fiscal_position': order.partner_id.property_account_position and order.partner_id.property_account_position.id or False |
|
238 |
,'company_id': order.company_id.id |
|
239 |
,'journal_id': len(journal_ids) and journal_ids[0] or False |
|
240 |
||
241 |
}
|
|
242 |
self._logger.debug('vals inv`%s`', vals_inv) |
|
243 |
#cost_obj.create(cr, uid, vals, context=None)
|
|
244 |
inv_id = invoice_obj.create(cr, uid, vals_inv, context=None) |
|
245 |
vals_line = { |
|
246 |
'product_id' : order_cost.product_id.id |
|
247 |
,'name' : order_cost.product_id.name |
|
888
by ferdinand
[FIX] missing fields in form |
248 |
#,'amount' : order_cost.amount
|
249 |
#,'amount_currency' : order_cost.amount_currency
|
|
250 |
#,'picking_id' : pick_id
|
|
934.2.3
by David Cormier
Adds helper method to calculate percentage of landed cost to be put on po line |
251 |
,'account_id' : self._get_product_account_expense_id(order_cost.product_id) |
886.1.2
by ferdinand
[REF] landed cost invoices |
252 |
,'partner_id' : order_cost.partner_id.id |
253 |
,'invoice_id' : inv_id |
|
254 |
,'price_unit' : order_cost.amount |
|
255 |
,'invoice_line_tax_id': [(6, 0, [x.id for x in order_cost.product_id.supplier_taxes_id])], |
|
256 |
||
257 |
}
|
|
258 |
self._logger.debug('vals line `%s`', vals_line) |
|
259 |
inv_line_id = invoice_line_obj.create(cr, uid, vals_line, context=None) |
|
260 |
||
167.24.9
by office at chricar
[REF] landing costs for pick copied |
261 |
|
262 |
#self.pool.get('landed.cost.position').create(cr, uid, cost_lines, context=None)
|
|
263 |
# landing costs for PICK Lines from PO
|
|
886.1.2
by ferdinand
[REF] landed cost invoices |
264 |
#pick_obj = self.pool.get('stock.picking')
|
265 |
#for pick in pick_obj.browse(cr, uid, [pick_id], context=None):
|
|
266 |
# self._logger.debug('pick `%s`', pick)
|
|
267 |
# for line in pick.move_lines:
|
|
268 |
# self._logger.debug('line `%s`', line)
|
|
269 |
# for order_cost in line.purchase_line_id.landed_cost_line_ids:
|
|
270 |
# vals = {}
|
|
271 |
# vals['product_id'] = order_cost.product_id.id
|
|
272 |
# vals['partner_id'] = order_cost.partner_id.id
|
|
273 |
# vals['amount'] = order_cost.amount
|
|
274 |
# vals['amount_currency'] = order_cost.amount_currency
|
|
275 |
# vals['currency_id'] = order_cost.currency_id.id
|
|
276 |
# vals['price_type'] = order_cost.price_type
|
|
277 |
# vals['move_line_id'] = line.id
|
|
278 |
# self._logger.debug('vals `%s`', vals)
|
|
279 |
# cost_obj.create(cr, uid, vals, context=None)
|
|
280 |
#self._logger.debug('cost created')
|
|
167.24.9
by office at chricar
[REF] landing costs for pick copied |
281 |
|
282 |
return res |
|
167.24.2
by office at chricar
[ADD] purchase_landed_costs |
283 |
|
284 |
purchase_order() |