@actual-app/sync-server 25.7.0-nightly.20250620 → 25.7.0-nightly.20250621
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { title } from '../../util/title/index.js';
|
|
2
2
|
import Fallback from './integration-bank.js';
|
|
3
|
-
const regexCard = /^CARTE
|
|
4
|
-
const regexAtmWithdrawal = /^RETRAIT DAB
|
|
3
|
+
const regexCard = /^CARTE (?<date>\d{2}\/\d{2}\/\d{2}) (?<payeeName>.+?)( \d+)?( CB\*\d{4})?$/;
|
|
4
|
+
const regexAtmWithdrawal = /^RETRAIT DAB (?<date>\d{2}\/\d{2}\/\d{2}) (?<locationName>.+?) CB\*\d{4,}/;
|
|
5
5
|
const regexTransfer = /^VIR /;
|
|
6
6
|
const regexInstantTransfer = /^VIR INST /;
|
|
7
7
|
const regexSepa = /^(PRLV|VIR) SEPA /;
|
|
8
8
|
const regexLoan = /^ECH PRET:/;
|
|
9
|
+
const regexCreditNote = /^AVOIR (?<date>\d{2}\/\d{2}\/\d{2}) (?<payeeName>.+?) CB\*\d{4,}/;
|
|
9
10
|
/** @type {import('./bank.interface.js').IBank} */
|
|
10
11
|
export default {
|
|
11
12
|
...Fallback,
|
|
@@ -13,59 +14,70 @@ export default {
|
|
|
13
14
|
normalizeTransaction(transaction, booked) {
|
|
14
15
|
const editedTrans = { ...transaction };
|
|
15
16
|
editedTrans.remittanceInformationUnstructuredArray =
|
|
16
|
-
// Remove the backslashes that are sometimes present
|
|
17
|
+
// Remove the localisation with backslashes that are sometimes present
|
|
17
18
|
transaction.remittanceInformationUnstructuredArray
|
|
18
|
-
.map(line => line.replace(
|
|
19
|
+
.map(line => line.replace(/\\.+/g, ''))
|
|
19
20
|
// Remove an unwanted line that pollutes the remittance information
|
|
20
21
|
.filter(line => line.startsWith('Réf : ') === false);
|
|
21
22
|
const infoArray = editedTrans.remittanceInformationUnstructuredArray;
|
|
22
23
|
const firstLine = infoArray[0];
|
|
23
|
-
|
|
24
|
+
let match;
|
|
25
|
+
/*
|
|
26
|
+
* Some transactions always have their identifier in the first line (e.g. card),
|
|
27
|
+
* while others have it **randomly** in any of the lines (e.g. transfers).
|
|
28
|
+
*/
|
|
29
|
+
// Check the first line for specific patterns
|
|
30
|
+
if ((match = firstLine.match(regexCard))) {
|
|
24
31
|
// Card transaction
|
|
25
|
-
const payeeName =
|
|
32
|
+
const payeeName = match.groups.payeeName;
|
|
26
33
|
editedTrans.payeeName = title(payeeName);
|
|
34
|
+
editedTrans.notes = `Carte ${match.groups.date}`;
|
|
35
|
+
if (infoArray.length > 1) {
|
|
36
|
+
editedTrans.notes += ' ' + infoArray.slice(1).join(' ');
|
|
37
|
+
}
|
|
27
38
|
}
|
|
28
|
-
else if (firstLine.match(
|
|
29
|
-
// Instant transfer
|
|
30
|
-
editedTrans.payeeName = title(firstLine.replace(regexInstantTransfer, ''));
|
|
31
|
-
}
|
|
32
|
-
else if (firstLine.match(regexSepa)) {
|
|
33
|
-
// SEPA transfer
|
|
34
|
-
editedTrans.payeeName = title(firstLine.replace(regexSepa, ''));
|
|
35
|
-
}
|
|
36
|
-
else if (firstLine.match(regexTransfer) && infoArray.length > 1) {
|
|
37
|
-
// Other transfer
|
|
38
|
-
// Must be evaluated after the other transfers as they're more specific (here VIR only)
|
|
39
|
-
editedTrans.payeeName = title(infoArray[1]);
|
|
40
|
-
editedTrans.notes = firstLine.replace(regexTransfer, '');
|
|
41
|
-
}
|
|
42
|
-
else if (firstLine.match(regexLoan)) {
|
|
39
|
+
else if ((match = firstLine.match(regexLoan))) {
|
|
43
40
|
// Loan
|
|
44
41
|
editedTrans.payeeName = 'Prêt bancaire';
|
|
45
42
|
editedTrans.notes = firstLine;
|
|
46
43
|
}
|
|
47
|
-
else if (firstLine.match(regexAtmWithdrawal)) {
|
|
44
|
+
else if ((match = firstLine.match(regexAtmWithdrawal))) {
|
|
48
45
|
// ATM withdrawal
|
|
49
46
|
editedTrans.payeeName = 'Retrait DAB';
|
|
50
|
-
editedTrans.notes =
|
|
51
|
-
firstLine.match(regexAtmWithdrawal).groups.locationName;
|
|
47
|
+
editedTrans.notes = `Retrait ${match.groups.date} ${match.groups.locationName}`;
|
|
52
48
|
if (infoArray.length > 1) {
|
|
53
|
-
editedTrans.notes += ' ' + infoArray
|
|
49
|
+
editedTrans.notes += ' ' + infoArray.slice(1).join(' ');
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
|
-
else {
|
|
57
|
-
|
|
52
|
+
else if ((match = firstLine.match(regexCreditNote))) {
|
|
53
|
+
// Credit note (refund)
|
|
54
|
+
editedTrans.payeeName = title(match.groups.payeeName);
|
|
55
|
+
editedTrans.notes = `Avoir ${match.groups.date}`;
|
|
58
56
|
}
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
if (infoArray.
|
|
62
|
-
//
|
|
63
|
-
editedTrans.
|
|
57
|
+
else {
|
|
58
|
+
// For the next patterns, we need to check all lines as the identifier can be anywhere
|
|
59
|
+
if ((match = infoArray.find(line => regexInstantTransfer.test(line)))) {
|
|
60
|
+
// Instant transfer
|
|
61
|
+
editedTrans.payeeName = title(match.replace(regexInstantTransfer, ''));
|
|
62
|
+
editedTrans.notes = infoArray.filter(l => l !== match).join(' ');
|
|
63
|
+
}
|
|
64
|
+
else if ((match = infoArray.find(line => regexSepa.test(line)))) {
|
|
65
|
+
// SEPA transfer
|
|
66
|
+
editedTrans.payeeName = title(match.replace(regexSepa, ''));
|
|
67
|
+
editedTrans.notes = infoArray.filter(l => l !== match).join(' ');
|
|
68
|
+
}
|
|
69
|
+
else if ((match = infoArray.find(line => regexTransfer.test(line)))) {
|
|
70
|
+
// Other transfer
|
|
71
|
+
// Must be evaluated after the other transfers as they're more specific
|
|
72
|
+
// (here VIR only)
|
|
73
|
+
const infoArrayWithoutLine = infoArray.filter(l => l !== match);
|
|
74
|
+
editedTrans.payeeName = title(infoArrayWithoutLine.join(' '));
|
|
75
|
+
editedTrans.notes = match.replace(regexTransfer, '');
|
|
64
76
|
}
|
|
65
77
|
else {
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
editedTrans.notes = '';
|
|
78
|
+
// Unknown transaction type
|
|
79
|
+
editedTrans.payeeName = title(firstLine.replace(/ \d+$/, ''));
|
|
80
|
+
editedTrans.notes = infoArray.slice(1).join(' ');
|
|
69
81
|
}
|
|
70
82
|
}
|
|
71
83
|
return Fallback.normalizeTransaction(transaction, booked, editedTrans);
|
|
@@ -2,21 +2,26 @@ import BoursoBank from '../boursobank_bousfrppxxx.js';
|
|
|
2
2
|
describe('BoursoBank', () => {
|
|
3
3
|
describe('#normalizeTransaction', () => {
|
|
4
4
|
it.each([
|
|
5
|
-
[['CARTE 01/03/25 PAYEE NAME CB*4567'], 'Payee Name', ''],
|
|
6
|
-
[
|
|
7
|
-
|
|
5
|
+
[['CARTE 01/03/25 PAYEE NAME CB*4567'], 'Payee Name', 'Carte 01/03/25'],
|
|
6
|
+
[
|
|
7
|
+
['CARTE 01/03/25 PAYEE NAME 713621 CB*4567'],
|
|
8
|
+
'Payee Name',
|
|
9
|
+
'Carte 01/03/25',
|
|
10
|
+
],
|
|
11
|
+
[['CARTE 01/03/25 PAYEE NAME'], 'Payee Name', 'Carte 01/03/25'],
|
|
12
|
+
[['CARTE 01/03/25 PAYEE NAME 7428347'], 'Payee Name', 'Carte 01/03/25'],
|
|
8
13
|
[
|
|
9
14
|
[
|
|
10
15
|
'CARTE 03/02/25 PAYEE NAME CB*1234',
|
|
11
16
|
'2,80 NZD / 1 euro = 1,818181818',
|
|
12
17
|
],
|
|
13
18
|
'Payee Name',
|
|
14
|
-
'2,80 NZD / 1 euro = 1,818181818',
|
|
19
|
+
'Carte 03/02/25 2,80 NZD / 1 euro = 1,818181818',
|
|
15
20
|
],
|
|
16
21
|
[
|
|
17
22
|
['RETRAIT DAB 01/03/25 My location CB*9876'],
|
|
18
23
|
'Retrait DAB',
|
|
19
|
-
'My location',
|
|
24
|
+
'Retrait 01/03/25 My location',
|
|
20
25
|
],
|
|
21
26
|
[
|
|
22
27
|
[
|
|
@@ -24,13 +29,18 @@ describe('BoursoBank', () => {
|
|
|
24
29
|
'2,80 NZD / 1 euro = 1,818181818',
|
|
25
30
|
],
|
|
26
31
|
'Retrait DAB',
|
|
27
|
-
'My location 2,80 NZD / 1 euro = 1,818181818',
|
|
32
|
+
'Retrait 01/03/25 My location 2,80 NZD / 1 euro = 1,818181818',
|
|
28
33
|
],
|
|
29
34
|
[
|
|
30
35
|
['VIR Text put by the sender', 'PAYEE NAME'],
|
|
31
36
|
'Payee Name',
|
|
32
37
|
'Text put by the sender',
|
|
33
38
|
],
|
|
39
|
+
[
|
|
40
|
+
['PAYEE NAME', 'VIR Text put by the sender'],
|
|
41
|
+
'Payee Name',
|
|
42
|
+
'Text put by the sender',
|
|
43
|
+
],
|
|
34
44
|
[
|
|
35
45
|
[
|
|
36
46
|
'VIR Text put by the sender',
|
|
@@ -49,11 +59,31 @@ describe('BoursoBank', () => {
|
|
|
49
59
|
'Payee Name',
|
|
50
60
|
'Text put by the sender',
|
|
51
61
|
],
|
|
62
|
+
[
|
|
63
|
+
[
|
|
64
|
+
'Réf : SOME TEXT PUT BY THE BANK',
|
|
65
|
+
'VIR Text put by the sender',
|
|
66
|
+
'PAYEE NAME',
|
|
67
|
+
],
|
|
68
|
+
'Payee Name',
|
|
69
|
+
'Text put by the sender',
|
|
70
|
+
],
|
|
52
71
|
[
|
|
53
72
|
['VIR INST PAYEE NAME', 'Text put by the sender'],
|
|
54
73
|
'Payee Name',
|
|
55
74
|
'Text put by the sender',
|
|
56
75
|
],
|
|
76
|
+
[
|
|
77
|
+
['Text put by the sender', 'VIR INST PAYEE NAME'],
|
|
78
|
+
'Payee Name',
|
|
79
|
+
'Text put by the sender',
|
|
80
|
+
],
|
|
81
|
+
[['VIR INST PAYEE NAME'], 'Payee Name', ''],
|
|
82
|
+
[
|
|
83
|
+
['PAYEE NAME', 'VIR Text put by the sender'],
|
|
84
|
+
'Payee Name',
|
|
85
|
+
'Text put by the sender',
|
|
86
|
+
],
|
|
57
87
|
[
|
|
58
88
|
[
|
|
59
89
|
'VIR SEPA PAYEE NAME',
|
|
@@ -62,7 +92,17 @@ describe('BoursoBank', () => {
|
|
|
62
92
|
'YET ANOTHER TEXT',
|
|
63
93
|
],
|
|
64
94
|
'Payee Name',
|
|
65
|
-
'',
|
|
95
|
+
'SOME TEXT ANOTHER TEXT YET ANOTHER TEXT',
|
|
96
|
+
],
|
|
97
|
+
[
|
|
98
|
+
[
|
|
99
|
+
'SOME TEXT',
|
|
100
|
+
'ANOTHER TEXT',
|
|
101
|
+
'VIR SEPA PAYEE NAME',
|
|
102
|
+
'YET ANOTHER TEXT',
|
|
103
|
+
],
|
|
104
|
+
'Payee Name',
|
|
105
|
+
'SOME TEXT ANOTHER TEXT YET ANOTHER TEXT',
|
|
66
106
|
],
|
|
67
107
|
[
|
|
68
108
|
[
|
|
@@ -73,15 +113,28 @@ describe('BoursoBank', () => {
|
|
|
73
113
|
'PRELEVEMENT FOO BAR BAZ du',
|
|
74
114
|
],
|
|
75
115
|
'Payee Name',
|
|
76
|
-
'',
|
|
116
|
+
'HERE IS SOMETHING SOME OTHER TEXT 30/04/2025 PRELEVEMENT FOO BAR BAZ du',
|
|
117
|
+
],
|
|
118
|
+
[
|
|
119
|
+
[
|
|
120
|
+
'30/05/2025',
|
|
121
|
+
'SOME.TEXT.123.456',
|
|
122
|
+
'PRELEVEMENT FOO BAR BAZ du',
|
|
123
|
+
'PRLV SEPA Payee Name',
|
|
124
|
+
'ABC 1934821371',
|
|
125
|
+
],
|
|
126
|
+
'Payee Name',
|
|
127
|
+
'30/05/2025 SOME.TEXT.123.456 PRELEVEMENT FOO BAR BAZ du ABC 1934821371',
|
|
77
128
|
],
|
|
78
129
|
[
|
|
79
130
|
['ECH PRET:1823918329832913'],
|
|
80
131
|
'Prêt bancaire',
|
|
81
132
|
'ECH PRET:1823918329832913',
|
|
82
133
|
],
|
|
83
|
-
[['PAYEE NAME'], 'Payee Name', ''],
|
|
84
|
-
[['PAYEE
|
|
134
|
+
[['PAYEE NAME 411'], 'Payee Name', ''],
|
|
135
|
+
[['PAYEE NAME\\PARIS\\ FR'], 'Payee Name', ''],
|
|
136
|
+
[['PAYEE NAME 1\\PARIS\\ FR'], 'Payee Name', ''],
|
|
137
|
+
[['AVOIR 17/06/25 PAYEE NAME CB*1234'], 'Payee Name', 'Avoir 17/06/25'],
|
|
85
138
|
])('normalizes transaction with %s', (remittanceInformationUnstructuredArray, expectedPayeeName, expectedNotes) => {
|
|
86
139
|
const transaction = {
|
|
87
140
|
transactionId: '1234567890',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actual-app/sync-server",
|
|
3
|
-
"version": "25.7.0-nightly.
|
|
3
|
+
"version": "25.7.0-nightly.20250621",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "actual syncing server",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@actual-app/crdt": "2.1.0",
|
|
31
|
-
"@actual-app/web": "25.7.0-nightly.
|
|
31
|
+
"@actual-app/web": "25.7.0-nightly.20250621",
|
|
32
32
|
"bcrypt": "^5.1.1",
|
|
33
33
|
"better-sqlite3": "^11.10.0",
|
|
34
34
|
"convict": "^6.2.4",
|