@proconnect-gouv/proconnect.identite 1.1.0 → 1.2.0
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.
- package/CHANGELOG.md +6 -0
- package/dist/data/certification/commune-code-conversion.d.ts +13 -0
- package/dist/data/certification/commune-code-conversion.d.ts.map +1 -0
- package/dist/data/certification/commune-code-conversion.js +5188 -0
- package/dist/data/certification/country-iso-to-cog.d.ts +12 -0
- package/dist/data/certification/country-iso-to-cog.d.ts.map +1 -0
- package/dist/data/certification/country-iso-to-cog.js +438 -0
- package/dist/data/certification/index.d.ts +3 -0
- package/dist/data/certification/index.d.ts.map +1 -0
- package/dist/data/certification/index.js +3 -0
- package/dist/{mappers/certification/index.d.ts → managers/certification/adapters/api_entreprise.d.ts} +2 -2
- package/dist/managers/certification/adapters/api_entreprise.d.ts.map +1 -0
- package/dist/managers/certification/adapters/api_entreprise.js +14 -0
- package/dist/managers/certification/adapters/franceconnect.d.ts +3 -0
- package/dist/managers/certification/adapters/franceconnect.d.ts.map +1 -0
- package/dist/managers/certification/adapters/franceconnect.js +15 -0
- package/dist/managers/certification/adapters/insee.d.ts +4 -0
- package/dist/managers/certification/adapters/insee.d.ts.map +1 -0
- package/dist/managers/certification/adapters/insee.js +29 -0
- package/dist/managers/certification/adapters/rne.d.ts +4 -0
- package/dist/managers/certification/adapters/rne.d.ts.map +1 -0
- package/dist/managers/certification/adapters/rne.js +45 -0
- package/dist/managers/certification/birthplace-conversion.d.ts +27 -0
- package/dist/managers/certification/birthplace-conversion.d.ts.map +1 -0
- package/dist/managers/certification/birthplace-conversion.js +45 -0
- package/dist/managers/certification/certification-score.d.ts +22 -0
- package/dist/managers/certification/certification-score.d.ts.map +1 -0
- package/dist/managers/certification/certification-score.js +72 -0
- package/dist/managers/certification/index.d.ts +1 -1
- package/dist/managers/certification/index.d.ts.map +1 -1
- package/dist/managers/certification/index.js +1 -1
- package/dist/managers/certification/is-organization-dirigeant.d.ts +38 -8
- package/dist/managers/certification/is-organization-dirigeant.d.ts.map +1 -1
- package/dist/managers/certification/is-organization-dirigeant.js +89 -52
- package/dist/managers/certification/normalize.d.ts +21 -0
- package/dist/managers/certification/normalize.d.ts.map +1 -0
- package/dist/managers/certification/normalize.js +64 -0
- package/dist/managers/franceconnect/openid-client.d.ts +1 -0
- package/dist/managers/franceconnect/openid-client.d.ts.map +1 -1
- package/dist/managers/organization/adapters/api_entreprise.d.ts +25 -0
- package/dist/managers/organization/adapters/api_entreprise.d.ts.map +1 -0
- package/dist/{mappers/organization/from-siret.js → managers/organization/adapters/api_entreprise.js} +25 -2
- package/dist/managers/organization/get-organization-info.d.ts.map +1 -1
- package/dist/managers/organization/get-organization-info.js +3 -3
- package/dist/repositories/organization/upsert.d.ts +1 -1
- package/dist/repositories/organization/upsert.d.ts.map +1 -1
- package/dist/repositories/organization/upsert.js +26 -1
- package/dist/repositories/user/get-franceconnect-user-info.d.ts +1 -0
- package/dist/repositories/user/get-franceconnect-user-info.d.ts.map +1 -1
- package/dist/repositories/user/upsert-franceconnect-userinfo.d.ts +1 -0
- package/dist/repositories/user/upsert-franceconnect-userinfo.d.ts.map +1 -1
- package/dist/services/organization/is-syndicat-communal.d.ts.map +1 -1
- package/dist/services/organization/is-syndicat-communal.js +2 -0
- package/dist/types/dirigeant.d.ts +5 -0
- package/dist/types/dirigeant.d.ts.map +1 -1
- package/dist/types/dirigeant.js +2 -0
- package/dist/types/franceconnect.d.ts +2 -0
- package/dist/types/franceconnect.d.ts.map +1 -1
- package/dist/types/franceconnect.js +1 -0
- package/dist/types/organization.d.ts +2 -2
- package/dist/types/organization.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/data/certification/commune-code-conversion.ts +5189 -0
- package/src/data/certification/country-iso-to-cog.ts +439 -0
- package/src/data/certification/index.ts +4 -0
- package/src/managers/certification/adapters/api_entreprise.test.ts +68 -0
- package/src/managers/certification/adapters/api_entreprise.test.ts.snapshot +109 -0
- package/src/{mappers/certification/index.ts → managers/certification/adapters/api_entreprise.ts} +7 -4
- package/src/managers/certification/adapters/franceconnect.ts +21 -0
- package/src/managers/certification/adapters/insee.test.ts +18 -0
- package/src/managers/certification/adapters/insee.test.ts.snapshot +21 -0
- package/src/managers/certification/adapters/insee.ts +39 -0
- package/src/managers/certification/adapters/rne.test.ts +276 -0
- package/src/managers/certification/adapters/rne.ts +64 -0
- package/src/managers/certification/birthplace-conversion.test.ts +76 -0
- package/src/managers/certification/birthplace-conversion.ts +58 -0
- package/src/managers/certification/certification-score.test.ts +309 -0
- package/src/managers/certification/certification-score.ts +97 -0
- package/src/managers/certification/index.ts +1 -1
- package/src/managers/certification/is-organization-dirigeant.test.ts +139 -48
- package/src/managers/certification/is-organization-dirigeant.ts +132 -106
- package/src/managers/certification/normalize.test.ts +71 -0
- package/src/managers/certification/normalize.ts +72 -0
- package/src/managers/organization/adapters/api_entreprise.test.ts +31 -0
- package/src/{mappers/organization/from-siret.test.ts.snapshot → managers/organization/adapters/api_entreprise.test.ts.snapshot} +26 -3
- package/src/{mappers/organization/from-siret.ts → managers/organization/adapters/api_entreprise.ts} +53 -3
- package/src/managers/organization/get-organization-info.test.ts +1 -1
- package/src/managers/organization/get-organization-info.ts +3 -3
- package/src/repositories/organization/upsert.ts +69 -19
- package/src/repositories/user/get-franceconnect-user-info.test.ts +1 -0
- package/src/repositories/user/upsert-franceconnect-userinfo.test.ts +2 -0
- package/src/services/organization/is-syndicat-communal.ts +2 -0
- package/src/types/dirigeant.ts +3 -0
- package/src/types/franceconnect.ts +1 -0
- package/src/types/organization.ts +2 -2
- package/testing/seed/franceconnect/index.ts +12 -9
- package/testing/seed/organizations/index.ts +34 -0
- package/tsconfig.json +5 -2
- package/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/managers/certification/distance.d.ts +0 -4
- package/dist/managers/certification/distance.d.ts.map +0 -1
- package/dist/managers/certification/distance.js +0 -16
- package/dist/mappers/certification/index.d.ts.map +0 -1
- package/dist/mappers/certification/index.js +0 -11
- package/dist/mappers/index.d.ts +0 -2
- package/dist/mappers/index.d.ts.map +0 -1
- package/dist/mappers/index.js +0 -2
- package/dist/mappers/organization/from-siret.d.ts +0 -5
- package/dist/mappers/organization/from-siret.d.ts.map +0 -1
- package/dist/mappers/organization/index.d.ts +0 -2
- package/dist/mappers/organization/index.d.ts.map +0 -1
- package/dist/mappers/organization/index.js +0 -2
- package/src/managers/certification/distance.test.ts +0 -109
- package/src/managers/certification/distance.ts +0 -41
- package/src/mappers/index.ts +0 -3
- package/src/mappers/organization/from-siret.test.ts +0 -26
- package/src/mappers/organization/index.ts +0 -3
- package/testing/seed/insee/index.ts +0 -22
- package/testing/seed/mandataires/index.ts +0 -32
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
exports[`toIdentityVector > LiElJonsonEstablishment 1`] = `
|
|
2
|
+
{
|
|
3
|
+
"birthcountry": null,
|
|
4
|
+
"birthdate": "+028500-02-05T00:00:00.000Z",
|
|
5
|
+
"birthplace": "75056",
|
|
6
|
+
"family_name": "EL'JONSON",
|
|
7
|
+
"gender": "male",
|
|
8
|
+
"given_name": "LION"
|
|
9
|
+
}
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports[`toIdentityVector > RogalDornEstablishment 1`] = `
|
|
13
|
+
{
|
|
14
|
+
"birthcountry": "99102",
|
|
15
|
+
"birthdate": "+029000-01-07T00:00:00.000Z",
|
|
16
|
+
"birthplace": null,
|
|
17
|
+
"family_name": "DORN",
|
|
18
|
+
"gender": "male",
|
|
19
|
+
"given_name": "ROGAL"
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IdentityVector } from "#src/types";
|
|
2
|
+
import { formatBirthdate } from "@proconnect-gouv/proconnect.insee/formatters";
|
|
3
|
+
import type { InseSirenUniteLegale } from "@proconnect-gouv/proconnect.insee/types";
|
|
4
|
+
import { match } from "ts-pattern";
|
|
5
|
+
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
export function toIdentityVector(
|
|
9
|
+
uniteLegale: InseSirenUniteLegale,
|
|
10
|
+
): IdentityVector {
|
|
11
|
+
let birthdate: Date | null = null;
|
|
12
|
+
const nomUniteLegale = uniteLegale.periodesUniteLegale?.at(0)?.nomUniteLegale;
|
|
13
|
+
|
|
14
|
+
if (uniteLegale?.dateNaissanceUniteLegale) {
|
|
15
|
+
const parsedDate = formatBirthdate(
|
|
16
|
+
String(uniteLegale.dateNaissanceUniteLegale),
|
|
17
|
+
);
|
|
18
|
+
birthdate = isNaN(parsedDate.getTime()) ? null : parsedDate;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
birthcountry: uniteLegale?.codePaysNaissanceUniteLegale ?? null,
|
|
23
|
+
birthdate,
|
|
24
|
+
birthplace: uniteLegale?.codeCommuneNaissanceUniteLegale ?? null,
|
|
25
|
+
family_name: nomUniteLegale ?? null,
|
|
26
|
+
gender: match(uniteLegale?.sexeUniteLegale)
|
|
27
|
+
.with("M", () => "male" as const)
|
|
28
|
+
.with("F", () => "female" as const)
|
|
29
|
+
.otherwise(() => null),
|
|
30
|
+
given_name: [
|
|
31
|
+
uniteLegale?.prenom1UniteLegale,
|
|
32
|
+
uniteLegale?.prenom2UniteLegale,
|
|
33
|
+
uniteLegale?.prenom3UniteLegale,
|
|
34
|
+
uniteLegale?.prenom4UniteLegale,
|
|
35
|
+
]
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.join(" "),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
RogalDornPouvoir,
|
|
5
|
+
UlysseTosiPouvoir,
|
|
6
|
+
} from "@proconnect-gouv/proconnect.registre_national_entreprises/testing/seed";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { suite, test } from "node:test";
|
|
9
|
+
import { toIdentityVector } from "./rne.js";
|
|
10
|
+
|
|
11
|
+
suite("RNE adapter - toIdentityVector", () => {
|
|
12
|
+
test("converts valid pouvoir with all fields", () => {
|
|
13
|
+
const result = toIdentityVector(UlysseTosiPouvoir);
|
|
14
|
+
|
|
15
|
+
assert.deepEqual(result, {
|
|
16
|
+
birthcountry: "99100",
|
|
17
|
+
birthdate: new Date(Date.UTC(1992, 8, 7)), // September (month 8) 7, 1992
|
|
18
|
+
birthplace: "13055",
|
|
19
|
+
family_name: "TOSI",
|
|
20
|
+
gender: "male",
|
|
21
|
+
given_name: "Ulysse",
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("converts pouvoir with multiple prenoms", () => {
|
|
26
|
+
const pouvoir = {
|
|
27
|
+
individu: {
|
|
28
|
+
descriptionPersonne: {
|
|
29
|
+
dateDeNaissance: "1985-06-15",
|
|
30
|
+
lieuDeNaissance: "Paris",
|
|
31
|
+
nom: "DUPONT",
|
|
32
|
+
prenoms: ["Jean", "Paul", "Marie"],
|
|
33
|
+
genre: "1",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const result = toIdentityVector(pouvoir);
|
|
39
|
+
|
|
40
|
+
assert.equal(result.given_name, "Jean Paul Marie");
|
|
41
|
+
assert.equal(result.family_name, "DUPONT");
|
|
42
|
+
assert.equal(result.gender, "male");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("handles invalid date format - returns null birthdate", () => {
|
|
46
|
+
const pouvoir = {
|
|
47
|
+
individu: {
|
|
48
|
+
descriptionPersonne: {
|
|
49
|
+
dateDeNaissance: "invalid-date",
|
|
50
|
+
lieuDeNaissance: "Lyon",
|
|
51
|
+
nom: "MARTIN",
|
|
52
|
+
prenoms: ["Alice"],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const result = toIdentityVector(pouvoir);
|
|
58
|
+
|
|
59
|
+
assert.equal(result.birthdate, null);
|
|
60
|
+
assert.equal(result.family_name, "MARTIN");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("handles missing optional fields - returns null", () => {
|
|
64
|
+
const result = toIdentityVector({});
|
|
65
|
+
|
|
66
|
+
assert.deepEqual(result, {
|
|
67
|
+
birthcountry: null,
|
|
68
|
+
birthdate: null,
|
|
69
|
+
birthplace: null,
|
|
70
|
+
family_name: null,
|
|
71
|
+
gender: null,
|
|
72
|
+
given_name: null,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("handles empty prenoms array", () => {
|
|
77
|
+
const pouvoir = {
|
|
78
|
+
individu: {
|
|
79
|
+
descriptionPersonne: {
|
|
80
|
+
dateDeNaissance: "1990-01-01",
|
|
81
|
+
lieuDeNaissance: "Marseille",
|
|
82
|
+
nom: "BERNARD",
|
|
83
|
+
prenoms: [],
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const result = toIdentityVector(pouvoir);
|
|
89
|
+
|
|
90
|
+
assert.equal(result.given_name, "");
|
|
91
|
+
assert.equal(result.family_name, "BERNARD");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("handles far future date (RogalDorn from year 29000)", () => {
|
|
95
|
+
const result = toIdentityVector(RogalDornPouvoir);
|
|
96
|
+
|
|
97
|
+
// Year 29000 should be parsed correctly
|
|
98
|
+
assert.deepEqual(result, {
|
|
99
|
+
birthcountry: "99102", // ISL (Iceland) converts to 99102
|
|
100
|
+
birthdate: new Date(Date.UTC(29000, 0, 7)), // January 7, 29000
|
|
101
|
+
birthplace: null,
|
|
102
|
+
family_name: "DORN",
|
|
103
|
+
gender: "male",
|
|
104
|
+
given_name: "ROGAL",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("handles partial date components", () => {
|
|
109
|
+
const pouvoir = {
|
|
110
|
+
individu: {
|
|
111
|
+
descriptionPersonne: {
|
|
112
|
+
dateDeNaissance: "2000-12-31",
|
|
113
|
+
lieuDeNaissance: "Bordeaux",
|
|
114
|
+
nom: "LAURENT",
|
|
115
|
+
prenoms: ["Sophie"],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const result = toIdentityVector(pouvoir);
|
|
121
|
+
|
|
122
|
+
assert.deepEqual(result.birthdate, new Date(Date.UTC(2000, 11, 31))); // December 31, 2000
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("handles undefined individu fields gracefully", () => {
|
|
126
|
+
const pouvoir = {};
|
|
127
|
+
|
|
128
|
+
const result = toIdentityVector(pouvoir);
|
|
129
|
+
|
|
130
|
+
assert.deepEqual(result, {
|
|
131
|
+
birthcountry: null,
|
|
132
|
+
birthdate: null,
|
|
133
|
+
birthplace: null,
|
|
134
|
+
family_name: null,
|
|
135
|
+
gender: null,
|
|
136
|
+
given_name: null,
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("maps genre 1 to male", () => {
|
|
141
|
+
const pouvoir = {
|
|
142
|
+
individu: {
|
|
143
|
+
descriptionPersonne: {
|
|
144
|
+
dateDeNaissance: "1990-01-01",
|
|
145
|
+
lieuDeNaissance: "Paris",
|
|
146
|
+
nom: "DUPONT",
|
|
147
|
+
prenoms: ["Jean"],
|
|
148
|
+
genre: "1",
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const result = toIdentityVector(pouvoir);
|
|
154
|
+
assert.equal(result.gender, "male");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("maps genre 2 to female", () => {
|
|
158
|
+
const pouvoir = {
|
|
159
|
+
individu: {
|
|
160
|
+
descriptionPersonne: {
|
|
161
|
+
dateDeNaissance: "1990-01-01",
|
|
162
|
+
lieuDeNaissance: "Paris",
|
|
163
|
+
nom: "MARTIN",
|
|
164
|
+
prenoms: ["Marie"],
|
|
165
|
+
genre: "2",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const result = toIdentityVector(pouvoir);
|
|
171
|
+
assert.equal(result.gender, "female");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("returns null for unknown genre", () => {
|
|
175
|
+
const pouvoir = {
|
|
176
|
+
individu: {
|
|
177
|
+
descriptionPersonne: {
|
|
178
|
+
dateDeNaissance: "1990-01-01",
|
|
179
|
+
lieuDeNaissance: "Paris",
|
|
180
|
+
nom: "BERNARD",
|
|
181
|
+
prenoms: ["Alex"],
|
|
182
|
+
genre: "3",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const result = toIdentityVector(pouvoir);
|
|
188
|
+
assert.equal(result.gender, null);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test("ignores codeInseeGeographique when codePostalNaissance is missing", () => {
|
|
192
|
+
const pouvoir = {
|
|
193
|
+
individu: {
|
|
194
|
+
descriptionPersonne: {
|
|
195
|
+
dateDeNaissance: "1990-01-01",
|
|
196
|
+
lieuDeNaissance: "Lyon",
|
|
197
|
+
nom: "DUPONT",
|
|
198
|
+
prenoms: ["Jean"],
|
|
199
|
+
codeInseeGeographique: "69123",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const result = toIdentityVector(pouvoir);
|
|
205
|
+
assert.equal(result.birthplace, null);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("ignores codeInseeGeographique when format is invalid", () => {
|
|
209
|
+
const pouvoir = {
|
|
210
|
+
individu: {
|
|
211
|
+
descriptionPersonne: {
|
|
212
|
+
dateDeNaissance: "1990-01-01",
|
|
213
|
+
lieuDeNaissance: "Lyon",
|
|
214
|
+
nom: "DUPONT",
|
|
215
|
+
prenoms: ["Jean"],
|
|
216
|
+
codeInseeGeographique: "1234", // Invalid: only 4 digits
|
|
217
|
+
codePostalNaissance: "69001",
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const result = toIdentityVector(pouvoir);
|
|
223
|
+
assert.equal(result.birthplace, null);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("ignores codeInseeGeographique when it starts with 99 (foreign country)", () => {
|
|
227
|
+
const pouvoir = {
|
|
228
|
+
individu: {
|
|
229
|
+
descriptionPersonne: {
|
|
230
|
+
dateDeNaissance: "1990-01-01",
|
|
231
|
+
lieuDeNaissance: "Foreign",
|
|
232
|
+
nom: "DUPONT",
|
|
233
|
+
prenoms: ["Jean"],
|
|
234
|
+
codeInseeGeographique: "99123", // Foreign country code
|
|
235
|
+
codePostalNaissance: "69001",
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const result = toIdentityVector(pouvoir);
|
|
241
|
+
assert.equal(result.birthplace, null);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
test("converts codePaysNaissance from ISO 3166 to COG format", () => {
|
|
245
|
+
const pouvoir = {
|
|
246
|
+
individu: {
|
|
247
|
+
descriptionPersonne: {
|
|
248
|
+
dateDeNaissance: "1990-01-01",
|
|
249
|
+
lieuDeNaissance: "Dublin",
|
|
250
|
+
nom: "O'CONNOR",
|
|
251
|
+
prenoms: ["Sean"],
|
|
252
|
+
codePaysNaissance: "IRL",
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const result = toIdentityVector(pouvoir);
|
|
258
|
+
assert.equal(result.birthcountry, "99136");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("returns null for birthcountry when codePaysNaissance is invalid", () => {
|
|
262
|
+
const pouvoir = {
|
|
263
|
+
individu: {
|
|
264
|
+
descriptionPersonne: {
|
|
265
|
+
dateDeNaissance: "1990-01-01",
|
|
266
|
+
nom: "DUPONT",
|
|
267
|
+
prenoms: ["Jean"],
|
|
268
|
+
codePaysNaissance: "XXX",
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const result = toIdentityVector(pouvoir);
|
|
274
|
+
assert.equal(result.birthcountry, null);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { IdentityVector } from "#src/types";
|
|
2
|
+
import type { FindPouvoirsBySirenHandler } from "@proconnect-gouv/proconnect.registre_national_entreprises/api";
|
|
3
|
+
import { match } from "ts-pattern";
|
|
4
|
+
import {
|
|
5
|
+
convertCountryIsoToCog,
|
|
6
|
+
isValidBirthplaceFormat,
|
|
7
|
+
} from "../birthplace-conversion.js";
|
|
8
|
+
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
export function toIdentityVector(
|
|
12
|
+
pouvoir: NonNullable<Awaited<ReturnType<FindPouvoirsBySirenHandler>>[number]>,
|
|
13
|
+
): IdentityVector {
|
|
14
|
+
const descriptionPersonne = pouvoir.individu?.descriptionPersonne;
|
|
15
|
+
|
|
16
|
+
const dateMatch = String(descriptionPersonne?.dateDeNaissance).match(
|
|
17
|
+
/^(?<year>\d+)-(?<month>\d{2})-(?<day>\d{2})$/,
|
|
18
|
+
);
|
|
19
|
+
const { day, month, year } = dateMatch?.groups ?? {
|
|
20
|
+
day: NaN,
|
|
21
|
+
month: NaN,
|
|
22
|
+
year: NaN,
|
|
23
|
+
};
|
|
24
|
+
const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)));
|
|
25
|
+
const birthdate = isNaN(date.getTime()) ? null : date;
|
|
26
|
+
|
|
27
|
+
// For RNE:
|
|
28
|
+
// birthplace: Use codeInseeGeographique only if:
|
|
29
|
+
// - codePostalNaissance is present
|
|
30
|
+
// - codeInseeGeographique has valid format (5 digits or 2A/2B + 3 digits)
|
|
31
|
+
// - first 2 chars are not "99" (not a foreign country code)
|
|
32
|
+
let birthplace: string | null = null;
|
|
33
|
+
const codeInseeGeographique = descriptionPersonne?.codeInseeGeographique;
|
|
34
|
+
const codePostalNaissance = descriptionPersonne?.codePostalNaissance;
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
codePostalNaissance &&
|
|
38
|
+
codeInseeGeographique &&
|
|
39
|
+
isValidBirthplaceFormat(codeInseeGeographique) &&
|
|
40
|
+
!codeInseeGeographique.startsWith("99")
|
|
41
|
+
) {
|
|
42
|
+
birthplace = codeInseeGeographique;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// birthcountry: Convert paysNaissance from ISO 3166 to COG format
|
|
46
|
+
let birthcountry: string | null = null;
|
|
47
|
+
const codePaysNaissance = descriptionPersonne?.codePaysNaissance;
|
|
48
|
+
|
|
49
|
+
if (codePaysNaissance) {
|
|
50
|
+
birthcountry = convertCountryIsoToCog(codePaysNaissance);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
birthcountry,
|
|
55
|
+
birthdate,
|
|
56
|
+
birthplace,
|
|
57
|
+
family_name: descriptionPersonne?.nom ?? null,
|
|
58
|
+
gender: match(descriptionPersonne?.genre)
|
|
59
|
+
.with("1", () => "male" as const)
|
|
60
|
+
.with("2", () => "female" as const)
|
|
61
|
+
.otherwise(() => null),
|
|
62
|
+
given_name: descriptionPersonne?.prenoms?.join(" ") ?? null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import assert from "node:assert/strict";
|
|
4
|
+
import { describe, it } from "node:test";
|
|
5
|
+
import {
|
|
6
|
+
convertCommuneCode,
|
|
7
|
+
convertCountryIsoToCog,
|
|
8
|
+
isValidBirthplaceFormat,
|
|
9
|
+
} from "./birthplace-conversion.js";
|
|
10
|
+
|
|
11
|
+
//
|
|
12
|
+
|
|
13
|
+
describe("convertCommuneCode", () => {
|
|
14
|
+
it("converts old commune code to new code", () => {
|
|
15
|
+
assert.equal(convertCommuneCode("75050"), "92050");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("returns original code if no conversion exists", () => {
|
|
19
|
+
assert.equal(convertCommuneCode("75056"), "75056");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("handles null and undefined", () => {
|
|
23
|
+
assert.equal(convertCommuneCode(null), null);
|
|
24
|
+
assert.equal(convertCommuneCode(undefined), null);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("convertCountryIsoToCog", () => {
|
|
29
|
+
it("converts France", () => {
|
|
30
|
+
assert.equal(convertCountryIsoToCog("FRA"), "99100");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("converts Ireland", () => {
|
|
34
|
+
assert.equal(convertCountryIsoToCog("IRL"), "99136");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("converts Iceland with 2-letter code", () => {
|
|
38
|
+
assert.equal(convertCountryIsoToCog("IS"), "99102");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("handles lowercase", () => {
|
|
42
|
+
assert.equal(convertCountryIsoToCog("fra"), "99100");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("returns null for unknown country", () => {
|
|
46
|
+
assert.equal(convertCountryIsoToCog("XXX"), null);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("handles null and undefined", () => {
|
|
50
|
+
assert.equal(convertCountryIsoToCog(null), null);
|
|
51
|
+
assert.equal(convertCountryIsoToCog(undefined), null);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("isValidBirthplaceFormat", () => {
|
|
56
|
+
it("validates 5-digit codes", () => {
|
|
57
|
+
assert.equal(isValidBirthplaceFormat("75001"), true);
|
|
58
|
+
assert.equal(isValidBirthplaceFormat("92050"), true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("validates Corsican codes (2A/2B)", () => {
|
|
62
|
+
assert.equal(isValidBirthplaceFormat("2A001"), true);
|
|
63
|
+
assert.equal(isValidBirthplaceFormat("2B042"), true);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("rejects invalid formats", () => {
|
|
67
|
+
assert.equal(isValidBirthplaceFormat("1234"), false);
|
|
68
|
+
assert.equal(isValidBirthplaceFormat("123456"), false);
|
|
69
|
+
assert.equal(isValidBirthplaceFormat("ABC12"), false);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("handles null and undefined", () => {
|
|
73
|
+
assert.equal(isValidBirthplaceFormat(null), false);
|
|
74
|
+
assert.equal(isValidBirthplaceFormat(undefined), false);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
COMMUNE_CODE_CONVERSION,
|
|
5
|
+
COUNTRY_ISO_TO_COG,
|
|
6
|
+
} from "#src/data/certification";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Converts a commune code to a canonical representation,
|
|
10
|
+
* ensuring consistency across historical and current versions.
|
|
11
|
+
* If the code is not in the conversion table, returns the original code.
|
|
12
|
+
*
|
|
13
|
+
* @param communeCode - The commune code to convert (format: XXXXX or 2AXXX or 2BXXX)
|
|
14
|
+
* @returns The converted code, or the original if no conversion is needed
|
|
15
|
+
*/
|
|
16
|
+
export function convertCommuneCode(
|
|
17
|
+
communeCode: string | null | undefined,
|
|
18
|
+
): string | null {
|
|
19
|
+
if (!communeCode) return null;
|
|
20
|
+
|
|
21
|
+
// Check if the code needs conversion
|
|
22
|
+
const converted = COMMUNE_CODE_CONVERSION[communeCode];
|
|
23
|
+
return converted || communeCode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Converts an ISO 3166 country code (2 or 3-letter) to COG format (5-digit).
|
|
28
|
+
*
|
|
29
|
+
* @param iso3166Code - The ISO 3166 country code (e.g., "IRL", "FRA")
|
|
30
|
+
* @returns The COG code (e.g., "99136"), or null if not found
|
|
31
|
+
*/
|
|
32
|
+
export function convertCountryIsoToCog(
|
|
33
|
+
iso3166Code: string | null | undefined,
|
|
34
|
+
): string | null {
|
|
35
|
+
if (!iso3166Code) return null;
|
|
36
|
+
|
|
37
|
+
const cogCode = COUNTRY_ISO_TO_COG[iso3166Code.toUpperCase()];
|
|
38
|
+
return cogCode || null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Validates if a birthplace code has the correct COG format.
|
|
43
|
+
* Valid formats:
|
|
44
|
+
* - 5 digits (e.g., "75001")
|
|
45
|
+
* - 2A or 2B + 3 digits (e.g., "2A001", "2B042" for Corsica)
|
|
46
|
+
*
|
|
47
|
+
* @param birthplaceCode - The birthplace code to validate
|
|
48
|
+
* @returns true if the format is valid, false otherwise
|
|
49
|
+
*/
|
|
50
|
+
export function isValidBirthplaceFormat(
|
|
51
|
+
birthplaceCode: string | null | undefined,
|
|
52
|
+
): boolean {
|
|
53
|
+
if (!birthplaceCode) return false;
|
|
54
|
+
|
|
55
|
+
// Match either 5 digits or 2A/2B + 3 digits
|
|
56
|
+
const validFormat = /^(\d{5}|2[AB]\d{3})$/;
|
|
57
|
+
return validFormat.test(birthplaceCode);
|
|
58
|
+
}
|