79 lines
3.1 KiB
TypeScript
79 lines
3.1 KiB
TypeScript
import { corsHeaders, handleCorsPreflightRequest } from '../_shared/cors.ts'
|
|
import { requireManager } from '../_shared/admin-auth.ts'
|
|
import { createServiceRoleClient } from '../_shared/quota.ts'
|
|
import { verifyCurrentAdminActor } from '../_shared/admin-current-role.ts'
|
|
import {
|
|
AdminPublicError,
|
|
adminErrorResponse,
|
|
adminJsonResponse,
|
|
requireUuid,
|
|
validateQueryKeys,
|
|
} from '../_shared/admin-contract.ts'
|
|
|
|
async function readPaymentHistory(req: Request): Promise<Response> {
|
|
const admin = await requireManager(req)
|
|
const url = new URL(req.url)
|
|
validateQueryKeys(url, ['userId', 'source'])
|
|
const userId = requireUuid(url.searchParams.get('userId'), 'invalid_userId')
|
|
const source = url.searchParams.get('source') ?? 'db'
|
|
if (source !== 'db' && source !== 'payple') throw new AdminPublicError(400, 'invalid_payment_source')
|
|
if (source === 'payple') {
|
|
throw new AdminPublicError(501, 'payple_live_history_not_configured')
|
|
}
|
|
|
|
const serviceClient = createServiceRoleClient()
|
|
await verifyCurrentAdminActor(serviceClient, admin)
|
|
const [subscriptionResult, auditResult, eventsResult, operationsResult] = await Promise.all([
|
|
serviceClient
|
|
.from('subscriptions')
|
|
.select('id, user_id, tier, status, provider, payment_provider, current_period_start, current_period_end, overage_credits, admin_note, cancel_at, created_at, updated_at')
|
|
.eq('user_id', userId)
|
|
.maybeSingle(),
|
|
serviceClient
|
|
.from('audit_log')
|
|
.select('id, admin_id, action, target_type, target_id, memo, created_at')
|
|
.eq('target_id', userId)
|
|
.eq('target_type', 'subscription')
|
|
.order('created_at', { ascending: false })
|
|
.limit(50),
|
|
serviceClient
|
|
.from('payment_provider_events')
|
|
.select('id, provider, event_type, event_created_at, disposition, received_at, processed_at')
|
|
.eq('user_id', userId)
|
|
.order('event_created_at', { ascending: false })
|
|
.limit(50),
|
|
serviceClient
|
|
.from('payment_provider_operations')
|
|
.select('id, provider, operation_type, requested_tier, state, error_code, expires_at, created_at, updated_at')
|
|
.eq('user_id', userId)
|
|
.order('created_at', { ascending: false })
|
|
.limit(50),
|
|
])
|
|
if (subscriptionResult.error || auditResult.error || eventsResult.error || operationsResult.error) {
|
|
throw new AdminPublicError(500, 'admin_payment_read_failed')
|
|
}
|
|
|
|
return adminJsonResponse({
|
|
subscription: subscriptionResult.data ?? null,
|
|
auditLogs: auditResult.data ?? [],
|
|
providerEvents: eventsResult.data ?? [],
|
|
providerOperations: operationsResult.data ?? [],
|
|
liveProviderHistoryAvailable: false,
|
|
}, corsHeaders)
|
|
}
|
|
|
|
export async function handleAdminPayments(req: Request): Promise<Response> {
|
|
const preflight = handleCorsPreflightRequest(req)
|
|
if (preflight) return preflight
|
|
try {
|
|
if (req.method !== 'GET') {
|
|
return adminJsonResponse({ error: 'method_not_allowed' }, corsHeaders, 405)
|
|
}
|
|
return await readPaymentHistory(req)
|
|
} catch (error) {
|
|
console.error('admin-payments request failed', error)
|
|
return adminErrorResponse(error, corsHeaders)
|
|
}
|
|
}
|
|
|
|
if (import.meta.main) Deno.serve(handleAdminPayments)
|