- Updated CustomersPage.vue to use decimalString for standard discount percent. - Enhanced IncomingInvoicesPage.vue to format item quantities, unit prices, and tax rates using decimalString. - Improved ItemsPage.vue with new supplier price management and decimal formatting for prices. - Modified OrganizationSetupPage.vue to use a dropdown for default tax rates and ensure numeric input for payment days. - Updated OutgoingInvoicesPage.vue to apply decimal formatting for customer discounts and item details. - Enhanced PriceImportsPage.vue to include additional fields in the import format. - Improved PriceRulesPage.vue to use decimal input for markup percentages. - Updated QuotesPage.vue to apply decimal formatting for customer discounts and item details. - Enhanced SuppliersPage.vue to use decimal input for standard discount percent. - Added a new SQL migration to set default unit for items to 'Stck'. - Introduced format.ts for centralized decimal and currency formatting utilities.
63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
const decimalFormatter = new Intl.NumberFormat("de-DE", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 4
|
|
});
|
|
|
|
const currencyFormatter = new Intl.NumberFormat("de-DE", {
|
|
style: "currency",
|
|
currency: "EUR",
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 4
|
|
});
|
|
|
|
export const unitOptions = ["Stck", "kg", "g", "L", "mg", "ml", "qm", "m", "cm", "mm"];
|
|
export const taxRateOptions = ["0", "7", "19"];
|
|
|
|
export function formatDecimal(value: string | number | null | undefined): string {
|
|
const number = toNumber(value);
|
|
return number === null ? "" : decimalFormatter.format(number);
|
|
}
|
|
|
|
export function formatEuro(value: string | number | null | undefined): string {
|
|
const number = toNumber(value);
|
|
return number === null ? "-" : currencyFormatter.format(number);
|
|
}
|
|
|
|
export function normalizeDecimal(value: string | number | null | undefined): string | null {
|
|
if (value === null || value === undefined || value === "") return null;
|
|
const text = String(value).trim();
|
|
if (!text) return null;
|
|
const compact = text.replace(/\s/g, "");
|
|
if (compact.includes(",")) return compact.replace(/\./g, "").replace(",", ".");
|
|
const dotCount = (compact.match(/\./g) ?? []).length;
|
|
if (dotCount > 1) return compact.replace(/\./g, "");
|
|
if (/^-?\d{1,3}\.\d{3}$/.test(compact)) return compact.replace(".", "");
|
|
return compact;
|
|
}
|
|
|
|
export function formatDecimalInput<T extends Record<string, unknown>>(target: T, key: keyof T) {
|
|
const normalized = normalizeDecimal(target[key] as string | number | null | undefined);
|
|
target[key] = (normalized === null ? null : formatDecimal(normalized)) as T[keyof T];
|
|
}
|
|
|
|
export function decimalString(value: string | number | null | undefined, fallback = "0"): string {
|
|
return normalizeDecimal(value) ?? fallback;
|
|
}
|
|
|
|
export function normalizeTaxRate(value: string | number | null | undefined, fallback = "19"): string {
|
|
const normalized = normalizeDecimal(value);
|
|
if (normalized === null) return fallback;
|
|
const number = Number(normalized);
|
|
if (!Number.isFinite(number)) return normalized;
|
|
const compact = String(number);
|
|
return taxRateOptions.includes(compact) ? compact : normalized;
|
|
}
|
|
|
|
function toNumber(value: string | number | null | undefined): number | null {
|
|
if (value === null || value === undefined || value === "") return null;
|
|
const normalized = normalizeDecimal(value);
|
|
if (normalized === null) return null;
|
|
const number = Number(normalized);
|
|
return Number.isFinite(number) ? number : null;
|
|
}
|