Merge lp:~camptocamp/sale-wkfl/product_procurement_type into lp:~sale-core-editors/sale-wkfl/7.0
- product_procurement_type
- Merge into 7.0
Status: | Superseded |
---|---|
Proposed branch: | lp:~camptocamp/sale-wkfl/product_procurement_type |
Merge into: | lp:~sale-core-editors/sale-wkfl/7.0 |
Diff against target: |
682 lines (+614/-0) 12 files modified
product_procurement_type/__init__.py (+22/-0) product_procurement_type/__openerp__.py (+50/-0) product_procurement_type/migrations/7.0.0.1/post-migration.py (+38/-0) product_procurement_type/product.py (+115/-0) product_procurement_type/product_view.xml (+42/-0) product_procurement_type/test/test_onchange_procurement_type.yml (+56/-0) product_procurement_type_dropshipping/__init__.py (+22/-0) product_procurement_type_dropshipping/__openerp__.py (+46/-0) product_procurement_type_dropshipping/migrations/7.0.0.1/post-migration.py (+39/-0) product_procurement_type_dropshipping/product.py (+115/-0) product_procurement_type_dropshipping/product_view.xml (+17/-0) product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml (+52/-0) |
To merge this branch: | bzr merge lp:~camptocamp/sale-wkfl/product_procurement_type |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Fayolle - camptocamp | test | Needs Resubmitting | |
Stefan Rijnhart (Opener) | Approve | ||
Leonardo Pistone | code review | Approve | |
Joël Grand-Guillaume @ camptocamp | code review, no tests | Approve | |
Yannick Vaucher @ Camptocamp | code review, no tests | Approve | |
Review via email: mp+207638@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-03-03.
Commit message
Description of the change
Hello,
Here are two new addons who brings a simple field to manage several combinations
for two procurements fields : procure_method & supply_method :
First addon adds:
- Normal: MTS + buy
- Bill of Materials: MTO + produce
Second addon depends of sale_dropshipping addon and adds:
- Dropshipping: MTO + buy
I'm not sure if it's the right community branch to propose it, if you think about a better
place, let me know.
Regards,
Romain
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote : | # |
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
> LGTM for the code
>
> However, I don't think we have a proper branch to extend procurement.
>
> Shall we create one?
Since this is mainly affecting sales, I think this branch is correct.
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
need to set the value of the attribute from current product configuration when the module is installed.
setting status to "Work in progress" until this is resolved
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
> > LGTM for the code
> >
> > However, I don't think we have a proper branch to extend procurement.
> >
> > Shall we create one?
>
> Since this is mainly affecting sales, I think this branch is correct.
However I'm not sure this is not too customer specific to get in OCA. What do other think?
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
> need to set the value of the attribute from current product configuration when
> the module is installed.
>
> setting status to "Work in progress" until this is resolved
dons
- 42. By Alexandre Fayolle - camptocamp
-
[FIX] tests
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
LGTM, and I agree about adding this module here. Thanks
Leonardo Pistone (lepistone) wrote : | # |
I approve the code.
I share Alexandre's question if there is interest to have that in OCA. If not, being it approved technically, we can quickly merge it to a specific branch.
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
I don't see a problem having these modules here. About the code: there is a migration script, and I think its purpose is to update existing products upon installation of the module. However, I don't think the script is run at module installation time. Are you sure that this is the case?
Otherwise, you will need to put it in the model's _auto_init() method. It will run every time the module is upgraded (or installed) but that should not hurt. What you can do is check if column 'procurement_type' exists, call super() and run the migration queries only if the column did not exist when you checked. This indicates the installation of the module.
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
> I don't see a problem having these modules here. About the code: there is a
> migration script, and I think its purpose is to update existing products upon
> installation of the module. However, I don't think the script is run at module
> installation time. Are you sure that this is the case?
Yes it is run at installation time, I checked for this.
> Otherwise, you will need to put it in the model's _auto_init() method. It will
> run every time the module is upgraded (or installed) but that should not hurt.
> What you can do is check if column 'procurement_type' exists, call super() and
> run the migration queries only if the column did not exist when you checked.
> This indicates the installation of the module.
Not sure what the cleanest way is. Do you have an opinion about the cleanness of either options, and what we should aim for in OCA modules?
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Great, that means that we have the pre- and post-installation scripts that I always wanted after all! Much better solution than the _auto_init one.
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
I found an issue (possibly a framework bug) which prevents the new attribute from being imported from a CSV file.
- 43. By Alexandre Fayolle - camptocamp
-
[FIX] issue when importing products from CSV with procurement_type attribute
There is an issue in the framework (I think) which will break the previous
version of the code in CSV imports: the get_product_procurement_ type method (in
product_template) is called with an instance of product_product for self, and
the call to super() crashed. This redesign works around the issue by extracting
get_product_procurement_ type to a function and thus avoiding self altogether. - 44. By Alexandre Fayolle - camptocamp
-
[IMP] remove unnecessary code pointed out by lpistone
- 45. By Alexandre Fayolle - camptocamp
-
the migration scripts are not longer called on installation -> move to init method
- 46. By Romain Deheele - Camptocamp
-
[UPD] update manifest according to selection values
- 47. By Romain Deheele - Camptocamp
-
replace ValueError exception with False value that will be refused because a value is required : avoid ugly traceback
- 48. By Romain Deheele - Camptocamp
-
[UPD] update manifest description
Unmerged revisions
- 48. By Romain Deheele - Camptocamp
-
[UPD] update manifest description
- 47. By Romain Deheele - Camptocamp
-
replace ValueError exception with False value that will be refused because a value is required : avoid ugly traceback
- 46. By Romain Deheele - Camptocamp
-
[UPD] update manifest according to selection values
- 45. By Alexandre Fayolle - camptocamp
-
the migration scripts are not longer called on installation -> move to init method
- 44. By Alexandre Fayolle - camptocamp
-
[IMP] remove unnecessary code pointed out by lpistone
- 43. By Alexandre Fayolle - camptocamp
-
[FIX] issue when importing products from CSV with procurement_type attribute
There is an issue in the framework (I think) which will break the previous
version of the code in CSV imports: the get_product_procurement_ type method (in
product_template) is called with an instance of product_product for self, and
the call to super() crashed. This redesign works around the issue by extracting
get_product_procurement_ type to a function and thus avoiding self altogether. - 42. By Alexandre Fayolle - camptocamp
-
[FIX] tests
- 41. By Alexandre Fayolle - camptocamp
-
[ADD] migration script to ensure that the new attribute is populated
- 40. By Alexandre Fayolle - camptocamp
-
[FIX] values of procurement_type in dispatch method + help string + module version number
- 39. By Alexandre Fayolle - camptocamp
-
[IMP] follow changes in product_
procurement_ type_dropshippi ng
Preview Diff
1 | === added directory 'product_procurement_type' |
2 | === added file 'product_procurement_type/__init__.py' |
3 | --- product_procurement_type/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ product_procurement_type/__init__.py 2014-03-03 09:24:52 +0000 |
5 | @@ -0,0 +1,22 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# Author: Romain Deheele |
10 | +# Copyright 2014 Camptocamp SA |
11 | +# |
12 | +# This program is free software: you can redistribute it and/or modify |
13 | +# it under the terms of the GNU Affero General Public License as |
14 | +# published by the Free Software Foundation, either version 3 of the |
15 | +# License, or (at your option) any later version. |
16 | +# |
17 | +# This program is distributed in the hope that it will be useful, |
18 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | +# GNU Affero General Public License for more details. |
21 | +# |
22 | +# You should have received a copy of the GNU Affero General Public License |
23 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | +# |
25 | +############################################################################## |
26 | + |
27 | +from . import product |
28 | |
29 | === added file 'product_procurement_type/__openerp__.py' |
30 | --- product_procurement_type/__openerp__.py 1970-01-01 00:00:00 +0000 |
31 | +++ product_procurement_type/__openerp__.py 2014-03-03 09:24:52 +0000 |
32 | @@ -0,0 +1,50 @@ |
33 | +# -*- coding: utf-8 -*- |
34 | +############################################################################## |
35 | +# |
36 | +# Author: Romain Deheele |
37 | +# Copyright 2014 Camptocamp SA |
38 | +# |
39 | +# This program is free software: you can redistribute it and/or modify |
40 | +# it under the terms of the GNU Affero General Public License as |
41 | +# published by the Free Software Foundation, either version 3 of the |
42 | +# License, or (at your option) any later version. |
43 | +# |
44 | +# This program is distributed in the hope that it will be useful, |
45 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
46 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
47 | +# GNU Affero General Public License for more details. |
48 | +# |
49 | +# You should have received a copy of the GNU Affero General Public License |
50 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
51 | +# |
52 | +############################################################################## |
53 | + |
54 | +{ |
55 | + "name": "Product Procurement Types", |
56 | + "version": "0.1", |
57 | + "author": "Camptocamp", |
58 | + "license": "AGPL-3", |
59 | + "category": "Sales", |
60 | + "description": |
61 | + """ |
62 | + Add a procurement type selection on products. |
63 | + Let create products as : |
64 | + - Standard |
65 | + - Bill of Materials |
66 | + |
67 | + Choose "Standard" changes automatically |
68 | + procurement method as "make to stock" and supply method as "buy". |
69 | + Choose "Bill of Materials" changes automatically |
70 | + procurement method as "make to order" and supply method as "produce". |
71 | + |
72 | + """, |
73 | + "website": "http://camptocamp.com", |
74 | + "depends": ['sale', |
75 | + 'procurement', |
76 | + 'mrp'], |
77 | + "data": ['product_view.xml'], |
78 | + "demo": [], |
79 | + "test": ['test/test_onchange_procurement_type.yml'], |
80 | + "active": False, |
81 | + "installable": True, |
82 | +} |
83 | |
84 | === added directory 'product_procurement_type/migrations' |
85 | === added directory 'product_procurement_type/migrations/7.0.0.1' |
86 | === added file 'product_procurement_type/migrations/7.0.0.1/post-migration.py' |
87 | --- product_procurement_type/migrations/7.0.0.1/post-migration.py 1970-01-01 00:00:00 +0000 |
88 | +++ product_procurement_type/migrations/7.0.0.1/post-migration.py 2014-03-03 09:24:52 +0000 |
89 | @@ -0,0 +1,38 @@ |
90 | +# -*- coding: utf-8 -*- |
91 | +############################################################################## |
92 | +# |
93 | +# Author: Alexandre Fayolle |
94 | +# Copyright 2014 Camptocamp SA |
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 | +import logging |
112 | + |
113 | +logger = logging.getLogger('openerp.upgrade') |
114 | + |
115 | + |
116 | +def migrate(cr, version): |
117 | + logger.info('Migrating product_procurement_type') |
118 | + query = ("UPDATE product_template pt " |
119 | + "SET procurement_type=%(procurement_type)s " |
120 | + "WHERE procure_method=%(procure_method)s and supply_method=%(supply_method)s") |
121 | + fixes = [{'procurement_type': 'buy_stock', 'procure_method': 'make_to_stock', 'supply_method': 'buy'}, |
122 | + {'procurement_type': 'buy_demand', 'procure_method': 'make_to_order', 'supply_method': 'buy'}, |
123 | + {'procurement_type': 'produce_stock', 'procure_method': 'make_to_stock', 'supply_method': 'produce'}, |
124 | + {'procurement_type': 'produce_demand', 'procure_method': 'make_to_order', 'supply_method': 'produce'}, |
125 | + ] |
126 | + for fix in fixes: |
127 | + cr.execute(query, fix) |
128 | |
129 | === added file 'product_procurement_type/product.py' |
130 | --- product_procurement_type/product.py 1970-01-01 00:00:00 +0000 |
131 | +++ product_procurement_type/product.py 2014-03-03 09:24:52 +0000 |
132 | @@ -0,0 +1,115 @@ |
133 | +# -*- coding: utf-8 -*- |
134 | +############################################################################## |
135 | +# |
136 | +# Author: Romain Deheele |
137 | +# Copyright 2014 Camptocamp SA |
138 | +# |
139 | +# This program is free software: you can redistribute it and/or modify |
140 | +# it under the terms of the GNU Affero General Public License as |
141 | +# published by the Free Software Foundation, either version 3 of the |
142 | +# License, or (at your option) any later version. |
143 | +# |
144 | +# This program is distributed in the hope that it will be useful, |
145 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
146 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
147 | +# GNU Affero General Public License for more details. |
148 | +# |
149 | +# You should have received a copy of the GNU Affero General Public License |
150 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
151 | +# |
152 | +############################################################################## |
153 | + |
154 | +from openerp.osv import orm, fields |
155 | + |
156 | +def get_procurement_type_selection(): |
157 | + return [('buy_stock', 'On stock, buy'), |
158 | + ('buy_demand', 'On demand, buy'), |
159 | + ('produce_demand', 'On demand, produce'), |
160 | + ('produce_stock', 'On stock, produce'), |
161 | + ] |
162 | + |
163 | +class product_template(orm.Model): |
164 | + |
165 | + _inherit = 'product.template' |
166 | + |
167 | + def get_procurement_type_selection(self, cr, uid, context=None): |
168 | + """ |
169 | + Has to be inherited to add procurement type |
170 | + """ |
171 | + return get_procurement_type_selection() |
172 | + |
173 | + def _compute_procurement_vals(self, vals): |
174 | + if vals['procurement_type'] == 'buy_stock': |
175 | + vals.update({'procure_method': 'make_to_stock', |
176 | + 'supply_method': 'buy', |
177 | + }) |
178 | + elif vals['procurement_type'] == 'produce_demand': |
179 | + vals.update({'procure_method': 'make_to_order', |
180 | + 'supply_method': 'produce', |
181 | + }) |
182 | + elif vals['procurement_type'] == 'buy_demand': |
183 | + vals.update({'procure_method': 'make_to_order', |
184 | + 'supply_method': 'buy', |
185 | + }) |
186 | + elif vals['procurement_type'] == 'produce_stock': |
187 | + vals.update({'procure_method': 'make_to_stock', |
188 | + 'supply_method': 'produce', |
189 | + }) |
190 | + else: |
191 | + raise ValueError(vals['procurement_type']) |
192 | + return vals |
193 | + |
194 | + _columns = { |
195 | + 'procurement_type': fields.selection( |
196 | + get_procurement_type_selection, |
197 | + 'Procurement Type', |
198 | + required=True, |
199 | + help='On stock, buy: Procurement Method: Make to Stock, ' |
200 | + 'Supply Method: Buy.\n' |
201 | + 'On stock, produce: Procurement Method: Make to Stock, ' |
202 | + 'Supply Method: Produce.\n' |
203 | + 'On order, buy: Procurement Method: Make to Order, ' |
204 | + 'Supply Method: Buy.\n' |
205 | + 'On order, produce: Procurement Method: Make to Order, ' |
206 | + 'Supply Method: Produce.\n' |
207 | + ), |
208 | + } |
209 | + |
210 | + _defaults = { |
211 | + 'procurement_type': 'buy_stock', |
212 | + } |
213 | + |
214 | + def onchange_procurement_type(self, cr, uid, ids, type, procurement_type, |
215 | + context=None): |
216 | + vals = {'procurement_type': procurement_type} |
217 | + if type != 'service': |
218 | + vals = self._compute_procurement_vals(vals) |
219 | + return {'value': vals} |
220 | + |
221 | + def write(self, cr, uid, ids, vals, context=None): |
222 | + for product in self.read(cr, uid, ids, ['type'], context=context): |
223 | + if product['type'] != 'service' and \ |
224 | + vals.get('procurement_type'): |
225 | + vals = self._compute_procurement_vals(vals) |
226 | + res = super(product_template, self).write(cr, uid, ids, vals, |
227 | + context=context) |
228 | + return res |
229 | + |
230 | + def create(self, cr, uid, vals, context=None): |
231 | + if vals['type'] != 'service' and vals.get('procurement_type'): |
232 | + vals = self._compute_procurement_vals(vals) |
233 | + return super(product_template, self).create(cr, uid, vals, |
234 | + context=context) |
235 | + |
236 | + |
237 | +class product_product(orm.Model): |
238 | + |
239 | + _inherit = 'product.product' |
240 | + |
241 | + def onchange_procurement_type(self, cr, uid, ids, type, procurement_type, |
242 | + context=None): |
243 | + tmpl_obj = self.pool['product.template'] |
244 | + res = tmpl_obj.onchange_procurement_type(cr, uid, ids, type, |
245 | + procurement_type, |
246 | + context=context) |
247 | + return {'value': res['value']} |
248 | |
249 | === added file 'product_procurement_type/product_view.xml' |
250 | --- product_procurement_type/product_view.xml 1970-01-01 00:00:00 +0000 |
251 | +++ product_procurement_type/product_view.xml 2014-03-03 09:24:52 +0000 |
252 | @@ -0,0 +1,42 @@ |
253 | +<?xml version="1.0" encoding="utf-8"?> |
254 | +<openerp> |
255 | + <data> |
256 | + <record id="product_normal_form_view_procurement_type" model="ir.ui.view"> |
257 | + <field name="name">product.product.procurement_type</field> |
258 | + <field name="model">product.product</field> |
259 | + <field name="inherit_id" ref="procurement.product_form_view_procurement_button"/> |
260 | + <field name="arch" type="xml"> |
261 | + <data> |
262 | + <field name="procure_method" position="before"> |
263 | + <field name="procurement_type" on_change="onchange_procurement_type(type, procurement_type)" attrs="{'invisible':[('type','=','service')]}"/> |
264 | + </field> |
265 | + <field name="supply_method" position="attributes"> |
266 | + <attribute name="attrs">{'invisible':[('type','!=','service')]}</attribute> |
267 | + </field> |
268 | + <field name="procure_method" position="attributes"> |
269 | + <attribute name="attrs">{'invisible':[('type','!=','service')]}</attribute> |
270 | + </field> |
271 | + </data> |
272 | + </field> |
273 | + </record> |
274 | + |
275 | + <record model="ir.ui.view" id="product_template_form_view_procurement_type"> |
276 | + <field name="name">product.template.procurement_type</field> |
277 | + <field name="model">product.template</field> |
278 | + <field name="inherit_id" ref="procurement.product_template_form_view_procurement"/> |
279 | + <field name="arch" type="xml"> |
280 | + <data> |
281 | + <field name="procure_method" position="before"> |
282 | + <field name="procurement_type" on_change="onchange_procurement_type(type, procurement_type)" attrs="{'invisible':[('type','=','service')]}"/> |
283 | + </field> |
284 | + <field name="procure_method" position="attributes"> |
285 | + <attribute name="invisible">{'invisible':[('type','!=','service')]}</attribute> |
286 | + </field> |
287 | + <field name="supply_method" position="attributes"> |
288 | + <attribute name="invisible">{'invisible':[('type','!=','service')]}</attribute> |
289 | + </field> |
290 | + </data> |
291 | + </field> |
292 | + </record> |
293 | + </data> |
294 | +</openerp> |
295 | |
296 | === added directory 'product_procurement_type/test' |
297 | === added file 'product_procurement_type/test/test_onchange_procurement_type.yml' |
298 | --- product_procurement_type/test/test_onchange_procurement_type.yml 1970-01-01 00:00:00 +0000 |
299 | +++ product_procurement_type/test/test_onchange_procurement_type.yml 2014-03-03 09:24:52 +0000 |
300 | @@ -0,0 +1,56 @@ |
301 | +- |
302 | + Testing change of procurement type on product |
303 | +- |
304 | + I create a product "Store" with type buy_stock |
305 | +- |
306 | + !record {model: product.product, id: product1}: |
307 | + name: Store |
308 | + type: product |
309 | + procurement_type: buy_stock |
310 | +- |
311 | + I check if the product is MTS + buy |
312 | +- |
313 | + !assert {model: product.product, id: product1}: |
314 | + - procure_method == 'make_to_stock' |
315 | + - supply_method == 'buy' |
316 | +- |
317 | + I create a product "Curtain" with type produce_demand |
318 | +- |
319 | + !record {model: product.product, id: product2}: |
320 | + name: Curtain |
321 | + type: product |
322 | + procurement_type: produce_demand |
323 | +- |
324 | + I check if the product is MTO + produce |
325 | +- |
326 | + !assert {model: product.product, id: product2}: |
327 | + - procure_method == 'make_to_order' |
328 | + - supply_method == 'produce' |
329 | + |
330 | +- |
331 | + I create a product "Curtain2" with type produce_stock |
332 | +- |
333 | + !record {model: product.product, id: product3}: |
334 | + name: Curtain2 |
335 | + type: product |
336 | + procurement_type: produce_stock |
337 | +- |
338 | + I check if the product is MTS + produce |
339 | +- |
340 | + !assert {model: product.product, id: product3}: |
341 | + - procure_method == 'make_to_stock' |
342 | + - supply_method == 'produce' |
343 | + |
344 | +- |
345 | + I create a product "Store2" with type buy_demand |
346 | +- |
347 | + !record {model: product.product, id: product4}: |
348 | + name: Store2 |
349 | + type: product |
350 | + procurement_type: buy_demand |
351 | +- |
352 | + I check if the product is MTO + buy |
353 | +- |
354 | + !assert {model: product.product, id: product4}: |
355 | + - procure_method == 'make_to_order' |
356 | + - supply_method == 'buy' |
357 | |
358 | === added directory 'product_procurement_type_dropshipping' |
359 | === added file 'product_procurement_type_dropshipping/__init__.py' |
360 | --- product_procurement_type_dropshipping/__init__.py 1970-01-01 00:00:00 +0000 |
361 | +++ product_procurement_type_dropshipping/__init__.py 2014-03-03 09:24:52 +0000 |
362 | @@ -0,0 +1,22 @@ |
363 | +# -*- coding: utf-8 -*- |
364 | +############################################################################## |
365 | +# |
366 | +# Author: Romain Deheele |
367 | +# Copyright 2014 Camptocamp SA |
368 | +# |
369 | +# This program is free software: you can redistribute it and/or modify |
370 | +# it under the terms of the GNU Affero General Public License as |
371 | +# published by the Free Software Foundation, either version 3 of the |
372 | +# License, or (at your option) any later version. |
373 | +# |
374 | +# This program is distributed in the hope that it will be useful, |
375 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
376 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
377 | +# GNU Affero General Public License for more details. |
378 | +# |
379 | +# You should have received a copy of the GNU Affero General Public License |
380 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
381 | +# |
382 | +############################################################################## |
383 | + |
384 | +from . import product |
385 | |
386 | === added file 'product_procurement_type_dropshipping/__openerp__.py' |
387 | --- product_procurement_type_dropshipping/__openerp__.py 1970-01-01 00:00:00 +0000 |
388 | +++ product_procurement_type_dropshipping/__openerp__.py 2014-03-03 09:24:52 +0000 |
389 | @@ -0,0 +1,46 @@ |
390 | +# -*- coding: utf-8 -*- |
391 | +############################################################################## |
392 | +# |
393 | +# Author: Romain Deheele |
394 | +# Copyright 2014 Camptocamp SA |
395 | +# |
396 | +# This program is free software: you can redistribute it and/or modify |
397 | +# it under the terms of the GNU Affero General Public License as |
398 | +# published by the Free Software Foundation, either version 3 of the |
399 | +# License, or (at your option) any later version. |
400 | +# |
401 | +# This program is distributed in the hope that it will be useful, |
402 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
403 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
404 | +# GNU Affero General Public License for more details. |
405 | +# |
406 | +# You should have received a copy of the GNU Affero General Public License |
407 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
408 | +# |
409 | +############################################################################## |
410 | + |
411 | +{ |
412 | + "name": "Product Procurement Type Dropshipping", |
413 | + "version": "0.1", |
414 | + "author": "Camptocamp", |
415 | + "license": "AGPL-3", |
416 | + "category": "Sales", |
417 | + "description": |
418 | + """ |
419 | + Add a choice named 'dropshipping' in procurement_type selection |
420 | + introduced by product_procurement_type addon. |
421 | + Choose "Dropshipping" changes automatically |
422 | + procurement method as "make to order" and supply method as "buy". |
423 | + It checks if at least one supplier is associated on supplier list |
424 | + in product form. |
425 | + |
426 | + """, |
427 | + "website": "http://camptocamp.com", |
428 | + "depends": ['product_procurement_type', |
429 | + 'sale_dropshipping'], |
430 | + "data": ['product_view.xml'], |
431 | + "demo": [], |
432 | + "test": ['test/test_onchange_procurement_type.yml'], |
433 | + "active": False, |
434 | + "installable": True, |
435 | +} |
436 | |
437 | === added directory 'product_procurement_type_dropshipping/migrations' |
438 | === added directory 'product_procurement_type_dropshipping/migrations/7.0.0.1' |
439 | === added file 'product_procurement_type_dropshipping/migrations/7.0.0.1/post-migration.py' |
440 | --- product_procurement_type_dropshipping/migrations/7.0.0.1/post-migration.py 1970-01-01 00:00:00 +0000 |
441 | +++ product_procurement_type_dropshipping/migrations/7.0.0.1/post-migration.py 2014-03-03 09:24:52 +0000 |
442 | @@ -0,0 +1,39 @@ |
443 | +# -*- coding: utf-8 -*- |
444 | +############################################################################## |
445 | +# |
446 | +# Author: Alexandre Fayolle |
447 | +# Copyright 2014 Camptocamp SA |
448 | +# |
449 | +# This program is free software: you can redistribute it and/or modify |
450 | +# it under the terms of the GNU Affero General Public License as |
451 | +# published by the Free Software Foundation, either version 3 of the |
452 | +# License, or (at your option) any later version. |
453 | +# |
454 | +# This program is distributed in the hope that it will be useful, |
455 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
456 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
457 | +# GNU Affero General Public License for more details. |
458 | +# |
459 | +# You should have received a copy of the GNU Affero General Public License |
460 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
461 | +# |
462 | +############################################################################## |
463 | + |
464 | +import logging |
465 | + |
466 | +logger = logging.getLogger('openerp.upgrade') |
467 | + |
468 | + |
469 | +def migrate(cr, version): |
470 | + logger.info('Migrating product_procurement_type_dropshipping') |
471 | + query = ("UPDATE product_template AS pt " |
472 | + "SET procurement_type=%(procurement_type)s " |
473 | + "FROM product_supplierinfo AS psi " |
474 | + "WHERE procure_method=%(procure_method)s " |
475 | + " AND supply_method=%(supply_method)s " |
476 | + " AND psi.product_id = pt.id " |
477 | + " AND psi.direct_delivery_flag = true") |
478 | + fixes = [{'procurement_type': 'direct_delivery', 'procure_method': 'make_to_order', 'supply_method': 'buy'}, |
479 | + ] |
480 | + for fix in fixes: |
481 | + cr.execute(query, fix) |
482 | |
483 | === added file 'product_procurement_type_dropshipping/product.py' |
484 | --- product_procurement_type_dropshipping/product.py 1970-01-01 00:00:00 +0000 |
485 | +++ product_procurement_type_dropshipping/product.py 2014-03-03 09:24:52 +0000 |
486 | @@ -0,0 +1,115 @@ |
487 | +# -*- coding: utf-8 -*- |
488 | +############################################################################## |
489 | +# |
490 | +# Author: Romain Deheele |
491 | +# Copyright 2014 Camptocamp SA |
492 | +# |
493 | +# This program is free software: you can redistribute it and/or modify |
494 | +# it under the terms of the GNU Affero General Public License as |
495 | +# published by the Free Software Foundation, either version 3 of the |
496 | +# License, or (at your option) any later version. |
497 | +# |
498 | +# This program is distributed in the hope that it will be useful, |
499 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
500 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
501 | +# GNU Affero General Public License for more details. |
502 | +# |
503 | +# You should have received a copy of the GNU Affero General Public License |
504 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
505 | +# |
506 | +############################################################################## |
507 | + |
508 | +from openerp.osv import orm, fields |
509 | +from openerp.tools.translate import _ |
510 | +from openerp.addons.product_procurement_type.product import get_procurement_type_selection |
511 | + |
512 | +def get_procurement_type_selection_with_dropshipping(): |
513 | + selections = get_procurement_type_selection() |
514 | + selections.append(('direct_delivery', 'Drop Shipping')) |
515 | + return selections |
516 | + |
517 | +class product_template(orm.Model): |
518 | + |
519 | + _inherit = 'product.template' |
520 | + |
521 | + def get_procurement_type_selection(self, cr, uid, context=None): |
522 | + """ |
523 | + Adds type dropshipping in procurement_type selection |
524 | + """ |
525 | + return get_procurement_type_selection_with_dropshipping() |
526 | + |
527 | + def _compute_procurement_vals(self, vals): |
528 | + if vals['procurement_type'] == 'direct_delivery': |
529 | + vals.update({'procure_method': 'make_to_order', |
530 | + 'supply_method': 'buy', |
531 | + }) |
532 | + else: |
533 | + vals = super(product_template, self)._compute_procurement_vals(vals) |
534 | + return vals |
535 | + |
536 | + def _check_sellers(self, cr, uid, ids, procurement_type, context=None): |
537 | + dd_flag = procurement_type == 'direct_delivery' |
538 | + seller_pool = self.pool['product.supplierinfo'] |
539 | + seller_ids = seller_pool.search(cr, uid, [('product_id', 'in', ids)], |
540 | + context=context) |
541 | + if seller_ids: |
542 | + seller_pool.write(cr, uid, seller_ids, |
543 | + {'direct_delivery_flag': dd_flag}, |
544 | + context=context) |
545 | + else: |
546 | + if dd_flag: |
547 | + raise orm.except_orm( |
548 | + _('Warning'), |
549 | + _('No suppliers defined')) |
550 | + |
551 | + _columns = { |
552 | + 'procurement_type': fields.selection( |
553 | + get_procurement_type_selection, |
554 | + 'Procurement Type', |
555 | + required=True, |
556 | + help='On stock, buy: Procurement Method: Make to Stock, ' |
557 | + 'Supply Method: Buy.\n' |
558 | + 'On stock, produce: Procurement Method: Make to Stock, ' |
559 | + 'Supply Method: Produce.\n' |
560 | + 'On order, buy: Procurement Method: Make to Order, ' |
561 | + 'Supply Method: Buy.\n' |
562 | + 'On order, produce: Procurement Method: Make to Order, ' |
563 | + 'Supply Method: Produce.\n' |
564 | + 'DropShipping: Procurement Method: Make to Order, ' |
565 | + 'Supply Method: Buy + supplier does drop shipping'), |
566 | + } |
567 | + |
568 | + def onchange_procurement_type(self, cr, uid, ids, type, |
569 | + procurement_type, context=None): |
570 | + res = super(product_template, self).\ |
571 | + onchange_procurement_type(cr, |
572 | + uid, |
573 | + ids, |
574 | + type, |
575 | + procurement_type) |
576 | + if type != 'service': |
577 | + res['value'].update( |
578 | + self._compute_procurement_vals( |
579 | + {'procurement_type': procurement_type}) |
580 | + ) |
581 | + self._check_sellers(cr, uid, ids, procurement_type, |
582 | + context=context) |
583 | + return res |
584 | + |
585 | + def write(self, cr, uid, ids, vals, context=None): |
586 | + for product in self.read(cr, uid, ids, ['type'], context=context): |
587 | + if product['type'] != 'service' and \ |
588 | + vals.get('procurement_type'): |
589 | + vals = self._compute_procurement_vals(vals) |
590 | + self._check_sellers(cr, uid, ids, |
591 | + vals['procurement_type'], |
592 | + context=context) |
593 | + res = super(product_template, self).write(cr, uid, ids, |
594 | + vals, context=context) |
595 | + return res |
596 | + |
597 | + def create(self, cr, uid, vals, context=None): |
598 | + if vals['type'] != 'service' and vals.get('procurement_type'): |
599 | + vals = self._compute_procurement_vals(vals) |
600 | + return super(product_template, self).create(cr, uid, vals, |
601 | + context=context) |
602 | |
603 | === added file 'product_procurement_type_dropshipping/product_view.xml' |
604 | --- product_procurement_type_dropshipping/product_view.xml 1970-01-01 00:00:00 +0000 |
605 | +++ product_procurement_type_dropshipping/product_view.xml 2014-03-03 09:24:52 +0000 |
606 | @@ -0,0 +1,17 @@ |
607 | +<?xml version="1.0" encoding="utf-8"?> |
608 | +<openerp> |
609 | + <data> |
610 | + <record id="view_product_supplier_context_dropshipping" model="ir.ui.view"> |
611 | + <field name="name">product.supplier.context.dropshipping</field> |
612 | + <field name="model">product.product</field> |
613 | + <field name="inherit_id" ref="purchase.view_product_supplier_inherit"/> |
614 | + <field name="arch" type="xml"> |
615 | + <data> |
616 | + <field name="seller_ids" position="attributes"> |
617 | + <attribute name="context">{'uom_id': uom_id, 'default_direct_delivery_flag': procurement_type == 'direct_delivery'}</attribute> |
618 | + </field> |
619 | + </data> |
620 | + </field> |
621 | + </record> |
622 | + </data> |
623 | +</openerp> |
624 | |
625 | === added directory 'product_procurement_type_dropshipping/test' |
626 | === added file 'product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml' |
627 | --- product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml 1970-01-01 00:00:00 +0000 |
628 | +++ product_procurement_type_dropshipping/test/test_onchange_procurement_type.yml 2014-03-03 09:24:52 +0000 |
629 | @@ -0,0 +1,52 @@ |
630 | +- |
631 | + Testing change of procurement type on product |
632 | +- |
633 | + I create a product "Jalousie" |
634 | +- |
635 | + !record {model: product.product, id: product3}: |
636 | + name: Jalousie |
637 | + type: product |
638 | +- |
639 | + I define the product with dropshipping |
640 | + but it fails because the product has no suppliers defined. |
641 | +- |
642 | + !python {model: product.product}: | |
643 | + from openerp.osv import orm |
644 | + product3_id = ref("product3") |
645 | + try: |
646 | + self.write(cr, uid, [product3_id], {'procurement_type': 'direct_delivery'}) |
647 | + except orm.except_orm as err: |
648 | + assert 'Error Expected' |
649 | +- |
650 | + I create a supplier "Dupont" |
651 | +- |
652 | + !record {model: res.partner, id: partner1}: |
653 | + name: Dupont |
654 | + supplier: True |
655 | +- |
656 | + I set this supplier on the product "Jalousie" |
657 | +- |
658 | + !record {model: product.supplierinfo, id: psupinfo1}: |
659 | + name: partner1 |
660 | + product_id: product3 |
661 | + min_qty: 1.0 |
662 | +- |
663 | + I define dropshipping on the product. |
664 | +- |
665 | + !python {model: product.product}: | |
666 | + product3_id = ref("product3") |
667 | + try: |
668 | + values = self.onchange_procurement_type(cr, uid, [product3_id], 'product', 'direct_delivery') |
669 | + self.write(cr, uid, [product3_id], values['value']) |
670 | + except: |
671 | + raise AssertionError('Expected no error') |
672 | +- |
673 | + I check if the product is now made to order |
674 | +- |
675 | + !assert {model: product.product, id: product3}: |
676 | + - procure_method == 'make_to_order' |
677 | +- |
678 | + I check if supplier is checked as doing dropshipping |
679 | +- |
680 | + !assert {model: product.supplierinfo, id: psupinfo1}: |
681 | + - direct_delivery_flag == 1 |
682 | \ No newline at end of file |
LGTM for the code
However, I don't think we have a proper branch to extend procurement.
Shall we create one?