RTIX / migrations /0025_payouts.sql
github-actions
deploy: clean backend production release
7856e60
Raw
History Blame Contribute Delete
2.96 kB
-- 0025_payouts.sql
-- Automated Payout Engine for Rtix
-- Tracks bank payout schedules, disbursements, and reconciliation.
CREATE TABLE IF NOT EXISTS merchant_bank_accounts (
id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
merchant_id VARCHAR(36) NOT NULL REFERENCES merchants(merchant_id) ON DELETE CASCADE,
account_holder VARCHAR(255) NOT NULL,
account_number VARCHAR(50) NOT NULL, -- stored encrypted in practice
ifsc_code VARCHAR(20) NOT NULL,
bank_name VARCHAR(100),
is_primary BOOLEAN NOT NULL DEFAULT TRUE,
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(merchant_id, account_number)
);
CREATE TABLE IF NOT EXISTS payouts (
id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
merchant_id VARCHAR(36) NOT NULL REFERENCES merchants(merchant_id) ON DELETE CASCADE,
bank_account_id VARCHAR(36) REFERENCES merchant_bank_accounts(id),
amount_inr NUMERIC(14, 2) NOT NULL CHECK (amount_inr > 0),
fee_inr NUMERIC(10, 2) NOT NULL DEFAULT 0.0,
net_inr NUMERIC(14, 2) GENERATED ALWAYS AS (amount_inr - fee_inr) STORED,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING'
CHECK (status IN ('PENDING', 'PROCESSING', 'SUCCESS', 'FAILED', 'REVERSED')),
mode VARCHAR(10) NOT NULL DEFAULT 'NEFT'
CHECK (mode IN ('NEFT', 'IMPS', 'RTGS', 'UPI')),
utr_number VARCHAR(50), -- Unique Transaction Reference from bank
initiated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
processed_at TIMESTAMPTZ,
failure_reason TEXT,
order_ids JSONB DEFAULT '[]', -- array of settled order IDs in this payout
notes TEXT
);
CREATE TABLE IF NOT EXISTS notification_log (
id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
merchant_id VARCHAR(36),
recipient_email VARCHAR(255) NOT NULL,
event_type VARCHAR(100) NOT NULL, -- e.g. ORDER_PLACED, PAYOUT_SUCCESS, SUB_RENEWAL
subject VARCHAR(500) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'SENT'
CHECK (status IN ('SENT', 'FAILED', 'BOUNCED')),
provider_id VARCHAR(255), -- external message ID from Resend/SES
sent_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
error_message TEXT
);
CREATE INDEX IF NOT EXISTS idx_payouts_merchant ON payouts(merchant_id);
CREATE INDEX IF NOT EXISTS idx_payouts_status ON payouts(status);
CREATE INDEX IF NOT EXISTS idx_payouts_initiated ON payouts(initiated_at DESC);
CREATE INDEX IF NOT EXISTS idx_bank_accounts_merchant ON merchant_bank_accounts(merchant_id);
CREATE INDEX IF NOT EXISTS idx_notification_log_merchant ON notification_log(merchant_id);
CREATE INDEX IF NOT EXISTS idx_notification_log_event ON notification_log(event_type);