Skip to content

fix(qif): import transaction categories from QIF files#7315

Open
Muhammad-Nur-Alamsyah-Anwar wants to merge 2 commits intoactualbudget:masterfrom
Muhammad-Nur-Alamsyah-Anwar:fix/qif-category-not-imported
Open

fix(qif): import transaction categories from QIF files#7315
Muhammad-Nur-Alamsyah-Anwar wants to merge 2 commits intoactualbudget:masterfrom
Muhammad-Nur-Alamsyah-Anwar:fix/qif-category-not-imported

Conversation

@Muhammad-Nur-Alamsyah-Anwar
Copy link
Copy Markdown

@Muhammad-Nur-Alamsyah-Anwar Muhammad-Nur-Alamsyah-Anwar commented Mar 29, 2026

Description

QIF files use L lines to specify transaction categories, and qif2json already parses them correctly into category/subcategory fields. The problem was in parseQIF — it was just dropping those values instead of mapping them through to the returned transaction.

Related issue(s)

Fixes #3910

Testing

Added a QIF fixture with a few different L line formats and unit tests in parse-file.test.ts to cover the main cases (category only, category + subcategory, and no L line at all). To reproduce the original bug, import a QIF file containing L lines and check that the category column is populated in the import modal.

Checklist

  • Release notes added
  • No obvious regressions in affected areas
  • Self-review has been performed - I understand what each change in the code does and why it is needed

Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 27 12.09 MB 0%
loot-core 1 4.83 MB → 4.83 MB (+188 B) +0.00%
api 4 4.06 MB → 4.06 MB (+186 B) +0.00%
cli 1 7.88 MB 0%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
27 12.09 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
static/js/index.js 3.23 MB 0%
static/js/BackgroundImage.js 119.98 kB 0%
static/js/FormulaEditor.js 846.44 kB 0%
static/js/ReportRouter.js 1.02 MB 0%
static/js/TransactionList.js 81.29 kB 0%
static/js/ca.js 182.91 kB 0%
static/js/da.js 104.66 kB 0%
static/js/de.js 174.79 kB 0%
static/js/en-GB.js 7.16 kB 0%
static/js/en.js 170.76 kB 0%
static/js/es.js 182.09 kB 0%
static/js/fr.js 177.47 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.46 kB 0%
static/js/it.js 166.25 kB 0%
static/js/narrow.js 354.27 kB 0%
static/js/nb-NO.js 152.2 kB 0%
static/js/nl.js 108.93 kB 0%
static/js/pl.js 88.34 kB 0%
static/js/pt-BR.js 177.84 kB 0%
static/js/resize-observer.js 18.03 kB 0%
static/js/sv.js 80.58 kB 0%
static/js/th.js 179.94 kB 0%
static/js/theme.js 30.68 kB 0%
static/js/uk.js 213.14 kB 0%
static/js/useTransactionBatchActions.js 4.29 MB 0%
static/js/wide.js 418 B 0%
static/js/workbox-window.prod.es5.js 7.28 kB 0%

loot-core

Total

Files count Total bundle size % Changed
1 4.83 MB → 4.83 MB (+188 B) +0.00%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/import/parse-file.ts 📈 +188 B (+3.32%) 5.53 kB → 5.71 kB
View detailed bundle breakdown

Added

Asset File Size % Changed
kcab.worker.0MJZX4St.js 0 B → 4.83 MB (+4.83 MB) -

Removed

Asset File Size % Changed
kcab.worker.CwpE34S5.js 4.83 MB → 0 B (-4.83 MB) -100%

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged
No assets were unchanged


api

Total

Files count Total bundle size % Changed
4 4.06 MB → 4.06 MB (+186 B) +0.00%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/import/parse-file.ts 📈 +186 B (+3.27%) 5.56 kB → 5.74 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
index.js 3.84 MB → 3.84 MB (+186 B) +0.00%

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
from-Bl-Hslp4.js 167.73 kB 0%
multipart-parser-BnDysoMr.js 8.1 kB 0%
src-iMkUmuwR.js 43.64 kB 0%

cli

Total

Files count Total bundle size % Changed
1 7.88 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
cli.js 7.88 MB 0%

Copilot AI review requested due to automatic review settings March 29, 2026 04:28
@actual-github-bot actual-github-bot bot changed the title fix(qif): import transaction categories from QIF files [WIP] fix(qif): import transaction categories from QIF files Mar 29, 2026
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 29, 2026

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit f6bd920
🔍 Latest deploy log https://app.netlify.com/projects/actualbudget/deploys/69c8bf99f17537000851e0eb
😎 Deploy Preview https://deploy-preview-7315.demo.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hello contributor!

We would love to review your PR! Before we can do that, please make sure:

  • ✅ All CI checks pass
  • ✅ The PR is moved from draft to open (if applicable)
  • ✅ The "[WIP]" prefix is removed from the PR title
  • ✅ All CodeRabbit code review comments are resolved (if you disagree with anything - reply to the bot with your reasoning so we can read through it). The bot will eventually approve the PR.

We do this to reduce the TOIL the core contributor team has to go through for each PR and to allow for speedy reviews and merges.

For more information, please see our Contributing Guide.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ecb3cec6-c1bc-41b2-94d0-69bfefd44a97

📥 Commits

Reviewing files that changed from the base of the PR and between f7e9ced and f6bd920.

📒 Files selected for processing (4)
  • packages/loot-core/src/mocks/files/data-with-categories.qif
  • packages/loot-core/src/server/transactions/import/parse-file.test.ts
  • packages/loot-core/src/server/transactions/import/parse-file.ts
  • upcoming-release-notes/7315.md

📝 Walkthrough

Walkthrough

Added an optional category?: string to parsed transactions and populated it for QIF imports by deriving a category string from parsed trans.category and trans.subcategory ("category:subcategory", category, or null). Added tests, a QIF fixture, and a release note entry.

Changes

Cohort / File(s) Summary
QIF parsing & type
packages/loot-core/src/server/transactions/import/parse-file.ts
Added category?: string to StructuredTransaction. Updated QIF mapping to compute and include a category derived from trans.category and trans.subcategory (combine with : when both present, otherwise use one or null).
Tests
packages/loot-core/src/server/transactions/import/parse-file.test.ts
Added tests loading data-with-categories.qif to assert per-transaction category values and a test asserting category === null when no L lines exist.
Mocks / Fixtures
packages/loot-core/src/mocks/files/data-with-categories.qif
Added a QIF fixture with three bank transactions containing L category lines to exercise category parsing.
Release notes
upcoming-release-notes/7315.md
Added release note entry (category: Bugfix, author set) documenting the fix for QIF-imported transaction categories.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nibbled through QIF leaves, found labels tucked tight,
Wove main and sub with a hop, stitched them just right.
Payees dance, amounts hum, categories now sing,
A carrot-coded triumph — I twirl and I spring! 🥕

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the primary fix: importing transaction categories from QIF files, which is the main objective of the PR.
Description check ✅ Passed The PR description clearly explains the problem, solution, and testing approach, all directly related to the changeset.
Linked Issues check ✅ Passed The PR successfully addresses issue #3910 by extending StructuredTransaction with a category field, implementing category mapping logic in parseQIF, and adding comprehensive unit tests covering all specified scenarios.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue: the category field addition, QIF parsing logic, test fixture, and unit tests are all necessary to resolve the reported bug.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Muhammad-Nur-Alamsyah-Anwar added a commit to Muhammad-Nur-Alamsyah-Anwar/actual that referenced this pull request Mar 29, 2026
- Update  type to include optional
- Map / to  in
- Add release note for PR actualbudget#7315
@Muhammad-Nur-Alamsyah-Anwar Muhammad-Nur-Alamsyah-Anwar changed the title [WIP] fix(qif): import transaction categories from QIF files fix(qif): import transaction categories from QIF files Mar 29, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes QIF import so that category/subcategory parsed from L lines is surfaced to the transaction import flow (issue #3910), and documents the change in upcoming release notes.

Changes:

  • Extend QIF parsing in parseQIF to derive a category string from category + subcategory.
  • Add a new transaction field intended to carry imported category information.
  • Add release notes entry for the bugfix.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
upcoming-release-notes/7315.md Adds release note announcing QIF category import support.
packages/loot-core/src/server/transactions/import/parse-file.ts Attempts to include QIF category/subcategory on parsed transactions returned from parseFile.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

payee_name: string;
imported_payee: string;
notes: string;
imported_category?: string;
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imported_category is being added to the parsed transaction objects, but it is not a recognized field in the transactions schema. These objects are later sent back to the server (ImportTransactionsModal spreads all remaining fields into the payload), and db.insertTransaction will throw when schema validation encounters an unknown field. Suggestion: don’t introduce a new top-level field here; instead populate the existing category field with the raw category string for the import modal (it gets mapped to an id before import), or ensure any extra preview-only fields are prefixed with _ / stripped before calling transactions-import.

Suggested change
imported_category?: string;
category?: string;

Copilot uses AI. Check for mistakes.
imported_payee: payeeSource || (fallbackUsed ? memoSource : null),
notes:
options.importNotes && !fallbackUsed ? memoSource || null : null,
imported_category: category || null,
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imported_category: category || null will (1) not be displayed/mapped by the import modal (it looks at transaction.category), and (2) will cause imports to fail because the client sends this field back and the server schema rejects unknown transaction fields on insert/update. Suggestion: put the raw QIF category string into category (or another schema-approved field) and avoid returning imported_category from parseQIF.

Suggested change
imported_category: category || null,
category: category || null,

Copilot uses AI. Check for mistakes.
Comment on lines +187 to +190
const category = trans.subcategory
? `${trans.category}:${trans.subcategory}`
: trans.category;

Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change introduces new behavior (carrying QIF categories through parsing) but there’s no automated coverage added/updated in the existing import test suite (parse-file.test.ts) to assert that categories are preserved/mapped as expected. Adding a targeted QIF fixture/assertion for L lines (including Category:Subcategory) would prevent regressions.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/loot-core/src/server/transactions/import/parse-file.ts`:
- Around line 187-190: The category composition currently does
`${trans.category}:${trans.subcategory}` whenever trans.subcategory exists,
which can produce invalid strings when trans.category is missing; update the
logic where the variable category is set (and the other similar occurrence at
the second composition) to only join with ':' when both trans.category and
trans.subcategory are truthy, otherwise use the single defined part
(trans.category || trans.subcategory) or a safe fallback (e.g., '' or
'Uncategorized') so imported_category never becomes something like
"undefined:Groceries".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3aa86a5-3f9b-4302-a047-17674e6c7582

📥 Commits

Reviewing files that changed from the base of the PR and between 4bf6273 and 8ab4ef2.

📒 Files selected for processing (2)
  • packages/loot-core/src/server/transactions/import/parse-file.ts
  • upcoming-release-notes/7315.md
✅ Files skipped from review due to trivial changes (1)
  • upcoming-release-notes/7315.md

Muhammad-Nur-Alamsyah-Anwar added a commit to Muhammad-Nur-Alamsyah-Anwar/actual that referenced this pull request Mar 29, 2026
- Update  type to include optional
- Map / to  in
- Add release note for PR actualbudget#7315
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/loot-core/src/server/transactions/import/parse-file.ts (1)

187-190: ⚠️ Potential issue | 🟡 Minor

Guard category composition to avoid malformed imported_category values.

At Line 187, joining whenever trans.subcategory exists can emit invalid values like undefined:Groceries if trans.category is absent. Compose with : only when both parts are present; otherwise use whichever single part exists.

Proposed fix
-        const category = trans.subcategory
-          ? `${trans.category}:${trans.subcategory}`
-          : trans.category;
+        const importedCategory =
+          trans.category && trans.subcategory
+            ? `${trans.category}:${trans.subcategory}`
+            : trans.category || trans.subcategory || null;

         return {
           amount:
             trans.amount != null ? looselyParseAmount(trans.amount) : null,
           date: trans.date,
           payee_name: payeeSource || (fallbackUsed ? memoSource : null),
           imported_payee: payeeSource || (fallbackUsed ? memoSource : null),
           notes:
             options.importNotes && !fallbackUsed ? memoSource || null : null,
-          imported_category: category || null,
+          imported_category: importedCategory,
         };

Also applies to: 199-199

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/loot-core/src/server/transactions/import/parse-file.ts` around lines
187 - 190, The current category composition assigns `category` by concatenating
`trans.category` and `trans.subcategory` when `trans.subcategory` exists, which
can produce malformed values like "undefined:Groceries"; update the logic where
`category` is computed (the assignment that references `trans.subcategory` and
`trans.category`) to only join with ":" when both `trans.category` and
`trans.subcategory` are non-empty/defined, otherwise set `category` to whichever
of `trans.category` or `trans.subcategory` is present (or undefined/null if
neither); apply the same guarded composition fix to the other occurrence
mentioned (the similar assignment around the other block at the later
occurrence).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/loot-core/src/server/transactions/import/parse-file.ts`:
- Around line 187-190: The current category composition assigns `category` by
concatenating `trans.category` and `trans.subcategory` when `trans.subcategory`
exists, which can produce malformed values like "undefined:Groceries"; update
the logic where `category` is computed (the assignment that references
`trans.subcategory` and `trans.category`) to only join with ":" when both
`trans.category` and `trans.subcategory` are non-empty/defined, otherwise set
`category` to whichever of `trans.category` or `trans.subcategory` is present
(or undefined/null if neither); apply the same guarded composition fix to the
other occurrence mentioned (the similar assignment around the other block at the
later occurrence).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 957468cb-08e3-43e1-b02d-1a8163e355e4

📥 Commits

Reviewing files that changed from the base of the PR and between 8ab4ef2 and 913bb01.

📒 Files selected for processing (2)
  • packages/loot-core/src/server/transactions/import/parse-file.ts
  • upcoming-release-notes/7315.md
✅ Files skipped from review due to trivial changes (1)
  • upcoming-release-notes/7315.md

@coderabbitai coderabbitai bot removed the size small label Mar 29, 2026
QIF files use L lines to specify transaction categories, and qif2json
already parses them into category/subcategory. The problem was in
parseQIF — it was just dropping them instead of mapping them through.
Also guard against "undefined:Groceries" when only subcategory is set.

Fixes actualbudget#3910
@Muhammad-Nur-Alamsyah-Anwar
Copy link
Copy Markdown
Author

Muhammad-Nur-Alamsyah-Anwar commented Mar 29, 2026

Hey, I've addressed the review comments in the latest commits — switched to the category field and added a guard so you don't get undefined:Groceries when only subcategory is present. Also added unit tests and a QIF fixture. @coderabbitai please re-review.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

Let me fetch the latest state of the changed files to conduct a thorough re-review.


🏁 Script executed:

#!/bin/bash
# Get the current state of parse-file.ts (QIF section)
rg -n "parseQIF|subcategory|importedCategory|category" packages/loot-core/src/server/transactions/import/parse-file.ts -A2 -B2

echo "=== StructuredTransaction type ==="
rg -n "StructuredTransaction" packages/loot-core/src/server/transactions/import/parse-file.ts -A15

echo "=== Full parseQIF function ==="
ast-grep --pattern 'function parseQIF($_) {
  $$$
}'

echo "=== Test file ==="
fd "parse-file.test.ts" --exec cat {}

echo "=== QIF fixture ==="
fd "data-with-categories.qif" --exec cat {}

Length of output: 46590


@Muhammad-Nur-Alamsyah-Anwar: Thank you for addressing all the review comments! Here's a summary of what I verified in the latest commit:

StructuredTransaction typecategory?: string is the correct field (not imported_category).

✅ Category guard logic — The fix correctly handles all cases:

trans.category && trans.subcategory
  ? `${trans.category}:${trans.subcategory}`
  : trans.category || trans.subcategory || null
  • LUsual Expenses:Shoppingcategory: 'Usual Expenses', subcategory: 'Shopping'"Usual Expenses:Shopping"
  • LGroceriescategory: 'Groceries', no subcategory → "Groceries"
  • No L line → both undefined → null

✅ Unit tests — Two new tests in parse-file.test.ts:

  1. qif import preserves categories from L lines — validates each of the three fixture transactions.
  2. qif import handles missing category gracefully — confirms data.qif (no L lines) produces null categories for all transactions.

✅ QIF fixture (data-with-categories.qif) — Covers the category-only, category+subcategory, and no-category cases.

The implementation looks solid and all previously raised concerns have been properly resolved. The PR is ready from a code review perspective. 🐇


🧠 Learnings used
Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js:1-2
Timestamp: 2026-02-18T20:28:32.168Z
Learning: In the actualbudget/actual repository, JavaScript files under packages/sync-server/src/app-gocardless/banks/ should not be converted to TypeScript in code reviews. These bank integration files are intentionally kept as JS and will be migrated to TypeScript in a separate coordinated effort.

Learnt from: MatissJanis
Repo: actualbudget/actual PR: 7200
File: packages/api/methods.ts:12-12
Timestamp: 2026-03-14T13:05:42.963Z
Learning: In `packages/api/methods.ts`, `ImportTransactionsOpts` (imported from `actual-app/core/types/api-handlers`) used as a parameter type in `importTransactions()` is acceptable. MatissJanis confirmed this is OK even though the function is part of the public API surface. The previous concern about leaking the internal type does not apply here — only explicit named re-exports of `ImportTransactionsOpts` from the public index should be avoided.

Learnt from: misu-dev
Repo: actualbudget/actual PR: 5167
File: packages/desktop-client/src/components/spreadsheet/useFormat.ts:64-72
Timestamp: 2025-06-16T17:45:40.807Z
Learning: The user misu-dev prefers strict type checking for financial format types in useFormat.ts as a long-term goal, but acknowledges that creating follow-up issues for cleanup should wait until after the current PR is merged, not during the development phase.

Learnt from: MatissJanis
Repo: actualbudget/actual PR: 5770
File: packages/loot-core/src/server/transactions/import/parse-file.ts:58-59
Timestamp: 2025-09-22T16:56:19.716Z
Learning: In the ImportTransactionsModal system, ParseFileResult.transactions?: Transaction[] is correct because the Transaction type includes `& Record<string, string | number | boolean>` which allows CSV raw data to conform to the type, and field mappings (applyFieldMappings) handle transformation from raw CSV columns to transaction fields later in the process.

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 29, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Tip

For best results, initiate chat on the files or code changes.

@Muhammad-Nur-Alamsyah-Anwar: The re-review has already been completed — please see my response just above in this thread. To summarize:

  • StructuredTransaction.category?: string field is correctly used.
  • ✅ The guard logic correctly handles all three cases: category + subcategory, category only, and null when neither is present.
  • ✅ Unit tests cover both the happy path (L lines preserved) and the graceful fallback (no L lines → null).
  • ✅ The QIF fixture (data-with-categories.qif) covers all relevant scenarios.

All previously raised concerns have been properly resolved. The PR is ready from a code review perspective. 🐇


🧠 Learnings used
Learnt from: MatissJanis
Repo: actualbudget/actual PR: 7200
File: packages/api/methods.ts:12-12
Timestamp: 2026-03-14T13:05:42.963Z
Learning: In `packages/api/methods.ts`, `ImportTransactionsOpts` (imported from `actual-app/core/types/api-handlers`) used as a parameter type in `importTransactions()` is acceptable. MatissJanis confirmed this is OK even though the function is part of the public API surface. The previous concern about leaking the internal type does not apply here — only explicit named re-exports of `ImportTransactionsOpts` from the public index should be avoided.

Learnt from: MatissJanis
Repo: actualbudget/actual PR: 5770
File: packages/loot-core/src/server/transactions/import/parse-file.ts:58-59
Timestamp: 2025-09-22T16:56:19.716Z
Learning: In the ImportTransactionsModal system, ParseFileResult.transactions?: Transaction[] is correct because the Transaction type includes `& Record<string, string | number | boolean>` which allows CSV raw data to conform to the type, and field mappings (applyFieldMappings) handle transformation from raw CSV columns to transaction fields later in the process.

Learnt from: misu-dev
Repo: actualbudget/actual PR: 5167
File: packages/desktop-client/src/components/spreadsheet/useFormat.ts:64-72
Timestamp: 2025-06-16T17:45:40.807Z
Learning: The user misu-dev prefers strict type checking for financial format types in useFormat.ts as a long-term goal, but acknowledges that creating follow-up issues for cleanup should wait until after the current PR is merged, not during the development phase.

@Muhammad-Nur-Alamsyah-Anwar
Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

✅ Actions performed

Full review triggered.

const fallbackUsed = !payeeSource && swap;

const importedCategory =
trans.category && trans.subcategory
Copy link
Copy Markdown
Contributor

@StephenBrown2 StephenBrown2 Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an enhancement, if both category and subcategory are created, could we check if the category already exists as a category group and import to the subcategory -> category instead of joining the names?

QIF Actual
category category group
subcategory category

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. If the : is standard in QIF to separate category and subcategory, then they should be mapped to Actual directly as group and category.

@matt-fidd matt-fidd force-pushed the master branch 2 times, most recently from 5c7c70d to d262f7d Compare April 5, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: parseQIF function does not return assigned category thus category is empty on import modal

4 participants