Generar un numero de factura usando mysql

2,876 views
Skip to first unread message

Marcelo Barberis

unread,
Aug 30, 2017, 2:24:50 PM8/30/17
to publicesvfoxpro
Hola buenas tardes, deseo consultarle como puedo generar un numero de factura teniendo un bd en mysql en un ambiente de red donde al mismo tiempo unas 3 o mas pc pueden crear una factura.

1.- Yo tengo una tabla donde tengo tblFactura es la tabla, un campo autoincremental con un indice primary key id_factura y tambien tengo otro campo para el nro de factura nro_factura tipo decimal 15,0 aqui es donde guardo los nro de facturas.

2.- he creado una vista para generar los nros de facturas al momento de crear en mi sistema una nueva factura. esta vista la creo de esta manera dentro de bd que tengo en mysql

SELECT
MAX(tbl_factura.NRO_FACTURA)+1 AS NRO_FACTURA
FROM
tbl_factura

usando un metodo en el form de crear factura logro obtener el nro de factura

LPARAMETERS lctablafacturas

IF TYPE("lcTablaFacturas")="L"
   RETURN 0
ENDIF
LOCAL lcaliastabla, lnfactura
lcaliastabla = sqlconsulta(lctablafacturas, .F., .F., .F., "bdConn", "nro_factura", ALLTRIM(this.lcbasedatos))
IF EMPTY(lcaliastabla) .OR.  .NOT. USED(lcaliastabla)
   RETURN 0
ENDIF
SELECT (lcaliastabla)
lnfactura = IIF(ISNULL(&lcaliastabla..nro_factura),1,&lcaliastabla..nro_factura)
USE IN (lcaliastabla)
RETURN lnfactura

para obtener el nro de factura utilizo esto 
THIS.nro_factura.Value = THIS.traer_nro_fact ("vw_numero_fac")

Ahora todo esto sale bien si es que estoy trabando solo con una sola computadora. El tema esta en el caso de que al mismo tiempo por ejemplo en una supermercado pueden estar trabajando 10 pc y al mismo tiempo pueden haber creado una factura el cual se generaria un mismo nro de factura por el tema de que hacen uso de la vista la cual usa la funcion max()

Las conexiones de red la hago usando la modalidad de conexiones mediante ip fijo para hacer las conexiones a la bd que puede estar en una oficina aparte a las pc que pueden trabajar en red

Desde ya agradecido por cualquier aporte 

--
Marcelo Barberis Gutierrez
Sistemas Informaticos
Villa Montes - Bolivia
Telef.: +591-76830544

Armando Rodríguez B.

unread,
Aug 30, 2017, 2:29:57 PM8/30/17
to publice...@googlegroups.com

Yo le dejo esa chamba a mySql. Utilizando el folio de la factura como un campo auto incremental.

Saludos

LEWIS LOPEZ GOMEZ

unread,
Aug 30, 2017, 2:30:18 PM8/30/17
to publice...@googlegroups.com
Haslo directamente en servidor de MySQL, usando un disparador, BEFORE_INSERT. y así no tendrás dicho problema.


Cordialmente
Lewis Lopez Gomez
GERENTE
LOPEZSOFT S.A.S NIT: 901091403 - 2
Diseño y desarrollo de Software a la medida
Diseño y desarrollo web y Móvil
 310 843 5431
Jesús le dijo: Yo soy el camino, la verdad y la vida; nadie viene al Padre, sino por mí. Juan 14:6

LEWIS LOPEZ GOMEZ

unread,
Aug 30, 2017, 2:30:58 PM8/30/17
to publice...@googlegroups.com
Haslo directamente en servidor de MySQL, usando un disparador, BEFORE_INSERT en la tabla de las facturas. y así no tendrás dicho problema


Cordialmente
Lewis Lopez Gomez
GERENTE
LOPEZSOFT S.A.S NIT: 901091403 - 2
Diseño y desarrollo de Software a la medida
Diseño y desarrollo web y Móvil
 310 843 5431
Jesús le dijo: Yo soy el camino, la verdad y la vida; nadie viene al Padre, sino por mí. Juan 14:6


LEWIS LOPEZ GOMEZ

unread,
Aug 30, 2017, 2:36:45 PM8/30/17
to publice...@googlegroups.com
CREATE DEFINER=`root`@`localhost` TRIGGER `tblFactura_before_insert` BEFORE INSERT ON `tblFactura` FOR EACH ROW BEGIN
DECLARE _nro_factura INT DEFAULT 0;
      SELECT NRO_FACTURA +1 INTO _nro_factura FROM tblFactura ORDER BY NRO_FACTURA DESC LIMIT 1;
SET NEW.NRO_FACTURA = _nro_factura;
END


Cordialmente
Lewis Lopez Gomez
GERENTE
LOPEZSOFT S.A.S NIT: 901091403 - 2
Diseño y desarrollo de Software a la medida
Diseño y desarrollo web y Móvil
 310 843 5431
Jesús le dijo: Yo soy el camino, la verdad y la vida; nadie viene al Padre, sino por mí. Juan 14:6


Antonio Meza

unread,
Aug 30, 2017, 2:54:47 PM8/30/17
to Comunidad de Visual Foxpro en Español
Un campo Autoincrementable si la transacción falla de todas formas se incrementa el valor y tendrías saltos entre los folios de las facturas por lo que no es nada recomendable usarlo para eso, de hecho un campo AI solo se debe usar para relacionar con otras tablas y hacer actualizaciones al registro y a parte sirve para identificar cada registro.

En mi caso el campo que uso para guardar del folio de la factura es Char(10), y tengo otro campo para la serie, no uso campo numérico pues no voy a sumar o hacer operaciones matemáticas con ese valor, y normalmente le agrego ceros a la izquierda "0000000001" y para obtener un consecutivo único me apoyo en otra tabla donde si tengo un campo numérico que se va a ir incrementando siempre y cuando la transacción se haya completado correctamente y realizo un bloqueo a ese registro para asegurarme que no se repitan y no se salten.

Con FoxyDb es muy sencillo tiene una función llamada Code() que te permite hacer todo eso de una forma sencilla, incluso puedes ver el código para que te des una idea de como hacerlo.

saludos
Antonio Meza

Antonio Meza

unread,
Aug 30, 2017, 3:06:21 PM8/30/17
to Comunidad de Visual Foxpro en Español
Esta interesante tu planteamiento pero me surge muchas dudas pero de momento una jejeje

Before Insert es para que haga algo antes de insertar el registro es decir el registro aun no esta en la tabla, por lo que en teoría no existe, entonces como sabe Mysql a cual registro le va a insertar el valor obtenido de la consulta?

saludos
Antonio Meza

ZeRoberto

unread,
Aug 30, 2017, 6:45:44 PM8/30/17
to publicesvfoxpro
Yo lo genero al momento de guardar el documento

En este orden

1.- Inicio Transaccion
2.- Obtengo Numero De Folio
3.- Guardo Cabecera de Factura
4.- Guardo Detalle de Factura
5.- Si no hubo error COMMIT de lo contrario ROLLBACK


Saludos




LEWIS LOPEZ GOMEZ

unread,
Aug 30, 2017, 6:46:37 PM8/30/17
to publice...@googlegroups.com
Hola Antonio Meza, BEFORE_INSERT se ejecuta justo antes de confirmar la inserción del Registro actual. Al Igual que AFTER_INSERT, se ejecuta inmediatamente después que haya confirmado la inserción del registro actual.


Cordialmente
Lewis Lopez Gomez
GERENTE
LOPEZSOFT S.A.S NIT: 901091403 - 2
Diseño y desarrollo de Software a la medida
Diseño y desarrollo web y Móvil
 310 843 5431
Jesús le dijo: Yo soy el camino, la verdad y la vida; nadie viene al Padre, sino por mí. Juan 14:6


El 30 de agosto de 2017, 14:06, Antonio Meza<solv...@gmail.com> escribió:

ZeRoberto

unread,
Aug 30, 2017, 6:56:17 PM8/30/17
to publicesvfoxpro
Aca muestro un codigo de como mas o menos lo hago

PROCEDURE Guardar
Local loKardex, loCompras, loCtaCte, llResult

   loCmd = NewObject("uo_Command", "class\database.vcx")
   loCmd.ActiveConnection = goSQL
    
   goSQL.SQLStart()

   Try

      llResult = .T.
      loCompras = NewObject("uo_Compras", "class\datos.vcx")
      loCompras.InsertMode = This.isNew
      loCompras.Save()

      loKardex = NewObject("uo_Kardex", "class\datos.vcx")
      loKardex.InsertMode = This.isNew
      loKardex.Save()

      If loInput.Credito = TRUE
         This.Cobrar()
         loCtaCte = NewObject("uo_Proveedores_CtaCte", "class\datos.vcx")
         loCtaCte.InsertMode = This.isNew
         loCtaCte.Save()
      EndIf

    Catch To loError

       goSql.SQLRollBack()
       lcMessage = Iif(loError.ErrorNo = 2071, loError.UserValue, loError.Message) + CRLF + loCmd.eMessage
       goApp.MessageBox("ERROR: " + lcMessage, MB_EXCLAMATION)
       llResult = .F.

   EndTry

   Release loCmd, loKardex, loCompras, loCtaCte
   
   If llResult = .T.
      goSql.SQLCommit()
      goApp.MessageBox("El documento fue registrado con exito")
   EndIf
    
Return (llResult)

En la clase Datos.Vcx

PROCEDURE uo_Compras.Save()
Local lcSQLCommand, lcAction, lcWhere

   */-- Obtener Correlativo
   If This.InsertMode
      loInput.CompraID = loCmd.SQLLastInsertID("compras", "CompraID")
   EndIf
  
   If loInput.CompraID = -1
      Throw "No se pudo obtener el correlativo"
   EndIf

   lcAction = "UPDATE"
   lcWhere = "WHERE CompraID = ?loInput.CompraID"
   If This.InsertMode
      lcAction = "INSERT"
      lcWhere = ""
   EndIf
   */-- Insertamos la cabecera del documento
   Text To lcSQLCommand TextMerge NoShow Flags 1 Pretext 15
       <<lcAction>> compras
              SET CompraID = ?loInput.CompraID,
                  UniqueID = ?loInput.UniqueID,
                  ProveedorID = ?loInput.ProveedorID,
                  Credito = ?loInput.Credito
              <<lcWhere>>
   EndText
   loCmd.SQLExec(lcSQLCommand)
   If loCmd.SQLCode < 0
      Throw "No se pudo guardar la compra..."
   EndIf
    
Return

En el procedimientoe SQLLastInsertID

PROCEDURE Cmd.SQLLastInsertID
Parameters tcTable, tcAutoIncField, tcWhere
Local lnResult
    tcWhere = Iif(Vartype(tcWhere) == "C", " WHERE " + tcWhere + " ", "")
    lnResult = -1
    This.SQLExec("SELECT " + tcAutoIncField + " AS LastID FROM " + tcTable + tcWhere + " ORDER BY 1 DESC LIMIT 1", "dbSQLQuery")
    If This.SQLCode > 0
       lnResult = dbSQLQuery.LastID + 1
       Use In Select("dbSQLQuery")
    EndIf
Return (lnResult)


Marcelo Barberis

unread,
Aug 30, 2017, 10:31:03 PM8/30/17
to publicesvfoxpro
por ahi alguien me comento que use el campo donde esta el primary key pero yo tenia el tema de que como hago facturacion computarizada donde la renta me da el nro de factura que debo comenzar, por decirte en un negocio esta en el nro 15879 por lo que en el primary key al ser el primer registro seria 1 y yo tengo que emitir una factura con numero 158780, bueno ahi esta el detalle, por otro lado el campo primary key es el campo clave para las relaciones con otras tablas como ser tbl_item_factura alli estan los item de la factura la cual en su posterior se la usa para armar el tema de la impresion de la factura con campos tanto de facturas como de item de factura relacionado con el campo clave el cual es de tipo primary key

Newbie

unread,
Aug 31, 2017, 4:15:56 PM8/31/17
to Comunidad de Visual Foxpro en Español
Marcelo, hasta donde YO sé, cada dosificación inicia en 1, me gustaría saber de donde tomaste esa información, por si estoy cometiendo errores.

Antonio Meza

unread,
Aug 31, 2017, 5:25:14 PM8/31/17
to Comunidad de Visual Foxpro en Español
Puedes cambiar el valor inicial del PrimaryKey sin problemas, el detalle es que no lo debes usar para obtener el folio de la factura, todos los que te digan que un AutoIncrementable lo puedes usar como folio de factura están completamente equivocados, que les funcione es una cosa, lamentablemente la frase "A mi me funciona" esta muy generalizada pero no quiere decir que sea correcto.

Por ejemplo: Muchos dicen "A mi me funciona"  pisar el pedal de clutch cuando llego a un semáforo teniendo la velocidad puesta, claramente esa persona no leyó el manual o no tomo clases de manejo, ahhh pero le funciona y es feliz y le dice a todos los demás que así lo hagan, pero lo correcto es poner el carro en neutral, no pisar el clutch si no poner el freno de mano, incluso recomiendan apagar el carro si vas a durar mas de ciertos segundos detenido, no recuerdo el tiempo pero cada carro en su manual lo indica.

saludos
Antonio Meza

Marcelo Barberis

unread,
Aug 31, 2017, 9:33:35 PM8/31/17
to publicesvfoxpro
claro eso lo se cuando es primera vez la dosificaciones siempre en 1 y despues solo es continuar con la numeracion donde quedo la facturacion, pero hay un negocio que facturan manual y van en 15879 y uno no sabe como son estos de la renta y cuando ellos se quieran pasar a facturacion computarizada no vaya ser que la renta le diga que debe seguir donde quedo la facturacion manual solo por eso dije ese comentario

mpulla

unread,
Sep 1, 2017, 3:01:15 PM9/1/17
to Comunidad de Visual Foxpro en Español
Hola Marcelo.

SELECT
MAX(tbl_factura.NRO_FACTURA)+1 AS NRO_FACTURA
FROM
tbl_factura

Si 2 usuarios ejecutan el código al mismo tiempo van a tener igual numero, la forma correcta es la que recomienda Antonio.

Saludos.
Mauricio

Marcelo Barberis

unread,
Sep 1, 2017, 11:08:49 PM9/1/17
to publicesvfoxpro
Si es asi amigo, por eso era mi inquietud de mejorar esta forma que implemente porque ya tuve duplicacion en el nro de factura

Daniel Sánchez

unread,
Sep 2, 2017, 10:23:33 AM9/2/17
to Comunidad de Visual Foxpro en Español
La cabecera de tu factura mas el control de la secuencia del mismo debes hacerlo de manera consecutiva, por decirlo de otra manera a la vez, y todo eso debe estar dentro de un transacción, así mientras la transacción bloquea las tablas que son usadas en ese momento otro no podrá acceder hasta que esta termine, por eso todo este proceso debe ejecutarse junto. Lo recomendable seria al decirle registrar documento toma la secuencia correspondiente graba en la cabecera de factura y actualiza la tabla de secuencia, desbloqueo terminando la transacción y así ya queda disponible para que otro usuario tome su número.
No debes olvidar entre que inicias la transacción y la terminas no debe haber ninguna interacción con el usuario para que la transacción quede bloqueado a los demás usuarios, si el usuario no da respuesta o llena un dato, esta transacción debe registrar las tablas de manera secuencial una tabla detrás de otra y esto debe demorar menos de un segundo, así nadie queda bloqueado.

procedure RegistrarNuevaFactura

iniciar transacción

select * from tablaSecuencias where documento=Factura o boleta u otro documento

Correlativo=TablaSecuencias.correlativo

insertar en CabeceraFactura sus campos de la cabecera con el correlativo correspondiente

grabar otros datos necesarios si tuvieras que hacer en otras tablas

si todo ok finalizar transaccion
no ok deshacer registros

endproc

Saludos

El 1 de septiembre de 2017, 22:08, Marcelo Barberis <alexm...@gmail.com> escribió:
Si es asi amigo, por eso era mi inquietud de mejorar esta forma que implemente porque ya tuve duplicacion en el nro de factura

El 1 de septiembre de 2017, 15:01, 'mpulla' via Comunidad de Visual Foxpro en Español <publicesvfoxpro@googlegroups.com> escribió:
Hola Marcelo.

SELECT
MAX(tbl_factura.NRO_FACTURA)+1 AS NRO_FACTURA
FROM
tbl_factura

Si 2 usuarios ejecutan el código al mismo tiempo van a tener igual numero, la forma correcta es la que recomienda Antonio.

Saludos.
Mauricio




--
Marcelo Barberis Gutierrez
Sistemas Informaticos
Villa Montes - Bolivia
Telef.: +591-76830544




--
Daniel Sánchez Escobar
Investigación y Desarrollo
Reset Software & Sistemas
Móvil +051-949398047 RPM #948615385
Trujillo - Perú

P  Sugerimos no imprimir este e-mail a menos que sea absolutamente necesario. Protejamos el medio ambiente.

Newbie

unread,
Sep 2, 2017, 1:11:09 PM9/2/17
to Comunidad de Visual Foxpro en Español
Marcelo realmente estás muy mal asesorado en cuanto a lo de la tributación, ayer hable con el equipo de Auditoría, y esto es lo que sacamos en conclusión..!

1.- Por Resolucion publicada en la WEB de Impuestos, cada dosificación inicia en la factura 1
2.- Es altamente recomendable más NO obligatorio el mantener la facturación manual, para emitir facturas en contingencia.

Daniel Sánchez

unread,
Sep 3, 2017, 9:30:36 PM9/3/17
to Comunidad de Visual Foxpro en Español
Lo que yo entiendo es que se refiere a que si comienza el a trabajar con un cliente que ya tiene su numeración iniciada con otro sistema y cambian a su sistema entonces va ha tomar con su numeración ya iniciada, a eso se refiere, por lo que usar autoincremental no le serviría a parte que no es para nada recomendable.

Saludos

Marcelo Barberis

unread,
Sep 4, 2017, 10:31:51 PM9/4/17
to publicesvfoxpro
si asi es amigo el tema es que debo ver todas las opciones, por ej este tema no lo habia visto del lado que varios pc al mismo tiempo puedan generar las facturas, yo siempre lo vi del lado de monousuario una sola pc, por eso ahora debo ver y tomar todas las opciones posibles, si es primera vez, si debo tomar la numeracion ya iniciada, en fin todos los angulos posibles 
Reply all
Reply to author
Forward
0 new messages