mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 12:43:09 -05:00
🐛 (import) fix YNAB (and other) importers (#1462)
This commit is contained in:
committed by
GitHub
parent
cd54a2093e
commit
7b7e6e4db0
1681
packages/desktop-client/e2e/data/ynab5-demo-budget.json
Normal file
1681
packages/desktop-client/e2e/data/ynab5-demo-budget.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -41,8 +41,21 @@ test.describe('Onboarding', () => {
|
||||
await expect(accountPage.accountBalance).toHaveText('2,607.00');
|
||||
});
|
||||
|
||||
// TODO: implement this test once we have an example nYNAB file
|
||||
// test('creates a new budget file by importing nYNAB budget');
|
||||
test('creates a new budget file by importing nYNAB budget', async () => {
|
||||
await configurationPage.clickOnNoServer();
|
||||
const budgetPage = await configurationPage.importBudget(
|
||||
'nYNAB',
|
||||
path.resolve(__dirname, 'data/ynab5-demo-budget.json'),
|
||||
);
|
||||
|
||||
await expect(budgetPage.budgetTable).toBeVisible({ timeout: 30000 });
|
||||
|
||||
const accountPage = await navigation.goToAccountPage('Checking');
|
||||
await expect(accountPage.accountBalance).toHaveText('700.00');
|
||||
|
||||
await navigation.goToAccountPage('Saving');
|
||||
await expect(accountPage.accountBalance).toHaveText('200.00');
|
||||
});
|
||||
|
||||
test('creates a new budget file by importing Actual budget', async () => {
|
||||
await configurationPage.clickOnNoServer();
|
||||
|
||||
@@ -6,11 +6,11 @@ import { importBudget } from 'loot-core/src/client/actions/budgets';
|
||||
import { styles, colors } from '../../style';
|
||||
import Block from '../common/Block';
|
||||
import { ButtonWithLoading } from '../common/Button';
|
||||
import Modal from '../common/Modal';
|
||||
import Modal, { type ModalProps } from '../common/Modal';
|
||||
import Paragraph from '../common/Paragraph';
|
||||
import View from '../common/View';
|
||||
|
||||
function getErrorMessage(error) {
|
||||
function getErrorMessage(error: string): string {
|
||||
switch (error) {
|
||||
case 'parse-error':
|
||||
return 'Unable to parse file. Please select a JSON file exported from nYNAB.';
|
||||
@@ -27,9 +27,13 @@ function getErrorMessage(error) {
|
||||
}
|
||||
}
|
||||
|
||||
function Import({ modalProps }) {
|
||||
type ImportProps = {
|
||||
modalProps?: ModalProps;
|
||||
};
|
||||
|
||||
function Import({ modalProps }: ImportProps) {
|
||||
const dispatch = useDispatch();
|
||||
const [error, setError] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [importing, setImporting] = useState(false);
|
||||
|
||||
async function onImport() {
|
||||
@@ -39,7 +43,7 @@ function Import({ modalProps }) {
|
||||
});
|
||||
if (res) {
|
||||
setImporting(true);
|
||||
setError(false);
|
||||
setError(null);
|
||||
try {
|
||||
await dispatch(importBudget(res[0], 'actual'));
|
||||
} catch (err) {
|
||||
@@ -6,11 +6,11 @@ import { importBudget } from 'loot-core/src/client/actions/budgets';
|
||||
import { styles, colors } from '../../style';
|
||||
import Block from '../common/Block';
|
||||
import { ButtonWithLoading } from '../common/Button';
|
||||
import Modal from '../common/Modal';
|
||||
import Modal, { type ModalProps } from '../common/Modal';
|
||||
import Paragraph from '../common/Paragraph';
|
||||
import View from '../common/View';
|
||||
|
||||
function getErrorMessage(error) {
|
||||
function getErrorMessage(error: string): string {
|
||||
switch (error) {
|
||||
case 'not-ynab4':
|
||||
return 'This file is not valid. Please select a compressed ynab4 zip file.';
|
||||
@@ -19,9 +19,13 @@ function getErrorMessage(error) {
|
||||
}
|
||||
}
|
||||
|
||||
function Import({ modalProps }) {
|
||||
type ImportProps = {
|
||||
modalProps?: ModalProps;
|
||||
};
|
||||
|
||||
function Import({ modalProps }: ImportProps) {
|
||||
const dispatch = useDispatch();
|
||||
const [error, setError] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [importing, setImporting] = useState(false);
|
||||
|
||||
async function onImport() {
|
||||
@@ -31,7 +35,7 @@ function Import({ modalProps }) {
|
||||
});
|
||||
if (res) {
|
||||
setImporting(true);
|
||||
setError(false);
|
||||
setError(null);
|
||||
try {
|
||||
await dispatch(importBudget(res[0], 'ynab4'));
|
||||
} catch (err) {
|
||||
@@ -7,11 +7,11 @@ import { styles, colors } from '../../style';
|
||||
import Block from '../common/Block';
|
||||
import { ButtonWithLoading } from '../common/Button';
|
||||
import ExternalLink from '../common/ExternalLink';
|
||||
import Modal from '../common/Modal';
|
||||
import Modal, { type ModalProps } from '../common/Modal';
|
||||
import Paragraph from '../common/Paragraph';
|
||||
import View from '../common/View';
|
||||
|
||||
function getErrorMessage(error) {
|
||||
function getErrorMessage(error: string): string {
|
||||
switch (error) {
|
||||
case 'parse-error':
|
||||
return 'Unable to parse file. Please select a JSON file exported from nYNAB.';
|
||||
@@ -22,9 +22,13 @@ function getErrorMessage(error) {
|
||||
}
|
||||
}
|
||||
|
||||
function Import({ modalProps }) {
|
||||
type ImportProps = {
|
||||
modalProps?: ModalProps;
|
||||
};
|
||||
|
||||
function Import({ modalProps }: ImportProps) {
|
||||
const dispatch = useDispatch();
|
||||
const [error, setError] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [importing, setImporting] = useState(false);
|
||||
|
||||
async function onImport() {
|
||||
@@ -34,7 +38,7 @@ function Import({ modalProps }) {
|
||||
});
|
||||
if (res) {
|
||||
setImporting(true);
|
||||
setError(false);
|
||||
setError(null);
|
||||
try {
|
||||
await dispatch(importBudget(res[0], 'ynab5'));
|
||||
} catch (err) {
|
||||
@@ -147,7 +147,6 @@ export function handleGlobalEvents(actions, store) {
|
||||
|
||||
listen('start-import', () => {
|
||||
actions.closeBudgetUI();
|
||||
actions.setAppState({ loadingText: 'Importing...' });
|
||||
});
|
||||
|
||||
listen('finish-import', () => {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
export namespace YNAB5 {
|
||||
export interface Budget {
|
||||
budget_name: string;
|
||||
name?: string;
|
||||
budget_name?: string;
|
||||
accounts: Account[];
|
||||
payees: Payee[];
|
||||
category_groups: CategoryGroup[];
|
||||
|
||||
@@ -294,10 +294,13 @@ export function parseFile(buffer: Buffer): YNAB5.Budget {
|
||||
if (data.data) {
|
||||
data = data.data;
|
||||
}
|
||||
if (data.budget) {
|
||||
data = data.budget;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export function getBudgetName(_filepath: string, data: YNAB5.Budget) {
|
||||
return data.budget_name;
|
||||
return data.budget_name || data.name;
|
||||
}
|
||||
|
||||
@@ -2053,14 +2053,13 @@ handlers['import-budget'] = async function ({ filepath, type }) {
|
||||
}
|
||||
|
||||
let buffer = Buffer.from(await fs.readFile(filepath, 'binary'));
|
||||
await handleBudgetImport(type, filepath, buffer);
|
||||
let results = await handleBudgetImport(type, filepath, buffer);
|
||||
return results || {};
|
||||
} catch (err) {
|
||||
err.message = 'Error importing budget: ' + err.message;
|
||||
captureException(err);
|
||||
return { error: 'internal-error' };
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
handlers['export-budget'] = async function () {
|
||||
|
||||
6
upcoming-release-notes/1462.md
Normal file
6
upcoming-release-notes/1462.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Bugfix
|
||||
authors: [MatissJanis]
|
||||
---
|
||||
|
||||
Fix import from nYNAB and error-handling of other importers
|
||||
Reference in New Issue
Block a user