1 function openerp_picking_widgets(instance){
3 var module = instance.stock;
4 var _t = instance.web._t;
5 var QWeb = instance.web.qweb;
7 // This widget makes sure that the scaling is disabled on mobile devices.
8 // Widgets that want to display fullscreen on mobile phone need to extend this
11 module.MobileWidget = instance.web.Widget.extend({
13 if(!$('#oe-mobilewidget-viewport').length){
14 $('head').append('<meta id="oe-mobilewidget-viewport" name="viewport" content="initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">');
19 $('#oe-mobilewidget-viewport').remove();
24 module.PickingEditorWidget = instance.web.Widget.extend({
25 template: 'PickingEditorWidget',
26 init: function(parent,options){
27 this._super(parent,options);
30 this.search_filter = "";
31 jQuery.expr[":"].Contains = jQuery.expr.createPseudo(function(arg) {
32 return function( elem ) {
33 return jQuery(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
37 get_header: function(){
38 return this.getParent().get_header();
40 get_location: function(){
41 var model = this.getParent();
44 _.each(model.locations, function(loc){
45 locations.push({name: loc.complete_name, id: loc.id,});
49 get_logisticunit: function(){
50 var model = this.getParent();
53 _.each(model.uls, function(ulog){
54 ul.push({name: ulog.name, id: ulog.id,});
59 var model = this.getParent();
62 var pack_created = [];
63 _.each( model.packoplines, function(packopline){
66 if (packopline.product_id[1] !== undefined){ pack = packopline.package_id[1];}
67 if (packopline.product_qty == packopline.qty_done){ color = "success "; }
68 if (packopline.product_qty < packopline.qty_done){ color = "danger "; }
69 //also check that we don't have a line already existing for that package
70 if (packopline.result_package_id[1] !== undefined && $.inArray(packopline.result_package_id[0], pack_created) === -1){
71 var myPackage = $.grep(model.packages, function(e){ return e.id == packopline.result_package_id[0]; })[0];
73 cols: { product: packopline.result_package_id[1],
79 container: packopline.result_package_id[1],
80 container_id: undefined,
81 loc: packopline.location_id[1],
82 dest: packopline.location_dest_id[1],
83 id: packopline.result_package_id[0],
84 product_id: undefined,
87 processed: packopline.processed,
88 package_id: myPackage.id,
89 ul_id: myPackage.ul_id[0],
91 classes: ('success container_head ') + (packopline.processed === "true" ? 'processed hidden ':''),
93 pack_created.push(packopline.result_package_id[0]);
96 cols: { product: packopline.product_id[1] || packopline.package_id[1],
97 qty: packopline.product_qty,
98 rem: packopline.qty_done,
99 uom: packopline.product_uom_id[1],
100 lot: packopline.lot_id[1],
102 container: packopline.result_package_id[1],
103 container_id: packopline.result_package_id[0],
104 loc: packopline.location_id[1],
105 dest: packopline.location_dest_id[1],
107 product_id: packopline.product_id[0],
108 can_scan: packopline.result_package_id[1] === undefined ? true : false,
109 head_container: false,
110 processed: packopline.processed,
111 package_id: undefined,
114 classes: color + (packopline.result_package_id[1] !== undefined ? 'in_container_hidden ' : '') + (packopline.processed === "true" ? 'processed hidden ':''),
117 //sort element by things to do, then things done, then grouped by packages
118 group_by_container = _.groupBy(self.rows, function(row){
119 return row.cols.container;
122 if (group_by_container.undefined !== undefined){
123 group_by_container.undefined.sort(function(a,b){return (b.classes === '') - (a.classes === '');});
124 $.each(group_by_container.undefined, function(key, value){
125 sorted_row.push(value);
129 $.each(group_by_container, function(key, value){
130 if (key !== 'undefined'){
131 $.each(value, function(k,v){
139 renderElement: function(){
142 this.check_content_screen();
143 this.$('.js_pick_done').click(function(){ self.getParent().done(); });
144 this.$('.js_pick_print').click(function(){ self.getParent().print_picking(); });
145 this.$('.oe_pick_app_header').text(self.get_header());
146 this.$('.oe_searchbox').keyup(function(event){
147 self.on_searchbox($(this).val());
149 this.$('.js_putinpack').click(function(){ self.getParent().pack(); });
150 this.$('.js_drop_down').click(function(){ self.getParent().drop_down();});
151 this.$('.js_clear_search').click(function(){
152 self.on_searchbox('');
153 self.$('.oe_searchbox').val('');
155 this.$('.oe_searchbox').focus(function(){
156 self.getParent().barcode_scanner.disconnect();
158 this.$('.oe_searchbox').blur(function(){
159 self.getParent().barcode_scanner.connect(function(ean){
160 self.get_Parent().scan(ean);
163 this.$('#js_select').change(function(){
164 var selection = self.$('#js_select option:selected').attr('value');
165 if (selection === "ToDo"){
166 self.getParent().$('.js_pick_pack').removeClass('hidden')
167 self.getParent().$('.js_drop_down').removeClass('hidden')
168 self.$('.js_pack_op_line.processed').addClass('hidden')
169 self.$('.js_pack_op_line:not(.processed)').removeClass('hidden')
172 self.getParent().$('.js_pick_pack').addClass('hidden')
173 self.getParent().$('.js_drop_down').addClass('hidden')
174 self.$('.js_pack_op_line.processed').removeClass('hidden')
175 self.$('.js_pack_op_line:not(.processed)').addClass('hidden')
177 self.on_searchbox(self.search_filter);
179 this.$('.js_plus').click(function(){
180 var id = $(this).data('product-id');
181 var op_id = $(this).parents("[data-id]:first").data('id');
182 self.getParent().scan_product_id(id,true,op_id);
184 this.$('.js_minus').click(function(){
185 var id = $(this).data('product-id');
186 var op_id = $(this).parents("[data-id]:first").data('id');
187 self.getParent().scan_product_id(id,false,op_id);
189 this.$('.js_unfold').click(function(){
190 var op_id = $(this).parent().data('id');
191 var line = $(this).parent();
192 //select all js_pack_op_line with class in_container_hidden and correct container-id
193 select = self.$('.js_pack_op_line.in_container_hidden[data-container-id='+op_id+']')
194 if (select.length > 0){
196 line.addClass('warning');
197 select.removeClass('in_container_hidden');
198 select.addClass('in_container');
202 line.removeClass('warning');
203 select = self.$('.js_pack_op_line.in_container[data-container-id='+op_id+']')
204 select.removeClass('in_container');
205 select.addClass('in_container_hidden');
208 this.$('.js_create_lot').click(function(){
209 var op_id = $(this).parents("[data-id]:first").data('id');
210 var lot_name = false;
211 self.$('.js_lot_scan').val('');
212 var $lot_modal = self.$el.siblings('#js_LotChooseModal');
213 //disconnect scanner to prevent scanning a product in the back while dialog is open
214 self.getParent().barcode_scanner.disconnect();
217 $lot_modal.on('shown.bs.modal', function(){
218 self.$('.js_lot_scan').focus();
220 //reactivate scanner when dialog close
221 $lot_modal.on('hidden.bs.modal', function(){
222 self.getParent().barcode_scanner.connect(function(ean){
223 self.getParent().scan(ean);
226 self.$('.js_lot_scan').focus();
228 self.$('.js_validate_lot').click(function(){
229 //get content of input
230 var name = self.$('.js_lot_scan').val();
231 if (name.length !== 0){
234 $lot_modal.modal('hide');
235 //we need this here since it is not sure the hide event
236 //will be catch because we refresh the view after the create_lot call
237 self.getParent().barcode_scanner.connect(function(ean){
238 self.getParent().scan(ean);
240 self.getParent().create_lot(op_id, lot_name);
243 this.$('.js_delete_pack').click(function(){
244 var pack_id = $(this).parents("[data-id]:first").data('id');
245 self.getParent().delete_package_op(pack_id);
247 this.$('.js_print_pack').click(function(){
248 var pack_id = $(this).parents("[data-id]:first").data('id');
249 // $(this).parents("[data-id]:first").data('id')
250 self.getParent().print_package(pack_id);
252 this.$('.js_submit_value').submit(function(event){
253 var op_id = $(this).parents("[data-id]:first").data('id');
254 var value = parseFloat($("input", this).val());
256 self.getParent().set_operation_quantity(value, op_id);
258 $("input", this).val("");
261 this.$('.js_qty').focus(function(){
262 self.getParent().barcode_scanner.disconnect();
264 this.$('.js_qty').blur(function(){
265 var op_id = $(this).parents("[data-id]:first").data('id');
266 var value = parseFloat($(this).val());
268 self.getParent().set_operation_quantity(value, op_id);
271 self.getParent().barcode_scanner.connect(function(ean){
272 self.getParent().scan(ean);
275 this.$('.js_change_src').click(function(){
276 var op_id = $(this).parents("[data-id]:first").data('id');//data('op_id');
277 self.$('#js_loc_select').addClass('source');
278 self.$('#js_loc_select').data('op-id',op_id);
279 self.$el.siblings('#js_LocationChooseModal').modal();
281 this.$('.js_change_dst').click(function(){
282 var op_id = $(this).parents("[data-id]:first").data('id');
283 self.$('#js_loc_select').data('op-id',op_id);
284 self.$el.siblings('#js_LocationChooseModal').modal();
286 this.$('.js_pack_change_dst').click(function(){
287 var op_id = $(this).parents("[data-id]:first").data('id');
288 self.$('#js_loc_select').addClass('pack');
289 self.$('#js_loc_select').data('op-id',op_id);
290 self.$el.siblings('#js_LocationChooseModal').modal();
292 this.$('.js_validate_location').click(function(){
293 //get current selection
294 var select_dom_element = self.$('#js_loc_select');
295 var loc_id = self.$('#js_loc_select option:selected').data('loc-id');
297 var op_id = select_dom_element.data('op-id');
298 if (select_dom_element.hasClass('pack')){
299 select_dom_element.removeClass('source');
301 self.$('.js_pack_op_line[data-container-id='+op_id+']').each(function(){
302 op_ids.push($(this).data('id'));
306 else if (select_dom_element.hasClass('source')){
308 select_dom_element.removeClass('source');
310 if (loc_id === false){
312 self.$el.siblings('#js_LocationChooseModal').modal('hide');
315 self.$el.siblings('#js_LocationChooseModal').modal('hide');
316 self.getParent().change_location(op_id, parseInt(loc_id), src_dst);
320 this.$('.js_pack_configure').click(function(){
321 var pack_id = $(this).parents(".js_pack_op_line:first").data('package-id');
322 var ul_id = $(this).parents(".js_pack_op_line:first").data('ulid');
323 self.$('#js_packconf_select').val(ul_id);
324 self.$('#js_packconf_select').data('pack-id',pack_id);
325 self.$el.siblings('#js_PackConfModal').modal();
327 this.$('.js_validate_pack').click(function(){
328 //get current selection
329 var select_dom_element = self.$('#js_packconf_select');
330 var ul_id = self.$('#js_packconf_select option:selected').data('ul-id');
331 var pack_id = select_dom_element.data('pack-id');
332 self.$el.siblings('#js_PackConfModal').modal('hide');
334 self.getParent().set_package_pack(pack_id, ul_id);
335 $('.container_head[data-package-id="'+pack_id+'"]').data('ulid', ul_id);
339 //remove navigtion bar from default openerp GUI
340 $('td.navbar').html('<div></div>');
342 on_searchbox: function(query){
343 //hide line that has no location matching the query and highlight location that match the query
344 this.search_filter = query;
345 var processed = ".processed";
346 if (this.$('#js_select option:selected').attr('value') == "ToDo"){
347 processed = ":not(.processed)";
350 this.$('.js_loc:not(.js_loc:Contains('+query+'))').removeClass('info');
351 this.$('.js_loc:Contains('+query+')').addClass('info');
352 this.$('.js_pack_op_line'+processed+':not(.js_pack_op_line:has(.js_loc:Contains('+query+')))').addClass('hidden');
353 this.$('.js_pack_op_line'+processed+':has(.js_loc:Contains('+query+'))').removeClass('hidden');
355 //if no query specified, then show everything
357 this.$('.js_loc').removeClass('info');
358 this.$('.js_pack_op_line'+processed+'.hidden').removeClass('hidden');
360 this.check_content_screen();
362 check_content_screen: function(){
363 //get all visible element and if none has positive qty, disable put in pack and process button
365 var processed = this.$('.js_pack_op_line.processed');
366 var qties = this.$('.js_pack_op_line:not(.processed):not(.hidden) .js_qty').map(function(){return $(this).val()});
367 var container = this.$('.js_pack_op_line.container_head:not(.processed):not(.hidden)')
369 $.each(qties,function(index, value){
370 if (parseInt(value)>0){
376 if (container.length===0){
377 self.$('.js_drop_down').addClass('disabled');
380 self.$('.js_drop_down').removeClass('disabled');
382 self.$('.js_pick_pack').addClass('disabled');
383 if (processed.length === 0){
384 self.$('.js_pick_done').addClass('disabled');
387 self.$('.js_pick_done').removeClass('disabled');
391 self.$('.js_drop_down').removeClass('disabled');
392 self.$('.js_pick_pack').removeClass('disabled');
393 self.$('.js_pick_done').removeClass('disabled');
396 get_current_op_selection: function(ignore_container){
397 //get ids of visible on the screen
399 this.$('.js_pack_op_line:not(.processed):not(.js_pack_op_line.hidden):not(.container_head)').each(function(){
400 cur_id = $(this).data('id');
401 pack_op_ids.push(parseInt(cur_id));
403 //get list of element in this.rows where rem > 0 and container is empty is specified
405 _.each(this.rows, function(row){
406 if (row.cols.rem > 0 && (ignore_container || row.cols.container === undefined)){
407 list.push(row.cols.id);
410 //return only those visible with rem qty > 0 and container empty
411 return _.intersection(pack_op_ids, list);
413 remove_blink: function(){
414 this.$('.js_pack_op_line.blink_me').removeClass('blink_me');
416 blink: function(op_id){
417 this.$('.js_pack_op_line[data-id="'+op_id+'"]').addClass('blink_me');
419 check_done: function(){
420 var model = this.getParent();
423 _.each( model.packoplines, function(packopline){
424 if (packopline.processed === "false"){
431 get_visible_ids: function(){
433 var visible_op_ids = []
434 var op_ids = this.$('.js_pack_op_line:not(.processed):not(.hidden):not(.container_head):not(.in_container):not(.in_container_hidden)').map(function(){
435 return $(this).data('id');
437 $.each(op_ids, function(key, op_id){
438 visible_op_ids.push(parseInt(op_id));
440 return visible_op_ids;
444 module.PickingMenuWidget = module.MobileWidget.extend({
445 template: 'PickingMenuWidget',
446 init: function(parent, params){
447 this._super(parent,params);
449 $(window).bind('hashchange', function(){
450 var states = $.bbq.getState();
451 if (states.action === "stock.ui"){
453 type: 'ir.actions.client',
457 clear_breadcrumbs: true,
461 this.picking_types = [];
462 this.loaded = this.load();
463 this.scanning_type = 0;
464 this.barcode_scanner = new module.BarcodeScanner();
465 this.pickings_by_type = {};
466 this.pickings_by_id = {};
467 this.picking_search_string = "";
471 return new instance.web.Model('stock.picking.type').get_func('search_read')([],[])
472 .then(function(types){
473 self.picking_types = types;
474 for(var i = 0; i < types.length; i++){
475 self.pickings_by_type[types[i].id] = [];
477 self.pickings_by_type[0] = [];
479 return new instance.web.Model('stock.picking').call('search_read',[ [['state','in', ['assigned', 'partially_available']]], [] ], {context: new instance.web.CompoundContext()});
481 }).then(function(pickings){
482 self.pickings = pickings;
483 for(var i = 0; i < pickings.length; i++){
484 var picking = pickings[i];
485 self.pickings_by_type[picking.picking_type_id[0]].push(picking);
486 self.pickings_by_id[picking.id] = picking;
487 self.picking_search_string += '' + picking.id + ':' + picking.name.toUpperCase() + '\n'
492 renderElement: function(){
495 this.$('.js_pick_quit').click(function(){ self.quit(); });
496 this.$('.js_pick_scan').click(function(){ self.scan_picking($(this).data('id')); });
497 this.$('.js_pick_last').click(function(){ self.goto_last_picking_of_type($(this).data('id')); });
498 this.$('.oe_searchbox').keyup(function(event){
499 self.on_searchbox($(this).val());
501 //remove navigtion bar from default openerp GUI
502 $('td.navbar').html('<div></div>');
507 instance.webclient.set_content_full_screen(true);
508 this.barcode_scanner.connect(function(barcode){
509 self.on_scan(barcode);
511 this.loaded.then(function(){
512 self.renderElement();
515 goto_picking: function(picking_id){
516 $.bbq.pushState('#action=stock.ui&picking_id='+picking_id);
517 $(window).trigger('hashchange');
519 goto_last_picking_of_type: function(type_id){
520 $.bbq.pushState('#action=stock.ui&picking_type_id='+type_id);
521 $(window).trigger('hashchange');
523 search_picking: function(barcode){
525 var re = RegExp("([0-9]+):.*?"+barcode.toUpperCase(),"gi");
528 //avoid crash if a not supported char is given (like '\' or ')')
533 for(var i = 0; i < 100; i++){
534 r = re.exec(this.picking_search_string);
536 var picking = this.pickings_by_id[Number(r[1])];
538 results.push(picking);
546 on_scan: function(barcode){
548 for(var i = 0, len = this.pickings.length; i < len; i++){
549 var picking = this.pickings[i];
550 if(picking.name.toUpperCase() === $.trim(barcode.toUpperCase())){
551 this.goto_picking(picking.id);
555 this.$('.js_picking_not_found').removeClass('hidden');
557 clearTimeout(this.picking_not_found_timeout);
558 this.picking_not_found_timeout = setTimeout(function(){
559 self.$('.js_picking_not_found').addClass('hidden');
563 on_searchbox: function(query){
566 clearTimeout(this.searchbox_timeout);
567 this.searchbox_timout = setTimeout(function(){
569 self.$('.js_picking_not_found').addClass('hidden');
570 self.$('.js_picking_categories').addClass('hidden');
571 self.$('.js_picking_search_results').html(
572 QWeb.render('PickingSearchResults',{results:self.search_picking(query)})
574 self.$('.js_picking_search_results .oe_picking').click(function(){
575 self.goto_picking($(this).data('id'));
577 self.$('.js_picking_search_results').removeClass('hidden');
579 self.$('.js_title_label').removeClass('hidden');
580 self.$('.js_picking_categories').removeClass('hidden');
581 self.$('.js_picking_search_results').addClass('hidden');
586 return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_picking_type_form']], ['res_id']).pipe(function(res) {
587 window.location = '/web#action=' + res[0]['res_id'];
592 this.barcode_scanner.disconnect();
593 instance.webclient.set_content_full_screen(false);
596 openerp.web.client_actions.add('stock.menu', 'instance.stock.PickingMenuWidget');
598 module.PickingMainWidget = module.MobileWidget.extend({
599 template: 'PickingMainWidget',
600 init: function(parent,params){
601 this._super(parent,params);
603 $(window).bind('hashchange', function(){
604 var states = $.bbq.getState();
605 if (states.action === "stock.menu"){
607 type: 'ir.actions.client',
611 clear_breadcrumbs: true,
615 init_hash = $.bbq.getState();
616 this.picking_type_id = init_hash.picking_type_id ? init_hash.picking_type_id:0;
617 this.picking_id = init_hash.picking_id ? init_hash.picking_id:undefined;
620 this.packoplines = null;
621 this.selected_operation = { id: null, picking_id: null};
622 this.packages = null;
623 this.barcode_scanner = new module.BarcodeScanner();
627 this.loaded = this.load(this.picking_id);
629 this.loaded = this.load();
634 // load the picking data from the server. If picking_id is undefined, it will take the first picking
635 // belonging to the category
636 load: function(picking_id){
640 function load_picking_list(type_id){
641 var pickings = new $.Deferred();
642 new instance.web.Model('stock.picking')
643 .call('get_next_picking_for_ui',[{'default_picking_type_id':parseInt(type_id)}])
644 .then(function(picking_ids){
645 if(!picking_ids || picking_ids.length === 0){
646 (new instance.web.Dialog(self,{
647 title: _t('No Picking Available'),
654 }, _t('<p>We could not find a picking to display.</p>'))).open();
658 self.pickings = picking_ids;
659 pickings.resolve(picking_ids);
666 // if we have a specified picking id, we load that one, and we load the picking of the same type as the active list
668 var loaded_picking = new instance.web.Model('stock.picking')
669 .call('read',[[parseInt(picking_id)], [], new instance.web.CompoundContext()])
670 .then(function(picking){
671 self.picking = picking[0];
672 self.picking_type_id = picking[0].picking_type_id[0];
673 return load_picking_list(self.picking.picking_type_id[0]);
676 // if we don't have a specified picking id, we load the pickings belong to the specified type, and then we take
677 // the first one of that list as the active picking
678 var loaded_picking = new $.Deferred();
679 load_picking_list(self.picking_type_id)
681 return new instance.web.Model('stock.picking').call('read',[self.pickings[0],[], new instance.web.CompoundContext()]);
683 .then(function(picking){
684 self.picking = picking;
685 self.picking_type_id = picking.picking_type_id[0];
686 loaded_picking.resolve();
690 return loaded_picking.then(function(){
691 return new instance.web.Model('stock.location').call('search',[[['usage','=','internal']]]).then(function(locations_ids){
692 return new instance.web.Model('stock.location').call('read',[locations_ids, []]).then(function(locations){
693 self.locations = locations;
697 return new instance.web.Model('stock.picking').call('check_group_pack').then(function(result){
698 return self.show_pack = result;
701 return new instance.web.Model('stock.picking').call('check_group_lot').then(function(result){
702 return self.show_lot = result;
705 if (self.picking.pack_operation_exist === false){
706 self.picking.recompute_pack_op = false;
707 return new instance.web.Model('stock.picking').call('do_prepare_partial',[[self.picking.id]]);
710 return new instance.web.Model('stock.pack.operation').call('search',[[['picking_id','=',self.picking.id]]])
711 }).then(function(pack_op_ids){
712 return new instance.web.Model('stock.pack.operation').call('read',[pack_op_ids, [], new instance.web.CompoundContext()])
713 }).then(function(operations){
714 self.packoplines = operations;
715 var package_ids = [];
717 for(var i = 0; i < operations.length; i++){
718 if(!_.contains(package_ids,operations[i].result_package_id[0])){
719 if (operations[i].result_package_id[0]){
720 package_ids.push(operations[i].result_package_id[0]);
724 return new instance.web.Model('stock.quant.package').call('read',[package_ids, [], new instance.web.CompoundContext()])
725 }).then(function(packages){
726 self.packages = packages;
728 return new instance.web.Model('product.ul').call('search',[[]])
729 }).then(function(uls_ids){
730 return new instance.web.Model('product.ul').call('read',[uls_ids, []])
731 }).then(function(uls){
738 instance.webclient.set_content_full_screen(true);
739 this.barcode_scanner.connect(function(ean){
743 this.$('.js_pick_quit').click(function(){ self.quit(); });
744 this.$('.js_pick_prev').click(function(){ self.picking_prev(); });
745 this.$('.js_pick_next').click(function(){ self.picking_next(); });
746 this.$('.js_pick_menu').click(function(){ self.menu(); });
747 this.$('.js_reload_op').click(function(){ self.reload_pack_operation();});
749 $.when(this.loaded).done(function(){
750 self.picking_editor = new module.PickingEditorWidget(self);
751 self.picking_editor.replace(self.$('.oe_placeholder_picking_editor'));
753 if( self.picking.id === self.pickings[0]){
754 self.$('.js_pick_prev').addClass('disabled');
756 self.$('.js_pick_prev').removeClass('disabled');
759 if( self.picking.id === self.pickings[self.pickings.length-1] ){
760 self.$('.js_pick_next').addClass('disabled');
762 self.$('.js_pick_next').removeClass('disabled');
764 if (self.picking.recompute_pack_op){
765 self.$('.oe_reload_op').removeClass('hidden');
768 self.$('.oe_reload_op').addClass('hidden');
770 if (!self.show_pack){
771 self.$('.js_pick_pack').addClass('hidden');
774 self.$('.js_create_lot').addClass('hidden');
777 }).fail(function(error) {console.log(error);});
780 on_searchbox: function(query){
782 self.picking_editor.on_searchbox(query.toUpperCase());
784 // reloads the data from the provided picking and refresh the ui.
785 // (if no picking_id is provided, gets the first picking in the db)
786 refresh_ui: function(picking_id){
788 var remove_search_filter = "";
789 if (self.picking.id === picking_id){
790 remove_search_filter = self.$('.oe_searchbox').val();
792 return this.load(picking_id)
794 self.picking_editor.remove_blink();
795 self.picking_editor.renderElement();
796 if (!self.show_pack){
797 self.$('.js_pick_pack').addClass('hidden');
800 self.$('.js_create_lot').addClass('hidden');
802 if (self.picking.recompute_pack_op){
803 self.$('.oe_reload_op').removeClass('hidden');
806 self.$('.oe_reload_op').addClass('hidden');
809 if( self.picking.id === self.pickings[0]){
810 self.$('.js_pick_prev').addClass('disabled');
812 self.$('.js_pick_prev').removeClass('disabled');
815 if( self.picking.id === self.pickings[self.pickings.length-1] ){
816 self.$('.js_pick_next').addClass('disabled');
818 self.$('.js_pick_next').removeClass('disabled');
820 if (remove_search_filter === ""){
821 self.$('.oe_searchbox').val('');
822 self.on_searchbox('');
825 self.$('.oe_searchbox').val(remove_search_filter);
826 self.on_searchbox(remove_search_filter);
830 get_header: function(){
832 return this.picking.name;
838 $.bbq.pushState('#action=stock.menu');
839 $(window).trigger('hashchange');
841 scan: function(ean){ //scans a barcode, sends it to the server, then reload the ui
843 var product_visible_ids = this.picking_editor.get_visible_ids();
844 return new instance.web.Model('stock.picking')
845 .call('process_barcode_from_ui', [self.picking.id, ean, product_visible_ids])
846 .then(function(result){
847 if (result.filter_loc !== false){
848 //check if we have receive a location as answer
849 if (result.filter_loc !== undefined){
850 var modal_loc_hidden = self.$('#js_LocationChooseModal').attr('aria-hidden');
851 if (modal_loc_hidden === "false"){
852 var line = self.$('#js_LocationChooseModal .js_loc_option[data-loc-id='+result.filter_loc_id+']').attr('selected','selected');
855 self.$('.oe_searchbox').val(result.filter_loc);
856 self.on_searchbox(result.filter_loc);
860 if (result.operation_id !== false){
861 self.refresh_ui(self.picking.id).then(function(){
862 return self.picking_editor.blink(result.operation_id);
867 scan_product_id: function(product_id,increment,op_id){ //performs the same operation as a scan, but with product id instead
869 return new instance.web.Model('stock.picking')
870 .call('process_product_id_from_ui', [self.picking.id, product_id, op_id, increment])
871 .then(function(result){
872 return self.refresh_ui(self.picking.id);
877 var pack_op_ids = self.picking_editor.get_current_op_selection(false);
878 if (pack_op_ids.length !== 0){
879 return new instance.web.Model('stock.picking')
880 .call('action_pack',[[[self.picking.id]], pack_op_ids])
882 instance.session.user_context.current_package_id = false;
883 return self.refresh_ui(self.picking.id);
887 drop_down: function(){
889 var pack_op_ids = self.picking_editor.get_current_op_selection(true);
890 if (pack_op_ids.length !== 0){
891 return new instance.web.Model('stock.pack.operation')
892 .call('action_drop_down', [pack_op_ids])
894 return self.refresh_ui(self.picking.id).then(function(){
895 if (self.picking_editor.check_done()){
904 return new instance.web.Model('stock.picking')
905 .call('action_done_from_ui',[self.picking.id, {'default_picking_type_id': self.picking_type_id}])
906 .then(function(new_picking_ids){
907 if (new_picking_ids){
908 return self.refresh_ui(new_picking_ids[0]);
915 create_lot: function(op_id, lot_name){
917 return new instance.web.Model('stock.pack.operation')
918 .call('create_and_assign_lot',[parseInt(op_id), lot_name])
920 return self.refresh_ui(self.picking.id);
923 change_location: function(op_id, loc_id, is_src_dst){
925 var vals = {'location_dest_id': loc_id};
927 vals = {'location_id': loc_id};
929 return new instance.web.Model('stock.pack.operation')
930 .call('write',[op_id, vals])
932 return self.refresh_ui(self.picking.id);
935 print_package: function(package_id){
937 return new instance.web.Model('stock.quant.package')
938 .call('action_print',[[package_id]])
939 .then(function(action){
940 return self.do_action(action);
943 print_picking: function(){
945 return new instance.web.Model('stock.picking.type').call('read', [[self.picking_type_id], ['code'], new instance.web.CompoundContext()])
946 .then(function(pick_type){
947 return new instance.web.Model('stock.picking').call('do_print_picking',[[self.picking.id]])
948 .then(function(action){
949 return self.do_action(action);
953 picking_next: function(){
954 for(var i = 0; i < this.pickings.length; i++){
955 if(this.pickings[i] === this.picking.id){
956 if(i < this.pickings.length -1){
957 $.bbq.pushState('picking_id='+this.pickings[i+1]);
958 this.refresh_ui(this.pickings[i+1]);
964 picking_prev: function(){
965 for(var i = 0; i < this.pickings.length; i++){
966 if(this.pickings[i] === this.picking.id){
968 $.bbq.pushState('picking_id='+this.pickings[i-1]);
969 this.refresh_ui(this.pickings[i-1]);
975 delete_package_op: function(pack_id){
977 return new instance.web.Model('stock.pack.operation').call('search', [[['result_package_id', '=', pack_id]]])
978 .then(function(op_ids) {
979 return new instance.web.Model('stock.pack.operation').call('write', [op_ids, {'result_package_id':false}])
981 return self.refresh_ui(self.picking.id);
985 set_operation_quantity: function(quantity, op_id){
988 return new instance.web.Model('stock.pack.operation')
989 .call('write',[[op_id],{'qty_done': quantity }])
991 self.refresh_ui(self.picking.id);
996 set_package_pack: function(package_id, pack){
998 return new instance.web.Model('stock.quant.package')
999 .call('write',[[package_id],{'ul_id': pack }]);
1002 reload_pack_operation: function(){
1004 return new instance.web.Model('stock.picking')
1005 .call('do_prepare_partial',[[self.picking.id]])
1007 self.refresh_ui(self.picking.id);
1012 return new instance.web.Model("ir.model.data").get_func("search_read")([['name', '=', 'action_picking_type_form']], ['res_id']).pipe(function(res) {
1013 window.location = '/web#action=' + res[0]['res_id'];
1016 destroy: function(){
1018 // this.disconnect_numpad();
1019 this.barcode_scanner.disconnect();
1020 instance.webclient.set_content_full_screen(false);
1023 openerp.web.client_actions.add('stock.ui', 'instance.stock.PickingMainWidget');
1025 module.BarcodeScanner = instance.web.Class.extend({
1026 connect: function(callback){
1031 this.handler = function(e){
1032 if(e.which === 13){ //ignore returns
1036 if(timeStamp + 50 < new Date().getTime()){
1040 timeStamp = new Date().getTime();
1041 clearTimeout(timeout);
1043 code += String.fromCharCode(e.which);
1045 timeout = setTimeout(function(){
1046 if(code.length >= 3){
1053 $('body').on('keypress', this.handler);
1056 disconnect: function(){
1057 $('body').off('keypress', this.handler);
1063 openerp.stock = function(openerp) {
1064 openerp.stock = openerp.stock || {};
1065 openerp_picking_widgets(openerp);