Merge lp:~elbati/purchase-wkfl/adding_purchase_delivery_term_7 into lp:~purchase-core-editors/purchase-wkfl/7.0
- adding_purchase_delivery_term_7
- Merge into 7.0
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 |
Related bugs: |
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 |
Commit message
Description of the change
purchase_
-------
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 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_
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
- 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
Lorenzo Battistini (elbati) wrote : | # |
Hello Alexandre,
I made the changes.
Thanks
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) : | # |
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
LGTM
Preview Diff
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 |
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 master_ line.delivery_ term_id. line_ids)
for group_index, term_line in enumerate(
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.