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.

273 lines
9.9 KiB

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