MySQL - store procedure - descarga de stock

 
Vista:
sin imagen de perfil

store procedure - descarga de stock

Publicado por Eduardo (5 intervenciones) el 14/10/2021 19:03:39
Saludos colegas,

Tengo la siguiente store procedure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
CREATE PROCEDURE `sp_descargalotecualquiera` (IN localid INT,IN itemid INT,IN articuloid INT,IN cuantas INT,IN modulo CHAR(4),IN operacion INT)
BEGIN
 
DECLARE loteslista varchar(300) DEFAULT "" ;
DECLARE descargas int DEFAULT 0 ;
DECLARE descargar int DEFAULT cuantas ;
DECLARE intentos  int DEFAULT 0 ;
DECLARE rlocked   int DEFAULT 0 ;
DECLARE finished  int DEFAULT 0 ;
DECLARE lote_id   char(20) ;
DECLARE lote_vc   char(8) ;
DECLARE lote_un   int     ;
DECLARE arti_fr   int     ;
DECLARE arti_cs   numeric(12,2) ;
DECLARE arti_lk   tinyint ;
DECLARE arti_st   int  ;
DECLARE curLotes CURSOR FOR
SELECT stock_lote,stock_vence,stock_unids
FROM articulos_stocks
WHERE stock_local_id = localid AND stock_articulo_id = articuloid AND stock_unids > 0
ORDER BY stock_vence ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1 ;
 
lock_arti: loop
	select articulo_fracciones,articulo_costo_promed,articulo_rlock INTO arti_fr,arti_cs,arti_lk
    from articulos
    where articulo_id = articuloid ;
 
    if arti_lk = 0 then
		update articulos set articulo_rlock = 1 where articulo_id = articuloid ;
        set rlocked = 1 ;
        leave lock_arti ;
	end if ;
 
	set intentos = intentos + 1 ;
 
    if intentos > 5000 then
		leave lock_arti ;
    end if ;
end loop lock_arti ;
 
if rlocked = 1 then
 
	OPEN curLotes ;
	getLotes: LOOP
 
		SELECT COALESCE(sum(stock_unids),0) as stock_total INTO arti_st
        FROM articulos_stocks
		WHERE stock_local_id = localid AND stock_articulo_id = articuloid AND stock_unids > 0 ;
 
		FETCH curLotes INTO lote_id,lote_vc,lote_un ;
 
		IF finished = 1 THEN
			LEAVE getLotes ;
		END IF;
 
        IF lote_un >= descargar THEN
 
			UPDATE articulos_stocks SET stock_unids = stock_unids - descargar WHERE stock_local_id = localid AND stock_articulo_id = articuloid AND stock_lote = lote_id ;
 
            INSERT INTO kardex (kdx_local_id,kdx_arti_id,kdx_fecha,kdx_tipo,kdx_oper_mod,kdx_oper_id,kdx_arti_frac,kdx_stock_ant,kdx_stock_mov,kdx_stock_sld    ,kdx_costo_prm,kdx_lote,kdx_vence)
                         VALUES( localid    ,articuloid ,NOW()    ,"-"     ,modulo      ,operacion  ,arti_fr      ,arti_st      ,descargar    ,arti_st-descargar,arti_cs      ,lote_id ,lote_vc  ) ;
 
			SET descargas = descargas + descargar ;
			SET loteslista = CONCAT( loteslista,"(",lote_id,",",lote_vc,",",descargar,")" );
 
	    ELSE
 
			UPDATE articulos_stocks SET stock_unids = 0 WHERE stock_local_id = localid AND stock_articulo_id = articuloid AND stock_lote = lote_id ;
 
            INSERT INTO kardex (kdx_local_id,kdx_arti_id,kdx_fecha,kdx_tipo,kdx_oper_mod,kdx_oper_id,kdx_arti_frac,kdx_stock_ant,kdx_stock_mov,kdx_stock_sld    ,kdx_costo_prm,kdx_lote,kdx_vence)
                         VALUES( localid    ,articuloid ,NOW()    ,"-"     ,modulo      ,operacion  ,arti_fr      ,arti_st      ,lote_un      ,arti_st-lote_un  ,arti_cs      ,lote_id ,lote_vc  ) ;
 
			SET descargas = descargas + lote_un ;
			SET loteslista = CONCAT( loteslista,"(",lote_id,",",lote_vc,",",lote_un,")" );
 
        END IF ;
 
        IF descargas = cuantas THEN
			LEAVE getLotes ;
	    ELSE
			SET descargar = descargar - descargas ;
        END IF ;
 
	END LOOP getLotes ;
	CLOSE curLotes ;
 
end if ;
 
insert into descargas values(modulo,operacion,itemid,loteslista) ;
update articulos set articulo_rlock = 0 where articulo_id = articuloid ;
 
END

Lo que hace es descargar stock de un producto específico en la tabla ARTICULOS_STOCKS y agregar el movimiento en la tabla KARDEX. Para resolver la concurrencia se me ocurrió crear un campo en la tabla de productos llamado ARTICULO_LOCK, cuando se trata de mover stock de ese producto, la SP revisa que ARTICULO_LOCK sea igual a cero, si es cero lo pone en 1 y procede a realizar la descarga del stock y al terminar pone el ARTICULO_LOCK otra vez en cero.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
lock_arti: loop
	select articulo_fracciones,articulo_costo_promed,articulo_rlock INTO arti_fr,arti_cs,arti_lk
    from articulos
    where articulo_id = articuloid ;
 
    if arti_lk = 0 then
		update articulos set articulo_rlock = 1 where articulo_id = articuloid ;
        set rlocked = 1 ;
        leave lock_arti ;
	end if ;
 
	set intentos = intentos + 1 ;
 
    if intentos > 5000 then
		leave lock_arti ;
    end if ;
end loop lock_arti ;

Tengo 2 dudas al respecto (pero OJO, actualmente la store procedure esta funcionando):

1. ¿ Es esta la manera más optima de resolver la concurrencia ?
2. ¿ El número de intentos (5000) del bucle es el adecuado ?

Quisiera saber, desde su experiencia, como resuelven o han resuelto Ustedes este tema.

Cordiales saludos y gracias anticipadas por su tiempo.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder