Merge lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge into lp:~sale-core-editors/sale-wkfl/7.0
- move_sale_exception_module_from_e-commerce-addons-jge
- Merge into 7.0
Status: | Merged |
---|---|
Merged at revision: | 21 |
Proposed branch: | lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge |
Merge into: | lp:~sale-core-editors/sale-wkfl/7.0 |
Diff against target: |
994 lines (+925/-0) 13 files modified
sale_exceptions/__init__.py (+26/-0) sale_exceptions/__openerp__.py (+46/-0) sale_exceptions/i18n/fr.po (+177/-0) sale_exceptions/i18n/sale_exceptions.pot (+177/-0) sale_exceptions/sale.py (+236/-0) sale_exceptions/sale_exceptions_data.xml (+19/-0) sale_exceptions/sale_view.xml (+102/-0) sale_exceptions/sale_workflow.xml (+9/-0) sale_exceptions/security/ir.model.access.csv (+3/-0) sale_exceptions/settings/sale.exception.csv (+5/-0) sale_exceptions/wizard/__init__.py (+24/-0) sale_exceptions/wizard/sale_exception_confirm.py (+62/-0) sale_exceptions/wizard/sale_exception_confirm_view.xml (+39/-0) |
To merge this branch: | bzr merge lp:~openerp-community-reviewer/sale-wkfl/move_sale_exception_module_from_e-commerce-addons-jge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nicolas Bessi - Camptocamp (community) | no test, code review | Approve | |
Guewen Baconnier @ Camptocamp | Approve | ||
Review via email: mp+193567@code.launchpad.net |
Commit message
[MOVE] Move here the sale_exceptions module from the lp:e-commerce-addons
Description of the change
Hi,
I suggest to move the sale_exceptions module from e-commerce-addons to here because it really concerns the sales workflow in a more generic way than just the e-commerce context.
I put the branch under the reviewer team so feel free to fix stuff if you'd like.
WARNING: Merge this proposal when this one is done : https:/
Regards,
Joël
Pedro Manuel Baeza (pedro.baeza) wrote : | # |
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote : | # |
Hi, I am working on the split of sale_exception in two module "sale_exception" and "exception_rule". The aim is to have the exception on different object like purchase_order, stock_picking, invoice ... (already implemented on purchase_order and soon on picking).
If we put the module sale_exception here where should I put the module "exception_rule" and "purchase_
I see two solution possible
- Putting exception_rule in "server-env-tools" and than all implementation in sale-wkfl, purchase-wkfl...
- Creating a project "workflow-
What do you prefers?
Pedro Manuel Baeza (pedro.baeza) wrote : | # |
Hi, Sébastien, is there too much logic on exception_rule so that it is mandatory to split it in one module?, or it can be easily repeated in consequent other modules "purchase_
Regards.
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
Hi,
+1 for Pedro. Having such a general module doesn't seems mandatory. The exception can IMO define in every module.
Moreover, the sale_exception module was already there like this. So I just move it. We can't assume doing both in one. Your suggestion may break back-compatibility so... My suggestion: move on to have it in the right project/branches, then when you'll be ready, make your MP so we'll have the opportunity to discuss that with something concrete !
What do you think ?
++
Joël
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote : | # |
After my split I have around 140 ligne of python in exception_rule and around 40 in sale_exception so I really think it's worth to split it because we will avoid to duplicate the 140 ligne in every module for nothing, it's not a lot but it's always better to no duplicate the code (on improvement improve all module). Moreover we use the same pop-up wizard in sale_exception and purchase_exception so it the same interface for the end user.
Here is my work : http://
(not ready to be merge yet, I have to be sure that I do not miss any improvement done by guewen here https:/
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote : | # |
Sorry I made a mistake around 180 line in the generic module
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
Hi Sébastien,
Your work looks great. Can you please make another MP once this one is done with your work ? This we move forward on this one.
@Pedro : Would you add your review here please ?
Regards,
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
I approve for the move
- 46. By Nicolas Bessi - Camptocamp
-
[PEP8] and community conventions
- 47. By Nicolas Bessi - Camptocamp
-
[PEP8]
- 48. By Nicolas Bessi - Camptocamp
-
[PEP8] + removing class instantiation
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
LGTM
I also committed PEP8 and community convention fixes.
Moving the module is OK.
- 49. By Nicolas Bessi - Camptocamp
-
[FIX] licence
- 50. By Nicolas Bessi - Camptocamp
-
[MRG] migration of sale_exceptions from original branch
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
Hello,
I have merge back migration/fixes recently commited in lp:e-commerce-addons
Preview Diff
1 | === added directory 'sale_exceptions' |
2 | === added file 'sale_exceptions/__init__.py' |
3 | --- sale_exceptions/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ sale_exceptions/__init__.py 2013-11-15 12:55:43 +0000 |
5 | @@ -0,0 +1,26 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# Copyright (C) 2011 Akretion LTDA. |
11 | +# authors: Raphaël Valyi, Renato Lima |
12 | +# Copyright (C) 2010-2012 Akretion Sébastien BEAU <sebastien.beau@akretion.com> |
13 | +# Copyright (C) 2012 Camptocamp SA (Guewen Baconnier) |
14 | +# |
15 | +# This program is free software: you can redistribute it and/or modify |
16 | +# it under the terms of the GNU Affero General Public License as |
17 | +# published by the Free Software Foundation, either version 3 of the |
18 | +# License, or (at your option) any later version. |
19 | +# |
20 | +# This program is distributed in the hope that it will be useful, |
21 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | +# GNU Affero General Public License for more details. |
24 | +# |
25 | +# You should have received a copy of the GNU Affero General Public License |
26 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
27 | +# |
28 | +############################################################################## |
29 | + |
30 | +from . import sale |
31 | +from . import wizard |
32 | |
33 | === added file 'sale_exceptions/__openerp__.py' |
34 | --- sale_exceptions/__openerp__.py 1970-01-01 00:00:00 +0000 |
35 | +++ sale_exceptions/__openerp__.py 2013-11-15 12:55:43 +0000 |
36 | @@ -0,0 +1,46 @@ |
37 | +# -*- coding: utf-8 -*- |
38 | +############################################################################## |
39 | +# |
40 | +# OpenERP, Open Source Management Solution |
41 | +# Copyright (C) 2011 Akretion LTDA. |
42 | +# authors: Raphaël Valyi, Renato Lima |
43 | +# Copyright (C) 2010-2012 Akretion Sébastien BEAU <sebastien.beau@akretion.com> |
44 | +# Copyright (C) 2012 Camptocamp SA (Guewen Baconnier) |
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 |
48 | +# published by the Free Software Foundation, either version 3 of the |
49 | +# License, or (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 | +{'name': 'Sale Exceptions', |
61 | + 'version': '0.1', |
62 | + 'category': 'Generic Modules/Sale', |
63 | + 'description': """ |
64 | +This module allows you attach several customizable exceptions to your sale order |
65 | + in a way that you can filter orders by exceptions type and fix them. |
66 | + |
67 | +This is especially useful in an order importation scenario such as with |
68 | +the base_sale_multi_channels module, because it's likely a few orders have errors |
69 | +when you import them (like product not found in OpenERP, wrong line format etc...) |
70 | +""", |
71 | + 'author': 'Akretion', |
72 | + 'website': 'http://www.akretion.com', |
73 | + 'depends': ['sale'], |
74 | + 'init_xml': ['settings/sale.exception.csv'], |
75 | + 'update_xml': ['sale_workflow.xml', |
76 | + 'sale_view.xml', |
77 | + 'sale_exceptions_data.xml', |
78 | + 'wizard/sale_exception_confirm_view.xml', |
79 | + 'security/ir.model.access.csv'], |
80 | + 'demo_xml': [], |
81 | + 'installable': True, |
82 | + } |
83 | |
84 | === added directory 'sale_exceptions/i18n' |
85 | === added file 'sale_exceptions/i18n/fr.po' |
86 | --- sale_exceptions/i18n/fr.po 1970-01-01 00:00:00 +0000 |
87 | +++ sale_exceptions/i18n/fr.po 2013-11-15 12:55:43 +0000 |
88 | @@ -0,0 +1,177 @@ |
89 | +# Translation of OpenERP Server. |
90 | +# This file contains the translation of the following modules: |
91 | +# * sale_exceptions |
92 | +# |
93 | +msgid "" |
94 | +msgstr "" |
95 | +"Project-Id-Version: OpenERP Server 7.0\n" |
96 | +"Report-Msgid-Bugs-To: \n" |
97 | +"POT-Creation-Date: 2013-05-02 06:57+0000\n" |
98 | +"PO-Revision-Date: 2013-05-02 06:57+0000\n" |
99 | +"Last-Translator: <>\n" |
100 | +"Language-Team: \n" |
101 | +"MIME-Version: 1.0\n" |
102 | +"Content-Type: text/plain; charset=UTF-8\n" |
103 | +"Content-Transfer-Encoding: \n" |
104 | +"Plural-Forms: \n" |
105 | + |
106 | +#. module: sale_exceptions |
107 | +#: model:ir.model,name:sale_exceptions.model_sale_exception_confirm |
108 | +msgid "sale.exception.confirm" |
109 | +msgstr "" |
110 | + |
111 | +#. module: sale_exceptions |
112 | +#: selection:sale.exception,model:0 |
113 | +msgid "Sale Order Line" |
114 | +msgstr "Ligne de commande" |
115 | + |
116 | +#. module: sale_exceptions |
117 | +#: field:sale.exception,model:0 |
118 | +msgid "Apply on" |
119 | +msgstr "Appliquer sur" |
120 | + |
121 | +#. module: sale_exceptions |
122 | +#: model:sale.exception,name:sale_exceptions.excep_no_stock |
123 | +msgid "Not Enough Virtual Stock" |
124 | +msgstr "Pas assez de quantité de stock prévue" |
125 | + |
126 | +#. module: sale_exceptions |
127 | +#: field:sale.exception,description:0 |
128 | +msgid "Description" |
129 | +msgstr "Description" |
130 | + |
131 | +#. module: sale_exceptions |
132 | +#: help:sale.exception,sequence:0 |
133 | +msgid "Gives the sequence order when applying the test" |
134 | +msgstr "Définit l'ordre d'application des contrôles" |
135 | + |
136 | +#. module: sale_exceptions |
137 | +#: view:sale.exception.confirm:0 |
138 | +msgid "Sale Exceptions On Sale Order" |
139 | +msgstr "Restrictions sur la commande" |
140 | + |
141 | +#. module: sale_exceptions |
142 | +#: field:sale.exception.confirm,exception_ids:0 |
143 | +msgid "Exceptions to resolve" |
144 | +msgstr "Restrictions à résoudre" |
145 | + |
146 | +#. module: sale_exceptions |
147 | +#: view:sale.exception.confirm:0 |
148 | +msgid "_Ok" |
149 | +msgstr "_Ok" |
150 | + |
151 | +#. module: sale_exceptions |
152 | +#: view:sale.exception:0 |
153 | +#: view:sale.exception.confirm:0 |
154 | +msgid "Sale Exception" |
155 | +msgstr "Restriction de vente" |
156 | + |
157 | +#. module: sale_exceptions |
158 | +#: view:sale.order:0 |
159 | +msgid "TO FIX" |
160 | +msgstr "A CORRIGER" |
161 | + |
162 | +#. module: sale_exceptions |
163 | +#: help:sale.exception,code:0 |
164 | +msgid "Python code executed to check if the exception apply or not. The code must apply block = True to apply the exception." |
165 | +msgstr "Code Python exécuté pour déterminer si la restriction s'applique. The bloc de code doit retourner block = True pour appliquer la restriction." |
166 | + |
167 | +#. module: sale_exceptions |
168 | +#: view:sale.order:0 |
169 | +msgid "Exception" |
170 | +msgstr "Restriction" |
171 | + |
172 | +#. module: sale_exceptions |
173 | +#: view:sale.order:0 |
174 | +msgid "Error:" |
175 | +msgstr "Erreur :" |
176 | + |
177 | +#. module: sale_exceptions |
178 | +#: selection:sale.exception,model:0 |
179 | +msgid "Sale Order" |
180 | +msgstr "Bon de commande" |
181 | + |
182 | +#. module: sale_exceptions |
183 | +#: field:sale.exception.confirm,sale_id:0 |
184 | +msgid "Sale" |
185 | +msgstr "Commande" |
186 | + |
187 | +#. module: sale_exceptions |
188 | +#: field:sale.exception,active:0 |
189 | +msgid "Active" |
190 | +msgstr "Actif" |
191 | + |
192 | +#. module: sale_exceptions |
193 | +#: field:sale.exception,name:0 |
194 | +msgid "Exception Name" |
195 | +msgstr "Nom de la restriction" |
196 | + |
197 | +#. module: sale_exceptions |
198 | +#: field:sale.order,exceptions_ids:0 |
199 | +msgid "Exceptions" |
200 | +msgstr "Restrictions" |
201 | + |
202 | +#. module: sale_exceptions |
203 | +#: model:ir.actions.act_window,name:sale_exceptions.action_sale_exception_confirm |
204 | +#: model:ir.model,name:sale_exceptions.model_sale_exception |
205 | +#: view:sale.exception.confirm:0 |
206 | +msgid "Sale Exceptions" |
207 | +msgstr "Restrictions de vente" |
208 | + |
209 | +#. module: sale_exceptions |
210 | +#: model:ir.actions.act_window,name:sale_exceptions.action_sale_test_tree |
211 | +#: model:ir.ui.menu,name:sale_exceptions.menu_sale_test |
212 | +msgid "Exception Rules" |
213 | +msgstr "Règles de restriction" |
214 | + |
215 | +#. module: sale_exceptions |
216 | +#: model:ir.model,name:sale_exceptions.model_sale_order |
217 | +msgid "Sales Order" |
218 | +msgstr "Bon de commande" |
219 | + |
220 | +#. module: sale_exceptions |
221 | +#: field:sale.exception,sequence:0 |
222 | +msgid "Sequence" |
223 | +msgstr "Séquence" |
224 | + |
225 | +#. module: sale_exceptions |
226 | +#: field:sale.exception,code:0 |
227 | +msgid "Python Code" |
228 | +msgstr "Code Python" |
229 | + |
230 | +#. module: sale_exceptions |
231 | +#: view:sale.order:0 |
232 | +msgid "Sales" |
233 | +msgstr "Bons de commande" |
234 | + |
235 | +#. module: sale_exceptions |
236 | +#: model:sale.exception,name:sale_exceptions.excep_no_zip |
237 | +msgid "No ZIP code on destination" |
238 | +msgstr "Code postal manquant sur la destination" |
239 | + |
240 | +#. module: sale_exceptions |
241 | +#: view:sale.exception:0 |
242 | +msgid "Sale Exception Setup" |
243 | +msgstr "Configuration des restrictions de vente" |
244 | + |
245 | +#. module: sale_exceptions |
246 | +#: view:sale.exception:0 |
247 | +msgid "Affected Sales Orders" |
248 | +msgstr "Bons de commande affectés" |
249 | + |
250 | +#. module: sale_exceptions |
251 | +#: field:sale.exception,sale_order_ids:0 |
252 | +msgid "Sale Orders" |
253 | +msgstr "Bons de commande" |
254 | + |
255 | +#. module: sale_exceptions |
256 | +#: field:sale.exception.confirm,ignore:0 |
257 | +#: field:sale.order,ignore_exceptions:0 |
258 | +msgid "Ignore Exceptions" |
259 | +msgstr "Ignorer la restriction" |
260 | + |
261 | +#. module: sale_exceptions |
262 | +#: field:sale.order,main_exception_id:0 |
263 | +msgid "Main Exception" |
264 | +msgstr "Restriction principale" |
265 | + |
266 | |
267 | === added file 'sale_exceptions/i18n/sale_exceptions.pot' |
268 | --- sale_exceptions/i18n/sale_exceptions.pot 1970-01-01 00:00:00 +0000 |
269 | +++ sale_exceptions/i18n/sale_exceptions.pot 2013-11-15 12:55:43 +0000 |
270 | @@ -0,0 +1,177 @@ |
271 | +# Translation of OpenERP Server. |
272 | +# This file contains the translation of the following modules: |
273 | +# * sale_exceptions |
274 | +# |
275 | +msgid "" |
276 | +msgstr "" |
277 | +"Project-Id-Version: OpenERP Server 7.0\n" |
278 | +"Report-Msgid-Bugs-To: \n" |
279 | +"POT-Creation-Date: 2013-05-02 06:57+0000\n" |
280 | +"PO-Revision-Date: 2013-05-02 06:57+0000\n" |
281 | +"Last-Translator: <>\n" |
282 | +"Language-Team: \n" |
283 | +"MIME-Version: 1.0\n" |
284 | +"Content-Type: text/plain; charset=UTF-8\n" |
285 | +"Content-Transfer-Encoding: \n" |
286 | +"Plural-Forms: \n" |
287 | + |
288 | +#. module: sale_exceptions |
289 | +#: model:ir.model,name:sale_exceptions.model_sale_exception_confirm |
290 | +msgid "sale.exception.confirm" |
291 | +msgstr "" |
292 | + |
293 | +#. module: sale_exceptions |
294 | +#: selection:sale.exception,model:0 |
295 | +msgid "Sale Order Line" |
296 | +msgstr "" |
297 | + |
298 | +#. module: sale_exceptions |
299 | +#: field:sale.exception,model:0 |
300 | +msgid "Apply on" |
301 | +msgstr "" |
302 | + |
303 | +#. module: sale_exceptions |
304 | +#: model:sale.exception,name:sale_exceptions.excep_no_stock |
305 | +msgid "Not Enough Virtual Stock" |
306 | +msgstr "" |
307 | + |
308 | +#. module: sale_exceptions |
309 | +#: field:sale.exception,description:0 |
310 | +msgid "Description" |
311 | +msgstr "" |
312 | + |
313 | +#. module: sale_exceptions |
314 | +#: help:sale.exception,sequence:0 |
315 | +msgid "Gives the sequence order when applying the test" |
316 | +msgstr "" |
317 | + |
318 | +#. module: sale_exceptions |
319 | +#: view:sale.exception.confirm:0 |
320 | +msgid "Sale Exceptions On Sale Order" |
321 | +msgstr "" |
322 | + |
323 | +#. module: sale_exceptions |
324 | +#: field:sale.exception.confirm,exception_ids:0 |
325 | +msgid "Exceptions to resolve" |
326 | +msgstr "" |
327 | + |
328 | +#. module: sale_exceptions |
329 | +#: view:sale.exception.confirm:0 |
330 | +msgid "_Ok" |
331 | +msgstr "" |
332 | + |
333 | +#. module: sale_exceptions |
334 | +#: view:sale.exception:0 |
335 | +#: view:sale.exception.confirm:0 |
336 | +msgid "Sale Exception" |
337 | +msgstr "" |
338 | + |
339 | +#. module: sale_exceptions |
340 | +#: view:sale.order:0 |
341 | +msgid "TO FIX" |
342 | +msgstr "" |
343 | + |
344 | +#. module: sale_exceptions |
345 | +#: help:sale.exception,code:0 |
346 | +msgid "Python code executed to check if the exception apply or not. The code must apply block = True to apply the exception." |
347 | +msgstr "" |
348 | + |
349 | +#. module: sale_exceptions |
350 | +#: view:sale.order:0 |
351 | +msgid "Exception" |
352 | +msgstr "" |
353 | + |
354 | +#. module: sale_exceptions |
355 | +#: view:sale.order:0 |
356 | +msgid "Error:" |
357 | +msgstr "" |
358 | + |
359 | +#. module: sale_exceptions |
360 | +#: selection:sale.exception,model:0 |
361 | +msgid "Sale Order" |
362 | +msgstr "" |
363 | + |
364 | +#. module: sale_exceptions |
365 | +#: field:sale.exception.confirm,sale_id:0 |
366 | +msgid "Sale" |
367 | +msgstr "" |
368 | + |
369 | +#. module: sale_exceptions |
370 | +#: field:sale.exception,active:0 |
371 | +msgid "Active" |
372 | +msgstr "" |
373 | + |
374 | +#. module: sale_exceptions |
375 | +#: field:sale.exception,name:0 |
376 | +msgid "Exception Name" |
377 | +msgstr "" |
378 | + |
379 | +#. module: sale_exceptions |
380 | +#: field:sale.order,exceptions_ids:0 |
381 | +msgid "Exceptions" |
382 | +msgstr "" |
383 | + |
384 | +#. module: sale_exceptions |
385 | +#: model:ir.actions.act_window,name:sale_exceptions.action_sale_exception_confirm |
386 | +#: model:ir.model,name:sale_exceptions.model_sale_exception |
387 | +#: view:sale.exception.confirm:0 |
388 | +msgid "Sale Exceptions" |
389 | +msgstr "" |
390 | + |
391 | +#. module: sale_exceptions |
392 | +#: model:ir.actions.act_window,name:sale_exceptions.action_sale_test_tree |
393 | +#: model:ir.ui.menu,name:sale_exceptions.menu_sale_test |
394 | +msgid "Exception Rules" |
395 | +msgstr "" |
396 | + |
397 | +#. module: sale_exceptions |
398 | +#: model:ir.model,name:sale_exceptions.model_sale_order |
399 | +msgid "Sales Order" |
400 | +msgstr "" |
401 | + |
402 | +#. module: sale_exceptions |
403 | +#: field:sale.exception,sequence:0 |
404 | +msgid "Sequence" |
405 | +msgstr "" |
406 | + |
407 | +#. module: sale_exceptions |
408 | +#: field:sale.exception,code:0 |
409 | +msgid "Python Code" |
410 | +msgstr "" |
411 | + |
412 | +#. module: sale_exceptions |
413 | +#: view:sale.order:0 |
414 | +msgid "Sales" |
415 | +msgstr "" |
416 | + |
417 | +#. module: sale_exceptions |
418 | +#: model:sale.exception,name:sale_exceptions.excep_no_zip |
419 | +msgid "No ZIP code on destination" |
420 | +msgstr "" |
421 | + |
422 | +#. module: sale_exceptions |
423 | +#: view:sale.exception:0 |
424 | +msgid "Sale Exception Setup" |
425 | +msgstr "" |
426 | + |
427 | +#. module: sale_exceptions |
428 | +#: view:sale.exception:0 |
429 | +msgid "Affected Sales Orders" |
430 | +msgstr "" |
431 | + |
432 | +#. module: sale_exceptions |
433 | +#: field:sale.exception,sale_order_ids:0 |
434 | +msgid "Sale Orders" |
435 | +msgstr "" |
436 | + |
437 | +#. module: sale_exceptions |
438 | +#: field:sale.exception.confirm,ignore:0 |
439 | +#: field:sale.order,ignore_exceptions:0 |
440 | +msgid "Ignore Exceptions" |
441 | +msgstr "" |
442 | + |
443 | +#. module: sale_exceptions |
444 | +#: field:sale.order,main_exception_id:0 |
445 | +msgid "Main Exception" |
446 | +msgstr "" |
447 | + |
448 | |
449 | === added file 'sale_exceptions/sale.py' |
450 | --- sale_exceptions/sale.py 1970-01-01 00:00:00 +0000 |
451 | +++ sale_exceptions/sale.py 2013-11-15 12:55:43 +0000 |
452 | @@ -0,0 +1,236 @@ |
453 | +# -*- coding: utf-8 -*- |
454 | +############################################################################## |
455 | +# |
456 | +# OpenERP, Open Source Management Solution |
457 | +# Copyright (C) 2011 Akretion LTDA. |
458 | +# Copyright (C) 2010-2012 Akretion Sébastien BEAU <sebastien.beau@akretion.com> |
459 | +# Copyright (C) 2012 Camptocamp SA (Guewen Baconnier) |
460 | +# |
461 | +# This program is free software: you can redistribute it and/or modify |
462 | +# it under the terms of the GNU Affero General Public License as |
463 | +# published by the Free Software Foundation, either version 3 of the |
464 | +# License, or (at your option) any later version. |
465 | +# |
466 | +# This program is distributed in the hope that it will be useful, |
467 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
468 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
469 | +# GNU Affero General Public License for more details. |
470 | +# |
471 | +# You should have received a copy of the GNU Affero General Public License |
472 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
473 | +# |
474 | +############################################################################## |
475 | + |
476 | +import time |
477 | + |
478 | +from openerp.osv import orm, fields |
479 | +from openerp.tools.safe_eval import safe_eval |
480 | +from openerp.tools.translate import _ |
481 | + |
482 | + |
483 | +class sale_exception(orm.Model): |
484 | + _name = "sale.exception" |
485 | + _description = "Sale Exceptions" |
486 | + _order = "active desc, sequence asc" |
487 | + _columns = { |
488 | + 'name': fields.char('Exception Name', required=True, translate=True), |
489 | + 'description': fields.text('Description', translate=True), |
490 | + 'sequence': fields.integer( |
491 | + 'Sequence', |
492 | + help="Gives the sequence order when applying the test"), |
493 | + 'model': fields.selection([('sale.order', 'Sale Order'), |
494 | + ('sale.order.line', 'Sale Order Line')], |
495 | + string='Apply on', required=True), |
496 | + 'active': fields.boolean('Active'), |
497 | + 'code': fields.text( |
498 | + 'Python Code', |
499 | + help="Python code executed to check if the exception apply or not. " |
500 | + "The code must apply block = True to apply the exception."), |
501 | + 'sale_order_ids': fields.many2many( |
502 | + 'sale.order', |
503 | + 'sale_order_exception_rel', 'exception_id', 'sale_order_id', |
504 | + string='Sale Orders', |
505 | + readonly=True), |
506 | + } |
507 | + |
508 | + _defaults = { |
509 | + 'code': """# Python code. Use failed = True to block the sale order. |
510 | +# You can use the following variables : |
511 | +# - self: ORM model of the record which is checked |
512 | +# - order or line: browse_record of the sale order or sale order line |
513 | +# - object: same as order or line, browse_record of the sale order or sale order line |
514 | +# - pool: ORM model pool (i.e. self.pool) |
515 | +# - time: Python time module |
516 | +# - cr: database cursor |
517 | +# - uid: current user id |
518 | +# - context: current context |
519 | +""" |
520 | + } |
521 | + |
522 | + |
523 | +class sale_order(orm.Model): |
524 | + _inherit = "sale.order" |
525 | + |
526 | + _order = 'main_exception_id asc, date_order desc, name desc' |
527 | + |
528 | + def _get_main_error(self, cr, uid, ids, name, args, context=None): |
529 | + res = {} |
530 | + for sale_order in self.browse(cr, uid, ids, context=context): |
531 | + if sale_order.state == 'draft' and sale_order.exceptions_ids: |
532 | + res[sale_order.id] = sale_order.exceptions_ids[0].id |
533 | + else: |
534 | + res[sale_order.id] = False |
535 | + return res |
536 | + |
537 | + _columns = { |
538 | + 'main_exception_id': fields.function( |
539 | + _get_main_error, |
540 | + type='many2one', |
541 | + relation="sale.exception", |
542 | + string='Main Exception', |
543 | + store={ |
544 | + 'sale.order': (lambda self, cr, uid, ids, c=None: ids, |
545 | + ['exceptions_ids', 'state'], 10), |
546 | + }), |
547 | + 'exceptions_ids': fields.many2many( |
548 | + 'sale.exception', |
549 | + 'sale_order_exception_rel', 'sale_order_id', 'exception_id', |
550 | + string='Exceptions'), |
551 | + 'ignore_exceptions': fields.boolean('Ignore Exceptions'), |
552 | + } |
553 | + |
554 | + def test_all_draft_orders(self, cr, uid, context=None): |
555 | + ids = self.search(cr, uid, [('state', '=', 'draft')], context=context) |
556 | + self.test_exceptions(cr, uid, ids, context=context) |
557 | + return True |
558 | + |
559 | + def _popup_exceptions(self, cr, uid, order_id, context=None): |
560 | + if context is None: |
561 | + context = {} |
562 | + model_data_obj = self.pool.get('ir.model.data') |
563 | + list_obj = self.pool.get('sale.exception.confirm') |
564 | + ctx = context.copy() |
565 | + ctx.update({'active_id': order_id, |
566 | + 'active_ids': [order_id]}) |
567 | + list_id = list_obj.create(cr, uid, {}, context=ctx) |
568 | + view_id = model_data_obj.get_object_reference( |
569 | + cr, uid, 'sale_exceptions', 'view_sale_exception_confirm')[1] |
570 | + action = { |
571 | + 'name': _("Blocked in draft due to exceptions"), |
572 | + 'type': 'ir.actions.act_window', |
573 | + 'view_type': 'form', |
574 | + 'view_mode': 'form', |
575 | + 'res_model': 'sale.exception.confirm', |
576 | + 'view_id': [view_id], |
577 | + 'target': 'new', |
578 | + 'nodestroy': True, |
579 | + 'res_id': list_id, |
580 | + } |
581 | + return action |
582 | + |
583 | + def action_button_confirm(self, cr, uid, ids, context=None): |
584 | + exception_ids = self.detect_exceptions(cr, uid, ids, context=context) |
585 | + if exception_ids: |
586 | + return self._popup_exceptions(cr, uid, ids[0], context=context) |
587 | + else: |
588 | + return super(sale_order, self).action_button_confirm(cr, uid, ids, |
589 | + context=context) |
590 | + |
591 | + def test_exceptions(self, cr, uid, ids, context=None): |
592 | + """ |
593 | + Condition method for the workflow from draft to confirm |
594 | + """ |
595 | + exception_ids = self.detect_exceptions(cr, uid, ids, context=context) |
596 | + if exception_ids: |
597 | + return False |
598 | + return True |
599 | + |
600 | + def detect_exceptions(self, cr, uid, ids, context=None): |
601 | + exception_obj = self.pool.get('sale.exception') |
602 | + order_exception_ids = exception_obj.search( |
603 | + cr, uid, |
604 | + [('model', '=', 'sale.order')], |
605 | + context=context) |
606 | + line_exception_ids = exception_obj.search( |
607 | + cr, uid, |
608 | + [('model', '=', 'sale.order.line')], |
609 | + context=context) |
610 | + |
611 | + order_exceptions = exception_obj.browse(cr, uid, order_exception_ids, |
612 | + context=context) |
613 | + line_exceptions = exception_obj.browse(cr, uid, line_exception_ids, |
614 | + context=context) |
615 | + |
616 | + exception_ids = False |
617 | + for order in self.browse(cr, uid, ids, context=context): |
618 | + if order.ignore_exceptions: |
619 | + continue |
620 | + exception_ids = self._detect_exceptions(cr, uid, |
621 | + order, |
622 | + order_exceptions, |
623 | + line_exceptions, |
624 | + context=context) |
625 | + |
626 | + self.write(cr, uid, [order.id], |
627 | + {'exceptions_ids': [(6, 0, exception_ids)]}, |
628 | + context=context) |
629 | + return exception_ids |
630 | + |
631 | + def _exception_rule_eval_context(self, cr, uid, obj_name, obj, context=None): |
632 | + if context is None: |
633 | + context = {} |
634 | + |
635 | + user = self.pool.get('res.users').browse(cr, uid, uid, context=context) |
636 | + return {obj_name: obj, |
637 | + 'self': self.pool.get(obj._name), |
638 | + 'object': obj, |
639 | + 'obj': obj, |
640 | + 'pool': self.pool, |
641 | + 'cr': cr, |
642 | + 'uid': uid, |
643 | + 'user': user, |
644 | + 'time': time, |
645 | + # copy context to prevent side-effects of eval |
646 | + 'context': context.copy()} |
647 | + |
648 | + def _rule_eval(self, cr, uid, rule, obj_name, obj, context): |
649 | + expr = rule.code |
650 | + space = self._exception_rule_eval_context(cr, uid, obj_name, obj, |
651 | + context=context) |
652 | + try: |
653 | + safe_eval(expr, |
654 | + space, |
655 | + mode='exec', |
656 | + nocopy=True) # nocopy allows to return 'result' |
657 | + except Exception, e: |
658 | + raise orm.except_orm( |
659 | + _('Error'), |
660 | + _('Error when evaluating the sale exception ' |
661 | + 'rule:\n %s \n(%s)') % (rule.name, e)) |
662 | + return space.get('failed', False) |
663 | + |
664 | + def _detect_exceptions(self, cr, uid, order, order_exceptions, |
665 | + line_exceptions, context=None): |
666 | + exception_ids = [] |
667 | + for rule in order_exceptions: |
668 | + if self._rule_eval(cr, uid, rule, 'order', order, context): |
669 | + exception_ids.append(rule.id) |
670 | + |
671 | + for order_line in order.order_line: |
672 | + for rule in line_exceptions: |
673 | + if rule.id in exception_ids: |
674 | + # we do not matter if the exception as already been |
675 | + # found for an order line of this order |
676 | + continue |
677 | + if self._rule_eval(cr, uid, rule, 'line', order_line, context): |
678 | + exception_ids.append(rule.id) |
679 | + |
680 | + return exception_ids |
681 | + |
682 | + def copy(self, cr, uid, id, default=None, context=None): |
683 | + if default is None: |
684 | + default = {} |
685 | + default.update({ |
686 | + 'ignore_exceptions': False, |
687 | + }) |
688 | + return super(sale_order, self).copy(cr, uid, id, default=default, context=context) |
689 | |
690 | === added file 'sale_exceptions/sale_exceptions_data.xml' |
691 | --- sale_exceptions/sale_exceptions_data.xml 1970-01-01 00:00:00 +0000 |
692 | +++ sale_exceptions/sale_exceptions_data.xml 2013-11-15 12:55:43 +0000 |
693 | @@ -0,0 +1,19 @@ |
694 | +<?xml version="1.0" encoding="utf-8"?> |
695 | +<openerp> |
696 | + <data noupdate="1"> |
697 | + |
698 | + <record forcecreate="True" id="ir_cron_test_orders" model="ir.cron"> |
699 | + <field name="name">Test Draft Orders</field> |
700 | + <field eval="False" name="active"/> |
701 | + <field name="user_id" ref="base.user_root"/> |
702 | + <field name="interval_number">20</field> |
703 | + <field name="interval_type">minutes</field> |
704 | + <field name="numbercall">-1</field> |
705 | + <field eval="False" name="doall"/> |
706 | + <field eval="'sale.order'" name="model"/> |
707 | + <field eval="'test_all_draft_orders'" name="function"/> |
708 | + <field eval="'()'" name="args"/> |
709 | + </record> |
710 | + |
711 | + </data> |
712 | +</openerp> |
713 | |
714 | === added file 'sale_exceptions/sale_view.xml' |
715 | --- sale_exceptions/sale_view.xml 1970-01-01 00:00:00 +0000 |
716 | +++ sale_exceptions/sale_view.xml 2013-11-15 12:55:43 +0000 |
717 | @@ -0,0 +1,102 @@ |
718 | +<?xml version="1.0" ?> |
719 | +<openerp> |
720 | + <data> |
721 | + |
722 | + <record id="view_sale_exception_tree" model="ir.ui.view"> |
723 | + <field name="name">sale.exception.tree</field> |
724 | + <field name="model">sale.exception</field> |
725 | + <field name="arch" type="xml"> |
726 | + <tree string="Sale Exception"> |
727 | + <field name="active"/> |
728 | + <field name="name"/> |
729 | + <field name="description"/> |
730 | + <field name="model"/> |
731 | + <field name="sequence"/> |
732 | + </tree> |
733 | + </field> |
734 | + </record> |
735 | + |
736 | + <record id="view_sale_exception_form" model="ir.ui.view"> |
737 | + <field name="name">sale.exception.form</field> |
738 | + <field name="model">sale.exception</field> |
739 | + <field name="arch" type="xml"> |
740 | + <form string="Sale Exception Setup"> |
741 | + <group colspan="4" col="2"> |
742 | + <field name="name"/> |
743 | + <field name="description"/> |
744 | + </group> |
745 | + <group col="4" colspan="4" groups="base.group_sale_manager"> |
746 | + <field name="active"/> |
747 | + <field name="sequence"/> |
748 | + <group colspan="4" col="2" groups="base.group_system"> |
749 | + <field name="model"/> |
750 | + <field name="code"/> |
751 | + </group> |
752 | + </group> |
753 | + <group colspan="4" col="2"> |
754 | + <separator string="Affected Sales Orders"/> |
755 | + <newline/> |
756 | + <field name="sale_order_ids" nolabel="1" domain="[('state', '=', 'draft')]"/> |
757 | + </group> |
758 | + </form> |
759 | + </field> |
760 | + </record> |
761 | + |
762 | + <record id="action_sale_test_tree" model="ir.actions.act_window"> |
763 | + <field name="name">Exception Rules</field> |
764 | + <field name="res_model">sale.exception</field> |
765 | + <field name="view_type">form</field> |
766 | + <field name="view_mode">tree,form</field> |
767 | + <field name="view_id" ref="view_sale_exception_tree"/> |
768 | + <field name="context">{'active_test': False}</field> |
769 | + </record> |
770 | + |
771 | + <menuitem action="action_sale_test_tree" id="menu_sale_test" parent="base.menu_sale_config_sales" /> |
772 | + |
773 | + |
774 | + <record id="view_order_form" model="ir.ui.view"> |
775 | + <field name="name">sale_exceptions.view_order_form</field> |
776 | + <field name="model">sale.order</field> |
777 | + <field name="inherit_id" ref="sale.view_order_form"/> |
778 | + <field name="arch" type="xml"> |
779 | + <field name="name" position="after"> |
780 | + <group> |
781 | + <field name="main_exception_id" options='{"no_open": True}' |
782 | + class="oe_inline" string="Error:" |
783 | + attrs="{'invisible':[('main_exception_id','=', False)]}"/> |
784 | + </group> |
785 | + </field> |
786 | + <xpath expr="//page[@string='Other Information']/group" |
787 | + position="inside"> |
788 | + <group name="exception" colspan="2" col="2"> |
789 | + <separator string="Exception" colspan="2"/> |
790 | + <field name="exceptions_ids" colspan="2" nolabel="1"/> |
791 | + </group> |
792 | + </xpath> |
793 | + </field> |
794 | + </record> |
795 | + |
796 | + <record id="view_order_tree" model="ir.ui.view"> |
797 | + <field name="name">sale_exceptions.view_order_tree</field> |
798 | + <field name="model">sale.order</field> |
799 | + <field name="inherit_id" ref="sale.view_order_tree"/> |
800 | + <field name="arch" type="xml"> |
801 | + <field name="state" position="after"> |
802 | + <field name="main_exception_id"/> |
803 | + </field> |
804 | + </field> |
805 | + </record> |
806 | + |
807 | + <record id="view_sales_order_filter" model="ir.ui.view"> |
808 | + <field name="name">sale_exceptions.view_sales_order_filter</field> |
809 | + <field name="model">sale.order</field> |
810 | + <field name="inherit_id" ref="sale.view_sales_order_filter" /> |
811 | + <field name="arch" type="xml"> |
812 | + <filter name="sales" position="after"> |
813 | + <separator orientation="vertical"/> |
814 | + <filter icon="terp-emblem-important" name="tofix" string="Blocked in draft" domain="[('main_exception_id','!=',False)]"/> |
815 | + </filter> |
816 | + </field> |
817 | + </record> |
818 | + </data> |
819 | +</openerp> |
820 | |
821 | === added file 'sale_exceptions/sale_workflow.xml' |
822 | --- sale_exceptions/sale_workflow.xml 1970-01-01 00:00:00 +0000 |
823 | +++ sale_exceptions/sale_workflow.xml 2013-11-15 12:55:43 +0000 |
824 | @@ -0,0 +1,9 @@ |
825 | +<?xml version="1.0" encoding="utf-8"?> |
826 | +<openerp> |
827 | + <data> |
828 | + <record id="sale.trans_draft_router" model="workflow.transition"> |
829 | + <field name="signal">order_confirm</field> |
830 | + <field name="condition">test_exceptions()</field> |
831 | + </record> |
832 | + </data> |
833 | +</openerp> |
834 | |
835 | === added directory 'sale_exceptions/security' |
836 | === added file 'sale_exceptions/security/ir.model.access.csv' |
837 | --- sale_exceptions/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
838 | +++ sale_exceptions/security/ir.model.access.csv 2013-11-15 12:55:43 +0000 |
839 | @@ -0,0 +1,3 @@ |
840 | +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" |
841 | +"access_sale_exception","sale.exception","model_sale_exception","base.group_user",1,0,0,0 |
842 | +"access_sale_exception_manager","sale.exception","model_sale_exception","base.group_sale_manager",1,1,1,1 |
843 | |
844 | === added directory 'sale_exceptions/settings' |
845 | === added file 'sale_exceptions/settings/sale.exception.csv' |
846 | --- sale_exceptions/settings/sale.exception.csv 1970-01-01 00:00:00 +0000 |
847 | +++ sale_exceptions/settings/sale.exception.csv 2013-11-15 12:55:43 +0000 |
848 | @@ -0,0 +1,5 @@ |
849 | +"id","name","description","sequence","model","code","active" |
850 | +"excep_no_zip","No ZIP code on destination",,50,"sale.order","if not order.partner_shipping_id.zip: |
851 | + failed=True",False |
852 | +"excep_no_stock","Not Enough Virtual Stock",,50,"sale.order.line","if line.product_id and line.product_id.type == 'product' and line.product_id.virtual_available < line.product_uom_qty: |
853 | + failed=True",False |
854 | |
855 | === added directory 'sale_exceptions/wizard' |
856 | === added file 'sale_exceptions/wizard/__init__.py' |
857 | --- sale_exceptions/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
858 | +++ sale_exceptions/wizard/__init__.py 2013-11-15 12:55:43 +0000 |
859 | @@ -0,0 +1,24 @@ |
860 | +# -*- coding: utf-8 -*- |
861 | +############################################################################## |
862 | +# |
863 | +# OpenERP, Open Source Management Solution |
864 | +# Copyright (C) 2011 Akretion LTDA. |
865 | +# authors: Raphaël Valyi, Renato Lima |
866 | +# Copyright (C) 2010-2012 Akretion Sébastien BEAU <sebastien.beau@akretion.com> |
867 | +# Copyright (C) 2012 Camptocamp SA (Guewen Baconnier) |
868 | +# |
869 | +# This program is free software: you can redistribute it and/or modify |
870 | +# it under the terms of the GNU Affero General Public License as |
871 | +# published by the Free Software Foundation, either version 3 of the |
872 | +# License, or (at your option) any later version. |
873 | +# |
874 | +# This program is distributed in the hope that it will be useful, |
875 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
876 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
877 | +# GNU Affero General Public License for more details. |
878 | +# |
879 | +# You should have received a copy of the GNU Affero General Public License |
880 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
881 | +# |
882 | +############################################################################## |
883 | +from . import sale_exception_confirm |
884 | |
885 | === added file 'sale_exceptions/wizard/sale_exception_confirm.py' |
886 | --- sale_exceptions/wizard/sale_exception_confirm.py 1970-01-01 00:00:00 +0000 |
887 | +++ sale_exceptions/wizard/sale_exception_confirm.py 2013-11-15 12:55:43 +0000 |
888 | @@ -0,0 +1,62 @@ |
889 | +# -*- coding: utf-8 -*- |
890 | +############################################################################## |
891 | +# |
892 | +# Copyright Camptocamp SA |
893 | +# @author: Guewen Baconnier |
894 | +# |
895 | +# This program is free software: you can redistribute it and/or modify |
896 | +# it under the terms of the GNU General Public License as published by |
897 | +# the Free Software Foundation, either version 3 of the License, or |
898 | +# (at your option) any later version. |
899 | +# |
900 | +# This program is distributed in the hope that it will be useful, |
901 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
902 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
903 | +# GNU General Public License for more details. |
904 | +# |
905 | +# You should have received a copy of the GNU General Public License |
906 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
907 | +# |
908 | +############################################################################## |
909 | +from openerp.osv import orm, fields |
910 | + |
911 | + |
912 | +class SaleExceptionConfirm(orm.TransientModel): |
913 | + |
914 | + _name = 'sale.exception.confirm' |
915 | + |
916 | + _columns = { |
917 | + 'sale_id': fields.many2one('sale.order', 'Sale'), |
918 | + 'exception_ids': fields.many2many('sale.exception', |
919 | + string='Exceptions to resolve', |
920 | + readonly=True), |
921 | + 'ignore': fields.boolean('Ignore Exceptions'), |
922 | + } |
923 | + |
924 | + def default_get(self, cr, uid, fields, context=None): |
925 | + if context is None: |
926 | + context = {} |
927 | + res = super(SaleExceptionConfirm, self).default_get( |
928 | + cr, uid, fields, context=context) |
929 | + order_obj = self.pool.get('sale.order') |
930 | + sale_id = context.get('active_ids') |
931 | + assert len(sale_id) == 1, "Only 1 ID accepted, got %r" % sale_id |
932 | + sale_id = sale_id[0] |
933 | + sale = order_obj.browse(cr, uid, sale_id, context=context) |
934 | + exception_ids = [e.id for e in sale.exceptions_ids] |
935 | + res.update({'exception_ids': [(6, 0, exception_ids)]}) |
936 | + res.update({'sale_id': sale_id}) |
937 | + return res |
938 | + |
939 | + def action_confirm(self, cr, uid, ids, context=None): |
940 | + if hasattr(ids, '__iter__'): |
941 | + assert len(ids) == 1, "Only 1 ID accepted, got %r" % ids |
942 | + ids = ids[0] |
943 | + form = self.browse(cr, uid, ids, context=context) |
944 | + if form.ignore: |
945 | + self.pool.get('sale.order').write( |
946 | + cr, uid, |
947 | + form.sale_id.id, |
948 | + {'ignore_exceptions': True}, |
949 | + context=context) |
950 | + return {'type': 'ir.actions.act_window_close'} |
951 | |
952 | === added file 'sale_exceptions/wizard/sale_exception_confirm_view.xml' |
953 | --- sale_exceptions/wizard/sale_exception_confirm_view.xml 1970-01-01 00:00:00 +0000 |
954 | +++ sale_exceptions/wizard/sale_exception_confirm_view.xml 2013-11-15 12:55:43 +0000 |
955 | @@ -0,0 +1,39 @@ |
956 | +<?xml version="1.0" encoding="utf-8"?> |
957 | +<openerp> |
958 | + <data> |
959 | + |
960 | + <record id="view_sale_exception_confirm" model="ir.ui.view"> |
961 | + <field name="name">Sale Exceptions</field> |
962 | + <field name="model">sale.exception.confirm</field> |
963 | + <field name="arch" type="xml"> |
964 | + <form string="Blocked in draft due to exceptions" version="7.0"> |
965 | + <group> |
966 | + <field name="exception_ids" nolabel="1" colspan="4"> |
967 | + <tree string="Sale Exceptions"> |
968 | + <field name="name"/> |
969 | + <field name="description"/> |
970 | + </tree> |
971 | + </field> |
972 | + <newline/> |
973 | + <field name="ignore" groups='base.group_sale_manager'/> |
974 | + </group> |
975 | + <footer> |
976 | + <button name="action_confirm" string="_Close" |
977 | + colspan="1" type="object" icon="gtk-ok" /> |
978 | + </footer> |
979 | + </form> |
980 | + </field> |
981 | + </record> |
982 | + |
983 | + <record id="action_sale_exception_confirm" model="ir.actions.act_window"> |
984 | + <field name="name">Blocked in draft due to exceptions</field> |
985 | + <field name="type">ir.actions.act_window</field> |
986 | + <field name="res_model">sale.exception.confirm</field> |
987 | + <field name="view_type">form</field> |
988 | + <field name="view_mode">form</field> |
989 | + <field name="view_id" ref="view_sale_exception_confirm"/> |
990 | + <field name="target">new</field> |
991 | + </record> |
992 | + |
993 | + </data> |
994 | +</openerp> |
As your reasoning on community list, I approve it blindly.
Regards.