diff --git a/README.md b/README.md index b1474e4d2..fb6d4941c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +> [!IMPORTANT] +> This repository will be merged into [actualbudget/actual](https://github.com/actualbudget/actual/tree/master/packages/sync-server) in February 2025 and placed in a readonly state. For more information please see our [Docs](https://actualbudget.org/docs/actual-server-repo-move) or our [Discord](https://discord.com/invite/pRYNYr4W5A). + + This is the main project to run [Actual](https://github.com/actualbudget/actual), a local-first personal finance tool. It comes with the latest version of Actual, and a server to persist changes and make data available across all devices. ### Getting Started @@ -7,7 +11,7 @@ If you are interested in contributing, or want to know how development works, se Want to say thanks? Click the ⭐ at the top of the page. -### Documentation +### Documentation We have a wide range of documentation on how to use Actual. This is all available in our [Community Documentation](https://actualbudget.org/docs/), including topics on [installing](https://actualbudget.org/docs/install/), [Budgeting](https://actualbudget.org/docs/budgeting/), [Account Management](https://actualbudget.org/docs/accounts/), [Tips & Tricks](https://actualbudget.org/docs/getting-started/tips-tricks) and some documentation for developers. diff --git a/package.json b/package.json index 36aa60ad3..ca75553d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "actual-sync", - "version": "25.1.0", + "version": "25.2.1", "license": "MIT", "description": "actual syncing server", "type": "module", @@ -23,7 +23,7 @@ }, "dependencies": { "@actual-app/crdt": "2.1.0", - "@actual-app/web": "25.1.0", + "@actual-app/web": "25.2.1", "bcrypt": "^5.1.1", "better-sqlite3": "^11.7.0", "body-parser": "^1.20.3", diff --git a/src/app-gocardless/bank-factory.js b/src/app-gocardless/bank-factory.js index 5a3fb7280..33d6a4ec8 100644 --- a/src/app-gocardless/bank-factory.js +++ b/src/app-gocardless/bank-factory.js @@ -1,83 +1,30 @@ -import AbancaCaglesmm from './banks/abanca_caglesmm.js'; -import AbnamroAbnanl2a from './banks/abnamro_abnanl2a.js'; -import AmericanExpressAesudef1 from './banks/american_express_aesudef1.js'; -import BancsabadellBsabesbb from './banks/bancsabadell_bsabesbbb.js'; -import BankinterBkbkesmm from './banks/bankinter_bkbkesmm.js'; -import BankOfIrelandB365Bofiie2d from './banks/bank_of_ireland_b365_bofiie2d.js'; -import BelfiusGkccbebb from './banks/belfius_gkccbebb.js'; -import BerlinerSparkasseBeladebexxx from './banks/berliner_sparkasse_beladebexxx.js'; -import BnpBeGebabebb from './banks/bnp_be_gebabebb.js'; -import CbcCregbebb from './banks/cbc_cregbebb.js'; -import CommerzbankCobadeff from './banks/commerzbank_cobadeff.js'; -import DanskebankDabno22 from './banks/danskebank_dabno22.js'; -import DirektHeladef1822 from './banks/direkt_heladef1822.js'; -import EasybankBawaatww from './banks/easybank_bawaatww.js'; -import EntercardSwednokk from './banks/entercard_swednokk.js'; -import FortuneoFtnofrp1xxx from './banks/fortuneo_ftnofrp1xxx.js'; -import HypeHyeeit22 from './banks/hype_hyeeit22.js'; -import IngIngbrobu from './banks/ing_ingbrobu.js'; -import IngIngddeff from './banks/ing_ingddeff.js'; -import IngPlIngbplpw from './banks/ing_pl_ingbplpw.js'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + import IntegrationBank from './banks/integration-bank.js'; -import IsyBankItbbitmm from './banks/isybank_itbbitmm.js'; -import KbcKredbebb from './banks/kbc_kredbebb.js'; -import LhvLhvbee22 from './banks/lhv-lhvbee22.js'; -import MbankRetailBrexplpw from './banks/mbank_retail_brexplpw.js'; -import NationwideNaiagb21 from './banks/nationwide_naiagb21.js'; -import NbgEthngraaxxx from './banks/nbg_ethngraaxxx.js'; -import NorwegianXxNorwnok1 from './banks/norwegian_xx_norwnok1.js'; -import RevolutRevolt21 from './banks/revolut_revolt21.js'; -import SebKortBankAb from './banks/seb_kort_bank_ab.js'; -import SebPrivat from './banks/seb_privat.js'; -import SandboxfinanceSfin0000 from './banks/sandboxfinance_sfin0000.js'; -import SparnordSpnodk22 from './banks/sparnord_spnodk22.js'; -import SpkKarlsruheKarsde66 from './banks/spk_karlsruhe_karsde66.js'; -import SpkMarburgBiedenkopfHeladef1mar from './banks/spk_marburg_biedenkopf_heladef1mar.js'; -import SpkWormsAlzeyRiedMalade51wor from './banks/spk_worms_alzey_ried_malade51wor.js'; -import SskDusseldorfDussdeddxxx from './banks/ssk_dusseldorf_dussdeddxxx.js'; -import SwedbankHabalv22 from './banks/swedbank_habalv22.js'; -import VirginNrnbgb22 from './banks/virgin_nrnbgb22.js'; -export const banks = [ - AbancaCaglesmm, - AbnamroAbnanl2a, - AmericanExpressAesudef1, - BancsabadellBsabesbb, - BankinterBkbkesmm, - BankOfIrelandB365Bofiie2d, - BelfiusGkccbebb, - BerlinerSparkasseBeladebexxx, - BnpBeGebabebb, - CbcCregbebb, - CommerzbankCobadeff, - DanskebankDabno22, - DirektHeladef1822, - EasybankBawaatww, - EntercardSwednokk, - FortuneoFtnofrp1xxx, - HypeHyeeit22, - IngIngbrobu, - IngIngddeff, - IngPlIngbplpw, - IsyBankItbbitmm, - KbcKredbebb, - LhvLhvbee22, - MbankRetailBrexplpw, - NationwideNaiagb21, - NbgEthngraaxxx, - NorwegianXxNorwnok1, - RevolutRevolt21, - SebKortBankAb, - SebPrivat, - SandboxfinanceSfin0000, - SparnordSpnodk22, - SpkKarlsruheKarsde66, - SpkMarburgBiedenkopfHeladef1mar, - SpkWormsAlzeyRiedMalade51wor, - SskDusseldorfDussdeddxxx, - SwedbankHabalv22, - VirginNrnbgb22, -]; +const dirname = path.resolve(fileURLToPath(import.meta.url), '..'); +const banksDir = path.resolve(dirname, 'banks'); + +async function loadBanks() { + const bankHandlers = fs + .readdirSync(banksDir) + .filter((filename) => filename.includes('_') && filename.endsWith('.js')); + + const imports = await Promise.all( + bankHandlers.map((file) => { + const fileUrlToBank = pathToFileURL(path.resolve(banksDir, file)); // pathToFileURL for ESM compatibility + return import(fileUrlToBank.toString()).then( + (handler) => handler.default, + ); + }), + ); + + return imports; +} + +export const banks = await loadBanks(); export default (institutionId) => banks.find((b) => b.institutionIds.includes(institutionId)) || diff --git a/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js b/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js index 1de9f4848..b196afe44 100644 --- a/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js +++ b/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js @@ -7,6 +7,18 @@ export default { institutionIds: ['SSK_DUSSELDORF_DUSSDEDDXXX'], normalizeTransaction(transaction, _booked) { + // If the transaction is not booked yet by the bank, don't import it. + // Reason being that the transaction doesn't have the information yet + // to make the payee and notes field be of any use. It's filled with + // a placeholder text and wouldn't be corrected on the next sync. + if (!_booked) { + console.debug( + 'Skipping unbooked transaction:', + transaction.transactionId, + ); + return null; + } + // Prioritize unstructured information, falling back to structured formats let remittanceInformationUnstructured = transaction.remittanceInformationUnstructured ?? @@ -14,10 +26,12 @@ export default { transaction.remittanceInformationStructuredArray?.join(' '); if (transaction.additionalInformation) - remittanceInformationUnstructured = - (remittanceInformationUnstructured ?? '') + - ' ' + - transaction.additionalInformation; + remittanceInformationUnstructured = [ + remittanceInformationUnstructured, + transaction.additionalInformation, + ] + .filter(Boolean) + .join(' '); const usefulCreditorName = transaction.ultimateCreditor || diff --git a/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js b/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js new file mode 100644 index 000000000..d04f8daea --- /dev/null +++ b/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js @@ -0,0 +1,101 @@ +import { jest } from '@jest/globals'; +import SskDusseldorfDussdeddxxx from '../ssk_dusseldorf_dussdeddxxx.js'; + +describe('ssk_dusseldorf_dussdeddxxx', () => { + let consoleSpy; + + beforeEach(() => { + consoleSpy = jest.spyOn(console, 'debug'); + }); + + afterEach(() => { + consoleSpy.mockRestore(); + }); + + describe('#normalizeTransaction', () => { + const bookedTransactionOne = { + transactionId: '2024102900000000-1', + bookingDate: '2024-10-29', + valueDate: '2024-10-29', + transactionAmount: { + amount: '-99.99', + currency: 'EUR', + }, + creditorName: 'a useful creditor name', + remittanceInformationStructured: 'structured information', + remittanceInformationUnstructured: 'unstructured information', + additionalInformation: 'some additional information', + }; + + const bookedTransactionTwo = { + transactionId: '2024102900000000-2', + bookingDate: '2024-10-29', + valueDate: '2024-10-29', + transactionAmount: { + amount: '-99.99', + currency: 'EUR', + }, + creditorName: 'a useful creditor name', + ultimateCreditor: 'ultimate creditor', + remittanceInformationStructured: 'structured information', + additionalInformation: 'some additional information', + }; + + it('properly combines remittance information', () => { + expect( + SskDusseldorfDussdeddxxx.normalizeTransaction( + bookedTransactionOne, + true, + ).remittanceInformationUnstructured, + ).toEqual('unstructured information some additional information'); + + expect( + SskDusseldorfDussdeddxxx.normalizeTransaction( + bookedTransactionTwo, + true, + ).remittanceInformationUnstructured, + ).toEqual('structured information some additional information'); + }); + + it('prioritizes creditor names correctly', () => { + expect( + SskDusseldorfDussdeddxxx.normalizeTransaction( + bookedTransactionOne, + true, + ).payeeName, + ).toEqual('A Useful Creditor Name'); + + expect( + SskDusseldorfDussdeddxxx.normalizeTransaction( + bookedTransactionTwo, + true, + ).payeeName, + ).toEqual('Ultimate Creditor'); + }); + + const unbookedTransaction = { + transactionId: '2024102900000000-1', + valueDate: '2024-10-29', + transactionAmount: { + amount: '-99.99', + currency: 'EUR', + }, + creditorName: 'some nonsensical creditor', + remittanceInformationUnstructured: 'some nonsensical information', + }; + + it('returns null for unbooked transactions', () => { + expect( + SskDusseldorfDussdeddxxx.normalizeTransaction( + unbookedTransaction, + false, + ), + ).toBeNull(); + + expect(consoleSpy).toHaveBeenCalledWith( + 'Skipping unbooked transaction:', + unbookedTransaction.transactionId, + ); + }); + }); +}); diff --git a/upcoming-release-notes/499.md b/upcoming-release-notes/499.md deleted file mode 100644 index 6c41db698..000000000 --- a/upcoming-release-notes/499.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Bugfix -authors: [twk3] ---- - -Fix the auth proxy trust by ensuring the proxy is in the trust diff --git a/upcoming-release-notes/531.md b/upcoming-release-notes/531.md deleted file mode 100644 index bb2262bc5..000000000 --- a/upcoming-release-notes/531.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [DennaGherlyn] ---- - -Add GoCardless formatter for `SSK_DUSSELDORF_DUSSDEDDXXX` Stadtsparkasse Düsseldorf (Germany) diff --git a/upcoming-release-notes/533.md b/upcoming-release-notes/533.md deleted file mode 100644 index 93f58649d..000000000 --- a/upcoming-release-notes/533.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Bugfix -authors: [robxgd] ---- - -Fixed issue when no payeename is given for KBC transaction \ No newline at end of file diff --git a/upcoming-release-notes/534.md b/upcoming-release-notes/534.md deleted file mode 100644 index 3d03094a6..000000000 --- a/upcoming-release-notes/534.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [UnderKoen] ---- - -Make Google Pay transactions work for ABNAMRO_ABNANL2A diff --git a/upcoming-release-notes/535.md b/upcoming-release-notes/535.md deleted file mode 100644 index 95df93430..000000000 --- a/upcoming-release-notes/535.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Bugfix -authors: [spideraxal] ---- - -Add corner case transaction for ING Bank Romania diff --git a/upcoming-release-notes/537.md b/upcoming-release-notes/537.md deleted file mode 100644 index 0d34ffdf3..000000000 --- a/upcoming-release-notes/537.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [nsulzer] ---- - -Add GoCardless integration for COMMERZBANK_COBADEFF \ No newline at end of file diff --git a/upcoming-release-notes/538.md b/upcoming-release-notes/538.md deleted file mode 100644 index fd2b85351..000000000 --- a/upcoming-release-notes/538.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Maintenance -authors: [lnagel] ---- - -Fix WARN: FromAsCasing: 'as' and 'FROM' keywords' casing do not match in Dockerfiles diff --git a/upcoming-release-notes/539.md b/upcoming-release-notes/539.md deleted file mode 100644 index 28b6968b7..000000000 --- a/upcoming-release-notes/539.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [MatissJanis] ---- - -Add GoCardless formatter for `BANK_OF_IRELAND_B365_BOFIIE2D` Bank of Ireland. diff --git a/upcoming-release-notes/542.md b/upcoming-release-notes/542.md deleted file mode 100644 index 8b20a730d..000000000 --- a/upcoming-release-notes/542.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [lnagel] ---- - -Add GoCardless formatter for LHV Estonia (`LHV_LHVBEE22`). diff --git a/upcoming-release-notes/546.md b/upcoming-release-notes/546.md deleted file mode 100644 index 4ca7cb84e..000000000 --- a/upcoming-release-notes/546.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [Knocks83] ---- - -Add health check section to the existing `docker-compose.yml` file. diff --git a/upcoming-release-notes/547.md b/upcoming-release-notes/547.md deleted file mode 100644 index 19922aec3..000000000 --- a/upcoming-release-notes/547.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [ihhha] ---- - -Add "Caixa Geral De Depositos" PT to banks with limited history diff --git a/upcoming-release-notes/550.md b/upcoming-release-notes/550.md deleted file mode 100644 index fe13d172d..000000000 --- a/upcoming-release-notes/550.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Features -authors: [sergiofmreis] ---- - -Add support for `ABANCA_CORP_CAGLPTPL` payee name diff --git a/upcoming-release-notes/551.md b/upcoming-release-notes/551.md deleted file mode 100644 index c335d9f55..000000000 --- a/upcoming-release-notes/551.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [matt-fidd] ---- - -Use the maximum access validity time provided by GoCardless diff --git a/upcoming-release-notes/554.md b/upcoming-release-notes/554.md deleted file mode 100644 index 41b0fdb20..000000000 --- a/upcoming-release-notes/554.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -category: Enhancements -authors: [matt-fidd] ---- - -Add handler for `direkt_heladef1822` diff --git a/upcoming-release-notes/541.md b/upcoming-release-notes/557.md similarity index 58% rename from upcoming-release-notes/541.md rename to upcoming-release-notes/557.md index 56a0e2b54..5a392e1a4 100644 --- a/upcoming-release-notes/541.md +++ b/upcoming-release-notes/557.md @@ -3,4 +3,4 @@ category: Maintenance authors: [matt-fidd] --- -Standardize GoCardless bank handlers +Dynamically load GoCardless handlers diff --git a/upcoming-release-notes/560.md b/upcoming-release-notes/560.md new file mode 100644 index 000000000..c4b76b05e --- /dev/null +++ b/upcoming-release-notes/560.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [MikesGlitch] +--- + +Updating readme regarding the consolidation of the Actual-Server and Actual repos diff --git a/upcoming-release-notes/566.md b/upcoming-release-notes/566.md new file mode 100644 index 000000000..0b7fca0b1 --- /dev/null +++ b/upcoming-release-notes/566.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [MikesGlitch] +--- + +Fix ESM bug on Windows when loading gocardless banks diff --git a/yarn.lock b/yarn.lock index 54bcc6ef7..ce1f26c42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,10 +16,10 @@ __metadata: languageName: node linkType: hard -"@actual-app/web@npm:25.1.0": - version: 25.1.0 - resolution: "@actual-app/web@npm:25.1.0" - checksum: 10c0/8164184d7d0fe36591d996d4cf0e3fbd9ead1f3fc144f7326e4bd36f831d1a63f44ae5878585e125475334d2a8118e20d65e5fdccddd32f9b8cb656842da278c +"@actual-app/web@npm:25.2.1": + version: 25.2.1 + resolution: "@actual-app/web@npm:25.2.1" + checksum: 10c0/569dc6bdb13096943e65063a0f053ee1eb354aeca219707f2e66ed7af30b20ac498dbfe19292ea068517eb77a7fa8a53c2866661218aba6a26a62243eb7f0019 languageName: node linkType: hard @@ -1531,7 +1531,7 @@ __metadata: resolution: "actual-sync@workspace:." dependencies: "@actual-app/crdt": "npm:2.1.0" - "@actual-app/web": "npm:25.1.0" + "@actual-app/web": "npm:25.2.1" "@babel/preset-typescript": "npm:^7.20.2" "@types/bcrypt": "npm:^5.0.2" "@types/better-sqlite3": "npm:^7.6.12"