diff --git a/packages/desktop-client/src/components/accounts/Account.js b/packages/desktop-client/src/components/accounts/Account.js
index 8785669fcdd..43f889b6828 100644
--- a/packages/desktop-client/src/components/accounts/Account.js
+++ b/packages/desktop-client/src/components/accounts/Account.js
@@ -462,6 +462,7 @@ class AccountInternal extends PureComponent {
onImport = async () => {
const accountId = this.props.accountId;
const account = this.props.accounts.find(acct => acct.id === accountId);
+ const categories = await this.props.getCategories();
if (account) {
const res = await window.Actual.openFileDialog({
@@ -476,6 +477,7 @@ class AccountInternal extends PureComponent {
if (res) {
this.props.pushModal('import-transactions', {
accountId,
+ categories,
filename: res[0],
onImported: didChange => {
if (didChange) {
diff --git a/packages/desktop-client/src/components/modals/ImportTransactions.js b/packages/desktop-client/src/components/modals/ImportTransactions.js
index e9f27f5c80a..65bb061e766 100644
--- a/packages/desktop-client/src/components/modals/ImportTransactions.js
+++ b/packages/desktop-client/src/components/modals/ImportTransactions.js
@@ -182,14 +182,18 @@ function getInitialMappings(transactions) {
fields.find(([name, value]) => value.match(/^-?[.,\d]+$/)),
);
+ let categoryField = key(
+ fields.find(([name, value]) => name.toLowerCase().includes('category')),
+ );
+
let payeeField = key(
- fields.find(([name, value]) => name !== dateField && name !== amountField),
+ fields.find(([name, value]) => name !== dateField && name !== amountField && name !== categoryField),
);
let notesField = key(
fields.find(
([name, value]) =>
- name !== dateField && name !== amountField && name !== payeeField,
+ name !== dateField && name !== amountField && name !== categoryField && name !== payeeField,
),
);
@@ -198,6 +202,7 @@ function getInitialMappings(transactions) {
amount: amountField,
payee: payeeField,
notes: notesField,
+ category: categoryField,
};
}
@@ -248,6 +253,19 @@ function parseAmountFields(trans, splitMode, flipAmount, multiplierAmount) {
};
}
+function parseCategoryFields(trans, categories) {
+ let match = null;
+ for (let category of categories) {
+ if (category.id === trans.category) {
+ return null;
+ }
+ if (category.name === trans.category) {
+ match = category.id;
+ }
+ }
+ return match;
+}
+
function Transaction({
transaction: rawTransaction,
fieldMappings,
@@ -302,6 +320,9 @@ function Transaction({
{transaction.notes}
+
+ {transaction.category}
+
{splitMode ? (
<>
+
+
+ onChange('category', name)}
+ hasHeaderRow={hasHeaderRow}
+ firstTransaction={transactions[0]}
+ />
+
{splitMode ? (
<>
@@ -571,7 +603,7 @@ export default function ImportTransactions({ modalProps, options }) {
let [splitMode, setSplitMode] = useState(false);
let [flipAmount, setFlipAmount] = useState(false);
let [multiplierEnabled, setMultiplierEnabled] = useState(false);
- let { accountId, onImported } = options;
+ let { accountId, categories, onImported } = options;
// This cannot be set after parsing the file, because changing it
// requires re-parsing the file. This is different from the other
@@ -757,6 +789,11 @@ export default function ImportTransactions({ modalProps, options }) {
break;
}
+ const category_id = parseCategoryFields(trans, categories.list);
+ if (category_id != null) {
+ trans.category = category_id;
+ }
+
let { inflow, outflow, ...finalTransaction } = trans;
finalTransactions.push({
...finalTransaction,
@@ -810,6 +847,7 @@ export default function ImportTransactions({ modalProps, options }) {
{ name: 'Date', width: 200 },
{ name: 'Payee', width: 'flex' },
{ name: 'Notes', width: 'flex' },
+ { name: 'Category', width: 'flex' },
];
if (splitMode) {
@@ -847,7 +885,7 @@ export default function ImportTransactions({ modalProps, options }) {
index}
renderEmpty={() => {
diff --git a/upcoming-release-notes/1801.md b/upcoming-release-notes/1801.md
new file mode 100644
index 00000000000..b6199f33614
--- /dev/null
+++ b/upcoming-release-notes/1801.md
@@ -0,0 +1,6 @@
+---
+category: Enhancements
+authors: [ScottFries,blakegearin]
+---
+
+Add ability to import categories from CSV
\ No newline at end of file