You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
9.2 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. odoo.define('pos_keyboard.pos', function (require) {
  2. "use strict";
  3. var core = require('web.core');
  4. var gui = require('point_of_sale.gui');
  5. var models = require('point_of_sale.models');
  6. var screens = require('point_of_sale.screens');
  7. var PopupWidget = require('point_of_sale.popups');
  8. var _super_posmodel = models.PosModel.prototype;
  9. models.PosModel = models.PosModel.extend({
  10. initialize: function (session, attributes) {
  11. var self = this;
  12. this.keypad = new Keypad({'pos': this});
  13. _super_posmodel.initialize.call(this, session, attributes);
  14. this.ready.then(function(){
  15. self.keypad.set_action_callback(function(data){
  16. var current_screen = self.gui.current_screen;
  17. var current_popup = self.gui.current_popup;
  18. if (current_popup) {
  19. current_popup.keypad_action(data);
  20. } else if (current_screen.numpad && current_screen.numpad.keypad_action) {
  21. current_screen.numpad.keypad_action(data);
  22. }
  23. });
  24. });
  25. }
  26. });
  27. gui.Gui.prototype.popup_classes.filter(function(c){
  28. return c.name === 'password';
  29. })[0].widget.include({
  30. init: function(parent, args) {
  31. this._super(parent, args);
  32. this.popup_type = 'password';
  33. },
  34. });
  35. PopupWidget.include({
  36. keypad_action: function(data){
  37. var type = this.pos.keypad.type;
  38. if (data.type === type.numchar){
  39. this.click_keyboard(data.val);
  40. } else if (data.type === type.backspace){
  41. this.click_keyboard('BACKSPACE');
  42. } else if (data.type === type.enter){
  43. this.click_confirm();
  44. } else if (data.type === type.escape){
  45. this.click_cancel();
  46. }
  47. },
  48. click_keyboard: function(value){
  49. var newbuf = this.gui.numpad_input(
  50. this.inputbuffer,
  51. value,
  52. {'firstinput': this.firstinput});
  53. this.firstinput = (newbuf.length === 0);
  54. var $value = this.$('.value');
  55. if (newbuf !== this.inputbuffer) {
  56. this.inputbuffer = newbuf;
  57. $value.text(this.inputbuffer);
  58. }
  59. if (this.popup_type === 'password') {
  60. $value.text($value.text().replace(/./g, '•'));
  61. }
  62. },
  63. show: function(options){
  64. this._super(options);
  65. this.$('input,textarea').focus();
  66. },
  67. });
  68. screens.NumpadWidget.include({
  69. keypad_action: function(data){
  70. var type = this.pos.keypad.type;
  71. if (data.type === type.numchar){
  72. this.state.appendNewChar(data.val);
  73. }
  74. else if (data.type === type.bmode) {
  75. this.state.changeMode(data.val);
  76. }
  77. else if (data.type === type.sign){
  78. this.clickSwitchSign();
  79. }
  80. else if (data.type === type.backspace){
  81. this.clickDeleteLastChar();
  82. }
  83. }
  84. });
  85. screens.PaymentScreenWidget.include({
  86. show: function(){
  87. this._super();
  88. this.pos.keypad.disconnect();
  89. },
  90. hide: function(){
  91. this._super();
  92. this.pos.keypad.connect();
  93. }
  94. });
  95. // this module mimics a keypad-only cash register. Use connect() and
  96. // disconnect() to activate and deactivate it.
  97. var Keypad = core.Class.extend({
  98. init: function(attributes){
  99. this.pos = attributes.pos;
  100. /*this.pos_widget = this.pos.pos_widget;*/
  101. this.type = {
  102. numchar: 'number, dot',
  103. bmode: 'quantity, discount, price',
  104. sign: '+, -',
  105. backspace: 'backspace',
  106. enter: 'enter',
  107. escape: 'escape',
  108. };
  109. this.data = {
  110. type: undefined,
  111. val: undefined
  112. };
  113. this.action_callback = undefined;
  114. },
  115. save_callback: function(){
  116. this.saved_callback_stack.push(this.action_callback);
  117. },
  118. restore_callback: function(){
  119. if (this.saved_callback_stack.length > 0) {
  120. this.action_callback = this.saved_callback_stack.pop();
  121. }
  122. },
  123. set_action_callback: function(callback){
  124. this.action_callback = callback;
  125. },
  126. //remove action callback
  127. reset_action_callback: function(){
  128. this.action_callback = undefined;
  129. },
  130. // starts catching keyboard events and tries to interpret keystrokes,
  131. // calling the callback when needed.
  132. connect: function(){
  133. var self = this;
  134. // --- additional keyboard ---//
  135. // KeyCode: + or - (Keypad '+')
  136. var KC_PLU = 107;
  137. // KeyCode: Quantity (Keypad '/')
  138. var KC_QTY = 111;
  139. // KeyCode: Price (Keypad '*')
  140. var KC_AMT = 106;
  141. // KeyCode: Discount Percentage [0..100] (Keypad '-')
  142. var KC_DISC = 109;
  143. // --- basic keyboard --- //
  144. // KeyCode: sign + or - (Keypad 's')
  145. var KC_PLU_1 = 83;
  146. // KeyCode: Quantity (Keypad 'q')
  147. var KC_QTY_1 = 81;
  148. // KeyCode: Price (Keypad 'p')
  149. var KC_AMT_1 = 80;
  150. // KeyCode: Discount Percentage [0..100] (Keypad 'd')
  151. var KC_DISC_1 = 68;
  152. // KeyCode: Backspace (Keypad 'backspace')
  153. var KC_BACKSPACE = 8;
  154. // KeyCode: Enter (Keypad 'enter')
  155. var KC_ENTER = 13;
  156. // KeyCode: Escape (Keypad 'esc')
  157. var KC_ESCAPE = 27;
  158. var kc_lookup = {
  159. 48: '0', 49: '1', 50: '2', 51: '3', 52: '4',
  160. 53: '5', 54: '6', 55: '7', 56: '8', 57: '9',
  161. 80: 'p', 83: 's', 68: 'd', 190: '.', 81: 'q',
  162. 96: '0', 97: '1', 98: '2', 99: '3', 100: '4',
  163. 101: '5', 102: '6', 103: '7', 104: '8', 105: '9',
  164. 106: '*', 107: '+', 109: '-', 110: '.', 111: '/'
  165. };
  166. //usb keyboard keyup event
  167. var rx = /INPUT|SELECT|TEXTAREA/i;
  168. var ok = false;
  169. var timeStamp = 0;
  170. $('body').on('keyup', '', function (e){
  171. var statusHandler = !rx.test(e.target.tagName) ||
  172. e.target.disabled || e.target.readOnly;
  173. if (statusHandler){
  174. var is_number = false;
  175. var type = self.type;
  176. var buttonMode = {
  177. qty: 'quantity',
  178. disc: 'discount',
  179. price: 'price'
  180. };
  181. var token = e.keyCode;
  182. if (((token >= 96 && token <= 105) || token === 110) ||
  183. ((token >= 48 && token <= 57) || token === 190)) {
  184. self.data.type = type.numchar;
  185. self.data.val = kc_lookup[token];
  186. is_number = true;
  187. ok = true;
  188. } else if (token === KC_PLU || token === KC_PLU_1) {
  189. self.data.type = type.sign;
  190. ok = true;
  191. } else if (token === KC_QTY || token === KC_QTY_1) {
  192. self.data.type = type.bmode;
  193. self.data.val = buttonMode.qty;
  194. ok = true;
  195. } else if (token === KC_AMT || token === KC_AMT_1) {
  196. self.data.type = type.bmode;
  197. self.data.val = buttonMode.price;
  198. ok = true;
  199. } else if (token === KC_DISC || token === KC_DISC_1) {
  200. self.data.type = type.bmode;
  201. self.data.val = buttonMode.disc;
  202. ok = true;
  203. } else if (token === KC_BACKSPACE) {
  204. self.data.type = type.backspace;
  205. ok = true;
  206. } else if (token === KC_ENTER) {
  207. self.data.type = type.enter;
  208. ok = true;
  209. } else if (token === KC_ESCAPE) {
  210. self.data.type = type.escape;
  211. ok = true;
  212. } else {
  213. self.data.type = undefined;
  214. self.data.val = undefined;
  215. ok = false;
  216. }
  217. if (is_number) {
  218. if (timeStamp + 50 > new Date().getTime()) {
  219. ok = false;
  220. }
  221. }
  222. timeStamp = new Date().getTime();
  223. setTimeout(function(){
  224. if (ok) {self.action_callback(self.data);}
  225. }, 50);
  226. }
  227. });
  228. },
  229. // stops catching keyboard events
  230. disconnect: function(){
  231. $('body').off('keyup', '');
  232. }
  233. });
  234. return {
  235. Keypad: Keypad
  236. };
  237. });