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