/** * Handelsware — API-Client (quick-261002-fm5). Konsumiert * `/modules/handelsware-datev`. Die Excel-Datei geht als Multipart-Feld `file`; * beim Export zusaetzlich `buchungsdatum` und `newAccounts` (JSON-Text der von * der Vorschau gemeldeten neuen Konten) — die API liest alle Zeilen erneut aus * derselben Datei, damit die TXT nicht von der Arbeitsmappe abweichen kann. */ import { accountingRequest, type FileResponse } from '@/lib/accounting-request'; export type { FileResponse } from '@/lib/accounting-request'; export { AccountingRequestError as HandelswareRequestError } from '@/lib/accounting-request'; const BASE = '/modules/handelsware-datev'; export interface HandelswareSettings { erloeskonto: number | null; startGegenkonto: number | null; configured: boolean; } export interface HandelswareSettingsInput { erloeskonto: number; startGegenkonto: number; } export interface HandelswareAccount { id: string; name: string; gegenkonto: number; erloeskonto: number; } export interface HandelswareAccountInput { name: string; gegenkonto: number; erloeskonto: number; } export interface NewAccount { name: string; gegenkonto: number; erloeskonto: number; } export interface PreviewRow { line: number; buchungstext: string; umsatz: string; sollHaben: 'S' | 'H'; gegenkonto: number; erloeskonto: number; isNew: boolean; } export interface RowError { line: number; code: string; message: string; } export interface HandelswarePreview { headerText: string; suggestedBuchungsdatum: string; exportFilename: string; rows: PreviewRow[]; newAccounts: NewAccount[]; rowErrors: RowError[]; } export type HandelswareExportResult = FileResponse & { createdCount: number }; const DAYS_PER_MONTH = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; /** TTMM: vier Ziffern, Monat 1-12, Tag passend zum Monat (Februar bis 29) — wie die API. */ export function isValidBuchungsdatum(ttmm: string): boolean { if (!/^\d{4}$/.test(ttmm)) return false; const day = Number.parseInt(ttmm.slice(0, 2), 10); const month = Number.parseInt(ttmm.slice(2, 4), 10); if (month < 1 || month > 12) return false; return day >= 1 && day <= DAYS_PER_MONTH[month - 1]; } function fileForm(file: File): FormData { const form = new FormData(); form.append('file', file); return form; } export function getHandelswareSettings(): Promise { return accountingRequest(`${BASE}/settings`); } export function saveHandelswareSettings( input: HandelswareSettingsInput, ): Promise { return accountingRequest(`${BASE}/settings`, { method: 'PUT', json: input }); } export function previewHandelsware(file: File): Promise { return accountingRequest(`${BASE}/preview`, { method: 'POST', form: fileForm(file) }); } export function exportHandelsware( file: File, buchungsdatum: string, newAccounts: NewAccount[], ): Promise { const form = fileForm(file); form.append('buchungsdatum', buchungsdatum); form.append('newAccounts', JSON.stringify(newAccounts)); return accountingRequest(`${BASE}/export`, { method: 'POST', form }); } export function listAccounts(): Promise { return accountingRequest(`${BASE}/accounts`); } export function createAccount(input: HandelswareAccountInput): Promise { return accountingRequest(`${BASE}/accounts`, { method: 'POST', json: input }); } export function updateAccount( id: string, input: HandelswareAccountInput, ): Promise { return accountingRequest(`${BASE}/accounts/${encodeURIComponent(id)}`, { method: 'PUT', json: input, }); } export function deleteAccount(id: string): Promise<{ deleted: true }> { return accountingRequest(`${BASE}/accounts/${encodeURIComponent(id)}`, { method: 'DELETE' }); } export function importAccountsCsv(file: File): Promise<{ count: number }> { return accountingRequest(`${BASE}/accounts/import-csv`, { method: 'POST', form: fileForm(file) }); } export function exportAccountsCsv(): Promise { return accountingRequest(`${BASE}/accounts/export-csv`); }