-- ===================================================== -- ORBIQUANT IA - PAYMENTS TABLE -- ===================================================== -- Description: Payment transaction records -- Schema: financial -- ===================================================== CREATE TABLE financial.payments ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Referencias user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE RESTRICT, subscription_id UUID REFERENCES financial.subscriptions(id) ON DELETE SET NULL, invoice_id UUID REFERENCES financial.invoices(id) ON DELETE SET NULL, wallet_transaction_id UUID REFERENCES financial.wallet_transactions(id) ON DELETE SET NULL, -- Stripe integration stripe_payment_intent_id VARCHAR(255) UNIQUE, stripe_charge_id VARCHAR(255), stripe_payment_method_id VARCHAR(255), -- Payment details amount DECIMAL(15,2) NOT NULL, currency financial.currency_code NOT NULL, payment_method financial.payment_method NOT NULL, status financial.payment_status NOT NULL DEFAULT 'pending', -- Descripción description TEXT, statement_descriptor VARCHAR(255), -- Lo que ve el usuario en su estado de cuenta -- Refunds refunded BOOLEAN DEFAULT false, refund_amount DECIMAL(15,2), refund_reason TEXT, refunded_at TIMESTAMPTZ, -- Metadata metadata JSONB DEFAULT '{}', -- Error handling failure_code VARCHAR(100), failure_message TEXT, -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), succeeded_at TIMESTAMPTZ, failed_at TIMESTAMPTZ, -- Constraints CONSTRAINT positive_amount CHECK (amount > 0), CONSTRAINT positive_refund CHECK (refund_amount IS NULL OR refund_amount > 0), CONSTRAINT refund_lte_amount CHECK (refund_amount IS NULL OR refund_amount <= amount), CONSTRAINT refunded_has_data CHECK ( (refunded = false AND refund_amount IS NULL AND refunded_at IS NULL) OR (refunded = true AND refund_amount IS NOT NULL AND refunded_at IS NOT NULL) ), CONSTRAINT succeeded_has_timestamp CHECK ( (status = 'succeeded' AND succeeded_at IS NOT NULL) OR (status != 'succeeded') ), CONSTRAINT failed_has_data CHECK ( (status = 'failed' AND failed_at IS NOT NULL) OR (status != 'failed') ) ); -- Indexes CREATE INDEX idx_payments_user_id ON financial.payments(user_id); CREATE INDEX idx_payments_subscription_id ON financial.payments(subscription_id) WHERE subscription_id IS NOT NULL; CREATE INDEX idx_payments_invoice_id ON financial.payments(invoice_id) WHERE invoice_id IS NOT NULL; CREATE INDEX idx_payments_status ON financial.payments(status); CREATE INDEX idx_payments_stripe_intent ON financial.payments(stripe_payment_intent_id) WHERE stripe_payment_intent_id IS NOT NULL; CREATE INDEX idx_payments_created_at ON financial.payments(created_at DESC); CREATE INDEX idx_payments_user_created ON financial.payments(user_id, created_at DESC); CREATE INDEX idx_payments_payment_method ON financial.payments(payment_method); CREATE INDEX idx_payments_refunded ON financial.payments(refunded) WHERE refunded = true; -- Comments COMMENT ON TABLE financial.payments IS 'Payment transaction records with Stripe integration'; COMMENT ON COLUMN financial.payments.stripe_payment_intent_id IS 'Stripe PaymentIntent ID'; COMMENT ON COLUMN financial.payments.payment_method IS 'Payment method used: card, bank_transfer, crypto, etc.'; COMMENT ON COLUMN financial.payments.statement_descriptor IS 'Text shown on customer bank statement'; COMMENT ON COLUMN financial.payments.wallet_transaction_id IS 'Related wallet transaction if payment funds a wallet'; COMMENT ON COLUMN financial.payments.metadata IS 'Additional payment metadata and context';