pela aplicação vc pode colocar no evento um update, ou fazer igual eu fiz.
fiz a baixa pelo banco. com trigger e procedure, segue como fiz.
criei as tabelas venda, saida_produto, entrada_produto, estoque, produto. essas só são partes das minhas tabelas só pra ilustrar
pois no scriptcase o form_venda é mestre do detalhe saida_produto, que ao inserir uma venda na tabela guardo apenas os ides dos produtos da tabela saida_produtos e no banco de dados um procedure chama a trigger atualizando os intens do estoque reduzindo os mesmos caso exclua os intens gravados da tabela saida_produtos os mesmos serão incrementados de volta na tabela estoque,
faça um teste.
CREATE TABLE produto (
id INT(11) NOT NULL AUTO_INCREMENT,
status CHAR(1) NOT NULL DEFAULT ‘A’,
descricao VARCHAR(50) NULL DEFAULT NULL,
estoque_minimo INT(11) NULL DEFAULT NULL,
estoque_maximo INT(11) NULL DEFAULT NULL,
PRIMARY KEY (id))
CREATE TABLE entrada_produto (
id INT(11) NOT NULL AUTO_INCREMENT,
id_produto INT(11) NULL DEFAULT NULL,
qtde INT(11) NULL DEFAULT NULL,
valor_unitario DECIMAL(9,2) NULL DEFAULT ‘0.00’,
data_entrada DATE NULL DEFAULT NULL,
PRIMARY KEY (id))
CREATE TABLE estoque (
id INT(11) NOT NULL AUTO_INCREMENT,
id_produto INT(11) NULL DEFAULT NULL,
qtde INT(11) NULL DEFAULT NULL,
valor_unitario DECIMAL(9,2) NULL DEFAULT ‘0.00’,
PRIMARY KEY (id))
CREATE TABLE saida_produto (
id INT(11) NOT NULL AUTO_INCREMENT,
id_produto INT(11) NULL DEFAULT NULL,
qtde INT(11) NULL DEFAULT NULL,
data_saida DATE NULL DEFAULT NULL,
valor_unitario DECIMAL(9,2) NULL DEFAULT ‘0.00’,
PRIMARY KEY (id))
procedure SP_AtualizaEstoque
DELIMITER //
CREATE PROCEDURE SP_AtualizaEstoque( id_prod int, qtde_comprada int, valor_unit decimal(9,2))
BEGIN
declare contador int(11);
SELECT count(*) into contador FROM estoque WHERE id_produto = id_prod;
IF contador > 0 THEN
UPDATE estoque SET qtde=qtde + qtde_comprada, valor_unitario= valor_unit
WHERE id_produto = id_prod;
ELSE
INSERT INTO estoque (id_produto, qtde, valor_unitario) values (id_prod, qtde_comprada, valor_unit);
END IF;
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER TRG_EntradaProduto_AI AFTER INSERT ON entrada_produto
FOR EACH ROW
BEGIN
CALL SP_AtualizaEstoque (new.id_produto, new.qtde, new.valor_unitario);
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER TRG_EntradaProduto_AU AFTER UPDATE ON entrada_produto
FOR EACH ROW
BEGIN
CALL SP_AtualizaEstoque (new.id_produto, new.qtde - old.qtde, new.valor_unitario);
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER TRG_EntradaProduto_AD AFTER DELETE ON entrada_produto
FOR EACH ROW
BEGIN
CALL SP_AtualizaEstoque (old.id_produto, old.qtde * -1, old.valor_unitario);
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER TRG_SaidaProduto_AI AFTER INSERT ON saida_produto
FOR EACH ROW
BEGIN
CALL SP_AtualizaEstoque (new.id_produto, new.qtde * -1, new.valor_unitario);
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER TRG_SaidaProduto_AU AFTER UPDATE ON saida_produto
FOR EACH ROW
BEGIN
CALL SP_AtualizaEstoque (new.id_produto, old.qtde - new.qtde, new.valor_unitario);
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER TRG_SaidaProduto_AD AFTER DELETE ON saida_produto
FOR EACH ROW
BEGIN
CALL SP_AtualizaEstoque (old.id_produto, old.qtde, old.valor_unitario);
END //
DELIMITER ;
Observação: observem que em algumas chamadas do procedure “SP_AtualizaEstoque”, antes de passar o parâmetro “qtde” é feita a multiplicação desse valor por -1, essa operação muda o sinal matemático do valor para negativo. Dentro do procedure somamos as quantidades, mas quando passamos o sinal de negativo ocorre então uma subtração dos valores resultando em débito no estoque.
Depois de todo esse trabalho é só cadastrar as compras e as vendas nas respectivas tabelas. Como criamos um trigger para cada evento, todas as ações (INSERT, UPDATE, DELETE) na compra ou venda serão refletidas na tabela “ESTOQUE”. Vamos dizer que na teoria não tem como haver “furo” nesse estoque, pelo menos no sistema.