From ded6ee8a659eedc91b1f5bcd54d156cc2dfce9a8 Mon Sep 17 00:00:00 2001
From: youngcw <calebyoung94@gmail.com>
Date: Sun, 11 Jun 2023 07:14:46 -0700
Subject: [PATCH] Goals: Check template action (#1108)

This adds an option to the month drop down to check all the template
lines. If there are errors the offending line is shown with its
category.

I also modified the wording on the regular template return to be more
accurate. Fixes #1100
---
 .../budget/rollover/BudgetSummary.tsx         |  4 ++
 .../loot-core/src/client/actions/queries.ts   |  3 ++
 packages/loot-core/src/server/budget/app.ts   |  4 ++
 .../src/server/budget/goaltemplates.ts        | 43 +++++++++++++++++--
 .../src/server/budget/types/handlers.d.ts     |  2 +
 upcoming-release-notes/1108.md                |  6 +++
 6 files changed, 59 insertions(+), 3 deletions(-)
 create mode 100644 upcoming-release-notes/1108.md

diff --git a/packages/desktop-client/src/components/budget/rollover/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/rollover/BudgetSummary.tsx
index cb33597e0..b4b1e6b5d 100644
--- a/packages/desktop-client/src/components/budget/rollover/BudgetSummary.tsx
+++ b/packages/desktop-client/src/components/budget/rollover/BudgetSummary.tsx
@@ -394,6 +394,10 @@ export function BudgetSummary({
                         name: 'set-3-avg',
                         text: 'Set budgets to 3 month avg',
                       },
+                      isGoalTemplatesEnabled && {
+                        name: 'check-templates',
+                        text: 'Check templates',
+                      },
                       isGoalTemplatesEnabled && {
                         name: 'apply-goal-template',
                         text: 'Apply budget template',
diff --git a/packages/loot-core/src/client/actions/queries.ts b/packages/loot-core/src/client/actions/queries.ts
index 3308684a2..3dc59dc5e 100644
--- a/packages/loot-core/src/client/actions/queries.ts
+++ b/packages/loot-core/src/client/actions/queries.ts
@@ -25,6 +25,9 @@ export function applyBudgetAction(month, type, args) {
       case 'set-3-avg':
         await send('budget/set-3month-avg', { month });
         break;
+      case 'check-templates':
+        dispatch(addNotification(await send('budget/check-templates')));
+        break;
       case 'apply-goal-template':
         dispatch(
           addNotification(await send('budget/apply-goal-template', { month })),
diff --git a/packages/loot-core/src/server/budget/app.ts b/packages/loot-core/src/server/budget/app.ts
index a501281ee..6360e2a6d 100644
--- a/packages/loot-core/src/server/budget/app.ts
+++ b/packages/loot-core/src/server/budget/app.ts
@@ -15,6 +15,10 @@ app.method(
 );
 app.method('budget/set-zero', mutator(undoable(actions.setZero)));
 app.method('budget/set-3month-avg', mutator(undoable(actions.set3MonthAvg)));
+app.method(
+  'budget/check-templates',
+  mutator(undoable(goalActions.runCheckTemplates)),
+);
 app.method(
   'budget/apply-goal-template',
   mutator(undoable(goalActions.applyTemplate)),
diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts
index 94a1e4b1a..e1eb10cd5 100644
--- a/packages/loot-core/src/server/budget/goaltemplates.ts
+++ b/packages/loot-core/src/server/budget/goaltemplates.ts
@@ -26,6 +26,10 @@ export function overwriteTemplate({ month }) {
   return processTemplate(month, true);
 }
 
+export function runCheckTemplates() {
+  return checkTemplates();
+}
+
 function checkScheduleTemplates(template) {
   let lowPriority = template[0].priority;
   let errorNotice = false;
@@ -211,9 +215,7 @@ async function processTemplate(month, force) {
       return { type: 'message', message: 'All categories were up to date.' };
     }
   } else {
-    let applied = `Successfully applied templates to ${num_applied} ${
-      num_applied === 1 ? 'category' : 'categories'
-    }.`;
+    let applied = `Successfully applied ${num_applied} templates.`;
     if (errors.length) {
       return {
         sticky: true,
@@ -617,3 +619,38 @@ async function applyCategoryTemplate(
     return { amount: to_budget, errors };
   }
 }
+
+async function checkTemplates() {
+  let category_templates = await getCategoryTemplates();
+  let errors = [];
+
+  let categories = await db.all(
+    'SELECT * FROM v_categories WHERE tombstone = 0',
+  );
+
+  // run through each line and see if its an error
+  for (let c = 0; c < categories.length; c++) {
+    let category = categories[c];
+    let template = category_templates[category.id];
+    if (template) {
+      for (let l = 0; l < template.length; l++) {
+        if (template[l].type === 'error') {
+          //return { type: 'message', message: "found a bad one",};
+          errors.push(category.name + ': ' + template[l].line);
+        }
+      }
+    }
+  }
+  if (errors.length) {
+    return {
+      sticky: true,
+      message: `There were errors interpreting some templates:`,
+      pre: errors.join('\n\n'),
+    };
+  } else {
+    return {
+      type: 'message',
+      message: 'All templates passed! 🎉',
+    };
+  }
+}
diff --git a/packages/loot-core/src/server/budget/types/handlers.d.ts b/packages/loot-core/src/server/budget/types/handlers.d.ts
index eb251efbd..bca907c64 100644
--- a/packages/loot-core/src/server/budget/types/handlers.d.ts
+++ b/packages/loot-core/src/server/budget/types/handlers.d.ts
@@ -7,6 +7,8 @@ export interface BudgetHandlers {
 
   'budget/set-3month-avg': (...args: unknown[]) => Promise<unknown>;
 
+  'budget/check-templates': (...args: unknown[]) => Promise<unknown>;
+
   'budget/apply-goal-template': (...args: unknown[]) => Promise<unknown>;
 
   'budget/overwrite-goal-template': (...args: unknown[]) => Promise<unknown>;
diff --git a/upcoming-release-notes/1108.md b/upcoming-release-notes/1108.md
new file mode 100644
index 000000000..6c2774569
--- /dev/null
+++ b/upcoming-release-notes/1108.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [youncw]
+---
+
+Add action in month drop down to check template lines for proper formatting
-- 
GitLab