Merge lp:~akretion-team/stock-logistic-flows/stock-logistic-flows-61-product_serial into lp:stock-logistic-flows/6.1
- stock-logistic-flows-61-product_serial
- Merge into 6.1
Proposed by
Sébastien BEAU - http://www.akretion.com
Status: | Merged |
---|---|
Approved by: | Alexandre Fayolle - camptocamp |
Approved revision: | 57 |
Merged at revision: | 24 |
Proposed branch: | lp:~akretion-team/stock-logistic-flows/stock-logistic-flows-61-product_serial |
Merge into: | lp:stock-logistic-flows/6.1 |
Diff against target: |
1355 lines (+1289/-0) 13 files modified
product_serial/__init__.py (+26/-0) product_serial/__openerp__.py (+47/-0) product_serial/company.py (+39/-0) product_serial/company_view.xml (+21/-0) product_serial/i18n/es.po (+140/-0) product_serial/i18n/fr_BE.po (+75/-0) product_serial/i18n/mrp_prodlot_autosplit.pot (+75/-0) product_serial/i18n/sv.po (+96/-0) product_serial/prodlot_wizard.py (+119/-0) product_serial/product.py (+37/-0) product_serial/product_view.xml (+18/-0) product_serial/stock.py (+297/-0) product_serial/stock_view.xml (+299/-0) |
To merge this branch: | bzr merge lp:~akretion-team/stock-logistic-flows/stock-logistic-flows-61-product_serial |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexis de Lattre (community) | code review and tests | Approve | |
Alexandre Fayolle - camptocamp | code review, no test | Approve | |
Review via email: mp+162974@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote : | # |
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
LGTM
review:
Approve
(code review, no test)
Revision history for this message
Alexis de Lattre (alexis-via) wrote : | # |
I have checked that the extraction from extra-6.0 is OK and that it works well on OpenERP 6.1. So it's ok to merge.
review:
Approve
(code review and tests)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'product_serial' |
2 | === added file 'product_serial/__init__.py' |
3 | --- product_serial/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ product_serial/__init__.py 2013-05-08 13:17:25 +0000 |
5 | @@ -0,0 +1,26 @@ |
6 | +# -*- encoding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# Product serial module for OpenERP |
10 | +# Copyright (C) 2008 Raphaël Valyi |
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 | +import product |
28 | +import stock |
29 | +import company |
30 | +import prodlot_wizard |
31 | + |
32 | |
33 | === added file 'product_serial/__openerp__.py' |
34 | --- product_serial/__openerp__.py 1970-01-01 00:00:00 +0000 |
35 | +++ product_serial/__openerp__.py 2013-05-08 13:17:25 +0000 |
36 | @@ -0,0 +1,47 @@ |
37 | +# -*- encoding: utf-8 -*- |
38 | +############################################################################## |
39 | +# |
40 | +# Copyright (C) 2008 Raphaël Valyi |
41 | +# |
42 | +# This program is free software: you can redistribute it and/or modify |
43 | +# it under the terms of the GNU Affero General Public License as |
44 | +# published by the Free Software Foundation, either version 3 of the |
45 | +# License, or (at your option) any later version. |
46 | +# |
47 | +# This program is distributed in the hope that it will be useful, |
48 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
49 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
50 | +# GNU Affero General Public License for more details. |
51 | +# |
52 | +# You should have received a copy of the GNU Affero General Public License |
53 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
54 | +# |
55 | +############################################################################## |
56 | + |
57 | +{ |
58 | + "name" : "Unique serial number management", |
59 | + "version" : "1.0.0", |
60 | + "author" : "Akretion, NaN·tic", |
61 | + "website" : "http://www.akretion.com", |
62 | + "depends" : ['stock'], |
63 | + "category" : "Generic Modules/Inventory Control", |
64 | + "license": "AGPL-3", |
65 | + "description":"""Turns production lot tracking numbers into unique per product instance code (serial number). |
66 | + Moreover, it |
67 | + 1) adds a new selection field on the product form to enable or disable this behavior and with split type choice (you should also enable in/out tracking) |
68 | + 2) then forbids to perform a move if a move involves more than one product instance |
69 | + 3) automagically splits up picking list movements into one movement per product instance or logistical unit packing qty (in that case, only the first LU is taken into account at the present time. Improvement to take them all to be done !!!) |
70 | + 4) turns incoming pickings into an editable grid where you can directly type the codes |
71 | + of a new production and tracking number/code to create and associate to the move (it also checks it |
72 | + doesn't exist yet) |
73 | + |
74 | + We would also like to extend this module to split automatic production orders (from MRP engine) into several individual production orders in order |
75 | + to make it easy to encode the serial numbers in the production. Let us know if you would like that simple extension to be made. |
76 | + """, |
77 | + "init_xml" : [], |
78 | + "demo_xml" : [], |
79 | + "update_xml" : ["product_view.xml", "company_view.xml", "stock_view.xml"], |
80 | + "active": False, |
81 | + "installable": True |
82 | +} |
83 | + |
84 | |
85 | === added file 'product_serial/company.py' |
86 | --- product_serial/company.py 1970-01-01 00:00:00 +0000 |
87 | +++ product_serial/company.py 2013-05-08 13:17:25 +0000 |
88 | @@ -0,0 +1,39 @@ |
89 | +# -*- encoding: utf-8 -*- |
90 | +############################################################################## |
91 | +# |
92 | +# Product serial module for OpenERP |
93 | +# Copyright (C) 2010-2011 Anevia. All Rights Reserved |
94 | +# (written by Sebastien Beau <sebastien.beau@akretion.com>) |
95 | +# |
96 | +# This program is free software: you can redistribute it and/or modify |
97 | +# it under the terms of the GNU Affero General Public License as |
98 | +# published by the Free Software Foundation, either version 3 of the |
99 | +# License, or (at your option) any later version. |
100 | +# |
101 | +# This program is distributed in the hope that it will be useful, |
102 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
103 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
104 | +# GNU Affero General Public License for more details. |
105 | +# |
106 | +# You should have received a copy of the GNU Affero General Public License |
107 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
108 | +# |
109 | +############################################################################## |
110 | + |
111 | +from osv import osv, fields |
112 | + |
113 | +class company(osv.osv): |
114 | + _inherit = 'res.company' |
115 | + |
116 | + _columns = { |
117 | + 'autosplit_is_active': fields.boolean('Active auto split', help="Active the automatic split of move lines on the pickings."), |
118 | + 'is_group_invoice_line': fields.boolean('Group invoice lines', help="If active, OpenERP will group the identical invoice lines. If inactive, each move line will generate one invoice line."), |
119 | + } |
120 | + |
121 | + _defaults = { |
122 | + 'autosplit_is_active': lambda *a: True, |
123 | + 'is_group_invoice_line': lambda *a: True, |
124 | + } |
125 | + |
126 | +company() |
127 | + |
128 | |
129 | === added file 'product_serial/company_view.xml' |
130 | --- product_serial/company_view.xml 1970-01-01 00:00:00 +0000 |
131 | +++ product_serial/company_view.xml 2013-05-08 13:17:25 +0000 |
132 | @@ -0,0 +1,21 @@ |
133 | +<?xml version="1.0" ?> |
134 | +<openerp> |
135 | + <data> |
136 | + |
137 | + <record id="autosplit_company" model="ir.ui.view"> |
138 | + <field name="name">res.company.autosplit.config</field> |
139 | + <field name="model">res.company</field> |
140 | + <field name="type">form</field> |
141 | + <field name="inherit_id" ref="base.view_company_form"/> |
142 | + <field name="arch" type="xml"> |
143 | + <page string="Configuration" position="inside"> |
144 | + <separator string="Product serial" colspan="4"/> |
145 | + <field name="autosplit_is_active"/> |
146 | + <field name="is_group_invoice_line"/> |
147 | + <newline/> |
148 | + </page> |
149 | + </field> |
150 | + </record> |
151 | + |
152 | + </data> |
153 | +</openerp> |
154 | |
155 | === added directory 'product_serial/i18n' |
156 | === added file 'product_serial/i18n/es.po' |
157 | --- product_serial/i18n/es.po 1970-01-01 00:00:00 +0000 |
158 | +++ product_serial/i18n/es.po 2013-05-08 13:17:25 +0000 |
159 | @@ -0,0 +1,140 @@ |
160 | +# Spanish translation for openobject-addons |
161 | +# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 |
162 | +# This file is distributed under the same license as the openobject-addons package. |
163 | +# FIRST AUTHOR <EMAIL@ADDRESS>, 2011. |
164 | +# |
165 | +msgid "" |
166 | +msgstr "" |
167 | +"Project-Id-Version: openobject-addons\n" |
168 | +"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n" |
169 | +"POT-Creation-Date: 2009-11-26 10:28+0000\n" |
170 | +"PO-Revision-Date: 2011-02-15 15:14+0000\n" |
171 | +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
172 | +"Language-Team: Spanish <es@li.org>\n" |
173 | +"MIME-Version: 1.0\n" |
174 | +"Content-Type: text/plain; charset=UTF-8\n" |
175 | +"Content-Transfer-Encoding: 8bit\n" |
176 | +"X-Launchpad-Export-Date: 2011-07-08 05:57+0000\n" |
177 | +"X-Generator: Launchpad (build 13168)\n" |
178 | + |
179 | +#. module: mrp_prodlot_autosplit |
180 | +#: field:product.product,unique_production_number:0 |
181 | +msgid "Unique Production Number" |
182 | +msgstr "Número de lote de producción único (número de serie)" |
183 | + |
184 | +#. module: mrp_prodlot_autosplit |
185 | +#: constraint:ir.ui.view:0 |
186 | +msgid "Invalid XML for View Architecture!" |
187 | +msgstr "¡XML no válido para la definición de la vista!" |
188 | + |
189 | +#. module: mrp_prodlot_autosplit |
190 | +#: model:ir.module.module,description:mrp_prodlot_autosplit.module_meta_information |
191 | +msgid "" |
192 | +"Turns production lot tracking numbers into unique per product instance code " |
193 | +"(serial number).\n" |
194 | +" Moreover, it\n" |
195 | +" 1) adds a new checkbox on the product form to enable or disable this " |
196 | +"behavior (you should also enable in/out tracking)\n" |
197 | +" 2) then forbids to perform a move if a move involves more than one " |
198 | +"product instance\n" |
199 | +" 3) automagically splits up picking list movements into one movement per " |
200 | +"product instance\n" |
201 | +" 4) turns incoming pickings into an editable grid where you can directly " |
202 | +"type the code\n" |
203 | +" of a new production number/code to create and associate to the move (it " |
204 | +"also checks it\n" |
205 | +" doesn't exist yet)\n" |
206 | +" \n" |
207 | +" Important Note 1: serial numbers are more easily encode using an " |
208 | +"editable tree grid, including a special field with new serial to be " |
209 | +"created.\n" |
210 | +" However, there is currently a limitation in the OpenObject framework " |
211 | +"preventing from easily changing non editable trees to editable trees\n" |
212 | +" by simple extension. Rather than overwriting all views, we prefer give " |
213 | +"only one example: the active customied view for easy serial encoding\n" |
214 | +" is available using Stock Management > Incoming Products. Looking that " |
215 | +"that view definition, the same thing is easily achieved in\n" |
216 | +" other picking list, like out going products for instance. However it's " |
217 | +"not \"on\" by default, you would need to work it out for your case.\n" |
218 | +" Meanwhile, we hope Tiny add a third \"merge_attributes\" view extension " |
219 | +"point to the 3 existing ones: \"before\", \"after\" and \"replace\".\n" |
220 | +" It would basically simply merge the attributes given (redefined) in the " |
221 | +"original view XML and let inner content unchanged.\n" |
222 | +" Blueprint is registred here: https://blueprints.launchpad.net/openobject-" |
223 | +"server/+spec/merge-attributes-view-extension-point\n" |
224 | +" \n" |
225 | +" Important Note 2: this module doesn't split product bill of materials in " |
226 | +"MRP since they don't use pickings\n" |
227 | +" A good workaround when generating production orders manually one by one " |
228 | +"is too define several lines of individual products in nomemclatures\n" |
229 | +" and produce 1 by 1 (if possible) to make it easier to encode unique " |
230 | +"prodlot in production orders too.\n" |
231 | +" We would also like to extend this module to split automatic production " |
232 | +"orders (from MRP engine) into several individual production orders in order\n" |
233 | +" to make it easy to encode the serial numbers in the production. Let us " |
234 | +"know if you would like that simple extension to be made.\n" |
235 | +" " |
236 | +msgstr "" |
237 | +"Convierte los números de lote en uno único por producto (número de serie)\n" |
238 | +" Más aún,\n" |
239 | +" 1) Añade una nueva casilla de verificación en el formulario de producto " |
240 | +"para activar o desactivar esta funcionalidad(debería también activar lotes " |
241 | +"en entrada/salida\n" |
242 | +" 2) Prohibe realizar un movimiento si el movimiento requiere más de una " |
243 | +"instancia de producto\n" |
244 | +" 3) Automágicamente desglosa la línea de movimientos para varios " |
245 | +"productos en un único movimiento por cada producto\n" |
246 | +" 4) Convierte los albaranes de entrada en una tabla editable donde puede " |
247 | +"directamente escribir el número de serie de un nuevo número de serie para " |
248 | +"crearlo y asociarlo al movimiento (también verifica que no exista antes)\n" |
249 | +"\n" |
250 | +" Importante Nota 1: Los número de serie se codifican mejor utilizando una " |
251 | +"tabla editable, que incluye un campo especial con el nuevo número de serie " |
252 | +"para ser creado. En cualquier caso hay actualmente una limitación en el " |
253 | +"framework de OpenObject que previene de cambiar fácilmente grids no " |
254 | +"editables a editables por una simple extensión. En vez de sobreescribir " |
255 | +"todas las vistas, preferimos dar un único ejemplo: La vista activa " |
256 | +"modificada para facilitar la codificación de números de serie está " |
257 | +"disponible utilizando Fabricación / productos entrantes. Buscando esta " |
258 | +"definción de la vista, esto mismo es fácilmente trasladable a otros " |
259 | +"albaranes, como por ejemplo los de salida. De todas formas no está activo " |
260 | +"por defecto, necesitaría trabajar con ello para su caso específico.\n" |
261 | +"Mientras tanto, esperamos que Tiny añada una tercera vista " |
262 | +"\"merge_attributes\" a los 3 existentes: \"antes\", \"despues\" y " |
263 | +"\"reemplazar\". Básicamente permitiría combinar los atributos dados " |
264 | +"(redefinidos) en la vista origial XML y dejar el contenido sin cambiar.\n" |
265 | +"La solicitud de mejora está registrada aquí: " |
266 | +"https://blueprints.launchpad.net/openobject-server/+spec/merge-attributes-" |
267 | +"view-extension-point\n" |
268 | +"\n" |
269 | +"Importante Nota 2: Este módulo no desglos la lista de materiales en MRP ya " |
270 | +"que no usa albaranes.\n" |
271 | +"Una buena aproximación al generar órdenes de fabricación manualmente una por " |
272 | +"una es definir varias líneas de productos individuales en nomenclaturas y " |
273 | +"producir uno a uno ( si es posible) para hacer más fácil la codificación de " |
274 | +"un único número de serie también en las órdenes de producción.\n" |
275 | +"También queremos extender este módulo para desglosar automáticamente órdenes " |
276 | +"de producción (desde el motor MRP) en varias órdenes individuales para " |
277 | +"faciliar la codificación de los números de serie en producción. Haznos saber " |
278 | +"si te gustaría que abordásemos el desarrollo de esta extensión.\n" |
279 | +" " |
280 | + |
281 | +#. module: mrp_prodlot_autosplit |
282 | +#: field:stock.production.lot,last_location_id:0 |
283 | +msgid "Last Location" |
284 | +msgstr "Última ubicación" |
285 | + |
286 | +#. module: mrp_prodlot_autosplit |
287 | +#: model:ir.module.module,shortdesc:mrp_prodlot_autosplit.module_meta_information |
288 | +msgid "Unique serial number management" |
289 | +msgstr "Gestión de número de serie único" |
290 | + |
291 | +#. module: mrp_prodlot_autosplit |
292 | +#: field:stock.move,new_prodlot_code:0 |
293 | +msgid "Production Tracking Code To Create" |
294 | +msgstr "Número de tracking de producción para crear" |
295 | + |
296 | +#. module: mrp_prodlot_autosplit |
297 | +#: view:stock.picking:0 |
298 | +msgid "Stock Moves" |
299 | +msgstr "Movimientos de stock" |
300 | |
301 | === added file 'product_serial/i18n/fr_BE.po' |
302 | --- product_serial/i18n/fr_BE.po 1970-01-01 00:00:00 +0000 |
303 | +++ product_serial/i18n/fr_BE.po 2013-05-08 13:17:25 +0000 |
304 | @@ -0,0 +1,75 @@ |
305 | +# Translation of OpenERP Server. |
306 | +# This file contains the translation of the following modules: |
307 | +# * mrp_prodlot_autosplit |
308 | +# |
309 | +msgid "" |
310 | +msgstr "" |
311 | +"Project-Id-Version: OpenERP Server 5.0.6\n" |
312 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
313 | +"POT-Creation-Date: 2009-11-26 10:28:43+0000\n" |
314 | +"PO-Revision-Date: 2009-11-26 10:28:43+0000\n" |
315 | +"Last-Translator: <>\n" |
316 | +"Language-Team: \n" |
317 | +"MIME-Version: 1.0\n" |
318 | +"Content-Type: text/plain; charset=UTF-8\n" |
319 | +"Content-Transfer-Encoding: \n" |
320 | +"Plural-Forms: \n" |
321 | + |
322 | +#. module: mrp_prodlot_autosplit |
323 | +#: field:product.product,unique_production_number:0 |
324 | +msgid "Unique Production Number" |
325 | +msgstr "" |
326 | + |
327 | +#. module: mrp_prodlot_autosplit |
328 | +#: constraint:ir.ui.view:0 |
329 | +msgid "Invalid XML for View Architecture!" |
330 | +msgstr "" |
331 | + |
332 | +#. module: mrp_prodlot_autosplit |
333 | +#: model:ir.module.module,description:mrp_prodlot_autosplit.module_meta_information |
334 | +msgid "Turns production lot tracking numbers into unique per product instance code (serial number).\n" |
335 | +" Moreover, it\n" |
336 | +" 1) adds a new checkbox on the product form to enable or disable this behavior (you should also enable in/out tracking)\n" |
337 | +" 2) then forbids to perform a move if a move involves more than one product instance\n" |
338 | +" 3) automagically splits up picking list movements into one movement per product instance\n" |
339 | +" 4) turns incoming pickings into an editable grid where you can directly type the code\n" |
340 | +" of a new production number/code to create and associate to the move (it also checks it\n" |
341 | +" doesn't exist yet)\n" |
342 | +" \n" |
343 | +" Important Note 1: serial numbers are more easily encode using an editable tree grid, including a special field with new serial to be created.\n" |
344 | +" However, there is currently a limitation in the OpenObject framework preventing from easily changing non editable trees to editable trees\n" |
345 | +" by simple extension. Rather than overwriting all views, we prefer give only one example: the active customied view for easy serial encoding\n" |
346 | +" is available using Stock Management > Incoming Products. Looking that that view definition, the same thing is easily achieved in\n" |
347 | +" other picking list, like out going products for instance. However it's not \"on\" by default, you would need to work it out for your case.\n" |
348 | +" Meanwhile, we hope Tiny add a third \"merge_attributes\" view extension point to the 3 existing ones: \"before\", \"after\" and \"replace\".\n" |
349 | +" It would basically simply merge the attributes given (redefined) in the original view XML and let inner content unchanged.\n" |
350 | +" Blueprint is registred here: https://blueprints.launchpad.net/openobject-server/+spec/merge-attributes-view-extension-point\n" |
351 | +" \n" |
352 | +" Important Note 2: this module doesn't split product bill of materials in MRP since they don't use pickings\n" |
353 | +" A good workaround when generating production orders manually one by one is too define several lines of individual products in nomemclatures\n" |
354 | +" and produce 1 by 1 (if possible) to make it easier to encode unique prodlot in production orders too.\n" |
355 | +" We would also like to extend this module to split automatic production orders (from MRP engine) into several individual production orders in order\n" |
356 | +" to make it easy to encode the serial numbers in the production. Let us know if you would like that simple extension to be made.\n" |
357 | +" " |
358 | +msgstr "" |
359 | + |
360 | +#. module: mrp_prodlot_autosplit |
361 | +#: field:stock.production.lot,last_location_id:0 |
362 | +msgid "Last Location" |
363 | +msgstr "" |
364 | + |
365 | +#. module: mrp_prodlot_autosplit |
366 | +#: model:ir.module.module,shortdesc:mrp_prodlot_autosplit.module_meta_information |
367 | +msgid "Unique serial number management" |
368 | +msgstr "" |
369 | + |
370 | +#. module: mrp_prodlot_autosplit |
371 | +#: field:stock.move,new_prodlot_code:0 |
372 | +msgid "Production Tracking Code To Create" |
373 | +msgstr "" |
374 | + |
375 | +#. module: mrp_prodlot_autosplit |
376 | +#: view:stock.picking:0 |
377 | +msgid "Stock Moves" |
378 | +msgstr "" |
379 | + |
380 | |
381 | === added file 'product_serial/i18n/mrp_prodlot_autosplit.pot' |
382 | --- product_serial/i18n/mrp_prodlot_autosplit.pot 1970-01-01 00:00:00 +0000 |
383 | +++ product_serial/i18n/mrp_prodlot_autosplit.pot 2013-05-08 13:17:25 +0000 |
384 | @@ -0,0 +1,75 @@ |
385 | +# Translation of OpenERP Server. |
386 | +# This file contains the translation of the following modules: |
387 | +# * mrp_prodlot_autosplit |
388 | +# |
389 | +msgid "" |
390 | +msgstr "" |
391 | +"Project-Id-Version: OpenERP Server 5.0.6\n" |
392 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
393 | +"POT-Creation-Date: 2009-11-26 10:28:43+0000\n" |
394 | +"PO-Revision-Date: 2009-11-26 10:28:43+0000\n" |
395 | +"Last-Translator: <>\n" |
396 | +"Language-Team: \n" |
397 | +"MIME-Version: 1.0\n" |
398 | +"Content-Type: text/plain; charset=UTF-8\n" |
399 | +"Content-Transfer-Encoding: \n" |
400 | +"Plural-Forms: \n" |
401 | + |
402 | +#. module: mrp_prodlot_autosplit |
403 | +#: field:product.product,unique_production_number:0 |
404 | +msgid "Unique Production Number" |
405 | +msgstr "" |
406 | + |
407 | +#. module: mrp_prodlot_autosplit |
408 | +#: constraint:ir.ui.view:0 |
409 | +msgid "Invalid XML for View Architecture!" |
410 | +msgstr "" |
411 | + |
412 | +#. module: mrp_prodlot_autosplit |
413 | +#: model:ir.module.module,description:mrp_prodlot_autosplit.module_meta_information |
414 | +msgid "Turns production lot tracking numbers into unique per product instance code (serial number).\n" |
415 | +" Moreover, it\n" |
416 | +" 1) adds a new checkbox on the product form to enable or disable this behavior (you should also enable in/out tracking)\n" |
417 | +" 2) then forbids to perform a move if a move involves more than one product instance\n" |
418 | +" 3) automagically splits up picking list movements into one movement per product instance\n" |
419 | +" 4) turns incoming pickings into an editable grid where you can directly type the code\n" |
420 | +" of a new production number/code to create and associate to the move (it also checks it\n" |
421 | +" doesn't exist yet)\n" |
422 | +" \n" |
423 | +" Important Note 1: serial numbers are more easily encode using an editable tree grid, including a special field with new serial to be created.\n" |
424 | +" However, there is currently a limitation in the OpenObject framework preventing from easily changing non editable trees to editable trees\n" |
425 | +" by simple extension. Rather than overwriting all views, we prefer give only one example: the active customied view for easy serial encoding\n" |
426 | +" is available using Stock Management > Incoming Products. Looking that that view definition, the same thing is easily achieved in\n" |
427 | +" other picking list, like out going products for instance. However it's not \"on\" by default, you would need to work it out for your case.\n" |
428 | +" Meanwhile, we hope Tiny add a third \"merge_attributes\" view extension point to the 3 existing ones: \"before\", \"after\" and \"replace\".\n" |
429 | +" It would basically simply merge the attributes given (redefined) in the original view XML and let inner content unchanged.\n" |
430 | +" Blueprint is registred here: https://blueprints.launchpad.net/openobject-server/+spec/merge-attributes-view-extension-point\n" |
431 | +" \n" |
432 | +" Important Note 2: this module doesn't split product bill of materials in MRP since they don't use pickings\n" |
433 | +" A good workaround when generating production orders manually one by one is too define several lines of individual products in nomemclatures\n" |
434 | +" and produce 1 by 1 (if possible) to make it easier to encode unique prodlot in production orders too.\n" |
435 | +" We would also like to extend this module to split automatic production orders (from MRP engine) into several individual production orders in order\n" |
436 | +" to make it easy to encode the serial numbers in the production. Let us know if you would like that simple extension to be made.\n" |
437 | +" " |
438 | +msgstr "" |
439 | + |
440 | +#. module: mrp_prodlot_autosplit |
441 | +#: field:stock.production.lot,last_location_id:0 |
442 | +msgid "Last Location" |
443 | +msgstr "" |
444 | + |
445 | +#. module: mrp_prodlot_autosplit |
446 | +#: model:ir.module.module,shortdesc:mrp_prodlot_autosplit.module_meta_information |
447 | +msgid "Unique serial number management" |
448 | +msgstr "" |
449 | + |
450 | +#. module: mrp_prodlot_autosplit |
451 | +#: field:stock.move,new_prodlot_code:0 |
452 | +msgid "Production Tracking Code To Create" |
453 | +msgstr "" |
454 | + |
455 | +#. module: mrp_prodlot_autosplit |
456 | +#: view:stock.picking:0 |
457 | +msgid "Stock Moves" |
458 | +msgstr "" |
459 | + |
460 | |
461 | === added file 'product_serial/i18n/sv.po' |
462 | --- product_serial/i18n/sv.po 1970-01-01 00:00:00 +0000 |
463 | +++ product_serial/i18n/sv.po 2013-05-08 13:17:25 +0000 |
464 | @@ -0,0 +1,96 @@ |
465 | +# Translation of OpenERP Server. |
466 | +# This file contains the translation of the following modules: |
467 | +# * mrp_prodlot_autosplit |
468 | +# |
469 | +msgid "" |
470 | +msgstr "" |
471 | +"Project-Id-Version: OpenERP Server 5.0.14\n" |
472 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
473 | +"POT-Creation-Date: 2009-11-26 10:28+0000\n" |
474 | +"PO-Revision-Date: 2011-02-15 15:14+0000\n" |
475 | +"Last-Translator: Olivier Dony (OpenERP) <Unknown>\n" |
476 | +"Language-Team: \n" |
477 | +"MIME-Version: 1.0\n" |
478 | +"Content-Type: text/plain; charset=UTF-8\n" |
479 | +"Content-Transfer-Encoding: 8bit\n" |
480 | +"X-Launchpad-Export-Date: 2011-07-08 05:57+0000\n" |
481 | +"X-Generator: Launchpad (build 13168)\n" |
482 | + |
483 | +#. module: mrp_prodlot_autosplit |
484 | +#: field:product.product,unique_production_number:0 |
485 | +msgid "Unique Production Number" |
486 | +msgstr "" |
487 | + |
488 | +#. module: mrp_prodlot_autosplit |
489 | +#: constraint:ir.ui.view:0 |
490 | +msgid "Invalid XML for View Architecture!" |
491 | +msgstr "" |
492 | + |
493 | +#. module: mrp_prodlot_autosplit |
494 | +#: model:ir.module.module,description:mrp_prodlot_autosplit.module_meta_information |
495 | +msgid "" |
496 | +"Turns production lot tracking numbers into unique per product instance code " |
497 | +"(serial number).\n" |
498 | +" Moreover, it\n" |
499 | +" 1) adds a new checkbox on the product form to enable or disable this " |
500 | +"behavior (you should also enable in/out tracking)\n" |
501 | +" 2) then forbids to perform a move if a move involves more than one " |
502 | +"product instance\n" |
503 | +" 3) automagically splits up picking list movements into one movement per " |
504 | +"product instance\n" |
505 | +" 4) turns incoming pickings into an editable grid where you can directly " |
506 | +"type the code\n" |
507 | +" of a new production number/code to create and associate to the move (it " |
508 | +"also checks it\n" |
509 | +" doesn't exist yet)\n" |
510 | +" \n" |
511 | +" Important Note 1: serial numbers are more easily encode using an " |
512 | +"editable tree grid, including a special field with new serial to be " |
513 | +"created.\n" |
514 | +" However, there is currently a limitation in the OpenObject framework " |
515 | +"preventing from easily changing non editable trees to editable trees\n" |
516 | +" by simple extension. Rather than overwriting all views, we prefer give " |
517 | +"only one example: the active customied view for easy serial encoding\n" |
518 | +" is available using Stock Management > Incoming Products. Looking that " |
519 | +"that view definition, the same thing is easily achieved in\n" |
520 | +" other picking list, like out going products for instance. However it's " |
521 | +"not \"on\" by default, you would need to work it out for your case.\n" |
522 | +" Meanwhile, we hope Tiny add a third \"merge_attributes\" view extension " |
523 | +"point to the 3 existing ones: \"before\", \"after\" and \"replace\".\n" |
524 | +" It would basically simply merge the attributes given (redefined) in the " |
525 | +"original view XML and let inner content unchanged.\n" |
526 | +" Blueprint is registred here: https://blueprints.launchpad.net/openobject-" |
527 | +"server/+spec/merge-attributes-view-extension-point\n" |
528 | +" \n" |
529 | +" Important Note 2: this module doesn't split product bill of materials in " |
530 | +"MRP since they don't use pickings\n" |
531 | +" A good workaround when generating production orders manually one by one " |
532 | +"is too define several lines of individual products in nomemclatures\n" |
533 | +" and produce 1 by 1 (if possible) to make it easier to encode unique " |
534 | +"prodlot in production orders too.\n" |
535 | +" We would also like to extend this module to split automatic production " |
536 | +"orders (from MRP engine) into several individual production orders in order\n" |
537 | +" to make it easy to encode the serial numbers in the production. Let us " |
538 | +"know if you would like that simple extension to be made.\n" |
539 | +" " |
540 | +msgstr "" |
541 | + |
542 | +#. module: mrp_prodlot_autosplit |
543 | +#: field:stock.production.lot,last_location_id:0 |
544 | +msgid "Last Location" |
545 | +msgstr "" |
546 | + |
547 | +#. module: mrp_prodlot_autosplit |
548 | +#: model:ir.module.module,shortdesc:mrp_prodlot_autosplit.module_meta_information |
549 | +msgid "Unique serial number management" |
550 | +msgstr "Unique serial number management" |
551 | + |
552 | +#. module: mrp_prodlot_autosplit |
553 | +#: field:stock.move,new_prodlot_code:0 |
554 | +msgid "Production Tracking Code To Create" |
555 | +msgstr "" |
556 | + |
557 | +#. module: mrp_prodlot_autosplit |
558 | +#: view:stock.picking:0 |
559 | +msgid "Stock Moves" |
560 | +msgstr "" |
561 | |
562 | === added file 'product_serial/prodlot_wizard.py' |
563 | --- product_serial/prodlot_wizard.py 1970-01-01 00:00:00 +0000 |
564 | +++ product_serial/prodlot_wizard.py 2013-05-08 13:17:25 +0000 |
565 | @@ -0,0 +1,119 @@ |
566 | +# -*- encoding: utf-8 -*- |
567 | +############################################################################## |
568 | +# |
569 | +# Product serial module for OpenERP |
570 | +# Copyright (C) 2010 NaN Projectes de Programari Lliure, S.L. |
571 | +# http://www.NaN-tic.com |
572 | +# |
573 | +# This program is free software: you can redistribute it and/or modify |
574 | +# it under the terms of the GNU Affero General Public License as |
575 | +# published by the Free Software Foundation, either version 3 of the |
576 | +# License, or (at your option) any later version. |
577 | +# |
578 | +# This program is distributed in the hope that it will be useful, |
579 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
580 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
581 | +# GNU Affero General Public License for more details. |
582 | +# |
583 | +# You should have received a copy of the GNU Affero General Public License |
584 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
585 | +# |
586 | +############################################################################## |
587 | + |
588 | +from osv import osv, fields |
589 | +from tools.translate import _ |
590 | + |
591 | +def is_integer(value): |
592 | + try: |
593 | + int(value) |
594 | + return True |
595 | + except: |
596 | + return False |
597 | + |
598 | +class stock_picking_prodlot_selection_wizard(osv.osv_memory): |
599 | + _name = 'stock.picking.prodlot.selection' |
600 | + |
601 | + _columns = { |
602 | + 'product_id': fields.many2one('product.product', 'Product', required=True), |
603 | + 'first_lot': fields.char('First Lot Number', size=256), |
604 | + 'last_lot': fields.char('Last Lot Number', size=256), |
605 | + } |
606 | + |
607 | + def action_cancel(self, cr, uid, ids, context=None): |
608 | + return {} |
609 | + |
610 | + def action_accept(self, cr, uid, ids, context=None): |
611 | + if context is None: |
612 | + context = {} |
613 | + if not ids: |
614 | + return {} |
615 | + if not 'active_id' in context: |
616 | + return {} |
617 | + |
618 | + record = self.browse(cr, uid, ids[0], context) |
619 | + first = record.first_lot |
620 | + last = record.last_lot |
621 | + if len(first) != len(last): |
622 | + raise osv.except_osv(_('Invalid lot numbers'), _('First and last lot numbers must have the same length.')) |
623 | + |
624 | + |
625 | + first_number = '' |
626 | + last_number = '' |
627 | + position = -1 |
628 | + for x in xrange(len(first)): |
629 | + if not position and first[x] == last[x]: |
630 | + continue |
631 | + if not position: |
632 | + position = x |
633 | + if not is_integer(first[x]) or not is_integer(last[x]): |
634 | + raise osv.except_osv(_('Invalid lot numbers'), _('First and last lot numbers differ in non-numeric values.')) |
635 | + first_number += first[x] |
636 | + last_number += last[x] |
637 | + |
638 | + if position >= 0: |
639 | + prefix = first[:position-1] |
640 | + else: |
641 | + prefix = '' |
642 | + |
643 | + number_fill = len(first_number) |
644 | + first_number = int(first_number) |
645 | + last_number = int(last_number) |
646 | + |
647 | + if last_number < first_number: |
648 | + raise osv.except_osv(_('Invalid lot numbers'), _('First lot number is greater than the last one.')) |
649 | + |
650 | + picking_id = context['active_id'] |
651 | + current_number = first_number |
652 | + for move in self.pool.get('stock.picking').browse(cr, uid, picking_id, context).move_lines: |
653 | + if move.prodlot_id or move.product_id != record.product_id: |
654 | + continue |
655 | + |
656 | + current_lot = '%%s%%0%dd' % number_fill % (prefix, current_number) |
657 | + lot_ids = self.pool.get('stock.production.lot').search(cr, uid, [('name','=',current_lot)], limit=1, context=context) |
658 | + if not lot_ids: |
659 | + raise osv.except_osv(_('Invalid lot numbers'), _('Production lot %s not found.') % current_lot) |
660 | + |
661 | + ctx = context.copy() |
662 | + ctx['location_id'] = move.location_id.id |
663 | + prodlot = self.pool.get('stock.production.lot').browse(cr, uid, lot_ids[0], ctx) |
664 | + |
665 | + if prodlot.product_id != record.product_id: |
666 | + raise osv.except_osv(_('Invalid lot numbers'), _('Production lot %s exists but not for product %s.') % (current_lot, record.product_id.name)) |
667 | + |
668 | + if prodlot.stock_available < move.product_qty: |
669 | + raise osv.except_osv(_('Invalid lot numbers'), _('Not enough stock available of production lot %s.') % current_lot) |
670 | + |
671 | + self.pool.get('stock.move').write(cr, uid, [move.id], { |
672 | + 'prodlot_id': lot_ids[0], |
673 | + }, context) |
674 | + |
675 | + current_number += 1 |
676 | + if current_number > last_number: |
677 | + break |
678 | + |
679 | + return {} |
680 | + |
681 | + |
682 | + |
683 | +stock_picking_prodlot_selection_wizard() |
684 | + |
685 | |
686 | === added file 'product_serial/product.py' |
687 | --- product_serial/product.py 1970-01-01 00:00:00 +0000 |
688 | +++ product_serial/product.py 2013-05-08 13:17:25 +0000 |
689 | @@ -0,0 +1,37 @@ |
690 | +# -*- encoding: utf-8 -*- |
691 | +############################################################################## |
692 | +# |
693 | +# Product serial module for OpenERP |
694 | +# Copyright (C) 2008 Raphaël Valyi |
695 | +# |
696 | +# This program is free software: you can redistribute it and/or modify |
697 | +# it under the terms of the GNU Affero General Public License as |
698 | +# published by the Free Software Foundation, either version 3 of the |
699 | +# License, or (at your option) any later version. |
700 | +# |
701 | +# This program is distributed in the hope that it will be useful, |
702 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
703 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
704 | +# GNU Affero General Public License for more details. |
705 | +# |
706 | +# You should have received a copy of the GNU Affero General Public License |
707 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
708 | +# |
709 | +############################################################################## |
710 | + |
711 | +from osv import fields, osv |
712 | + |
713 | +class product_product(osv.osv): |
714 | + _inherit = "product.product" |
715 | + |
716 | + _columns = { |
717 | + 'lot_split_type': fields.selection([('none','None'), |
718 | + ('single','Single'), |
719 | + ('lu','Logistical Unit')], 'Lot split type', required=True, help="None: no split ; single: 1 line/product unit ; Logistical Unit: split using the 1st Logistical Unit quantity of the product form packaging tab (to be improved to take into account all LU)"), |
720 | + } |
721 | + _defaults = { |
722 | + 'lot_split_type': lambda *a: 'none', |
723 | + } |
724 | + |
725 | +product_product() |
726 | + |
727 | |
728 | === added file 'product_serial/product_view.xml' |
729 | --- product_serial/product_view.xml 1970-01-01 00:00:00 +0000 |
730 | +++ product_serial/product_view.xml 2013-05-08 13:17:25 +0000 |
731 | @@ -0,0 +1,18 @@ |
732 | +<?xml version="1.0" encoding="utf-8"?> |
733 | +<openerp> |
734 | + <data> |
735 | + |
736 | + <record id="view_normal_unique_production_number_form" model="ir.ui.view"> |
737 | + <field name="name">product.normal.stock.form.unique_production_number.inherit</field> |
738 | + <field name="model">product.product</field> |
739 | + <field name="type">form</field> |
740 | + <field name="inherit_id" ref="stock.view_normal_stock_property_form"/> |
741 | + <field name="arch" type="xml"> |
742 | + <field name="track_outgoing" position="after"> |
743 | + <field name="lot_split_type" /> |
744 | + </field> |
745 | + </field> |
746 | + </record> |
747 | + |
748 | + </data> |
749 | +</openerp> |
750 | |
751 | === added file 'product_serial/stock.py' |
752 | --- product_serial/stock.py 1970-01-01 00:00:00 +0000 |
753 | +++ product_serial/stock.py 2013-05-08 13:17:25 +0000 |
754 | @@ -0,0 +1,297 @@ |
755 | +# -*- encoding: utf-8 -*- |
756 | +############################################################################## |
757 | +# |
758 | +# Product serial module for OpenERP |
759 | +# Copyright (C) 2008 Raphaël Valyi |
760 | +# Copyright (C) 2011 Anevia S.A. - Ability to group invoice lines |
761 | +# written by Alexis Demeaulte <alexis.demeaulte@anevia.com> |
762 | +# Copyright (C) 2011 Akretion - Ability to split lines on logistical units |
763 | +# written by Emmanuel Samyn |
764 | +# |
765 | +# This program is free software: you can redistribute it and/or modify |
766 | +# it under the terms of the GNU Affero General Public License as |
767 | +# published by the Free Software Foundation, either version 3 of the |
768 | +# License, or (at your option) any later version. |
769 | +# |
770 | +# This program is distributed in the hope that it will be useful, |
771 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
772 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
773 | +# GNU Affero General Public License for more details. |
774 | +# |
775 | +# You should have received a copy of the GNU Affero General Public License |
776 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
777 | +# |
778 | +############################################################################## |
779 | + |
780 | +from osv import fields, osv |
781 | +import hashlib |
782 | +from tools.translate import _ |
783 | + |
784 | + |
785 | +class stock_move(osv.osv): |
786 | + _inherit = "stock.move" |
787 | + # We order by product name because otherwise, after the split, |
788 | + # the products are "mixed" and not grouped by product name any more |
789 | + _order = "picking_id, name, id" |
790 | + |
791 | + def copy(self, cr, uid, id, default=None, context=None): |
792 | + if not default: |
793 | + default = {} |
794 | + default['new_prodlot_code'] = False |
795 | + return super(stock_move, self).copy(cr, uid, id, default, context=context) |
796 | + |
797 | + def _get_prodlot_code(self, cr, uid, ids, field_name, arg, context=None): |
798 | + res = {} |
799 | + for move in self.browse(cr, uid, ids): |
800 | + res[move.id] = move.prodlot_id and move.prodlot_id.name or False |
801 | + return res |
802 | + |
803 | + def _set_prodlot_code(self, cr, uid, ids, name, value, arg, context=None): |
804 | + if not value: return False |
805 | + |
806 | + if isinstance(ids, (int, long)): |
807 | + ids = [ids] |
808 | + |
809 | + for move in self.browse(cr, uid, ids, context=context): |
810 | + product_id = move.product_id.id |
811 | + existing_prodlot = move.prodlot_id |
812 | + if existing_prodlot: #avoid creating a prodlot twice |
813 | + self.pool.get('stock.production.lot').write(cr, uid, existing_prodlot.id, {'name': value}) |
814 | + else: |
815 | + prodlot_id = self.pool.get('stock.production.lot').create(cr, uid, { |
816 | + 'name': value, |
817 | + 'product_id': product_id, |
818 | + }) |
819 | + move.write({'prodlot_id' : prodlot_id}) |
820 | + |
821 | + def _get_tracking_code(self, cr, uid, ids, field_name, arg, context=None): |
822 | + res = {} |
823 | + for move in self.browse(cr, uid, ids): |
824 | + res[move.id] = move.tracking_id and move.tracking_id.name or False |
825 | + return res |
826 | + |
827 | + def _set_tracking_code(self, cr, uid, ids, name, value, arg, context=None): |
828 | + if not value: return False |
829 | + |
830 | + if isinstance(ids, (int, long)): |
831 | + ids = [ids] |
832 | + |
833 | + for move in self.browse(cr, uid, ids, context=context): |
834 | + product_id = move.product_id.id |
835 | + existing_tracking = move.tracking_id |
836 | + if existing_tracking: #avoid creating a tracking twice |
837 | + self.pool.get('stock.tracking').write(cr, uid, existing_tracking.id, {'name': value}) |
838 | + else: |
839 | + tracking_id = self.pool.get('stock.tracking').create(cr, uid, { |
840 | + 'name': value, |
841 | + }) |
842 | + move.write({'tracking_id' : tracking_id}) |
843 | + |
844 | + _columns = { |
845 | + 'new_prodlot_code': fields.function(_get_prodlot_code, fnct_inv=_set_prodlot_code, |
846 | + method=True, type='char', size=64, |
847 | + string='Prodlot fast input', select=1 |
848 | + ), |
849 | + 'new_tracking_code': fields.function(_get_tracking_code, fnct_inv=_set_tracking_code, |
850 | + method=True, type='char', size=64, |
851 | + string='Tracking fast input', select=1 |
852 | + ), |
853 | + } |
854 | + |
855 | + def action_done(self, cr, uid, ids, context=None): |
856 | + """ |
857 | + If we autosplit moves without reconnecting them 1 by 1, at least when some move which has descendants is split |
858 | + The following situation would happen (alphabetical order is order of creation, initially b and a pre-exists, then a is split, so a might get assigned and then split too): |
859 | + Incoming moves b, c, d |
860 | + Outgoing moves a, e, f |
861 | + Then we have those links: b->a, c->a, d->a |
862 | + and: b->, b->e, b->f |
863 | + The following code will detect this situation and reconnect properly the moves into only: b->a, c->e and d->f |
864 | + """ |
865 | + result = super(stock_move, self).action_done(cr, uid, ids, context) |
866 | + for move in self.browse(cr, uid, ids): |
867 | + if move.product_id.lot_split_type and move.move_dest_id and move.move_dest_id.id: |
868 | + cr.execute("select stock_move.id from stock_move_history_ids left join stock_move on stock_move.id = stock_move_history_ids.child_id where parent_id=%s and stock_move.product_qty=1", (move.id,)) |
869 | + unitary_out_moves = cr.fetchall() |
870 | + if unitary_out_moves and len(unitary_out_moves) > 1: |
871 | + unitary_in_moves = [] |
872 | + out_node = False |
873 | + counter = 0 |
874 | + while len(unitary_in_moves) != len(unitary_out_moves) and counter < len(unitary_out_moves): |
875 | + out_node = unitary_out_moves[counter][0] |
876 | + cr.execute("select stock_move.id from stock_move_history_ids left join stock_move on stock_move.id = stock_move_history_ids.parent_id where child_id=%s and stock_move.product_qty=1", (out_node,)) |
877 | + unitary_in_moves = cr.fetchall() |
878 | + counter += 1 |
879 | + |
880 | + if len(unitary_in_moves) == len(unitary_out_moves): |
881 | + unitary_out_moves.reverse() |
882 | + unitary_out_moves.pop() |
883 | + unitary_in_moves.reverse() |
884 | + unitary_in_moves.pop() |
885 | + counter = 0 |
886 | + for unitary_in_move in unitary_in_moves: |
887 | + cr.execute("delete from stock_move_history_ids where parent_id=%s and child_id=%s", (unitary_in_moves[counter][0], out_node)) |
888 | + cr.execute("update stock_move_history_ids set parent_id=%s where parent_id=%s and child_id=%s", (unitary_in_moves[counter][0], move.id, unitary_out_moves[counter][0])) |
889 | + counter += 1 |
890 | + |
891 | + return result |
892 | + |
893 | + def split_move(self, cr, uid, ids, context=None): |
894 | + all_ids = list(ids) |
895 | + for move in self.browse(cr, uid, ids, context=context): |
896 | + qty = move.product_qty |
897 | + lu_qty = False |
898 | + if move.product_id.lot_split_type == 'lu': |
899 | + if not move.product_id.packaging: |
900 | + raise osv.except_osv(_('Error :'), _("Product '%s' has 'Lot split type' = 'Logistical Unit' but is missing packaging information.") % (move.product_id.name)) |
901 | + lu_qty = move.product_id.packaging[0].qty |
902 | + elif move.product_id.lot_split_type == 'single': |
903 | + lu_qty = 1 |
904 | + if lu_qty and qty > 1: |
905 | + # Set existing move to LU quantity |
906 | + self.write(cr, uid, move.id, {'product_qty': lu_qty, 'product_uos_qty': move.product_id.uos_coeff}) |
907 | + qty -= lu_qty |
908 | + # While still enough qty to create a new move, create it |
909 | + while qty >= lu_qty: |
910 | + all_ids.append( self.copy(cr, uid, move.id, {'state': move.state, 'prodlot_id': None}) ) |
911 | + qty -= lu_qty |
912 | + # Create a last move for the remainder qty |
913 | + if qty > 0: |
914 | + all_ids.append( self.copy(cr, uid, move.id, {'state': move.state, 'prodlot_id': None, 'product_qty': qty}) ) |
915 | + return all_ids |
916 | + |
917 | +stock_move() |
918 | + |
919 | + |
920 | +class stock_picking(osv.osv): |
921 | + _inherit = "stock.picking" |
922 | + |
923 | + def action_assign_wkf(self, cr, uid, ids): |
924 | + result = super(stock_picking, self).action_assign_wkf(cr, uid, ids) |
925 | + |
926 | + for picking in self.browse(cr, uid, ids): |
927 | + if picking.company_id.autosplit_is_active: |
928 | + for move in picking.move_lines: |
929 | + # Auto split |
930 | + if ((move.product_id.track_production and move.location_id.usage == 'production') or \ |
931 | + (move.product_id.track_production and move.location_dest_id.usage == 'production') or \ |
932 | + (move.product_id.track_incoming and move.location_id.usage == 'supplier') or \ |
933 | + (move.product_id.track_outgoing and move.location_dest_id.usage == 'customer')): |
934 | + self.pool.get('stock.move').split_move(cr, uid, [move.id]) |
935 | + |
936 | + return result |
937 | + |
938 | + # Because stock move line can be splitted by the module, we merge |
939 | + # invoice lines (if option 'is_group_invoice_line' is activated for the company) |
940 | + # at the following conditions : |
941 | + # - the product is the same and |
942 | + # - the discount is the same and |
943 | + # - the unit price is the same and |
944 | + # - the description is the same and |
945 | + # - taxes are the same |
946 | + # - they are from the same sale order lines (requires extra-code) |
947 | + # we merge invoice line together and do the sum of quantity and |
948 | + # subtotal. |
949 | + def action_invoice_create(self, cursor, user, ids, journal_id=False, |
950 | + group=False, type='out_invoice', context=None): |
951 | + invoice_dict = super(stock_picking, self).action_invoice_create(cursor, user, |
952 | + ids, journal_id, group, type, context=context) |
953 | + |
954 | + for picking_key in invoice_dict: |
955 | + invoice = self.pool.get('account.invoice').browse(cursor, user, invoice_dict[picking_key], context=context) |
956 | + if not invoice.company_id.is_group_invoice_line: |
957 | + continue |
958 | + |
959 | + new_line_list = {} |
960 | + |
961 | + for line in invoice.invoice_line: |
962 | + |
963 | + # Build a key |
964 | + key = unicode(line.product_id.id) + ";" \ |
965 | + + unicode(line.discount) + ";" \ |
966 | + + unicode(line.price_unit) + ";" \ |
967 | + + line.name + ";" |
968 | + |
969 | + # Add the tax key part |
970 | + tax_tab = [] |
971 | + for tax in line.invoice_line_tax_id: |
972 | + tax_tab.append(tax.id) |
973 | + tax_tab.sort() |
974 | + for tax in tax_tab: |
975 | + key = key + unicode(tax) + ";" |
976 | + |
977 | + # Add the sale order line part but check if the field exist because |
978 | + # it's install by a specific module (not from addons) |
979 | + if self.pool.get('ir.model.fields').search(cursor, user, |
980 | + [('name', '=', 'sale_order_lines'), ('model', '=', 'account.invoice.line')], context=context) != []: |
981 | + order_line_tab = [] |
982 | + for order_line in line.sale_order_lines: |
983 | + order_line_tab.append(order_line.id) |
984 | + order_line_tab.sort() |
985 | + for order_line in order_line_tab: |
986 | + key = key + unicode(order_line) + ";" |
987 | + |
988 | + |
989 | + # Get the hash of the key |
990 | + hash_key = hashlib.sha224(key.encode('utf8')).hexdigest() |
991 | + |
992 | + # if the key doesn't already exist, we keep the invoice line |
993 | + # and we add the key to new_line_list |
994 | + if not new_line_list.has_key(hash_key): |
995 | + new_line_list[hash_key] = { |
996 | + 'id': line.id, |
997 | + 'quantity': line.quantity, |
998 | + 'price_subtotal': line.price_subtotal, |
999 | + } |
1000 | + # if the key already exist, we update new_line_list and |
1001 | + # we delete the invoice line |
1002 | + else: |
1003 | + new_line_list[hash_key]['quantity'] = new_line_list[hash_key]['quantity'] + line.quantity |
1004 | + new_line_list[hash_key]['price_subtotal'] = new_line_list[hash_key]['price_subtotal'] \ |
1005 | + + line.price_subtotal |
1006 | + self.pool.get('account.invoice.line').unlink(cursor, user, line.id, context=context) |
1007 | + |
1008 | + # Write modifications made on invoice lines |
1009 | + for hash_key in new_line_list: |
1010 | + line_id = new_line_list[hash_key]['id'] |
1011 | + del new_line_list[hash_key]['id'] |
1012 | + self.pool.get('account.invoice.line').write(cursor, user, line_id, new_line_list[hash_key], context=context) |
1013 | + |
1014 | + return invoice_dict |
1015 | + |
1016 | +stock_picking() |
1017 | + |
1018 | + |
1019 | +class stock_production_lot(osv.osv): |
1020 | + _inherit = "stock.production.lot" |
1021 | + |
1022 | + def _last_location_id(self, cr, uid, ids, field_name, arg, context={}): |
1023 | + """Retrieves the last location where the product with given serial is. |
1024 | + Instead of using dates we assume the product is in the location having the |
1025 | + highest number of products with the given serial (should be 1 if no mistake). This |
1026 | + is better than using move dates because moves can easily be encoded at with wrong dates.""" |
1027 | + res = {} |
1028 | + |
1029 | + for prodlot_id in ids: |
1030 | + cr.execute( |
1031 | + "select location_dest_id " \ |
1032 | + "from stock_move inner join stock_report_prodlots on stock_report_prodlots.location_id = location_dest_id and stock_report_prodlots.prodlot_id = %s " \ |
1033 | + "where stock_move.prodlot_id = %s and stock_move.state=%s "\ |
1034 | + "order by stock_report_prodlots.qty DESC ", |
1035 | + (prodlot_id, prodlot_id, 'done')) |
1036 | + results = cr.fetchone() |
1037 | + |
1038 | + #TODO return tuple to avoid name_get being requested by the GTK client |
1039 | + res[prodlot_id] = results and results[0] or False |
1040 | + |
1041 | + return res |
1042 | + |
1043 | + _columns = { |
1044 | + 'last_location_id': fields.function(_last_location_id, method=True, |
1045 | + type="many2one", relation="stock.location", |
1046 | + string="Last location", |
1047 | + help="Display the current stock location of this production lot"), |
1048 | + } |
1049 | + |
1050 | +stock_production_lot() |
1051 | + |
1052 | |
1053 | === added file 'product_serial/stock_view.xml' |
1054 | --- product_serial/stock_view.xml 1970-01-01 00:00:00 +0000 |
1055 | +++ product_serial/stock_view.xml 2013-05-08 13:17:25 +0000 |
1056 | @@ -0,0 +1,299 @@ |
1057 | +<?xml version="1.0"?> |
1058 | +<openerp> |
1059 | +<data> |
1060 | + |
1061 | + <!-- In the form view of Incoming/Outgoing products, make the tree view of move lines editable and set the parameters that are only present in the form view to the fields of the tree view--> |
1062 | + <record id="view_picking_in_form_editable_move_lines" model="ir.ui.view"> |
1063 | + <field name="name">view.picking.in.form.editable_move_lines</field> |
1064 | + <field name="model">stock.picking</field> |
1065 | + <field name="inherit_id" ref="stock.view_picking_in_form" /> |
1066 | + <field name="type">form</field> |
1067 | + <field name="arch" type="xml"> |
1068 | + <xpath expr="/form/notebook/page/field/tree[@string='Stock Moves']" position="attributes"> |
1069 | + <attribute name="editable">bottom</attribute> |
1070 | + </xpath> |
1071 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_id']" position="attributes"> |
1072 | + <attribute name="on_change">onchange_product_id(product_id,location_id,location_dest_id, parent.address_id)</attribute> |
1073 | + </xpath> |
1074 | + <!-- we need to have the "name" field in the tree view, because it is a required field that is set by the on_change on product_id... otherwise we get an error message when adding a new move line via the editable tree view --> |
1075 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_id']" position="after"> |
1076 | + <field name="name" invisible="1"/> |
1077 | + </xpath> |
1078 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_qty']" position="attributes"> |
1079 | + <attribute name="on_change">onchange_quantity(product_id, product_qty, product_uom, product_uos)</attribute> |
1080 | + </xpath> |
1081 | + <xpath expr="/form/notebook/page/field/tree/field[@name='prodlot_id']" position="attributes"> |
1082 | + <attribute name="context">{'location_id':location_id, 'product_id':product_id}</attribute> |
1083 | + <attribute name="domain">[('product_id','=?',product_id)]</attribute> |
1084 | + <attribute name="on_change">onchange_lot_id(prodlot_id, product_qty, location_id, product_id, product_uom)</attribute> |
1085 | + </xpath> |
1086 | + <xpath expr="/form/notebook/page/field/tree/field[@name='location_dest_id']" position="attributes"> |
1087 | + <attribute name="domain">[('usage','=','internal')]</attribute> |
1088 | + </xpath> |
1089 | + </field> |
1090 | + </record> |
1091 | + |
1092 | + <record id="view_picking_out_form_editable_move_lines" model="ir.ui.view"> |
1093 | + <field name="name">view.picking.out.form.editable_move_lines</field> |
1094 | + <field name="model">stock.picking</field> |
1095 | + <field name="inherit_id" ref="stock.view_picking_out_form" /> |
1096 | + <field name="type">form</field> |
1097 | + <field name="arch" type="xml"> |
1098 | + <xpath expr="/form/notebook/page/field/tree[@string='Stock Moves']" position="attributes"> |
1099 | + <attribute name="editable">bottom</attribute> |
1100 | + </xpath> |
1101 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_id']" position="attributes"> |
1102 | + <attribute name="on_change">onchange_product_id(product_id,location_id,location_dest_id, parent.address_id)</attribute> |
1103 | + </xpath> |
1104 | + <!-- we need to have the "name" field in the tree view, because it is a required field that is set by the on_change on product_id... otherwise we get an error message when adding a new move line via the editable tree view --> |
1105 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_id']" position="after"> |
1106 | + <field name="name" invisible="1"/> |
1107 | + </xpath> |
1108 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_qty']" position="attributes"> |
1109 | + <attribute name="on_change">onchange_quantity(product_id, product_qty, product_uom, product_uos)</attribute> |
1110 | + </xpath> |
1111 | + <xpath expr="/form/notebook/page/field/tree/field[@name='product_uos']" position="attributes"> |
1112 | + <attribute name="on_change">onchange_quantity(product_id, product_qty, product_uom, product_uos)</attribute> |
1113 | + </xpath> |
1114 | + <xpath expr="/form/notebook/page/field/tree/field[@name='prodlot_id']" position="attributes"> |
1115 | + <attribute name="context">{'location_id':location_id, 'product_id':product_id}</attribute> |
1116 | + <attribute name="domain">[('product_id','=?',product_id)]</attribute> |
1117 | + <attribute name="on_change">onchange_lot_id(prodlot_id, product_qty, location_id, product_id, product_uom)</attribute> |
1118 | + </xpath> |
1119 | + <xpath expr="/form/notebook/page/field/tree/field[@name='location_id']" position="attributes"> |
1120 | + <attribute name="domain">[('usage','=','internal')]</attribute> |
1121 | + </xpath> |
1122 | + </field> |
1123 | + </record> |
1124 | + |
1125 | + <!-- In the form view of Incoming products, add the "new_prodlot_code" fields --> |
1126 | + <record id="view_picking_in_form_new_prodlot_code" model="ir.ui.view"> |
1127 | + <field name="name">view.picking.in.form.new_prodlot_code</field> |
1128 | + <field name="model">stock.picking</field> |
1129 | + <field name="inherit_id" ref="stock.view_picking_in_form" /> |
1130 | + <field name="type">form</field> |
1131 | + <field name="arch" type="xml"> |
1132 | + <xpath expr="/form/notebook/page/field/tree/field[@name='prodlot_id']" position="before"> |
1133 | + <field name="new_prodlot_code" /> |
1134 | + </xpath> |
1135 | + </field> |
1136 | + </record> |
1137 | + |
1138 | + <!-- In the form view of Incoming products, add the "new_tracking_code" fields --> |
1139 | + <record id="view_picking_in_form_new_tracking_code" model="ir.ui.view"> |
1140 | + <field name="name">view.picking.in.form.new_tracking_code</field> |
1141 | + <field name="model">stock.picking</field> |
1142 | + <field name="inherit_id" ref="stock.view_picking_in_form" /> |
1143 | + <field name="type">form</field> |
1144 | + <field name="arch" type="xml"> |
1145 | + <xpath expr="/form/notebook/page/field/tree/field[@name='tracking_id']" position="before"> |
1146 | + <field name="new_tracking_code" /> |
1147 | + </xpath> |
1148 | + </field> |
1149 | + </record> |
1150 | + |
1151 | + <!-- We should have both source stock + dest location in the form view of Incoming/Outgoing products/Internal moves --> |
1152 | + <record id="view_picking_in_form_source_stock_location" model="ir.ui.view"> |
1153 | + <field name="name">view.picking.in.form.source_stock_location</field> |
1154 | + <field name="model">stock.picking</field> |
1155 | + <field name="inherit_id" ref="stock.view_picking_in_form" /> |
1156 | + <field name="type">form</field> |
1157 | + <field name="arch" type="xml"> |
1158 | + <xpath expr="/form/notebook/page/field/tree/field[@name='location_dest_id']" position="before"> |
1159 | + <field name="location_id" domain="[('usage','<>','view')]" /> |
1160 | + </xpath> |
1161 | + </field> |
1162 | + </record> |
1163 | + |
1164 | + <record id="view_picking_out_form_dest_stock_location" model="ir.ui.view"> |
1165 | + <field name="name">view.picking.out.form.dest_stock_location</field> |
1166 | + <field name="model">stock.picking</field> |
1167 | + <field name="inherit_id" ref="stock.view_picking_out_form" /> |
1168 | + <field name="type">form</field> |
1169 | + <field name="arch" type="xml"> |
1170 | + <xpath expr="/form/notebook/page/field/tree/field[@name='location_id']" position="after"> |
1171 | + <field name="location_dest_id" domain="[('usage','<>','view')]" /> |
1172 | + </xpath> |
1173 | + </field> |
1174 | + </record> |
1175 | + |
1176 | + <record id="view_picking_form_source_stock_location" model="ir.ui.view"> |
1177 | + <field name="name">view.picking.form.source_stock_location</field> |
1178 | + <field name="model">stock.picking</field> |
1179 | + <field name="inherit_id" ref="stock.view_picking_form" /> |
1180 | + <field name="type">form</field> |
1181 | + <field name="arch" type="xml"> |
1182 | + <xpath expr="/form/notebook/page/field/tree/field[@name='location_dest_id']" position="before"> |
1183 | + <field name="location_id" domain="[('usage','<>','view')]" /> |
1184 | + </xpath> |
1185 | + </field> |
1186 | + </record> |
1187 | + |
1188 | + |
1189 | + <record id="view_picking_in_form_manual_split" model="ir.ui.view"> |
1190 | + <field name="name">view.picking.in.form.manual_split</field> |
1191 | + <field name="model">stock.picking</field> |
1192 | + <field name="inherit_id" ref="stock.view_picking_in_form" /> |
1193 | + <field name="type">form</field> |
1194 | + <field name="priority">24</field> <!-- inherit after product_hardware_revision --> |
1195 | + <field name="arch" type="xml"> |
1196 | + <xpath expr="/form/notebook/page/field/form/group/button[@string='Split']" position="after"> |
1197 | + <label string="" colspan="3" /> |
1198 | + <button name="split_move" string="Manual split" |
1199 | + groups="base.group_extended" |
1200 | + states="draft,waiting,confirmed,assigned" |
1201 | + type="object" icon="terp-stock_effects-object-colorize" |
1202 | + colspan="1" /> |
1203 | + </xpath> |
1204 | + <xpath expr="/form/notebook/page/field/tree/button[@string='Split in production lots']" position="replace"> |
1205 | + <button name="split_move" string="Manual split" |
1206 | + groups="base.group_extended" |
1207 | + states="draft,waiting,confirmed,assigned" |
1208 | + type="object" icon="terp-stock_effects-object-colorize"/> |
1209 | + </xpath> |
1210 | + </field> |
1211 | + </record> |
1212 | + |
1213 | + <record id="view_picking_out_form_manual_split" model="ir.ui.view"> |
1214 | + <field name="name">view.picking.out.form.manual_split</field> |
1215 | + <field name="model">stock.picking</field> |
1216 | + <field name="inherit_id" ref="stock.view_picking_out_form" /> |
1217 | + <field name="type">form</field> |
1218 | + <field name="priority">24</field> <!-- inherit after product_hardware_revision --> |
1219 | + <field name="arch" type="xml"> |
1220 | + <xpath expr="/form/notebook/page/field/form/group/button[@string='Split']" position="after"> |
1221 | + <label string="" colspan="3" /> |
1222 | + <button name="split_move" string="Manual split" |
1223 | + groups="base.group_extended" |
1224 | + states="draft,waiting,confirmed,assigned" |
1225 | + type="object" icon="terp-stock_effects-object-colorize" |
1226 | + colspan="1" /> |
1227 | + </xpath> |
1228 | + <xpath expr="/form/notebook/page/field/tree/button[@string='Split in production lots']" position="replace"> |
1229 | + <button name="split_move" string="Manual split" |
1230 | + groups="base.group_extended" |
1231 | + states="draft,waiting,confirmed,assigned" |
1232 | + type="object" icon="terp-stock_effects-object-colorize"/> |
1233 | + </xpath> |
1234 | + </field> |
1235 | + </record> |
1236 | + |
1237 | + |
1238 | + <!-- Internal moves --> |
1239 | + <record id="view_picking_form_manual_split" model="ir.ui.view"> |
1240 | + <field name="name">view.picking.form.manual_split</field> |
1241 | + <field name="model">stock.picking</field> |
1242 | + <field name="inherit_id" ref="stock.view_picking_form" /> |
1243 | + <field name="type">form</field> |
1244 | + <field name="arch" type="xml"> |
1245 | + <xpath expr="/form/notebook/page/field/form/group/button[@string='Split']" position="after"> |
1246 | + <label string="" colspan="3" /> |
1247 | + <button name="split_move" string="Manual split" |
1248 | + groups="base.group_extended" |
1249 | + states="draft,waiting,confirmed,assigned" |
1250 | + type="object" icon="terp-stock_effects-object-colorize" |
1251 | + colspan="1" /> |
1252 | + </xpath> |
1253 | + <xpath expr="/form/notebook/page/field/tree/button[@string='Split in production lots']" position="replace"> |
1254 | + <button name="split_move" string="Manual split" |
1255 | + groups="base.group_extended" |
1256 | + states="draft,waiting,confirmed,assigned" |
1257 | + type="object" icon="terp-stock_effects-object-colorize"/> |
1258 | + </xpath> |
1259 | + </field> |
1260 | + </record> |
1261 | + |
1262 | + |
1263 | + <!-- Add "last_location_id" on prod lot view --> |
1264 | + <record id="view_production_lot_form_unique_production_number" model="ir.ui.view"> |
1265 | + <field name="name">view_production_lot_form_unique_production_number</field> |
1266 | + <field name="model">stock.production.lot</field> |
1267 | + <field name="inherit_id" ref="stock.view_production_lot_form"/> |
1268 | + <field name="type">form</field> |
1269 | + <field name="arch" type="xml"> |
1270 | + <field name="stock_available" position="after"> |
1271 | + <field name="last_location_id"/> |
1272 | + </field> |
1273 | + </field> |
1274 | + </record> |
1275 | + |
1276 | + <!-- Wizard to help users input production lots in batch --> |
1277 | +<!-- TODO Nan-TIc : port to v6 |
1278 | + <record id="view_stock_picking_prodlot_selection" model="ir.ui.view"> |
1279 | + <field name="name">stock.picking.prodlot.selection</field> |
1280 | + <field name="model">stock.picking.prodlot.selection</field> |
1281 | + <field name="type">form</field> |
1282 | + <field name="arch" type="xml"> |
1283 | + <form string="Select Production Lots"> |
1284 | + <field name="product_id" colspan="4"/> |
1285 | + <field name="first_lot"/> |
1286 | + <field name="last_lot"/> |
1287 | + <button type="object" name="action_cancel" string="Cancel" icon="gtk-cancel" special="cancel" colspan="2"/> |
1288 | + <button type="object" name="action_accept" string="Accept" icon="gtk-ok" colspan="2"/> |
1289 | + </form> |
1290 | + </field> |
1291 | + </record> |
1292 | + |
1293 | + <record model="ir.actions.act_window" id="action_prodlot_selection"> |
1294 | + <field name="name">Select Production Lots</field> |
1295 | + <field name="res_model">stock.picking.prodlot.selection</field> |
1296 | + <field name="view_type">form</field> |
1297 | + <field name="view_mode">form</field> |
1298 | + <field name="target">new</field> |
1299 | + </record> |
1300 | + |
1301 | + <record id="view_picking_form" model="ir.ui.view"> |
1302 | + <field name="name">stock.picking.form.prodlot.selection</field> |
1303 | + <field name="model">stock.picking</field> |
1304 | + <field name="type">form</field> |
1305 | + <field name="inherit_id" ref="stock.view_picking_form"/> |
1306 | + <field name="arch" type="xml"> |
1307 | + <xpath expr="/form/notebook/page/group/label[@colspan='6']" position="replace"> |
1308 | + <label colspan="5"/> |
1309 | + <button type="action" name="%(action_prodlot_selection)d" string="Spread Production Lots" states="draft,confirmed,assigned"/> |
1310 | + </xpath> |
1311 | + </field> |
1312 | + </record> |
1313 | + |
1314 | + <record id="view_picking_in_form" model="ir.ui.view"> |
1315 | + <field name="name">stock.picking.in.form.prodlot.selection</field> |
1316 | + <field name="model">stock.picking</field> |
1317 | + <field name="type">form</field> |
1318 | + <field name="inherit_id" ref="stock.view_picking_in_form"/> |
1319 | + <field name="arch" type="xml"> |
1320 | + <xpath expr="/form/notebook/page/group/label[@colspan='5']" position="replace"> |
1321 | + <label colspan="4"/> |
1322 | + <button type="action" name="%(action_prodlot_selection)d" string="Spread Production Lots" states="draft,confirmed,assigned"/> |
1323 | + </xpath> |
1324 | + </field> |
1325 | + </record> |
1326 | + |
1327 | + <record id="view_picking_out_form" model="ir.ui.view"> |
1328 | + <field name="name">stock.picking.out.form</field> |
1329 | + <field name="model">stock.picking</field> |
1330 | + <field name="type">form</field> |
1331 | + <field name="inherit_id" ref="stock.view_picking_out_form"/> |
1332 | + <field name="arch" type="xml"> |
1333 | + <xpath expr="/form/notebook/page/group/label[@colspan='6']" position="replace"> |
1334 | + <label colspan="5"/> |
1335 | + <button type="action" name="%(action_prodlot_selection)d" string="Spread Production Lots" states="draft,confirmed,assigned"/> |
1336 | + </xpath> |
1337 | + </field> |
1338 | + </record> |
1339 | + |
1340 | + <record id="view_picking_delivery_form" model="ir.ui.view"> |
1341 | + <field name="name">stock.picking.delivery.form</field> |
1342 | + <field name="model">stock.picking</field> |
1343 | + <field name="type">form</field> |
1344 | + <field name="inherit_id" ref="stock.view_picking_delivery_form"/> |
1345 | + <field name="arch" type="xml"> |
1346 | + <xpath expr="/form/notebook/page/group/label[@colspan='6']" position="replace"> |
1347 | + <label colspan="5"/> |
1348 | + <button type="action" name="%(action_prodlot_selection)d" string="Spread Production Lots" states="draft,confirmed,assigned"/> |
1349 | + </xpath> |
1350 | + </field> |
1351 | + </record> |
1352 | +--> |
1353 | + |
1354 | +</data> |
1355 | +</openerp> |
Extract the module product_serial from the extra-addons