= Тригери = == Автоматско ажурирање на статус на маса при креирање на нарачка == === Опис === Кога келнерот креира нова нарачка за одредена маса, статусот на масата автоматски се менува во „ЗАФАТЕНА". Ова спречува две нарачки да бидат креирани за иста маса во исто време. === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_order_insert_update_table() RETURNS TRIGGER AS $$ BEGIN UPDATE project.restaurant_table SET status = 'ЗАФАТЕНА' WHERE table_id = NEW.table_id AND status = 'СЛОБОДНА'; IF NOT FOUND THEN RAISE EXCEPTION 'Масата % е веќе зафатена или неактивна', NEW.table_id; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_order_insert AFTER INSERT ON project.orders FOR EACH ROW EXECUTE FUNCTION trg_order_insert_update_table(); }}} == Автоматско ослободување на маса при плаќање == === Опис === Кога нарачката ќе биде платена, статусот на масата автоматски се враќа во „СЛОБОДНА". === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_payment_release_table() RETURNS TRIGGER AS $$ BEGIN UPDATE project.restaurant_table SET status = 'СЛОБОДНА' WHERE table_id = ( SELECT table_id FROM project.orders WHERE order_id = NEW.order_id ); UPDATE project.orders SET status = 'ПЛАТЕНА' WHERE order_id = NEW.order_id; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_payment_insert AFTER INSERT ON project.payment FOR EACH ROW EXECUTE FUNCTION trg_payment_release_table(); }}} == Автоматско намалување на залиха при продажба == === Опис === При додавање на ставка во нарачка, залихата на производот автоматски се намалува. Ако залихата е недоволна, трансакцијата се отфрла. === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_order_item_update_inventory() RETURNS TRIGGER AS $$ DECLARE current_stock INTEGER; BEGIN SELECT COALESCE(SUM(quantity_change), 0) INTO current_stock FROM project.inventory WHERE product_id = NEW.product_id; IF current_stock < NEW.quantity THEN RAISE EXCEPTION 'Недоволна залиха за производ %. Достапно: %, Побарувано: %', NEW.product_id, current_stock, NEW.quantity; END IF; INSERT INTO project.inventory (product_id, quantity_change, operation_type) VALUES (NEW.product_id, -NEW.quantity, 'ПРОДАЖБА'); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_order_item_inventory AFTER INSERT ON project.order_item FOR EACH ROW EXECUTE FUNCTION trg_order_item_update_inventory(); }}} == Контрола на залиха со дозволен минимум == === Опис === При секое движење на залиха, системот проверува дали залихата е под минималното ниво. Ако е под минимум, се евидентира предупредување во `audit_log`. === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_inventory_check_min_stock() RETURNS TRIGGER AS $$ DECLARE current_stock INTEGER; min_stock_level INTEGER; product_name TEXT; BEGIN SELECT COALESCE(SUM(quantity_change), 0) INTO current_stock FROM project.inventory WHERE product_id = NEW.product_id; SELECT p.min_stock, p.name INTO min_stock_level, product_name FROM project.product p WHERE p.product_id = NEW.product_id; IF current_stock < min_stock_level THEN INSERT INTO project.audit_log (user_id, action, entity_name) VALUES ( 1, 'LOW_STOCK: ' || product_name || ' (' || current_stock || '/' || min_stock_level || ')', 'PRODUCT' ); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_inventory_min_stock AFTER INSERT ON project.inventory FOR EACH ROW EXECUTE FUNCTION trg_inventory_check_min_stock(); }}} == Автоматско затворање на смена при плаќање == === Опис === При затворање на смена, системот автоматски ги пресметува вкупниот приход и бројот на нарачки. === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_shift_close_calculate() RETURNS TRIGGER AS $$ DECLARE total_amount NUMERIC; order_count_val INTEGER; shift_start TIMESTAMP; BEGIN SELECT start_time INTO shift_start FROM project.shift WHERE end_time IS NULL LIMIT 1; SELECT COUNT(*), COALESCE(SUM(p.amount), 0) INTO order_count_val, total_amount FROM project.orders o JOIN project.payment p ON p.order_id = o.order_id WHERE o.status = 'ПЛАТЕНА' AND o.created_at >= shift_start; NEW.total := total_amount; NEW.order_count := order_count_val; NEW.closed_at := NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_shift_close BEFORE INSERT ON project.shift_close FOR EACH ROW EXECUTE FUNCTION trg_shift_close_calculate(); }}} == Превенција на бришење на нарачки со историја на плаќање == === Опис === Спречува бришење на нарачки кои имаат поврзани плаќања. === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_prevent_order_delete() RETURNS TRIGGER AS $$ BEGIN IF EXISTS (SELECT 1 FROM project.payment WHERE order_id = OLD.order_id) THEN RAISE EXCEPTION 'Не може да се избрише нарачка % бидејќи има поврзано плаќање.', OLD.order_id; END IF; RETURN OLD; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_prevent_order_delete BEFORE DELETE ON project.orders FOR EACH ROW EXECUTE FUNCTION trg_prevent_order_delete(); }}} == Автоматско логирање на промени во audit_log == === Опис === При секое креирање, измена или бришење на нарачка, системот автоматски додава запис во `audit_log`. === Имплементација === {{{ CREATE OR REPLACE FUNCTION trg_audit_log_changes() RETURNS TRIGGER AS $$ BEGIN IF TG_OP = 'INSERT' THEN INSERT INTO project.audit_log (user_id, action, entity_name) VALUES (NEW.user_id, 'CREATE_ORDER', 'ORDERS'); ELSIF TG_OP = 'UPDATE' THEN INSERT INTO project.audit_log (user_id, action, entity_name) VALUES (NEW.user_id, 'UPDATE_ORDER', 'ORDERS'); ELSIF TG_OP = 'DELETE' THEN INSERT INTO project.audit_log (user_id, action, entity_name) VALUES (OLD.user_id, 'DELETE_ORDER', 'ORDERS'); END IF; RETURN COALESCE(NEW, OLD); END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_audit_orders AFTER INSERT OR UPDATE OR DELETE ON project.orders FOR EACH ROW EXECUTE FUNCTION trg_audit_log_changes(); }}}