Commit Graph

12 Commits

Author SHA1 Message Date
Inna 1b0920d11f Permitir pagar los servicios con PD, Stripe o SumUp (elección)
Los 9 servicios con precio en euros (rename, customize, change-race,
change-faction, level-up, gold, transfer, restore-item, send-gift) ahora
ofrecen un selector de forma de pago con las 3 opciones: saldo PD, tarjeta
(Stripe) o tarjeta (SumUp).

- lib/dpoints: spendDPoints() descuenta PD de forma atómica (FOR UPDATE).
- lib/pay-with-dpoints: paga con saldo PD, ejecuta la acción al momento y
  reembolsa si la ejecución falla; 100 PD = 1 €.
- rutas checkout (character/[service] y gift): rama provider='pd' que valida
  saldo, descuenta, ejecuta fulfill y devuelve la URL de éxito (sin pasarela).
- service-success: rama provider='pd' (la entrega ya se hizo en el checkout).
- PaymentMethodSelect: componente compartido con coste por método y saldo;
  desactiva PD si no hay saldo suficiente.
- Formularios (PaidServiceForm, Gold, Transfer, RestoreItems, SendGift) y sus
  páginas pasan el saldo PD y envían el método elegido + locale.
- i18n: namespace Pay (es/en); añadidas claves Paid.restore-item que faltaban.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:44:31 +00:00
Inna 671632a6a0 web-next: /restore-items cobra por SumUp (1€/ítem) en vez de PD
- Nuevo servicio de pago `restore-item` (getRestoreItemPrice default 1€, fulfill
  SOAP `.item restore <recover_id> <char>`). Al pulsar "Recuperar" se crea un
  checkout de SumUp y al pagar se ejecuta el restore.
- Se quita el descuento de 100 PD y el gate "No tienes PD suficientes".
- La búsqueda sigue igual (gratis, cooldown 8h, Turnstile).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:17:23 +00:00
Inna 03f75e189c web-next: /restore-character y /restore-items con todas las condiciones
- /restore-character: recupera personajes borrados por BD (como .character deleted
  restore). Condiciones: nivel>60, borrado <30 días, DK no si ya hay DK activo,
  nombre libre, cooldown 12h/personaje. Gratis. Tabla home_restorehistory.
- /restore-items: recupera ítems borrados vía SOAP del core (.item restore list /
  .item restore); el core aplica calidad/equipable/BoP/<7días. Cada ítem 100 PD
  (reembolso si SOAP falla), consulta con cooldown 8h/personaje + Turnstile.
  Tabla home_itemsearchhistory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:09:11 +00:00
Inna d95fa932f9 web-next: /transfer-character (transferir personaje por SumUp con todas las condiciones)
- Nueva ruta /transfer-character (10€ SumUp); borra /transfer (Stripe) y actualiza
  el link del panel.
- lib/transfer-character.ts: precheck con todas las condiciones — personaje offline,
  contraseña, token de seguridad, 2FA activo, cuenta destino válida (≠ propia) y,
  para Caballeros de la Muerte, la cuenta destino debe tener un personaje nivel >=55
  y no tener ya un DK; + bloqueo de 5s tras transferencia reciente.
- El hook precheck de PaidServiceConfig ahora recibe {accountId,email,character,body}.
- TransferForm: contraseña + token (con ojos), provider sumup, confirm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 12:52:25 +00:00
Inna eaae16e33a web-next: change-race/faction/level-up/gold por SumUp + rastreador de misiones
- /change-race-character (3€), /change-faction-character (5€, valida condiciones:
  sin hermandad/correo/subastas/capitán-arena y oro <= cap por nivel),
  /level-up-character (10€), /gold-character (oro por correo SOAP). Cada uno borra
  su ruta antigua y actualiza el link del panel.
- SumUp: hook precheck en PaidServiceConfig (condiciones cambio de facción);
  columna home_stripelog.metadata para campos extra (gold_amount).
- /quest-character: rastreador de estado de misiones/cadenas (clase, Hijos de
  Hodir, misión por ID) en personaje offline; cooldowns por categoría, Turnstile,
  IDs de misión verificados en wotlkdb 3.3.5a. Tabla home_questsearchhistory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 12:39:28 +00:00
Inna f7a376bd7c web-next: rename-character/customize-character por SumUp + renombrado de rutas
- /rename-character y /customize-character: renombrar/personalizar pagados por SumUp
  (getRenamePrice/getCustomizePrice). SumUp ahora es service-aware: columna
  home_stripelog.service; createSumUpCheckout guarda service+character;
  fulfillSumUpCheckout despacha a la acción del servicio (.char rename/customi) o,
  sin service, acredita PD. [service]/checkout acepta provider:'sumup';
  PaidServiceForm acepta provider+confirmText; service-success maneja el return SumUp.
  Se eliminan las antiguas /rename y /customize (Stripe).
- /revive-character (comparte ReviveServiceContent); se elimina /revive.
- Renombres de ruta + todos sus enlaces:
  /account -> /my-account, /recruit -> /recruit-a-friend, /unstuck -> /unstuck-character.
  (/select-account y /api/account/* intactos.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 11:35:56 +00:00
Inna 389dac68c4 Stripe: webhook que entrega el servicio aunque el usuario no vuelva
- app/api/stripe/webhook: verifica firma (constructEventAsync) y en
  checkout.session.completed registra la IP de Stripe (como Django) y ENTREGA
  el servicio. Idempotente frente a la página de éxito.
- lib/stripe.ts: claimPaidCheckout ahora es ATÓMICO (UPDATE ... WHERE fulfilled=0
  + affectedRows) para evitar doble entrega entre webhook y página de éxito;
  nuevo recordStripeIp.
- lib/fulfill.ts: fulfillCheckoutSession compartido (reclama + resuelve servicio
  desde metadata.service + ejecuta). checkout guarda `service` en metadata.
- service-success: usa la entrega compartida y distingue entregado/ya-procesado/error.
- i18n: Paid.alreadyProcessed.

Requiere configurar STRIPE_WEBHOOK_SECRET en .env.local (endpoint apuntando a
/api/stripe/webhook, evento checkout.session.completed).

Verificado: build OK, webhook 400 sin firma / firma inválida.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 00:55:18 +00:00
Inna 3e47a3d240 Aplica el sistema de diseño (nw-input/nw-btn/nw-card) a todas las páginas
Reemplazo masivo de los estilos sueltos repetidos por las clases del sistema visual
en ~20 componentes/páginas (auth, cuenta, servicios de personaje, foro, admin, voto):
- inputs -> .nw-input, botones primarios -> .nw-btn, tarjetas -> .nw-card.
Cohesión visual completa con la home y la cabecera.

Verificado: build OK, páginas clave 200/redirect correctos, clases aplicadas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 00:13:22 +00:00
Inna 548fca16e6 Añade gold y transfer: patrón de pago unificado con fulfill + metadata
- lib/stripe.ts: createCheckoutSession acepta metadata; claimPaidCheckout la
  recupera de la sesión Stripe y la devuelve.
- lib/paid-services.ts: config unificado con fulfill(character, meta) + extraFields.
  gold -> UPDATE characters money (BD directa, no SOAP), transfer -> SOAP
  .char changeaccount. Los 5 simples usan soapFulfill.
- checkout [service]: lee extraFields -> metadata, precio depende de metadata (gold),
  valida precio>0. service-success llama cfg.fulfill(name, metadata).
- prices.ts: getTransferPrice, getGoldOptions/goldPriceFor (home_goldprice).
- GoldForm (personaje + cantidad) y TransferForm (personaje + destino); páginas
  /gold y /transfer. Catálogos Paid.gold/transfer.

Verificado: /gold /transfer redirigen a login, checkout 401 sin sesión, home OK.
NOTA: transfer no valida aún el token de seguridad ni reglas AC (nivel>=55, DK).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 23:32:12 +00:00
Inna 87f9b0b003 Generaliza los servicios de personaje de pago (5) con infra común
- lib/paid-services.ts: config PAID_SERVICES (rename/customize/change-race/
  change-faction/level-up) con comando SOAP, precio y productName por servicio.
- app/api/character/[service]/checkout: ruta de checkout GENÉRICA (valida servicio +
  personaje, crea la sesión Stripe con successUrl /service-success?service=...).
- app/[locale]/service-success: página de éxito ÚNICA que verifica el pago
  (claimPaidCheckout) y ejecuta el comando SOAP del servicio.
- components/ServicePageContent: contenido común (guardas + PaidServiceForm).
- 5 páginas mínimas /rename /customize /change-race /change-faction /level-up.
- Catálogo Paid (por servicio: title/pay/success) sustituye a Rename.

Verificado: 5 páginas redirigen a login, checkout 401 sin sesión, servicio inválido
404, service-success con pago inválido no entrega (muestra error). Pendiente: gold
(cantidad) y transfer (destino+token), variantes del patrón.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 23:25:57 +00:00
Inna e7cff56954 Servicios de personaje de pago (Stripe): patrón + rename
- lib/stripe.ts: createCheckoutSession (crea sesión Stripe + StripeLog en
  home_stripelog, success_url con {CHECKOUT_SESSION_ID}), isSessionPaid,
  claimPaidCheckout (verifica pagado + no entregado, marca fulfilled -> evita
  re-entregas; port de require_paid_stripe).
- lib/prices.ts: precios desde home_*price (rename/customize/race/faction/level).
- components/PaidServiceForm.tsx: selector + botón de pago -> redirige a la URL de
  Checkout de Stripe (session.url, sin stripe.js).
- Rename: route /api/character/rename/checkout (guard + valida personaje + crea
  checkout), página /rename (PaidServiceForm) y /rename/success (verifica pago y
  ejecuta SOAP .char rename, i18n). STRIPE_* + NEXT_PUBLIC_STRIPE_PUBLIC_KEY en
  .env.local. Namespace Rename.

Verificado: checkout sin sesión 401, /rename redirige a login, /rename/success con
session_id inválido no entrega el servicio (muestra error). Patrón para los demás
servicios de pago (cambiar precio + comando SOAP).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 23:21:30 +00:00
Inna 96e996e9c2 Cliente SOAP + servicios de personaje SOAP (revive/unstuck) en Next.js
- lib/soap.ts: executeSoapCommand (port de ac_soap.py; POST SOAP + basic auth al
  worldserver, timeout 5s, null si inaccesible). AC_SOAP_* en .env.local.
- lib/characters.ts: getGameCharacters / characterIsOfflineAndOwned (acore_characters).
- lib/character-services.ts: soapCharacterAction genérico (valida propiedad+offline,
  cooldown 12h vía home_revive/unstuckhistory, SOAP, registra historial) ->
  reviveCharacter / unstuckCharacter.
- components/CharacterActionForm.tsx (cliente reutilizable: select + botón).
- Routes /api/character/revive|unstuck (guard de sesión) y páginas
  app/[locale]/revive|unstuck (SSR, guardas, i18n). Namespace Services.

Verificado: API sin sesión 401, páginas redirigen a login, cliente SOAP devuelve null
limpio sin worldserver. Patrón base para el resto de servicios de personaje.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 23:16:32 +00:00