Merge lp:~david-cormier-j/sale-wkfl/sale_landed_costs into lp:~sale-core-editors/sale-wkfl/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
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

Description of the change

Add a sale_landed_costs module

This module is an adaptation of the purchase_landed_costs (in c2c_rd_addons project) for sales

To post a comment you must log in.
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

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

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://github.com/OCA/sale-workflow. Please move your proposal there. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

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>

Subscribers

People subscribed via source and target branches