Quitar el prefijo home_ de las 41 tablas del portal
El prefijo venía del nombre de la app Django (`home`), jubilada y borrada hoy, así que ya no significaba nada: home_stripelog -> stripelog. La BD se sigue llamando django_wow por historia (renombrarla es otra operación). Comprobado antes de tocar nada: 0 colisiones con nombres existentes, 0 palabras reservadas (contrastado contra las 260 de MySQL), sin vistas ni triggers que dependieran de ellas. El RENAME va en una sola sentencia porque así es atómico, y MySQL reapunta solo las 4 claves ajenas entre estas tablas. 170 referencias actualizadas en 37 ficheros. Se dejó a propósito sql/drop_home_securitytoken_authuser_fk.sql sin tocar: es una migración ya aplicada y reescribirla sería falsear el historial. De paso salió un fallo previo: prices.ts consultaba `home_restoreitemprice`, una tabla que NO existe. El try/catch de priceFrom se comía el error y devolvía siempre el precio por defecto, así que el precio de restaurar objetos nunca fue configurable. Se deja documentado en el código; crear la tabla es otra decisión. Verificado tras aplicar: 0 tablas home_, las 51 siguen ahí, y el conteo exacto de filas cuadra con el volcado previo (store_item 3068, item_data 44873, stripelog 35, store_order 26, noticia 50). La web responde 200 en todas las rutas y la portada carga las noticias sin errores. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+19
-19
@@ -7,7 +7,7 @@ import { MAX_COPIES, PD_PER_EUR, PV_PER_EUR, storeEuroTotal as pureEuroTotal } f
|
||||
|
||||
/**
|
||||
* Tienda de ítems (transfiguración/equipo), portada del sistema antiguo (BENNU).
|
||||
* Catálogo en `home_store_category` (árbol por `code` "1-1-1") + `home_store_item`
|
||||
* Catálogo en `store_category` (árbol por `code` "1-1-1") + `store_item`
|
||||
* (precio en PD o PV, cantidad, icono). Se paga con el saldo PD/PV de la cuenta y
|
||||
* los ítems se envían por correo al personaje elegido (SOAP `.send items`).
|
||||
*/
|
||||
@@ -22,7 +22,7 @@ export function isValidCharName(name: string): boolean {
|
||||
const MAIL_ITEM_LIMIT = 12 // máximo de ítems por correo en AzerothCore
|
||||
|
||||
export interface StoreItem {
|
||||
id: number // fila de home_store_item (clave del carrito)
|
||||
id: number // fila de store_item (clave del carrito)
|
||||
itemId: number
|
||||
name: string
|
||||
icon: string | null
|
||||
@@ -114,10 +114,10 @@ export function parseCategoryName(html: string): NamePart[] {
|
||||
/**
|
||||
* Árbol completo de la tienda (categorías anidadas con sus ítems en las hojas).
|
||||
*
|
||||
* El nombre del ítem sale de `home_item_data` (extraído de los DB2 del cliente
|
||||
* El nombre del ítem sale de `item_data` (extraído de los DB2 del cliente
|
||||
* 3.4.3, ver sql/db2/), que es el ÚNICO sitio con el nombre en inglés: el
|
||||
* `home_store_item.name` del catálogo original es solo español. El de la
|
||||
* categoría sale de `home_store_category.name_en` (ver sql/store_category_en.sql).
|
||||
* `store_item.name` del catálogo original es solo español. El de la
|
||||
* categoría sale de `store_category.name_en` (ver sql/store_category_en.sql).
|
||||
* En ambos casos, si falta el nombre en ese idioma se cae al del catálogo, que
|
||||
* siempre está.
|
||||
*/
|
||||
@@ -132,13 +132,13 @@ export async function getStoreCatalog(locale: string): Promise<StoreCategory[]>
|
||||
try {
|
||||
;[cats] = await db(DB.default).query<CatRow[]>(
|
||||
`SELECT code, parent_code, COALESCE(NULLIF(${catNameCol}, ''), name) AS name, css, depth, sort
|
||||
FROM home_store_category ORDER BY sort`,
|
||||
FROM store_category ORDER BY sort`,
|
||||
)
|
||||
;[items] = await db(DB.default).query<ItemRow[]>(
|
||||
`SELECT i.id, i.category_code, i.item_id, COALESCE(NULLIF(d.${nameCol}, ''), i.name) AS name,
|
||||
i.icon, i.quantity, i.currency, i.price, i.preview, i.sort
|
||||
FROM home_store_item i
|
||||
LEFT JOIN home_item_data d ON d.entry = i.item_id
|
||||
FROM store_item i
|
||||
LEFT JOIN item_data d ON d.entry = i.item_id
|
||||
ORDER BY i.sort`,
|
||||
)
|
||||
} catch {
|
||||
@@ -184,7 +184,7 @@ export async function getStoreBalances(accountId: number): Promise<{ dp: number;
|
||||
if (!accountId) return { dp: 0, vp: 0 }
|
||||
try {
|
||||
const [rows] = await db(DB.default).query<RowDataPacket[]>(
|
||||
'SELECT dp, vp FROM home_api_points WHERE accountID = ?',
|
||||
'SELECT dp, vp FROM api_points WHERE accountID = ?',
|
||||
[accountId],
|
||||
)
|
||||
return rows[0] ? { dp: Number(rows[0].dp), vp: Number(rows[0].vp) } : { dp: 0, vp: 0 }
|
||||
@@ -200,7 +200,7 @@ export interface StoreCartLine {
|
||||
}
|
||||
|
||||
export interface PricedCart {
|
||||
// `qty` = lote que entrega CADA copia (home_store_item.quantity);
|
||||
// `qty` = lote que entrega CADA copia (store_item.quantity);
|
||||
// `copies` = cuántas veces se compra la línea. Total de unidades = qty*copies.
|
||||
// `name` = nombre del catálogo; lo usa el concepto del cobro con tarjeta.
|
||||
lines: { id: number; itemId: number; name: string; qty: number; currency: Currency; price: number; copies: number }[]
|
||||
@@ -217,13 +217,13 @@ export interface PricedCart {
|
||||
*
|
||||
* OJO: la IP va aquí a propósito (identificar al pagador si hay fraude o una
|
||||
* devolución a mano), pero esto se la manda a la pasarela; hasta ahora solo se
|
||||
* guardaba en `home_stripelog.acore_ip`. Se omite si no se conoce, y también el
|
||||
* guardaba en `stripelog.acore_ip`. Se omite si no se conoce, y también el
|
||||
* 0.0.0.0 de relleno, que no dice nada.
|
||||
*
|
||||
* Se recorta a `MAX_CONCEPT`: Stripe y SumUp limitan el campo (~250-255), y un
|
||||
* carrito de 100 líneas se pasaría de largo. Se recortan solo los ÍTEMS, nunca
|
||||
* la cabecera: quién ha pagado importa más que el listado completo, que además
|
||||
* queda entero en `home_store_order`.
|
||||
* queda entero en `store_order`.
|
||||
*/
|
||||
const MAX_CONCEPT = 200
|
||||
|
||||
@@ -255,7 +255,7 @@ export function storeConcept(
|
||||
|
||||
/**
|
||||
* Valida el carrito contra la BD (precios/cantidades/moneda REALES, nunca del
|
||||
* cliente) a partir de las filas `home_store_item.id` y las copias pedidas.
|
||||
* cliente) a partir de las filas `store_item.id` y las copias pedidas.
|
||||
* Devuelve null si está vacío, si alguna copia no es válida o si algún id no
|
||||
* existe en el catálogo (mismo criterio que `priceCart` de send-gift).
|
||||
*/
|
||||
@@ -274,7 +274,7 @@ export async function priceStoreCart(cart: StoreCartLine[]): Promise<PricedCart
|
||||
let rows: ItemRow[] = []
|
||||
try {
|
||||
;[rows] = await db(DB.default).query<ItemRow[]>(
|
||||
`SELECT id, item_id, name, quantity, currency, price FROM home_store_item WHERE id IN (${ids.map(() => '?').join(',')})`,
|
||||
`SELECT id, item_id, name, quantity, currency, price FROM store_item WHERE id IN (${ids.map(() => '?').join(',')})`,
|
||||
ids,
|
||||
)
|
||||
} catch {
|
||||
@@ -353,14 +353,14 @@ export async function purchaseStoreCart(
|
||||
try {
|
||||
await conn.beginTransaction()
|
||||
const [pts] = await conn.query<RowDataPacket[]>(
|
||||
'SELECT dp, vp FROM home_api_points WHERE accountID = ? FOR UPDATE',
|
||||
'SELECT dp, vp FROM api_points WHERE accountID = ? FOR UPDATE',
|
||||
[accountId],
|
||||
)
|
||||
const dp = pts[0] ? Number(pts[0].dp) : 0
|
||||
const vp = pts[0] ? Number(pts[0].vp) : 0
|
||||
if (dp < cart.pdTotal) { await conn.rollback(); return { success: false, error: 'insufficientPd' } }
|
||||
if (vp < cart.vpTotal) { await conn.rollback(); return { success: false, error: 'insufficientVp' } }
|
||||
await conn.query('UPDATE home_api_points SET dp = dp - ?, vp = vp - ? WHERE accountID = ?', [cart.pdTotal, cart.vpTotal, accountId])
|
||||
await conn.query('UPDATE api_points SET dp = dp - ?, vp = vp - ? WHERE accountID = ?', [cart.pdTotal, cart.vpTotal, accountId])
|
||||
await conn.commit()
|
||||
charged = true
|
||||
} catch {
|
||||
@@ -382,7 +382,7 @@ export async function purchaseStoreCart(
|
||||
const vpBack = back('pv')
|
||||
if (charged && (pdBack > 0 || vpBack > 0)) {
|
||||
await db(DB.default)
|
||||
.query('UPDATE home_api_points SET dp = dp + ?, vp = vp + ? WHERE accountID = ?', [pdBack, vpBack, accountId])
|
||||
.query('UPDATE api_points SET dp = dp + ?, vp = vp + ? WHERE accountID = ?', [pdBack, vpBack, accountId])
|
||||
.catch(() => {})
|
||||
}
|
||||
// Si no salió ni un correo es el fallo de siempre (SOAP caído). Si salió
|
||||
@@ -430,7 +430,7 @@ export async function createStoreOrder(
|
||||
const amount = storeEuroTotal(cart.pdTotal, cart.vpTotal)
|
||||
try {
|
||||
await db(DB.default).query(
|
||||
'INSERT INTO home_store_order (ref, account_id, character_name, items, amount) VALUES (?, ?, ?, ?, ?)',
|
||||
'INSERT INTO store_order (ref, account_id, character_name, items, amount) VALUES (?, ?, ?, ?, ?)',
|
||||
[ref, accountId, character, items, amount],
|
||||
)
|
||||
return true
|
||||
@@ -458,7 +458,7 @@ export async function fulfillStoreOrder(
|
||||
let rows: RowDataPacket[] = []
|
||||
try {
|
||||
;[rows] = await db(DB.default).query<RowDataPacket[]>(
|
||||
'SELECT character_name, items, amount FROM home_store_order WHERE ref = ?',
|
||||
'SELECT character_name, items, amount FROM store_order WHERE ref = ?',
|
||||
[ref],
|
||||
)
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user