Testy pro Total-solutions

stránka pro testování přístupu k externím stránkám


```
-- Vytvoření tabulek
CREATE TABLE clients (
    client_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name VARCHAR2(100) NOT NULL,
    email VARCHAR2(100) UNIQUE NOT NULL,
    created_at DATE DEFAULT SYSDATE,
    status VARCHAR2(10) DEFAULT 'ACTIVE' CHECK (status IN ('ACTIVE', 'BLOCKED'))
);

CREATE TABLE accounts (
    account_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    client_id NUMBER NOT NULL,
    currency VARCHAR2(3) DEFAULT 'CZK' NOT NULL,
    balance NUMBER(18,2) DEFAULT 0 NOT NULL,
    created_at DATE DEFAULT SYSDATE,
    closed_at DATE,
    CONSTRAINT fk_client_id FOREIGN KEY (client_id) REFERENCES clients(client_id)
);

CREATE TABLE transactions (
    tx_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    account_id NUMBER NOT NULL,
    tx_type VARCHAR2(10) NOT NULL CHECK (tx_type IN ('DEPOSIT', 'WITHDRAW', 'TRANSFER')),
    amount NUMBER(18,2) NOT NULL,
    tx_timestamp DATE DEFAULT SYSDATE,
    reference VARCHAR2(50),
    related_tx_id NUMBER,
    CONSTRAINT fk_account_id FOREIGN KEY (account_id) REFERENCES accounts(account_id),
    CONSTRAINT fk_related_tx_id FOREIGN KEY (related_tx_id) REFERENCES transactions(tx_id)
);

CREATE TABLE account_balance_history (
    history_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    account_id NUMBER NOT NULL,
    balance_before NUMBER(18,2),
    balance_after NUMBER(18,2),
    tx_id NUMBER NOT NULL,
    change_timestamp DATE DEFAULT SYSDATE,
    CONSTRAINT fk_history_account_id FOREIGN KEY (account_id) REFERENCES accounts(account_id),
    CONSTRAINT fk_history_tx_id FOREIGN KEY (tx_id) REFERENCES transactions(tx_id)
);

CREATE TABLE transaction_audit_log (
    log_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    tx_id NUMBER NOT NULL,
    operation_type VARCHAR2(20) NOT NULL,
    operation_timestamp DATE DEFAULT SYSDATE,
    user_info VARCHAR2(100),
    details CLOB,
    CONSTRAINT fk_audit_tx_id FOREIGN KEY (tx_id) REFERENCES transactions(tx_id)
);

CREATE TABLE error_log (
    error_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    error_timestamp DATE DEFAULT SYSDATE,
    error_code NUMBER,
    error_message VARCHAR2(4000),
    error_stack VARCHAR2(4000),
    module_name VARCHAR2(100),
    procedure_name VARCHAR2(100)
);

-- Vytvoření indexů
CREATE INDEX i_accounts_client_id ON accounts(client_id) TABLESPACE index_data;
CREATE INDEX i_transactions_account_id ON transactions(account_id) TABLESPACE index_data;
CREATE INDEX i_transactions_timestamp ON transactions(tx_timestamp) TABLESPACE index_data;
CREATE INDEX i_transactions_type ON transactions(tx_type) TABLESPACE index_data;
CREATE INDEX i_accounts_currency ON accounts(currency) TABLESPACE index_data;
CREATE INDEX i_accounts_created_at ON accounts(created_at) TABLESPACE index_data;

-- Balíček validací
CREATE OR REPLACE PACKAGE pkg_validation AS
    -- Vlastní výjimky
    invalid_account EXCEPTION;
    insufficient_funds EXCEPTION;
    invalid_amount EXCEPTION;
    account_closed EXCEPTION;
    
    -- Funkce pro validaci
    FUNCTION validate_account(p_account_id NUMBER) RETURN BOOLEAN;
    FUNCTION validate_amount(p_amount NUMBER) RETURN BOOLEAN;
    FUNCTION validate_account_status(p_account_id NUMBER) RETURN BOOLEAN;
    FUNCTION validate_transfer_amount(p_account_id NUMBER, p_amount NUMBER) RETURN BOOLEAN;
END pkg_validation;
/

CREATE OR REPLACE PACKAGE BODY pkg_validation AS
    FUNCTION validate_account(p_account_id NUMBER) RETURN BOOLEAN IS
        l_count NUMBER;
    BEGIN
        SELECT COUNT(*) INTO l_count FROM accounts WHERE account_id = p_account_id;
        RETURN l_count > 0;
    EXCEPTION
        WHEN OTHERS THEN
            RAISE_APPLICATION_ERROR(-20001, 'Chyba při validaci účtu: ' || SQLERRM);
    END validate_account;
    
    FUNCTION validate_amount(p_amount NUMBER) RETURN BOOLEAN IS
    BEGIN
        RETURN p_amount > 0;
    EXCEPTION
        WHEN OTHERS THEN
            RAISE_APPLICATION_ERROR(-20002, 'Chyba při validaci částky: ' || SQLERRM);
    END validate_amount;
    
    FUNCTION validate_account_status(p_account_id NUMBER) RETURN BOOLEAN IS
        l_status VARCHAR2(10);
    BEGIN
        SELECT status INTO l_status FROM accounts WHERE account_id = p_account_id;
        RETURN l_status = 'ACTIVE';
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            RAISE invalid_account;
        WHEN TOO_MANY_ROWS THEN
            RAISE_APPLICATION_ERROR(-20003, 'Nalezeno více účtů');
        WHEN OTHERS THEN
            RAISE_APPLICATION_ERROR(-20004, 'Chyba při validaci stavu účtu: ' || SQLERRM);
    END validate_account_status;
    
    FUNCTION validate_transfer_amount(p_account_id NUMBER, p_amount NUMBER) RETURN BOOLEAN IS
        l_balance NUMBER;
    BEGIN
        SELECT balance INTO l_balance FROM accounts WHERE account_id = p_account_id;
        RETURN l_balance >= p_amount;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            RAISE invalid_account;
        WHEN TOO_MANY_ROWS THEN
            RAISE_APPLICATION_ERROR(-20005, 'Nalezeno více účtů');
        WHEN OTHERS THEN
            RAISE_APPLICATION_ERROR(-20006, 'Chyba při validaci částky pro převod: ' || SQLERRM);
    END validate_transfer_amount;
END pkg_validation;
/

-- Balíček operací s účty
CREATE OR REPLACE PACKAGE pkg_account_ops AS
    -- Vlastní výjimky
    account_not_found EXCEPTION;
    insufficient_balance EXCEPTION;
    invalid_transaction_type EXCEPTION;
    
    -- Procedury
    PROCEDURE create_account(p_client_id NUMBER, p_currency VARCHAR2, p_account_id OUT NUMBER);
    PROCEDURE deposit(p_account_id NUMBER, p_amount NUMBER, p_reference VARCHAR2 DEFAULT NULL);
    PROCEDURE withdraw(p_account_id NUMBER, p_amount NUMBER, p_reference VARCHAR2 DEFAULT NULL);
    PROCEDURE transfer(p_from_account NUMBER, p_to_account NUMBER, p_amount NUMBER, p_reference VARCHAR2 DEFAULT NULL);
END pkg_account_ops;
/

CREATE OR REPLACE PACKAGE BODY pkg_account_ops AS
    PROCEDURE create_account(p_client_id NUMBER, p_currency VARCHAR2, p_account_id OUT NUMBER) IS
        l_client_exists NUMBER;
    BEGIN
        -- Validace klienta
        SELECT COUNT(*) INTO l_client_exists FROM clients WHERE client_id = p_client_id;
        IF l_client_exists = 0 THEN
            RAISE_APPLICATION_ERROR(-20007, 'Klient s ID ' || p_client_id || ' neexistuje');
        END IF;
        
        -- Vytvoření účtu
        INSERT INTO accounts (client_id, currency)
        VALUES (p_client_id, p_currency)
        RETURNING account_id INTO p_account_id;
        
        -- Zápis do auditního logu
        INSERT INTO transaction_audit_log (tx_id, operation_type, user_info, details)
        VALUES (NULL, 'CREATE_ACCOUNT', USER, 'Vytvořen účet pro klienta ' || p_client_id);
        
        COMMIT;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            INSERT INTO error_log (error_code, error_message, error_stack, module_name, procedure_name)
            VALUES (SQLCODE, SQLERRM, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, 'pkg_account_ops', 'create_account');
            RAISE;
    END create_account;
    
    PROCEDURE deposit(p_account_id NUMBER, p_amount NUMBER, p_reference VARCHAR2 DEFAULT NULL) IS
        l_balance_before NUMBER;
        l_balance_after NUMBER;
        l_tx_id NUMBER;
    BEGIN
        -- Validace účtu a částky
        IF NOT pkg_validation.validate_account(p_account_id) THEN
            RAISE account_not_found;
        END IF;
        
        IF NOT pkg_validation.validate_amount(p_amount) THEN
            RAISE invalid_transaction_type;
        END IF;
        
        -- Získání aktuálního stavu účtu
        SELECT balance INTO l_balance_before FROM accounts WHERE account_id = p_account_id FOR UPDATE;
        
        -- Výpočet nového stavu
        l_balance_after := l_balance_before + p_amount;
        
        -- Aktualizace účtu
        UPDATE accounts SET balance = l_balance_after WHERE account_id = p_account_id;
        
        -- Vložení transakce
        INSERT INTO transactions (account_id, tx_type, amount, reference)
        VALUES (p_account_id, 'DEPOSIT', p_amount, p_reference)
        RETURNING tx_id INTO l_tx_id;
        
        -- Zápis do historie
        INSERT INTO account_balance_history (account_id, balance_before, balance_after, tx_id)
        VALUES (p_account_id, l_balance_before, l_balance_after, l_tx_id);
        
        -- Zápis do auditního logu
        INSERT INTO transaction_audit_log (tx_id, operation_type, user_info, details)
        VALUES (l_tx_id, 'DEPOSIT', USER, 'Vklad ' || p_amount || ' na účet ' || p_account_id);
        
        COMMIT;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            INSERT INTO error_log (error_code, error_message, error_stack, module_name, procedure_name)
            VALUES (SQLCODE, SQLERRM, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, 'pkg_account_ops', 'deposit');
            RAISE;
    END deposit;
    
    PROCEDURE withdraw(p_account_id NUMBER, p_amount NUMBER, p_reference VARCHAR2 DEFAULT NULL) IS
        l_balance_before NUMBER;
        l_balance_after NUMBER;
        l_tx_id NUMBER;
    BEGIN
        -- Validace účtu a částky
        IF NOT pkg_validation.validate_account(p_account_id) THEN
            RAISE account_not_found;
        END IF;
        
        IF NOT pkg_validation.validate_amount(p_amount) THEN
            RAISE invalid_transaction_type;
        END IF;
        
        -- Získání aktuálního stavu účtu
        SELECT balance INTO l_balance_before FROM accounts WHERE account_id = p_account_id FOR UPDATE;
        
        -- Kontrola dostatečného stavu
        IF l_balance_before < p_amount THEN
            RAISE insufficient_balance;
        END IF;
        
        -- Výpočet nového stavu
        l_balance_after := l_balance_before - p_amount;
        
        -- Aktualizace účtu
        UPDATE accounts SET balance = l_balance_after WHERE account_id = p_account_id;
        
        -- Vložení transakce
        INSERT INTO transactions (account_id, tx_type, amount, reference)
        VALUES (p_account_id, 'WITHDRAW', p_amount, p_reference)
        RETURNING tx_id INTO l_tx_id;
        
        -- Zápis do historie
        INSERT INTO account_balance_history (account_id, balance_before, balance_after, tx_id)
        VALUES (p_account_id, l_balance_before, l_balance_after, l_tx_id);
        
        -- Zápis do auditního logu
        INSERT INTO transaction_audit_log (tx_id, operation_type, user_info, details)
        VALUES (l_tx_id, 'WITHDRAW', USER, 'Výběr ' || p_amount || ' z účtu ' || p_account_id);
        
        COMMIT;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            INSERT INTO error_log (error_code, error_message, error_stack, module_name, procedure_name)
            VALUES (SQLCODE, SQLERRM, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, 'pkg_account_ops', 'withdraw');
            RAISE;
    END withdraw;
    
    PROCEDURE transfer(p_from_account NUMBER, p_to_account NUMBER, p_amount NUMBER, p_reference VARCHAR2 DEFAULT NULL) IS
        l_balance_before NUMBER;
        l_balance_after NUMBER;
        l_tx_id NUMBER;
        l_tx_id2 NUMBER;
    BEGIN
        -- Validace účtů a částky
        IF NOT pkg_validation.validate_account(p_from_account) THEN
            RAISE account_not_found;
        END IF;
        
        IF NOT pkg_validation.validate_account(p_to_account) THEN
            RAISE account_not_found;
        END IF;
        
        IF NOT pkg_validation.validate_amount(p_amount) THEN
            RAISE invalid_transaction_type;
        END IF;
        
        IF NOT pkg_validation.validate_transfer_amount(p_from_account, p_amount) THEN
            RAISE insufficient_balance;
        END IF;
        
        -- Získání aktuálního stavu účtu
        SELECT balance INTO l_balance_before FROM accounts WHERE account_id = p_from_account FOR UPDATE;
        
        -- Výpočet nového stavu
        l_balance_after := l_balance_before - p_amount;
        
        -- Aktualizace účtu
        UPDATE accounts SET balance = l_balance_after WHERE account_id = p_from_account;
        
        -- Vložení transakce (odesílající účet)
        INSERT INTO transactions (account_id, tx_type, amount, reference, related_tx_id)
        VALUES (p_from_account, 'TRANSFER', p_amount, p_reference, NULL)
        RETURNING tx_id INTO l_tx_id;
        
        -- Zápis do historie
        INSERT INTO account_balance_history (account_id, balance_before, balance_after, tx_id)
        VALUES (p_from_account, l_balance_before, l_balance_after, l_tx_id);
        
        -- Získání aktuálního stavu přijímajícího účtu
        SELECT balance INTO l_balance_before FROM accounts WHERE account_id = p_to_account FOR UPDATE;
        
        -- Výpočet nového stavu
        l_balance_after := l_balance_before + p_amount;
        
        -- Aktualizace účtu
        UPDATE accounts SET balance = l_balance_after WHERE account_id = p_to_account;
        
        -- Vložení transakce (přijímající účet)
        INSERT INTO transactions (account_id, tx_type, amount, reference, related_tx_id)
        VALUES (p_to_account, 'TRANSFER', p_amount, p_reference, l_tx_id)
        RETURNING tx_id INTO l_tx_id2;
        
        -- Zápis do historie
        INSERT INTO account_balance_history (account_id, balance_before, balance_after, tx_id)
        VALUES (p_to_account, l_balance_before, l_balance_after, l_tx_id2);
        
        -- Aktualizace vztahu mezi transakcemi
        UPDATE transactions SET related_tx_id = l_tx_id2 WHERE tx_id = l_tx_id;
        
        -- Zápis do auditního logu
        INSERT INTO transaction_audit_log (tx_id, operation_type, user_info, details)
        VALUES (l_tx_id, 'TRANSFER', USER, 'Převod ' || p_amount || ' z účtu ' || p_from_account || ' na účet ' || p_to_account);
        
        COMMIT;
        
    EXCEPTION
        WHEN OTHERS THEN
            ROLLBACK;
            INSERT INTO error_log (error_code, error_message, error_stack, module_name, procedure_name)
            VALUES (SQLCODE, SQLERRM, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, 'pkg_account_ops', 'transfer');
            RAISE;
    END transfer;
END pkg_account_ops;
/

-- Balíček pro analytické funkce
CREATE OR REPLACE PACKAGE pkg_reporting AS
    -- Funkce pro analýzu
    FUNCTION get_account_balance_history(p_account_id NUMBER) RETURN SYS_REFCURSOR;
    FUNCTION get_account_transactions_summary(p_account_id NUMBER) RETURN SYS_REFCURSOR;
    FUNCTION get_top_accounts_by_balance(p_limit NUMBER DEFAULT 10) RETURN SYS_REFCURSOR;
    FUNCTION get_transaction_volume_by_date(p_days NUMBER DEFAULT 30) RETURN SYS_REFCURSOR;
END pkg_reporting;
/

CREATE OR REPLACE PACKAGE BODY pkg_reporting AS
    FUNCTION get_account_balance_history(p_account_id NUMBER) RETURN SYS_REFCURSOR IS
        l_cursor SYS_REFCURSOR;
    BEGIN
        OPEN l_cursor FOR
            SELECT h.history_id, h.balance_before, h.balance_after, h.change_timestamp, t.tx_type, t.amount, t.reference
            FROM account_balance_history h
            JOIN transactions t ON h.tx_id = t.tx_id
            WHERE h.account_id = p_account_id
            ORDER BY h.change_timestamp DESC;
        RETURN l_cursor;
    END get_account_balance_history;
    
    FUNCTION get_account_transactions_summary(p_account_id NUMBER) RETURN SYS_REFCURSOR IS
        l_cursor SYS_REFCURSOR;
    BEGIN
        OPEN l_cursor FOR
            SELECT tx_type, COUNT(*) as transaction_count, SUM(amount) as total_amount
            FROM transactions
            WHERE account_id = p_account_id
            GROUP BY tx_type
            ORDER BY tx_type;
        RETURN l_cursor;
    END get_account_transactions_summary;
    
    FUNCTION get_top_accounts_by_balance(p_limit NUMBER DEFAULT 10) RETURN SYS_REFCURSOR IS
        l_cursor SYS_REFCURSOR;
    BEGIN
        OPEN l_cursor FOR
            SELECT account_id, balance
            FROM accounts
            ORDER BY balance DESC
            FETCH FIRST p_limit ROWS ONLY;
        RETURN l_cursor;
    END get_top_accounts_by_balance;
    
    FUNCTION get_transaction_volume_by_date(p_days NUMBER DEFAULT 30) RETURN SYS_REFCURSOR IS
        l_cursor SYS_REFCURSOR;
    BEGIN
        OPEN l_cursor FOR
            SELECT TRUNC(t.transaction_date) as transaction_date, 
                   COUNT(*) as transaction_count, 
                   SUM(t.amount) as total_amount
            FROM transactions t
            WHERE t.transaction_date >= SYSDATE - p_days
            GROUP BY TRUNC(t.transaction_date)
            ORDER BY transaction_date;
        RETURN l_cursor;
    END get_transaction_volume_by_date;
END pkg_reporting;
/

-- Generování testovacích dat
CREATE OR REPLACE PROCEDURE generate_test_data IS
    l_account_id NUMBER;
    l_amount NUMBER;
BEGIN
    -- Vytvoření několika testovacích účtů
    FOR i IN 1..100 LOOP
        INSERT INTO accounts (account_id, balance, created_date)
        VALUES (i, ROUND(DBMS_RANDOM.VALUE(100, 10000), 2), SYSDATE);
        
        -- Vytvoření několika transakcí pro každý účet
        FOR j IN 1..ROUND(DBMS_RANDOM.VALUE(5, 20)) LOOP
            l_amount := ROUND(DBMS_RANDOM.VALUE(10, 1000), 2);
            
            IF DBMS_RANDOM.VALUE < 0.5 THEN
                pkg_account_ops.deposit(i, l_amount, 'Test deposit ' || j);
            ELSE
                pkg_account_ops.withdraw(i, l_amount, 'Test withdrawal ' || j);
            END IF;
        END LOOP;
    END LOOP;
    
    COMMIT;
END generate_test_data;
/

-- Spuštění generování testovacích dat
BEGIN
    generate_test_data;
END;
/

-- Výpočet statistik
CREATE OR REPLACE PROCEDURE calculate_statistics IS
BEGIN
    -- Výpočet celkového počtu transakcí
    DBMS_OUTPUT.PUT_LINE('Total transactions: ' || (SELECT COUNT(*) FROM transactions));
    
    -- Výpočet celkového objemu transakcí
    DBMS_OUTPUT.PUT_LINE('Total transaction volume: ' || (SELECT SUM(amount) FROM transactions));
    
    -- Výpočet průměrného stavu účtu
    DBMS_OUTPUT.PUT_LINE('Average account balance: ' || (SELECT AVG(balance) FROM accounts));
    
    -- Výpočet počtu účtů
    DBMS_OUTPUT.PUT_LINE('Total accounts: ' || (SELECT COUNT(*) FROM accounts));
END calculate_statistics;
/

-- Spuštění statistik
BEGIN
    calculate_statistics;
END;
/

-- Zobrazení výsledků
SELECT * FROM accounts WHERE account_id <= 5;
SELECT * FROM transactions WHERE account_id <= 5 ORDER BY transaction_date DESC;
SELECT * FROM account_balance_history WHERE account_id <= 5 ORDER BY change_timestamp DESC;

-- Zobrazení výsledků z analytických funkcí
DECLARE
    l_cursor SYS_REFCURSOR;
BEGIN
    -- Získání historie pro první účet
    l_cursor := pkg_reporting.get_account_balance_history(1);
    DBMS_OUTPUT.PUT_LINE('Account 1 balance history:');
    -- Zde by bylo možné zpracovat cursor
    
    -- Získání shrnutí transakcí pro první účet
    l_cursor := pkg_reporting.get_account_transactions_summary(1);
    DBMS_OUTPUT.PUT_LINE('Account 1 transaction summary:');
    -- Zde by bylo možné zpracovat cursor
    
    -- Získání top účtů
    l_cursor := pkg_reporting.get_top_accounts_by_balance(5);
    DBMS_OUTPUT.PUT_LINE('Top 5 accounts by balance:');
    -- Zde by bylo možné zpracovat cursor
END;
/
```