Merge lp:~elbati/purchase-wkfl/adding_purchase_delivery_term_7 into lp:~purchase-core-editors/purchase-wkfl/7.0

Proposed by Lorenzo Battistini
Status: Merged
Approved by: Guewen Baconnier @ Camptocamp
Approved revision: 20
Merged at revision: 11
Proposed branch: lp:~elbati/purchase-wkfl/adding_purchase_delivery_term_7
Merge into: lp:~purchase-core-editors/purchase-wkfl/7.0
Diff against target: 584 lines (+519/-0)
12 files modified
purchase_delivery_term/AUTHORS.txt (+1/-0)
purchase_delivery_term/__init__.py (+22/-0)
purchase_delivery_term/__openerp__.py (+42/-0)
purchase_delivery_term/purchase.py (+208/-0)
purchase_delivery_term/purchase_view.xml (+79/-0)
purchase_delivery_term/security/ir.model.access.csv (+10/-0)
purchase_multi_picking/AUTHORS.txt (+1/-0)
purchase_multi_picking/__init__.py (+22/-0)
purchase_multi_picking/__openerp__.py (+41/-0)
purchase_multi_picking/purchase.py (+65/-0)
purchase_multi_picking/purchase_view.xml (+23/-0)
purchase_multi_picking/security/ir.model.access.csv (+5/-0)
To merge this branch: bzr merge lp:~elbati/purchase-wkfl/adding_purchase_delivery_term_7
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp code review, no test Approve
Alexandre Fayolle - camptocamp code review, no test Approve
Review via email: mp+147608@code.launchpad.net

Description of the change

purchase_multi_picking
----------------------
This module allows to generate several pickings from the same purchase order.
You just have to indicate which order lines have to be grouped in the same picking. When confirming the order, for each group a picking is generated.

purchase_delivery_term
----------------------
Delivery term for purchase orders.
You can configure delivery terms specifying the quantity percentage and the delay for every term line.
You can then associate the term to the 'main' order line and generate the 'detailed' order lines which in turn will generate several pickings according to delivery term (thanks to 'purchase_multi_picking' module).

To post a comment you must log in.
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

l. 67: too long, needs wrapping

l73-74: init_xml and data_xml should be merged into 'data'. 'demo_xml' is now just 'demo'

In the addon code, could you consider using orm.Model (resp orm.TransientModel) as the base class rather than osv.osv (resp. osv.osv_memory). In the same vein, it is no longer necessary to instantiate the model class, so you can get rid of these.

l. 191: 'product_qty': lambda *a: 1.0 can be simplified with just "product_qty': 1.0

l202 too long please wrap. Lots of lines in there are over 80 cols. I won't stop merging solely because of this but this one really mandates wrapping.

l. 232: when using "%s" format, str() is implicitely called on the value. OTOH, maybe you want to use %d in the template string as len() is garanteed to return an integer.

l. 237: you could write this loop as:

l512: you can get rid of the \ by using " as string delimiter
for group_index, term_line in enumerate(master_line.delivery_term_id.line_ids)

This removes the need to initialize group_index to 0 and to increment it in the loop.

l. 526: you completely control the creation of lines_by_group directory, so there is no risk of having None or False values in this dictionary. Therefore you should use the "in" keyword to test the presence of a key in the dictionary, and not the get() method. I'd also suggest rewriting the block starting at line 525 to remove the code duplication between both branches of the tesT.

review: Needs Fixing (code review, no test)
12. By Lorenzo Battistini

[FIX] classes and __openerp__

13. By Lorenzo Battistini

[FIX] orm.Model and lines length

14. By Lorenzo Battistini

[IMP] from . import

15. By Lorenzo Battistini

[FIX] %d

16. By Lorenzo Battistini

[IMP] lines_by_group

17. By Lorenzo Battistini

[IMP] ._create_pickings

18. By Lorenzo Battistini

[FIX] lambda

19. By Lorenzo Battistini

[IMP] enumerate

20. By Lorenzo Battistini

[FIX] string delimiter

Revision history for this message
Lorenzo Battistini (elbati) wrote :

Hello Alexandre,
I made the changes.

Thanks

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) :
review: Approve (code review, no test)
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

LGTM

review: Approve (code review, no test)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'purchase_delivery_term'
2=== added file 'purchase_delivery_term/AUTHORS.txt'
3--- purchase_delivery_term/AUTHORS.txt 1970-01-01 00:00:00 +0000
4+++ purchase_delivery_term/AUTHORS.txt 2013-02-20 07:57:20 +0000
5@@ -0,0 +1,1 @@
6+Lorenzo Battistini <lorenzo.battistini@agilebg.com>
7
8=== added file 'purchase_delivery_term/__init__.py'
9--- purchase_delivery_term/__init__.py 1970-01-01 00:00:00 +0000
10+++ purchase_delivery_term/__init__.py 2013-02-20 07:57:20 +0000
11@@ -0,0 +1,22 @@
12+# -*- coding: utf-8 -*-
13+##############################################################################
14+#
15+# Copyright (C) 2012-2013 Agile Business Group sagl
16+# (<http://www.agilebg.com>)
17+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
18+#
19+# This program is free software: you can redistribute it and/or modify
20+# it under the terms of the GNU Affero General Public License as published
21+# by the Free Software Foundation, either version 3 of the License, or
22+# (at your option) any later version.
23+#
24+# This program is distributed in the hope that it will be useful,
25+# but WITHOUT ANY WARRANTY; without even the implied warranty of
26+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+# GNU Affero General Public License for more details.
28+#
29+# You should have received a copy of the GNU Affero General Public License
30+# along with this program. If not, see <http://www.gnu.org/licenses/>.
31+#
32+##############################################################################
33+from . import purchase
34
35=== added file 'purchase_delivery_term/__openerp__.py'
36--- purchase_delivery_term/__openerp__.py 1970-01-01 00:00:00 +0000
37+++ purchase_delivery_term/__openerp__.py 2013-02-20 07:57:20 +0000
38@@ -0,0 +1,42 @@
39+# -*- coding: utf-8 -*-
40+##############################################################################
41+#
42+# Copyright (C) 2012-2013 Agile Business Group sagl
43+# (<http://www.agilebg.com>)
44+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
45+#
46+# This program is free software: you can redistribute it and/or modify
47+# it under the terms of the GNU Affero General Public License as published
48+# by the Free Software Foundation, either version 3 of the License, or
49+# (at your option) any later version.
50+#
51+# This program is distributed in the hope that it will be useful,
52+# but WITHOUT ANY WARRANTY; without even the implied warranty of
53+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54+# GNU Affero General Public License for more details.
55+#
56+# You should have received a copy of the GNU Affero General Public License
57+# along with this program. If not, see <http://www.gnu.org/licenses/>.
58+#
59+##############################################################################
60+{
61+ 'name': "Purchase delivery terms",
62+ 'version': '0.2',
63+ 'category': 'Purchase Management',
64+ 'description': """
65+Delivery term for purchase orders.
66+You can configure delivery terms specifying the quantity percentage and the delay for every term line.
67+You can then associate the term to the 'main' order line and generate the 'detailed' order lines which in turn will generate several pickings according to delivery term (thanks to 'purchase_multi_picking' module).
68+""",
69+ 'author': 'Agile Business Group',
70+ 'website': 'http://www.agilebg.com',
71+ 'license': 'AGPL-3',
72+ "depends" : ['purchase_multi_picking'],
73+ "data" : [
74+ 'purchase_view.xml',
75+ 'security/ir.model.access.csv',
76+ ],
77+ "demo" : [],
78+ "active": False,
79+ "installable": True
80+}
81
82=== added directory 'purchase_delivery_term/i18n'
83=== added file 'purchase_delivery_term/purchase.py'
84--- purchase_delivery_term/purchase.py 1970-01-01 00:00:00 +0000
85+++ purchase_delivery_term/purchase.py 2013-02-20 07:57:20 +0000
86@@ -0,0 +1,208 @@
87+# -*- coding: utf-8 -*-
88+##############################################################################
89+#
90+# Copyright (C) 2012-2013 Agile Business Group sagl
91+# (<http://www.agilebg.com>)
92+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
93+#
94+# This program is free software: you can redistribute it and/or modify
95+# it under the terms of the GNU Affero General Public License as published
96+# by the Free Software Foundation, either version 3 of the License, or
97+# (at your option) any later version.
98+#
99+# This program is distributed in the hope that it will be useful,
100+# but WITHOUT ANY WARRANTY; without even the implied warranty of
101+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
102+# GNU Affero General Public License for more details.
103+#
104+# You should have received a copy of the GNU Affero General Public License
105+# along with this program. If not, see <http://www.gnu.org/licenses/>.
106+#
107+##############################################################################
108+
109+from openerp.osv import fields, orm
110+from openerp.tools.translate import _
111+import openerp.addons.decimal_precision as dp
112+from datetime import datetime, timedelta
113+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
114+
115+class purchase_delivery_term(orm.Model):
116+ _name = 'purchase.delivery.term'
117+ _columns = {
118+ 'name': fields.char('Name', size=64, required=True),
119+ 'line_ids': fields.one2many('purchase.delivery.term.line', 'term_id', 'Lines', required=True),
120+ 'company_id': fields.many2one('res.company','Company',required=True,select=1),
121+ }
122+ _defaults = {
123+ 'company_id': lambda self,cr,uid,c: self.pool.get(
124+ 'res.company')._company_default_get(cr, uid, 'purchase.delivery.term', context=c),
125+ }
126+
127+ def is_total_percentage_correct(self, cr, uid, term_ids, context=None):
128+ for term in self.browse(cr, uid, term_ids, context=context):
129+ total = 0.0
130+ for line in term.line_ids:
131+ total += line.quantity_perc
132+ if total != 1 :
133+ return False
134+ return True
135+
136+
137+class purchase_delivery_term_line(orm.Model):
138+
139+ _name = 'purchase.delivery.term.line'
140+ _rec_name = 'term_id'
141+ _columns = {
142+ 'term_id': fields.many2one('purchase.delivery.term', 'Term'),
143+ 'quantity_perc': fields.float('Quantity percentage',
144+ required=True, help="For 20% set '0.2'"),
145+ 'delay': fields.float('Delivery Lead Time', required=True,
146+ help="Number of days between the order confirmation and the shipping of the products from the supplier"),
147+ }
148+
149+class purchase_order_line_master(orm.Model):
150+
151+ def onchange_product_id(self, cr, uid, ids, pricelist_id, product_id, qty, uom_id,
152+ partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
153+ name=False, price_unit=False, context=None):
154+ return self.pool.get('purchase.order.line').onchange_product_id(
155+ cr, uid, ids, pricelist_id, product_id, qty, uom_id,
156+ partner_id, date_order=date_order, fiscal_position_id=fiscal_position_id, date_planned=date_planned,
157+ name=name, price_unit=price_unit, context=context)
158+
159+ def onchange_product_uom(self, cr, uid, ids, pricelist_id, product_id, qty, uom_id,
160+ partner_id, date_order=False, fiscal_position_id=False, date_planned=False,
161+ name=False, price_unit=False, context=None):
162+ return self.pool.get('purchase.order.line').onchange_product_uom(cr, uid, ids, pricelist_id, product_id, qty, uom_id,
163+ partner_id, date_order=date_order, fiscal_position_id=fiscal_position_id, date_planned=date_planned,
164+ name=name, price_unit=price_unit, context=context)
165+
166+ def _amount_line(self, cr, uid, ids, prop, arg, context=None):
167+ res = {}
168+ cur_obj=self.pool.get('res.currency')
169+ tax_obj = self.pool.get('account.tax')
170+ for line in self.browse(cr, uid, ids, context=context):
171+ taxes = tax_obj.compute_all(cr, uid, line.taxes_id, line.price_unit, line.product_qty)
172+ cur = line.order_id.pricelist_id.currency_id
173+ res[line.id] = cur_obj.round(cr, uid, cur, taxes['total'])
174+ return res
175+
176+ _name = 'purchase.order.line.master'
177+ _columns = {
178+ 'order_id': fields.many2one('purchase.order', 'Order Reference',
179+ select=True, required=True, ondelete='cascade'),
180+ 'delivery_term_id': fields.many2one('purchase.delivery.term',
181+ 'Delivery term', required=True),
182+ 'name': fields.char('Description', size=256, required=True),
183+ 'product_id': fields.many2one('product.product', 'Product',
184+ domain=[('purchase_ok','=',True)], change_default=True),
185+ 'price_unit': fields.float('Unit Price', required=True,
186+ digits_compute= dp.get_precision('Purchase Price')),
187+ 'price_subtotal': fields.function(_amount_line, string='Subtotal',
188+ digits_compute= dp.get_precision('Purchase Price')),
189+ 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product UoM'), required=True),
190+ 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True),
191+ 'order_line_ids': fields.one2many('purchase.order.line',
192+ 'master_line_id', 'Detailed lines'),
193+ 'taxes_id': fields.many2many('account.tax', 'purchase_master_order_line_tax', 'ord_line_id', 'tax_id', 'Taxes'),
194+ 'date_planned': fields.date('Scheduled Date', required=True, select=True),
195+ }
196+ _defaults = {
197+ 'product_qty': 1.0,
198+ }
199+
200+ def _prepare_order_line(self, cr, uid, term_line, master_line, group_index=0, context=None):
201+ order_line_pool = self.pool.get('purchase.order.line')
202+ group_pool = self.pool.get('purchase.order.line.group')
203+ group_ids = group_pool.search(cr, uid, [])
204+ product_qty = master_line.product_qty * term_line.quantity_perc
205+ order_line_vals = {}
206+ on_change_res = order_line_pool.onchange_product_id(cr, uid, [],
207+ master_line.order_id.pricelist_id.id, master_line.product_id.id,
208+ master_line.product_qty, master_line.product_uom.id,
209+ master_line.order_id.partner_id.id, date_order=master_line.order_id.date_order,
210+ fiscal_position_id=master_line.order_id.fiscal_position.id, date_planned=master_line.date_planned,
211+ name=master_line.name, price_unit=master_line.price_unit, context=context)
212+ order_line_vals.update(on_change_res['value'])
213+ date_planned = datetime.strptime(master_line.date_planned,
214+ DEFAULT_SERVER_DATE_FORMAT) + timedelta(term_line.delay)
215+ order_line_vals.update({
216+ 'order_id': master_line.order_id.id,
217+ 'name': master_line.name,
218+ 'price_unit': master_line.price_unit,
219+ 'product_qty': product_qty,
220+ 'product_uom': master_line.product_uom.id,
221+ 'product_id': master_line.product_id and master_line.product_id.id or False,
222+ 'master_line_id': master_line.id,
223+ 'date_planned': date_planned,
224+ 'picking_group_id': group_ids[group_index],
225+ 'taxes_id': [(6,0, [tax.id for tax in master_line.taxes_id])],
226+ })
227+ return order_line_vals
228+
229+ def generate_detailed_lines(self, cr, uid, ids, context=None):
230+ group_pool = self.pool.get('purchase.order.line.group')
231+ order_line_pool = self.pool.get('purchase.order.line')
232+ group_ids = group_pool.search(cr, uid, [])
233+ for master_line in self.browse(cr, uid, ids):
234+ if master_line.order_line_ids:
235+ raise osv.except_osv(_('Error'),
236+ _("Detailed lines generated yet (for master line '%s'). Remove them first") % master_line.name)
237+ if len(master_line.delivery_term_id.line_ids) > len(group_ids):
238+ raise osv.except_osv(_('Error'),
239+ _("Delivery term lines are %d. Order line groups are %d. Please create more groups")
240+ % (len(master_line.delivery_term_id.line_ids), len(group_ids)))
241+ if not master_line.delivery_term_id.is_total_percentage_correct():
242+ raise osv.except_osv(_('Error'),
243+ _("Total percentage of delivery term %s is not equal to 1") % master_line.delivery_term_id.name)
244+ for group_index, term_line in enumerate(master_line.delivery_term_id.line_ids):
245+ order_line_vals = self._prepare_order_line(cr, uid, term_line,
246+ master_line, group_index=group_index, context=context)
247+ order_line_pool.create(cr, uid, order_line_vals, context=context)
248+ return True
249+
250+ def copy_data(self, cr, uid, id, default=None, context=None):
251+ if not default:
252+ default = {}
253+ default.update({
254+ 'order_line_ids': [],
255+ })
256+ return super(purchase_order_line_master, self).copy_data(
257+ cr, uid, id, default, context=context)
258+
259+
260+class purchase_order_line(orm.Model):
261+ _inherit = 'purchase.order.line'
262+ _columns = {
263+ 'master_line_id': fields.many2one('purchase.order.line.master', 'Master Line'),
264+ }
265+
266+ def copy_data(self, cr, uid, id, default=None, context=None):
267+ if not default:
268+ default = {}
269+ default.update({'master_line_id': False})
270+ return super(purchase_order_line, self).copy_data(cr, uid, id, default, context=context)
271+
272+
273+class purchase_order(orm.Model):
274+ _inherit = 'purchase.order'
275+ _columns = {
276+ 'master_order_line': fields.one2many('purchase.order.line.master',
277+ 'order_id', 'Master Order Lines', readonly=True,
278+ states={'draft': [('readonly', False)]}),
279+ }
280+
281+ def copy(self, cr, uid, id, default=None, context=None):
282+ if not default:
283+ default = {}
284+ default.update({
285+ 'order_line': [],
286+ })
287+ return super(purchase_order, self).copy(cr, uid, id, default, context=context)
288+
289+ def generate_detailed_lines(self, cr, uid, ids, context=None):
290+ for order in self.browse(cr, uid, ids, context):
291+ for master_line in order.master_order_line:
292+ master_line.generate_detailed_lines()
293+ return True
294+
295
296=== added file 'purchase_delivery_term/purchase_view.xml'
297--- purchase_delivery_term/purchase_view.xml 1970-01-01 00:00:00 +0000
298+++ purchase_delivery_term/purchase_view.xml 2013-02-20 07:57:20 +0000
299@@ -0,0 +1,79 @@
300+<openerp>
301+ <data>
302+ <record id="purchase_delivery_term_form" model="ir.ui.view">
303+ <field name="name">purchase.delivery.term.form</field>
304+ <field name="model">purchase.delivery.term</field>
305+ <field name="arch" type="xml">
306+ <form string="Delivery term">
307+ <field name="name" select="1"/>
308+ <field name="line_ids" string="Term Lines" colspan="4" nolabel="1">
309+ <form>
310+ <field name="quantity_perc"></field>
311+ <field name="delay"></field>
312+ </form>
313+ <tree editable="bottom">
314+ <field name="quantity_perc"></field>
315+ <field name="delay"></field>
316+ </tree>
317+ </field>
318+ </form>
319+ </field>
320+ </record>
321+ <record id="action_delivery_term_form" model="ir.actions.act_window">
322+ <field name="name">Delivery Terms</field>
323+ <field name="type">ir.actions.act_window</field>
324+ <field name="res_model">purchase.delivery.term</field>
325+ <field name="view_type">form</field>
326+ <field name="view_mode">tree,form</field>
327+ </record>
328+
329+ <menuitem action="action_delivery_term_form" id="menu_action_delivery_term_form" parent="purchase.menu_purchase_config_purchase" />
330+
331+ <record id="purchase_order_line_master_form" model="ir.ui.view">
332+ <field name="name">purchase_order_line_master_form</field>
333+ <field name="model">purchase.order.line.master</field>
334+ <field name="arch" type="xml">
335+ <form string="Master order line">
336+ <field name="product_id" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)" required="1"/>
337+ <field name="product_qty" on_change="onchange_product_id(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id,parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)"/>
338+ <field name="product_uom" on_change="onchange_product_uom(parent.pricelist_id,product_id,product_qty,product_uom,parent.partner_id, parent.date_order,parent.fiscal_position,date_planned,name,price_unit,context)"/>
339+ <newline></newline>
340+ <field name="name" colspan="4"/>
341+ <field name="date_planned" widget="date"/>
342+ <field name="price_unit" />
343+ <field name="delivery_term_id" />
344+ <separator colspan="4" string="Taxes"/>
345+ <field colspan="4" nolabel="1" name="taxes_id"
346+ domain="[('parent_id','=',False),('type_tax_use','!=','sale')]"/>
347+ </form>
348+ </field>
349+ </record>
350+ <record id="purchase_order_line_master_tree" model="ir.ui.view">
351+ <field name="name">purchase_order_line_master_tree</field>
352+ <field name="model">purchase.order.line.master</field>
353+ <field name="arch" type="xml">
354+ <tree string="Master order lines">
355+ <field name="date_planned" />
356+ <field name="name" />
357+ <field name="price_unit" />
358+ <field name="product_qty" />
359+ <field name="product_uom" />
360+ <field name="price_subtotal" />
361+ <field name="delivery_term_id" />
362+ </tree>
363+ </field>
364+ </record>
365+
366+ <record id="purchase_order_form" model="ir.ui.view">
367+ <field name="name">purchase.order.form</field>
368+ <field name="model">purchase.order</field>
369+ <field name="inherit_id" ref="purchase.purchase_order_form"></field>
370+ <field name="arch" type="xml">
371+ <field name="order_line" position="before">
372+ <field colspan="4" name="master_order_line" nolabel="1"></field>
373+ <button name="generate_detailed_lines" string="Generate detailed lines" icon="gtk-go-forward" type="object" colspan="2"/>
374+ </field>
375+ </field>
376+ </record>
377+ </data>
378+</openerp>
379
380=== added directory 'purchase_delivery_term/security'
381=== added file 'purchase_delivery_term/security/ir.model.access.csv'
382--- purchase_delivery_term/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
383+++ purchase_delivery_term/security/ir.model.access.csv 2013-02-20 07:57:20 +0000
384@@ -0,0 +1,10 @@
385+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
386+access_purchase_order_line_master,purchase.order.line_master user,model_purchase_order_line_master,purchase.group_purchase_user,1,1,1,1
387+access_purchase_order_line_master_stock_worker,purchase.order.line_master stock,model_purchase_order_line_master,stock.group_stock_user,1,0,0,0
388+access_purchase_order_line_master_manager,purchase.order.line_master manager,model_purchase_order_line_master,purchase.group_purchase_manager,1,1,1,1
389+access_purchase_delivery_term,purchase_delivery_term user,model_purchase_delivery_term,purchase.group_purchase_user,1,0,0,0
390+access_purchase_delivery_term_stock_worker,purchase_delivery_term stock,model_purchase_delivery_term,stock.group_stock_user,1,0,0,0
391+access_purchase_delivery_term_manager,purchase_delivery_term manager,model_purchase_delivery_term,purchase.group_purchase_manager,1,1,1,1
392+access_purchase_delivery_term_line,purchase_delivery_term_line user,model_purchase_delivery_term_line,purchase.group_purchase_user,1,0,0,0
393+access_purchase_delivery_term_line_stock_worker,purchase_delivery_term_line stock,model_purchase_delivery_term_line,stock.group_stock_user,1,0,0,0
394+access_purchase_delivery_term_line_manager,purchase_delivery_term_line manager,model_purchase_delivery_term_line,purchase.group_purchase_manager,1,1,1,1
395
396=== added directory 'purchase_multi_picking'
397=== added file 'purchase_multi_picking/AUTHORS.txt'
398--- purchase_multi_picking/AUTHORS.txt 1970-01-01 00:00:00 +0000
399+++ purchase_multi_picking/AUTHORS.txt 2013-02-20 07:57:20 +0000
400@@ -0,0 +1,1 @@
401+Lorenzo Battistini <lorenzo.battistini@agilebg.com>
402
403=== added file 'purchase_multi_picking/__init__.py'
404--- purchase_multi_picking/__init__.py 1970-01-01 00:00:00 +0000
405+++ purchase_multi_picking/__init__.py 2013-02-20 07:57:20 +0000
406@@ -0,0 +1,22 @@
407+# -*- coding: utf-8 -*-
408+##############################################################################
409+#
410+# Copyright (C) 2012-2013 Agile Business Group sagl
411+# (<http://www.agilebg.com>)
412+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
413+#
414+# This program is free software: you can redistribute it and/or modify
415+# it under the terms of the GNU Affero General Public License as published
416+# by the Free Software Foundation, either version 3 of the License, or
417+# (at your option) any later version.
418+#
419+# This program is distributed in the hope that it will be useful,
420+# but WITHOUT ANY WARRANTY; without even the implied warranty of
421+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
422+# GNU Affero General Public License for more details.
423+#
424+# You should have received a copy of the GNU Affero General Public License
425+# along with this program. If not, see <http://www.gnu.org/licenses/>.
426+#
427+##############################################################################
428+from . import purchase
429
430=== added file 'purchase_multi_picking/__openerp__.py'
431--- purchase_multi_picking/__openerp__.py 1970-01-01 00:00:00 +0000
432+++ purchase_multi_picking/__openerp__.py 2013-02-20 07:57:20 +0000
433@@ -0,0 +1,41 @@
434+# -*- coding: utf-8 -*-
435+##############################################################################
436+#
437+# Copyright (C) 2012-2013 Agile Business Group sagl
438+# (<http://www.agilebg.com>)
439+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
440+#
441+# This program is free software: you can redistribute it and/or modify
442+# it under the terms of the GNU Affero General Public License as published
443+# by the Free Software Foundation, either version 3 of the License, or
444+# (at your option) any later version.
445+#
446+# This program is distributed in the hope that it will be useful,
447+# but WITHOUT ANY WARRANTY; without even the implied warranty of
448+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
449+# GNU Affero General Public License for more details.
450+#
451+# You should have received a copy of the GNU Affero General Public License
452+# along with this program. If not, see <http://www.gnu.org/licenses/>.
453+#
454+##############################################################################
455+{
456+ 'name': "Multi Pickings from Purchase Orders",
457+ 'version': '0.2',
458+ 'category': 'Purchase Management',
459+ 'description': """
460+This module allows to generate several pickings from the same purchase order.
461+You just have to indicate which order lines have to be grouped in the same picking. When confirming the order, for each group a picking is generated.
462+""",
463+ 'author': 'Agile Business Group',
464+ 'website': 'http://www.agilebg.com',
465+ 'license': 'AGPL-3',
466+ "depends" : ['purchase', 'stock'],
467+ "data" : [
468+ 'purchase_view.xml',
469+ 'security/ir.model.access.csv',
470+ ],
471+ "demo" : [],
472+ "active": False,
473+ "installable": True
474+}
475
476=== added directory 'purchase_multi_picking/i18n'
477=== added file 'purchase_multi_picking/purchase.py'
478--- purchase_multi_picking/purchase.py 1970-01-01 00:00:00 +0000
479+++ purchase_multi_picking/purchase.py 2013-02-20 07:57:20 +0000
480@@ -0,0 +1,65 @@
481+# -*- coding: utf-8 -*-
482+##############################################################################
483+#
484+# Copyright (C) 2012-2013 Agile Business Group sagl
485+# (<http://www.agilebg.com>)
486+# Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
487+#
488+# This program is free software: you can redistribute it and/or modify
489+# it under the terms of the GNU Affero General Public License as published
490+# by the Free Software Foundation, either version 3 of the License, or
491+# (at your option) any later version.
492+#
493+# This program is distributed in the hope that it will be useful,
494+# but WITHOUT ANY WARRANTY; without even the implied warranty of
495+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
496+# GNU Affero General Public License for more details.
497+#
498+# You should have received a copy of the GNU Affero General Public License
499+# along with this program. If not, see <http://www.gnu.org/licenses/>.
500+#
501+##############################################################################
502+
503+from openerp.osv import fields, orm
504+
505+class purchase_order_line_group(orm.Model):
506+ _name = 'purchase.order.line.group'
507+ _columns = {
508+ 'name': fields.char('Group', size=64, required=True),
509+ 'company_id': fields.many2one('res.company','Company',required=True,select=1),
510+ }
511+ _defaults = {
512+ 'company_id': lambda self,cr,uid,c: self.pool.get(
513+ 'res.company')._company_default_get(cr, uid, 'purchase.order.line.group', context=c),
514+ }
515+
516+
517+class purchase_order_line(orm.Model):
518+ _inherit = 'purchase.order.line'
519+ _columns = {
520+ 'picking_group_id': fields.many2one('purchase.order.line.group',
521+ 'Group', help="This is used by 'multi-picking' to group order lines in one picking"),
522+ }
523+
524+
525+class purchase_order(orm.Model):
526+ _inherit = 'purchase.order'
527+
528+ def action_picking_create(self, cr, uid, ids, context=None):
529+ picking_pool = self.pool.get('stock.picking')
530+ picking_ids = []
531+ for order in self.browse(cr, uid, ids, context=context):
532+ lines_by_group = {}
533+ for line in order.order_line:
534+ group_id = line.picking_group_id.id if line.picking_group_id else 0
535+ lines_by_group.setdefault(group_id, []).append(line)
536+ for group in lines_by_group:
537+ if not group:
538+ picking_id = None
539+ else:
540+ picking_vals = super(purchase_order, self)._prepare_order_picking(cr, uid, order, context=context)
541+ picking_id = picking_pool.create(cr, uid, picking_vals, context=context)
542+ picking_ids.extend(super(purchase_order, self)._create_pickings(
543+ cr, uid, order, lines_by_group[group], picking_id, context=context))
544+ return picking_ids[0] if picking_ids else False # ?
545+
546
547=== added file 'purchase_multi_picking/purchase_view.xml'
548--- purchase_multi_picking/purchase_view.xml 1970-01-01 00:00:00 +0000
549+++ purchase_multi_picking/purchase_view.xml 2013-02-20 07:57:20 +0000
550@@ -0,0 +1,23 @@
551+<openerp>
552+ <data>
553+ <record id="purchase_order_line_form" model="ir.ui.view">
554+ <field name="name">purchase.order.line.form</field>
555+ <field name="model">purchase.order.line</field>
556+ <field name="inherit_id" ref="purchase.purchase_order_line_form"></field>
557+ <field name="arch" type="xml">
558+ <field name="account_analytic_id" position="after">
559+ <field name="picking_group_id"/>
560+ </field>
561+ </field>
562+ </record>
563+ <record id="action_purchase_order_line_group_form" model="ir.actions.act_window">
564+ <field name="name">Purchase order line Groups</field>
565+ <field name="type">ir.actions.act_window</field>
566+ <field name="res_model">purchase.order.line.group</field>
567+ <field name="view_type">form</field>
568+ <field name="view_mode">tree,form</field>
569+ </record>
570+
571+ <menuitem action="action_purchase_order_line_group_form" id="menu_action_purchase_order_line_group_form" parent="purchase.menu_purchase_config_purchase" />
572+ </data>
573+</openerp>
574
575=== added directory 'purchase_multi_picking/security'
576=== added file 'purchase_multi_picking/security/ir.model.access.csv'
577--- purchase_multi_picking/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
578+++ purchase_multi_picking/security/ir.model.access.csv 2013-02-20 07:57:20 +0000
579@@ -0,0 +1,5 @@
580+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
581+access_purchase_order_line_group,purchase.order.line_group user,model_purchase_order_line_group,purchase.group_purchase_user,1,1,1,1
582+access_purchase_order_line_group_manager,purchase.order.line_group manager,model_purchase_order_line_group,purchase.group_purchase_manager,1,0,0,0
583+access_purchase_order_line_group_stock_worker,purchase.order.line_group manager,model_purchase_order_line_group,stock.group_stock_user,1,0,0,0
584+access_purchase_order_line_group_manager,purchase.order.line_group manager,model_purchase_order_line_group,purchase.group_purchase_manager,1,1,1,1

Subscribers

People subscribed via source and target branches