diff --git a/addons/stock/static/src/js/widgets.js b/addons/stock/static/src/js/widgets.js index b3dff621208..6110e325efd 100644 --- a/addons/stock/static/src/js/widgets.js +++ b/addons/stock/static/src/js/widgets.js @@ -26,140 +26,181 @@ function openerp_picking_widgets(instance){ template: 'PickingEditorWidget', init: function(parent,options){ this._super(parent,options); + this.rows = []; }, get_rows: function(){ var model = this.getParent(); - var rows = []; + this.rows = []; var self = this; _.each( model.packoplines, function(packopline){ - rows.push({ - cols: { product: packopline.product_id[1], - qty: packopline.product_qty, - rem: packopline.remaining_qty, - uom: packopline.product_uom_id[1], - lot: packopline.lot_id[1], - pack: packopline.package_id[1], - container: packopline.result_package_id[1], - loc: packopline.location_id[1], - dest: packopline.location_dest_id[1], - id: packopline.product_id[0], - }, - classes: (packopline.qty_remaining < 0 ? 'danger' : ''), - }); + if (packopline.processed === 'false'){ + var pack = undefined; + if (packopline.product_id[1] !== undefined){ pack = packopline.package_id[1];} + self.rows.push({ + cols: { product: packopline.product_id[1] || packopline.package_id[1], + qty: packopline.product_qty, + rem: packopline.qty_done, + uom: packopline.product_uom_id[1], + lot: packopline.lot_id[1], + pack: pack, + container: packopline.result_package_id[1], + loc: packopline.location_id[1], + dest: packopline.location_dest_id[1], + id: packopline.id, + product_id: packopline.product_id[0], + }, + classes: (packopline.product_qty <= packopline.qty_done ? 'active' : ''), + }); + } }); - return rows; + return self.rows; }, renderElement: function(){ var self = this; this._super(); this.$('.js_pack_scan').click(function(){ var id = parseInt($(this).attr('op-id')); - console.log('Id:',id); self.getParent().scan_product_id(id); }); + this.$('.js_pack_op_line').click(function(){ + if (this.classList.contains('warning')){ + $(this).removeClass('warning'); + } + else{ + $(this).addClass('warning'); + } + }); //remove navigtion bar from default openerp GUI $('td.navbar').html('
'); }, on_searchbox: function(query){ - var self = this; + //hide line that has no location matching the query and highlight location that match the query if (query !== '') { - this.$('.js_loc:not(.js_loc:contains('+query+'))').removeClass('warning'); - this.$('.js_loc:contains('+query+')').addClass('warning'); + this.$('.js_loc:not(.js_loc:contains('+query+'))').removeClass('info'); + this.$('.js_loc:contains('+query+')').addClass('info'); this.$('.js_pack_op_line:not(.js_pack_op_line:has(.js_loc:contains('+query+')))').addClass('hidden'); this.$('.js_pack_op_line:has(.js_loc:contains('+query+'))').removeClass('hidden'); } + //if no query specified, then show everything if (query === '') { - this.$('.js_loc').removeClass('warning'); - this.$('.js_pack_op_line.hidden').removeClass('hidden'); + this.$('.js_pack_op_line.warning').removeClass('warning'); + this.$('.js_loc').removeClass('info'); + this.$('.js_pack_op_line.hidden').removeClass('hidden'); } - return true; + }, + get_current_op_selection: function(){ + //get ids of visible on the screen + pack_op_ids = [] + if (this.$('.js_pack_op_line.warning:not(.js_pack_op_line.hidden)').length > 0){ + console.log('some selected'); + this.$('.js_pack_op_line.warning:not(.js_pack_op_line.hidden)').each(function(){ + cur_id = this.attributes.getNamedItem('data-id').value; + pack_op_ids.push(parseInt(cur_id)); + }); + } + else{ + console.log('nothing selected'); + this.$('.js_pack_op_line:not(.js_pack_op_line.hidden)').each(function(){ + cur_id = this.attributes.getNamedItem('data-id').value; + pack_op_ids.push(parseInt(cur_id)); + }); + } + //get list of element in this.rows where rem > 0 and container is empty + list = [] + _.each(this.rows, function(row){ + if (row.cols.rem > 0 && row.cols.container === undefined){ + list.push(row.cols.id); + } + }); + //return only those visible with rem qty > 0 and container empty + return _.intersection(pack_op_ids, list); } }); - module.PackageEditorWidget = instance.web.Widget.extend({ - template: 'PackageEditorWidget', - get_header: function(){ - var model = this.getParent(); - var current_package = model.get_selected_package(); - return current_package ? 'Operations for Package: ' + current_package.name : 'Current Operations'; - }, - get_rows: function(){ - var model = this.getParent(); - var rows = []; - var ops = model.get_current_operations(); - _.each( ops, function(op){ - rows.push({ - cols: { - product: (op.package_id ? op.package_id[1] : op.product_id[1]) + (op.lot_id ? ' Lot: ' + op.lot_id[1] : ''), - uom: op.product_uom ? product_uom[1] : '', - qty: op.product_qty, - }, - classes: 'js_pack_op '+ (op.id === model.get_selected_operation() ? 'warning' : ''), - att_op_id: op.id, - }); - }); + // module.PackageEditorWidget = instance.web.Widget.extend({ + // template: 'PackageEditorWidget', + // get_header: function(){ + // var model = this.getParent(); + // var current_package = model.get_selected_package(); + // return current_package ? 'Operations for Package: ' + current_package.name : 'Current Operations'; + // }, + // get_rows: function(){ + // var model = this.getParent(); + // var rows = []; + // var ops = model.get_current_operations(); + // _.each( ops, function(op){ + // rows.push({ + // cols: { + // product: (op.package_id ? op.package_id[1] : op.product_id[1]) + (op.lot_id ? ' Lot: ' + op.lot_id[1] : ''), + // uom: op.product_uom ? product_uom[1] : '', + // qty: op.product_qty, + // }, + // classes: 'js_pack_op '+ (op.id === model.get_selected_operation() ? 'warning' : ''), + // att_op_id: op.id, + // }); + // }); - return rows; - }, - renderElement: function(){ - var self = this; - this._super(); - var model = this.getParent(); - this.$('.js_pack_op').click(function(){ - if (!this.classList.contains('warning')){ - self.$('.js_pack_op').removeClass('warning'); - $(this).addClass('warning'); - model.set_selected_operation(parseInt($(this).attr('op-id'))); - } else { - $(this).removeClass('warning'); - model.set_selected_operation(null); - }; - }); - }, - }); + // return rows; + // }, + // renderElement: function(){ + // var self = this; + // this._super(); + // var model = this.getParent(); + // this.$('.js_pack_op').click(function(){ + // if (!this.classList.contains('warning')){ + // self.$('.js_pack_op').removeClass('warning'); + // $(this).addClass('warning'); + // model.set_selected_operation(parseInt($(this).attr('op-id'))); + // } else { + // $(this).removeClass('warning'); + // model.set_selected_operation(null); + // }; + // }); + // }, + // }); - module.PackageSelectorWidget = instance.web.Widget.extend({ - template: 'PackageSelectorWidget', - get_header: function(){ - return this._header || 'Packages:'; - }, - get_rows: function(){ - var model = this.getParent(); - var current_package = model.get_selected_package(); - var rows = []; - _.each( model.packages, function(pack){ - rows.push({ - cols:{ pack: pack.name}, - id: pack.id, - classes: pack === current_package ? ' warning' : '' , - }); - }); - return rows; - }, - renderElement: function(){ - this._super(); - var model = this.getParent(); - 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_op(pack_id); }); - $('.js_pack_minus', this).click(function(){ - if(model.get_selected_package() && model.get_selected_package().id === pack_id){ - model.deselect_package(); - } - model.delete_package_op(pack_id); }); - $('.js_pack_select', this).click(function(){ - if(model.get_selected_package() && model.get_selected_package().id === pack_id){ - model.deselect_package(); - }else{ - model.select_package(pack_id); - } - }); - }); - }, - }); + // module.PackageSelectorWidget = instance.web.Widget.extend({ + // template: 'PackageSelectorWidget', + // get_header: function(){ + // return this._header || 'Packages:'; + // }, + // get_rows: function(){ + // var model = this.getParent(); + // var current_package = model.get_selected_package(); + // var rows = []; + // _.each( model.packages, function(pack){ + // rows.push({ + // cols:{ pack: pack.name}, + // id: pack.id, + // classes: pack === current_package ? ' warning' : '' , + // }); + // }); + // return rows; + // }, + // renderElement: function(){ + // this._super(); + // var model = this.getParent(); + // 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_op(pack_id); }); + // $('.js_pack_minus', this).click(function(){ + // if(model.get_selected_package() && model.get_selected_package().id === pack_id){ + // model.deselect_package(); + // } + // model.delete_package_op(pack_id); }); + // $('.js_pack_select', this).click(function(){ + // if(model.get_selected_package() && model.get_selected_package().id === pack_id){ + // model.deselect_package(); + // }else{ + // model.select_package(pack_id); + // } + // }); + // }); + // }, + // }); module.PickingMenuWidget = module.MobileWidget.extend({ template: 'PickingMenuWidget', @@ -434,6 +475,14 @@ function openerp_picking_widgets(instance){ this.$('.oe_searchbox').keyup(function(event){ self.on_searchbox($(this).val()); }); + this.$('.js_clear_search').click(function(){ + self.on_searchbox(''); + self.$('.oe_searchbox').val(''); + }); + this.$('.js_pack_op_line').click(function(){ + console.log("click line"); + $(this).addClass('warning'); + }); this.hotkey_handler = function(event){ if(event.keyCode === 37 ){ // Left Arrow @@ -449,11 +498,11 @@ function openerp_picking_widgets(instance){ self.picking_editor = new module.PickingEditorWidget(self); self.picking_editor.replace(self.$('.oe_placeholder_picking_editor')); - self.package_editor = new module.PackageEditorWidget(self); - self.package_editor.replace(self.$('.oe_placeholder_package_editor')); + // self.package_editor = new module.PackageEditorWidget(self); + // self.package_editor.replace(self.$('.oe_placeholder_package_editor')); - self.package_selector = new module.PackageSelectorWidget(self); - self.package_selector.replace(self.$('.oe_placeholder_package_selector')); + // self.package_selector = new module.PackageSelectorWidget(self); + // self.package_selector.replace(self.$('.oe_placeholder_package_selector')); if( self.picking.id === self.pickings[0]){ self.$('.js_pick_prev').addClass('disabled'); @@ -475,17 +524,20 @@ function openerp_picking_widgets(instance){ on_searchbox: function(query){ var self = this; self.picking_editor.on_searchbox(query); - // self.refresh_ui(self.picking); }, // reloads the data from the provided picking and refresh the ui. // (if no picking_id is provided, gets the first picking in the db) refresh_ui: function(picking_id){ var self = this; + var remove_search_filter = true; + if (self.picking.id === picking_id){ + remove_search_filter = false; + } return this.load(picking_id) - .then(function(){ + .then(function(){ self.picking_editor.renderElement(); - self.package_editor.renderElement(); - self.package_selector.renderElement(); + // self.package_editor.renderElement(); + // self.package_selector.renderElement(); if( self.picking.id === self.pickings[0]){ self.$('.js_pick_prev').addClass('disabled'); @@ -499,6 +551,13 @@ function openerp_picking_widgets(instance){ self.$('.js_pick_next').removeClass('disabled'); } self.$('.oe_pick_app_header').text(self.get_header()); + if (remove_search_filter){ + self.$('.oe_searchbox').val(''); + self.on_searchbox(''); + } + else{ + self.on_searchbox(self.$('.oe_searchbox').val()); + } }); }, get_header: function(){ @@ -538,13 +597,15 @@ function openerp_picking_widgets(instance){ }, pack: function(){ var self = this; - new instance.web.Model('stock.picking') - .call('action_pack',[[[self.picking.id]]]) - .then(function(){ - instance.session.user_context.current_package_id = false; - - return self.refresh_ui(self.picking.id); - }); + var pack_op_ids = self.picking_editor.get_current_op_selection(); + if (pack_op_ids.length !== 0){ + new instance.web.Model('stock.picking') + .call('action_pack',[[[self.picking.id]], pack_op_ids]) + .then(function(){ + instance.session.user_context.current_package_id = false; + return self.refresh_ui(self.picking.id); + }); + } }, done: function(){ var self = this; @@ -605,44 +666,44 @@ function openerp_picking_widgets(instance){ } } }, - copy_package_op: function(pack_id){ - var self = this; - new instance.web.Model('stock.quant.package').call('copy_pack',[pack_id]) - .then(function(){ - return self.refresh_ui(self.picking.id); - }); - }, - delete_package_op: function(pack_id){ - var self = this; - new instance.web.Model('stock.pack.operation').call('search', [[['result_package_id', '=', pack_id]]]) - .then(function(op_ids) { - new instance.web.Model('stock.pack.operation').call('unlink', [op_ids]) - .then(function() { - return self.refresh_ui(self.picking.id); - }); - }); - }, - deselect_package: function(){ - instance.session.user_context.current_package_id = false; - this.package_editor.renderElement(); - this.package_selector.renderElement(); - }, - select_package: function(package_id){ - instance.session.user_context.current_package_id = package_id; - this.package_editor.renderElement(); - this.package_selector.renderElement(); - }, - get_selected_package: function(){ - var current_package; + // copy_package_op: function(pack_id){ + // var self = this; + // new instance.web.Model('stock.quant.package').call('copy_pack',[pack_id]) + // .then(function(){ + // return self.refresh_ui(self.picking.id); + // }); + // }, + // delete_package_op: function(pack_id){ + // var self = this; + // new instance.web.Model('stock.pack.operation').call('search', [[['result_package_id', '=', pack_id]]]) + // .then(function(op_ids) { + // new instance.web.Model('stock.pack.operation').call('unlink', [op_ids]) + // .then(function() { + // return self.refresh_ui(self.picking.id); + // }); + // }); + // }, + // deselect_package: function(){ + // instance.session.user_context.current_package_id = false; + // this.package_editor.renderElement(); + // this.package_selector.renderElement(); + // }, + // select_package: function(package_id){ + // instance.session.user_context.current_package_id = package_id; + // this.package_editor.renderElement(); + // this.package_selector.renderElement(); + // }, + // get_selected_package: function(){ + // var current_package; - _.each( this.packages, function(pack){ - if(pack.id === instance.session.user_context.current_package_id){ - current_package = pack; - } - }); + // _.each( this.packages, function(pack){ + // if(pack.id === instance.session.user_context.current_package_id){ + // current_package = pack; + // } + // }); - return current_package; - }, + // return current_package; + // }, get_current_operations: function(){ var current_package_id = instance.session.user_context.current_package_id; var ops = []; @@ -656,7 +717,6 @@ function openerp_picking_widgets(instance){ } ops.push(op); }); - console.log('Current Operations:',ops); return ops; }, get_selected_operation: function(){ @@ -708,7 +768,6 @@ function openerp_picking_widgets(instance){ }else if(e.keyCode >= 48 && e.keyCode <= 57){ // NUMPAD NUMBERS numpad.push(e.keyCode - 48); }else if(e.keyCode === 13){ // ENTER - console.log('enter'); if(numpad.length > 0){ self.set_operation_quantity(parseInt(numpad.join(''))); } diff --git a/addons/stock/static/src/xml/picking.xml b/addons/stock/static/src/xml/picking.xml index b6968bbc98b..ad48c70bdb8 100644 --- a/addons/stock/static/src/xml/picking.xml +++ b/addons/stock/static/src/xml/picking.xml @@ -51,14 +51,12 @@

Operations Informations

- +
- - @@ -70,17 +68,16 @@ - - + - + - - + + @@ -241,7 +238,8 @@

- + +
diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 69d5be34957..1f0803b13d4 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1216,20 +1216,34 @@ class stock_picking(osv.osv): #return id of next picking to work on return self.get_next_picking_for_ui(cr, uid, context=context) - def action_pack(self, cr, uid, picking_ids, context=None): + def action_pack(self, cr, uid, picking_ids, operation_filter_ids=None, context=None): """ Create a package with the current pack_operation_ids of the picking that aren't yet in a pack. - Used in the barcode scanner UI and the normal interface as well. """ + Used in the barcode scanner UI and the normal interface as well. + operation_filter_ids is used by barcode scanner interface to specify a subset of operation to pack""" + if operation_filter_ids == None: + operation_filter_ids = [] stock_operation_obj = self.pool.get('stock.pack.operation') package_obj = self.pool.get('stock.quant.package') stock_move_obj = self.pool.get('stock.move') for picking_id in picking_ids: - operation_ids = stock_operation_obj.search(cr, uid, [('picking_id', '=', picking_id), ('result_package_id', '=', False)], context=context) + operation_search_domain = [('picking_id', '=', picking_id), ('result_package_id', '=', False)] + if operation_filter_ids != []: + operation_search_domain.append(('id', 'in', operation_filter_ids)) + operation_ids = stock_operation_obj.search(cr, uid, operation_search_domain, context=context) + pack_operation_ids = [] if operation_ids: for operation in stock_operation_obj.browse(cr, uid, operation_ids, context=context): - for record in operation.linked_move_operation_ids: - stock_move_obj.check_tracking(cr, uid, record.move_id, operation.package_id.id or operation.lot_id.id, context=context) + #If we haven't done all qty in operation, we have to split into 2 operation + op = operation + if (operation.qty_done < operation.product_qty): + new_operation = stock_operation_obj.copy(cr, uid, operation.id, {'product_qty': operation.qty_done,'qty_done': operation.qty_done}, context=context) + stock_operation_obj.write(cr, uid, operation.id, {'product_qty': operation.product_qty - operation.qty_done,'qty_done': 0}, context=context) + op = stock_operation_obj.browse(cr, uid, new_operation, context=context) + pack_operation_ids.append(op.id) + for record in op.linked_move_operation_ids: + stock_move_obj.check_tracking(cr, uid, record.move_id, op.package_id.id or op.lot_id.id, context=context) package_id = package_obj.create(cr, uid, {}, context=context) - stock_operation_obj.write(cr, uid, operation_ids, {'result_package_id': package_id}, context=context) + stock_operation_obj.write(cr, uid, pack_operation_ids, {'result_package_id': package_id}, context=context) return True def process_product_id_from_ui(self, cr, uid, picking_id, product_id, context=None): @@ -3471,6 +3485,7 @@ class stock_pack_operation(osv.osv): 'product_id': fields.many2one('product.product', 'Product', ondelete="CASCADE"), # 1 'product_uom_id': fields.many2one('product.uom', 'Product Unit of Measure'), 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True), + 'qty_done': fields.float('Quantity Processed', digits_compute=dp.get_precision('Product Unit of Measure')), 'package_id': fields.many2one('stock.quant.package', 'Package'), # 2 'lot_id': fields.many2one('stock.production.lot', 'Lot/Serial Number'), 'result_package_id': fields.many2one('stock.quant.package', 'Container Package', help="If set, the operations are packed into this package", required=False, ondelete='cascade'), @@ -3483,10 +3498,13 @@ class stock_pack_operation(osv.osv): 'remaining_qty': fields.function(_get_remaining_qty, type='float', string='Remaining Qty'), 'location_id': fields.many2one('stock.location', 'Location From'), 'location_dest_id': fields.many2one('stock.location', 'Location To'), + 'processed': fields.selection([('true','Yes'), ('false','No')],'Has been processed?', required=True), } _defaults = { 'date': fields.date.context_today, + 'qty_done': 0, + 'processed': lambda *a: 'false', } def write(self, cr, uid, ids, vals, context=None): @@ -3621,13 +3639,14 @@ class stock_pack_operation(osv.osv): if existing_operation_ids: #existing operation found for the given domain and picking => increment its quantity operation_id = existing_operation_ids[0] - qty = self.browse(cr, uid, operation_id, context=context).product_qty + 1 - self.write(cr, uid, [operation_id], {'product_qty': qty}, context=context) + qty = self.browse(cr, uid, operation_id, context=context).qty_done + 1 + self.write(cr, uid, [operation_id], {'qty_done': qty}, context=context) else: #no existing operation found for the given domain and picking => create a new one values = { 'picking_id': picking_id, 'product_qty': 1, + 'qty_done': 1, } for key in domain: var_name, dummy, value = key

Product Total Qty Qty done Source Location Destination Location Lot