UNPKG

@debito/hippo-lib

Version:

Double-entry accounting library for CouchDB

105 lines (87 loc) 3.95 kB
import JournalEntry from '../JournalEntry.js'; import COA from '../coa.js'; /** * JournalTemplate class for creating journal entries from predefined templates */ class JournalTemplate { /** * List all available journal templates * @returns {Promise<Array>} Array of journal template objects */ static async listTemplates() { try { // Get templates from COA settings const coa = await COA.loadCOAFromDB(); return coa.journelTemplates || []; } catch (error) { throw new Error(`Failed to list journal templates: ${error.message}`); } } /** * Create a journal entry from a template * @param {string} templateKey - The key of the template to use * @param {number} amount - The transaction amount * @param {Object} options - Options containing placeholder values (e.g., {vendor: "abc-corp"}) * @param {string} [description] - Optional description for the journal entry * @param {string} [date] - Optional ISO date string for the journal entry * @returns {Promise<JournalEntry>} The created and saved journal entry */ static async createJournalEntryFromTemplate(templateKey, amount, options = {}, description = null, date = null) { if (!templateKey || !amount) { throw new Error('Template key and amount are required'); } // Get the COA document to access journal templates const coaDoc = await COA.loadCOAFromDB(); if (!coaDoc.journelTemplates) { throw new Error('No journal templates found in COA'); } // Find the specified template const template = coaDoc.journelTemplates.find(t => t.key === templateKey); if (!template) { throw new Error(`Journal template '${templateKey}' not found`); } // Create the journal entry with description and template tag const entryDescription = description || template.description || `Entry from template: ${template.label}`; const journalEntry = await JournalEntry.new(entryDescription, [templateKey]); // Set the date if provided if (date) { journalEntry._doc.date = date; } // Process each line in the template for (const line of template.lines) { // Resolve account keys by replacing placeholders const accountKey = this._resolveAccountKey(line['account-key'], options); // Create line descriptions const lineDescription = line.description || entryDescription; // Add the lines to the journal entry journalEntry.addLine(accountKey, line.type, amount, lineDescription); } // Post the journal entry (creates ledger entries and updates balances) await journalEntry.post(); return journalEntry; } /** * Resolve account key by replacing placeholders with actual values * @param {string} accountKey - The account key that may contain placeholders * @param {Object} options - Options containing placeholder values * @returns {string} The resolved account key * @private */ static _resolveAccountKey(accountKey, options) { if (!accountKey) { throw new Error('Account key is required'); } // If it's a regular account key (no placeholder), return as-is if (!accountKey.startsWith('$')) { return accountKey; } // Extract the placeholder key (remove the $ prefix) const placeholderKey = accountKey.substring(1); // Look for the key in options if (options[placeholderKey]) { return options[placeholderKey]; } throw new Error(`Placeholder '${placeholderKey}' not found in options. Available: ${Object.keys(options).join(', ')}`); } } export default JournalTemplate;