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