Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 29-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
teoría de un TPV

Voy a intentar tratar la teoría de como funciona un TPV, en este caso sólo voy a dar conceptos y algún trozo de código, pero no voy a poner el programa ni todo el código, ya que me llevaría mucho tiempo, como siempre lo que doy son ideas y explicaciones de por que hago las cosas de una determinada manera, soys libres como siempre de corregirme, contradecirme, añadir, etc.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #2  
Antiguo 29-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
como el compañero manuel fontanot me hizo una pregunta que va relacionado con lo que voy a explicar empiezo por aquí, su pregunta fue

Cita:
Empezado por manuel fontanot
Estimado Jose Luis, vi el secuencial de tu respuesta en referencia al procedimiento para la pantalla tactil (no entendoi nada) pero loq ue yo necesito es que acabo de comprar una PC de pantalla tactil con la finalidad de usarla en mi restaurante en la parte de la entrada para que mis clientes puedan ver mi menu y las imagenes de mis platillos, asi como los especiales etc, el protector de pantalla lo usare con imagenes de mi negocio y algunos platillos, eso no creo tener problema, pero no se que es lo que necesito para esto, me gustaria que hubiera unos botones de Menu, galeria, especiales, etc, y te suplico me recomiendes software o la manera paso a paso de como le hago, de antemano muchas gracias y feliz 2014.
Manuel con respecto a recomendarte un software que lo haga no se que decirte, creo que otros compañeros te pueden ayudar mejor que yo.

Con respecto a la pantalla táctil, hace dos funciones básicas, la de monitor y la de sistema de introducción de datos, estas pantallas llevan normalmente un cable para la entrada de vídeo, uno para los altavoces y un último cable para la comunicación de datos de la pantalla al pc, suele ser un cable USB, realmente funciona como si hiciéramos todo por ratón, pero usando normalmente nuestro dedo, al hacer un programa para pantalla táctil debemos tener en cuenta las siguientes pautas:

1) Todos los botones deben tener un buen tamaño (ya que tanto el acierto de dar en el sitio por parte del usuario como la sensibilidad del monitor pueden jugar en
nuestra contra)
2) Todos los textos y campos a rellenar deben hacerse grandes ya que debemos preparar el programa para que todas las entradas se hagan por pantalla, ya que puede
darse el caso de que el usuario no use ningún otro método de introducción de datos
3) este punto deriva del anterior, debemos usar componentes que nos permitan introducir los diferentes campos, algunos ejemplos de esto lo podeis ver en mi anterior
hilo http://www.clubdelphi.com/foros/showthread.php?t=83837, debo enumerar alguno de estos y su funcionalidad:
a) teclado en pantalla (nos permitirá la entradas de textos)
c) El TCalendar de la pestaña samples para las fechas (usar este y no el montCalendar, ya que este es redimensionable y funciona bien)
c) algún componente para entrada de integer, floats, date, time, etc. Comercial conozco el TAdvSmoothSpinner y luego algunos que he hecho yo, algunos van mejor
que otros, pero se puede hacer con un poco de código y componentes más o menos normales, os pongo un ejemplo

Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  label1.Caption:=IntToStr(StrToInt(Label1.Caption)+1);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  label1.Caption:=IntToStr(StrToInt(Label1.Caption)-1);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Label1.Font.Size:=36;
  Label1.Font.Style:=[fsBold];
  Label1.Caption:='0';
  Button1.Font.Size:=36;
  Button2.Font.Size:=36;
  Button1.Font.Style:=[fsBold];
  Button2.Font.Style:=[fsBold];
  Button1.Caption:='+';
  Button2.Caption:='-';
end;

end.


y una imagen


como este se pueden hacer varios, para nuestro uso, claro esta si tenemos componentes, que lo hagan nos ahorramos mucho código
Siguiendo con el punto 3, el tamaño de los campos de entrada debe ser lo suficiente ancho como para que podamos pulsar en el y nos salga un editor de entradas
(uso este método ya que en un sólo modulo y con una variable global respondemos a todos los campo, ya lo daré más adelante.

Esta respuesta es para el compañero manuel fontanot, pero como se va a dar en este tema lo único que hago es anticiparla.

Manuel creo que tu pregunta viene dada por esta imagén que publique en el tema "Necesito vuestra opinión sobre mi TPV"



Esta imagen es del TPV que tengo a medio montar, el aspecto definitivo, no es este pero si es muy parecido, les comento que el componente con fondo negro y texto desplazable hacia arriba se trata de un componente freeware al que le he hecho unas modificaciones para mi uso (poder cambiar el color y tamaño de algunas frases y añadir de manera simplificada una linea), no lo he publicado ya que no he obtenido el permiso del autor original, lo único que hago es definir el textos con mi editor y seleccionar la velocidad de desplazamiento y listo.

En cuanto a mostrar los platos, lo hago a través de una base de datos independiente a la del programa, en una tabla están estas imágenes y el texto, se eligen de manera aleatoria, en la tabla configuración de la base de datos del programa, establezco el intervalo en milisegundos y los componentes usados son un timer, un ibquerry un Tdataset y claro esta los componentes de conexión de la base de datos y el panel que pone "Saltar a otra imagen", que lo que hace es poner el timer a 0 y saltar a una imagen aleatoria mente.

Pro que uso una base de datos independiente de la del programa, fácil, por el tamaño que puede coger esta, ya que puede contener imágenes de gran tamaño (no lo aconsejo), pudiendo saturar el programa y a la hora de hacer las copias de seguridad, se nos pueden hacer bastante grandes y tediosas. Ya se tratará el por que guardo las imágenes en tablas y no en ficheros independientes.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #3  
Antiguo 29-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Necesidades de un TPV: en este caso voy a tratar sobre un TPV, bastante especifico para una cafetería, piscolabis, bar, etc.
En un tpv de estas características puede hacerse con pantallas livianas o pesadas, me refiero con esto a que tenga pocas o muchas opciones, de que va a depender esto, pues de las necesidades del cliente, pongamos ejemplos para entenderlo mejor:

Caso 1 nuestro cliente es un restaurante, donde los camareros tienen un terminal o incluso terminales portátiles, el gerente tiene su propio terminal, la cocina tiene otro y por último la caja tiene el suyo propio, en este caso:
El camarero. solo necesita los productos, y la ubicación de las mesas y si acaso pasar notas a cocina o caja para la cuenta, el resto le sobra.
El gerente necesitará saber la entrada y salida de productos, los pedidos, el balance de como va el día etc.
En cocina necesita saber los pedidos y si existe alguna anotación sobre ese pedido, ejemplo que el cliente sea alérgico a un alimento o condimento
La caja sólo necesita tener control de los tickets y del dinero y cobros, sean por talones, vales, cupones, tarjeta, efectivo, etc.

Caso 2 Tenemos un bar con servicio de plancha y algo de cocina, pero trabajan la mujer y el marido únicamente
En este caso lo más probable es que necesiten una pantalla que les permita hacer todo (o casí) para no tener que perderse en múltiples pantallas.

En el caso 1 necesitamos varias pantallas adecuadas a cada puesto (livianas) en cambio en el segundo caso necesitamos una pantalla genérica con casi todas las opciones (pesada).

Esto no tiene nada que ver con la rapidez y funcionalidad del programa, ya que de ello va a depender de como lo planteemos y lo codifiquemos, según mi humilde opinión después de haber tenido un bar con cocina, la situación en el mismo eran las siguientes

1: El bar tenia varias horas muertas, en las que había muy pocos clientes o no había clientes.
2: El bar tenia sus horas (desayunos, almuerzos y medias tardes) en que entraban varias personas y se animaba algo pero eran periodos de 2 horas a 3 horas como mucho, el trabajo era más intensivo, pero sin agobiar.
3: El bar tenia algún evento cercano y la entrada de clientes era bastante fluida
4: El bar estaba junto a la entrada del estadio de fútbol, la entrada horas antes y después del partido eran brutales, podías tener ochenta o más pedidos a la vez, en estos casos era estresante y necesitaba personal auxiliar

claro según fuese el día y la situación necesitabas mayor o menor rapidez y el software que tenia no era precisamente super veloz, se trataba de un software que no tenia imágenes y con muy pocas opciones, poco atractivo y aunque en principio parecía que sería rápido resulto no ser lo suficiente el software tenía las siguiente opciones.

8 colores para distinguir las familias y artículos
Nombre, familia y precio del artículo
Total de ventas
No tenía password ni de acceso y ni de nada

sencillo y rápido pensé yo, claro los problemas eran los siguientes

Tenia múltiples pantallas de bebidas, con lo que buscar una en un momento determinado se volvía una locura y como lo único que podías era poner un color y el texto y por pantalla podías tener 24 artículos y muchas veces eran casi idénticos, ejemplo (chupito Ron Telde, Vaso Ron Telde, Chupito Ron Abana oro, vaso Ron Abana oro, etc) y eso sólo el ron que podía ser color malva y tenia 8 tipos de ron diferentes y se pedían en los diferentes formatos que estaba puesto, pues los fui creando según se iban pidiendo, salvo algunos que eran más genéricos y los cree de entrada. Esto lo hacía tedioso y lento

A la hora de cobrar te preguntaba el importe entregado por el cliente, sacaba el calculo de la devolución y preguntaba si imprimir ticket, despues de esto si optabas o no por imprimir el ticket, abría el cajón, imprimía el ticket (si habías decidido hacerlo y mantenía la pantalla 5 segundos +/- con el importe de la consumición, el entregado por el cliente y la devolución no permitiendo hacer nada durante este tiempo, lo cual paralizaba bastante.

Principalmente estos factores, junto con no controlar el stock, que al sacar el cierre si le decías imprimir te lanzaba todos los ticket y no tenia opción de un resumen y que no tenia configuración salvo para los datos de la empresa, el no tener control de clientes, etc, demostraron la mala elección del programa, pero no me voy a a quejar. (a toro pasado)

según siempre mi opinión una de las mayores faltas en lo programas de TPV son la de diferencias diversos modos de trabajo y la de tener la opción de familias y productos únicamente Sobre este último time trataré en el siguiente hilo.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #4  
Antiguo 29-12-2013
Avatar de Ñuño Martínez
Ñuño Martínez Ñuño Martínez is offline
Moderador
 
Registrado: jul 2006
Ubicación: Ciudad Catedral, Españistán
Posts: 6.000
Poder: 25
Ñuño Martínez Tiene un aura espectacularÑuño Martínez Tiene un aura espectacular
Una magnífica iniciativa, José Luís. Ahora tengo un poco de prisa, pero quizá más adelante aporte yo también algo.
__________________
Proyectos actuales --> Allegro 5 Pascal ¡y Delphi!|MinGRo Game Engine
Responder Con Cita
  #5  
Antiguo 29-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Tratando la pantalla principal del TPV trataremos el combate entre

(1)Familias y productos contra (2)Familias. Subfamilias y productos


Ventajas e inconvenientes de cada sistema:

Ventajas de 1, menos pulsaciones, Desventajas caos de productos y probablemente múltiples pantallas de una familia
Ventajas de 2, mas control y mejor visualización de los datos, Desventajas, que como mínimo habrá que pulsar una vez más

veamos como podemos organizar los siguientes grupos de artículos ( lo que encontréis entre paracentesis será el número de artículos relacionados a este grupo que puede contener ejemplo cerveza (botellin marca 1, botellin marca 2, botella marca 1, botella marca 2, botella marca 1 sin alcohol, botella marca 2 sin alcohol, media caña, caña, caña grande))

Menús (4), Primeros(20), segundos(20), aguas(6), refrescos(4), zumos(3), batidos(6), helados(10), hamburguesas(4), perritos(3), entrantes(20), vinos(8), rones(6), cervezas(10), coñacs(3), whisky(4), Ginebra(3), Cremas(2), Licores(4), Tequila(2) bocadillos(10), Cafés(10), sandwiches(4), patatas de paquete(3), chicles(12), chocolates(5), flanes(2), fruta(1), bollería(6), etc

Priero definiremos que en un pantalla nos puede mostrar unos 16 artículos a la vez

Hagamos un árbol de familias para el sistema 1 y su contenido

Comidas con (Menús (4), Primeros(20), segundos(20), entrantes(20), helados(10), flanes(2), fruta(1))=77 artículos/16= 5 pantallas
Bebidas alcohólicas con (vinos(8), rones(6), cervezas(10), coñacs(3), whisky(4), Ginebra(3), Cremas(2), Licores(4), Tequila(2))=42 artículos/16= 3 pantallas
Otras Bebidas con ( aguas(6), refrescos(4), zumos(3), batidos(6),Cafés(10))=29 artículos/16= 2 pantallas
Golosinas con ( patatas de paquete(3), chicles(12), chocolates(5))=20/16 = 2 pantallas
Bollería y bocadillos (bocadillos(10), , sándwiches(4), , bollería(6))=20/16= 2 pantallas
Comida rápida (hamburguesas(4), perritos(3))=7/16= 1 pantalla

Hay que tomar esto como lo que es un ejemplo ya se que podríamos dividirlo más para que quedara más disuelto, e incluso poner parte de los artículos de bebidas alcohólicas en otras bebidas (algunos licores y cervezas sin ) y viceversa (café irlandés), pero creo como ejemplo queda claro y eso que faltan muchísimos artículos, como pizzas, burritos, bebidas, postres etc.

Hagamos el árbol de familias del sistema 2, recordad que tiene subfamilia y dentro de esta los artículos

Comidas con (Menús (4)/16=1 pantalla
Primeros(20)/16=2 pantallas
segundos(20)/16=2 pantallas
entrantes(20)/16=2 pantallas
helados(10)/16=1 pantalla
flanes(2)/16=1 pantalla
fruta(1)/16=1 pantalla )
)

Bebidas con (vinos(8)=1 pantalla
rones(6)=1 pantalla
cervezas(10)=1 pantalla
coñacs(3)=1 pantalla
whisky(4)=1 pantalla
Ginebra(3)=1 pantalla
Cremas(2)=1 pantalla
Licores(4)=1 pantalla
Tequila(2)=1 pantalla
aguas(6)=1 pantalla
refrescos(4)=1 pantalla
zumos(3)=1 pantalla
batidos(6)=1 pantalla
Cafés(10)=1 pantalla)

Golosinas con (patatas de paquete(3)=1 pantalla
chicles(12)=1 pantalla
chocolates(5)=1 pantalla)

Bollería y bocadillos con (bocadillos(10)=1 pantalla
sándwiches(4)=1 pantalla
bollería(6)=1 pantalla)

Comida rápida con (hamburguesas(4)=1 pantalla
perritos(3)=1 pantalla)

Como podemos ver podemos ver los artículos casi siempre en una única pantalla, salvo excepciones, por lo que será visualmente más rápido, pongo una imagen para que quede más claro

Primero veamos una cogida al azar de internet del sistema 1 (espero no vulnerar derechos algunos, la pongo a modo de ejemplo simplemente)



y ahora del sistema que yo propongo el 2




Realmente no se si existen en usos ya este sistema en otros TPV, de momento yo no lo he visto.

Debo de de decir que ambos sistemas consiguen el mismo fin, pero personalmente creo que es mucho más rápido el 2 que el primero.

Por hoy no voy a seguir pero hay aun un puñado de temas que creo deberían tocarse y procurare hacerlo en los próximos días.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #6  
Antiguo 29-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Cita:
Empezado por Ñuño Martínez Ver Mensaje
Una magnífica iniciativa, José Luís. Ahora tengo un poco de prisa, pero quizá más adelante aporte yo también algo.
Perfecto entre más ideas y opiniones mejor.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #7  
Antiguo 29-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
intento subir un vídeo pequeño hecho de mi programa como ejemplo espero se pueda ver

__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #8  
Antiguo 29-12-2013
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.021
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Responder Con Cita
  #9  
Antiguo 30-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Bueno espero que lo que he dado hasta el momento, a) sea correcto y b) este claro.

Sigo con los modos de trabajo, siempre según mi experiencia, debemos tener en cuenta que los momentos de trabajo varían mucho de unos a otros, según los casos, debemos tener en cuenta las diferentes situaciones.

Empresas o particulares, que necesiten una factura con sus datos, que pueden consumir a lo largo del mes y pagar con vales o a finales o principios del siguiente mes.

Que nuestros camareros tengan comisión o queramos tener gestión de sus ventas o mesas simplemente.

Estas dos variables, son importantes ya que varían mucho la velocidad de la venta desde nuestro punto.

Estaréis de acuerdo con migo, que más de un 90% de los clientes de bares, cafeterías y restaurantes, son anónimos, salvo claras excepciones (centros de restauración de empresas o similares por ejemplo).

en cambio usar un control de camareros, puede ser un requisito indispensable, sabiendo esto debemos hacer nuestro programa teniendo en cuenta las necesidades presentes y haciendo un poco el adivino por que también algunas futuras.

Sabiendo esto, debemos saber que cuantos más parámetros, debemos meter, más lento irán los procesos, por ejemplo que cada vez que cambia de camarero, tenga que meter su clave, puede producir una perdida de tiempo de unos 5 minutos por hora e incluso más, en momentos de máxima aculturación eso es un gran error.

He visto programas que incluso cuando se hace un nuevo ticket pide el camarero y es muy probable que sea el mismo, entonces por qué pedirlo nuevamente?

Bueno después de soltaros toda la parrafada, os digo las situaciones como las he solventado.

1) Tiempos muertos o clientes con registro completo (el más lento de todos), podemos crear el ticket nuevo, seleccionando la mesa, taburete, etc del mapa*, elegimos el cliente y el camarero (pedirá clave o no según nuestra configuración), procedemos a introducir los artículos y listo**.

2) Tenemos ajetreo, en nuestra cafetería y los clientes son los típicos, que nos pueden pedir el ticket pero que no les hace falta que estén a su nombre, puede que nos nos interese saber su ubicación exacta, así que podemos ir un poco más rápido.

3) Tenemos el local lleno con un evento y todo son consumiciones, rápidas y directas, en este caso, lo mejor es una venta directa, según configuremos nuestra aplicación, será con control de camareros o no.

yo lo que me he planteado es lo siguiente, puse un símbolo más (+) a lo que retrasaba y un menos (-) a lo que se volvería más rápido y me plantee más o menos el siguiente esquema.

Seleccionar del mapa + no hacerlo -
Elegir cliente + no hacerlo -
Elegir comercial + no hacerlo -
Comercial con clave + no hacerlo -
Cobro con factura +
Cobro con ticket + Cobro sin ticket -
Cobro directo *** -


si volvemos a los casos 1, 2 y 3 serían más o menos de la siguiente manera si cada + le sumamos 1 y cada - se lo restamos, cuanto menor sea el valor más rápido será el sistema

Caso.....Mapa.....Cliente....Comercial....Clave....Factura....Ticket......Cobro Directo.....Puntos de velocidad
...1.........+...........+.............+...........OP.+.....OP.+........+/-................OP.-..............de 1 a 6
...2.........OP.+......OP.+.........+...........OP.+.....OP.+........+/-................OP.-..............de -1 a 6
...3.........-...........-..............OP+.......OP.+.....OP.+........+/-................OP.-..............de -4 a 4

Espero este esquema os resulte de utilidad como me lo fue a mi.

En este esquema faltan otros apartados que pueden darse más adelante, por lo que no los menciono aún pero que vosotros mismo podéis ir hilando.

También es importante a la hora de cobrar, nuestro programa, puede tener un sistema de control de entradas y salidas de los diferentes formatos de la moneda, que nos resultaría perfecto para tener arqueos controlados de la caja, pero en ciertos casos el cliente preferiré pasar de este con tal de atender muy rápidamente al cliente, así que es otro punto a tener en cuenta (lo trataremos más adelante detalladamente)


* el mapa es el siguiente tema que trataremos
** listo por que podemos recuperar nuestro ticket en cualquier momento (ya lo trataré)
*** El botón de cobro directo, no tiene en cuenta ni la devolución ni el capital entregado en el balance y el ticket, por lo que debemos usarlo en los casos de que el cliente no quiera el ticket.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #10  
Antiguo 30-12-2013
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
El Mapa

Cuando decidimos montar nuestro programa de TPV, debemos tomar decisiones importantes, que harán a nuestro programa + comercial, pero que también puede hacerlo + o - productivo a la hora de trabajar.

La decisión de usar un mapa de situación, dependerá entre otras muchas cosas de como nos hemos planteado hacer el programa, así como de exigencias del cliente, pero debemos saber que hacer un mapa de situación, aunque parezca complejo no lo es tanto, el mio esta hecho con mis propios Speedbutons para este tipo y además permite múltiples planos*.

Dentro de cada plano disponemos de los diferentes elementos (taburetes, mesas, sillas de terraza, etc) que deben aparecer gráficamente en nuestro plano de situación, yo lo que he hecho es crear una tabla con la situación(los diferentes planos) y otra con la ubicación, los elementos especificando donde se encuentra el elemento (su situación), en esta última tiene registros como si esta ocupada, número de ocupantes, reservada, unida y número de unión, camarero, etc.

Otra cosa buena que tiene un plano, es saber de manera visual las mesas que tenemos ocupadas y otros muchos detalles, el elegir visualmente que elemento vamos a a ocupar, etc.

Existen programas de tpv, con planos super detallados y visualmente muy bonitos, otros simplemente con botones que representan los diferentes elemento, etc. Yo considero que es una buena manera de poder trabajar de una manera completamente visual. Pero esto es algo muy subjetivo y dependerá de cada uno

Existen opciones muy variadas y componentes diversos, por ejemplo tenéis unos del maestro Neftalí que están muy bien, de hecho en un principio los use, pero luego los descarte, en mi aplicación por motivos prácticos al usar mis Speedbuttons, pero visualmente quedaban mucho mejor con su componente que con un TImagen como he usado yo.

*El cliente puede tener varios salones, terrazas, etc y cada uno es un plano de situación diferente.

Bueno si dios quiere mañana seguiré, con la grilla, el ticket, etc.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #11  
Antiguo 01-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Bueno primero que nada espero hayáis tenido una gran fiesta de Fin de año y que este en el que entramos (2014) sea un año de parabienes para todos.

Me voy a meter con el ticket

Primero esta parte la voy a dividir en 3 partes, ya que es una de las partes más importantes y representativas de nuestros programas, la primera va a ser la definición del mismo, la segunda debe ser el contenido y la tercera métodos de hacer el ticket.

Vamos con la primera parte.

El ticket es el comprobante que por regla general puede llevarse nuestro cliente, de hecho en muchos sitios y empresas, se admite el ticket como factura siempre y cuando tenga los datos necesarios, pero tener este no exime de tener/poder entregar facturas.

Debemos crear unas tablas maestro detalle para nuestros tickets, en estas tablas debemos registrar los diversos datos del ticket y en el detalle los movimientos del propio ticket, de hecho yo uso tres tablas, el maestro, el detalle y la forma de pago.

Yo personalmente prefiero en el maestro, poner campos completos, incluidos el total, se que esto incrementa nuestra tabla y por consiguiente la Base de Datos, pero con las capacidades de los equipos de hoy en día y la velocidad de los mismos, creo que es una gota en un océano, se que podría hacerlo por SQL, pero me es más cómodo y creo que más práctico de esta manera.

Aparte de estas tres tablas en configuración uso un campo para tener el último número del ticket, de esta manera no estoy mirando el último registro de la tabla para saber por que número voy.

Al igual que con todo debemos de plantearnos su estructura, antes de ponerse hacerlo, de hecho es bueno coger tickets de la compras, consumiciones, etc y comparar, ver que nos gustaría añadir, etc.

El uso de una imagen en los tickets, es muy importante pero debemos saber, que no es posible con todas las impresoras y que de hecho hay impresoras que lo permiten pero al estar nuestro hadware (la impresora de tickets) o el del cliente, desfasado, puede que tengamos que usarlo como una impresora de texto únicamente.

Elijamos el método que decidamos, debemos tener en cuenta que hay una serie de opciones que deben ser elegibles por nuestro clientes, por lo tanto deben estar en alguna parte, una tabla (configuración u otra), un fichero ini, un XLS, etc, como deben ser apertura del cajón, mostrar imagen en el ticket y la imagen, usar dos colores, etc.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #12  
Antiguo 01-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
El ticket y su contenido

Esto que parece un chorrada, es algo que se pasa por alto muchas veces, coger bolígrafos de publicidad, tickets, etc y leerlos con atención, pongamos el siguiente ejemplo

Químicas XXX, S.L.
Teléfono 999-999-999

A que se dedica esta empresa, puede ser un fabricante de productos de limpieza, de piscina, farmacéutico, etc o simplemente un distribuidor, no no los etc indicando, por eso debemos especificar bien y muy detalladamente algunos de nuestros datos ya que estos nos pueden representar y ser nuestra publicidad, también en el ticket.

Nuestra ticket debe estar dividido en varias partes y este es más o menos el estándar:

LA CABECERA (1)

Logo (opcional)
Nombre
A que nos dedicamos
Calle
Provincia
Código postal y población
Teléfono y fax
CIF o NIF
Email
Web

DATOS DEL TICKET (1)

Número del ticket
Fecha y hora
Terminal o persona que le atendió
Elemento (mesa, taburete, etc)

DATOS DEL DETALLE

Unidades, descripción, precio ud., descuento y subtotal (2)

TOTAL

Total
impuestos
entregado (el importe únicamente)
Devuelto (el importe únicamente)

CIERRE

Una frase de cierre como "gracias por su compra" (3)


Claro esta, debemos tener en cuenta el ancho y la capacidad de caracteres de nuestro ticket yo en el mio uso 42 caracteres por linea, por lo que debemos limitar el ancho y es aveces preferible que no aparezca un dato como el email o la web si no va a poder leerse entero , esto deberemos decidir si hay campos del ticket que su lengt es mayor que el ancho disponible no salgan, así de simple.


(1) Si alguno de los datos esta en blanco, simplemente no pasa por el ticket, evitando de esta manera un linea en blanco, salvo que en esa misma linea exista otro dato
claro esta

(2) en una linea mejor que en 2

(3) Esta frase debe poder ser preseleccionada, incluso en mi proceso de desarrollo previo pensé en poner dos frases una que pusiese según la hora del día más o menos la
siguiente frase

que pase (un buen día) o (una buena tarde) o (buena noche)

Y otra para ofertas tipo

café + sándwich 2'80 €

(opcional) pues eso que el cliente pueda elegir si quiere que le aparezca en el ticket
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #13  
Antiguo 01-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Por último queda el método a usar, existen varios que conozca, a través de un report, tipo memo y por código de impresora, yo he usado los dos últimos, pero no descarto otros métodos más, hablo de los que he leído y de aquí en adelante de los que yo uso, para ello os pongo el código de las funciones que uso que suelo usar para ambos casos ya que más adelante aparecerá y sin esta parte será más compliacado entenderlo

Código Delphi [-]
unit uimpticket;

interface

uses printers, WinSpool,  Windows, Sysutils, Dialogs, StrUtils;

function WriteRawDataToPrinter(PrinterName: String; Str: String): Boolean;

Function GetImpresora(Impre:String):Integer;

function MyTextReplace(Texto:String):String;

function CenterString(aStr: String; Len: Integer): String;

implementation

function WriteRawDataToPrinter(PrinterName: String; Str: String): Boolean;
var
  PrinterHandle: THandle;
  DocInfo: TDocInfo1;
  i: Integer;
  B: Byte;
  Escritos: DWORD;
begin
  Result:= FALSE;
  if OpenPrinter(PChar(PrinterName), PrinterHandle, nil) then
  try
    FillChar(DocInfo,Sizeof(DocInfo),#0);
    with DocInfo do
    begin
      pDocName:= PChar('Printer Test');
      pOutputFile:= nil;
      pDataType:= 'RAW';
    end;
    if StartDocPrinter(PrinterHandle, 1, @DocInfo) <> 0 then
    try
      if StartPagePrinter(PrinterHandle) then
      try
        while Length(Str) > 0 do
        begin
          if Copy(Str, 1, 1) = '\' then
          begin
            if Uppercase(Copy(Str, 2, 1)) = 'X' then
              Str[2]:= '$';
            if not TryStrToInt(Copy(Str, 2, 3),i) then
              Exit;
            B:= Byte(i);
            Delete(Str, 1, 3);
          end else B:= Byte(Str[1]);
          Delete(Str,1,1);
          WritePrinter(PrinterHandle, @B, 1, Escritos);
        end;
        Result:= TRUE;
      finally
        EndPagePrinter(PrinterHandle);
      end;
    finally
      EndDocPrinter(PrinterHandle);
    end;
  finally
    ClosePrinter(PrinterHandle);
  end;
end;

Function GetImpresora(Impre:String):Integer;
//------------------------------------------------------------------------------
//**********************************************************[ GetImpresora ]****
// de Marcos Zorilla bajada de http://www.clubdelphi.com/foros/showthread.php?t=68519
//------------------------------------------------------------------------------
Var
nCont:Integer;
lSearch:Boolean;
cNewLIne:String;
begin
  lSearch:=False;
  cNewLine:=Chr(10)+Chr(13);
  For nCont:=0 to Printer.Printers.Count - 1 do   //buscamos la impresora en la lista del sistema
  begin
      if Pos(impre, Printer.Printers[nCont]) <> 0 then
      begin
      lSearch:=True;
      Result:=nCont;
      Break;
      end;
  end;
  if lSearch = False then
  begin
  ShowMessage('Impresora no encontrada.'+impre+cNewLine+'Se utilizará la predeterminda.');
  Result:=-1
  end;
end;

function MyTextReplace(Texto:String):String;
begin
    if Texto<>'' then begin
    Texto:= AnsiReplaceStr(Texto,'Ñ', #165);
    Texto:= AnsiReplaceStr(Texto,'ñ', #164);
    Texto:= AnsiReplaceStr(Texto,'á', #160);
    Texto:= AnsiReplaceStr(Texto,'é', #101);//#130);
    Texto:= AnsiReplaceStr(Texto,'í', #161);
    Texto:= AnsiReplaceStr(Texto,'ó', #162);
    Texto:= AnsiReplaceStr(Texto,'ú', #163);
    Texto:= AnsiReplaceStr(Texto,'Á', #65);
    Texto:= AnsiReplaceStr(Texto,'É', #144);
    Texto:= AnsiReplaceStr(Texto,'Í', #73);
    Texto:= AnsiReplaceStr(Texto,'Ó', #79);
    Texto:= AnsiReplaceStr(Texto,'Ú', #85);
    Texto:= AnsiReplaceStr(Texto,'Ü', #85);
    Texto:= AnsiReplaceStr(Texto,'Ü', #129);
    Result:=Texto;
  end;
end;

function CenterString(aStr: String; Len: Integer): String;
var
  posStr : integer;
begin
  if Length(aStr)>Len then
    Result := Copy(aStr, 1, Len)
  else
  begin
    posStr := (len - Length(aStr)) div 2;
    Result := Format('%*s', [len, aStr + Format('%-*s', [posStr, ''])]);
  end;
end;

end.

el WriteRawDataToPrinte es del maestro SEONE

el GetImpresora es del maestro Marcos Zorrilla

el MyTextReplace es bajado de Planetadelphi.com

Y CenterString no estoy seguro si es mía o la baje de algún lado

Yo personalmente uso ambos sistemas y dejo que el cliente decida si quiere imprimir por código o ticket simple, esto lo hace en configuración mediante el campo método de impresión con dos valores posibles 1 o 2.

Pongo una imagen de mi visor de tickets



en esta me queda varias cosas que corregir, detalles como nº de artículos, ya que hace referencia al número de lineas y no de artículos, etc, pero os vale de ejemplo.

El método por código es un poco más trabajoso y debemos tener en cuenta que en cualquier momento el cliente puede cambiar de impresora, resultando que los códigos ya no son válidos, el método de usar un memo, es 100% fiable ya que imprimimos nada más que un texto plano y podemos salvar que nuestra impresora admita acentos o no ya que los sustituiremos gracias a la función MyTextReplace, permitiendo imprimir en cualquier impresora que admita los códigos ASCII, por la tanto en todas, salvo especificas para otros países que no tengan la posibilidad de cambiar el idioma /(ejemplo caracteres, chino, cirilicos o árabes)

Pongo el código de unos de mis primeros tickets por código y memo con selección de impresora normal o no (ya digo mi antiguo método

Código Delphi [-]
//------------------------------------------------------------------------------
//**************************************************************[ Imprimir ]****
//------------------------------------------------------------------------------
var
  r: TRect;
  i,p: Integer;
begin
  if DM.DsConfi.DataSet.FieldByName('USARTICKETNORMAL').Value='S' then
  begin  //Si vamos a usar impresión por código
     if not DsTicket.DataSet.IsEmpty then
     begin
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXTINICIAR').Value);
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('RETROCEDER').Value);
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('RETROCEDER').Value);
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXGRANDE').Value);
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,CenterString(DM.DsConf  i.DataSet.FieldByName('EMPRESA').Value,35));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXCOMPRIMIDO').Value);
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(MyTextReplace  ('Calle:'+DM.DsConfi.DataSet.FieldByName('DIRECCION').Value),42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(MyTextReplace  ('Población:'+DM.DsConfi.DataSet.FieldByName('POBLACION').Value),42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(MyTextReplace  ('C.P.:'+DM.DsConfi.DataSet.FieldByName('CODIGOPOSTAL').Value+'  Provincia:'+DM.DsConfi.DataSet.FieldByName('PROVINCIA').Value),42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(MyTextReplace  ('Tf.:'+DM.DsConfi.DataSet.FieldByName('TELEFONO').Value+'   CIF:'+DM.DsConfi.DataSet.FieldByName('CIF').Value),42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(MyTextReplace  ('Email:'+DM.DsConfi.DataSet.FieldByName('EMAIL').Value),42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(MyTextReplace  ('Web:'+DM.DsConfi.DataSet.FieldByName('WEB').Value),42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(' ',42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,Espacios(MyTextReplace  ('Número: ')+DsTicket.DataSet.FieldByName('NUMERO').AsString+
                                                                                             '       '+DsTicket.DataSet.FieldByName('FECHA').AsString+
                                                                                             '    '+DsTicket.DataSet.FieldByName('HORA').AsString,42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(' ',42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,Espacios('Cant.',6,0)+  espacios('Producto',20,0)+espacios('Dto.',6,0)+espacios('Sub-total',10,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('--------------------------------------------',42,0));
       //----------------------------------------------------------------------------
       with DsDetalle.DataSet do
       begin
          First;
          while not Eof do
          begin
            WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(DsDetalle.Dat  aSet.FieldByName('UNIDADES').AsString,5,1)+' '+
                            espacios(Copy(MyTextReplace(DsDetalle.DataSet.FieldByName('DESCRIPCION').AsString),1,19),19,0)+' '+
                            espacios(FormatFloat('#,##0.00',DsDetalle.DataSet.FieldByName('DESCUENTO').Value),5,1)+' '+
                            espacios(FormatFloat('#,##0.00',DsDetalle.DataSet.FieldByName('SUBTOTAL').value),10,1));
            Next;
          end;
        end;
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('--------------------------------------------',42,0));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXTCOMPRIMIDANEGRITA').Value);
       if not DsTicket.DataSet.FieldByName('TOTAL').IsNull then WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('Total: ',32,1)+Espacios(FormatFloat('#,##0.00',DsTicket.DataSet.FieldByName('TOTAL').Value),10,1))
                                                           else WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('Total: ',32,1)+Espacios(FormatFloat('#,##0.00',0),10,1));
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXCOMPRIMIDO').Value);
       if not DsTicket.DataSet.FieldByName('ENTREGADO').IsNull then WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('Entregado: ',32,1)+Espacios(FormatFloat('#,##0.00',DsTicket.DataSet.FieldByName('ENTREGADO').Value),10,1))
                                                               else WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('Entregado: ',32,1)+Espacios(FormatFloat('#,##0.00',0),10,1));
       if DsTicket.DataSet.FieldByName('SINPAGAR').AsString='N' then
       begin
          if not DsTicket.DataSet.FieldByName('DEVUELTO').IsNull then WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('Devuelto: ',32,1)+Espacios(FormatFloat('#,##0.00',DsTicket.DataSet.FieldByName('DEVUELTO').Value),10,1))
                                                                 else WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios('Devuelto: ',32,1)+Espacios(FormatFloat('#,##0.00',0),10,1));
       end else
       begin
         if not DsTicket.DataSet.FieldByName('DEVUELTO').IsNull then WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,Espacios('SinP.[x]',10,0)+espacios('Devuelto: ',22,1)+Espacios(FormatFloat('#,##0.00',DsTicket.DataSet.FieldByName('DEVUELTO').Value),10,1))
                                                                else WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,Espacios('SinP.[x]',10,0)+espacios('Devuelto: ',22,1)+Espacios(FormatFloat('#,##0.00',0),10,1));
       end;
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(' ',44,0));
       //CAMBIAR POR DATOS EN CONFIGURACION------------------------------------------
       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,CenterString(MyTextRep  lace(DM.DsConfi.DataSet.FieldByName('FRASECIERRE').Value),44));
       //----------------------------------------------------------------------------
//       WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,espacios(' ',44,0));
       for i := 1 to 7 do  WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXTAVANZAR').Value);
     end;
  end else
  begin
    with Printer do
    begin
        PrinterIndex:=GetImpresora(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value);
        r := Rect(100,100,(Pagewidth - 100),(PageHeight - 100));
        BeginDoc;
        Canvas.Brush.Style := bsClear;
        for i := 0 to Memo1.Lines.Count do
           Canvas.TextOut(100,180 + (i * Canvas.TextHeight(Memo1.Lines.Strings[i])),
        Memo1.Lines.Strings[i]);
        Canvas.Brush.Color := clBlack;
        Canvas.FrameRect(r);
        EndDoc;
    end;
  end;
  //Cortar papel
  WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXTCORTE').Value);
  //aBrirCajon
  WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('CODIGOAPERTURACAJA').Value);
  //Inicializa la impresora
  WriteRawDataToPrinter(DM.DsConfi.DataSet.FieldByName('IMPRESORATICKET').Value,DM.DsConfi.DataSet.Fie  ldByName('TEXTINICIAR').Value);
end;

Como veis lo que hago es diversas llamadas a la tabla de configuración donde tengo definidos los campos con su código tipo TEXTCORTE, TEXTINICIAR, etc.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #14  
Antiguo 01-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
No se si os valdrá pero qui pongo alguno de los códigos usados en mis viejas EPDON TM 210 de las que no tengo drivers para mi windows 7, os advierto que puedo poner el texto a rojo, pero luego debo reiniciar mi impresora para que vuelva a salir a negro, no se por que es pero aquí os pongo casí todos, pero me reservo unos pocos para mi

Cita:

Iniciar la impresora \027\064 o \x1B
Cambiar a rojo \027\114\049
Cambiar a negro \027\114\048
Saltar x lineas \027\074\N (donde n es el número de lineas)
Algunos de los tamaños y tipos \027\033\X (donde x es alguno de los siguientes)
0 retorna a normal
1 Comprimida
8 Negrita
16 Grande
128 subrayada
Existen combinaciones como 9, 41 o 153 que combinan los diferentes formatos, pero así tenéis algo de trabajo vaguetes
Avanzar papel \027\100\N ( N= 0 a 255)
Cortar el papel \x1B@\x0A\x0D\x1Bi\x0A\x0D
Retroceder micras la impresora \027\075\n (n= 0 a 48)
Espero sea de utilidad, pero estos códigos podéis encontrarlos en los manuales de las impresoras.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #15  
Antiguo 01-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Bueno ya no sigo por hoy con el monologo y espero no estar haciendo el ridículo, se que lo que he puesto debería estar bien ya que lo he probado, pero no me gustaría estar dando mal la información por que yo este equivocado, de hecho os hablo por que he estado al otro lado de la barra y se que era lo que me hacia falta, pero eso no quiere decir que mi verdad pueda ser la única.

Sigo diciendo que no soy la persona más adecuada, para enseñar, ya que me queda mucho por aprender, pero estoy seguro y muy seguro de que muchas de las cosas de las que hablo están en la red o debieran estar, lo único que hago es unificarlas y darles un punto de vista determinado, claro esta el mio.

Me considero bueno analizando problemas en los programas y a veces logro dar soluciones buenas, pero como me enseño mi amigo Jesús en programación normalmente a problema puede abordarse de varias maneras, que sean más o menos efectivas ya depende del programador, su experiencia y lo que quiera arriesgar.

Como ya dije no pienso poner esta vez el programa ni módulos completos, sólo es la teoría de como debe funcionar un TPV.

Que tengáis buen día.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #16  
Antiguo 01-01-2014
Avatar de fjcg02
[fjcg02] fjcg02 is offline
Miembro Premium
 
Registrado: dic 2003
Ubicación: Zamudio
Posts: 1.408
Poder: 22
fjcg02 Va camino a la fama
Gracias por la clase, magistral y cercana, como siempre.

Un saludo
__________________
Cuando los grillos cantan, es que es de noche - viejo proverbio chino -
Responder Con Cita
  #17  
Antiguo 02-01-2014
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.233
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Fantástica explicación.



Gracias.
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #18  
Antiguo 03-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Vamos con las rejillas y el stock



se pueden hacer con bastante trabajo mediante abundante código, las he visto incluso con un dbgrid normal y uno vertical, incluso de manera más común en un Stringrid, pero según mi modesta opinión lo mejor es usar un componente para ello, de hecho en el programa que estoy realizando es el único componente al que no le he metido mano y no es mio, lo llevo recomendando mucho tiempo es gratuito y lo podeis descargar junto con otros componente interesantes desde http://componentes.clubdelphi.com/, en este conjunto de componentes cedidos por algunos maestros del clubdelphi, así como un par de ellos míos y de otros compañeros, lo bueno de esta idea era que podi participar cualquiera independiente de su nivel y conocimientos, mientras el componente fuese suyo y lo cediera libremente, el componente si no recuerdo mal es CCDdBimagenGrid, la verdad que esta muy completo, sólo echo en falta el hint por casilla y que me da algunos problemas si los controles avanzar y retroceder páginas los inserto dentro de la rejilla, por ese motivo he optado por ponerlos en un panel aparte.

Lo bueno es que visualmente es atractivo, no he querido meterle mano y mirarlo con detenimiento, pero si lo hago le pediré permiso al compañero Luis Bataller, autor del componente, he intentaría añadirles propiedades como un auto hint con el teto del campo asociado y que la imagen pueda ser proporcional, para que no se deforme, el resto es muy muy bueno, seguro que hay componentes de pago que lograrán lo mismo, pero tampoco los he buscado.

Después de todo este monologo, paso a detallar lo que yo considero debemos tener en nuestra rejilla, es muy simple, principalmente su imagen descriptiva, recordar que vale más una imagen que mil palabras y mas en entornos de este tipo ya que nuestro cerebro asocia rápidamente la imagen a lo que deseamos mientras que el proceso de leer lleva muchísimo más tiempo, es recomendable que aparezca el texto descriptivo, he incluso su precio, pero con los dos primeros debemos darnos por contento.

Si os fijáis en la banda negra que pone artículos, es un panel que a su derecha tiene otro panel, donde pongo el artículo seleccionado, al no disponer del un autohint, debajo de esta tengo un panel con los botones para retroceder y avanzar página (flecha arriba y abajo), debajo de la primera flecha puse un estatic tex que relleno con los diferentes precios (*), y debajo de esta la palabra stock y un display donde nos mostrará el stock disponible de este producto, pero hablamos de productos como bocadillos, cafés etc, con esto quiero decir que no podemos poner un sistema de stock cerrado, simplemente regula ra el stock de los productos que nosotros deseamos al crear el artículo, dejando el uso de los otros libres, os pongo un ejemplo más claro.

Nosotros tenemos 10 cajas de cerveza de 250 c.c. a 18 botellas por caja nos da un total de 180 botella s de cerveza, de este artículo podemos hacer en su creación que tengamos el stock cerrado o no, realmente importa poco, la principal diferencia es que nos descuente o no del stock.

También tenemos 50 panes para bocadillos, pero no podemos darle entrada por e stock, salvo que sean ya preparados, ya que un bocadillo puede ser de tortilla, de lomo, etc

Esto no quiera decir que perdemos el control sobre las ventas, sólo lo perdemos sobre el stock, nosotros podemos saber cuantos bocadillos, cafés, cervezas, etc, hemos vendido, mediante una consulta SQL a nuestra tabla de tickets detalle.

Lo correcto para la entrada de productos es tener un form distinto, donde nos permita buscar el artículo, darle la cantidad de entrada, asegurarnos de que entra al mismo precio y si no es así si debemos cambiar el precio de nuestros productos.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #19  
Antiguo 03-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
Precios de los productos o artículos

Aquí es donde podemos dar muchas veces un toque de distinción entre nuestro programa y los de la competencia, lo habitual en la entrada de productos, es poco más o menos los siguientes campos

Código
Familia
Imagen
Descripción
Precio
stock

Yo me he ido un poco más lejos y os pongo algunos de ellos no todos pero casi, y os pongo el motivo de ellos

Código (sin comentarios)
Código de Familia (sin comentarios)
Código de subfamilia (como ya explique prefiero el sistema de familias->Subfamilias->Productos, que el estándar de Familias->Productos)
Nombre o descripción (sin comentarios)
PVP ración (precio de una ración o unidad)
PVP media Ración (precio de la medía ración)
PVP Tapa (precio de pincho o tapa)
PVP ración en oferta (lo mismo que su equivalente pero si esta marcado como oferta)
PVP media Ración en oferta (lo mismo que su equivalente pero si esta marcado como oferta)
PVP Tapa en oferta (lo mismo que su equivalente pero si esta marcado como oferta)
En oferta (si el producto queremos que este en oferta)
En menú (si el producto entra dentro del menú)
Combinar (si el producto tiene combinaciones)
Código del proveedor (sin comentarios)

Se que esto es rizar el rizo pero todo tiene fácil explicación

Por qué los formatos ración, media y tapa, fácil, o metes tres veces el producto cada uno con su precio o lo simplificas de esta manera, de esta lo único es seleccionar previamente el formato ya veremos como hacerlo.

Por qué los formatos anteriores como ofertas, esto es más simple aún, los motivos de las ofertas son los siguientes, captar público, productos que le quedan poco tiempo para caducarse, librarse de una mercancía para dejar espacio, para lo que sea y seguro que hay más, pero básicamente estos son los principales, imaginemos un proveedor que nos deja la botella de cerveza a 0,20 céntimos, pero le quedan 2 semanas para caducar, que hacemos, colocar la oferta lo más visible para sacar antes la mercancía, es lo lógico, pero además deberemos cambiar nuestro precios, vale pues yo en mi caso, simplemente lo marco como oferta y listo, después veréis un análisis de como debe actual el programa al pulsar sobre un artículo.

En menú, normalmente se suelen ofrecer en estos establecimientos un menú compuesto por primeros, segundos, postre 1 bebida y 1 pan, debe especificarse las cantidades para no tener problemas, pero es también habitual, que el cliente no quiera los primeros o los segundos por que no le gusta, o nos pida un licor reserva, normalmente se opta por poner x menús y no detallar su consumo y estoy totalmente de acuerdo con ello cara al ticket, pero no cara a nuestro sistema, ya que podíamos dar aun cliente de menú un Santateresa gran reserva como bebida, cuando el coste puede ser hasta más del 25% del precio del menú, con lo que reduciría el margen de beneficios del cliente dramáticamente, para ello cada vez que creamos un nuevo artículo se marca el producto como que puede entrar en el menú, sólo si lo desmarcamos no será posible ponerlo dando el mensaje al operario al introducirlo.

Combinar, para mi este apartado es fundamental, todos conocemos el cuba libre (Ron+cola), como ejemplo de un combinado, podemos optar por poner los dos artículos por separado, pero normalmente por lo menos en mi tierra, el precio del combinado, siempre es inferior al de los dos productos por separado, de hecho en mi programa tengo un form y una tabla para crear combinados, os pongo una imagen del combinado que hablamos



y de como los creo



Si os fijáis me permite combinar hasta 4 artículos diferentes Flecha roja y con la flecha azul, marco la foto que coge por defecto, luego podemos cambiarla, pero de entrada hace un montaje con los artículos de los que se compone, claro como mínimo deben de ser 2 artículos y el máximo al que yo lo he limitado de 4.

Como llevarlo a cabo, e aquí la madre del cordero, seguro que se os ocurre mil métodos, pero yo os explico por encima el mio con este pequeño análisis al pulsar sobre un artículo

Previamente tengo en la parte baja de mi pantalla tres botones con las opciones , ración, media y tapa, son speedbutons con los que tengo en grupo en cada tag tiene una de las siguientes cantidades 100, 50, 25, perteneciente a uno de los formatos, entonces sabiendo esto estos son lo pasos que hago

Mostramos los datos, stock y precios del producto seleccionado.
compruebo que tipo esta pulsado y asigno el valor de su tag.
Compruebo si esta en oferta, para saber si debo buscar por PVP de ofertas o normales
Ahora busco sabiendo el tag si debo buscar en ración, en media o en tapa, si el campo PVP esta vacio o a 0, doy un mensaje de que este formato no es valido, en caso contrario continuo.
compruebo cual es la entrada (en mi caso tengo 3 sistemas, el numpad, un contador de entradas y por pulsación en la rejilla).
//En la tabla----------------------------------------
Pasamos a buscar si ya existe este artículo, en nuestra tabla, con e número de ticket ya asignado, si lo encontramos, sumamos la cantidad de artículos que tenia con la nueva. En caso contrario lo creamos y metemos los datos.
Calculamos el nuevo total y subtotal, pero sabiendo si esta marcada la casilla descuento, para saber que total y subtotal poner.
Si es stock cerrado restamos de su stock la cantidad correspondiente
//Pasamos ahora al listview-------------------------------
Realizamos la búsqueda del artículo igual poco más o menos que como con la tabla.
Actualizamos subtotal y totales, con los mismos criterios que antes.

Lo dejamos preparado para el siguiente artículo

Si estamos en menú, lo único que hacemos diferente, es comprobar si el artículo esta permitido para el menú y que el artículo marque la opción no visible en la tabla ticket y en el listview, para que no salga reflejado.

Queda alguna cosa más pero me la guardo para mi.

Bueno con esto es todo por hoy
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
  #20  
Antiguo 04-01-2014
Avatar de José Luis Garcí
[José Luis Garcí] José Luis Garcí is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Las Palmas de G.C.
Posts: 1.372
Poder: 22
José Luis Garcí Va camino a la fama
El Arqueo de caja

Yo en mi programa uso dos tipos de arqueo, pero primero explicar que es el arqueo, este simplemente es comprobar la cantidad de monedas o billetes que tenemos en nuestra caja, para obtener el total, es decir como si dijésemos el stock de dinero disponible.

Aclarado el concepto os pongo una imagen de mi sistema de arqueo



Esta pantalla tiene acceso a 20 valores diferentes (moneda o billetes), como ya dije tengo dos arqueos posibles en mi programa, desde 0 que es para saber únicamente el dinero que tienes en caja, usando la pantalla, el arqueo comparativo que te permite introducir los valores al igual que desde 0 pero , al valor de cada moneda pone encaja: 0, pues en este caso pondría el total de esta moneda que tiene registrado el programa.

Esta pantalla tiene capacidad para 20 valores como ya dije pero como veis se ven ahora sólo 15, esto es debido a que si la base de datos, donde registramos nuestra moneda (valores monedas y billetes), tiene menos de 20 registro mostrará ´solo los que estén registrando, dejando en visible a false el resto de los huecos.

Esta pantalla se usa en 4 situaciones, para los dos tipos de arqueo como ya comente, a la hora del cierre (realmente es un arqueo comparativo) y en la apertura, aunque este último caso, nos lo podemos saltar en cierta forma si lo establecemos en nuestro programa, de manera que al hacer el cierre, y haber totalizado nos deje para la apertura , introduciendo con cuanto abrimos al día siguiente.

Debo decir que esta es una imagen antigua ya que le he añadido un panel en la parte inferior con algunos botones más, algunos visibles en unos momentos o no, botones como por ejemplo descontar, que en vez de añadir descuenta en el valor, el propio totalizar y un botón de apertura automática, que ya tiene configurado unos valores, si a la hora de hacer el cierre, dispone de esos valores o lo más cercanos posibles los deja como apertura al totalizar, ejemplo 20 monedas de 1 euro y quedan 18 pues deja 18 simplemente.

Para que el form nos sirva para las 4 utilidades que tiene lo único que utilizo es una variable fija en mi DataModule, según el valor que le de en la llamada, cambia el caption y deja ver o no ciertos componentes.


Con respecto a si el arqueo automático es real, depende mucho de como se lleve, si se lleva correctamente si, pero si optamos por cobros directos y demás no, esto es algo que debemos saber, se que existe un aparato que pones las monedas y billetes (dos apartados diferentes) y el te los cuenta y te los contabiliza de manera automática, tipo al que tiene la Caixa para los billetes. pero no lo he usado nunca y pienso que la mayor parte de nuestros clientes simplemente usarán el cajón motorizado.
__________________
Un saludo desde Canarias, "El abuelo Cebolleta"
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Teoría del Infierno fidel Humor 5 28-10-2016 02:00:14
Teoria y Practica jcarteagaf Humor 0 18-08-2008 17:32:34
Teoría sobre Archivos de Recursos MaMu OOP 3 15-04-2008 13:36:31
Frameworks, Persistencia: ¿Teoria? Delphius OOP 8 13-04-2008 00:27:24
Teoría del Salario obiwuan Humor 0 06-05-2003 23:00:43


La franja horaria es GMT +2. Ahora son las 19:59:31.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi