Yimaru-BackEnd/db/query/payments.sql
Yared Yemane fbad083ca4 Add admin payments list API with filters and fix /admin route conflict.
Expose GET /api/v1/admin/payments for filtered gateway transaction listing, constrain /admin/:id to integers so /admin/payments is not mistaken for an admin id, and grant payments.list_all to ADMIN.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 05:50:46 -07:00

170 lines
6.7 KiB
SQL

-- =====================
-- Payments
-- =====================
-- name: CreatePayment :one
INSERT INTO payments (
user_id, plan_id, subscription_id, session_id, transaction_id, nonce,
amount, currency, payment_method, status, payment_url, expires_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, COALESCE($10, 'PENDING'), $11, $12)
RETURNING *;
-- name: GetPaymentByID :one
SELECT * FROM payments WHERE id = $1;
-- name: GetPaymentBySessionID :one
SELECT * FROM payments WHERE session_id = $1;
-- name: GetPaymentByNonce :one
SELECT * FROM payments WHERE nonce = $1;
-- name: GetPaymentByTransactionID :one
SELECT * FROM payments WHERE transaction_id = $1;
-- name: GetPaymentsByUserID :many
SELECT p.*, sp.name AS plan_name
FROM payments p
LEFT JOIN subscription_plans sp ON sp.id = p.plan_id
WHERE p.user_id = $1
ORDER BY p.created_at DESC
LIMIT sqlc.narg('limit')::INT
OFFSET sqlc.narg('offset')::INT;
-- name: GetPendingPaymentsByUserID :many
SELECT * FROM payments
WHERE user_id = $1 AND status = 'PENDING'
ORDER BY created_at DESC;
-- name: UpdatePaymentStatus :exec
UPDATE payments
SET
status = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
-- name: UpdatePaymentStatusBySessionID :exec
UPDATE payments
SET
status = sqlc.arg(status)::varchar,
transaction_id = COALESCE(sqlc.arg(transaction_id)::text, transaction_id),
payment_method = COALESCE(sqlc.arg(payment_method)::text, payment_method),
paid_at = CASE WHEN sqlc.arg(status)::varchar = 'SUCCESS' THEN CURRENT_TIMESTAMP ELSE paid_at END,
updated_at = CURRENT_TIMESTAMP
WHERE session_id = sqlc.arg(session_id)::text;
-- name: UpdatePaymentStatusByNonce :exec
UPDATE payments
SET
status = sqlc.arg(status)::varchar,
transaction_id = COALESCE(sqlc.arg(transaction_id)::text, transaction_id),
payment_method = COALESCE(sqlc.arg(payment_method)::text, payment_method),
paid_at = CASE WHEN sqlc.arg(status)::varchar = 'SUCCESS' THEN CURRENT_TIMESTAMP ELSE paid_at END,
updated_at = CURRENT_TIMESTAMP
WHERE nonce = sqlc.arg(nonce)::text;
-- name: UpdatePaymentSessionID :exec
UPDATE payments
SET
session_id = $1,
payment_url = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $3;
-- name: LinkPaymentToSubscription :exec
UPDATE payments
SET
subscription_id = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
-- name: GetExpiredPendingPayments :many
SELECT * FROM payments
WHERE status = 'PENDING'
AND expires_at IS NOT NULL
AND expires_at <= CURRENT_TIMESTAMP;
-- name: ExpirePayment :exec
UPDATE payments
SET
status = 'EXPIRED',
updated_at = CURRENT_TIMESTAMP
WHERE id = $1;
-- name: CountUserPayments :one
SELECT COUNT(*) FROM payments WHERE user_id = $1;
-- name: ListPaymentsAdmin :many
SELECT
p.id,
p.user_id,
p.plan_id,
p.subscription_id,
p.session_id,
p.transaction_id,
p.nonce,
p.amount,
p.currency,
p.payment_method,
p.status,
p.payment_url,
p.paid_at,
p.expires_at,
p.created_at,
p.updated_at,
sp.name AS plan_name,
sp.category AS plan_category,
u.email AS user_email,
u.first_name AS user_first_name,
u.last_name AS user_last_name
FROM payments p
LEFT JOIN subscription_plans sp ON sp.id = p.plan_id
LEFT JOIN users u ON u.id = p.user_id
WHERE (sqlc.narg('payment_id')::bigint IS NULL OR p.id = sqlc.narg('payment_id')::bigint)
AND (sqlc.narg('user_id')::bigint IS NULL OR p.user_id = sqlc.narg('user_id')::bigint)
AND (sqlc.narg('plan_id')::bigint IS NULL OR p.plan_id = sqlc.narg('plan_id')::bigint)
AND (sqlc.narg('subscription_id')::bigint IS NULL OR p.subscription_id = sqlc.narg('subscription_id')::bigint)
AND (sqlc.narg('status')::varchar IS NULL OR p.status = sqlc.narg('status')::varchar)
AND (sqlc.narg('payment_method')::varchar IS NULL OR UPPER(COALESCE(p.payment_method, '')) = UPPER(sqlc.narg('payment_method')::varchar))
AND (sqlc.narg('currency')::varchar IS NULL OR UPPER(p.currency) = UPPER(sqlc.narg('currency')::varchar))
AND (sqlc.narg('plan_category')::varchar IS NULL OR sp.category = sqlc.narg('plan_category')::varchar)
AND (sqlc.narg('created_from')::timestamptz IS NULL OR p.created_at >= sqlc.narg('created_from')::timestamptz)
AND (sqlc.narg('created_to')::timestamptz IS NULL OR p.created_at < sqlc.narg('created_to')::timestamptz)
AND (sqlc.narg('paid_from')::timestamptz IS NULL OR p.paid_at >= sqlc.narg('paid_from')::timestamptz)
AND (sqlc.narg('paid_to')::timestamptz IS NULL OR p.paid_at < sqlc.narg('paid_to')::timestamptz)
AND (sqlc.narg('min_amount')::numeric IS NULL OR p.amount >= sqlc.narg('min_amount')::numeric)
AND (sqlc.narg('max_amount')::numeric IS NULL OR p.amount <= sqlc.narg('max_amount')::numeric)
AND (
sqlc.narg('reference')::text IS NULL
OR p.session_id ILIKE '%' || sqlc.narg('reference')::text || '%'
OR p.nonce ILIKE '%' || sqlc.narg('reference')::text || '%'
OR p.transaction_id ILIKE '%' || sqlc.narg('reference')::text || '%'
)
ORDER BY p.created_at DESC
LIMIT sqlc.arg('limit') OFFSET sqlc.arg('offset');
-- name: CountPaymentsAdmin :one
SELECT COUNT(*)::bigint AS total
FROM payments p
LEFT JOIN subscription_plans sp ON sp.id = p.plan_id
WHERE (sqlc.narg('payment_id')::bigint IS NULL OR p.id = sqlc.narg('payment_id')::bigint)
AND (sqlc.narg('user_id')::bigint IS NULL OR p.user_id = sqlc.narg('user_id')::bigint)
AND (sqlc.narg('plan_id')::bigint IS NULL OR p.plan_id = sqlc.narg('plan_id')::bigint)
AND (sqlc.narg('subscription_id')::bigint IS NULL OR p.subscription_id = sqlc.narg('subscription_id')::bigint)
AND (sqlc.narg('status')::varchar IS NULL OR p.status = sqlc.narg('status')::varchar)
AND (sqlc.narg('payment_method')::varchar IS NULL OR UPPER(COALESCE(p.payment_method, '')) = UPPER(sqlc.narg('payment_method')::varchar))
AND (sqlc.narg('currency')::varchar IS NULL OR UPPER(p.currency) = UPPER(sqlc.narg('currency')::varchar))
AND (sqlc.narg('plan_category')::varchar IS NULL OR sp.category = sqlc.narg('plan_category')::varchar)
AND (sqlc.narg('created_from')::timestamptz IS NULL OR p.created_at >= sqlc.narg('created_from')::timestamptz)
AND (sqlc.narg('created_to')::timestamptz IS NULL OR p.created_at < sqlc.narg('created_to')::timestamptz)
AND (sqlc.narg('paid_from')::timestamptz IS NULL OR p.paid_at >= sqlc.narg('paid_from')::timestamptz)
AND (sqlc.narg('paid_to')::timestamptz IS NULL OR p.paid_at < sqlc.narg('paid_to')::timestamptz)
AND (sqlc.narg('min_amount')::numeric IS NULL OR p.amount >= sqlc.narg('min_amount')::numeric)
AND (sqlc.narg('max_amount')::numeric IS NULL OR p.amount <= sqlc.narg('max_amount')::numeric)
AND (
sqlc.narg('reference')::text IS NULL
OR p.session_id ILIKE '%' || sqlc.narg('reference')::text || '%'
OR p.nonce ILIKE '%' || sqlc.narg('reference')::text || '%'
OR p.transaction_id ILIKE '%' || sqlc.narg('reference')::text || '%'
);