Procházet zdrojové kódy

changed barcode scanner in all forms, updated release notes

chemi ledon před 7 roky
rodič
revize
595c9f8fd7

+ 1 - 2
app/assets/javascripts/application.js

@@ -60,10 +60,9 @@
 
 //= require backstretch/jquery.backstretch.min.js
 //= require plugins/login-5.js
-//= require jquery-barcodeListener.js
-//= require jquery-code-scanner.js
 //= require jquery.remotipart
 //= require accounting.min.js
+//= require jquery-scannerdetection.js
 
 
 

+ 0 - 2
app/assets/javascripts/config.js

@@ -1697,8 +1697,6 @@ $(document).on("page:change", function() {
 	       	}
     	});
 	}
-
-
 });
 
 

+ 0 - 49
app/assets/javascripts/jquery-code-scanner.js

@@ -1,49 +0,0 @@
-(function ($) {
-    $.fn.codeScanner = function (options) {
-        var settings = $.extend({}, $.fn.codeScanner.defaults, options);
-
-        return this.each(function () {
-            var pressed = false;
-            var chars = [];
-            var $input = $(this);
-
-            $(window).keypress(function (e) {
-                var keycode = (e.which) ? e.which : e.keyCode;
-                if ((keycode >= 65 && keycode <= 90) ||
-                    (keycode >= 97 && keycode <= 122) ||
-                    (keycode >= 48 && keycode <= 57)
-                ) {
-                    chars.push(String.fromCharCode(e.which));
-                }
-                // console.log(e.which + ":" + chars.join("|"));
-                if (pressed == false) {
-                    setTimeout(function () {
-                        if (chars.length >= settings.minEntryChars) {
-                            var barcode = chars.join('');
-                            settings.onScan($input, barcode);
-                        }
-                        chars = [];
-                        pressed = false;
-                    }, settings.maxEntryTime);
-                }
-                pressed = true;
-            });
-
-            $(this).keypress(function (e) {
-                if (e.which === 13) {
-                    e.preventDefault();
-                }
-            });
-
-            return $(this);
-        });
-    };
-
-    $.fn.codeScanner.defaults = {
-        minEntryChars: 8,
-        maxEntryTime: 100,
-        onScan: function ($element, barcode) {
-            $element.val(barcode);
-        }
-    };
-})(jQuery);

+ 173 - 0
app/assets/javascripts/jquery-scannerdetection.js

@@ -0,0 +1,173 @@
+/*
+ * jQuery Scanner Detection
+ *
+ * Copyright (c) 2013 Julien Maurel
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Project home:
+ * https://github.com/julien-maurel/jQuery-Scanner-Detection
+ *
+ * Version: 1.2.1
+ *
+ */
+(function($){
+    $.fn.scannerDetection=function(options){
+
+        // If string given, call onComplete callback
+        if(typeof options==="string"){
+            this.each(function(){
+                this.scannerDetectionTest(options);
+            });
+            return this;
+        }
+
+	    // If false (boolean) given, deinitialize plugin
+	    if(options === false){
+	        this.each(function(){
+	    	    this.scannerDetectionOff();
+	        });
+	        return this;
+	    }
+
+        var defaults={
+            onComplete:false, // Callback after detection of a successfull scanning (scanned string in parameter)
+            onError:false, // Callback after detection of a unsuccessfull scanning (scanned string in parameter)
+            onReceive:false, // Callback after receiving and processing a char (scanned char in parameter)
+            onKeyDetect:false, // Callback after detecting a keyDown (key char in parameter) - in contrast to onReceive, this fires for non-character keys like tab, arrows, etc. too!
+            timeBeforeScanTest:100, // Wait duration (ms) after keypress event to check if scanning is finished
+            avgTimeByChar:30, // Average time (ms) between 2 chars. Used to do difference between keyboard typing and scanning
+            minLength:6, // Minimum length for a scanning
+            endChar:[9,13], // Chars to remove and means end of scanning
+	        startChar:[], // Chars to remove and means start of scanning
+	        ignoreIfFocusOn:false, // do not handle scans if the currently focused element matches this selector
+	        scanButtonKeyCode:false, // Key code of the scanner hardware button (if the scanner button a acts as a key itself)
+	        scanButtonLongPressThreshold:3, // How many times the hardware button should issue a pressed event before a barcode is read to detect a longpress
+            onScanButtonLongPressed:false, // Callback after detection of a successfull scan while the scan button was pressed and held down
+            stopPropagation:false, // Stop immediate propagation on keypress event
+            preventDefault:false // Prevent default action on keypress event
+        };
+        if(typeof options==="function"){
+            options={onComplete:options}
+        }
+        if(typeof options!=="object"){
+            options=$.extend({},defaults);
+        }else{
+            options=$.extend({},defaults,options);
+        }
+
+        this.each(function(){
+            var self=this, $self=$(self), firstCharTime=0, lastCharTime=0, stringWriting='', callIsScanner=false, testTimer=false, scanButtonCounter=0;
+            var initScannerDetection=function(){
+                firstCharTime=0;
+                stringWriting='';
+		        scanButtonCounter=0;
+            };
+	        self.scannerDetectionOff=function(){
+		    $self.unbind('keydown.scannerDetection');
+		    $self.unbind('keypress.scannerDetection');
+	    }
+	    self.isFocusOnIgnoredElement=function(){
+            if(!options.ignoreIfFocusOn) return false;
+		    if(typeof options.ignoreIfFocusOn === 'string') return $(':focus').is(options.ignoreIfFocusOn);
+	        if(typeof options.ignoreIfFocusOn === 'object' && options.ignoreIfFocusOn.length){
+		        var focused=$(':focus');
+		        for(var i=0; i<options.ignoreIfFocusOn.length; i++){
+			        if(focused.is(options.ignoreIfFocusOn[i])){
+			            return true;
+			        }
+		        }
+		    }
+		    return false;
+	    }
+        self.scannerDetectionTest=function(s){
+            // If string is given, test it
+            if(s){
+                firstCharTime=lastCharTime=0;
+                stringWriting=s;
+            }
+
+		    if (!scanButtonCounter){
+		        scanButtonCounter = 1;
+		    }
+
+			// If all condition are good (length, time...), call the callback and re-initialize the plugin for next scanning
+			// Else, just re-initialize
+			if(stringWriting.length>=options.minLength && lastCharTime-firstCharTime<stringWriting.length*options.avgTimeByChar){
+		        if(options.onScanButtonLongPressed && scanButtonCounter > options.scanButtonLongPressThreshold) options.onScanButtonLongPressed.call(self,stringWriting,scanButtonCounter);
+                    else if(options.onComplete) options.onComplete.call(self,stringWriting,scanButtonCounter);
+                    $self.trigger('scannerDetectionComplete',{string:stringWriting});
+                    initScannerDetection();
+                    return true;
+                }else{
+                    if(options.onError) options.onError.call(self,stringWriting);
+                    $self.trigger('scannerDetectionError',{string:stringWriting});
+                    initScannerDetection();
+                    return false;
+                }
+            }
+            $self.data('scannerDetection',{options:options}).unbind('.scannerDetection').bind('keydown.scannerDetection',function(e){
+			    // If it's just the button of the scanner, ignore it and wait for the real input
+		        if(options.scanButtonKeyCode !== false && e.which==options.scanButtonKeyCode) {
+                    scanButtonCounter++;
+                    // Cancel default
+                    e.preventDefault();
+                    e.stopImmediatePropagation();
+                }
+		        // Add event on keydown because keypress is not triggered for non character keys (tab, up, down...)
+                // So need that to check endChar and startChar (that is often tab or enter) and call keypress if necessary
+                else if((firstCharTime && options.endChar.indexOf(e.which)!==-1)
+			    || (!firstCharTime && options.startChar.indexOf(e.which)!==-1)){
+                    // Clone event, set type and trigger it
+                    var e2=jQuery.Event('keypress',e);
+                    e2.type='keypress.scannerDetection';
+                    $self.triggerHandler(e2);
+                    // Cancel default
+                    e.preventDefault();
+                    e.stopImmediatePropagation();
+                }
+                // Fire keyDetect event in any case!
+                if(options.onKeyDetect) options.onKeyDetect.call(self,e);
+                $self.trigger('scannerDetectionKeyDetect',{evt:e});
+
+            }).bind('keypress.scannerDetection',function(e){
+		        if (this.isFocusOnIgnoredElement()) return;
+                if(options.stopPropagation) e.stopImmediatePropagation();
+                if(options.preventDefault) e.preventDefault();
+
+                if(firstCharTime && options.endChar.indexOf(e.which)!==-1){
+                    e.preventDefault();
+                    e.stopImmediatePropagation();
+                    callIsScanner=true;
+                }else if(!firstCharTime && options.startChar.indexOf(e.which)!==-1){
+                    e.preventDefault();
+                    e.stopImmediatePropagation();
+		            callIsScanner=false;
+		        }else{
+                    if (typeof(e.which) != 'undefined'){
+                        stringWriting+=String.fromCharCode(e.which);
+                    }
+                    callIsScanner=false;
+                }
+
+                if(!firstCharTime){
+                    firstCharTime=Date.now();
+                }
+                lastCharTime=Date.now();
+
+                if(testTimer) clearTimeout(testTimer);
+                if(callIsScanner){
+                    self.scannerDetectionTest();
+                    testTimer=false;
+                }else{
+                    testTimer=setTimeout(self.scannerDetectionTest,options.timeBeforeScanTest);
+                }
+
+                if(options.onReceive) options.onReceive.call(self,e);
+                $self.trigger('scannerDetectionReceive',{evt:e});
+            });
+        });
+        return this;
+    }
+})(jQuery);

+ 1 - 1
app/controllers/supports_controller.rb

@@ -19,6 +19,6 @@ class SupportsController < ApplicationController
   end
 
   def system_updates # change the following
-    @date = "2018/08/09" # yyyy/mm/dd
+    @date = "2018/09/05" # yyyy/mm/dd
   end
 end

+ 10 - 4
app/views/available_products/_form_stock_printable.html.erb

@@ -34,10 +34,16 @@
     }
   });
 
-  $('body').barcodeListener().on('barcode.valid', function(e, code) {
-    $('input[type=search]').val(code);
-    $('#pointsale_stock input').unbind();
-    $('#pointsale_stock').dataTable().fnFilter(code);
+  $(document).scannerDetection({
+    timeBeforeScanTest: 200, // wait for the next character for upto 200ms
+    startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
+    endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
+    avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
+    onComplete: function(barcode, qty){
+      $('input[type=search]').val(code);
+      $('#pointsale_stock input').unbind();
+      $('#pointsale_stock').dataTable().fnFilter(code);
+    }
   });
 
   $('#category, #sub_category, #pointsale').on('change', function(e) {

+ 6 - 2
app/views/purchases/_form.html.erb

@@ -274,8 +274,12 @@
 
 	});
 
-	$('body').barcodeListener().on('barcode.valid', function(e, code) {
-		findProductByBarcode(code);
+	$(document).scannerDetection({
+		timeBeforeScanTest: 200, // wait for the next character for upto 200ms
+		startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
+		endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
+		avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
+		onComplete: function(barcode, qty){ findProductByBarcode(barcode) } // main callback function
 	});
 
 	var bloodhound = new Bloodhound({

+ 10 - 11
app/views/sales/_form.html.erb

@@ -1,4 +1,4 @@
-<%= form_for(@sale, :remote => true, :html => {:class=>"form-horizontal", :id=> "sale_form"}) do |f| %>
+<%= form_for(@sale, :remote => true, :html => {:class=>"form-horizontal form-barcode", :id=> "sale_form"}) do |f| %>
 	<div class="portlet-body form">
 		<%= hidden_field_tag :barcode_for_sale %>
 		<!-- este error explanation se usa para mostrar errores de presales e inventarios -->
@@ -259,7 +259,7 @@
 	var timeout = null;
 
 	$(document).on("page:change", function() {
-		App.init();
+		// App.init();
 		calculateTotals();
 		fillCustomerInfo();
 		enumeratePreSales();
@@ -325,17 +325,16 @@
 				}
 			}
 		});
-	});
 
-	if (window.location.pathname == "/sales/new") {
-		$('#sale_form #barcode_for_sale').codeScanner({
-			maxEntryTime: 200, // milliseconds
-			minEntryChars: 7,  // characters
-			onScan: function ($element, code) {
-				findProductByBarcode(code);
-			}
+		$(document).scannerDetection({
+			timeBeforeScanTest: 200, // wait for the next character for upto 200ms
+			startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
+			endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
+			avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
+			onComplete: function(barcode, qty){ findProductByBarcode(barcode) } // main callback function
 		});
-	}
+
+	});
 
 	$('#sale_customer_id').on('change', function() {
 		// $(this).attr('disabled', true);

+ 7 - 3
app/views/special_prices/_form.html.erb

@@ -86,10 +86,14 @@
 
   $(document).on("page:change", function() {
     App.init();
-  });
 
-  $('body').barcodeListener().on('barcode.valid', function(e, code) {
-    findProductByBarcode(code);
+		$(document).scannerDetection({
+			timeBeforeScanTest: 200, // wait for the next character for upto 200ms
+			startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
+			endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
+			avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
+			onComplete: function(barcode, qty){ findProductByBarcode(barcode) } // main callback function
+		});
   });
 
   $('#special_price_customer_id').on('change', function() {

+ 18 - 15
app/views/supports/system_updates.html.erb

@@ -21,37 +21,40 @@
               <br>
               <ul>
                 <h4>GENERAL</h4>
-                <li> <strong>Columna de Precio en Asignación de Productos al punto de venta</strong>
+                <li> <strong>Promociones por periodo de tiempo</strong>
                   <ul>
-                    <li>o	Se agregó la columna de Precio en la tabla de Asignación de Productos al punto de venta para así facilitar la búsqueda y como tal la identificación de los productos. </li>
+                    <li>En el menú de Puntos de venta podrás encontrar una nueva opción llamada “Promociones”. Aquí es posible crear promociones definiendo la fecha inicial y final, y tú definirás si será sobre un producto en específico (por variantes o general), una sublínea o una línea y su respectivo porcentaje de descuento. </li>
+                    <br><li>Estas las pueden crear los Administradores y Gerentes. Y los cajeros solo podrán consultarlas.</li>
                   </ul>
                 </li>
 
-                <li><strong>Precio al momento de Asignar Productos al punto de venta</strong>
+                <br><h4>ADMINISTRADOR</h4>
+                <li><strong>Impresión de etiquetas</strong>
                   <ul>
-                    <li>Cuando algún producto se maneja en varios puntos de venta y en estos no maneja el mismo precio, este se podía modificar en “Productos>Lista de Productos>Precios en punto de venta>Seleccionar punto de venta>Asignar un precio diferente a cada uno.</li>
-                    <li>Ahora es posible realizar esta acción al momento de Asignar los productos al punto de venta, ya que junto con la cantidad que hay en el inventario aparece el campo de precio de venta (El cual ya contiene el precio dado al momento de crear el producto) por si se requiere modificar.</li>
+                    <li>Ahora en la lista de productos del sistema punto de venta aparece el botón <a class="btn btn-icon-only purple"><i class="fa fa-ticket"></i></a> el cual es para que se impriman las etiquetas del producto seleccionado.</li>
+                      <ul>
+                        <li>Primero, después de que hagas clic ese botón, se abrirá una pequeña ventana que te solicitará que selecciones un punto de venta (para tomar las existencias del producto y sus precios en el caso de que estos sean diferentes entre puntos de venta).</li>
+                        <br><li>Una vez que seleccionaste un punto de venta, automáticamente se cargaran los stocks de cada variante que haya registrada.</li>
+                        <br><li>Seleccionamos imprimir en la parte de abajo, lo que te llevará a la ventana de impresión</li>
+                        <br><li>Aquí nada más seleccionas la impresora de etiquetas (Brother QL-700 o QL-800), imprimir y automáticamente la impresora imprimirá las etiquetas y las recortará de manera individual. (Nota: un rollo de etiquetas alcanza para 473 etiquetas aproximadamente)</li>
+                      </ul>
                   </ul>
                 </li>
-
-                <li><strong>Apartado de soporte en el menú</strong>
+                <br><li><strong>Reporte de utilidades</strong>
                   <ul>
-                    <li>Ahora en esta nueva sección del software está el área de Soporte Técnico, en el cual se coloca la información solicitada (Sucursal/Punto de venta, Tipo de perfil, Descripción del error y observaciones) y una vez listo, esta información es enviada al área de soporte técnico, desde la cual se pondrán en contacto con usted a la brevedad para dar seguimiento de dicho reporte.</li>
-                    <li>Además, se agregó la parte de Actualizaciones, en donde se estará colocando toda la información sobre las actualizaciones, correcciones, mejoras, cambios, etc.</li>
+                    <li>En este reporte, tú como administrador puedes consultar la utilidad que generan tus ventas. Esto se calcula usando el precio base,  el precio de venta y las cantidades vendidas. Este lo puedes filtrar por punto de venta, fechas, por línea y sublínea para verificar (por ejemplo) cuánto generaron de utilidad tus accesorios, zapatos, blusas, etc. </li>
                   </ul>
                 </li>
 
-                <br><h4>ADMINISTRADOR</h4>
-                <li><strong>El administrador tiene acceso a Stock Inicial y Mínimos y Máximos</strong>
+                <br><li><strong>Reporte de compras por mes</strong>
                   <ul>
-                    <li>Ahora el administrador puede acceder a las ventanas de Stock Inicial y Mínimos y Máximos sin tener que cambiar de sesión a un usuario con perfil de gerente. Solo es necesario seleccionar el punto de venta sobre el cual se va a trabajar y todo lo demás se realiza tal cual como en el perfil de gerente.</li>
+                    <li>En el reporte de compras, se te mostrará información relacionada con todas las compras y egresos que se han realizado en el periodo de tiempo que selecciones, así como en el punto de venta de tu elección (o todos en su defecto). Estos se desglosarán en tablas separadas y se incluirán todas tus compras con sus diferentes tipos de cambios.  </li>
                   </ul>
                 </li>
 
-                <br><h4>CAJA Y GERENTE</h4>
-                <li><strong>Selección automática del vendedor</strong>
+                <br><li><strong>Reporte de ventas por mes</strong>
                   <ul>
-                    <li>Al momento de realizar una nueva venta, el vendedor se selecciona automáticamente en base al vendedor seleccionado en la última venta, no obstante este puede cambiarse por cualquier otro, solo está para evitar acciones adicionales, si es el mismo vendedor no tener que seleccionarlo en cada venta.</li>
+                    <li>A este reporte se han agregado 2 nuevos filtros, el de línea y el de sublínea, esto para que se puedan revisar las ventas en base al tiempo que selecciones y cualquiera de estas 2 características. Y así puedas saber cuántas ventas en ese tiempo han sido de zapatos, bolsas, etc.  </li>
                   </ul>
                 </li>
               </ul>

+ 6 - 2
app/views/transfers/_form.html.erb

@@ -182,8 +182,12 @@
       }
   });
 
-  $('body').barcodeListener().on('barcode.valid', function(e, code) {
-    findProductByBarcode(code);
+  $(document).scannerDetection({
+    timeBeforeScanTest: 200, // wait for the next character for upto 200ms
+    startChar: [120], // Prefix character for the cabled scanner (OPL6845R)
+    endChar: [13], // be sure the scan is complete if key 13 (enter) is detected
+    avgTimeByChar: 40, // it's not a barcode if a character takes longer than 40ms
+    onComplete: function(barcode, qty){ findProductByBarcode(barcode) } // main callback function
   });
 
   $('#transfer_destiny_id').on('change', function() {