fix(veesp): читать acc_credit вместо acc_balance при получении баланса
Docker / build (push) Failing after 24s
Docker / build (push) Failing after 24s
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -260,7 +260,7 @@ describe('sync routes — veesp', () => {
|
|||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
json: async () => ({
|
json: async () => ({
|
||||||
details: { currency: 'EUR', acc_balance: '100.00', acc_credit: '0.00' },
|
details: { currency: 'EUR', acc_balance: '0.00', acc_credit: '100.00' },
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,35 @@
|
|||||||
import { describe, expect, it } from 'vitest'
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
import { parseVeespCollection } from './operations.js'
|
import { parseVeespBalanceResponse, parseVeespCollection } from './operations.js'
|
||||||
import type { VeespIpItem, VeespVmListItem } 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', () => {
|
describe('parseVeespCollection', () => {
|
||||||
it('parses vms object-map from Veesp API', () => {
|
it('parses vms object-map from Veesp API', () => {
|
||||||
const json = {
|
const json = {
|
||||||
|
|||||||
@@ -157,6 +157,28 @@ function parseAmount(raw: string | number | undefined | null): number {
|
|||||||
return Number.isFinite(n) ? n : 0
|
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 {
|
function normalizeSlug(value: string | undefined | null): string {
|
||||||
return String(value ?? '')
|
return String(value ?? '')
|
||||||
.trim()
|
.trim()
|
||||||
@@ -388,13 +410,7 @@ export async function fetchBalance(
|
|||||||
): Promise<VeespBalanceResult> {
|
): Promise<VeespBalanceResult> {
|
||||||
const client = clientFor(baseUrl, credentials)
|
const client = clientFor(baseUrl, credentials)
|
||||||
const json = await client.request<Record<string, unknown>>('/balance')
|
const json = await client.request<Record<string, unknown>>('/balance')
|
||||||
const details =
|
return parseVeespBalanceResponse(json, fallbackCurrency)
|
||||||
(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: '' }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchInvoices(baseUrl: string, credentials: string): Promise<VeespInvoice[]> {
|
export async function fetchInvoices(baseUrl: string, credentials: string): Promise<VeespInvoice[]> {
|
||||||
|
|||||||
Reference in New Issue
Block a user