fix(veesp): читать acc_credit вместо acc_balance при получении баланса
Docker / build (push) Failing after 24s

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-06-29 15:43:54 +07:00
co-authored by Cursor
parent 0682dd0e2f
commit 5998887148
3 changed files with 52 additions and 9 deletions
+1 -1
View File
@@ -260,7 +260,7 @@ describe('sync routes — veesp', () => {
return {
ok: true,
json: async () => ({
details: { currency: 'EUR', acc_balance: '100.00', acc_credit: '0.00' },
details: { currency: 'EUR', acc_balance: '0.00', acc_credit: '100.00' },
}),
}
}
+28 -1
View File
@@ -1,8 +1,35 @@
import { describe, expect, it } from 'vitest'
import { parseVeespCollection } from './operations.js'
import { parseVeespBalanceResponse, parseVeespCollection } from './operations.js'
import type { VeespIpItem, VeespVmListItem } from './operations.js'
describe('parseVeespBalanceResponse', () => {
it('uses acc_credit as available prepaid balance', () => {
const result = parseVeespBalanceResponse({
success: true,
details: { currency: 'EUR', acc_balance: '0.00', acc_credit: '42.50' },
})
expect(result.balance).toBe(42.5)
expect(result.currency).toBe('EUR')
})
it('does not treat unpaid invoice total (acc_balance) as account balance', () => {
const result = parseVeespBalanceResponse({
success: true,
details: { currency: 'USD', acc_balance: '123456.55', acc_credit: '0.00' },
})
expect(result.balance).toBe(0)
})
it('falls back to credit field when acc_credit is absent', () => {
const result = parseVeespBalanceResponse({
details: { currency: 'RUB', credit: '15.25' },
})
expect(result.balance).toBe(15.25)
expect(result.currency).toBe('RUB')
})
})
describe('parseVeespCollection', () => {
it('parses vms object-map from Veesp API', () => {
const json = {
+23 -7
View File
@@ -157,6 +157,28 @@ function parseAmount(raw: string | number | undefined | null): number {
return Number.isFinite(n) ? n : 0
}
/**
* Парсит ответ GET /balance Veesp/HostBill User API.
* acc_credit — предоплаченные средства на счёте; acc_balance — сумма неоплаченных инвойсов.
* @see https://secure.veesp.com/userapi — Billing → Account balance
*/
export function parseVeespBalanceResponse(
json: Record<string, unknown>,
fallbackCurrency = 'EUR',
): VeespBalanceResult {
const details =
(json.details as Record<string, unknown> | undefined) ??
(json.balance as Record<string, unknown> | undefined) ??
json
const currency = String(details.currency ?? fallbackCurrency).trim() || fallbackCurrency
const credit = parseAmount(details.acc_credit as string | number | undefined)
const direct = parseAmount(
(details.credit ?? details.balance) as string | number | undefined,
)
const balance = credit || direct
return { balance, currency, enoughmoneyto: '' }
}
function normalizeSlug(value: string | undefined | null): string {
return String(value ?? '')
.trim()
@@ -388,13 +410,7 @@ export async function fetchBalance(
): Promise<VeespBalanceResult> {
const client = clientFor(baseUrl, credentials)
const json = await client.request<Record<string, unknown>>('/balance')
const details =
(json.details as Record<string, unknown> | undefined) ??
(json.balance as Record<string, unknown> | undefined) ??
json
const currency = String(details.currency ?? fallbackCurrency).trim() || fallbackCurrency
const balance = parseAmount(details.acc_balance as string | number | undefined)
return { balance, currency, enoughmoneyto: '' }
return parseVeespBalanceResponse(json, fallbackCurrency)
}
export async function fetchInvoices(baseUrl: string, credentials: string): Promise<VeespInvoice[]> {