@fin.cx/skr
Version:
SKR03 and SKR04 German accounting standards for double-entry bookkeeping
336 lines • 26.1 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var JournalEntry_1;
import * as plugins from './plugins.js';
import { getDbSync } from './skr.database.js';
import { Account } from './skr.classes.account.js';
import { Transaction } from './skr.classes.transaction.js';
const { SmartDataDbDoc, svDb, unI, index, searchable } = plugins.smartdata;
let JournalEntry = JournalEntry_1 = class JournalEntry extends SmartDataDbDoc {
constructor(data) {
super();
if (data) {
this.id = plugins.smartunique.shortId();
this.journalNumber = this.generateJournalNumber();
this.date = data.date || new Date();
this.description = data.description || '';
this.reference = data.reference || '';
this.lines = data.lines || [];
this.skrType = data.skrType || 'SKR03';
this.totalDebits = 0;
this.totalCredits = 0;
this.isBalanced = false;
this.status = 'draft';
this.transactionIds = [];
// Set period and fiscal year
const entryDate = new Date(this.date);
this.period = `${entryDate.getFullYear()}-${String(entryDate.getMonth() + 1).padStart(2, '0')}`;
this.fiscalYear = entryDate.getFullYear();
this.createdAt = new Date();
this.postedAt = null;
this.createdBy = 'system';
// Normalize any negative amounts to the correct side
this.sanitizeLines();
// Calculate totals
this.calculateTotals();
}
}
generateJournalNumber() {
const timestamp = Date.now();
const random = Math.floor(Math.random() * 1000);
return `JE-${timestamp}-${random}`;
}
sanitizeLines() {
for (const line of this.lines) {
// Check if both debit and credit are set (not allowed)
if (line.debit !== undefined && line.debit !== 0 &&
line.credit !== undefined && line.credit !== 0) {
throw new Error('A line cannot have both debit and credit amounts');
}
// Handle negative debit - convert to positive credit
if (line.debit !== undefined && line.debit < 0) {
line.credit = Math.abs(line.debit);
delete line.debit;
}
// Handle negative credit - convert to positive debit
if (line.credit !== undefined && line.credit < 0) {
line.debit = Math.abs(line.credit);
delete line.credit;
}
// Check that at least one side has a positive value
const hasDebit = line.debit !== undefined && line.debit > 0;
const hasCredit = line.credit !== undefined && line.credit > 0;
if (!hasDebit && !hasCredit) {
throw new Error('Either debit or credit must be a positive number');
}
}
}
calculateTotals() {
this.totalDebits = 0;
this.totalCredits = 0;
for (const line of this.lines) {
if (line.debit) {
this.totalDebits += line.debit;
}
if (line.credit) {
this.totalCredits += line.credit;
}
}
// Check if balanced (allowing for small rounding differences)
const difference = Math.abs(this.totalDebits - this.totalCredits);
this.isBalanced = difference < 0.01;
}
static async createJournalEntry(data) {
const journalEntry = new JournalEntry_1(data);
await journalEntry.validate();
await journalEntry.save();
return journalEntry;
}
addLine(line) {
// Validate line
if (!line.accountNumber) {
throw new Error('Account number is required for journal entry line');
}
if (!line.debit && !line.credit) {
throw new Error('Either debit or credit amount is required');
}
if (line.debit && line.credit) {
throw new Error('A line cannot have both debit and credit amounts');
}
if (line.debit && line.debit < 0) {
throw new Error('Debit amount must be positive');
}
if (line.credit && line.credit < 0) {
throw new Error('Credit amount must be positive');
}
this.lines.push(line);
this.calculateTotals();
}
removeLine(index) {
if (index >= 0 && index < this.lines.length) {
this.lines.splice(index, 1);
this.calculateTotals();
}
}
async validate() {
// Check if entry is balanced
if (!this.isBalanced) {
throw new Error(`Journal entry is not balanced. Debits: ${this.totalDebits}, Credits: ${this.totalCredits}`);
}
// Check minimum lines
if (this.lines.length < 2) {
throw new Error('Journal entry must have at least 2 lines');
}
// Validate all accounts exist and are active
for (const line of this.lines) {
const account = await Account.getAccountByNumber(line.accountNumber, this.skrType);
if (!account) {
throw new Error(`Account ${line.accountNumber} not found for ${this.skrType}`);
}
if (!account.isActive) {
throw new Error(`Account ${line.accountNumber} is not active`);
}
}
}
async post() {
if (this.status === 'posted') {
throw new Error('Journal entry is already posted');
}
// Normalize any negative amounts to the correct side
this.sanitizeLines();
// Validate before posting
await this.validate();
// Create individual transactions for each debit-credit pair
const transactions = [];
// Simple posting logic: match debits with credits
// For complex entries, this could be enhanced with specific pairing logic
const debitLines = this.lines.filter((l) => l.debit);
const creditLines = this.lines.filter((l) => l.credit);
if (debitLines.length === 1 && creditLines.length === 1) {
// Simple entry: one debit, one credit
const transaction = await Transaction.createTransaction({
date: this.date,
debitAccount: debitLines[0].accountNumber,
creditAccount: creditLines[0].accountNumber,
amount: debitLines[0].debit,
description: this.description,
reference: this.reference,
skrType: this.skrType,
costCenter: debitLines[0].costCenter,
});
transactions.push(transaction);
}
else {
// Complex entry: multiple debits and/or credits
// Build working queues with remaining amounts (don't mutate original lines)
const debitQueue = debitLines.map(l => ({
line: l,
remaining: l.debit || 0
}));
const creditQueue = creditLines.map(l => ({
line: l,
remaining: l.credit || 0
}));
// Create transactions to balance the entry
for (const d of debitQueue) {
for (const c of creditQueue) {
const amount = Math.min(d.remaining, c.remaining);
if (amount > 0.0000001) { // small epsilon to avoid float artifacts
const transaction = await Transaction.createTransaction({
date: this.date,
debitAccount: d.line.accountNumber,
creditAccount: c.line.accountNumber,
amount: Math.round(amount * 100) / 100, // round to 2 decimals
description: `${this.description} - ${d.line.description || c.line.description || ''}`,
reference: this.reference,
skrType: this.skrType,
costCenter: d.line.costCenter || c.line.costCenter,
});
transactions.push(transaction);
// Reduce remaining amounts in working copies (not original lines)
d.remaining -= amount;
c.remaining -= amount;
}
if (d.remaining <= 0.0000001)
break;
}
}
}
// Store transaction IDs
this.transactionIds = transactions.map((t) => t.id);
// Update status
this.status = 'posted';
this.postedAt = new Date();
await this.save();
}
async reverse() {
if (this.status !== 'posted') {
throw new Error('Can only reverse posted journal entries');
}
// Create reversal entry with swapped debits and credits
const reversalLines = this.lines.map((line) => ({
accountNumber: line.accountNumber,
debit: line.credit, // Swap
credit: line.debit, // Swap
description: `Reversal: ${line.description || ''}`,
costCenter: line.costCenter,
}));
const reversalEntry = new JournalEntry_1({
date: new Date(),
description: `Reversal of ${this.journalNumber}: ${this.description}`,
reference: `REV-${this.journalNumber}`,
lines: reversalLines,
skrType: this.skrType,
});
await reversalEntry.validate();
await reversalEntry.post();
// Update original entry status
this.status = 'reversed';
await this.save();
return reversalEntry;
}
async beforeSave() {
// Normalize any negative amounts to the correct side
this.sanitizeLines();
// Recalculate totals before saving
this.calculateTotals();
// Validate required fields
if (!this.date) {
throw new Error('Journal entry date is required');
}
if (!this.description) {
throw new Error('Journal entry description is required');
}
if (this.lines.length === 0) {
throw new Error('Journal entry must have at least one line');
}
}
};
__decorate([
unI(),
__metadata("design:type", String)
], JournalEntry.prototype, "id", void 0);
__decorate([
svDb(),
index(),
__metadata("design:type", String)
], JournalEntry.prototype, "journalNumber", void 0);
__decorate([
svDb(),
index(),
__metadata("design:type", Date)
], JournalEntry.prototype, "date", void 0);
__decorate([
svDb(),
searchable(),
__metadata("design:type", String)
], JournalEntry.prototype, "description", void 0);
__decorate([
svDb(),
index(),
__metadata("design:type", String)
], JournalEntry.prototype, "reference", void 0);
__decorate([
svDb(),
__metadata("design:type", Array)
], JournalEntry.prototype, "lines", void 0);
__decorate([
svDb(),
index(),
__metadata("design:type", String)
], JournalEntry.prototype, "skrType", void 0);
__decorate([
svDb(),
__metadata("design:type", Number)
], JournalEntry.prototype, "totalDebits", void 0);
__decorate([
svDb(),
__metadata("design:type", Number)
], JournalEntry.prototype, "totalCredits", void 0);
__decorate([
svDb(),
__metadata("design:type", Boolean)
], JournalEntry.prototype, "isBalanced", void 0);
__decorate([
svDb(),
index(),
__metadata("design:type", String)
], JournalEntry.prototype, "status", void 0);
__decorate([
svDb(),
__metadata("design:type", Array)
], JournalEntry.prototype, "transactionIds", void 0);
__decorate([
svDb(),
index(),
__metadata("design:type", String)
], JournalEntry.prototype, "period", void 0);
__decorate([
svDb(),
__metadata("design:type", Number)
], JournalEntry.prototype, "fiscalYear", void 0);
__decorate([
svDb(),
__metadata("design:type", Date)
], JournalEntry.prototype, "createdAt", void 0);
__decorate([
svDb(),
__metadata("design:type", Date)
], JournalEntry.prototype, "postedAt", void 0);
__decorate([
svDb(),
__metadata("design:type", String)
], JournalEntry.prototype, "createdBy", void 0);
JournalEntry = JournalEntry_1 = __decorate([
plugins.smartdata.Collection(() => getDbSync()),
__metadata("design:paramtypes", [Object])
], JournalEntry);
export { JournalEntry };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmNsYXNzZXMuam91cm5hbGVudHJ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc2tyLmNsYXNzZXMuam91cm5hbGVudHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDOUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQU8zRCxNQUFNLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUM7QUFHcEUsSUFBTSxZQUFZLG9CQUFsQixNQUFNLFlBQWEsU0FBUSxjQUEwQztJQTJEMUUsWUFBWSxJQUE2QjtRQUN2QyxLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksSUFBSSxFQUFFLENBQUM7WUFDVCxJQUFJLENBQUMsRUFBRSxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDeEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUNsRCxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUNwQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1lBQzFDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUM5QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLElB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