Files
skr/ts/skr.export.accounts.ts
Juergen Kunz 73b46f7857
Some checks failed
Default (tags) / security (push) Successful in 48s
Default (tags) / test (push) Failing after 4m3s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
feat(invoice): add e-invoice support with XRechnung/ZUGFeRD and advanced export features
2025-08-12 12:37:01 +00:00

154 lines
3.9 KiB
TypeScript

import * as plugins from './plugins.js';
import * as path from 'path';
import type { IAccountData, TSKRType } from './skr.types.js';
// Extended interface for export with additional fields
export interface IAccountDataExport extends IAccountData {
parentAccount?: string;
defaultTaxCode?: string;
activeFrom?: Date | string;
activeTo?: Date | string;
}
export interface IAccountExportRow {
account_code: string;
name: string;
type: string;
class: number;
parent?: string;
skr_set: TSKRType;
tax_code_default?: string;
active_from?: string;
active_to?: string;
description?: string;
is_active: boolean;
}
export class AccountsExporter {
private exportPath: string;
private accounts: IAccountExportRow[] = [];
constructor(exportPath: string) {
this.exportPath = exportPath;
}
/**
* Adds an account to the export
*/
public addAccount(account: IAccountDataExport): void {
const exportRow: IAccountExportRow = {
account_code: account.accountNumber,
name: account.accountName,
type: account.accountType,
class: account.accountClass,
parent: account.parentAccount,
skr_set: account.skrType,
tax_code_default: account.defaultTaxCode,
active_from: account.activeFrom ? this.formatDate(account.activeFrom) : undefined,
active_to: account.activeTo ? this.formatDate(account.activeTo) : undefined,
description: account.description,
is_active: account.isActive !== false
};
this.accounts.push(exportRow);
}
/**
* Exports accounts to CSV format
*/
public async exportToCSV(): Promise<void> {
const csvPath = path.join(this.exportPath, 'data', 'accounting', 'accounts.csv');
await plugins.smartfile.fs.ensureDir(path.dirname(csvPath));
// Create CSV header
const headers = [
'account_code',
'name',
'type',
'class',
'parent',
'skr_set',
'tax_code_default',
'active_from',
'active_to',
'description',
'is_active'
];
let csvContent = headers.join(',') + '\n';
// Add account rows
for (const account of this.accounts) {
const row = [
this.escapeCSV(account.account_code),
this.escapeCSV(account.name),
this.escapeCSV(account.type),
account.class.toString(),
this.escapeCSV(account.parent || ''),
this.escapeCSV(account.skr_set),
this.escapeCSV(account.tax_code_default || ''),
this.escapeCSV(account.active_from || ''),
this.escapeCSV(account.active_to || ''),
this.escapeCSV(account.description || ''),
account.is_active.toString()
];
csvContent += row.join(',') + '\n';
}
await plugins.smartfile.memory.toFs(csvContent, csvPath);
}
/**
* Exports accounts to JSON format (alternative)
*/
public async exportToJSON(): Promise<void> {
const jsonPath = path.join(this.exportPath, 'data', 'accounting', 'accounts.json');
await plugins.smartfile.fs.ensureDir(path.dirname(jsonPath));
const jsonData = {
schema_version: '1.0',
export_date: new Date().toISOString(),
accounts: this.accounts
};
await plugins.smartfile.memory.toFs(
JSON.stringify(jsonData, null, 2),
jsonPath
);
}
/**
* Escapes CSV values
*/
private escapeCSV(value: string): string {
if (value.includes(',') || value.includes('"') || value.includes('\n')) {
return `"${value.replace(/"/g, '""')}"`;
}
return value;
}
/**
* Formats a date to ISO date string
*/
private formatDate(date: Date | string): string {
if (typeof date === 'string') {
return date.split('T')[0];
}
return date.toISOString().split('T')[0];
}
/**
* Gets the number of accounts
*/
public getAccountCount(): number {
return this.accounts.length;
}
/**
* Clears the accounts list
*/
public clear(): void {
this.accounts = [];
}
}