wiki:Trigger3

Version 1 (modified by 211101, 11 hours ago) ( diff )

--

Контрола на баланс со дозволен лимит за тип на акаунт

Опис

Овој тригер овозможува напредна валидација на трансакции со цел да се спречи надминување на дозволениот лимит на трансакциска сметка, при што:

  • се поддржува дозволен лимит и наместо фиксна граница (0), тригерот користи параметаризиран лимит, кој се дефинира при креирање на тригерот
  • се обработува edge case кога при UPDATE се менува трансакцискиот акаунт
  • се применува различна логика во зависност од типот на акаунт
  • типот на акаунтот не е експлицитен атрибут, туку се утврдува преку името на акаунтот, кое мора да го содржи типот (пример: Cash Wallet, Credit Card VISA, Forex EUR Account)

Тригерот се извршува само ако името на акаунтот го содржи типот проследен како аргумент пред внесување или ажурирање на помошна трансакција

Пример:

  • кеш сметки → лимит 0
  • кредитни сметки → лимит -10000

Табели опфатени со тригерот

  • transaction_account
  • transaction_breakdown

Тип на тригер

  • BEFORE INSERT
  • BEFORE UPDATE

Активиран над табелата transaction_breakdown

Поддржани типови на акаунти

Тип на акаунт Пример име Логика
CASH Cash, Cash Wallet, Cash MKD Не е дозволен негативен баланс
DEBIT Debit Account Не е дозволен негативен баланс
CREDIT Credit Card VISA, Credit Card Gold Дозволен негативен баланс до дефиниран лимит
FOREX Forex EUR, FX USD Дозволен негативен баланс до дефиниран лимит

Параметри на тригерот

Параметар Опис
TG_ARGV[0] Тип на акаунт (пример: cash, credit, debit, forex)
TG_ARGV[1] Дозволен минимален баланс (лимит)

SQL код

CREATE OR REPLACE FUNCTION enforce_account_limit_by_name()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
DECLARE
    allowed_type TEXT;
    allowed_limit NUMERIC;

    old_balance NUMERIC;
    new_balance NUMERIC;

    old_account_name TEXT;
    new_account_name TEXT;
BEGIN
    allowed_type  := LOWER(TG_ARGV[0]);
    allowed_limit := TG_ARGV[1]::NUMERIC;

    -- ===============================
    -- INSERT
    -- ===============================
    IF TG_OP = 'INSERT' THEN
        SELECT account_name, balance
        INTO new_account_name, new_balance
        FROM transaction_account
        WHERE transaction_account_id = NEW.transaction_account_id;

        IF LOWER(new_account_name) LIKE '%' || allowed_type || '%' THEN
            new_balance := new_balance
                           + COALESCE(NEW.earned_amount, 0)
                           - COALESCE(NEW.spent_amount, 0);

            IF new_balance < allowed_limit THEN
                RAISE EXCEPTION
                    'The limit for the % account has been exceeded! Balance: %, limit: %',
                    allowed_type, new_balance, allowed_limit;
            END IF;
        END IF;

        RETURN NEW;
    END IF;

    -- ===============================
    -- UPDATE
    -- ===============================
    IF TG_OP = 'UPDATE' THEN

        -- Читање на стар и нов акаунт
        SELECT account_name, balance
        INTO old_account_name, old_balance
        FROM transaction_account
        WHERE transaction_account_id = OLD.transaction_account_id;

        SELECT account_name, balance
        INTO new_account_name, new_balance
        FROM transaction_account
        WHERE transaction_account_id = NEW.transaction_account_id;

        -- Проверка на стариот акаунт (rollback ефект)
        IF LOWER(old_account_name) LIKE '%' || allowed_type || '%' THEN
            old_balance := old_balance
                           - COALESCE(OLD.earned_amount, 0)
                           + COALESCE(OLD.spent_amount, 0);

            IF old_balance < allowed_limit THEN
                RAISE EXCEPTION
                    'The limit for the % account has been exceeded during rollback! Balance: %, limit: %',
                    allowed_type, old_balance, allowed_limit;
            END IF;
        END IF;

        -- Проверка на новиот акаунт (apply нов ефект)
        IF LOWER(new_account_name) LIKE '%' || allowed_type || '%' THEN
            new_balance := new_balance
                           + COALESCE(NEW.earned_amount, 0)
                           - COALESCE(NEW.spent_amount, 0);

            IF new_balance < allowed_limit THEN
                RAISE EXCEPTION
                    'The limit for the % account has been exceeded during updation! Balance: %, limit: %',
                    allowed_type, new_balance, allowed_limit;
            END IF;
        END IF;

        RETURN NEW;
    END IF;

    RETURN NEW;
END;
$$;
Креирање на тригерите:
  • Кеш акаунти (без дозволен минус)
    CREATE TRIGGER trg_cash_account_limit
    BEFORE INSERT OR UPDATE
    ON transaction_breakdown
    FOR EACH ROW
    EXECUTE FUNCTION enforce_account_limit_by_name('cash', 0);
    
  • Кредитни акаунти (дозволен минус до -10000)
    CREATE TRIGGER trg_credit_account_limit
    BEFORE INSERT OR UPDATE
    ON transaction_breakdown
    FOR EACH ROW
    EXECUTE FUNCTION enforce_account_limit_by_name('credit', -10000);
    
  • Дебитни акаунти (без дозволен минус)
    CREATE TRIGGER trg_debit_account_limit
    BEFORE INSERT OR UPDATE
    ON transaction_breakdown
    FOR EACH ROW
    EXECUTE FUNCTION enforce_account_limit_by_name('debit', 0);
    
  • Forex акаунти (дозволен минус до -1000)
    CREATE TRIGGER trg_forex_account_limit
    BEFORE INSERT OR UPDATE
    ON transaction_breakdown
    FOR EACH ROW
    EXECUTE FUNCTION enforce_account_limit_by_name('forex', -1000);
    

Објаснување на логиката

Типот на акаунтот се утврдува со пребарување во account_name, се користи LIKE %type% за флексибилност

При UPDATE:

  • се проверува стариот акаунт (rollback)
  • потоа новиот акаунт (apply)

Лимитот се применува само ако типот се совпаѓа

Дозволениот лимит се проследува како аргумент на тригерот, функцијата ја чита вредноста преку TG_ARGV, балансот се пресметува пред реалното запишување, доколку се надмине лимитот → трансакцијата се блокира

Овој пристап овозможува флексибилна и повторно употреблива логика

Причина за користење

  • Поддршка за различни типови сметки
  • Централизирана контрола на бизнис логика
  • Избегнување "hardcoded" вредности
  • Лесна промена без измена на кодот
Note: See TracWiki for help on using the wiki.