Changes between Initial Version and Version 1 of Trigger3


Ignore:
Timestamp:
01/03/26 05:45:58 (2 months ago)
Author:
211101
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Trigger3

    v1 v1  
     1= Контрола на баланс со дозволен лимит за тип на акаунт
     2
     3==== Опис
     4
     5Овој тригер овозможува напредна валидација на трансакции со цел да се спречи надминување на дозволениот лимит на трансакциска сметка, при што:
     6- се поддржува дозволен лимит и наместо фиксна граница (0), тригерот користи параметаризиран лимит, кој се дефинира при креирање на тригерот
     7- се обработува edge case кога при `UPDATE` се менува трансакцискиот акаунт
     8- се применува различна логика во зависност од типот на акаунт
     9- типот на акаунтот не е експлицитен атрибут, туку се утврдува преку името на акаунтот, кое мора да го содржи типот (пример: Cash Wallet, Credit Card VISA, Forex EUR Account)
     10
     11Тригерот се извршува само ако името на акаунтот го содржи типот проследен како аргумент пред внесување или ажурирање на помошна трансакција
     12
     13Пример:
     14- кеш сметки → лимит 0
     15- кредитни сметки → лимит -10000
     16
     17==== Табели опфатени со тригерот
     18- `transaction_account`
     19- `transaction_breakdown`
     20
     21==== Тип на тригер
     22- **BEFORE INSERT
     23- **BEFORE UPDATE
     24Активиран над табелата `transaction_breakdown`
     25
     26==== Поддржани типови на акаунти
     27|| //Тип на акаунт || //Пример име || //Логика ||
     28|| **CASH || Cash, Cash Wallet, Cash MKD || Не е дозволен негативен баланс ||
     29|| **DEBIT || Debit Account || Не е дозволен негативен баланс ||
     30|| **CREDIT || Credit Card VISA, Credit Card Gold || Дозволен негативен баланс до дефиниран лимит ||
     31|| **FOREX || Forex EUR, FX USD || Дозволен негативен баланс до дефиниран лимит ||
     32
     33==== Параметри на тригерот
     34|| //Параметар || //Опис ||
     35|| **`TG_ARGV[0]` || Тип на акаунт (пример: cash, credit, debit, forex) ||
     36|| **`TG_ARGV[1]` || Дозволен минимален баланс (лимит) ||
     37
     38==== SQL код
     39{{{#!sql
     40CREATE OR REPLACE FUNCTION enforce_account_limit_by_name()
     41RETURNS TRIGGER
     42LANGUAGE plpgsql
     43AS $$
     44DECLARE
     45    allowed_type TEXT;
     46    allowed_limit NUMERIC;
     47
     48    old_balance NUMERIC;
     49    new_balance NUMERIC;
     50
     51    old_account_name TEXT;
     52    new_account_name TEXT;
     53BEGIN
     54    allowed_type  := LOWER(TG_ARGV[0]);
     55    allowed_limit := TG_ARGV[1]::NUMERIC;
     56
     57    -- ===============================
     58    -- INSERT
     59    -- ===============================
     60    IF TG_OP = 'INSERT' THEN
     61        SELECT account_name, balance
     62        INTO new_account_name, new_balance
     63        FROM transaction_account
     64        WHERE transaction_account_id = NEW.transaction_account_id;
     65
     66        IF LOWER(new_account_name) LIKE '%' || allowed_type || '%' THEN
     67            new_balance := new_balance
     68                           + COALESCE(NEW.earned_amount, 0)
     69                           - COALESCE(NEW.spent_amount, 0);
     70
     71            IF new_balance < allowed_limit THEN
     72                RAISE EXCEPTION
     73                    'The limit for the % account has been exceeded! Balance: %, limit: %',
     74                    allowed_type, new_balance, allowed_limit;
     75            END IF;
     76        END IF;
     77
     78        RETURN NEW;
     79    END IF;
     80
     81    -- ===============================
     82    -- UPDATE
     83    -- ===============================
     84    IF TG_OP = 'UPDATE' THEN
     85
     86        -- Читање на стар и нов акаунт
     87        SELECT account_name, balance
     88        INTO old_account_name, old_balance
     89        FROM transaction_account
     90        WHERE transaction_account_id = OLD.transaction_account_id;
     91
     92        SELECT account_name, balance
     93        INTO new_account_name, new_balance
     94        FROM transaction_account
     95        WHERE transaction_account_id = NEW.transaction_account_id;
     96
     97        -- Проверка на стариот акаунт (rollback ефект)
     98        IF LOWER(old_account_name) LIKE '%' || allowed_type || '%' THEN
     99            old_balance := old_balance
     100                           - COALESCE(OLD.earned_amount, 0)
     101                           + COALESCE(OLD.spent_amount, 0);
     102
     103            IF old_balance < allowed_limit THEN
     104                RAISE EXCEPTION
     105                    'The limit for the % account has been exceeded during rollback! Balance: %, limit: %',
     106                    allowed_type, old_balance, allowed_limit;
     107            END IF;
     108        END IF;
     109
     110        -- Проверка на новиот акаунт (apply нов ефект)
     111        IF LOWER(new_account_name) LIKE '%' || allowed_type || '%' THEN
     112            new_balance := new_balance
     113                           + COALESCE(NEW.earned_amount, 0)
     114                           - COALESCE(NEW.spent_amount, 0);
     115
     116            IF new_balance < allowed_limit THEN
     117                RAISE EXCEPTION
     118                    'The limit for the % account has been exceeded during updation! Balance: %, limit: %',
     119                    allowed_type, new_balance, allowed_limit;
     120            END IF;
     121        END IF;
     122
     123        RETURN NEW;
     124    END IF;
     125
     126    RETURN NEW;
     127END;
     128$$;
     129}}}
     130
     131===== Креирање на тригерите:
     132
     133- Кеш акаунти (без дозволен минус)
     134{{{#!sql
     135CREATE TRIGGER trg_cash_account_limit
     136BEFORE INSERT OR UPDATE
     137ON transaction_breakdown
     138FOR EACH ROW
     139EXECUTE FUNCTION enforce_account_limit_by_name('cash', 0);
     140}}}
     141
     142- Кредитни акаунти (дозволен минус до -10000)
     143{{{#!sql
     144CREATE TRIGGER trg_credit_account_limit
     145BEFORE INSERT OR UPDATE
     146ON transaction_breakdown
     147FOR EACH ROW
     148EXECUTE FUNCTION enforce_account_limit_by_name('credit', -10000);
     149}}}
     150
     151- Дебитни акаунти (без дозволен минус)
     152{{{#!sql
     153CREATE TRIGGER trg_debit_account_limit
     154BEFORE INSERT OR UPDATE
     155ON transaction_breakdown
     156FOR EACH ROW
     157EXECUTE FUNCTION enforce_account_limit_by_name('debit', 0);
     158}}}
     159
     160- Forex акаунти (дозволен минус до -1000)
     161{{{#!sql
     162CREATE TRIGGER trg_forex_account_limit
     163BEFORE INSERT OR UPDATE
     164ON transaction_breakdown
     165FOR EACH ROW
     166EXECUTE FUNCTION enforce_account_limit_by_name('forex', -1000);
     167}}}
     168
     169==== Објаснување на логиката
     170
     171Типот на акаунтот се утврдува со пребарување во `account_name`, се користи `LIKE %type%` за флексибилност
     172
     173При `UPDATE`:
     174- се проверува стариот акаунт (rollback)
     175- потоа новиот акаунт (apply)
     176
     177Лимитот се применува само ако типот се совпаѓа
     178
     179Дозволениот лимит се проследува како аргумент на тригерот, функцијата ја чита вредноста преку `TG_ARGV`, балансот се пресметува пред реалното запишување, доколку се надмине лимитот → трансакцијата се блокира
     180
     181Овој пристап овозможува флексибилна и повторно употреблива логика
     182
     183==== Причина за користење
     184- Поддршка за различни типови сметки
     185- Централизирана контрола на бизнис логика
     186- Избегнување "hardcoded" вредности
     187- Лесна промена без измена на кодот