diff --git a/packages/loot-core/src/mocks/files/8859-1.qfx b/packages/loot-core/src/mocks/files/8859-1.qfx new file mode 100644 index 0000000000000000000000000000000000000000..8e678c9be0c8bfd6aede980225fbdd45573c0f2e --- /dev/null +++ b/packages/loot-core/src/mocks/files/8859-1.qfx @@ -0,0 +1,63 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:TYPE1 +ENCODING:USASCII +CHARSET:8859-1 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE +<OFX> +<SIGNONMSGSRSV1> +<SONRS> +<STATUS> +<CODE>0 +<SEVERITY>INFO +<MESSAGE>OK +</STATUS> +<DTSERVER>20221020231556 +<USERKEY>3AAAAAAAAAAAAAA +<INTU.BID>00999 +<LANGUAGE>FRA +</SONRS> +</SIGNONMSGSRSV1> +<BANKMSGSRSV1> +<STMTTRNRS> +<TRNUID>AAAA-2022102023155614357 +<STATUS> +<CODE>0 +<SEVERITY>INFO +<MESSAGE>OK +</STATUS> +<STMTRS> +<CURDEF>CAD +<BANKACCTFROM> +<BANKID>700012345 +<BRANCHID>0055666 +<ACCTID>999-12345-0055666-EOP +<ACCTTYPE>CHECKING +</BANKACCTFROM> +<BANKTRANLIST> +<DTSTART>20221019120000 +<DTEND>20221019120000 +<STMTTRN> +<TRNTYPE>DEBIT +<DTPOSTED>20221019120000 +<TRNAMT>-20.00 +<FITID>wSoKuCS77 +<NAME>Paiement facture/Carte prépayée +<MEMO>PWW +</STMTTRN> +</BANKTRANLIST> +<LEDGERBAL> +<BALAMT>9999.99 +<DTASOF>20221020231556 +</LEDGERBAL> +<AVAILBAL> +<BALAMT>9999.99 +<DTASOF>20221020231556 +</AVAILBAL> +</STMTRS> +</STMTTRNRS> +</BANKMSGSRSV1> +</OFX> diff --git a/packages/loot-core/src/server/accounts/__snapshots__/parse-file.test.js.snap b/packages/loot-core/src/server/accounts/__snapshots__/parse-file.test.js.snap index c1300f42560f96bb7b68dccfd45876619a5d5d1b..5ada01f60d4186cc58b0802dd73e13c133aae631 100644 --- a/packages/loot-core/src/server/accounts/__snapshots__/parse-file.test.js.snap +++ b/packages/loot-core/src/server/accounts/__snapshots__/parse-file.test.js.snap @@ -1,5 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`File import handles non-ASCII characters 1`] = ` +Array [ + Object { + "acct": "one", + "amount": -2000, + "category": null, + "cleared": 1, + "date": 20221019, + "description": "id2", + "error": null, + "financial_id": "wSoKuCS77", + "id": "id3", + "imported_description": "Paiement facture/Carte prépayée", + "isChild": 0, + "isParent": 0, + "location": null, + "notes": "PWW", + "parent_id": null, + "pending": 0, + "schedule": null, + "sort_order": 123456789, + "starting_balance_flag": 0, + "tombstone": 0, + "transferred_id": null, + "type": null, + }, +] +`; + exports[`File import ofx import works 1`] = ` Array [ Object { diff --git a/packages/loot-core/src/server/accounts/parse-file.js b/packages/loot-core/src/server/accounts/parse-file.js index 06b6f793bc8e0e71ad1219f71ab1ef677de145f9..8d26e09d4fa520ff341c13e0d9bc26e6f3687577 100644 --- a/packages/loot-core/src/server/accounts/parse-file.js +++ b/packages/loot-core/src/server/accounts/parse-file.js @@ -91,7 +91,7 @@ async function parseOFX(filepath) { await initModule(); let errors = []; - let contents = await fs.readFile(filepath); + let contents = await fs.readFile(filepath, 'binary'); let data; try { diff --git a/packages/loot-core/src/server/accounts/parse-file.test.js b/packages/loot-core/src/server/accounts/parse-file.test.js index 785d2da4ad5a4f61cc7c9e1653739fca6544cc7c..ad3593f510eea783e86d6d75ab2c7ca805b22b2e 100644 --- a/packages/loot-core/src/server/accounts/parse-file.test.js +++ b/packages/loot-core/src/server/accounts/parse-file.test.js @@ -9,6 +9,17 @@ import { reconcileTransactions } from './sync'; beforeEach(global.emptyDatabase()); +// libofx spits out errors that contain the entire +// source code of the file in the stack which makes +// it hard to test. +let old = console.warn; +beforeAll(() => { + console.warn = () => {}; +}); +afterAll(() => { + console.warn = old; +}); + async function getTransactions(accountId) { return db.runQuery( 'SELECT * FROM transactions WHERE acct = ?', @@ -99,4 +110,17 @@ describe('File import', () => { expect(res.errors.length).toBe(1); expect(res.errors[0].message).toBe('Invalid file type'); }, 45000); + + test('handles non-ASCII characters', async () => { + prefs.loadPrefs(); + await db.insertAccount({ id: 'one', name: 'one' }); + + let { errors } = await importFileWithRealTime( + 'one', + __dirname + '/../../mocks/files/8859-1.qfx', + 'yyyy-MM-dd' + ); + expect(errors.length).toBe(0); + expect(await getTransactions('one')).toMatchSnapshot(); + }); }); diff --git a/packages/node-libofx/ffi.js b/packages/node-libofx/ffi.js index b4a49ae98f1d5af96fcc62e45bc31e15be49c450..f3e9d7dfcc2f4108dce8c9c311d42ccfca94fae8 100644 --- a/packages/node-libofx/ffi.js +++ b/packages/node-libofx/ffi.js @@ -3,7 +3,7 @@ function create(libofx) { init: libofx.cwrap('init', null, ['number']), debug: libofx.cwrap('debug', null, []), get_new_context: libofx.cwrap('get_new_context', 'number', []), - parse_data: libofx.cwrap('parse_data', null, ['number', 'string']), + parse_data: libofx.cwrap('parse_data', null, ['number', 'array']), ofx_set_transaction_cb: libofx.cwrap('ofx_set_transaction_cb', null, [ 'number',