trading-platform-database/ddl/schemas/investment/tables/06-withdrawal_requests.sql

120 lines
4.4 KiB
PL/PgSQL

-- ============================================================================
-- INVESTMENT SCHEMA - Tabla: withdrawal_requests
-- ============================================================================
-- Solicitudes de retiro de cuentas PAMM
-- Requiere aprobacion manual para montos grandes
-- ============================================================================
-- Enum para estado de solicitud
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'withdrawal_status' AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'investment')) THEN
CREATE TYPE investment.withdrawal_status AS ENUM (
'pending',
'under_review',
'approved',
'processing',
'completed',
'rejected',
'cancelled'
);
END IF;
END$$;
CREATE TABLE IF NOT EXISTS investment.withdrawal_requests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Relaciones
account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE RESTRICT,
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT,
-- Solicitud
request_number VARCHAR(20) NOT NULL UNIQUE,
amount DECIMAL(20, 8) NOT NULL,
currency VARCHAR(10) NOT NULL DEFAULT 'USD',
-- Estado
status investment.withdrawal_status NOT NULL DEFAULT 'pending',
-- Destino del retiro
destination_type VARCHAR(20) NOT NULL, -- 'wallet', 'bank', 'crypto'
destination_details JSONB NOT NULL DEFAULT '{}',
-- Fees
fee_amount DECIMAL(20, 8) NOT NULL DEFAULT 0,
fee_percentage DECIMAL(5, 2) NOT NULL DEFAULT 0,
net_amount DECIMAL(20, 8) GENERATED ALWAYS AS (amount - fee_amount) STORED,
-- Aprobacion
requires_approval BOOLEAN NOT NULL DEFAULT FALSE,
reviewed_by UUID REFERENCES auth.users(id),
reviewed_at TIMESTAMPTZ,
review_notes TEXT,
-- Procesamiento
processed_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
transaction_reference VARCHAR(100),
-- Rechazo/Cancelacion
rejection_reason TEXT,
cancelled_at TIMESTAMPTZ,
cancellation_reason TEXT,
-- Metadata
ip_address INET,
user_agent TEXT,
metadata JSONB DEFAULT '{}',
-- Timestamps
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- Constraints
CONSTRAINT chk_positive_amount CHECK (amount > 0),
CONSTRAINT chk_valid_fee CHECK (fee_amount >= 0 AND fee_amount <= amount),
CONSTRAINT chk_fee_percentage CHECK (fee_percentage >= 0 AND fee_percentage <= 100),
CONSTRAINT chk_destination_type CHECK (destination_type IN ('wallet', 'bank', 'crypto'))
);
-- Indices
CREATE INDEX idx_withdrawal_requests_account ON investment.withdrawal_requests(account_id);
CREATE INDEX idx_withdrawal_requests_user ON investment.withdrawal_requests(user_id);
CREATE INDEX idx_withdrawal_requests_status ON investment.withdrawal_requests(status);
CREATE INDEX idx_withdrawal_requests_created ON investment.withdrawal_requests(created_at DESC);
CREATE INDEX idx_withdrawal_requests_pending ON investment.withdrawal_requests(status, created_at)
WHERE status IN ('pending', 'under_review');
-- Comentarios
COMMENT ON TABLE investment.withdrawal_requests IS 'Solicitudes de retiro de cuentas PAMM';
COMMENT ON COLUMN investment.withdrawal_requests.request_number IS 'Numero unico de solicitud (WR-YYYYMMDD-XXXX)';
COMMENT ON COLUMN investment.withdrawal_requests.requires_approval IS 'True si el monto requiere aprobacion manual';
COMMENT ON COLUMN investment.withdrawal_requests.destination_details IS 'Detalles del destino (IBAN, wallet address, etc.)';
-- Funcion para generar numero de solicitud
CREATE OR REPLACE FUNCTION investment.generate_withdrawal_request_number()
RETURNS TRIGGER AS $$
DECLARE
v_date TEXT;
v_seq INTEGER;
BEGIN
v_date := TO_CHAR(NOW(), 'YYYYMMDD');
SELECT COALESCE(MAX(
CAST(SUBSTRING(request_number FROM 'WR-[0-9]{8}-([0-9]+)') AS INTEGER)
), 0) + 1
INTO v_seq
FROM investment.withdrawal_requests
WHERE request_number LIKE 'WR-' || v_date || '-%';
NEW.request_number := 'WR-' || v_date || '-' || LPAD(v_seq::TEXT, 4, '0');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_generate_withdrawal_request_number
BEFORE INSERT ON investment.withdrawal_requests
FOR EACH ROW
WHEN (NEW.request_number IS NULL)
EXECUTE FUNCTION investment.generate_withdrawal_request_number();