import { spendDPoints, creditDPoints, spendVPoints, creditVPoints, PD_PER_UNIT } from './dpoints' /** * Los PV (vote points) son gratis (se ganan votando), así que pagar con PV es * más caro que con PD: cuesta este factor por el coste en PD. Cambiar aquí. */ export const VP_PRICE_FACTOR = 2 /** Coste en PD de un precio en euros (100 PD = 1 €). */ export function dpointsCost(priceEur: number): number { return Math.round(priceEur * PD_PER_UNIT) } /** Coste en PV de un precio en euros (coste PD × VP_PRICE_FACTOR). */ export function vpointsCost(priceEur: number): number { return dpointsCost(priceEur) * VP_PRICE_FACTOR } /** * Paga un servicio con el saldo PD: descuenta el coste de forma atómica y * ejecuta la acción al momento (sin pasarela). Si la ejecución falla, reembolsa * el saldo. Devuelve `insufficientPd` si no hay saldo suficiente. */ export async function payServiceWithDPoints( accountId: number, priceEur: number, fulfill: () => Promise, ): Promise<{ success: boolean; error?: string }> { const cost = dpointsCost(priceEur) if (!(cost > 0)) return { success: false, error: 'invalidRequest' } const spent = await spendDPoints(accountId, cost) if (!spent.success) { return { success: false, error: spent.error === 'insufficientFunds' ? 'insufficientPd' : 'genericError' } } let ok = false try { ok = await fulfill() } catch { ok = false } if (!ok) { await creditDPoints(accountId, cost) // reembolso si no se pudo ejecutar return { success: false, error: 'fulfillFailed' } } return { success: true } } /** * Paga un servicio con el saldo PV: descuenta el coste (más caro que en PD) y * ejecuta la acción al momento. Reembolsa si falla. Devuelve `insufficientVp` * si no hay saldo suficiente. */ export async function payServiceWithVPoints( accountId: number, priceEur: number, fulfill: () => Promise, ): Promise<{ success: boolean; error?: string }> { const cost = vpointsCost(priceEur) if (!(cost > 0)) return { success: false, error: 'invalidRequest' } const spent = await spendVPoints(accountId, cost) if (!spent.success) { return { success: false, error: spent.error === 'insufficientFunds' ? 'insufficientVp' : 'genericError' } } let ok = false try { ok = await fulfill() } catch { ok = false } if (!ok) { await creditVPoints(accountId, cost) // reembolso si no se pudo ejecutar return { success: false, error: 'fulfillFailed' } } return { success: true } }