120 lines
4.4 KiB
PL/PgSQL
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();
|