Merge lp:~david-cormier-j/sale-wkfl/sale_landed_costs into lp:~sale-core-editors/sale-wkfl/7.0
- sale_landed_costs
- Merge into 7.0
Proposed by
David Cormier
Status: | Needs review |
---|---|
Proposed branch: | lp:~david-cormier-j/sale-wkfl/sale_landed_costs |
Merge into: | lp:~sale-core-editors/sale-wkfl/7.0 |
Diff against target: |
321 lines (+301/-0) 4 files modified
sale_landed_costs/__init__.py (+26/-0) sale_landed_costs/__openerp__.py (+47/-0) sale_landed_costs/sale.py (+188/-0) sale_landed_costs/sale_view.xml (+40/-0) |
To merge this branch: | bzr merge lp:~david-cormier-j/sale-wkfl/sale_landed_costs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Pedro Manuel Baeza | Needs Resubmitting | ||
Joël Grand-Guillaume @ camptocamp | code review, no tests | Needs Fixing | |
Review via email:
|
Commit message
Description of the change
Add a sale_landed_costs module
This module is an adaptation of the purchase_
To post a comment you must log in.
Revision history for this message

Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
review:
Needs Fixing
(code review, no tests)
Revision history for this message

Pedro Manuel Baeza (pedro.baeza) wrote : | # |
This project is now hosted on https:/
review:
Needs Resubmitting
Unmerged revisions
- 33. By David Cormier
-
[FIX] proper attribution
- 32. By David Cormier
-
[NEW] Add sale landed costs
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'sale_landed_costs' |
2 | === added file 'sale_landed_costs/__init__.py' |
3 | --- sale_landed_costs/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ sale_landed_costs/__init__.py 2014-02-10 20:32:58 +0000 |
5 | @@ -0,0 +1,26 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
11 | +# Copyright (C) 2010-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
12 | +# |
13 | +# This program is free software: you can redistribute it and/or modify |
14 | +# it under the terms of the GNU Affero General Public License as |
15 | +# published by the Free Software Foundation, either version 3 of the |
16 | +# License, or (at your option) any later version. |
17 | +# |
18 | +# This program is distributed in the hope that it will be useful, |
19 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | +# GNU Affero General Public License for more details. |
22 | +# |
23 | +# You should have received a copy of the GNU Affero General Public License |
24 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | +# |
26 | +############################################################################## |
27 | + |
28 | +import sale |
29 | + |
30 | + |
31 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
32 | |
33 | === added file 'sale_landed_costs/__openerp__.py' |
34 | --- sale_landed_costs/__openerp__.py 1970-01-01 00:00:00 +0000 |
35 | +++ sale_landed_costs/__openerp__.py 2014-02-10 20:32:58 +0000 |
36 | @@ -0,0 +1,47 @@ |
37 | +# -*- coding: utf-8 -*- |
38 | +############################################################################## |
39 | +# |
40 | +# OpenERP, Open Source Management Solution |
41 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
42 | +# Copyright (C) 2010-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
43 | +# |
44 | +# This program is free software: you can redistribute it and/or modify |
45 | +# it under the terms of the GNU Affero General Public License as |
46 | +# published by the Free Software Foundation, either version 3 of the |
47 | +# License, or (at your option) any later version. |
48 | +# |
49 | +# This program is distributed in the hope that it will be useful, |
50 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
51 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
52 | +# GNU Affero General Public License for more details. |
53 | +# |
54 | +# You should have received a copy of the GNU Affero General Public License |
55 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
56 | +# |
57 | +############################################################################## |
58 | + |
59 | + |
60 | +{ |
61 | + 'name': 'Sale Order Landed Costs', |
62 | + 'version': '1.0', |
63 | + 'author': 'Camptocamp Austria', |
64 | + 'maintainer': 'Savoir-faire Linux', |
65 | + 'website': 'http://www.savoirfairelinux.com', |
66 | + 'category': 'Warehouse Management', |
67 | + 'description': """\ |
68 | +This module add the possibility to include landed costs in the average price computation of Sale Orders. |
69 | + |
70 | + Contributors: |
71 | + Sandy Carter <sandy.carter@savoirfairelinux.com> |
72 | + David Cormier <david.cormier@savoirfairelinux.com> |
73 | + |
74 | +""", |
75 | + 'depends': ['sale', 'purchase_landed_costs'], |
76 | + 'external_dependencies': {}, |
77 | + 'data': ['sale_view.xml'], |
78 | + 'demo': [], |
79 | + 'test': [], |
80 | + 'installable': True, |
81 | + 'active': False, |
82 | +} |
83 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
84 | |
85 | === added file 'sale_landed_costs/sale.py' |
86 | --- sale_landed_costs/sale.py 1970-01-01 00:00:00 +0000 |
87 | +++ sale_landed_costs/sale.py 2014-02-10 20:32:58 +0000 |
88 | @@ -0,0 +1,188 @@ |
89 | +# -*- coding: utf-8 -*- |
90 | +############################################################################## |
91 | +# |
92 | +# OpenERP, Open Source Management Solution |
93 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
94 | +# Copyright (C) 2010-2012 Camptocamp Austria (<http://www.camptocamp.at>) |
95 | +# |
96 | +# This program is free software: you can redistribute it and/or modify |
97 | +# it under the terms of the GNU Affero General Public License as |
98 | +# published by the Free Software Foundation, either version 3 of the |
99 | +# License, or (at your option) any later version. |
100 | +# |
101 | +# This program is distributed in the hope that it will be useful, |
102 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
103 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
104 | +# GNU Affero General Public License for more details. |
105 | +# |
106 | +# You should have received a copy of the GNU Affero General Public License |
107 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
108 | +# |
109 | +############################################################################## |
110 | + |
111 | +from openerp.osv import orm, fields |
112 | +from openerp import netsvc |
113 | +import openerp.addons.decimal_precision as dp |
114 | + |
115 | + |
116 | +class landed_cost_position(orm.Model): |
117 | + """Adding link to sale order and sale order lines""" |
118 | + _inherit = "landed.cost.position" |
119 | + _columns = { |
120 | + 'sale_order_line_id': fields.many2one('sale.order.line', 'Sale Order Line'), |
121 | + 'sale_order_id': fields.many2one('sale.order', 'Sale Order'), |
122 | + } |
123 | + |
124 | + |
125 | +class sale_order_line(orm.Model): |
126 | + """Adding landing costs fields""" |
127 | + _inherit = "sale.order.line" |
128 | + |
129 | + def _landing_cost(self, cr, uid, ids, name, args, context): |
130 | + """Calculate landing costs from value costs and amount costs""" |
131 | + ret = {} |
132 | + for line in self.browse(cr, uid, ids): |
133 | + ret[line.id] = sum(costs.amount if costs.price_type == 'value' else costs.amount * line.product_uom_qty |
134 | + for costs in line.landed_cost_line_ids) |
135 | + return ret |
136 | + |
137 | + def _landing_cost_order(self, cr, uid, ids, name, args, context): |
138 | + """Calculate landed costs from Absolute values and Per Quantity values""" |
139 | + ret = {} |
140 | + for line in self.browse(cr, uid, ids): |
141 | + landed_costs = 0.0 |
142 | + if line.order_id.landed_cost_line_ids: |
143 | + try: |
144 | + landed_costs = ( |
145 | + line.order_id.landed_cost_base_value/line.order_id.amount_total * line.price_subtotal + |
146 | + line.order_id.landed_cost_base_quantity/line.order_id.quantity_total * line.product_uom_qty) |
147 | + except ZeroDivisionError: |
148 | + landed_costs = 0.0 |
149 | + ret[line.id] = landed_costs |
150 | + return ret |
151 | + |
152 | + def _landed_cost(self, cr, uid, ids, name, args, context): |
153 | + """Calculate total landed cost (regular price + landing costs)""" |
154 | + ret = {} |
155 | + for line in self.browse(cr, uid, ids): |
156 | + ret[line.id] = line.price_subtotal + line.landing_costs + line.landing_costs_order |
157 | + return ret |
158 | + |
159 | + _columns = { |
160 | + 'landed_cost_line_ids': fields.one2many('landed.cost.position', 'sale_order_line_id', 'Landed Costs Positions'), |
161 | + 'landing_costs': fields.function(_landing_cost, |
162 | + digits_compute=dp.get_precision('Account'), |
163 | + string='Landing Costs'), |
164 | + 'landing_costs_order': fields.function(_landing_cost_order, |
165 | + digits_compute=dp.get_precision('Account'), |
166 | + string='Landing Costs from Order'), |
167 | + 'landed_costs': fields.function(_landed_cost, |
168 | + digits_compute=dp.get_precision('Account'), |
169 | + string='Landed Costs'), |
170 | + } |
171 | + |
172 | + |
173 | +class sale_order(orm.Model): |
174 | + """Adding landing costs fields as well as total""" |
175 | + _inherit = "sale.order" |
176 | + |
177 | + def _landed_cost_base_value(self, cr, uid, ids, name, args, context): |
178 | + """Calculate total of costs of price type 'value'""" |
179 | + ret = {} |
180 | + for line in self.browse(cr, uid, ids): |
181 | + ret[line.id] = sum(costs.amount for costs in line.landed_cost_line_ids if costs.price_type == 'value') |
182 | + return ret |
183 | + |
184 | + def _landed_cost_base_quantity(self, cr, uid, ids, name, args, context): |
185 | + """Calculate total of costs of price type 'per_unit'""" |
186 | + ret = {} |
187 | + for line in self.browse(cr, uid, ids): |
188 | + ret[line.id] = sum(costs.amount for costs in line.landed_cost_line_ids if costs.price_type == 'per_unit') |
189 | + return ret |
190 | + |
191 | + def _quantity_total(self, cr, uid, ids, name, args, context): |
192 | + """Calculate total product quantity from sale order lines """ |
193 | + ret = {} |
194 | + for line in self.browse(cr, uid, ids): |
195 | + ret[line.id] = sum(sol.product_uom_qty for sol in line.order_line if sol.product_uom_qty > 0.0) |
196 | + return ret |
197 | + |
198 | + def _landed_cost(self, cr, uid, ids, name, args, context): |
199 | + ret = {} |
200 | + for line in self.browse(cr, uid, ids): |
201 | + ret[line.id] = (line.landing_cost_lines + line.landed_cost_base_value + line.landed_cost_base_quantity + |
202 | + line.amount_untaxed) |
203 | + return ret |
204 | + |
205 | + def _landing_cost_lines(self, cr, uid, ids, name, args, context): |
206 | + """Calculate total landed costs from sale order lines """ |
207 | + ret = {} |
208 | + for line in self.browse(cr, uid, ids): |
209 | + ret[line.id] = sum(sol.landing_costs for sol in line.order_line if sol.product_uom_qty > 0.0) |
210 | + return ret |
211 | + |
212 | + _columns = { |
213 | + 'landed_cost_line_ids': fields.one2many('landed.cost.position', 'sale_order_id', 'Landed Costs'), |
214 | + 'landed_cost_base_value': fields.function(_landed_cost_base_value, |
215 | + digits_compute=dp.get_precision('Account'), |
216 | + string='Landed Costs Base Value'), |
217 | + 'landed_cost_base_quantity': fields.function(_landed_cost_base_quantity, |
218 | + digits_compute=dp.get_precision('Account'), |
219 | + string='Landed Costs Base Quantity'), |
220 | + 'landing_cost_lines': fields.function(_landing_cost_lines, |
221 | + digits_compute=dp.get_precision('Account'), |
222 | + string='Landing Cost Lines'), |
223 | + 'landed_cost': fields.function(_landed_cost, |
224 | + digits_compute=dp.get_precision('Account'), |
225 | + string='Landed Costs Total Untaxed'), |
226 | + 'quantity_total': fields.function(_quantity_total, |
227 | + digits_compute=dp.get_precision('Product UoM'), |
228 | + string='Total Quantity'), |
229 | + } |
230 | + |
231 | + def _get_product_account_expense_id(self, product): |
232 | + """ |
233 | + Returns the product's account expense id if present |
234 | + or it's parent categories account expense id otherwise |
235 | + """ |
236 | + if product.property_account_expense.id: |
237 | + return product.property_account_expense.id |
238 | + return product.categ_id.property_account_expense_categ.id |
239 | + |
240 | + def _create_pickings(self, cr, uid, order, context=None): |
241 | + |
242 | + invoice_obj = self.pool.get('account.invoice') |
243 | + invoice_line_obj = self.pool.get('account.invoice.line') |
244 | + journal_obj = self.pool.get('account.journal') |
245 | + journal_ids = journal_obj.search(cr, uid, [('type', '=', 'purchase'), |
246 | + ('company_id', '=', order.company_id.id)], |
247 | + limit=1) |
248 | + for order_cost in order.landed_cost_line_ids: |
249 | + vals_inv = { |
250 | + 'partner_id': order_cost.partner_id.id, |
251 | + 'currency_id': order_cost.currency_id.id or order.company_id.currency_id.id, |
252 | + 'account_id': order_cost.partner_id.property_account_payable.id, |
253 | + 'type': 'in_invoice', |
254 | + 'origin': order.name, |
255 | + 'fiscal_position': (order.partner_id.property_account_position and |
256 | + order.partner_id.property_account_position.id or |
257 | + False), |
258 | + 'company_id': order.company_id.id, |
259 | + 'journal_id': len(journal_ids) and journal_ids[0] or False |
260 | + } |
261 | + inv_id = invoice_obj.create(cr, uid, vals_inv, context=None) |
262 | + vals_line = { |
263 | + 'product_id': order_cost.product_id.id, |
264 | + 'name': order_cost.product_id.name, |
265 | + 'account_id': self._get_product_account_expense_id(order_cost.product_id), |
266 | + 'partner_id': order_cost.partner_id.id, |
267 | + 'invoice_id': inv_id, |
268 | + 'price_unit': order_cost.amount, |
269 | + 'invoice_line_tax_id': [(6, 0, [x.id for x in order_cost.product_id.supplier_taxes_id])] |
270 | + } |
271 | + invoice_line_obj.create(cr, uid, vals_line, context=None) |
272 | + |
273 | + def action_done(self, cr, uid, ids, context=None): |
274 | + for order in self.browse(cr, uid, ids): |
275 | + self._create_pickings(cr, uid, order, context=context) |
276 | + return super(sale_order, self).action_done(cr, uid, ids, context=context) |
277 | |
278 | === added file 'sale_landed_costs/sale_view.xml' |
279 | --- sale_landed_costs/sale_view.xml 1970-01-01 00:00:00 +0000 |
280 | +++ sale_landed_costs/sale_view.xml 2014-02-10 20:32:58 +0000 |
281 | @@ -0,0 +1,40 @@ |
282 | +<?xml version="1.0" encoding="UTF-8"?> |
283 | +<openerp> |
284 | + <data> |
285 | + <!-- Landed costs Sale Form--> |
286 | + <record model="ir.ui.view" id="sale_order_landed_cost_view"> |
287 | + <field name="name">sale.order.landed.cost.form.view</field> |
288 | + <field name="model">sale.order</field> |
289 | + <field name="inherit_id" ref="sale.view_order_form"/> |
290 | + <field name="arch" type="xml"> |
291 | + <data> |
292 | + <field name="price_subtotal" position="after"> |
293 | + <field name="landing_costs" invisible="1"/> |
294 | + <field name="landing_costs_order"/> |
295 | + <field name="landed_costs"/> |
296 | + </field> |
297 | + <notebook position="inside"> |
298 | + <page string="Landing Costs" attrs="{'readonly':[('state','=','done')]}"> |
299 | + <group> |
300 | + <field name="quantity_total"/> |
301 | + <field name="landed_cost_base_quantity" /> |
302 | + <field name="landed_cost_base_value" /> |
303 | + </group> |
304 | + <group colspan="2" col="2"> |
305 | + <field name="landing_cost_lines"/> |
306 | + <field name="landed_cost"/> |
307 | + </group> |
308 | + |
309 | + <field |
310 | + name="landed_cost_line_ids" |
311 | + colspan="4" |
312 | + nolabel="1" |
313 | + widget="one2many_list" |
314 | + attrs="{'readonly': [('state', 'in', ('approved', 'done'))]}" /> |
315 | + </page> |
316 | + </notebook> |
317 | + </data> |
318 | + </field> |
319 | + </record> |
320 | + </data> |
321 | +</openerp> |
Hi David,
Thanks for porting this module. A few remarks:
* Would you please consider using the BZR extractor (https:/ /launchpad. net/bazaar- extractor) to put this module in that branch ? This will then keep the commite message insead of having just one commit that add the module. This seems fair on order to keep the author's work.
* Then, it deserve a bit of PEP8 formatting
Regards,
Joël