Merge lp:~camptocamp/carriers-deliveries/7.0-delivery_carrier_label_dispatch-output-file-yvr into lp:~stock-logistic-core-editors/carriers-deliveries/7.0

Proposed by Yannick Vaucher @ Camptocamp
Status: Needs review
Proposed branch: lp:~camptocamp/carriers-deliveries/7.0-delivery_carrier_label_dispatch-output-file-yvr
Merge into: lp:~stock-logistic-core-editors/carriers-deliveries/7.0
Prerequisite: lp:~camptocamp/carriers-deliveries/7.0-add-delivery_carrier_label_dispatch-yvr
Diff against target: 503 lines (+180/-199)
7 files modified
delivery_carrier_label_dispatch/__init__.py (+0/-1)
delivery_carrier_label_dispatch/__openerp__.py (+7/-2)
delivery_carrier_label_dispatch/i18n/delivery_carrier_label_dispatch.pot (+76/-95)
delivery_carrier_label_dispatch/pdf_utils.py (+2/-0)
delivery_carrier_label_dispatch/stock.py (+0/-62)
delivery_carrier_label_dispatch/wizard/generate_labels.py (+91/-34)
delivery_carrier_label_dispatch/wizard/generate_labels_view.xml (+4/-5)
To merge this branch: bzr merge lp:~camptocamp/carriers-deliveries/7.0-delivery_carrier_label_dispatch-output-file-yvr
Reviewer Review Type Date Requested Status
Leonardo Pistone code review Approve
Stock and Logistic Core Editors Pending
Review via email: mp+202444@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Leonardo Pistone (lepistone) wrote :

Hi Yannick,

#file_type='pdf'

is meant to be commented out?

I approve in any case because you are not really changing that line, justing indenting it a little :)

review: Approve (code review)
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

I have some work on my side on the same part of the code. I will merge your changes in my own branch because they will conflict a lot otherwise. I put your branch as WIP just to avoid people reviewing it meanwhile.

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Merged Guewen's work

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Resolved conflicts Needs reviews

21. By Yannick Vaucher @ Camptocamp

Add better exception message from dispatch to identify the pack with an error

22. By Yannick Vaucher @ Camptocamp

update pot file

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

This project is now hosted on https://github.com/OCA/carriers-deliveries. Please move your proposal there if you still want to merge it once fixed. This guide may help you https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub

Unmerged revisions

22. By Yannick Vaucher @ Camptocamp

update pot file

21. By Yannick Vaucher @ Camptocamp

Add better exception message from dispatch to identify the pack with an error

20. By Yannick Vaucher @ Camptocamp

merge main branch to resolve conflicts

19. By Yannick Vaucher @ Camptocamp

add file extension in file name for poor OS

18. By Yannick Vaucher @ Camptocamp

fix generation of picking shipping labels from picking dispatch when there are no pack defined in the pickings

17. By Guewen Baconnier @ Camptocamp

use the general method and not the one for the button

avoid utils.PdfReadError('Cannot read an empty file') error

16. By Yannick Vaucher @ Camptocamp

[FIX] delivery_carrier_label_dispatch - save picking dispatch label pdf file as attachement of the picking

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'delivery_carrier_label_dispatch/__init__.py'
2--- delivery_carrier_label_dispatch/__init__.py 2014-01-09 13:54:55 +0000
3+++ delivery_carrier_label_dispatch/__init__.py 2014-04-10 14:10:35 +0000
4@@ -18,6 +18,5 @@
5 # along with this program. If not, see <http://www.gnu.org/licenses/>.
6 #
7 ##############################################################################
8-from . import stock
9 from . import picking_dispatch
10 from . import wizard
11
12=== modified file 'delivery_carrier_label_dispatch/__openerp__.py'
13--- delivery_carrier_label_dispatch/__openerp__.py 2014-01-09 13:54:55 +0000
14+++ delivery_carrier_label_dispatch/__openerp__.py 2014-04-10 14:10:35 +0000
15@@ -29,8 +29,13 @@
16 [Link module] Carrier labels - Picking dispatch
17 ==============================
18
19-This module adds a wizard on picking dispatch to generate related picking
20-labels
21+This module adds a wizard on picking dispatch to generate the labels
22+of the packs. The labels are merged in one PDF file.
23+
24+If you want multiple labels for one picking, all the moves should have been
25+put in a pack before the labels can be printed.
26+
27+If you don't define your pack it will be considered a picking is a single pack.
28
29 Contributors
30 ------------
31
32=== modified file 'delivery_carrier_label_dispatch/i18n/delivery_carrier_label_dispatch.pot'
33--- delivery_carrier_label_dispatch/i18n/delivery_carrier_label_dispatch.pot 2014-01-09 13:54:55 +0000
34+++ delivery_carrier_label_dispatch/i18n/delivery_carrier_label_dispatch.pot 2014-04-10 14:10:35 +0000
35@@ -6,58 +6,75 @@
36 msgstr ""
37 "Project-Id-Version: OpenERP Server 7.0\n"
38 "Report-Msgid-Bugs-To: \n"
39-"POT-Creation-Date: 2014-01-09 13:29+0000\n"
40-"PO-Revision-Date: 2014-01-09 14:30+0100\n"
41-"Last-Translator: Yannick Vaucher <yannick.vaucher@camptocamp.com>\n"
42+"POT-Creation-Date: 2014-04-10 14:03+0000\n"
43+"PO-Revision-Date: 2014-04-10 14:03+0000\n"
44+"Last-Translator: <>\n"
45 "Language-Team: \n"
46 "MIME-Version: 1.0\n"
47 "Content-Type: text/plain; charset=UTF-8\n"
48-"Content-Transfer-Encoding: 8bit\n"
49+"Content-Transfer-Encoding: \n"
50 "Plural-Forms: \n"
51
52 #. module: delivery_carrier_label_dispatch
53+#: model:ir.model.fields,field_description:delivery_carrier_label_dispatch.field_picking_dispatch_carrier_id
54+#: field:picking.dispatch,carrier_id:0
55+msgid "Carrier"
56+msgstr ""
57+
58+#. module: delivery_carrier_label_dispatch
59 #: view:picking.dispatch:0
60 msgid "Carrier Info"
61 msgstr ""
62
63 #. module: delivery_carrier_label_dispatch
64+#: view:delivery.carrier.label.generate:0
65+msgid "Close"
66+msgstr ""
67+
68+#. module: delivery_carrier_label_dispatch
69+#: view:picking.dispatch:0
70+msgid "Delivery"
71+msgstr ""
72+
73+#. module: delivery_carrier_label_dispatch
74+#: code:_description:0
75+#: model:ir.model,name:delivery_carrier_label_dispatch.model_picking_dispatch
76+#, python-format
77+msgid "Dispatch Picking Order"
78+msgstr ""
79+
80+#. module: delivery_carrier_label_dispatch
81 #: model:ir.actions.act_window,name:delivery_carrier_label_dispatch.action_delivery_carrier_label_generate
82 msgid "Generate Carrier Labels"
83 msgstr ""
84
85 #. module: delivery_carrier_label_dispatch
86-#: model:ir.model,name:delivery_carrier_label_dispatch.model_stock_picking
87-msgid "Picking List"
88-msgstr ""
89-
90-#. module: delivery_carrier_label_dispatch
91-#: code:addons/delivery_carrier_label_dispatch/picking_dispatch.py:100
92-#, python-format
93-msgid ""
94-"You can not remove a mandatory option.\n"
95-"Options are reset to default."
96-msgstr ""
97-
98-#. module: delivery_carrier_label_dispatch
99-#: model:ir.model,name:delivery_carrier_label_dispatch.model_picking_dispatch
100-msgid "Dispatch Picking Order"
101-msgstr ""
102-
103-#. module: delivery_carrier_label_dispatch
104+#: view:delivery.carrier.label.generate:0
105+msgid "Generate Carriers Labels"
106+msgstr ""
107+
108+#. module: delivery_carrier_label_dispatch
109+#: view:delivery.carrier.label.generate:0
110+msgid "Generate Labels"
111+msgstr ""
112+
113+#. module: delivery_carrier_label_dispatch
114+#: field:delivery.carrier.label.generate,generate_new_labels:0
115+#: model:ir.model.fields,field_description:delivery_carrier_label_dispatch.field_delivery_carrier_label_generate_generate_new_labels
116+msgid "Generate new labels"
117+msgstr ""
118+
119+#. module: delivery_carrier_label_dispatch
120+#: help:delivery.carrier.label.generate,generate_new_labels:0
121+msgid "If this option is used, new labels will be generated for the packs even if they already have one.\n"
122+"The default is to use the existing label."
123+msgstr ""
124+
125+#. module: delivery_carrier_label_dispatch
126+#: model:ir.model.fields,field_description:delivery_carrier_label_dispatch.field_picking_dispatch_option_ids
127 #: view:picking.dispatch:0
128-msgid "Delivery"
129-msgstr ""
130-
131-#. module: delivery_carrier_label_dispatch
132-#: code:addons/delivery_carrier_label_dispatch/wizard/generate_labels.py:58
133-#, python-format
134-msgid "No picking dispatch selected"
135-msgstr ""
136-
137-#. module: delivery_carrier_label_dispatch
138-#: field:delivery.carrier.label.generate,label_pdf_file:0
139-#: model:ir.model.fields,field_description:delivery_carrier_label_dispatch.field_delivery_carrier_label_generate_label_pdf_file
140-msgid "Labels file"
141+#: field:picking.dispatch,option_ids:0
142+msgid "Options"
143 msgstr ""
144
145 #. module: delivery_carrier_label_dispatch
146@@ -67,71 +84,35 @@
147 msgstr ""
148
149 #. module: delivery_carrier_label_dispatch
150+#: code:_description:0
151+#: model:ir.model,name:delivery_carrier_label_dispatch.model_stock_picking
152+#, python-format
153+msgid "Picking List"
154+msgstr ""
155+
156+#. module: delivery_carrier_label_dispatch
157+#: view:picking.dispatch:0
158+msgid "Set Options"
159+msgstr ""
160+
161+#. module: delivery_carrier_label_dispatch
162+#: view:delivery.carrier.label.generate:0
163+msgid "This wizard creates an attachement on each selected dispatch containing picking labels"
164+msgstr ""
165+
166+#. module: delivery_carrier_label_dispatch
167+#: view:picking.dispatch:0
168+msgid "Warning, setting options will erase existing ones in pickings"
169+msgstr ""
170+
171+#. module: delivery_carrier_label_dispatch
172+#: code:_description:0
173 #: model:ir.model,name:delivery_carrier_label_dispatch.model_delivery_carrier_label_generate
174+#, python-format
175 msgid "delivery.carrier.label.generate"
176 msgstr ""
177
178 #. module: delivery_carrier_label_dispatch
179-#: view:picking.dispatch:0
180-msgid "Set Options"
181-msgstr ""
182-
183-#. module: delivery_carrier_label_dispatch
184-#: model:ir.model.fields,field_description:delivery_carrier_label_dispatch.field_picking_dispatch_carrier_id
185-#: field:picking.dispatch,carrier_id:0
186-msgid "Carrier"
187-msgstr ""
188-
189-#. module: delivery_carrier_label_dispatch
190-#: code:addons/delivery_carrier_label_dispatch/wizard/generate_labels.py:58
191-#, python-format
192-msgid "Error"
193-msgstr ""
194-
195-#. module: delivery_carrier_label_dispatch
196-#: view:picking.dispatch:0
197-msgid "Warning, setting options will erase existing ones in pickings"
198-msgstr ""
199-
200-#. module: delivery_carrier_label_dispatch
201-#: model:ir.model.fields,field_description:delivery_carrier_label_dispatch.field_picking_dispatch_option_ids
202-#: view:picking.dispatch:0
203-#: field:picking.dispatch,option_ids:0
204-msgid "Options"
205-msgstr ""
206-
207-#. module: delivery_carrier_label_dispatch
208-#: view:delivery.carrier.label.generate:0
209-msgid "Generate Labels"
210-msgstr ""
211-
212-#. module: delivery_carrier_label_dispatch
213-#: view:delivery.carrier.label.generate:0
214-msgid "Labels"
215-msgstr ""
216-
217-#. module: delivery_carrier_label_dispatch
218-#: view:delivery.carrier.label.generate:0
219-msgid "Generate Carriers Labels"
220-msgstr ""
221-
222-#. module: delivery_carrier_label_dispatch
223-#: view:delivery.carrier.label.generate:0
224-msgid "Close"
225-msgstr ""
226-
227-#. module: delivery_carrier_label_dispatch
228-#: code:addons/delivery_carrier_label_dispatch/picking_dispatch.py:99
229-#, python-format
230-msgid "User Error !"
231-msgstr ""
232-
233-#. module: delivery_carrier_label_dispatch
234-#: model:ir.model,name:delivery_carrier_label_dispatch.model_stock_picking_out
235-msgid "Delivery Orders"
236-msgstr ""
237-
238-#. module: delivery_carrier_label_dispatch
239 #: view:delivery.carrier.label.generate:0
240 msgid "or"
241 msgstr ""
242
243=== modified file 'delivery_carrier_label_dispatch/pdf_utils.py'
244--- delivery_carrier_label_dispatch/pdf_utils.py 2013-12-17 07:55:56 +0000
245+++ delivery_carrier_label_dispatch/pdf_utils.py 2014-04-10 14:10:35 +0000
246@@ -39,6 +39,8 @@
247
248 output = PdfFileWriter()
249 for pdf in pdf_list:
250+ if not pdf:
251+ continue
252 reader = PdfFileReader(StringIO(pdf))
253
254 for page in range(reader.getNumPages()):
255
256=== removed file 'delivery_carrier_label_dispatch/stock.py'
257--- delivery_carrier_label_dispatch/stock.py 2013-12-17 07:42:04 +0000
258+++ delivery_carrier_label_dispatch/stock.py 1970-01-01 00:00:00 +0000
259@@ -1,62 +0,0 @@
260-# -*- coding: utf-8 -*-
261-##############################################################################
262-#
263-# Author: Yannick Vaucher
264-# Copyright 2013 Camptocamp SA
265-#
266-# This program is free software: you can redistribute it and/or modify
267-# it under the terms of the GNU Affero General Public License as
268-# published by the Free Software Foundation, either version 3 of the
269-# License, or (at your option) any later version.
270-#
271-# This program is distributed in the hope that it will be useful,
272-# but WITHOUT ANY WARRANTY; without even the implied warranty of
273-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
274-# GNU Affero General Public License for more details.
275-#
276-# You should have received a copy of the GNU Affero General Public License
277-# along with this program. If not, see <http://www.gnu.org/licenses/>.
278-#
279-##############################################################################
280-from pdf_utils import assemble_pdf
281-from openerp.osv import orm
282-
283-
284-class stock_picking(orm.Model):
285- _inherit = 'stock.picking'
286-
287- def get_pdf_label(self, cr, uid, ids, context=None):
288- """ Return a single pdf of labels for a stock picking
289-
290- If more than one label is found for a picking we merge one label per
291- tracking in a single pdf
292-
293- :return: a list of pdf file data
294- """
295- res = dict.fromkeys(ids, False)
296- label_obj = self.pool.get('shipping.label')
297- for picking_id in ids:
298- label_ids = label_obj.search(cr, uid,
299- [('file_type', '=', 'pdf'),
300- ('res_id', '=', picking_id)],
301- order='create_date',
302- context=context)
303- if label_ids:
304- all_picking_labels = label_obj.browse(cr, uid,
305- label_ids,
306- context=context)
307-
308- tracking_ids = [l.tracking_id for l in all_picking_labels]
309-
310- # filter for newest created label for each trackings
311- label_datas = []
312- tracking_ids = set(tracking_ids)
313- while tracking_ids:
314- tracking_id = tracking_ids.pop()
315- for label in all_picking_labels:
316- if label.tracking_id.id == tracking_id.id:
317- label_datas.append(label.datas.decode('base64'))
318-
319- label_pdf = assemble_pdf(label_datas)
320- res[picking_id] = label_pdf.encode('base64')
321- return res
322
323=== modified file 'delivery_carrier_label_dispatch/wizard/generate_labels.py'
324--- delivery_carrier_label_dispatch/wizard/generate_labels.py 2013-12-17 07:42:04 +0000
325+++ delivery_carrier_label_dispatch/wizard/generate_labels.py 2014-04-10 14:10:35 +0000
326@@ -18,11 +18,14 @@
327 # along with this program. If not, see <http://www.gnu.org/licenses/>.
328 #
329 ##############################################################################
330+from operator import attrgetter
331+from itertools import groupby
332+
333+from openerp.osv import orm, fields
334+from openerp.tools.translate import _
335+
336 from ..pdf_utils import assemble_pdf
337
338-from openerp.osv import orm, fields
339-from tools.translate import _
340-
341
342 class DeliveryCarrierLabelGenerate(orm.TransientModel):
343
344@@ -40,52 +43,106 @@
345 _columns = {
346 'dispatch_ids': fields.many2many('picking.dispatch',
347 string='Picking Dispatch'),
348- 'label_pdf_file': fields.binary('Labels file'),
349+ 'generate_new_labels': fields.boolean(
350+ 'Generate new labels',
351+ help="If this option is used, new labels will be "
352+ "generated for the packs even if they already have one.\n"
353+ "The default is to use the existing label."),
354 }
355
356 _defaults = {
357 'dispatch_ids': _get_dispatch_ids,
358+ 'generate_new_labels': False,
359 }
360
361+ def _get_packs(self, cr, uid, wizard, dispatch, context=None):
362+ moves = sorted(dispatch.move_ids, key=attrgetter('tracking_id.name'))
363+ for pack, moves in groupby(moves, key=attrgetter('tracking_id')):
364+ pack_label = self._find_pack_label(cr, uid, wizard, pack,
365+ context=context)
366+ yield pack, list(moves), pack_label
367+
368+ def _find_picking_label(self, cr, uid, wizard, picking, context=None):
369+ label_obj = self.pool['shipping.label']
370+ domain = [('file_type', '=', 'pdf'),
371+ ('res_id', '=', picking.id),
372+ ('tracking_id', '=', False),
373+ ]
374+ label_id = label_obj.search(cr, uid, domain, order='create_date DESC',
375+ limit=1, context=context)
376+ if not label_id:
377+ return None
378+ return label_obj.browse(cr, uid, label_id[0], context=context)
379+
380+ def _find_pack_label(self, cr, uid, wizard, pack, context=None):
381+ label_obj = self.pool['shipping.label']
382+ domain = [('file_type', '=', 'pdf'),
383+ ('tracking_id', '=', pack.id),
384+ ]
385+ label_id = label_obj.search(cr, uid, domain, order='create_date DESC',
386+ limit=1, context=context)
387+ if not label_id:
388+ return None
389+ return label_obj.browse(cr, uid, label_id[0], context=context)
390+
391+ def _get_all_pdf(self, cr, uid, wizard, dispatch, context=None):
392+ for pack, moves, label in self._get_packs(cr, uid, wizard, dispatch,
393+ context=context):
394+ if not label or wizard.generate_new_labels:
395+ picking_out_obj = self.pool['stock.picking.out']
396+ picking = moves[0].picking_id
397+ # generate the label of the pack
398+ if pack:
399+ tracking_ids = [pack.id]
400+ else:
401+ tracking_ids = None
402+ try:
403+ picking_out_obj.generate_labels(
404+ cr, uid, [picking.id],
405+ tracking_ids=tracking_ids,
406+ context=context)
407+ except orm.except_orm as e:
408+ picking_name = _('Picking: %s') % picking.name
409+ pack_num = _('Pack: %s') % pack.name if pack else ''
410+ raise orm.except_orm(
411+ e.name,
412+ _('%s %s - %s') % (picking_name, pack_num, e.value))
413+ if pack:
414+ label = self._find_pack_label(cr, uid, wizard, pack,
415+ context=context)
416+ else:
417+ label = self._find_picking_label(cr, uid, wizard, picking,
418+ context=context)
419+ if not label:
420+ continue # no label could be generated
421+ yield label
422+
423 def action_generate_labels(self, cr, uid, ids, context=None):
424 """
425 Call the creation of the delivery carrier label
426 of the missing labels and get the existing ones
427 Then merge all of them in a single PDF
428+
429 """
430 this = self.browse(cr, uid, ids, context=context)[0]
431 if not this.dispatch_ids:
432 raise orm.except_orm(_('Error'), _('No picking dispatch selected'))
433
434- picking_out_obj = self.pool.get('stock.picking.out')
435-
436- # flatten all picking in one list to keep the order in case
437- # there are multiple dispatch or if pickings
438- # have been ordered to ease packaging
439- pickings = [(pick, pick.get_pdf_label()[pick.id])
440- for dispatch in this.dispatch_ids
441- for pick in dispatch.related_picking_ids]
442- # get picking ids for which we want to generate pdf label
443- picking_ids = [pick.id for pick, pdf in pickings
444- if not pdf]
445- # generate missing picking labels
446- picking_out_obj.action_generate_carrier_label(cr, uid,
447- picking_ids,
448- #file_type='pdf',
449- context=context)
450-
451- # Get all pdf files adding the newly generated ones
452- data_list = [pdf or pick.get_pdf_label()[pick.id]
453- for pick, pdf in pickings]
454- pdf_list = [data.decode('base64') for data in data_list if data]
455- pdf_file = assemble_pdf(pdf_list)
456- this.write({'label_pdf_file': pdf_file.encode('base64')})
457+ attachment_obj = self.pool.get('ir.attachment')
458+
459+ for dispatch in this.dispatch_ids:
460+ labels = self._get_all_pdf(cr, uid, this, dispatch,
461+ context=context)
462+ labels = (label.datas for label in labels)
463+ labels = (label.decode('base64') for label in labels if labels)
464+ data = {
465+ 'name': dispatch.name + '.pdf',
466+ 'res_id': dispatch.id,
467+ 'res_model': 'picking.dispatch',
468+ 'datas': assemble_pdf(labels).encode('base64'),
469+ }
470+ attachment_obj.create(cr, uid, data, context=context)
471+
472 return {
473- 'type': 'ir.actions.act_window',
474- 'res_model': 'delivery.carrier.label.generate',
475- 'view_mode': 'form',
476- 'view_type': 'form',
477- 'res_id': this.id,
478- 'views': [(False, 'form')],
479- 'target': 'new',
480+ 'type': 'ir.actions.act_window_close',
481 }
482
483=== modified file 'delivery_carrier_label_dispatch/wizard/generate_labels_view.xml'
484--- delivery_carrier_label_dispatch/wizard/generate_labels_view.xml 2013-12-06 12:51:58 +0000
485+++ delivery_carrier_label_dispatch/wizard/generate_labels_view.xml 2014-04-10 14:10:35 +0000
486@@ -7,13 +7,12 @@
487 <field name="model">delivery.carrier.label.generate</field>
488 <field name="arch" type="xml">
489 <form string="Generate Carriers Labels" version="7.0">
490-
491+ <group>
492+ <label string="This wizard creates an attachement on each selected dispatch containing picking labels"/>
493+ </group>
494 <group>
495 <field name="dispatch_ids"/>
496- </group>
497- <separator string="Labels"/>
498- <group>
499- <field name="label_pdf_file" filename="picking_labels.pdf"/>
500+ <field name="generate_new_labels"/>
501 </group>
502 <footer>
503 <button name="action_generate_labels" string="Generate Labels" type="object" icon="gtk-execute" class="oe_highlight"/>

Subscribers

People subscribed via source and target branches