feat(invoice): add e-invoice support with XRechnung/ZUGFeRD and advanced export features
This commit is contained in:
154
ts/skr.export.accounts.ts
Normal file
154
ts/skr.export.accounts.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
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 = [];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user