screen.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. function pos_screens1(instance, module){ //module is instance.point_of_sale
  2. var QWeb = instance.web.qweb,
  3. _t = instance.web._t;
  4. var round_pr = instance.web.round_precision
  5. module.ClientListScreenWidget = module.ScreenWidget.extend({
  6. template: 'ClientListScreenWidget',
  7. init: function(parent, options){
  8. this._super(parent, options);
  9. },
  10. show_leftpane: false,
  11. auto_back: true,
  12. show: function(){
  13. var self = this;
  14. this._super();
  15. this.renderElement();
  16. this.details_visible = false;
  17. this.old_client = this.pos.get('selectedOrder').get('client');
  18. this.new_client = this.old_client;
  19. this.$('.back').click(function(){
  20. self.pos_widget.screen_selector.back();
  21. });
  22. this.$('.next').click(function(){
  23. self.save_changes();
  24. self.pos_widget.screen_selector.back();
  25. });
  26. this.$('.new-customer').click(function(){
  27. self.display_client_details('edit',{
  28. 'country_id': self.pos.company.country_id,
  29. });
  30. });
  31. var partners = this.pos.db.get_partners_sorted(1000);
  32. this.render_list(partners);
  33. this.reload_partners();
  34. if( this.old_client ){
  35. this.display_client_details('show',this.old_client,0);
  36. }
  37. this.$('.client-list-contents').delegate('.client-line','click',function(event){
  38. self.line_select(event,$(this),parseInt($(this).data('id')));
  39. });
  40. var search_timeout = null;
  41. if(this.pos.config.iface_vkeyboard && this.pos_widget.onscreen_keyboard){
  42. this.pos_widget.onscreen_keyboard.connect(this.$('.searchbox input'));
  43. }
  44. this.$('.searchbox input').on('keyup',function(event){
  45. clearTimeout(search_timeout);
  46. var query = this.value;
  47. search_timeout = setTimeout(function(){
  48. self.perform_search(query,event.which === 13);
  49. },70);
  50. });
  51. this.$('.searchbox .search-clear').click(function(){
  52. self.clear_search();
  53. });
  54. },
  55. barcode_client_action: function(code){
  56. if (this.editing_client) {
  57. this.$('.detail.barcode').val(code.code);
  58. } else if (this.pos.db.get_partner_by_ean13(code.code)) {
  59. this.display_client_details('show',this.pos.db.get_partner_by_ean13(code.code));
  60. }
  61. },
  62. perform_search: function(query, associate_result){
  63. if(query){
  64. var customers = this.pos.db.search_partner(query);
  65. this.display_client_details('hide');
  66. if ( associate_result && customers.length === 1){
  67. this.new_client = customers[0];
  68. this.save_changes();
  69. this.pos_widget.screen_selector.back();
  70. }
  71. this.render_list(customers);
  72. }else{
  73. var customers = this.pos.db.get_partners_sorted();
  74. this.render_list(customers);
  75. }
  76. },
  77. clear_search: function(){
  78. var customers = this.pos.db.get_partners_sorted(1000);
  79. this.render_list(customers);
  80. this.$('.searchbox input')[0].value = '';
  81. this.$('.searchbox input').focus();
  82. },
  83. render_list: function(partners){
  84. var contents = this.$el[0].querySelector('.client-list-contents');
  85. contents.innerHTML = "";
  86. for(var i = 0, len = Math.min(partners.length,1000); i < len; i++){
  87. var partner = partners[i];
  88. var clientline_html = QWeb.render('ClientLine',{widget: this, partner:partners[i]});
  89. var clientline = document.createElement('tbody');
  90. clientline.innerHTML = clientline_html;
  91. clientline = clientline.childNodes[1];
  92. if( partners === this.new_client ){
  93. clientline.classList.add('highlight');
  94. }else{
  95. clientline.classList.remove('highlight');
  96. }
  97. contents.appendChild(clientline);
  98. }
  99. },
  100. save_changes: function(){
  101. if( this.has_client_changed() ){
  102. this.pos.get('selectedOrder').set_client(this.new_client);
  103. }
  104. },
  105. has_client_changed: function(){
  106. if( this.old_client && this.new_client ){
  107. return this.old_client.id !== this.new_client.id;
  108. }else{
  109. return !!this.old_client !== !!this.new_client;
  110. }
  111. },
  112. toggle_save_button: function(){
  113. var $button = this.$('.button.next');
  114. if (this.editing_client) {
  115. $button.addClass('oe_hidden');
  116. return;
  117. } else if( this.new_client ){
  118. if( !this.old_client){
  119. $button.text(_t('Set Customer'));
  120. }else{
  121. $button.text(_t('Change Customer'));
  122. }
  123. }else{
  124. $button.text(_t('Deselect Customer'));
  125. }
  126. $button.toggleClass('oe_hidden',!this.has_client_changed());
  127. },
  128. line_select: function(event,$line,id){
  129. var partner = this.pos.db.get_partner_by_id(id);
  130. this.$('.client-list .lowlight').removeClass('lowlight');
  131. if ( $line.hasClass('highlight') ){
  132. $line.removeClass('highlight');
  133. $line.addClass('lowlight');
  134. this.display_client_details('hide',partner);
  135. this.new_client = null;
  136. this.toggle_save_button();
  137. }else{
  138. this.$('.client-list .highlight').removeClass('highlight');
  139. $line.addClass('highlight');
  140. var y = event.pageY - $line.parent().offset().top
  141. this.display_client_details('show',partner,y);
  142. this.new_client = partner;
  143. this.toggle_save_button();
  144. }
  145. },
  146. partner_icon_url: function(id){
  147. return '/web/binary/image?model=res.partner&id='+id+'&field=image_small';
  148. },
  149. // ui handle for the 'edit selected customer' action
  150. edit_client_details: function(partner) {
  151. this.display_client_details('edit',partner);
  152. },
  153. // ui handle for the 'cancel customer edit changes' action
  154. undo_client_details: function(partner) {
  155. if (!partner.id) {
  156. this.display_client_details('hide');
  157. } else {
  158. this.display_client_details('show',partner);
  159. }
  160. },
  161. // what happens when we save the changes on the client edit form -> we fetch the fields, sanitize them,
  162. // send them to the backend for update, and call saved_client_details() when the server tells us the
  163. // save was successfull.
  164. save_client_details: function(partner) {
  165. var self = this;
  166. var fields = {}
  167. this.$('.client-details-contents .detail').each(function(idx,el){
  168. fields[el.name] = el.value;
  169. });
  170. if (!fields.name) {
  171. this.pos_widget.screen_selector.show_popup('error',{
  172. message: _t('A Customer Name Is Required'),
  173. });
  174. return;
  175. }
  176. if (this.uploaded_picture) {
  177. fields.image = this.uploaded_picture;
  178. }
  179. fields.id = partner.id || false;
  180. fields.country_id = fields.country_id || false;
  181. fields.ean13 = fields.ean13 ? this.pos.barcode_reader.sanitize_ean(fields.ean13) : false;
  182. new instance.web.Model('res.partner').call('create_from_ui',[fields]).then(function(partner_id){
  183. self.saved_client_details(partner_id, fields);
  184. },function(err,event){
  185. event.preventDefault();
  186. self.pos_widget.screen_selector.show_popup('error',{
  187. 'message':_t('Error: Could not Save Changes'),
  188. 'comment':_t('Your Internet connection is probably down.'),
  189. });
  190. });
  191. },
  192. // what happens when we've just pushed modifications for a partner of id partner_id
  193. saved_client_details: function(partner_id, fields){
  194. var self = this;
  195. this.reload_partners().then(function(){
  196. var partner = self.pos.db.get_partner_by_id(partner_id);
  197. partner['gps'] = fields.gps;
  198. if (partner) {
  199. self.new_client = partner;
  200. self.toggle_save_button();
  201. self.display_client_details('show',partner);
  202. } else {
  203. // should never happen, because create_from_ui must return the id of the partner it
  204. // has created, and reload_partner() must have loaded the newly created partner.
  205. self.display_client_details('hide');
  206. }
  207. });
  208. },
  209. // resizes an image, keeping the aspect ratio intact,
  210. // the resize is useful to avoid sending 12Mpixels jpegs
  211. // over a wireless connection.
  212. resize_image_to_dataurl: function(img, maxwidth, maxheight, callback){
  213. img.onload = function(){
  214. var png = new Image();
  215. var canvas = document.createElement('canvas');
  216. var ctx = canvas.getContext('2d');
  217. var ratio = 1;
  218. if (img.width > maxwidth) {
  219. ratio = maxwidth / img.width;
  220. }
  221. if (img.height * ratio > maxheight) {
  222. ratio = maxheight / img.height;
  223. }
  224. var width = Math.floor(img.width * ratio);
  225. var height = Math.floor(img.height * ratio);
  226. canvas.width = width;
  227. canvas.height = height;
  228. ctx.drawImage(img,0,0,width,height);
  229. var dataurl = canvas.toDataURL();
  230. callback(dataurl);
  231. }
  232. },
  233. // Loads and resizes a File that contains an image.
  234. // callback gets a dataurl in case of success.
  235. load_image_file: function(file, callback){
  236. var self = this;
  237. if (!file.type.match(/image.*/)) {
  238. this.pos_widget.screen_selector.show_popup('error',{
  239. message:_t('Unsupported File Format'),
  240. comment:_t('Only web-compatible Image formats such as .png or .jpeg are supported'),
  241. });
  242. return;
  243. }
  244. var reader = new FileReader();
  245. reader.onload = function(event){
  246. var dataurl = event.target.result;
  247. var img = new Image();
  248. img.src = dataurl;
  249. self.resize_image_to_dataurl(img,800,600,callback);
  250. }
  251. reader.onerror = function(){
  252. self.pos_widget.screen_selector.show_popup('error',{
  253. message:_t('Could Not Read Image'),
  254. comment:_t('The provided file could not be read due to an unknown error'),
  255. });
  256. };
  257. reader.readAsDataURL(file);
  258. },
  259. // This fetches partner changes on the server, and in case of changes,
  260. // rerenders the affected views
  261. reload_partners: function(){
  262. var self = this;
  263. return this.pos.load_new_partners().then(function(){
  264. self.render_list(self.pos.db.get_partners_sorted(1000));
  265. // update the currently assigned client if it has been changed in db.
  266. var curr_client = self.pos.get_order().get_client();
  267. if (curr_client) {
  268. self.pos.get_order().set_client(self.pos.db.get_partner_by_id(curr_client.id));
  269. }
  270. });
  271. },
  272. // Shows,hides or edit the customer details box :
  273. // visibility: 'show', 'hide' or 'edit'
  274. // partner: the partner object to show or edit
  275. // clickpos: the height of the click on the list (in pixel), used
  276. // to maintain consistent scroll.
  277. display_client_details: function(visibility,partner,clickpos){
  278. var self = this;
  279. var contents = this.$('.client-details-contents');
  280. var parent = this.$('.client-list').parent();
  281. var scroll = parent.scrollTop();
  282. var height = contents.height();
  283. contents.off('click','.button.edit');
  284. contents.off('click','.button.save');
  285. contents.off('click','.button.undo');
  286. contents.on('click','.button.edit',function(){ self.edit_client_details(partner); });
  287. contents.on('click','.button.save',function(){ self.save_client_details(partner); });
  288. contents.on('click','.button.undo',function(){ self.undo_client_details(partner); });
  289. this.editing_client = false;
  290. this.uploaded_picture = null;
  291. if(visibility === 'show'){
  292. contents.empty();
  293. contents.append($(QWeb.render('ClientDetails',{widget:this,partner:partner})));
  294. var new_height = contents.height();
  295. if(!this.details_visible){
  296. if(clickpos < scroll + new_height + 20 ){
  297. parent.scrollTop( clickpos - 20 );
  298. }else{
  299. parent.scrollTop(parent.scrollTop() + new_height);
  300. }
  301. }else{
  302. parent.scrollTop(parent.scrollTop() - height + new_height);
  303. }
  304. this.details_visible = true;
  305. this.toggle_save_button();
  306. } else if (visibility === 'edit') {
  307. this.editing_client = true;
  308. contents.empty();
  309. contents.append($(QWeb.render('ClientDetailsEdit',{widget:this,partner:partner})));
  310. this.toggle_save_button();
  311. contents.find('.image-uploader').on('change',function(event){
  312. self.load_image_file(event.target.files[0],function(res){
  313. if (res) {
  314. contents.find('.client-picture img, .client-picture .fa').remove();
  315. contents.find('.client-picture').append("<img src='"+res+"'>");
  316. contents.find('.detail.picture').remove();
  317. self.uploaded_picture = res;
  318. }
  319. });
  320. });
  321. } else if (visibility === 'hide') {
  322. contents.empty();
  323. if( height > scroll ){
  324. contents.css({height:height+'px'});
  325. contents.animate({height:0},400,function(){
  326. contents.css({height:''});
  327. });
  328. }else{
  329. parent.scrollTop( parent.scrollTop() - height);
  330. }
  331. this.details_visible = false;
  332. this.toggle_save_button();
  333. }
  334. },
  335. close: function(){
  336. this._super();
  337. },
  338. });
  339. }