--================================================================================================================ -- FUNCTIONS --================================================================================================================ -- 1. Конверзија на валути CREATE OR REPLACE FUNCTION fn_convert_currency( p_from_curr INT, p_to_curr INT, p_amount DECIMAL(20, 2), p_date DATE DEFAULT CURRENT_DATE ) RETURNS DECIMAL(20, 2) AS $$ DECLARE v_rate DECIMAL(15, 6); BEGIN IF p_from_curr = p_to_curr THEN RETURN p_amount; END IF; SELECT (er_to.rate / er_from.rate) INTO v_rate FROM Exchange_rate er_from JOIN Exchange_rate er_to ON er_to.currency_id = p_to_curr AND er_to.date_updated = p_date WHERE er_from.currency_id = p_from_curr AND er_from.date_updated = p_date; IF v_rate IS NULL THEN RAISE EXCEPTION 'Nema kurs za %', p_date; END IF; RETURN ROUND(p_amount * v_rate, 2); END; $$ LANGUAGE plpgsql; -- 2. Проверка дали сметка е активна CREATE OR REPLACE FUNCTION fn_is_account_eligible(p_account_id INT) RETURNS BOOLEAN AS $$ DECLARE v_acc_status VARCHAR(20); v_client_status VARCHAR(20); BEGIN SELECT a.status, c.status INTO v_acc_status, v_client_status FROM Account a JOIN Client c ON a.client_id = c.client_id WHERE a.account_id = p_account_id; IF NOT FOUND THEN RETURN FALSE; END IF; RETURN (v_acc_status = 'ACTIVE' AND v_client_status = 'ACTIVE'); END; $$ LANGUAGE plpgsql; -- 3. Враќа вкупен неплатен долг на клиент (сума на сите PENDING/LATE рати) CREATE OR REPLACE FUNCTION fn_get_client_total_debt(p_client_id INT) RETURNS DECIMAL(20, 2) AS $$ DECLARE v_total DECIMAL(20, 2); BEGIN SELECT COALESCE(SUM(li.amount), 0) INTO v_total FROM Loan_installment li JOIN Loan l ON li.loan_id = l.loan_id WHERE l.client_id = p_client_id AND li.status IN ('PENDING', 'LATE') AND l.status = 'APPROVED'; RETURN v_total; END; $$ LANGUAGE plpgsql; -- сите кредити на клиент SELECT fn_get_client_total_debt(318290); -- 4. Враќа преостаната сума за отплата на кредит CREATE OR REPLACE FUNCTION fn_get_loan_remaining_amount(p_loan_id INT) RETURNS TABLE ( loan_id INT, total_amount DECIMAL(15, 2), paid_amount DECIMAL(15, 2), remaining_amount DECIMAL(15, 2), late_count INT, pending_count INT ) AS $$ BEGIN RETURN QUERY SELECT l.loan_id, l.amount, COALESCE(SUM(li.amount) FILTER (WHERE li.status = 'PAID'), 0)::DECIMAL(15, 2), COALESCE(SUM(li.amount) FILTER (WHERE li.status != 'PAID'), 0)::DECIMAL(15, 2), COUNT(*) FILTER (WHERE li.status = 'LATE')::INT, COUNT(*) FILTER (WHERE li.status = 'PENDING')::INT FROM Loan l JOIN Loan_installment li ON l.loan_id = li.loan_id WHERE l.loan_id = p_loan_id GROUP BY l.loan_id, l.amount; IF NOT FOUND THEN RAISE EXCEPTION 'Кредитот со ID % не постои.', p_loan_id; END IF; END; $$ LANGUAGE plpgsql; SELECT * FROM fn_get_loan_remaining_amount(86961); -- 5. Го пресметува очекуваниот износ на камата за штедна сметка за даден период CREATE OR REPLACE FUNCTION fn_calculate_savings_interest( p_account_id INT, p_period_start DATE, p_period_end DATE ) RETURNS DECIMAL(20, 2) AS $$ DECLARE v_balance DECIMAL(20, 2); v_interest_rate DECIMAL(5, 2); v_interest_period VARCHAR(20); v_capitalization VARCHAR(20); v_days INT; v_result DECIMAL(20, 2); BEGIN SELECT a.balance, sa.interest_rate, sa.interest_period, sa.capitalization_type INTO v_balance, v_interest_rate, v_interest_period, v_capitalization FROM Account a JOIN SavingsAccount sa ON a.account_id = sa.account_id WHERE a.account_id = p_account_id; IF NOT FOUND THEN RAISE EXCEPTION 'Сметка % не е штедна сметка или не постои.', p_account_id; END IF; v_days := (p_period_end - p_period_start); IF v_capitalization = 'SIMPLE' THEN -- Проста камата: P * r * t v_result := v_balance * (v_interest_rate / 100.0) * (v_days / 365.0); ELSE -- Сложена камата: P * (1 + r)^t - P v_result := v_balance * ( POWER(1 + (v_interest_rate / 100.0), v_days / 365.0) - 1 ); END IF; RETURN ROUND(v_result, 2); END; $$ LANGUAGE plpgsql; SELECT fn_calculate_savings_interest(1001, '2026-04-01', '2026-04-30');