import { randomUUID } from 'crypto' import { getSession } from '@/lib/session' import { getGameCharacters } from '@/lib/characters' import { createCheckoutSession } from '@/lib/stripe' import { createSumUpCheckout, sumupConfigured } from '@/lib/sumup' import { getPaidService } from '@/lib/paid-services' export async function POST(request: Request, { params }: { params: Promise<{ service: string }> }) { const { service } = await params const cfg = getPaidService(service) if (!cfg) return Response.json({ success: false, error: 'invalidService' }, { status: 404 }) const session = await getSession() if (!session.accountId) return Response.json({ success: false, error: 'notAuthenticated' }, { status: 401 }) let body: Record = {} try { body = await request.json() } catch { return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 }) } const character = String(body.character ?? '') if (!character) return Response.json({ success: false, error: 'invalidCharacter' }) const chars = await getGameCharacters(session.accountId) if (!chars.find((c) => c.name === character)) { return Response.json({ success: false, error: 'invalidCharacter' }) } // Comprobación previa al pago (condiciones del servicio, p.ej. cambio de facción / transferencia). if (cfg.precheck) { const pc = await cfg.precheck({ accountId: session.accountId, email: session.bnetEmail || '', character, body }) if (!pc.ok) return Response.json({ success: false, error: 'ineligible', message: pc.message }) } // Campos extra del servicio (gold_amount, destination_account...) -> metadata. // `service` va en metadata para que el webhook sepa qué entregar sin la URL. const metadata: Record = { service } for (const f of cfg.extraFields) { const v = String(body[f] ?? '').trim() if (!v) return Response.json({ success: false, error: 'missingFields' }) metadata[f] = v } const price = await cfg.price(metadata) if (!price || price <= 0) return Response.json({ success: false, error: 'invalidRequest' }) const site = process.env.SITE_URL || '' const ip = (request.headers.get('x-forwarded-for') || '').split(',')[0].trim() || '0.0.0.0' const productName = cfg.productName(character, metadata) // Pago por SumUp (euros): al pagar, la reconciliación/return ejecuta la acción // del servicio sobre el personaje (no acredita PD). if (String(body.provider) === 'sumup') { if (!sumupConfigured()) return Response.json({ success: false, error: 'notConfigured' }) const reference = randomUUID() const r = await createSumUpCheckout({ accountId: session.accountId, username: session.username || '', email: session.bnetEmail || '', acoreIp: ip, amount: price, points: 0, reference, description: productName, returnUrl: `${site}/service-success?service=${service}&provider=sumup&ref=${reference}`, service, characterName: character, metadata, }) if (!r.success || !r.url) return Response.json({ success: false, error: r.error || 'sumupError' }) return Response.json({ success: true, url: r.url }) } const r = await createCheckoutSession({ accountId: session.accountId, username: session.username || '', email: session.bnetEmail || '', acoreIp: ip, amount: price, characterName: character, productName, successUrl: `${site}/service-success?service=${service}`, cancelUrl: `${site}/${service}`, metadata, }) if (!r.success || !r.url) return Response.json({ success: false, error: 'stripeError' }) return Response.json({ success: true, url: r.url }) }