93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
import { authFetch } from "../../../utils/authFetch";
|
|
|
|
interface VatRate {
|
|
countryCode: string;
|
|
standardRate: number;
|
|
}
|
|
|
|
const normalizeVatRate = (rate: number | null | undefined): number | null => {
|
|
if (rate == null || Number.isNaN(rate)) return null;
|
|
return rate > 1 ? rate / 100 : rate;
|
|
};
|
|
|
|
const toNumber = (v: any): number | null => {
|
|
if (v == null) return null;
|
|
const n = typeof v === 'string' ? Number(v) : (typeof v === 'number' ? v : Number(v));
|
|
return Number.isFinite(n) ? n : null;
|
|
};
|
|
|
|
const getCode = (row: any): string => {
|
|
const raw = row?.countryCode ?? row?.code ?? row?.country ?? row?.country_code;
|
|
return typeof raw === 'string' ? raw.toUpperCase() : '';
|
|
};
|
|
|
|
const getRateRaw = (row: any): number | null => {
|
|
// support multiple field names and string numbers
|
|
const raw = row?.standardRate ?? row?.rate ?? row?.ratePercent ?? row?.standard_rate;
|
|
const num = toNumber(raw);
|
|
return num;
|
|
};
|
|
|
|
const getRateNormalized = (row: any): number | null => {
|
|
const num = getRateRaw(row);
|
|
return normalizeVatRate(num);
|
|
};
|
|
|
|
/**
|
|
* Fetches the standard VAT rate for a given ISO country code.
|
|
* Returns null if not found or on any error.
|
|
*/
|
|
export async function getStandardVatRate(countryCode: string): Promise<number | null> {
|
|
try {
|
|
const url = `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/tax/vat-rates`;
|
|
console.info('[VAT] getStandardVatRate -> GET', url, { countryCode });
|
|
const res = await authFetch(url, { method: "GET" });
|
|
console.info('[VAT] getStandardVatRate status:', res.status);
|
|
if (!res.ok) return null;
|
|
|
|
const raw = await res.json().catch(() => null);
|
|
const arr = Array.isArray(raw?.data) ? raw.data : (Array.isArray(raw) ? raw : []);
|
|
console.info('[VAT] getStandardVatRate parsed length:', Array.isArray(arr) ? arr.length : 0);
|
|
if (!Array.isArray(arr) || arr.length === 0) return null;
|
|
|
|
const upper = countryCode.toUpperCase();
|
|
const match = arr.find((r: any) => getCode(r) === upper);
|
|
const normalized = match ? getRateNormalized(match) : null;
|
|
console.info('[VAT] getStandardVatRate match:', {
|
|
upper,
|
|
resolvedCode: match ? getCode(match) : null,
|
|
rawRate: match ? getRateRaw(match) : null,
|
|
normalized
|
|
});
|
|
return normalized;
|
|
} catch (e) {
|
|
console.error('[VAT] getStandardVatRate error:', e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export type VatRateEntry = { code: string; rate: number | null }
|
|
|
|
export async function getVatRates(): Promise<VatRateEntry[]> {
|
|
try {
|
|
const url = `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/tax/vat-rates`;
|
|
console.info('[VAT] getVatRates -> GET', url);
|
|
const res = await authFetch(url, { method: 'GET' });
|
|
console.info('[VAT] getVatRates status:', res.status);
|
|
if (!res.ok) return [];
|
|
const raw = await res.json().catch(() => null);
|
|
const arr = Array.isArray(raw?.data) ? raw.data : (Array.isArray(raw) ? raw : []);
|
|
console.info('[VAT] getVatRates parsed length:', Array.isArray(arr) ? arr.length : 0);
|
|
if (!Array.isArray(arr) || arr.length === 0) return [];
|
|
const mapped = arr.map((r: any) => ({
|
|
code: getCode(r),
|
|
rate: getRateNormalized(r)
|
|
})).filter((r: VatRateEntry) => !!r.code);
|
|
console.info('[VAT] getVatRates mapped sample:', mapped.slice(0, 5));
|
|
return mapped;
|
|
} catch (e) {
|
|
console.error('[VAT] getVatRates error:', e);
|
|
return [];
|
|
}
|
|
}
|