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.

272 lines
9.9 KiB

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