Blog

pfbatch (Impresoras Fiscales)

Introducción

Introducción

Una impresora fiscal es utilizada para imprimir tiquets y facturas
pfbatch Programa utilizado para enviar comandos a una impresora fiscal Epson.
vpfbatch Alternativa, soportado por arquitecturas de 64 bits: Descarga
jpfbatch Alternativa, requiere java: Descarga
ixbatch Alternativa privativa con una sintáxis mejorada: Descarga Si se utiliza la versión de prueba, imprimirá una leyenda “demo” en los tiquets y facturas

Los comandos presentados a continuación fueron probados en una impresora Epson TM-U220AFII versión fiscal para Argentina

Ejecución vpfbatch

Desde la interfaz de comando:

vpfbatch /c:2 /i:input.txt /o:output.txt
/c:2 #puerto com2
/i:input.txt #archivo de texto que contiene los comandos a ejecutar.
/o:output.txt #archivo de texto que contiene la salida de los comandos ejecutados. Se graba línea por línea la respuesta a cada comando como una cadena de caracteres
Ejecución jpfbatch

Desde la interfaz de comando:

java -jar jpfbatch.jar -i input.in
  -i comando.in #archivo de texto que contiene los comandos a ejecutar. La salida la guarda en un archivo con el mismo nombre pero la extensión out, para este caso comando.out
Sintaxis comandos
@COMANDO|00001|PARAM 1|PARAM 2|...
  00001 #número de transacción. Se define un número de referencia o de transacción dentro del lote para poder asociar las respuestas a cada transacción (este número se debe repetir para cada comando de la transacción, y debe ser distinto para cada transacción). Generalmente se realiza una transacción a la vez, por lo tanto el número siempre se define como 00001
  PARAM 1, PARAM 2 #parámetros

VPFBATCH y JPFBATCH utilizan la misma sintaxis que PFBATCH.
Las instrucciones de IxBatch a diferencia del PFBATCH no llevan un número de secuencia y las cifras deben tipearse con los decimales.

Comandos

Tiquets

Los tiquets son una factura B pero sin nombre del cliente. Su numeración sigue la secuencia de las facturas B.

@TIQUEABRE
@TIQUEABRE|00001
  00001 #numero de referencia

Ejemplo error: Ya existe un comprobante abierto

|@TIQUEABRE         |ERROR|0080|B620

Se soluciona cancelando el comprobante anterior

@TIQUEITEM
@TIQUEITEM|00001|descripcion|00001000|000000010|2100|M|00001|00000000
  00001 #numero de referencia
  descripcion #descripcion de articulo, hasta 20 caracteres
  00001000 #cantidad 5 enteros y 3 decimales
  000000010 #precio 7 enteros y 2 decimales
  2100 #Tasa de IVA 4 decimales. En general, no se discrimina IVA para tiquets y facturas B. (IVA = 0000)
  M #Calificador de ITEM 1 carácter. M Monto agregado mercadería SUMA. m Reversión Resta. R Bonificación Resta. r Anula la bonificación SUMA
  00001 #Cantidad de bultos 5 enteros
  00000000 #Tasa de ajuste 8 enteros
@TIQUESUBTOTAL
@FACTSUBTOTAL|00001|P|TITULO SUBTOTAL
  00001 #Número de transacción
  P #Modo de impresión: P imprime caso contrario envía la información
  TITULO SUBTOTAL #Descripción de la línea de subtotal (29 caracteres)
@TIQUEPAGO

En los tiquets se incluye al finalizar la leyenda:

SUMA DE SUS PAGOS XXXXXX
SU VUELTO YYYYYY

A través del comando TIQUEPAGO se puede indicar el valor de XXXXXX, YYYYYY se calculará automáticamente. Si no se incluye TIQUEPAGO, dependiendo del modelo del controlador fiscal se imprimirá XXXXXX en 0 e YYYYYY con el total negativo, o XXXXXX con el total e YYYYYY en 0

@TIQUEPAGO|00001|DESCRIP PAGO|000002050|T
  00001 #numero de referencia
  DESCRIP PAGO #leyenda del pago
  000002050 #Importe 7 enteros y 2 decimales 0000020,50
  T #Calificador de pago 1 carácter - C Cancela Comprobante - T Suma el importe pagado - t Anula un pago hecho con Ticket - D Realiza un descuento global por monto Fijo - R Realiza un recargo global por monto Fijo

Ejemplo cancelación

@TIQUEPAGO|00001|CANCELACION|000002000|C
@TIQUECIERRA
@TIQUECIERRA|00001|T
  00001 #numero de referencia
  T #Corte de papel. T Total P Parcial
Ejemplo input.txt
@TIQUEABRE|00001|C
@TIQUEITEM|00001|Nafta Mezcla|00012000|000003000|0000|M|00001|00000000
@TIQUEITEM|00001|Diesel + Euro|00010500|000002005|0000|M|00001|00000000
@TIQUESUBTOTAL|00001|P|SUBTOTAL
@TIQUEPAGO|00001|PAGO|00100000|T
@TIQUECIERRA|00001|T
Ejemplo output.txt
|@TIQUEITEM         |OK   |0080|3600||||||00000|00000|00000000
|@TIQUEITEM         |OK   |0080|3600||||||00000|00000|00000000
|@TIQUESUBTOTAL     |OK   
|0080|3600|A|00002|000000057053|000000000000|000000000000|000000000000|000000000000|000000057053
|@TIQUEPAGO         |OK   |0080|3600|000000000000
|@TIQUECIERRA       |OK   |0080|0600|00000010
  #00000010 coincide con numero de comprobante
Ejemplo tiquet impreso

tique

Factura y Notas de Crédito

En las facturas se define el nombre del cliente. Dependiendo del tipo de factura debe discriminarse iva.
Cada tipo de factura tiene su propia secuencia de numeración. La secuencia de las facturas B esta asociada a la de los tiquets.

@FACTABRE
@FACTABRE|00001|T|C|B|1|P|17|I|F|JUAN PEREZ|NOMBRE 2|DNI|20179665523|N|BELGRANO 970|DOMICILIO 2|DOMICILIO 3|REMITO 1|REMITO 2|C
  00001 #numero de referencia
  T #Tipo de documento T = Tique fiscal - M Notas de crédito
  C #Tipo de salida impresa - C formulario continuo - F hoja suelta
  B #Letra del documento - (facturas A-B-C)
  1 #Cantidad de copias
  P #Tipo de Formulario - F (pre impreso) - P (dibuja la impresora) - A (auto impreso)
  17 #Tamaño de los caracteres -10 12 17
  I #Responsable IVA Vendedor: I Responsable Inscripto - R Responsable no Inscripto - N No responsable - E Exento - M Monotributo
  F #Responsab IVA Comprador I R N E M F (cons. final). Para las facturas "tipo B" debe definirse "Responsable F", si se define "Responsable I" entonces se imprimirá una "Tipo A" por más que se haya puesto "Tipo B"
  JUAN PEREZ #Nombre comercial comprador 1 línea
  NOMBRE 2 #Opcional. Nombre comercial 2 línea
  DNI #Tipo de documento comprador DNI CUIT CUIL
  20179665523 #Nro. de documento comprador
  N #Bien de Uso - B (leyenda VTA BIENES USO) - N (no se imprime la leyenda)
  BELGRANO 970 #Domicilio de comprador 1 línea
  DOMICILIO 2 #Opcional. Domicilio de comprador 2 línea
  DOMICILIO 3 #Opcional. Domicilio de comprador 3 línea
  REMITO 1 #Remito 1 línea. Para las facturas, se imprime el número de remito. Para las notas de crédito, en el comprobante impreso se incluirá la leyenda ¿?
  REMITO 2 #Opcional. Remito 2 línea
  C #Formato para almacenar datos - C (no se va a realizar un DFH para Farmacia) - G (únicamente cuando se va a emitir un DFH para Farmacia)

Ejemplos

@FACTABRE|00001|T|C|A|1|P|10|I|I|JUAN PEREZ||CUIT|20312345678|N|DOMICILIO|||REMITO||C #Factura A
@FACTABRE|00001|M|C|A|1|P|10|I|I|JUAN PEREZ||CUIT|20312345678|N|DOMICILIO|||REMITO||C #Nota de Crédito A
@FACTABRE|00001|T|C|B|1|P|10|I|F|Consumidor Final||CUIT|000000000000|N|DOMICILIO|||REMITO||C #Factura B
@FACTABRE|00001|M|C|B|1|P|10|I|F|Consumidor Final||CUIT|000000000000|N|DOMICILIO|||REMITO||C #Nota de Crédito B
@FACTITEM
@FACTITEM|00001|DESCRIPCION ART 1|00012500|000000234|2100|M|00001|00000000|LIN COMP 1|LIN COMP2|LIN COMP3|0000|00000000
  00001 #Número de transacción 
  DESCRIPCION ART 1 #Descripción del ítem. En las pruebas se incluyeron longitudes de hasta 20 pero la impresión solo salieron 14 caracteres.
  00012500 #Cantidad Unidades (tres decimales), corresponde a 00012,500
  000000234 #Precio (dos decimales), corresponde a 0000002,34 - Factura A Sin IVA - Factura B y C Con IVA
  2100 #Tasa de IVA corresponde a 21% o 0,21
  M #Calificador de ITEM - M Monto Agregado de Mercaderías SUMA - m Anula el ítem Vendido RESTA - R Bonificación RESTA - r Anula una bonificación SUMA
  00001 #Cantidad de bultos No se usa 00001
  00000000 #Tasa de ajuste En Factura A se calcula diferente que en Facturas B. 8 decimales, ej 73206442 equivale a 0.73206442
  LIN COMP 1 #Línea extra 1 descrip complementaria. Generalmente aparece entre la descripción y la cantidad.
  LIN COMP 2 #Línea extra 2 descrip complementaria. Generalmente aparece entre la descripción y la cantidad.
  LIN COMP 3 #Línea extra 3 descrip complementaria. Generalmente aparece entre la descripción y la cantidad.
  0000 #Tasa de IVA acrecentamiento R.no Inscr. (Un resp. Inscripto le vende a un Resp. No Responsable Inscripto)
a un Resp. No Inscripto)
  00000000 #Monto de impuestos internos fijos |00000000|nnnnnnnnn.nnnnnnnn ¿¿??

Ejemplos

@FACTITEM|00001|Nafta Mezcla|00012000|000001716|2100|M|1|65019506||||0000|00000000 #utilizado en factura A o nota de credito A (se carga el precio neto y el iva)
@FACTITEM|00001|Nafta Mezcla|00012000|000003000|0000|M|1|00000000||||0000|00000000 #utilizado en factura B o nota de crédito B (se carga solo el precio total)
@FACTPERCEP
@FACTPERCEP|00001|DESCRIP PERCEPCION|O|000000053
  00001 #Número de transacción
  DESCRIP PERCEPCION #Descripción de la línea de percepción 25 caracteres.
  O #Marca de percepción de IVA Indica si es una percepción sobre IVA o sobre otra percepción. Cualquier otra letra rechaza el comando: I percepción sobre IVA - O Otro tipo de percepción
  000000053 #Monto de percepción: 7 enteros, dos decimales, corresponde a 0000000,53
@FACTSUBTOTAL

Similar a @TIQUESUBTOTAL

@FACTPAGO

Similar a @TIQUEPAGO

@FACTCIERRA
@FACTCIERRA|00001|T|A|FINAL
  00001 #Número de transacción
  T #Tipo de documento fiscal: F Factura Fiscal - T Ticket Factura Fiscal - R si estoy abriendo un Recibo Factura - 
  A #Letra de Documento Fiscal Factura A B o C (Según haya abierto)
  FINAL #Descripción de la línea de totaL

Ejemplos
@FACTCIERRA|00001|T|A|FINAL #Cierre de factura A
@FACTCIERRA|00001|M|A|FINAL #Cierre de nota de crédito A
@FACTCIERRA|00001|T|B|FINAL #Cierre de factura B
@FACTCIERRA|00001|M|B|FINAL #Cierre de nota de crédito B

Ejemplo input.txt Factura A
@FACTABRE|00001|T|C|A|1|P|10|I|I|Juan Perez||CUIT|20312345678|N|.|||.||C
@FACTITEM|00001|Nafta Mezcla|00012000|000001716|2100|M|1|65019506||||0000|00000000
@FACTITEM|00001|Diesel + Euro|00010500|000001272|2100|M|1|73206442||||0000|00000000
@FACTPERCEP|00001|PERCEPCION|O|000000001
@FACTSUBTOTAL|00001|P|SUBTOTAL
@FACTPAGO|00001|PAGO|00100000|T
@FACTCIERRA|00001|T|A|FINAL
Ejemplo output.txt Factura A
|@FACTABRE          |OK   |0080|3600|
|@FACTITEM          |OK   |0080|3600|
|@FACTITEM          |OK   |0080|3600|
|@FACTPERCEP        |OK   |0080|3600|
|@FACTSUBTOTAL      |OK
|0080|3600|A|00002|000000057045|000000007129|000000000000|000000015967|000000000000|000000033948
|@FACTPAGO          |OK   |0080|3600|000000000000
|@FACTCIERRA        |OK   |0080|0600|0000005
Ejemplo Factura A Impresa

facturaa

Otros

@ESTADO
@ESTADO|00001|

Respuesta ok

|@ESTADO            |OK
|0080|0600|00000|00000002|00000002|00000002|00000000|00000000|00000|00000000|00000000|00000000|00000000

Respuesta error: Debe hacerse un Cierre Z

|@ESTADO |ERROR|0080|0A00|N|*|||

Extra

Fuente

vpfbatch
jpfbatch
ixbatch
Manual de Soporte para Desarrolladores de Software Impresoras Fiscales

Ultima actualización 15/10/2016

Definir un esquema PostgreSQL desde un esquema MySQL creado con MySQL Workbench

Reemplazar ENGINE = InnoDB por ” (cadena vacia)
Reemplazar DEFAULT CHARACTER SET … por ”
Reemplazar COLLATE = … POR ”
Reemplazar CHARACTER SET … POR ”
Reemplazar SET … POR ”
Reemplazar acento frances ` por ”
Reemplazar UNIQUE INDEX … por ” y asignar UNIQUE a los campos correspondientes
Reemplazar INDEX … por ”

Reemplazar TINYINT(1) por BOOLEAN
Reemplazar id BIGINT(20) por BIGSERIAL
Reemplazar BIGINT(… por BIGINT
Reemplazar INT(… por INTEGER
Reemplazar INTEGER NOT NULL AUTO_INCREMENT por SERIAL

Eliminar fila CONSTRAINT de las fks
Eliminar fila CREATE INDEX
Eliminar fila CREATE UNIQUE y agregar UNIQUE a los campos correspondientes
Eliminar fila AUTO_INCREMENT =
Eliminar fila @OLD
Reemplazar UNSIGNED por cadena vacia

Reorganizar el orden de los create
Opcionalmente asignar bigserial o serial a los pk si no estan definidas recordando que

  
CREATE TABLE tablename (
  colname SERIAL
);

equivale a
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
    colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

Opcionalmente reemplazar IF NOT EXISTS por”
Luego de la migración inicializar secuencias:
SELECT colname FROM tablename ORDER BY colname DESC
ALTER SEQUENCE tablename_colname_seq RESTART WITH 105;

Correr una Aplicación Web en Docker

Introducción

For our web application we’re going to run a Python Flask application.

$ docker run -d -P training/webapp python app.py

-P #map any required network ports inside our container to our host. This lets us view our web application.
training/webapp #pre-built image you’ve created that contains a simple Python Flask web application
See on browser
docker ps
  NAMES: xyz #id o name
  PORTS: 0.0.0.0:49155->5000/tcp #In this case Docker has exposed port 5000 (the default Python Flask port) on port 49155. Para ver la aplicación corriendo ir a un navegador y escribir http://0.0.0.0:49155 o localhost:49155


docker logs xyz
  * Running on http://0.0.0.0:5000/
-p flag
-p flag #is a shortcut for -p 5000 that maps port 5000 inside the container to a high port (from ephemeral port range which typically ranges from 32768 to 61000) on the local Docker host. 

$ docker run -d -p 80:5000 training/webapp python app.py #This would map port 5000 inside our container to port 80 on our local host. 
EXPOSE

En el dockerfile, por ejemplo, incluimos
EXPOSE 80
EXPOSE 443

Debemos usar alguno de los puertos expuestos
docker run -p xx:80
docker run -p xx:443

commands
$ docker port xyz 5000 #Shortcut to see ports  we specify the ID or name of our container and then the port for which we need the corresponding public-facing port
  0.0.0.0:49155
  
$ docker port xyz
  5000/tcp 0.0.0.0:49155
  
docker top xyz #examine the processes running inside container. We can see python app.py
docker inspect xyz #low-level dive into our Docker container
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' xyz #Show specific element
docker start xyz #Restart stopped container -> 1) docker stop xyz 2) docker start xyz
docker rm xyz #Remove container -> 1) docker stop xyz 2) docker rm xyz

Fuente

https://docs.docker.com/engine/tutorials/usingdocker/

Introducción a Docker

Introducción

Introducción

Objetivo “Build, Ship, and Run Any App, Anywhere”.

Instalación https://docs.docker.com/engine/installation/
(UBUNTU 16.04)

   $ sudo apt-get update
   $ sudo apt-get install apt-transport-https ca-certificates
   $ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
   $ sudo gedit /etc/apt/sources.list.d/docker.list
   deb https://apt.dockerproject.org/repo ubuntu-xenial main
   $ sudo apt-get update
   $ sudo apt-get purge lxc-docker #purge old repo if exists
   $ apt-cache policy docker-engine #Verify that APT is pulling from the right repository.
   $ sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual # it’s recommended to install the linux-image-extra-* kernel packages. The linux-image-extra-* packages allows you use the aufs storage driver. El comando uname -r devuelve la version del kernel
   $ sudo apt-get install docker-engine
   $ sudo service docker start
   $ sudo docker run hello-world #Verify docker is installed correctly.
Ejemplo: “Hello World”
$ docker run ubuntu /bin/echo 'Hello World'
docker run #runs a container.
ubuntu #image
/bin/echo #command
Images and Containers

An image is a lightweight, stand-alone, executable package that includes everything needed to run a piece of software, including the code, a runtime, libraries, environment variables, and config files.

A container is a runtime instance of an image – what the image becomes in memory when actually executed. It runs completely isolated from the host environment by default, only accessing host files and ports if configured to do so.

Images and Registry

When you specify an image, Docker looks first for the image on your Docker host. If the image does not exist locally, then the image is pulled from the public image registry https://hub.docker.com/

Se pueden crear imagenes y subirlas al registro público, serán accesibles para todos.
Se pueden crear registros privados.

Tags

A repository potentially holds multiple variants of an image. When you run a container you refer to a tagged image like so:
$ docker run -t -i ubuntu:14.04 /bin/bash

If you don’t specify a variant default to using the ubuntu:latest image

Interactive and Daemonized containers

Introducción

A grandes rasgos podemos identificar a los contenedores como:
1) Una vez ejecutado, terminan: Ejemplo “Hello World”
2) Una vez ejecuta, no terminan: Ejemplo “Interactive” y “Daemonized”.

Ejemplo: “Interactive container”


$ docker run -t -i ubuntu /bin/bash

root@af8bae53bdd3:/#

-t flag assigns a pseudo-tty or terminal inside the new container.
-i flag allows you to make an interactive connection by grabbing the standard in (STDIN) of the container.
/bin/bash launches a Bash shell inside our container.

Now, you can play around inside this container. When completed, run the exit command or Ctrl-D.

Ejemplo: “Daemonized container”


$ docker run -d ubuntu /bin/sh -c “while true; do echo hello world; sleep 1; done”

1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147

-d flag runs the container in the background (to daemonize it).
/bin/sh -c “while true; do echo hello world; sleep 1; done” command to run
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147 container ID

Comandos

Introducción

Para ejecutar una aplicación, se necesita correr una imagen. Al correr una imagen se define un contenedor

  CONTAINER = docker run IMAGEN [+ commands] 
Imágenes

docker images #See the images you’ve previously used in the user guide
docker pull image_name #Preload images, eg. docker pull centos
docker search image_name #Search images
docker rmi image_name #Remove image from the host

Contenedores
docker ps #List running containers and show information (short version of container id, container name, etc)
docker log container_name #Shows the standard output of a container.
docker stop container_name #Stop running container
docker start container_name #iniciar contenedor
docker rm container_name #eliminar contenedor

docker ps -l #Return the details of the last container started.
docker ps -a #See stopped containers

docker log -f #act like the tail -f

docker exec -i -t container_name /bin/bash #acceder a una terminal de un docker corriendo

Fuente

Fuente

https://docs.docker.com/engine/tutorials/dockerizing/
https://docs.docker.com/engine/tutorials/dockerimages/

Documentación sobre como crear y subir imágenes a un repositorio: https://docs.docker.com/engine/tutorials/dockerimages/

Ultima actualización 10/10/2016

Typeahead de AngularUI/Bootstrap

Introducción

Dado el siguiente Esquema: Table.Xyz REFERENCED Table2.id, se define el campo Table.Xyz como “typeahead”.

Template
< input type="text" ng-model="fields.xyz_selected" placeholder="Buscar" uib-typeahead="opt as opt.label for opt in typeaheadOptions($viewValue)" typeahead-wait-ms="300" class="form-control">
< span ng-show="selectTypeahead()" class="glyphicon glyphicon-ok">< /span>
Variables del $scope
$scope.fields = {
  xyz, //id
  xyz_, //Objeto
  xyz_selected, //Si se inicializa de la base de datos, sera un string, caso contrario sera todo el objeto
  xyz_search //Busqueda relizada, este field es necesario para determinar si fue inicializado o no de la base de datos
}
Método $scope.typeaheadOptions
 //Definir opciones para el buscador
  $scope.typeaheadOptions = function(search){
    if(search.length < 4) return "";
    
    return DataDefinition.rowsExtLabel({entity:$scope.component.entity, search:{simple:search}}).then(
      function(response){ return response.rows; },
      function(error){ return $scope.processError(error); }
    );
  };
Método $scope.selectTypeahead
  //Seleccionar typeahead
  $scope.selectTypeahead = function(){
    if(($scope.fields["xyz_selected"]) && (typeof $scope.fields["xyz_selected"] === "object")){
      $scope.fields["xyz"] = $scope.fields["xyz_selected"]["id"];
      return true;
    }

    //si esta definido el "xyz" y no esta definido "xyz_search" signfica que el dato fue inicializado directamente de la base de datos
    else if(($scope.fields["xyz"]) && (!$scope.fields["xyz_search"])){
      return true;
    }

    $scope.fields["xyz"] = null;
    return false; 
  };