const PDFDocument = require('pdfkit'); const { all, one } = require('../db'); const { annualSchedule, money, monthlyFromAnnual } = require('../depreciation'); const { assetExportRows, assetFromRow } = require('./assets'); const { ruleSetForBook } = require('./ruleSets'); function depreciationReport(year, bookType) { const rules = ruleSetForBook(bookType); const rows = all(` SELECT a.*, b.book_type, b.active, b.cost, b.depreciation_method, b.convention, b.useful_life_months AS book_life, b.section_179_amount, b.bonus_percent, b.business_use_percent AS book_business_use_percent, b.investment_use_percent AS book_investment_use_percent, b.manual_depreciation, e.name AS entity_name FROM assets a JOIN asset_books b ON b.asset_id = a.id LEFT JOIN entities e ON e.id = a.entity_id WHERE b.active = 1 AND b.book_type = ? ORDER BY a.asset_id `, [bookType]); const reportRows = rows.map((row) => { const asset = assetFromRow(row); const book = { ...row, useful_life_months: row.book_life, business_use_percent: row.book_business_use_percent, investment_use_percent: row.book_investment_use_percent }; const schedule = annualSchedule(asset, book, rules, { startYear: year, endYear: year })[0] || {}; return { asset_id: row.asset_id, description: row.description, entity_name: row.entity_name, category: row.category, book: bookType, method: row.depreciation_method, methodLabel: schedule.methodLabel || row.depreciation_method, cost: money(row.cost ?? row.acquisition_cost), depreciation: money(schedule.depreciation || 0), accumulated: money(schedule.accumulated || 0), net_book_value: money(schedule.netBookValue ?? row.acquisition_cost) }; }); return { year, book: bookType, totals: { cost: money(reportRows.reduce((sum, row) => sum + row.cost, 0)), depreciation: money(reportRows.reduce((sum, row) => sum + row.depreciation, 0)), accumulated: money(reportRows.reduce((sum, row) => sum + row.accumulated, 0)), netBookValue: money(reportRows.reduce((sum, row) => sum + row.net_book_value, 0)) }, rows: reportRows }; } function monthlyDepreciationReport(year, bookType) { const rules = ruleSetForBook(bookType); const assets = all('SELECT * FROM assets ORDER BY asset_id').map(assetFromRow); const rows = assets.flatMap((asset) => { const book = one('SELECT * FROM asset_books WHERE asset_id = ? AND book_type = ? AND active = 1', [asset.id, bookType]); if (!book) return []; return annualSchedule(asset, book, rules, { startYear: year, endYear: year }).flatMap(monthlyFromAnnual); }); const months = Array.from({ length: 12 }, (_, index) => { const month = index + 1; return { month, depreciation: money(rows.filter((row) => row.month === month).reduce((sum, row) => sum + row.depreciation, 0)) }; }); return { year, book: bookType, months }; } function writeDepreciationPdf(res, year, book) { const rows = assetExportRows(); const doc = new PDFDocument({ margin: 36, size: 'LETTER' }); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="mixedassets-${book}-${year}.pdf"`); doc.pipe(res); doc.fontSize(18).text('MixedAssets Depreciation Report'); doc.fontSize(10).text(`Book: ${book} Year: ${year} Generated: ${new Date().toLocaleString()}`); doc.moveDown(); doc.fontSize(9).text('Asset ID', 36, doc.y, { continued: true, width: 80 }); doc.text('Description', 100, doc.y, { continued: true, width: 210 }); doc.text('Category', 300, doc.y, { continued: true, width: 110 }); doc.text('Cost', 430, doc.y, { align: 'right' }); doc.moveDown(0.5); rows.slice(0, 80).forEach((row) => { doc.text(row.asset_id, 36, doc.y, { continued: true, width: 80 }); doc.text(String(row.description).slice(0, 36), 100, doc.y, { continued: true, width: 210 }); doc.text(String(row.category).slice(0, 20), 300, doc.y, { continued: true, width: 110 }); doc.text(money(row.acquisition_cost).toLocaleString(), 430, doc.y, { align: 'right' }); }); doc.end(); } module.exports = { depreciationReport, monthlyDepreciationReport, writeDepreciationPdf };