From 8dc8302dadfbc16592d18669c0b99edcbb123f86 Mon Sep 17 00:00:00 2001 From: Nicolas Seinlet <nse@odoo.com> Date: Thu, 7 Aug 2014 08:57:48 +0200 Subject: [PATCH] [ADD] wms: add option to select package type in WMS barcode interface --- addons/stock/static/src/js/widgets.js | 80 +++++++++++++++++++------ addons/stock/static/src/xml/picking.xml | 65 +++++++++++++------- 2 files changed, 108 insertions(+), 37 deletions(-) diff --git a/addons/stock/static/src/js/widgets.js b/addons/stock/static/src/js/widgets.js index 80d3ba65ba30..c38be6ca88a0 100644 --- a/addons/stock/static/src/js/widgets.js +++ b/addons/stock/static/src/js/widgets.js @@ -46,6 +46,15 @@ function openerp_picking_widgets(instance){ }); return locations; }, + get_logisticunit: function(){ + var model = this.getParent(); + var ul = []; + var self = this; + _.each(model.uls, function(ulog){ + ul.push({name: ulog.name, id: ulog.id,}); + }); + return ul; + }, get_rows: function(){ var model = this.getParent(); this.rows = []; @@ -59,6 +68,7 @@ function openerp_picking_widgets(instance){ if (packopline.product_qty < packopline.qty_done){ color = "danger "; } //also check that we don't have a line already existing for that package if (packopline.result_package_id[1] !== undefined && $.inArray(packopline.result_package_id[0], pack_created) === -1){ + var myPackage = $.grep(model.packages, function(e){ return e.id == packopline.result_package_id[0]; })[0]; self.rows.push({ cols: { product: packopline.result_package_id[1], qty: '', @@ -75,6 +85,8 @@ function openerp_picking_widgets(instance){ can_scan: false, head_container: true, processed: packopline.processed, + package_id: myPackage.id, + ul_id: myPackage.ul_id[0], }, classes: ('success container_head ') + (packopline.processed === "true" ? 'processed hidden ':''), }); @@ -96,6 +108,8 @@ function openerp_picking_widgets(instance){ can_scan: packopline.result_package_id[1] === undefined ? true : false, head_container: false, processed: packopline.processed, + package_id: undefined, + ul_id: -1, }, classes: color + (packopline.result_package_id[1] !== undefined ? 'in_container_hidden ' : '') + (packopline.processed === "true" ? 'processed hidden ':''), }); @@ -132,10 +146,10 @@ function openerp_picking_widgets(instance){ this.$('.oe_searchbox').keyup(function(event){ self.on_searchbox($(this).val()); }); - this.$('.js_pick_pack').click(function(){ self.getParent().pack(); }); + this.$('.js_putinpack').click(function(){ self.getParent().pack(); }); this.$('.js_drop_down').click(function(){ self.getParent().drop_down();}); - this.$('.js_clear_search').click(function(){ - self.on_searchbox(''); + this.$('.js_clear_search').click(function(){ + self.on_searchbox(''); self.$('.oe_searchbox').val(''); }); this.$('.oe_searchbox').focus(function(){ @@ -181,14 +195,14 @@ function openerp_picking_widgets(instance){ //we unfold line.addClass('warning'); select.removeClass('in_container_hidden'); - select.addClass('in_container'); + select.addClass('in_container'); } else{ //we fold line.removeClass('warning'); select = self.$('.js_pack_op_line.in_container[data-container-id='+op_id+']') select.removeClass('in_container'); - select.addClass('in_container_hidden'); + select.addClass('in_container_hidden'); } }); this.$('.js_create_lot').click(function(){ @@ -201,7 +215,7 @@ function openerp_picking_widgets(instance){ $lot_modal.modal() //focus input $lot_modal.on('shown.bs.modal', function(){ - self.$('.js_lot_scan').focus(); + self.$('.js_lot_scan').focus(); }) //reactivate scanner when dialog close $lot_modal.on('hidden.bs.modal', function(){ @@ -298,6 +312,25 @@ function openerp_picking_widgets(instance){ } }); + this.$('.js_pack_configure').click(function(){ + var pack_id = $(this).parents(".js_pack_op_line:first").data('package-id'); + var ul_id = $(this).parents(".js_pack_op_line:first").data('ulid'); + self.$('#js_packconf_select').val(ul_id); + self.$('#js_packconf_select').data('pack-id',pack_id); + self.$el.siblings('#js_PackConfModal').modal(); + }); + this.$('.js_validate_pack').click(function(){ + //get current selection + var select_dom_element = self.$('#js_packconf_select'); + var ul_id = self.$('#js_packconf_select option:selected').data('ul-id'); + var pack_id = select_dom_element.data('pack-id'); + self.$el.siblings('#js_PackConfModal').modal('hide'); + if (pack_id){ + self.getParent().set_package_pack(pack_id, ul_id); + $('.container_head[data-package-id="'+pack_id+'"]').data('ulid', ul_id); + } + }); + //remove navigtion bar from default openerp GUI $('td.navbar').html('<div></div>'); }, @@ -439,7 +472,7 @@ function openerp_picking_widgets(instance){ self.pickings_by_type[0] = []; return new instance.web.Model('stock.picking').call('search_read',[ [['state','in', ['assigned', 'partially_available']]], [] ], {context: new instance.web.CompoundContext()}); - + }).then(function(pickings){ self.pickings = pickings; for(var i = 0; i < pickings.length; i++){ @@ -490,7 +523,7 @@ function openerp_picking_widgets(instance){ //avoid crash if a not supported char is given (like '\' or ')') return []; } - + var results = []; for(var i = 0; i < 100; i++){ r = re.exec(this.picking_search_string); @@ -584,6 +617,7 @@ function openerp_picking_widgets(instance){ this.packages = null; this.barcode_scanner = new module.BarcodeScanner(); this.locations = []; + this.uls = []; if(this.picking_id){ this.loaded = this.load(this.picking_id); }else{ @@ -597,7 +631,7 @@ function openerp_picking_widgets(instance){ load: function(picking_id){ var self = this; - + function load_picking_list(type_id){ var pickings = new $.Deferred(); new instance.web.Model('stock.picking') @@ -606,8 +640,8 @@ function openerp_picking_widgets(instance){ if(!picking_ids || picking_ids.length === 0){ (new instance.web.Dialog(self,{ title: _t('No Picking Available'), - buttons: [{ - text:_t('Ok'), + buttons: [{ + text:_t('Ok'), click: function(){ self.menu(); } @@ -634,7 +668,7 @@ function openerp_picking_widgets(instance){ return load_picking_list(self.picking.picking_type_id[0]); }); }else{ - // if we don't have a specified picking id, we load the pickings belong to the specified type, and then we take + // if we don't have a specified picking id, we load the pickings belong to the specified type, and then we take // the first one of that list as the active picking var loaded_picking = new $.Deferred(); load_picking_list(self.picking_type_id) @@ -685,6 +719,12 @@ function openerp_picking_widgets(instance){ return new instance.web.Model('stock.quant.package').call('read',[package_ids, [], new instance.web.CompoundContext()]) }).then(function(packages){ self.packages = packages; + }).then(function(){ + return new instance.web.Model('product.ul').call('search',[[]]) + }).then(function(uls_ids){ + return new instance.web.Model('product.ul').call('read',[uls_ids, []]) + }).then(function(uls){ + self.uls = uls; }); }, start: function(){ @@ -694,7 +734,7 @@ function openerp_picking_widgets(instance){ this.barcode_scanner.connect(function(ean){ self.scan(ean); }); - + this.$('.js_pick_quit').click(function(){ self.quit(); }); this.$('.js_pick_prev').click(function(){ self.picking_prev(); }); this.$('.js_pick_next').click(function(){ self.picking_next(); }); @@ -714,13 +754,13 @@ function openerp_picking_widgets(instance){ $.when(this.loaded).done(function(){ self.picking_editor = new module.PickingEditorWidget(self); self.picking_editor.replace(self.$('.oe_placeholder_picking_editor')); - + if( self.picking.id === self.pickings[0]){ self.$('.js_pick_prev').addClass('disabled'); }else{ self.$('.js_pick_prev').removeClass('disabled'); } - + if( self.picking.id === self.pickings[self.pickings.length-1] ){ self.$('.js_pick_next').addClass('disabled'); }else{ @@ -746,7 +786,7 @@ function openerp_picking_widgets(instance){ var self = this; self.picking_editor.on_searchbox(query.toUpperCase()); }, - // reloads the data from the provided picking and refresh the ui. + // 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; @@ -776,7 +816,7 @@ function openerp_picking_widgets(instance){ }else{ self.$('.js_pick_prev').removeClass('disabled'); } - + if( self.picking.id === self.pickings[self.pickings.length-1] ){ self.$('.js_pick_next').addClass('disabled'); }else{ @@ -958,6 +998,12 @@ function openerp_picking_widgets(instance){ } }, + set_package_pack: function(package_id, pack){ + var self = this; + new instance.web.Model('stock.quant.package') + .call('write',[[package_id],{'ul_id': pack }]); + return; + }, reload_pack_operation: function(){ var self = this; new instance.web.Model('stock.picking') diff --git a/addons/stock/static/src/xml/picking.xml b/addons/stock/static/src/xml/picking.xml index 8bc25b51d969..6f8921eef3cc 100644 --- a/addons/stock/static/src/xml/picking.xml +++ b/addons/stock/static/src/xml/picking.xml @@ -2,7 +2,7 @@ <templates id="template" xml:space="preserve"> <t t-name='PickingEditorWidget'> - + <div class="modal fade" id="js_LocationChooseModal" tabindex="-1" role="dialog" aria-labelledby="LocationChooseModal" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> @@ -44,18 +44,42 @@ </div> </div> </div> - </div> + </div> + <div class="modal fade" id="js_PackConfModal" tabindex="-1" role="dialog" aria-labelledby="PackConfModal" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> + <h4 class="modal-title" id="myModalLabel">Configure package</h4> + </div> + <div class="modal-body"> + <p>Package type</p> + <select id="js_packconf_select" class="form-control"> + <option class="js_packing_option" data-ul-id="false"></option> + <t t-foreach="widget.get_logisticunit()" t-as="ul"> + <option class="js_packing_option" t-att-data-ul-id="ul.id" t-att-value="ul.id"><t t-esc="ul.name"/></option> + </t> + </select> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary js_validate_pack">Validate package</button> + </div> + </div> + </div> + </div> + <div class="row"> <div> <div class="col-sm-4 col-xs-6"> <h2 class="oe_pick_app_header" /> </div> <div class="col-sm-8 col-xsâ»6 text-right"> - + <button type="button" class='btn btn-default js_pick_done'> Create backorder </button> <button type="button" class='btn btn-default js_pick_print'> Print </button> - + </div> </div> </div> @@ -67,7 +91,7 @@ <select id="js_select" class="form-control"> <option value="ToDo" id="js_select_todo">Operations ToDo</option> <option value="Processed" id="js_select_processed">Operations Processed</option> - </select> + </select> </strong> </h3> </div> @@ -83,18 +107,18 @@ </div> <div class="col-md-6 col-sm-4 col-xs-12 text-right"> <h3> - <button type="button" class='btn btn-default js_pick_pack'> Put in Pack </button> + <button type="button" class='btn btn-default js_pick_pack js_putinpack'> Put in Pack </button> <button type="button" class='btn btn-danger js_drop_down'> Process </button> </h3> </div> </div> </div> - <div> + <div> <table class='table table-condensed js_op_table_todo'> <thead> <tr> - <th class="text-left">Product</th> + <th class="text-left">Product</th> <th class='text-center' width="150">Scanned</th> <th class='text-center'>Todo</th> <th>From</th> @@ -104,12 +128,12 @@ <tbody> <t t-foreach="widget.get_rows()" t-as="row"> - <tr t-att-class="row.classes + 'js_pack_op_line'" t-att-data-id="row.cols.id" t-att-data-container-id="row.cols.container_id"> - <td t-att-class="'text-left' + row.cols.head_container ? ' js_unfold' : ''"> + <tr t-att-class="row.classes + 'js_pack_op_line'" t-att-data-id="row.cols.id" t-att-data-container-id="row.cols.container_id" t-att-data-package-id="row.cols.package_id" t-att-data-ulid="row.cols.ul_id"> + <td t-att-class="'brctbl-col1 text-left' + row.cols.head_container ? ' js_unfold' : ''"> <t t-if="!row.cols.head_container && row.cols.container"><span class="fa fa-level-up fa-rotate-90" style="margin-left:10px;margin-right:10px;"></span></t> - <t t-esc="row.cols.product" /> + <t t-esc="row.cols.product" /> </td> - <td class='text-center js_row_qty'> + <td class='brctbl-col2 text-center js_row_qty'> <t t-if="row.cols.processed == 'false' && !row.cols.container"> <div class="input-group"> <span class="input-group-addon js_minus input-sm" t-att-data-product-id='row.cols.product_id'><a href="#"><i class="fa fa-minus"></i></a></span> @@ -124,15 +148,15 @@ <t t-esc="row.cols.rem" /> </t> </td> - <td class="text-center"> + <td class="brctbl-col3 text-center"> <t t-esc="row.cols.qty"/> <t t-esc="row.cols.uom" /> </td> - <td class="js_loc"> + <td class="brctbl-col4 js_loc"> <t t-esc="row.cols.loc" /> <t t-if="row.cols.pack" ><span> : <t t-esc="row.cols.pack" /></span></t> <t t-if="row.cols.lot" ><span> : <t t-esc="row.cols.lot" /></span></t> </td> - <td class="js_loc"> <t t-esc="row.cols.dest" /> + <td class="brctbl-col5 js_loc"> <t t-esc="row.cols.dest" /> <div class="pull-right btn-group"> <button type="button" class="btn btn-default dropdown-toggle fa fa-cog" data-toggle="dropdown"> <span class="caret"></span> @@ -148,6 +172,7 @@ <t t-if="row.cols.head_container"> <li><a class="js_pack_change_dst" href="#">Change destination location</a></li> <li class="divider"></li> + <li><a class="js_pack_configure" href="#">Configure package</a></li> <li><a class="js_delete_pack" href="#">Remove from package</a></li> <li><a class="js_print_pack" href="#">Print package label</a></li> </t> @@ -192,11 +217,11 @@ <div class="navbar-header navbar-form navbar-right"> <button type="button" class="btn btn-danger js_pick_quit pull-right">Quit</button> </div> - + </div> </div> <div class="container"> - + <h1 class="js_title_label">Select your operation</h1> <div class='js_picking_not_found alert alert-warning hidden'> Scanned picking could not be found @@ -204,11 +229,11 @@ <div class='js_picking_search_results panel panel-info hidden'> </div> - + <div class="row js_picking_categories"> <t t-foreach="widget.picking_types" t-as="type"> <div class="col-lg-3 col-md-4"> - <div t-att-class="'oe_kanban oe_picking oe_kanban_color_' + type.color + ' ' + (widget.pickings_by_type[type.id].length === 0 ? 'oe_empty':'js_pick_last') " + <div t-att-class="'oe_kanban oe_picking oe_kanban_color_' + type.color + ' ' + (widget.pickings_by_type[type.id].length === 0 ? 'oe_empty':'js_pick_last') " t-att-data-id="type.id"> <t t-if="type.code == 'incoming'" ><span class="fa fa-sign-in fa-2x"></span></t> <t t-if="type.code == 'outgoing'" ><span class="fa fa-truck fa-2x fa-flip-horizontal"></span></t> @@ -220,7 +245,7 @@ </div> </div> </t> - </div> + </div> </div> </t> -- GitLab