diff --git a/calc-schedule-budget.js b/calc-schedule-budget.js index b8ec675..80153ab 100644 --- a/calc-schedule-budget.js +++ b/calc-schedule-budget.js @@ -10,6 +10,10 @@ checkEnv([ 'BUDGET_OUTCOME_NAME', ]); +const categories = await actual.getCategories(); +const incomeCategory = categories.find(c => c.name === process.env.BUDGET_INCOME_NAME); +const outcomeCategory = categories.find(c => c.name === process.env.BUDGET_OUTCOME_NAME); + console.log(); if (process.env.DRY_RUN) { console.log(chalk.grey.bold('Running in dry run mode\n')); @@ -22,16 +26,20 @@ function formatAmount(amount) { return chalk.bold(amountFormatter.format(Math.abs(amount / 100))); } -function formatSchedule(s) { +function formatSchedule(s, c) { const operator = s._amountOp === 'isapprox' ? '~ ' : ''; let meta = formatAmount(s._amount); if (s._date.frequency) { meta += ` - ${s._date.frequency}`; } + if (c?.name) { + meta += ` - ${c.name}`; + } return `${chalk.underline(s.name)} (${operator}${meta})`; } const schedules = await actual.getSchedules(); +const categoriesTotal = new Map(); let totalOutcome = 0; let totalIncome = 0; for (const s of schedules) { @@ -46,15 +54,17 @@ for (const s of schedules) { continue; } - if (s.name === "Etails - Téléphone" || s.name === "FF14") { + if (s.name === "Etalis - Téléphone") { console.log(s); } let date = start; if (typeof s._date === 'object') { let occurrences = 0; - while (date < month || occurrences < s._date.endOccurrences) { - occurrences += 1; + while (date < month && occurrences <= s._date.endOccurrences) { + if (s._date.endMode !== 'never') { + occurrences += 1; + } date = addFromFrequency(date, s._date.frequency, s._date.interval); } } @@ -64,29 +74,41 @@ for (const s of schedules) { continue; } - if (s._amount > 0) { - totalIncome += s._amount; - } else { - totalOutcome += Math.abs(s._amount); + const amount = Math.abs(s._amount); + let categoryId = s._actions.find((a) => a.field === 'category' && a.op === 'set')?.value; + if (!categoryId) { + console.log(chalk.yellow(` ${formatSchedule(s)}: falling back on default`)); + categoryId = (s._amount > 0 ? incomeCategory?.id : outcomeCategory?.id); } - console.log(chalk.green(`+ ${formatSchedule(s)}`)); + if (!categoryId) { + console.log(chalk.red(`- ${formatSchedule(s)}: no category found`)); + continue; + } + + if (s._amount > 0) { + totalIncome += amount; + } else { + totalOutcome += amount; + } + + categoriesTotal.set(categoryId, (categoriesTotal.get(categoryId) || 0) + amount); + console.log(chalk.green(`+ ${formatSchedule(s, categories.find((c) => c.id === categoryId))}`)); } -console.log(chalk.blue(`\nTotal income: +${formatAmount(totalIncome)}\nTotal outcome: -${formatAmount(totalOutcome)}\n`)); +console.log(chalk.bgBlue(`\nTotal income: +${formatAmount(totalIncome)}\nTotal outcome: -${formatAmount(totalOutcome)}\n`)); +console.log(`Budgets for ${month}: `); -if (!process.env.DRY_RUN) { - const categories = await actual.getCategories(); - const incomeCategory = categories.find(c => c.name === process.env.BUDGET_INCOME_NAME); - const outcomeCategory = categories.find(c => c.name === process.env.BUDGET_OUTCOME_NAME); +for (const [id, total] of categoriesTotal) { + const category = categories.find((c) => c.id === id); + if (!category) { + console.log(chalk.red(`Category ${id} not found`)); + continue; + } - if (incomeCategory) { - actual.setBudgetAmount(month, incomeCategory.id, totalIncome); - console.log(chalk.yellow(`Income set for "${process.env.BUDGET_INCOME_NAME}" at "${month}"`)); - } - if (outcomeCategory) { - actual.setBudgetAmount(month, outcomeCategory.id, totalOutcome); - console.log(chalk.yellow(`Outcome set for "${process.env.BUDGET_OUTCOME_NAME}" at "${month}"`)) + if (!process.env.DRY_RUN) { + actual.setBudgetAmount(month, id, total); } + console.log(chalk.blue(`${chalk.underline(category.name)} -> ${formatAmount(total)}`)); } console.log();