trading-platform-database-v2/ddl/schemas/financial/functions/04-views.sql
rckrdmrd 45e77e9a9c feat: Initial commit - Database schemas and scripts
DDL schemas for Trading Platform:
- User management
- Authentication
- Payments
- Education
- ML predictions
- Trading data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 04:30:23 -06:00

259 lines
8.3 KiB
SQL

-- =====================================================
-- ORBIQUANT IA - FINANCIAL SCHEMA VIEWS
-- =====================================================
-- Description: Useful views for common financial queries
-- Schema: financial
-- =====================================================
-- =====================================================
-- VIEW: Active user wallets summary
-- =====================================================
CREATE OR REPLACE VIEW financial.v_user_wallets_summary AS
SELECT
w.user_id,
w.wallet_type,
w.currency,
w.balance,
w.available_balance,
w.pending_balance,
w.status,
w.last_transaction_at,
w.total_deposits,
w.total_withdrawals,
w.created_at,
-- Transaction counts
(SELECT COUNT(*)
FROM financial.wallet_transactions wt
WHERE wt.wallet_id = w.id AND wt.status = 'completed') as total_transactions,
(SELECT COUNT(*)
FROM financial.wallet_transactions wt
WHERE wt.wallet_id = w.id AND wt.status = 'pending') as pending_transactions,
-- Latest transaction
(SELECT wt.created_at
FROM financial.wallet_transactions wt
WHERE wt.wallet_id = w.id
ORDER BY wt.created_at DESC
LIMIT 1) as last_tx_date
FROM financial.wallets w
WHERE w.status = 'active';
COMMENT ON VIEW financial.v_user_wallets_summary IS 'Active wallets with transaction statistics';
-- =====================================================
-- VIEW: User total balance across all wallets (USD)
-- =====================================================
CREATE OR REPLACE VIEW financial.v_user_total_balance AS
SELECT
user_id,
SUM(CASE WHEN currency = 'USD' THEN balance ELSE 0 END) as total_usd,
SUM(CASE WHEN currency = 'MXN' THEN balance ELSE 0 END) as total_mxn,
SUM(CASE WHEN currency = 'EUR' THEN balance ELSE 0 END) as total_eur,
-- Totals by wallet type
SUM(CASE WHEN wallet_type = 'trading' AND currency = 'USD' THEN balance ELSE 0 END) as trading_usd,
SUM(CASE WHEN wallet_type = 'investment' AND currency = 'USD' THEN balance ELSE 0 END) as investment_usd,
SUM(CASE WHEN wallet_type = 'earnings' AND currency = 'USD' THEN balance ELSE 0 END) as earnings_usd,
SUM(CASE WHEN wallet_type = 'referral' AND currency = 'USD' THEN balance ELSE 0 END) as referral_usd,
COUNT(*) as wallet_count,
MAX(last_transaction_at) as last_activity
FROM financial.wallets
WHERE status = 'active'
GROUP BY user_id;
COMMENT ON VIEW financial.v_user_total_balance IS 'Aggregated balance per user across all wallets';
-- =====================================================
-- VIEW: Recent transactions (last 30 days)
-- =====================================================
CREATE OR REPLACE VIEW financial.v_recent_transactions AS
SELECT
wt.id,
wt.wallet_id,
w.user_id,
w.wallet_type,
wt.transaction_type,
wt.status,
wt.amount,
wt.fee,
wt.net_amount,
wt.currency,
wt.description,
wt.reference_id,
wt.balance_before,
wt.balance_after,
wt.created_at,
wt.completed_at,
-- Days since transaction
EXTRACT(DAY FROM NOW() - wt.created_at) as days_ago
FROM financial.wallet_transactions wt
JOIN financial.wallets w ON w.id = wt.wallet_id
WHERE wt.created_at >= NOW() - INTERVAL '30 days'
ORDER BY wt.created_at DESC;
COMMENT ON VIEW financial.v_recent_transactions IS 'Wallet transactions from last 30 days';
-- =====================================================
-- VIEW: Active subscriptions with user details
-- =====================================================
CREATE OR REPLACE VIEW financial.v_active_subscriptions AS
SELECT
s.id,
s.user_id,
s.plan,
s.status,
s.price,
s.currency,
s.billing_interval,
s.current_period_start,
s.current_period_end,
s.next_payment_at,
s.cancel_at_period_end,
s.stripe_subscription_id,
-- Days until renewal
EXTRACT(DAY FROM s.current_period_end - NOW()) as days_until_renewal,
-- Is in trial
(s.status = 'trialing') as is_trial,
-- Trial days remaining
CASE
WHEN s.trial_end IS NOT NULL THEN EXTRACT(DAY FROM s.trial_end - NOW())
ELSE NULL
END as trial_days_remaining
FROM financial.subscriptions s
WHERE s.status IN ('active', 'trialing', 'past_due')
ORDER BY s.current_period_end ASC;
COMMENT ON VIEW financial.v_active_subscriptions IS 'Active subscriptions with renewal information';
-- =====================================================
-- VIEW: Pending payments
-- =====================================================
CREATE OR REPLACE VIEW financial.v_pending_payments AS
SELECT
p.id,
p.user_id,
p.subscription_id,
p.amount,
p.currency,
p.payment_method,
p.status,
p.description,
p.stripe_payment_intent_id,
p.created_at,
-- Days pending
EXTRACT(DAY FROM NOW() - p.created_at) as days_pending
FROM financial.payments p
WHERE p.status IN ('pending', 'processing')
ORDER BY p.created_at ASC;
COMMENT ON VIEW financial.v_pending_payments IS 'Payments awaiting completion';
-- =====================================================
-- VIEW: Unpaid invoices
-- =====================================================
CREATE OR REPLACE VIEW financial.v_unpaid_invoices AS
SELECT
i.id,
i.user_id,
i.invoice_number,
i.total,
i.amount_due,
i.currency,
i.due_date,
i.status,
i.invoice_date,
i.hosted_invoice_url,
-- Days overdue
CASE
WHEN i.due_date IS NOT NULL AND i.due_date < NOW()
THEN EXTRACT(DAY FROM NOW() - i.due_date)
ELSE 0
END as days_overdue,
-- Is overdue
(i.due_date IS NOT NULL AND i.due_date < NOW()) as is_overdue
FROM financial.invoices i
WHERE i.status = 'open' AND i.paid = false
ORDER BY i.due_date ASC NULLS LAST;
COMMENT ON VIEW financial.v_unpaid_invoices IS 'Open invoices with overdue status';
-- =====================================================
-- VIEW: Daily transaction volume
-- =====================================================
CREATE OR REPLACE VIEW financial.v_daily_transaction_volume AS
SELECT
DATE(wt.created_at) as transaction_date,
wt.transaction_type,
wt.currency,
COUNT(*) as transaction_count,
SUM(wt.amount) as total_amount,
SUM(wt.fee) as total_fees,
SUM(wt.net_amount) as total_net_amount,
AVG(wt.amount) as avg_amount
FROM financial.wallet_transactions wt
WHERE wt.status = 'completed'
AND wt.created_at >= NOW() - INTERVAL '90 days'
GROUP BY DATE(wt.created_at), wt.transaction_type, wt.currency
ORDER BY transaction_date DESC, transaction_type;
COMMENT ON VIEW financial.v_daily_transaction_volume IS 'Daily aggregated transaction statistics';
-- =====================================================
-- VIEW: Wallet activity summary (last 7 days)
-- =====================================================
CREATE OR REPLACE VIEW financial.v_wallet_activity_7d AS
SELECT
w.id as wallet_id,
w.user_id,
w.wallet_type,
w.currency,
w.balance,
-- Transaction counts by type
COUNT(CASE WHEN wt.transaction_type = 'deposit' THEN 1 END) as deposits_7d,
COUNT(CASE WHEN wt.transaction_type = 'withdrawal' THEN 1 END) as withdrawals_7d,
COUNT(CASE WHEN wt.transaction_type IN ('transfer_in', 'transfer_out') THEN 1 END) as transfers_7d,
-- Amounts
SUM(CASE WHEN wt.transaction_type = 'deposit' THEN wt.amount ELSE 0 END) as deposit_amount_7d,
SUM(CASE WHEN wt.transaction_type = 'withdrawal' THEN wt.amount ELSE 0 END) as withdrawal_amount_7d,
-- Total activity
COUNT(wt.id) as total_transactions_7d
FROM financial.wallets w
LEFT JOIN financial.wallet_transactions wt ON wt.wallet_id = w.id
AND wt.created_at >= NOW() - INTERVAL '7 days'
AND wt.status = 'completed'
WHERE w.status = 'active'
GROUP BY w.id, w.user_id, w.wallet_type, w.currency, w.balance;
COMMENT ON VIEW financial.v_wallet_activity_7d IS 'Wallet activity summary for last 7 days';
-- =====================================================
-- VIEW: Subscription revenue metrics
-- =====================================================
CREATE OR REPLACE VIEW financial.v_subscription_revenue AS
SELECT
s.plan,
s.billing_interval,
s.currency,
COUNT(*) as active_count,
SUM(s.price) as total_monthly_value,
AVG(s.price) as avg_price,
-- MRR calculation (Monthly Recurring Revenue)
SUM(CASE
WHEN s.billing_interval = 'month' THEN s.price
WHEN s.billing_interval = 'year' THEN s.price / 12
ELSE 0
END) as monthly_recurring_revenue
FROM financial.subscriptions s
WHERE s.status IN ('active', 'trialing')
GROUP BY s.plan, s.billing_interval, s.currency
ORDER BY s.plan, s.billing_interval;
COMMENT ON VIEW financial.v_subscription_revenue IS 'Subscription metrics and MRR calculation';