diff --git a/addons/stock/report/picking.py b/addons/stock/report/picking.py index d9d306caefb..ba5e74d2143 100644 --- a/addons/stock/report/picking.py +++ b/addons/stock/report/picking.py @@ -36,5 +36,6 @@ class picking(report_sxw.rml_parse): desc = '[' + move_line.product_id.default_code + ']' + ' ' + desc return desc -report_sxw.report_sxw('report.stock.picking.list','stock.picking','addons/stock/report/picking.rml',parser=picking, header='internal') +report_sxw.report_sxw('report.stock.picking.list','stock.picking','addons/stock/report/picking.rml',parser=picking) +report_sxw.report_sxw('report.stock.picking.list.internal','stock.picking','addons/stock/report/picking_internal.rml',parser=picking, header='internal') # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/stock/report/picking.rml b/addons/stock/report/picking.rml index e8e1268063b..9fa5e0306b5 100644 --- a/addons/stock/report/picking.rml +++ b/addons/stock/report/picking.rml @@ -66,7 +66,6 @@ - @@ -76,7 +75,6 @@ - @@ -86,7 +84,6 @@ - @@ -134,7 +131,7 @@ - + Description @@ -151,9 +148,6 @@ Quantity - - Barcode - @@ -162,6 +156,24 @@ + + + + Supplier Address : [[ (picking.type == 'in' or removeParentNode('para')) and '' ]] + Customer Address : [[ (picking.type == 'out' or removeParentNode('para')) and '' ]] + Warehouse Address : [[ (picking.type == 'internal' or removeParentNode('para')) and '' ]] + [[ (picking.partner_id and picking.partner_id.id and picking.partner_id.title.name) or '' ]] [[ picking.partner_id and picking.partner_id.id and picking.partner_id.name ]] + [[ picking.partner_id and display_address(picking.partner_id) ]] + [[ picking.partner_id.phone or picking.partner_id.email or removeParentNode('para')]] + + + Contact Address : + [[ picking.partner_id and picking.partner_id.title.name or '' ]] [[ picking.partner_id and picking.partner_id.name or '' ]] + [[ picking.partner_id and display_address(picking.partner_id) ]] + [[ picking.partner_id.phone or picking.partner_id.email or removeParentNode('para')]] + + + @@ -215,7 +227,7 @@ - + Description @@ -232,15 +244,12 @@ Quantity - - Barcode -
[[ repeatIn([line for line in picking.move_lines if ((line.state == 'confirmed' or line.state=='done' or line.state=='assigned') and not line.scrapped)],'move_lines') ]] [[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]] - + [[ get_product_desc(move_lines) ]] @@ -259,9 +268,6 @@ [[ formatLang(move_lines.product_uom_qty) ]] [[ move_lines.product_uom.name ]] - - [[ move_lines.product_id.ean13 ]] -
@@ -270,7 +276,7 @@
[[ repeatIn([line for line in picking.move_lines if (line.state == 'draft' or line.state=='waiting')],'move_lines') ]] [[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]] - + [[ get_product_desc(move_lines) ]] @@ -289,9 +295,6 @@ [[ formatLang(move_lines.product_uom_qty) ]] [[ move_lines.product_uom.name ]] - - [[ move_lines.product_id.ean13 ]] -
diff --git a/addons/stock/report/picking_barcode.rml b/addons/stock/report/picking_barcode.rml new file mode 100644 index 00000000000..a0967d7ca01 --- /dev/null +++ b/addons/stock/report/picking_barcode.rml @@ -0,0 +1,11 @@ + + + + + [[ packaging_id.product_id.ean13 ]] + + diff --git a/addons/stock/report/picking_internal.rml b/addons/stock/report/picking_internal.rml new file mode 100644 index 00000000000..084f2a8381d --- /dev/null +++ b/addons/stock/report/picking_internal.rml @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Description + + + Lot + + + Status + + + Location + + + Quantity + + + Barcode + + + + + [[repeatIn(objects,'picking')]] + [[picking.type == 'out' and picking.partner_id and setLang(picking.partner_id.lang) or '']] + + + + + + + + + + + + + Delivery Order : [[ (picking.type == 'out' or removeParentNode('para')) and '' ]] [[ picking.name ]] + Incoming Shipment : [[ (picking.type == 'in' or removeParentNode('para')) and '' ]] [[ picking.name ]] + Internal Shipment : [[ (picking.type == 'internal' or removeParentNode('para')) and '' ]] [[ picking.name ]] + + + + + + + + + + Journal + + + Order(Origin) + + + Schedule Date + + + Weight + + + + + + + [[ picking.stock_journal_id.name]] + + + [[ picking.origin or '']] + + + [[ formatLang(picking.min_date,date_time = True) ]] + + + [[ 'weight' in picking._columns.keys() and picking.weight or '']] + + + + + + + + + + Description + + + Serial Number + + + Status + + + Location + + + Quantity + + + Barcode + + + +
+ [[ repeatIn([line for line in picking.move_lines if ((line.state == 'confirmed' or line.state=='done' or line.state=='assigned') and not line.scrapped)],'move_lines') ]] + [[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]] + + + + [[ get_product_desc(move_lines) ]] + + + [[ (move_lines.prodlot_id and move_lines.prodlot_id.name) or '' ]] + + + Waiting Availability[[ move_lines.state == 'confirmed' and ' ' or removeParentNode('para') ]] + Done[[ move_lines.state == 'done' and ' ' or removeParentNode('para') ]] + Available[[ move_lines.state == 'assigned' and ' ' or removeParentNode('para') ]] + + + [[ (move_lines.location_id and move_lines.location_id.name) or '' ]] + + + [[ formatLang(move_lines.product_qty) ]] [[ move_lines.product_uom.name ]] + + + [[ move_lines.product_id.ean13 ]] + + + +
+ [[ ([line for line in picking.move_lines if (line.state == 'draft' or line.state=='waiting' )]) and 'Non Assigned Products:' or removeParentNode('para') ]] + +
+ [[ repeatIn([line for line in picking.move_lines if (line.state == 'draft' or line.state=='waiting')],'move_lines') ]] + [[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]] + + + + [[ get_product_desc(move_lines) ]] + + + [[ (move_lines.prodlot_id and move_lines.prodlot_id.name) or '' ]] + + + [[ (picking.type == 'in' or removeParentNode('para')) ]][[ move_lines.state == 'done' and 'Received' or move_lines.state]] + [[ (picking.type == 'out' or removeParentNode('para')) ]][[ move_lines.state == 'done' and 'Delivered' or move_lines.state]] + [[ (picking.type == 'internal' or removeParentNode('para')) ]][[ move_lines.state == 'done' and 'Transferred' or move_lines.state]] + + + [[ (move_lines.location_id and move_lines.location_id.name) or '' ]] + + + [[ formatLang(move_lines.product_qty) ]] [[ move_lines.product_uom.name ]] + + + [[ move_lines.product_id.ean13 ]] + + + +
+ + + +
+
+
diff --git a/addons/stock/static/src/js/widgets.js b/addons/stock/static/src/js/widgets.js index dfa6774cc08..1c5de1dc17f 100644 --- a/addons/stock/static/src/js/widgets.js +++ b/addons/stock/static/src/js/widgets.js @@ -82,6 +82,7 @@ function openerp_picking_widgets(instance){ this.$('.js_pack_row').each(function(){ var pack_id = parseInt($(this).attr('pack-id')); + $('.js_pack_print', this).click(function(){ model.print_package(pack_id); }); $('.js_pack_plus', this).click(function(){ model.copy_package(pack_id); }); $('.js_pack_minus', this).click(function(){ model.delete_package(pack_id); }); $('.js_pack_select', this).click(function(){ @@ -229,7 +230,17 @@ function openerp_picking_widgets(instance){ .call('action_done_from_packing_ui',[self.picking.id]) .then(function(new_picking_id){ console.log('New picking id:',new_picking_id); - //return self.refresh_ui(new_picking_id); + return self.refresh_ui(new_picking_id); + }); + }, + print_package: function(package_id){ + var self = this; + console.log('Print Package:',package_id); + new instance.web.Model('stock.quant.package') + .call('action_print',[[package_id]]) + .then(function(action){ + console.log('Print Package Repport Action:',action); + return self.do_action(action); }); }, copy_package: function(package_id){ diff --git a/addons/stock/static/src/xml/picking.xml b/addons/stock/static/src/xml/picking.xml index c90d8a6e520..77215e20729 100644 --- a/addons/stock/static/src/xml/picking.xml +++ b/addons/stock/static/src/xml/picking.xml @@ -130,11 +130,12 @@ + - Package + Package @@ -142,8 +143,9 @@ - copy - delete + Print + Copy + Delete diff --git a/addons/stock/stock.py b/addons/stock/stock.py index c0fd277cb69..48b948714ce 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1108,6 +1108,20 @@ class stock_move(osv.osv): res[m.id] = uom_obj._compute_qty_obj(cr, uid, m.product_uom, m.product_uom_qty, m.product_id.uom_id) return res + def _get_remaining_qty(self, cr, uid, ids, field_name, args, context=None): + #TODO: this function assumes that there aren't several stock move in the same picking with the same product. what should we do in that case? + #TODO take care of the quant on stock moves too + res = dict.fromkeys(ids, False) + for move in self.browse(cr, uid, ids, context=context): + res[move.id] = move.product_qty + for op in move.picking_id.pack_operation_ids: + if op.product_id == move.product_id or (op.quant_id and op.quant_id.product_id == move.product_id): + res[move.id] -= op.product_qty + if op.package_id: + #find the product qty recursively + res[move.id] -= self.pool.get('stock.quant.package')._get_product_total_qty(cr, uid, op.package_id, move.product_id.id, context=context) + return res + _columns = { 'name': fields.char('Description', required=True, select=True), 'priority': fields.selection([('0', 'Not urgent'), ('1', 'Urgent')], 'Priority'), @@ -1171,13 +1185,10 @@ class stock_move(osv.osv): # used for colors in tree views: 'scrapped': fields.related('location_dest_id','scrap_location',type='boolean',relation='stock.location',string='Scrapped', readonly=True), 'type': fields.related('picking_id', 'type', type='selection', selection=[('out', 'Sending Goods'), ('in', 'Getting Goods'), ('internal', 'Internal')], string='Shipping Type'), - 'quant_ids': fields.many2many('stock.quant', 'stock_quant_move_rel', 'move_id', 'quant_id', 'Quants'), 'reserved_quant_ids': fields.one2many('stock.quant', 'reservation_id', 'Reserved quants'), - - # FP Note: this should be a function field - 'remaining_qty': fields.float('Remaining Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}), # to be used in pick/pack new interface # TODO change this in a functional field to ease the handling - 'group_id': fields.many2one('procurement.group', 'Procurement Group'), + 'remaining_qty': fields.function(_get_remaining_qty, type='float', string='Remaining Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}), + 'group_id': fields.many2one('procurement.group', 'Procurement Group'), } def _check_location(self, cr, uid, ids, context=None): @@ -2268,6 +2279,10 @@ class stock_picking_out(osv.osv): # ------------------------- # Packaging related stuff # ------------------------- + +from openerp.report import report_sxw +report_sxw.report_sxw('report.stock.quant.package.barcode', 'stock.quant.package', 'addons/stock/report/picking_barcode.rml') + class stock_package(osv.osv): """ These are the packages, containing quants and/or others packages @@ -2296,6 +2311,20 @@ class stock_package(osv.osv): (_check_location, 'All quant inside a package should be in the same location', ['location_id']), ] + def action_print(self, cr, uid, ids, context=None): + if context is None: + context = {} + datas = { + 'ids': context.get('active_id') and [context.get('active_id')] or ids, + 'model': 'stock.quant.package', + 'form': self.read(cr, uid, ids)[0] + } + return { + 'type': 'ir.actions.report.xml', + 'report_name': 'stock.quant.package.barcode', + 'datas': datas + } + # FP Note: why not just over ridding the copy method? def action_copy(self, cr, uid, ids, context=None): stock_operation_obj = self.pool.get('stock.pack.operation') @@ -2316,6 +2345,16 @@ class stock_package(osv.osv): res += [qt.id for qt in package_record.quant_ids] return res + def _get_product_total_qty(self, cr, uid, package_record, product_id, context=None): + ''' find the total of given product 'product_id' inside the given package 'package_id''' + quant_obj = self.pool.get('stock.quant') + all_quant_ids = self.find_all_quants(cr, uid, package_record, context=context) + total = 0 + for quant in quant_obj.browse(cr, uid, all_quant_ids, context=context): + if quant.product_id.id == product_id: + total += quant.product_qty + return total + class stock_pack_operation(osv.osv): _name = "stock.pack.operation" diff --git a/addons/stock/stock_report.xml b/addons/stock/stock_report.xml index 540e6a8f902..1cd72b90a83 100644 --- a/addons/stock/stock_report.xml +++ b/addons/stock/stock_report.xml @@ -2,7 +2,8 @@ - + + diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index 00717b27179..399bc45c1ec 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -1173,6 +1173,14 @@ + + Stock picking + stock.ui + stock + + + +