Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Control de stock (https://www.clubdelphi.com/foros/showthread.php?t=89708)

Jack 21-01-2016 12:10:53

Control de stock
 
Otra pregunta, modifico una linea de venta y en los eventos de after update y before update, actualizo la ficha del stock del articulo vendido en la linea, parece ser que algún update de la ficha del stock falla, puesto que no refleja el movimiento, en el caso de fallo la grabasción de la ficha del stock, la linea de venta tampoco debería reflejar la modificación, según el funcionamiento de las transacciones. Pero a la práctica no sucede eso, la linea de venta se graba y la actualización del stock no se realiza. Pregunto si esto es cierto o no, y si es así como tiene que funcionar Firebird.
Un saludo Jack.

Casimiro Notevi 21-01-2016 14:42:28

No se entiende nada del problema que tienes. Pon código y explica exactamente la situación.

Neftali [Germán.Estévez] 21-01-2016 15:38:22

Me da la impresión de que no estás usando correctamente las transacciones.
Parece que estés usando diferentes transacciones para ambas operaciones. Para comportarse como quieres (según he entendido la pregunta) debes asegurarte de que utilizas la misma transacción para ambas y de que no realizas el Commit o el Rollback hasta que no hayas finalizado ambas.

Jack 21-01-2016 19:07:28

Mas explicación
 
Hola, la transacción empieza con la linea de venta y acaba con la linea de venta con un commitretaining. ( necesito conservar el contexto ).
Eso ocurre en el programa, en la base de datos ha dos triggers un before update y otro after update que actualizan la tabla de stocks.
Código SQL [-]
create or alter trigger trantes for LineasVentas as begin 
active before update 
update stocks
set ventastotales = coalesce(ventastotales,0) - Old.UnidadesVendidas
where codigostocks = old.codigolineadeventa
end
^
create or alter trigger trdespues fro LineasVentas as begin
active after update 
update stocks
set ventastotales = coalesce(ventastotales,0) + New.UnidadesVendidas
where codigostocks = new.codigolineadeventa
end

En la transación hay implicada una segunda tabla que es la de stocks, donde se guardan los totales de los movimientos por cada codigoarticulo, es decir va haciendo el stock a medida que va modificando lineas, también existe el trigger insert y delete con la misma estructura. Yo creo que la transaccion es única aunque se vean implicadas dos tablas. Para mi si la linea de ventas recoge la modificación obligatoriamente la tabla de stocks debe de hacer correctamente los dos updates. La transacción la inicia la linea de ventas y la acaba la linea de ventas.
La pregunta es porque este mecanismo no es seguro ?, en caso de fallo del update en la tabla de stocks debería también fallar la actualización de la tabla de lineas de ventas, esto es cierto. Lo que me ocurre es que no me actualiza el stock pero si acualiza bien la tabla de ventas. Utilizo los IBX de delphiXE2. LLevo años sin comprender este funcionamiento, a ver si alguien lo entiende y me lo puede explicar.
Gracias.

Casimiro Notevi 21-01-2016 20:19:11

Si no he entendido mal, si antes de actualizar las restas, y después de actualizar las sumas... te quedas igual que estabas :)

Jack 21-01-2016 20:27:33

Control Stock
 
Hola, en la linea de venta tengo 10 y modifico a 25. Es decir resto 10 ( old.unidadesventa), y sumo 20 ( new.unidadesventa ).
Gracias.

Casimiro Notevi 21-01-2016 20:28:52

¿Pero por qué restas lo que hay, si ya estarán contadas?

Jack 21-01-2016 20:45:10

Control Stock
 
La última pregunta no la entiendo, el hecho de primero restar y luego sumar es porque se puede cambia el codigo de articulo de la linea de venta si el articulo AA tenia 10 unidades, y modifico al articulo BB 20 unidades. la resta deja los AA en 0 y la suma pone los 25 en BB que es lo que tiene que haber.
Gracias.

Casimiro Notevi 21-01-2016 20:50:04

El stock se modifica cuando se compra y cuando se vende. Además se puede hacer un inventario manual para ajustarlo por posibles problemas, errores, etc.
Si compro, sumo al stock.
Si vendo, resto del stock.
Si hago inventario, pongo una cantidad fija.
No entiendo lo que dices de pasar stock de AA a BB. ¿Pasas 3 libros de matemáticas a 5 lápices de colores?

Jack 21-01-2016 21:02:49

Control Stock
 
Hola, solo estoy vendiento, he vendido 10 lapices pero me he equivocado y en realodad son 25 colorines, lo que hago es modificar la linea de venta sustituyendo lo 10 lapices por 25 colorines. Solo es eso.
Gracias

Casimiro Notevi 22-01-2016 01:22:52

Entonces no estás haciéndolo correctamente.
Piensa con lógica, ejemplo, has vendido 10 caramelos y querías vender 20 lápices.
Para solucionarlo tendrás que vender -10 caramelos.
Luegos venderás los 20 lápices.

juanelo 22-01-2016 20:33:18

Y pensaba que lo habia visto todo :confused:. Como dice Casimiro, tu problema esta en la logica, revisa el proceso y la iteraccion que tiene el usuario.

mamcx 22-01-2016 20:47:02

Jack: Te recomiendo que estudies sobre el tema, y uses una hoja de excel (o lapiz y papel) y paso a paso vayas haciendo el proceso. Si no tienes claro lo que haces, no podras programarlo.

Casimiro Notevi 22-01-2016 20:52:23

Cita:

Empezado por mamcx (Mensaje 501506)
Jack: Te recomiendo que estudies sobre el tema, y uses una hoja de excel (o lapiz y papel) y paso a paso vayas haciendo el proceso. Si no tienes claro lo que haces, no podras programarlo.

Totalmente cierto.
Yo siempre tomo papel y lápiz. Pienso en el proceso en la vida real. Lo describo siguiendo paso a paso cada opción. Cuando lo tengo resuelto en la "vida real" es entonces cuando enciendo el ordenador y lo tecleo en el lenguaje de programación que esté usando.

TiammatMX 23-01-2016 00:57:45

Cita:

Empezado por mamcx (Mensaje 501506)
Jack: Te recomiendo que estudies sobre el tema, y uses una hoja de excel (o lapiz y papel) y paso a paso vayas haciendo el proceso. Si no tienes claro lo que haces, no podras programarlo.

Regla CERO del diseño de sistemas: Si no entiendes PERFECTAMENTE el proceso a programar, no hagas nada, por mucha presión que exista.

Si le explicas a tu abuela el proceso y ella aporta ideas, estás listo para comenzar a codificar. :D:D;)

Casimiro Notevi 23-01-2016 11:13:31

Cita:

Empezado por TiammatMX (Mensaje 501516)
Regla CERO del diseño de sistemas: Si no entiendes PERFECTAMENTE el proceso a programar, no hagas nada, por mucha presión que exista.

Si le explicas a tu abuela el proceso y ella aporta ideas, estás listo para comenzar a codificar. :D:D;)

^\||/^\||/^\||/^\||/^\||/^\||/

Jack 31-01-2016 11:42:05

Alucino.
 
Que nadie comprenda lo que digo me hace alucinar, vuelvo a explicar que el usuario de mi programa ( no yo sino el usuario que quede bien claro ), graba una linea de venta de 10 lapices, despues una vez ha grabado la linea y descontado el stock de la ficha de lapices, rectifica la linea porque en realidad tenia que haber grabado 20 libretas( vuelvo a decir que el usuario se ha equivocado él y no yo ).
Si esta situación vuestros clientes no la tienen los mios si, y mi deber es que se puedan gestionar estos cambios en la base de datos con lo que nadie de vosotros tiene el derecho de opinar si mi pregunta es buena o mala, tan solo se pide que el que no la comprenda o no la sepa pues que no la conteste, decirme 'que le pregunte a mi abuela no se que', o que 'creía que lo había visto todo' esta totalmente fuera de lugar y es de muy mala educación ya que mi abuela esta ya fallecida.
Creía que esta página era para ayudarnos entre gente que trabaja con firebird, y que sufrimos lo indecible por intentar hacer bien las cosas pero veo que no.
No sé exactamente desde que año estoy suscrito a esta página, son muchos años y muchos años también trabajando con firebird, nunca jamás se me habría ocurrido contestar a nadie de la manera que aquí se me ha contestado. Una buena noticia para todos estos que me lo han hecho, esta sera la última vez que entre en esta página, jamás volveré a pisar los pies por aqui.
Es triste encontrase con gente así por la vida, aunque tengo claro que siempre que tenga que medirme con gente de este tipo, yo estaré infinitamente por encima de ellos, por respeto a los demas y por educación.

Casimiro Notevi 31-01-2016 13:35:42

Hay que ser más humilde, no pasa nada por reconocer que te has equivocado, todos lo hacemos y ninguno nacemos enseñados, se aprende de los errores.
En tu explicación del problema está claro, y así se te ha informado (con bromas sarcásticas, cierto) de que el planteamiento que haces es incorrecto. ¿Y te enfadas porque te han dicho que está equivocado el planteamiento que haces?, yo me alegraría que me dijeran que está mal y así poder solucionarlo.


PD. En relación a tu otro mensaje de baja, basta con que no nos visites más. Suerte.

Lepe 31-01-2016 15:04:17

Jack... lo siento por como te has tomado todo...

El problema que tienes es de concepto, es muy fácil de solucionar y no tiene nada que ver con Firebird, me explico:

Tu haces la interfaz con un ClientDataset, un StringGrid, pero no uses un DBGrid.
Dejas que el usuario haga todos los cambios que desee, pero tu transacción solo empieza cuando el usuario le da al botón "Aceptar".

Mientras tanto el usuario puede modificar su línea, sus cantidades, todo lo que quiera, eso lo "hace en memoria", no pasa por la Base de datos. Una vez que él lo tiene claro y pulsa "Aceptar", es en realidad cuando empieza la transacción se suma ó se resta y se acabó.

Tu error que no terminas de comprender es que el trigger beforepost y afterpost se ejecutan siempre que guardes en la tabla. Ejemplo:
"quiero vender 20 lápices" con tus triggers haces lo siguiente:

- Empieza la modificación, usuario vende 20 lapices y pulsa botón aceptar:
- trigger before post: stock.ventastotales = coalesce(ventastotales,0) - 20
- trigger after post: stock.ventastotales = coalesce(ventastotales,0) + 20
- Se hace el Post y después CommitRetainig. Todo queda grabado.

¿cuanto lápices te quedan en stock.ventastotales? Lo mismo que tenías antes de empezar. Eso es lo que todos te han dicho ya.

Me da la impresión que usas un DBGrid y cuando alguien graba una línea del grid haces el post y el commitRetainining, por eso te falla la lógica del negocio. Todo eso que el usuario "se equivoca"... esos errores que comete el usuario los hace "en memoria", en un stringGrid, sin pasar por la Base de datos!!!, o al menos así debe ser!!! ¿lo entiendes ahora?


Si el usuario se ha equivocado y ha pulsado el botón Aceptar. Lo que debe hacerse es un apunte rectificativo (no tiene nada que ver contigo ni con programación). Es él, el que debe añadir otro apunte a la tabla stock con concepto "anulación/rectificación en el apunte con ID=33" y en cantidad pone "-20" (si vendió 20 unidades, en este apunte pone que ha vendido "-20" y rectifica los totales de stock). Queda grabado en el sistema que él se equivocó y después lo corrigió.

Saludos

mamcx 31-01-2016 17:00:41

Cita:

Empezado por Jack (Mensaje 501721)
Que nadie comprenda lo que digo me hace alucinar...

Aunque tomaste una accion drastica, no debería sorprenderte que no te comprendan, y a la vez, que el programa no funcione. Ambos problemas son el mismo problema..

Definir el problema es como tener el 90% de la solución. Entender el problema es la puerta segura y facil al éxito.

Por ejemplo, de acuerdo al zen de python:

Cita:

Explicito es mejor que implicito
---
Al enfrentar la ambigüedad, rehusa la tentación de adivinar.
---
Si la implementación (osea, código) es difícil de explicar, probablemente sea una mala idea
Probablemente estas familiarizado con la idea que es dificil de estimar cuanto cuesta/dura un programa, que las especificaciones que te dan los clientes siempre son insuficientes, o que cuando vas a implementarlas te das cuenta que tienen lagunas.

Una razon? Porque si las especificaciones fuera realmente correctas y completas, no solo no tendrían ambigüedades sino que serian la explicación exacta y detallada del programa.

Un programa entonces, seria la explicación (en términos del lenguaje) concreta de la especificacion.

----

En pocas palabras: Cuanto tienes las preguntas claras, y son claras PRECISAMENTE PORQUE CUALQUIER LAS PUEDE ENTENDER, ERGO, LAS PUEDES PROGRAMAR Y EL LENGUAJE LAS "ENTENDERA".

Eso es especificamente, la labor que se hace en foros como este. Aqui NO DAMOS RESPUESTAS, no porque no queramos, sino porque muchas veces no podemos! (literalmente!)

Porque? Porque NO ENTENDEMOS LA PREGUNTA! Si la entendemos, tendremos las respuesta, y al MISMO tiempo, la tendrias tu ;)

toni.vi 31-01-2016 19:22:49

Jack
Entiendo tu problema, y no se porque no te funciona, a mi me funciona correctamente. Te paso mi codigo para que lo revises respecto al tuyo.
Solo añadir que tambien debes crear un trigger para beforeinsert

Código SQL [-]

CREATE TRIGGER FGEHIMAR_BU0 FOR FARTICULO
ACTIVE BEFORE INSERT OR UPDATE POSITION 1
AS
begin
  /* Trigger text */
  update FARTICULO
  set FARTICULO.STOCK = coalesce(FARTICULO.STOCK,0) - old.cantidad
  where FARTICULO.articulo  = old.Articulo;

end
^

CREATE TRIGGER FGEHIMAR_AU0 FOR FARTICULO
ACTIVE AFTER UPDATE POSITION 0
AS
begin
  /* Trigger text */

  update FARTICULO
  set FARTICULO.STOCK = coalesce(FARTICULO.STOCK,0) + new.cantidad
  where FARTICULO.articulo  = new.Articulo;

end
^

Jack 01-02-2016 10:21:29

Gracias por contestar
 
Gracias a todos por contestar, ( yo prefiero sin sarcasmos ), pero lo que me explicaís no es lo que pregunto. Ya veo que como Lepe dice el stock se queda a cero, pero antes de la modificación habían 10 unidades old.unidades, luego de la modificación hay 15 new.unidades, de donde sacas que ahora el stock se queda = 0. Digo que habra +10 -15 = -5. Si pongo 10 y quito 10 entonces si estoy igual. No pegunto si la secuencia de sumas y restas esta bien.
Mi pregunta es si el update de la tabla stocks puede fallar al grabar la linea de venta e ir a actualizar el stock en los triggers after insert, before update, after delete de la linea de ventas. Esa es mi pregunta, la secuencia lógica del programa no me falla, lo he probado con muchos casos y calcula bien el stock ( al borrar, al modificar y al añadir lineas nuevas, lo hace bien, suma y resta cuando toca ).
El desajuste ocurre cuando hay muchos movimientos o cuando hay varios usuarios trabajando o por algún motivo que yo no logro comprender.
Bien es cierto que utilizo un dbgrid, haciendo un commitretaining inmediatamente despues del post. Si esto no funciona que alguien me explique 2 cosas. a: para que esta el dbgrid, b: para que esta el commitretaining.
También es cierto que leí hace años en alguna página que se desaconsejaba el uso del commitretaining, aunque como he dicho antes en las pruebas que realicé en mi ordenador parecía que funcionaba bien.
Otra cosa a la que no puedo renunciar es a que el stock se actualice siempre a cada linea de venta, no al final de la introducción de cada documento, repito, necesito que sea al insertar una nueva linea o al actualizar una linea ya insertada con anterioridad.
Estuve hace tiempo tentado de utilizar un stringgrid para trabajar, pero no lo ví operativo y la estética que le pude dar no fue nada de mi agrado.

Despues de todo lo dicho, repito la pregunta.
Tengo una tabla linventas LV., dos campos LV.articulo, LV.unidades. Inserto una linea nueva LV.Articulo = 'A1', LV.Unidades = 25. La tabla LinVentas tiene un trigger after insert, donde hago lo siguiente a una tabla Stocks. ( esta asegurado que en esta tabla existe un articulo A1 )
Código SQL [-]
update Stocks ST, 
     set ST.UnidadesVentas = ST.UnidadesVentas + New.Unidades
 where ST.Articulo = New.Articulo
En la tabla stocks queda ST.Articulo = 'A1', ST.TotalUnidades = 25.
Utilizo la misma lógica con
los trigger after delete, before update, after update de la tabla linventas.
Esto se puede hacer o hay algún motivo por el que no se deba hacer este sistema de actualización de stocks. ( Las transaciones de las lineas finalizan con un commitretaining.
Podría ser que hubiera una situación de introducciones de lineas de ventas de varios usuarios concurrentes ( +10).

Yo solo preguntaba esto, me disculpo si no lo pregunte bien o si dije algo no conveniente al leer vuestras contestaciones. Cuando he preguntado algo siempre me habeís contestado amablemente y yo lo he agradecido siempre. Esto del stock me tiene muy preocupado. Actualmente he reprogramado todo el sistema y ya no lo hago de esta manera, aunque aún lo estoy probando, pero si que utilizo este sistema para otros menesteres. Es por eso que insisto tanto en la pregunta.
Gracias de antemano.

mamcx 01-02-2016 21:25:45

Cita:

Empezado por Jack (Mensaje 501746)
Mi pregunta es si el update de la tabla stocks puede fallar al grabar la linea de venta e ir a actualizar el stock en los triggers after insert, before update, after delete de la linea de ventas. Esa es mi pregunta, la secuencia lógica del programa no me falla, lo he probado con muchos casos y calcula bien el stock ( al borrar, al modificar y al añadir lineas nuevas, lo hace bien, suma y resta cuando toca ).
El desajuste ocurre cuando hay muchos movimientos o cuando hay varios usuarios trabajando o por algún motivo que yo no logro comprender.

Ok, ya esto es otra cosa.

Puede fallar? Si.

Pero para eso son las transacciones. Existen diversos niveles de transaccion, con diversas garantias y promesas.

Puedes (y deberias) leer los docs al respecto:

http://www.firebirdsql.org/manual/is...nsactions.html

-------

Un problema con la forma como casi siempre se hace esto es que el proceso es *destructivo*, y una vez completo, es prácticamente imposible reconstruir lo que paso.

Sin embargo, existe una forma de diseño que garantiza la reproducibilidad y el rastreo preciso de lo que pasa, y es muy similar a como funciona la contabilidad (Contabilidad bien echa NUNCA hace ediciones o borrados, solo inserta pa' delante):

http://www.codeproject.com/Articles/...Event-sourcing

En resumen, debes guardar un log de cada pasa que se ejecuta, y hacer un replay para reconstuir el valor actual. Eso es lo que hace una BD con su log de transacciones.

En el modelo comun, tienes:

UPDATE Producto=1 Cant = 2 WHRE Id=1

Cuando esto termina, no sabes que paso antes. El proceso es *destructivo*

En cambio, si lo vuelves un log:

Inv ID=1 ADD Producto=1 Cant = 1
Inv ID=1 UPDATE Producto=1 Cant = 2
Inv ID=1 ADD Producto=2 Cant = 3
Inv ID=1 DELETE

Como vez, al hacer esto asi, tenes un log inmutable que puedes evaluar y saber exactamente que paso, en que orden, etc. Es la forma segura de darle la maxima integridad y fiabilidad (y tiene otros beneficios, pero dejemoslo asi por ahora).

Tambien, considero que es la forma correcta de implementar un inventario.

P.D: Para la velocidad de consultas, puedes tener una tabla auxiliar que mantiene el valor actual desde los triggers del log. Es *mas* trabajo, pero es la forma de tener una auditoria perfecta y fiable.

TiammatMX 17-05-2017 18:48:45

Cita:

Empezado por Jack (Mensaje 501721)
...esta sera la última vez que entre en esta página, jamás volveré a pisar los pies por aqui.
Es triste encontrase con gente así por la vida, aunque tengo claro que siempre que tenga que medirme con gente de este tipo, yo estaré infinitamente por encima de ellos, por respeto a los demas y por educación.

No hace falta el que se va ni sobra el que se queda...


La franja horaria es GMT +2. Ahora son las 05:03:57.

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