Como usar ROLLBACK

From: marcosrios(at)planet(dot)com(dot)pe
To: pgsql-es-ayuda(at)postgresql(dot)org
Subject: Como usar ROLLBACK
Date: 2009-04-29 20:12:56
Message-ID: 20090429151256.95lncjzc8o8ck4cw@webmail.planet.com.pe
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-es-ayuda

Estimada Lista,

Tengo una funcion que me actualiza saldos de varios productos, le
envio como parametros un nro de pedido y la funcion lee todos los
productos relacionados con ese nro de pedido descontando uno a uno de
la tabla de saldos la cantidad solicitada.

Mi problema es que si alguna de las cantidades solicitadas excede al
stock, la funcion debe hacer un ROLLBACK a los registros que
previamente han sido procesados como validos dentro del mismo nro de
pedido. He intentado ponerle un ROLLBACK, pero me devuelve un error y
cuelga mi aplicativo.

Ejemplo: El pedido 100 tiene los siguientes registros:

CodProd Descripcion Cantidad Stock Disponible
1001 Producto A 20 50
1002 Producto B 10 37
1003 Producto C 25 12
1015 Producto X 15 10

La funcion procesa los dos primeros registros sin problema, pero el
tercero no debe procesarlo xq no hay stock disponible, es ahi que
deseo hacer un ROLLBACK para deshacer los registros anteriores y
abortar la funcion.

Por favor, les agradecere mucho me puedan ayudar a resolver este problema.

Saludos,

Marcos Rios Rodriguez
Arequipa - Peru

CREATE OR REPLACE FUNCTION actualizar_saldos_online(integer, integer,
integer, integer, character varying)
RETURNS smallint AS
$BODY$
DECLARE
v_empresa ALIAS FOR $1;
v_sucursal ALIAS FOR $2;
v_interno ALIAS FOR $3;
v_movimiento ALIAS FOR $4;
v_usuario ALIAS FOR $5;
reg_pedidos RECORD;
reg_saldos RECORD;
reg_lotes RECORD;
reg_movimientos RECORD;
reg_saldos_online RECORD;
v_saldo_pd int4 NOT NULL DEFAULT 0;
v_saldo_pdlote int4 NOT NULL DEFAULT 0;
BEGIN
RAISE NOTICE 'Filtrando Salidas';
IF v_movimiento IN (2,3,7,15,17,18) THEN --// Ventas Oficina,
Obsequios, Traslados entre Depositos, Consignaciones, Autoventa y
Preventa //--
FOR reg_pedidos IN SELECT
a.cod_producto
, a.cantidad
, b.fecha_emision
FROM
detalle_pedidos a
, pedidos b
WHERE a.empresa = v_empresa
AND a.sucursal = v_sucursal
AND a.pedido = v_interno
AND NOT a.procesado
AND NOT a.anulado
AND b.empresa = a.empresa
AND b.sucursal = a.sucursal
AND b.pedido = a.pedido
LOOP
SELECT INTO reg_saldos *
FROM saldos_online
WHERE empresa = v_empresa
AND sucursal = v_sucursal
AND cod_producto = reg_pedidos.cod_producto;
IF reg_saldos.saldo_apto >= reg_pedidos.cantidad THEN
UPDATE saldos_online
SET saldo_apto = saldo_apto - reg_pedidos.cantidad,
ultima_salida = reg_pedidos.cantidad
WHERE empresa = v_empresa
AND sucursal = v_sucursal
AND cod_producto = reg_pedidos.cod_producto;
ELSE
ROLLBACK; -- ME ARROJA UN ERROR.
RETURN 0; --// No existe Saldo suficiente para atender el
pedido //--
END IF;
RAISE NOTICE 'Actualizando detalle_pedidos';
UPDATE detalle_pedidos
SET procesado = true
WHERE empresa = v_empresa
AND sucursal = v_sucursal
AND pedido = v_interno
AND cod_producto = reg_pedidos.cod_producto;
RAISE NOTICE 'Actualizando pedidos';
UPDATE pedidos
SET procesado = true
WHERE empresa = v_empresa
AND sucursal = v_sucursal
AND pedido = v_interno;
RAISE NOTICE 'Actualizando productos';
IF v_movimiento IN (2,3,15,17,18) THEN
UPDATE productos
SET fecha_ultima_venta = reg_pedidos.fecha_emision
WHERE empresa = v_empresa
AND cod_producto = reg_pedidos.cod_producto;
END IF;
RAISE NOTICE 'Grabando movi_prod';
INSERT INTO movi_prod
VALUES
(
nextval('serie_moviprod')
, v_empresa
, v_sucursal
, reg_pedidos.fecha_emision
, reg_pedidos.cod_producto
, reg_pedidos.cantidad
, 0
, 0
, CASE WHEN v_movimiento = 2 THEN 'VENTAS OFICINA' WHEN
v_movimiento = 3 THEN 'TRANSFERENCIA GRATUITA' WHEN v_movimiento = 7
THEN 'TRASLADO ENTRE DEPOSITOS' WHEN v_movimiento = 15 THEN
'CONSIGNACIONES' WHEN v_movimiento = 17 THEN 'FACTURACION DE
AUTOVENTA' ELSE 'FACTURACION DE PREVENTA' END
, 90
, 1
, v_interno
, 'A'
, v_movimiento
, false
, v_usuario
, CURRENT_DATE
, CURRENT_TIME
);
RAISE NOTICE 'Filtrando Lotes';
v_saldo_pd := reg_pedidos.cantidad;
v_saldo_pdlote := reg_pedidos.cantidad;
FOR reg_lotes IN SELECT
a.lote
, a.vencimiento
, a.saldo_final_apto
FROM
vencimientos a
, productos b
WHERE a.empresa = v_empresa
AND a.sucursal = v_sucursal
AND a.cod_producto = reg_pedidos.cod_producto
AND a.saldo_final_apto > 0
AND b.empresa = a.empresa
AND b.cod_producto = a.cod_producto
AND b.controla_lote
ORDER BY a.empresa, a.sucursal, a.vencimiento, a.lote ASC
LOOP
IF v_saldo_pd > 0 THEN
v_saldo_pd := CASE WHEN reg_lotes.saldo_final_apto <=
v_saldo_pd THEN v_saldo_pd - reg_lotes.saldo_final_apto ELSE 0 END;
RAISE NOTICE 'Actualizar vencimientos';
UPDATE vencimientos
SET saldo_final_apto = CASE WHEN
reg_lotes.saldo_final_apto >= v_saldo_pdlote THEN
reg_lotes.saldo_final_apto - v_saldo_pdlote ELSE 0 END
WHERE empresa = v_empresa
AND sucursal = v_sucursal
AND cod_producto = reg_pedidos.cod_producto
AND vencimiento = reg_lotes.vencimiento
AND lote = reg_lotes.lote;
SELECT INTO reg_movimientos *
FROM mov_vencimientos
WHERE empresa = v_empresa
AND sucursal = v_sucursal
AND cod_movimiento = v_movimiento
AND pedido = v_interno
AND cod_producto = reg_pedidos.cod_producto
AND vencimiento = reg_lotes.vencimiento
AND lote = reg_lotes.lote;
IF FOUND THEN
RAISE NOTICE 'Actualizar movimiento';
UPDATE mov_vencimientos
SET cantidad = cantidad + (v_saldo_pdlote - v_saldo_pd)
WHERE empresa =v_empresa
AND sucursal = v_sucursal
AND cod_movimiento = v_movimiento
AND pedido = v_interno
AND cod_producto = reg_pedidos.cod_producto
AND vencimiento = reg_lotes.vencimiento
AND lote = reg_lotes.lote;
ELSE
RAISE NOTICE 'Grabar movimiento';
INSERT INTO mov_vencimientos
VALUES(
v_empresa
, v_sucursal
, v_movimiento
, v_interno
, reg_pedidos.cod_producto
, v_saldo_pdlote - v_saldo_pd
, reg_lotes.vencimiento
, reg_lotes.lote
);
END IF;
END IF;
v_saldo_pdlote := v_saldo_pd;
END LOOP;
END LOOP;
END IF;
RAISE NOTICE 'Proceso Finalizado';
RETURN 1;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION actualizar_saldos_online(integer, integer, integer,
integer, character varying) OWNER TO postgres;

Responses

Browse pgsql-es-ayuda by date

  From Date Subject
Next Message Angelo Astorga 2009-04-29 22:29:42 Procesos postgresql permanentes en linux !!!
Previous Message Diego Ayala 2009-04-29 18:43:55 Mondrian + Postgresql