CRC-8 con FileMaker 19 y JavaScript

Vamos a ver en la presente entrada cómo calcular el CRC-8 de un campo con FileMaker usando JavaScript, siguiendo el ejemplo de lo que se solicita para TicketBAI, un proyecto común de las Agencias Forales y del Gobierno Vasco.

Hace unos días recibí una consulta de Judith respecto a los QR. El tema derivó en unos intercambios de mails en los que se planteó otra cuestión: cómo calcular un CRC-8 con FileMaker. Así que a Judith se debe que me haya decidido a desempolvar el actualizador del blog y a ella va dedicada esta entrada 😉

El asunto era interesante, estábamos hablando de los QR y JavaScript y se planteaba la cuestión de si sería posible realizar algún cálculo con JavaScript y trasladarlo a FileMaker. Y la respuesta es sí, pero con FileMaker 19. Esa es una de las interesantes novedades de esta versión.

Pero, para ser honesto, antes de seguir debo decir que la inspiración no me vino por intercesión angelical, más bien fue al encontrar este vídeo:

El ejemplo que siguen en él es ligeramente diferente al que vamos a usar aquí, pero da las pistas clave para llevarlo a cabo. Luego, el modo de activar el guion también es distinto, ya que si lo hacía como dice el vídeo el campo que debía almacenar el valor hacía cosas raras y de la forma que se describe más abajo funciona bien. Pero vamos, eso no quita para que ese video sea una joya

Dicho esto, continuamos:

FileMaker 19 permite realizar lo que sea en JavaScript y trasladar el contenido de una variable JavaScript a un campo de FileMaker.

Esto lo consigue con un visualizador web, un guion y una casilla nueva que en esta versión aparece en el apartado del visualizador web:

Esa última casilla es nueva en FileMaker 19 y debe estar activada para poder trasladar datos de JavaScript a FileMaker

Pero, para explicarlo, mejor vamos con un ejemplo concreto.

Todo esto tiene su origen en TicketBAI… ¿Y qué es eso de TicketBAI? Bueno, pues como se define en uno de los PDF:

TicketBAI es un proyecto común de las Haciendas Forales y del Gobierno Vasco cuyo objetivo es la implantación de una serie de obligaciones legales y técnicas en los software de facturación de las personas contribuyentes, que permitan a la Administración tributaria el control de los ingresos de sus actividades económicas

Y uno de los requisitos de TicketBAI es calcular el CRC-8 de una cadena de caracteres compuesta de “TBAI” + guion + NIF + guion + FECHA (DDMMYY) + CARACTERES DE FIRMA (para nuestro ejemplo, cualquier carácter alfanumérico) + guion.

Podríamos realizar esta explicación directamente con una cadena de caracteres tal cual, pero es muy poca complicación adicional y realizamos un ejemplo práctico, que simplificar luego siempre es más fácil.

Por si alguien tiene interés, la información completa de TicketBAI se encuentra aquí:

https://web.araba.eus/es/hacienda/ticketbai

Concretamente en el documento que se encuentra enlazado al final de la página, “Especificaciones funcionales y técnicas”, es donde se detalla lo que debe calcular el CRC-8, en su apartado 4.3.2 . Luego, al final de dicho documento, en el Anexo 3, viene el algoritmo CRC de comprobación en lenguaje Java, así que la pregunta sería ¿Se puede calcular esto con FileMaker?

Para empezar, Java no es lo mismo que JavaScript, así que directamente, con el algoritmo ofrecido en la documentación, la respuesta es no.

Otra opción sería crear una función personalizada en FileMaker, pero yo por ahí, ni idea, así que vamos a ver qué podemos hacer con JavaScript. Pero antes de liarnos a programar ¿Existe algún algoritmo para el cálculo de CRC-8 en JavaScript? Y la respuesta es sí.

Buscando, encontré esto por GitHub, cuyo autor es mode80

https://github.com/mode80/crc8js

Antes de empezar hice un par de comprobaciones: Por un lado realicé una página web muy sencilla para meter una entrada y que me diera el código y poder compararlo con el de los ejemplos del PDF de TicketBAI, y salió perfecto. No obstante, por asegurarme, realicé otra para que mostrara el contenido del array de la tabla y compararlo con el del Anexo 3 del PDF y coinciden, así que, al lío.

Ingredientes (como si fuera una receta de cocina)

Como podemos ver, tenemos el script crc8.js y luego un ejemplo de uso que usaremos tal cual. Si echamos un vistazo al código y al ejemplo de uso que vamos a seguir, podremos ver que aún podríamos simplificar más el código JavaScript, ya que no pasamos argumentos al constructor,

var crc8 = new CRC8()

pero son media docena de líneas y tal como está funciona y funciona bien, así que si algo funciona ¿para qué vas a tocarlo? Cero complicaciones añadidas.

Pantallazo de GitHub de donde nos descargamos el script JS y con el código de ejemplo que usaremos casi tal cual
Contenido del script que más adelante modificaremos añadiendo una función

Así que para el FileMaker, y para este ejemplo concreto, vamos a necesitar:

      • La versión 19
      • Varios campos
      • Un visualizador web
      • Un guion

Vamos con los campos:

      • Cinco campos de texto, de los cuales dos serán globales.
      • Un campo de fecha
      • Tres campos de cálculo

Campos de texto globales

js, que almacenará el código JavaScript. En este campo copiaremos el contenido del script en JavaScript que trataremos más adelante, ya que modificaremos ligeramente el que hemos descargado. Y tbai, que almacenará la cadena “TBAI” para hacer coincidir nuestro ejemplo con lo que se pide en el PDF. En ambos casos será copiar los textos y pegarlos en los campos, que al ser globales tendrán el mismo contenido en cada registro que generemos.

Campos de texto de entrada

nif y firma: donde introduciremos las cadenas de texto que queramos. Teóricamente la primera sería el NIF del cliente y la segunda “Los trece primeros caracteres del campo SignatureValue del fichero TBAI asociado a la factura” Como esto es un ejemplo, meteremos a mano el texto que queramos. En este ejemplo los copiaremos de los que aparecen en el PDF para ver si el resultado coincide.

Campo de entrada de fecha

fecha, en formato DD-MM-YYYY que le gusta a FileMaker y que luego nos encargaremos de reajustar.

Campo de salida

crc8: Campo de texto normal en el que el guion pegará el contenido de la variable JavaScript que contenga el cálculo del CRC-8

Campos de cálculo:

cadena, con resultado texto: aquí juntaremos el contenido de los campos: tbai, nif, fecha y firma, separados por guiones y añadiendo un guion al final. Esta es la cadena de texto sobre la que calcular el CRC-8. Podríamos haber simplificado el ejemplo creando sólo este campo y siguiendo a partir de aquí, pero por ajustarlo a TicketBAI me ha parecido interesante hacerlo así y de paso resolver el problema del formato de fecha que se pide en DDMMYY.

Paréntesis: Por cierto, que me ha sorprendido que se pida la fecha con dos dígitos para el año porque esto supone que este sistema nace ya con fecha de caducidad. No sé bien si es lo que llaman “obsolescencia programada” o lo de que “el que venga detrás que arree”, en cualquier caso, viendo los actuales requisitos del TicketBAI actual, no le arriendo la ganancia a quien esté aquí dentro de ochenta años.

crc, con resultado texto: aquí generaremos “la web” que ha de procesar el visualizador.

salida, con resultado texto: Simplemente el resultado de unir las cadenas de “cadena” y “crc8” y poder comparar el resultado con los ejemplos, además de poder comprobar así que podemos operar con el campo crc8 obtenido de forma normal.

Campos de cálculo “cadena” y “salida

Vamos con estos dos campos, el campo “crc” lo trataremos en el siguiente punto ya que está estrechamente relacionado con el código JavaScript.

Ambos campos no tienen mucho misterio, se trata de unir cadenas. No obstante, el campo “cadena” sí que tiene una pequeña complicación y es trasladar la fecha del formato que le gusta a FileMaker: DD-MM-YYYY al que se solicita: DDMMYY.

Si empezamos por lo fácil, vamos con el campo salida. Este será el resultado de lo siguiente, copiar y pegar:

cadena & crc8

Fácil ¿no?

Pues el otro, cuando se sabe, no es muy complicado. Vamos con el campo cadena:

tbai & "-" & nif & "-" & SerialIncrement ( "00" ; Day ( fecha ) ) & SerialIncrement ( "00" ; Month ( fecha ) ) & (Year ( fecha ) - 2000) & "-" & firma & "-"

Como vemos, vamos uniendo el campo tbai, un guion, el campo nif… y así llegamos a la fecha.

Para el día y el mes usamos la función SerialIncrement, documentada aquí:

https://help.claris.com/es/pro-help/content/serialincrement.html?Highlight=serialincrement

Como el resultado del campo va a ser texto, decimos que a 00 le incremente el día que sea o el mes que sea.

Y luego, para el año, pues supongo que habrá soluciones más elegantes, pero simplemente con restar 2000 tenemos el asunto resuelto. ¡Ojo! Esto nos sirve para nuestro ejemplo en concreto, que manejará fechas entre 2022 y 2099 como máximo, por lo que no tendremos un cero a la izquierda que nos dé problemas como en los días y meses. No obstante, otra de las soluciones “más elegantes”, con resultado texto, podría ser esta:

SerialIncrement ( "00" ; Right ( GetAsText ( Year ( fecha ) ); 2 ))

Luego, seguimos concatenando guiones y campos y listo. Ya tenemos lo que se pide y sobre lo que se ha de calcular el CRC-8 que veremos a continuación.

Preparando el script y el campo de cálculo “crc

Echamos un vistazo al “ejemplo de uso” que mode80 nos muestra en GitHub:

Vemos que, lo único que necesitamos, es asignar a la variable “sample_text” el valor sobre lo que queramos calcular el CRC-8. En nuestro caso, ese valor será lo que contenga el campo cadena. Eso está en la primera línea.

Luego, en la última línea, tenemos que la variable checksum será la que contenga el cálculo del CRC-8. El contenido de esa variable es lo que queremos llevar al campo crc mediante un guion. Llamaremos a ese guion “pegasalida“, pero eso lo veremos luego.

Así que, lo que vamos a hacer en primer lugar es crear una función con el contenido de este ejemplo, así:

function entrada(valorentrada) {
   var sample_text = valorentrada;
   var byte_array = sample_text.split('').map(function(x){return x.charCodeAt(0)});
   var crc8 = new CRC8();
   var checksum = crc8.checksum(byte_array);
}

Creamos una función a la que pasaremos el argumento “valorentrada” y luego ese valor lo tomará la variable sample_text, se realizarán los cálculos y el resultado lo tendremos en la variable checksum.

Para pasar el valor de checksum al guion de FileMaker que lo habrá de colocar en el campo de texto y que hemos bautizado como “pegasalida“, tenemos que colocar la siguiente línea:

FileMaker.PerformScriptWithOption ( 'pegasalida', checksum, '0' );

Para aclarar dudas sobre esto, aquí:

https://help.claris.com/es/pro-help/content/scripting-javascript-in-web-viewers.html?Highlight=PerformScriptWithOption%20

Resumiendo:

Y en cuanto a las opciones disponibles, están aquí:

https://help.claris.com/es/pro-help/content/options-for-starting-scripts.html?Highlight=PerformScriptWithOption%20

Resumiendo: Usaremos la opción 0

Así que la función que añadimos al script queda así:

Y el script completo que meteremos en el campo js, así:

function CRC8(polynomial, initial_value) {
  if (polynomial == null) polynomial = CRC8.POLY.CRC8_CCITT
  this.table = CRC8.generateTable(polynomial);
  this.initial_value = initial_value;
}
CRC8.prototype.checksum = function(byte_array) {
  var c = this.initial_value;
  for (var i = 0; i < byte_array.length; i++ ) 
    c = this.table[(c ^ byte_array[i]) % 256] 
  return c;
} 
CRC8.generateTable =function(polynomial)
{
  var csTable = []  
  for ( var i = 0; i < 256; ++i ) {
    var curr = i
    for ( var j = 0; j < 8; ++j ) {
      if ((curr & 0x80) !== 0) {
        curr = ((curr << 1) ^ polynomial) % 256
      } else {
        curr = (curr << 1) % 256
      }
    }
    csTable[i] = curr 
  }  
  return csTable
}
CRC8.POLY = {
  CRC8 : 0xd5,
  CRC8_CCITT : 0x07,
  CRC8_DALLAS_MAXIM : 0x31,
  CRC8_SAE_J1850 : 0x1D,
  CRC_8_WCDMA : 0x9b,
}
function entrada(valorentrada) {
  var sample_text = valorentrada;
  var byte_array = sample_text.split('').map(function(x){return x.charCodeAt(0)});
  var crc8 = new CRC8();
  var checksum = crc8.checksum(byte_array);
  FileMaker.PerformScriptWithOption ( 'pegasalida', checksum, '0' );
}

Vamos ahora con el campo de cálculo.

Este campo será el que genere el código html que procese el visualizador web y que ejecute el código anterior. Su contenido no es muy complicado:

"<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=Utf-8'>
<script>" & js & "</script>
</head>
<body>
<script>
entrada('" & cadena & "');
</script> 
</body>
</html>"

Ojo a las comillas: todo con comillas simples y usamos las dobles para encerrarlas

Como vemos, lo que se hace es crear una página web en la que insertamos el código del campo js, nuestro script en JavaScript.  Y luego, en el body, insertamos un código JavaScript llamando a la función que hemos creado, entrada, y pasando como argumento el campo cadena.

Esto genera un código interpretable por cualquier navegador y, por supuesto, por nuestro visualizador web de FileMaker, pero atención, este código no genera ninguna salida por el visualizador, de forma totalmente intencionada, porque tampoco la necesitamos, de hecho, ocultaremos también el visualizador, sólo queremos que se procese el código y traernos el valor de la variable checksum.

El visualizador

Lo más complicado ya lo tenemos, así que ya va quedando menos y encima es cuesta abajo. Vamos con el visualizador, luego con el guion y asunto zanjado.

Insertamos en nuestra presentación un visualizador web al que le decimos que muestre una dirección web personalizada, que será el campo de cálculo anterior:

Y, en las opciones, nos aseguramos de que esté marcada la última: Permitir a JavaScript ejecutar guiones de FileMaker.

Pero la verdad es que ese visualizados nos estorba, sólo lo queremos para que procese el código, así que lo quitamos de la vista. Una de las formas, quizás algo chapucera, pero que funciona es darle una dimensión de 1 x 1 píxeles (y porque 0 x 0 no quiere):

Y luego lo dejo en una esquina donde no moleste:

Es ese puntito rojo que se ve arriba a la izquierda si estamos en modo presentación.

El guion

Un par de líneas y tenemos la magia:

Ampliamos para que se vea:

Como vemos son dos líneas. En la primera creamos una variable, que hemos llamado $jschecksum. Esta variable recibirá el contenido de la variable checksum de JavaScript.

La segunda línea establece el campo crc8 de nuestro archivo FileMaker y colocará en él el valor de la variable. En este caso, la variable que se pasa sólo contiene un valor, pero desde JavaScript podríamos pasar más de uno y colocarlos a nuestra conveniencia. Es similar a pasar un array (los valores irían separados uno en cada línea), aunque aquí el primer valor es 1 y no 0, pero hay que ponerlo. Más información:

https://help.claris.com/es/pro-help/content/getvalue.html?Highlight=getvalue

Edito: Por otras pruebas realizadas en las entradas relativas al QR, “parece” que no es necesario establecer un activador de guiones. Al tener en FM 19 la casilla de “permitir a JavaScript ejecutar guiones de FileMaker” este paso “creo” que es innecesario, o al menos, en alguna prueba que he hecho, el guion se ejecutaba perfectamente sin establecer ningún activador. 

Y ya sólo nos queda decir cuándo se ha de activar este guion. Para ello nos vamos a Presentación y con el botón derecho del ratón pulsamos sobre el “puntito” del visualizador web y seleccionamos “Establecer activadores de guion”

Y en la pantalla que se abra seleccionamos la primera de las opciones, OnObjectEnter:

Y ya está todo. Estos son los campos que hemos creado y sus contenidos si rellenamos las entradas con el primer ejemplo que viene en el PDF del TicketBAI:

Por supuesto, en nuestra presentación final no es necesario tener todos los campos a la vista, es sólo para ilustrar mejor el contenido de cada uno, ver cómo se comportan y lo que hacen.

Es una entrada poquito larga y quizás algo farragosa, pero esta interacción del visualizador hacia FileMaker bien merece la pena, porque abre todo un abanico de posibilidades a tener en cuenta.

A disfrutar!!!

Deja una respuesta

No está permitida la inserción de ningún dato de carácter personal (mail, tef...). Cualquier comentario que los contenga será editado o eliminado.

Por favor, si dejas un comentario pon cualquier nombre para poderme dirigir a ti pero que no te identifique

El comentario es totalmente anónimo. No se almacena la IP