PDA

Ver la Versión Completa : Sugerencias sobre numeracion de facturas


JoanKa
02-01-2007, 23:42:05
Buenas tardes a todos y feliz año.

Tengo una duda al respecto, es cuando doy de alta una factura, se me crea por ejemplo un 10450 y por "X" motivos cancelo y cuando quiero realizar otra factura me crea el 10451, lo normal es que cuando despues de cancelar una factura y cree nuevamente, me debe salir el numero de factura cancelada, es decir, 10450. No se si me deje entender ... !!!!

Uso como gestor de base de datos Interbase y el campo codi_factura lo tengo como numerico y para este campo clave tengo un GENERADOR: GEN_FACT_CODIGO, que hace que cada vez que cree una factura(registro), éste se incremente en uno.

Como podria realizarse este procedimiento, de tal manera que la numeracion sea correlativa y no halla salto de numeracion, y esto es lo que en este momento me esta pasando ??

Gracias y salu2 a todos

egostar
02-01-2007, 23:46:36
Mas bien creo que es lo adecuado, imagina este panorama, imprimes la Factura 10450 y por algún motivo la tienes que cancelar, si haces lo que deseas, entonces como vas a volver a utilizar la factura 10450 si ya está impresa. Bueno, cuestión de enfoques no?

Si no la imprimes, entonces no debes de tener reservada esa numeración, sino hasta despues de imprimir.

Saludos

ContraVeneno
03-01-2007, 00:04:55
yo tambien estoy de acuerdo que esa es la manera correcta, no puedes volver a utilizar un folio que ya has utilizado... de entre muchas cosas en las que te sirve eso, es a llevar un control de facturas canceladas. Es decir, llevas un registro de todo lo que van manejando.

Casimiro Notevi
03-01-2007, 00:11:04
Además de que "legalmente" no se pueden eliminar facturas, en todo caso se crean facturas "rectificativas" de la "errónea".

P.d: Hablo de España.

JoanKa
03-01-2007, 00:14:42
En otros palabras como puedo hacer para que no me haya saltos de numeracion de facturas. y llevar una correlatividad de la facturas. ????

Gracias

ContraVeneno
03-01-2007, 00:18:42
no se a que te refieres con "correlatividad de la facturas" o con los saltos...

como ya se dijo, es ilegal (Tambien en México) el utilizar más de una vez un número de factura.

Incluso dependiento de las necesidades del sistema, no solo puede haber cancelaciones, sino devoluciones, devoluciones parciales, rechazos, etc, etc, etc. Con lo cuál se hace todavía más dificil que no existan estos saltos en la numeración.

Tal vez si explicas un poco más de el porque quieres que no existan estos saltos te podríamos ayudar más.

luisgutierrezb
03-01-2007, 00:21:39
lo mas usual es que asignes los numeros de factura hasta antes de imprimir, asi si cancelas algo, es porque salio mal y por lo tanto tienes que incrementar el numero, pero como te han dicho en otros mensajes, tambien tienes que guardar las facturas canceladas para llevar una relacion

JoanKa
03-01-2007, 00:27:31
A ver amigos parece que el termino "cancelar" nos esta dando problemas de interpretacion, me estoy refiriendo al temino de cancelar una factura, es que cuando por ejemplo un cliente esta comprando y esta en la factura 10450 y esta comprando y justo en ese momento de va la corriente electrica o el cliente se arrepiente por que lo que tiene no le alcanza para comprar es alli donde presiono el BOTON DE CANCELAR., entonces la proxima vez que yo presione el BOTON de NUEVA FACTURA voy a tener la factura 10451, y eso es lo que me esta pasando en estos momentos. y CREO QUE NO ES CORRECTO A NIVEL MUNDIAL, porque no me debe dar la 10451 sino la 10450.

Me parece que ahora esta mejor.

En delphi como se puede hacer esto ???

Gracias y espero haberme explicado mejor.

ContraVeneno
03-01-2007, 00:29:24
Entonces el problema supongo esta en que estas asigando el número de factura antes de tenerla lista.

Mi sugerencia es que no le asignes número de factura hasta que no este completa la transacción.

JoanKa
03-01-2007, 00:35:59
Ahora nos entendemos mejor. Pero en codigo como podria realizarlo, lo que pasa es que quiero que todo este en orden, y es como debe ser por alli leyendo me dicen que tengo que ponerlo en el Beforepost de los dataset, pero previo a esto me parece que tenqo que buscar el ultimo registro.... en codigo como puedo hacer esto.

Gracias

egostar
03-01-2007, 00:54:48
Pues mas que código (creo que lo estas ya haciendo) tu problema es de concepto, si tienes un botón de cancelar deberías de usar el botón de imprimir para cerrar el folio.

Yo haria lo siguiente:

Si presiono el botón de CANCELAR hago un Rollback y si presiono el botón ACEPTAR hago un COMMIT.

Saludos.

AzidRain
03-01-2007, 06:00:41
Aqui tienes otra idea depende de como tengas configurada la impresión, si la impresora (y sus facturas) están conectadas solo a esa PC:

* Iniciar la transacción
* Obtener el siguiente de numero de factura que le corresponda (solo como referencia ya que se supone que es el mismo folio que esta en ese momento en la impresora listo para imprimir)
* Hacer la transacción
* Imprimir la factura
* ¿Se imprimió correctamente? (Si) (No) (pudo haberse atascado, roto, etc.)
Si si se imprimió (ahora si) guardar el folio a la BD
Si no se imprimió bien, saltar al siguiente folio y reintentar la impresión

Combat-F2D
03-01-2007, 09:00:11
Si si se imprimió (ahora si) guardar el folio a la BD
Si no se imprimió bien, saltar al siguiente folio y reintentar la impresión

¿y que pasaria si no imprimo porque no quiero hacerlo?, bine porque llegado el momento necesito realizar un proceso masivo de facturacion y por algun motivo no deseo sacarlas a papel pues por ejemplo porque en ese momento no dispongo de él?

yo sugiero un contador de facturas, no un generador ni similar para evitar los posibles huecos en la correlatividad de las mismas; además este contador estando ubicado en otra tabla podria manejarse y variar según conveniencia.

la experiencia me dice que los clientes, por muy correcto, legal, etc, prefieren no tener anuladas ni generar facturas de abono salvo ultimo recurso, y al fin son los que pagan y exigen.

la forma de generar esos numeros elementalmente estarian dentro de una misma y unica transacion, tal y como se indica

vamos, no deja de ser mas que un idea más

Lepe
03-01-2007, 11:50:29
Yo antes de nada, sugiero que no se utilice el número de factura como clave principal de la tabla (que sería lo lógico). Precisamente por todo lo comentado aquí.

Creamos un Store Procedure, que dada la clave primaria de una factura, nos devuelva el nº correlativo de dicha factura (o inserte el valor en la tabla factura). Sólo llamamos a este procedimiento cuando realmente estamos seguro de grabar la factura.

El correlativo, puede ser un generador. En caso de fallos, siempre se puede establecer un generador a un nº determinado.

Saludos

fjcg02
03-01-2007, 15:24:12
Si haces el insert del registro en la tabla, ya tienes el nuevo valor generado. Cualquier cancel que hagas posteriormente, no evitará que se tome el nuevo valor ( incrementado).
Lo que necesitas es generar la factura sin utilizar el insert en la tabla.
Yo utilizaría componentes que no sean de BBDD, y cuando vaya a imprimir/guardar, comenzar un transacción, hacer sentencias SQL insert parametrizadas y cerrar la transacción. Si cancelas, no has tocado la BBDD, por lo que el valor del nº de fra. no se habrá incrementado.
Yo en su día utilizaba cacheupdates de los objetos SQL en estos casos, aunque no me acuerdo bien y no tengo el compilador a mano. Realmente lo que hacen es crear registros en local, y al hacer ApplyUpdates ( asociandolo a la impresión/guardado ) realmente inyecta las sentencias sql que hayas definido.

Suerte

ckaki
03-01-2007, 18:57:08
Hola a todos y felíz 2007

Tengo un sistema de facturación y te sugiero lo siguiente.

Como lo han expresado otros no debes asignar el número de la factura hasta que vayas a calcularla o imprimirla. en este caso si el número de la factura es 0 incluso debes permitir que tu aplicación pueda eliminar físicamente el registro, no siendo de esta manera una vez que sea generada, osea que obtenga un consecutivo y después éste aumentará en uno.

Una vez creada la factura no podrás editar los datos y mucho menos eliminarla de la tabla. sin embargo debes permitir que se imprima con el mismo número que adquirió cuantas veces sea necesario y en caso de error cancelarla digamos que pudieras tener un campo lógico en tu tabla por ejemplo "Cancelada" que sería marcado a True cuando intentas eliminar una factura que ya tiene un número consecutivo el cual no volverás a usar.

Espero me hayas entendido

kuan-yiu
03-01-2007, 19:02:50
Sobre lo de la numeración de las facturas yo tengo un procedimiento almacenado que cuando lo ejecuto me da el mayor número de factura guardado en la BD y le suma 1.
Para eliminar facturas tengo otros controles que no afectan para nada a este generador.

ArdiIIa
04-01-2007, 05:38:16
Yo he utilizado varios y diferentes sistemas y últimamente, concretamente en la última aplicación que estoy haciendo, me he decantado por dejar los generadores para códigos "secundarios o sin importancia" y los contadores de documentos los genero mediante procedimiento que incrementa un campo en una tabla.
Independientemente de como se plantee el asunto de si asignar el número antes de grabar el documento o depués de grabar siempre surgen problemas añadidos.

Por ejemplo: Supongamos una sencilla facturación que está grabando números de factura en el ejercicio del año 2006.... Ha llegado el año 2007 y se supone que los generadores se deberían poner a cero y consecuentemente mediante generadores no podríamos añadir documentos del anterior ejercicio (cosa que en la práctica suele ocurrir). En este caso, yo estoy utilizando una tabla "ejercicios" y cada campo es un contador de documentos actualizable por un procedimiento que es en realidad el que hace toda la faena.. De este modo tengo accesible los contadores del ejercicio actual y los de cualquier otro ejercicio anterior... Luego entonces, cuando inserto un nuevo documento es ese procedimiento descrito anteriormente el que primero se segura que efectivamente haya un ejercicio abierto, segundo hace una búsqueda en otra tabla de "HUECOS" para verificar de que anteriormente no hayamos eliminado algún registro, así podemos recuperar un número perdido de cualquier documento. En el caso de encontrar un número en la tabla HUECOS, devuelve y ese número y es el que se asignará a la factura y en caso contrario, lo que hace es tomar un numero de la tabla de contadores, incrementarlo, y devolver este último número. De este modo no aseguramos que jamás vamos a perder ni un solo número. Este sistema implica que en la tabla afectada (facturas) existe un trigger INSERT para llamar al procedimiento de contadores y otro trigger DELETE para recuperar el múmero perdido e insertarlo en la tabla HUECOS. Este sistema se presume bastante versátil sobre todo cuando tenemos que trabajar con ejercicios.....
:confused:
En cuando lo de asignar el número al documento antes o después, ambas opciones tienen sus ventajas y por supuesto, sus inconvenientes. Yo aconsejo hacerlo una vez que se graba el documento que es en realidad cuando se accionan los triggers.
Una vez organizado todo el sistema, es el servidor o la DB quien hace prácticamente todo el trabajo sucio, ahorrando muchas líneas de código.

Una de las desventajas que veo a la hora de asignar el número después de grabar es que si por ejemplo el nuevo documento grabado obtiene un número de la tabla HUECOS, este seguramente será un número inferior al último registro grabado y consecuentemente por aquello de los índices, se posicionará en un lugar de la tabla que no se corresponde ordinalmente, perdiendo el usuario la vista de ese registro recién grabado, y en este caso, no funciona ni el GetBookmark ni tampoco será posible localizar ese registro mediante un locate o similar, dado que a priori desconocíamos el número antes de ser grabado... Gran paradoja.
En fin espero haber aportado algún granito y no resultar pesado...

Saludos :)

Lepe
04-01-2007, 14:05:51
concretamente en la última aplicación que estoy haciendo, me he decantado por dejar los generadores para códigos "secundarios o sin importancia" y los contadores de documentos los genero mediante procedimiento que incrementa un campo en una tabla.

Estoy de acuerdo con esa filosofía, al menos en tablas planas, usando tablas sql, hay otras alternativas como las ya comentadas.

Por ejemplo: Supongamos una sencilla facturación que está grabando números de factura en el ejercicio del año 2006.... Ha llegado el año 2007 y se supone que los generadores se deberían poner a cero
¿Por qué?, Dado que los generadores se crean e incrementan a través de su nombre (un string), se puede construir generadores cada año. Un programa con 100 tablas tendrá (normalmente) 100 generadores para sus claves primarias, para que ocurra lo mismo en facturas, deberían pasar 100 años usando el programa.

En el caso de encontrar un número en la tabla HUECOS, devuelve y ese número y es el que se asignará a la factura
Como ya se ha dicho, no puede existir huecos en la numeración de facturas. Por otro lado, e intentando encontrar sentido a lo que dices, tu método podría servir para reutilizar el último número de factura que ha sido borrado, pero, en este caso, ¿no resulta más eficiente grabar sólo cuando se ha aceptado la factura?. Si el cliente pide que se pueda borrar una factura, se le dice claramente: "lo que me pides es ilegal y no voy a hacerlo", (señores, no se está jugando a la PlayStation ;))

consecuentemente por aquello de los índices, se posicionará en un lugar de la tabla que no se corresponde ordinalmente,
¿Pero de qué hablamos? :confused: En tablas de escritorio sí hay diferencia entre llamar al método Append o al método Insert, respecto a la posición física del registro en la BBDD. En tablas sql, (como se habla en este hilo) no hay diferencia, ya que siempre usaremos un ORDER BY.

perdiendo el usuario la vista de ese registro recién grabado
Ya no sé si hablamos de aislamiento de las transacciones, de inserciones o de qué, lo siento :confused:.

En fin espero haber aportado algún granito y no resultar pesado...

Eso mismo espero yo ;) Saludos

ArdiIIa
04-01-2007, 14:46:41
Veamos si poco a poco vamos aclarándonos... esto promete.

¿Por qué?, Dado que los generadores se crean e incrementan a través de su nombre (un string), se puede construir generadores cada año. Un programa con 100 tablas tendrá (normalmente) 100 generadores para sus claves primarias, para que ocurra lo mismo en facturas, deberían pasar 100 años usando el programa.


Supongo que cuando estamos hablando de generadores, nos estamos refiriendo a los internos y que se actualizan de este modo:

NEW.CODIGO = Gen_Id(AUX_TIPO_SERVICIO,1);

Si es así, no entiendo muy bien tu planteamiento de construir generadores cada año.




Como ya se ha dicho, no puede existir huecos en la numeración de facturas. Por otro lado, e intentando encontrar sentido a lo que dices, tu método podría servir para reutilizar el último número de factura que ha sido borrado, pero, en este caso, ¿no resulta más eficiente grabar sólo cuando se ha aceptado la factura?. Si el cliente pide que se pueda borrar una factura, se le dice claramente: "lo que me pides es ilegal y no voy a hacerlo", (señores, no se está jugando a la PlayStation ;))


Aunque somos conscientes de lo que hablamos, y en este caso nos referimos a facturas, yo esto lo extiendo más... (Albaránes, Notas de Entrega, etc) luego dicho esto, no conozco ninguna aplicación que limite el borrado de registros de cualquier tipo de documentos, sin embargo, ahí está la cuestión; sea cual sea la razón por la que se ha borrado un registro, con este método no existe la posibilidad de perder un número, dado que cuando se inserte un nuevo registro será recuperado automáticamente. (Obviamos la legalidad/ilegalidad de las facturas).


¿Pero de qué hablamos? :confused: En tablas de escritorio sí hay diferencia entre llamar al método Append o al método Insert, respecto a la posición física del registro en la BBDD. En tablas sql, (como se habla en este hilo) no hay diferencia, ya que siempre usaremos un ORDER BY.


Esta es la madre del cordero. Precisamente cuando se "recupera" un registro de la tabla de huecos, el nuevo registro se ORDENA al número recuperado, y consecuentemente al ocupar su orden es cuando será perdido de vista por el usuario. No se si me explico, aunque esto es un fastidio, también existe la posibilidad de posicionarse sobre el nuevo registro, sabiendo a priori el número que la BD le va a asignar.


Ya no sé si hablamos de aislamiento de las transacciones, de inserciones o de qué, lo siento :confused:.
Eso mismo espero yo ;) Saludos

En definitiva, que cada maestrillo tiene su librillo, y hablando se entiende la gente. Naturalmente lo que yo comento no es la "piedra filosofal", pero funciona y bastante bien.

Saludetes

Lepe
04-01-2007, 16:30:20
Creo que nos estamos desviando mucho del tema, quizás lo que expongo ahora es demasiado para el tema que nos ocupa.

La filosofía:
- Primero comprobamos que el generador está creado en la BBDD, de lo contrario, lo creamos (habría que inicializarlo a un valor... pero no lo incluyo en el código).
- Ya que existe, y tiene un valor, lo incrementamos y recogemos su número.


const ExisteGen = 'SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = %s and RDB$SYSTEM_FLAG IS NULL' ;

const CreaGen = ' CREATE GENERATOR %s';

const IncrementaGen = 'SELECT GEN_ID(%s , 1) FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME = %s AND and RDB$SYSTEM_FLAG IS NULL';

begin
NombreGen:= 'Facturas_'+ inttostr(2007); // Nombre del Generador incluyendo el año

qry.sql.text := format( existeGen, [QuotedStr(NombreGen)]);
qry.Open;
if qry.IsEmpty then
begin
// vaya por dios, el generador no existe en la BBDD,
// si intentamos consultar su valor nos daría una bonita excepción
qry.Close;
qry.sql.text := Format(CreaGen, [NombreGen]); // pos creamos el generador
qry.ExecSql;
// aquí podríamos establecer su valor a cero, (sería lo lógico)
end;

qry.sql.text := Format(IncrementaGen, [NombreGen, QuotedStr(NombreGen)]);
qry.Open;
Result := qry.Fields[0].AsInteger; // el valor del generador, incrementado en 1


He tenido un problemilla con Firebird 1.5, y es que en un Store Procedure no se puede hacer algo asï:

create generator :NameGen
Donde NameGen es el parámetro de tipo string que se pasa al Store Procedure. Pues bueno, salvamos el escollo desde delphi que no tiene restricciones.

PD: El código está escrito de memoria, aunque los sqls han sido probado desde el SQL Editor de IB Expert Personal.

Consecuencias de usar este método:
- El número de factura solo se pediría al guardar definitivamente la factura.
- Estando en red, podría dar fallos al crear los generadores, igual se podrían crear 50 generadores desde el principio, y así obviamos el tener que comprobar que existen y que tienen asignados un valor.

Saludos

ContraVeneno
04-01-2007, 16:30:32
Aunque somos conscientes de lo que hablamos, y en este caso nos referimos a facturas, yo esto lo extiendo más... (Albaránes, Notas de Entrega, etc) luego dicho esto, no conozco ninguna aplicación que limite el borrado de registros de cualquier tipo de documentos, sin embargo, ahí está la cuestión; sea cual sea la razón por la que se ha borrado un registro, con este método no existe la posibilidad de perder un número, dado que cuando se inserte un nuevo registro será recuperado automáticamente. (Obviamos la legalidad/ilegalidad de las facturas).

Pues de antemano te comento que todos los sitemas empresariales que he estado utilizando en los últimos años, no le permiten al usuario borrar ningún registro. Esto es para llevar un mayor control de las acciones que se realizan.

El estatus de los registros puede cambiar (activo, cancelado, obsoleto, cerrado, facturado, etc) pero jamás se eliminan registros.

Así que yo te podría decir que, los sistemas que permiten al usuario borrar registros, tienen un gran hueco de seguridad y control de su información.

Esto es cuando hablamos de sistemas que contienen información legal o vital para la empresa.

ArdiIIa
04-01-2007, 16:50:47
Creo que nos estamos desviando mucho del tema, quizás lo que expongo ahora es demasiado para el tema que nos ocupa.


Perfecto Lepe:
A priori ese sistema me parece sofisticado e ingenioso, sin embargo tengo por costumbre no "hurgar" en las tablas del sistema, dado que en mis inicios de interbase, hice irrecuperable una base de datos tratando de ocultar las fuentes de la misma, y desde entonces son prohibidas para mi, no obstante viendo lo visto, sería cuestión primero reconsiderarlo y segundo quitarme el sombrero.

ArdiIIa
04-01-2007, 17:07:53
Pues de antemano te comento que todos los sitemas empresariales que he estado utilizando en los últimos años, no le permiten al usuario borrar ningún registro. Esto es para llevar un mayor control de las acciones que se realizan. .

:)


El estatus de los registros puede cambiar (activo, cancelado, obsoleto, cerrado, facturado, etc) pero jamás se eliminan registros.


Me parece muy adecuado pero tajante....


Así que yo te podría decir que, los sistemas que permiten al usuario borrar registros, tienen un gran hueco de seguridad y control de su información.

Esto es cuando hablamos de sistemas que contienen información legal o vital para la empresa.

Seamos un poco serios con aquello de la información legal y vital.
Recuerdo que hace unos años, mas o menos en los inicios del Club de Delphi, pululaba y pulula una empresa ""de cierto prestigio", la cual cuenta con una importante cartera de clientes, entre las que además del desarrollo de aplicaciones, impartía formación a programadores y se desarrolló un proyecto de gestión empresarial / contabilidad, que pretendía abarcar todos los ramos empresariales.
Bueno pues mira por donde, resulta que ese proyecto disponía de una doble contabilidad, la "legal" y la "otra" y mira por donde, resultó que la mayoría de las empresas que se interesaron por aquel proyecto, destacaban como principal virtud del proyecto, justamente esa faceta que te he comentado.
Estoy seguro que algunos de los usuarios de esta web, les suena de lo que estoy hablando.
Dicho esto; saca tus propias conclusiones.
Saludos