diff --git a/docker-compose.local.yml b/docker-compose.local.yml index afdf30697b..c19d127c68 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -6,7 +6,7 @@ volumes: services: postgres: - image: postgis/postgis:14-3.4 + image: postgres:14.9-alpine3.18 container_name: domifa-postgres volumes: - postgres-data:/var/lib/postgresql/data diff --git a/packages/backend/package.json b/packages/backend/package.json index 42b6e0c652..0bb788ec19 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -60,6 +60,7 @@ "@sentry/opentelemetry-node": "^7.72.0", "@socialgouv/streaming-file-encryption": "^1.1.0", "@types/source-map-support": "^0.5.4", + "@wmfs/xml2csv": "^1.32.0", "axios": "^1.4.0", "bcryptjs": "^2.4.3", "class-transformer": "0.5.1", @@ -103,6 +104,7 @@ "typeorm": "^0.3.17", "uuid": "^9.0.1", "xlsx": "^0.18.5", + "xml2csv": "^1.0.1", "yup": "^0.32.9", "yup-phone": "^1.3.2" }, diff --git a/packages/backend/src/_common/tmp-toulouse/MOTIF.const.ts b/packages/backend/src/_common/tmp-toulouse/MOTIF.const.ts new file mode 100644 index 0000000000..99690f48b4 --- /dev/null +++ b/packages/backend/src/_common/tmp-toulouse/MOTIF.const.ts @@ -0,0 +1,12 @@ +export const MOTIF = { + 1: "AME", + 2: "Demandeur d'asile", + 3: "DEMANDE DE PIECE D'IIDENTITE OFFICIELLE", + 4: "OUVERTURE DE DROITS", + 5: "DEMARCHES ADMINISTRATIVES", + 6: "ADRESSE POUR EMPLOYEUR", + 7: "RENOUVELLEMENT DES DROITS", + 8: "LOGEMENT", + 9: "ACCES AUX DROITS", + 10: "S.D.F.", +}; diff --git a/packages/backend/src/_common/tmp-toulouse/PAYS.ts b/packages/backend/src/_common/tmp-toulouse/PAYS.ts new file mode 100644 index 0000000000..9ff0ff00d9 --- /dev/null +++ b/packages/backend/src/_common/tmp-toulouse/PAYS.ts @@ -0,0 +1,215 @@ +export const PAYS = { + 2: "Algérie", + 3: "Togo", + 5: "Arménie", + 6: "Espagne", + 7: "Pologne", + 8: "Bulgarie", + 9: "Mozambique", + 10: "Cote d'Ivoire", + 11: "Irak", + 12: "Maroc", + 13: "Syrie", + 14: "Roumanie", + 15: "Lituanie", + 17: "Tunisie", + 18: "Tchad", + 19: "Russie", + 21: "Sierra Leone", + 22: "Ukraine", + 23: "Rwanda", + 24: "Angola", + 25: "Italie", + 28: "Tchétchénie", + 29: "Madagascar", + 30: "Moldavie", + 35: "Azerbaidjan", + 38: "Slovaquie", + 39: "Portugal", + 41: "Niger", + 42: "Turquie", + 43: "Somalie", + 44: "Cameroun", + 45: "Iran", + 46: "Libye", + 47: "Allemagne", + 48: "Albanie", + 49: "Soudan", + 51: "Nigeria", + 52: "Ethiopie", + 55: "Finlande", + 62: "Suisse", + 63: "Laos", + 65: "Sénégal", + 68: "Biélorussie", + 73: "Viêtnam", + 74: "France", + 76: "Belgique", + 78: "Burkina Faso", + 81: "Colombie", + 83: "Bénin", + 85: "Mauritanie", + 88: "Estonie", + 90: "Bosnie-Herzgovine", + 92: "Mongolie", + 94: "Djibouti", + 96: "Israël", + 97: "Hongrie", + 98: "Thaïlande", + 101: "Burundi", + 104: "Jamaïque", + 105: "Angleterre", + 110: "Pakistan", + 111: "Ghana", + 113: "Brésil", + 114: "Afghanistan", + 116: "Gambie", + 117: "Lettonie", + 121: "Egypte", + 122: "Slovénie", + 137: "Argentine", + 138: "Japon", + 140: "Norvège", + 142: "Comores", + 147: "Mali", + 158: "Liban", + 160: "Cuba", + 161: "Cap-Vert", + 168: "Luxembourg", + 169: "Inde", + 170: "Canada", + 171: "Chili", + 173: "Mexique", + 174: "Cambodge", + 177: "Malaisie", + 179: "Haïti", + 180: "Palestine", + 182: "Irlande", + 186: "Chine", + 188: "Bangladesh", + 190: "Guatemala", + 191: "Suriname", + 192: "Vénézuéla", + 193: "Croatie", + 194: "République Tchèque", + 195: "Corée du Nord", + 197: "Philippines", + 198: "Monténégro", + 201: "Pays-Bas", + 202: "Autriche", + 206: "Andorre ", + 207: "Equateur", + 208: "Yémen", + 209: "République dominicaine", + 210: "Bolivie", + 211: "Erythrée", + 219: "Sri Lanka", + 220: "Ouzbékistan", + 222: "Zimbabwe", + 224: "Grèce", + 225: "Pérou", + 226: "Etats-Unis", + 227: "Géorgie", + 228: "Guinée", + 229: "Guinée Equatoriale", + 232: "", + 233: "Bélorussie", + 235: "Koweït", + 236: "Gabon", + 238: "Costa Rica", + 240: "Sahara occidental", + 241: "Serbie", + 242: "Birmanie", + 243: "Ouganda", + 244: "Indonesie", + 245: "Nouvelle-Zélande", + 248: "Emirats arabes unis", + 253: "Tanzanie ", + 254: "Danemark", + 257: "Nicaragua", + 260: "Suède", + 261: "Sao Tomé-et-Principe", + 262: "Royaume-Uni", + 265: "Paraguay", + 266: "Népal", + 267: "Arabie Soudite", + 268: "Honduras", + 269: "Kenya", + 273: "Guinée-Bissau", + 274: "Guyane Britannique", + 275: "Kosovo", + 276: "Australie", + 277: "Kazakhstan", + 278: "Jordanie", + 279: "Sainte-Lucie", + 280: "Corée du sud", + 281: "Zambie", + 282: "Île Maurice", + 283: "Abkhazie", + 284: "Afrique du Sud", + 285: "Antigua-et-Barbuda", + 286: "Bahamas", + 287: "Bahreïn", + 288: "Barbade", + 289: "Belize", + 290: "Bhoutan", + 291: "Botswana", + 292: "Brunei", + 293: "Chypre du Nord", + 294: "Chypre du Sud", + 295: "Dominique", + 296: "Fidji", + 297: "Grenade", + 298: "Îles Cook", + 299: "Îles Marshall", + 300: "Irlande du Nord", + 301: "Islande", + 302: "Kirghizistan", + 303: "Kiribati", + 304: "Lesotho", + 305: "Liechtenstein", + 306: "Malawi", + 307: "Maldives", + 308: "Malte", + 309: "Monaco", + 310: "Namibie", + 311: "Nauru", + 312: "Niue", + 313: "Oman", + 314: "Ossétie du Sud", + 315: "Palaos", + 316: "Panama", + 317: "Papouasie-Nouvelle-Guinée", + 318: "République centrafricaine", + 319: "République de Macédoine", + 320: "Congo - Brazzaville", + 321: "Congo - Kinshasa", + 322: "Saint-Christophe-et-Niévès", + 323: "Saint-Marin", + 324: "Saint-Vincent-et-les-Grenadines", + 325: "Salomon", + 326: "Salvador", + 327: "Samoa", + 328: "Seychelles", + 329: "Singapour", + 330: "Soudan du Sud", + 331: "Swaziland", + 342: "Tadjikistan", + 343: "Taïwan", + 344: "Timor oriental", + 345: "Tonga", + 346: "Trinité-et-Tobago", + 347: "Turkménistan", + 348: "Tuvalu", + 349: "Uruguay", + 350: "Vanuatu", + 351: "Vatican", + 352: "Micronésie", + 353: "Myanmar", + 354: "Qatar", + 355: "Somaliland", + 356: "Tchécoslovaquie", + 357: "Yougoslavie", + 358: "Zaïre", + 359: "Liberia", +}; diff --git a/packages/backend/src/_migrations/tmp-toulouse/TOULOUSE_STRUCTURE_ID.const.ts b/packages/backend/src/_common/tmp-toulouse/TOULOUSE_STRUCTURE_ID.const.ts similarity index 53% rename from packages/backend/src/_migrations/tmp-toulouse/TOULOUSE_STRUCTURE_ID.const.ts rename to packages/backend/src/_common/tmp-toulouse/TOULOUSE_STRUCTURE_ID.const.ts index 70cb5de53a..331593a6b7 100644 --- a/packages/backend/src/_migrations/tmp-toulouse/TOULOUSE_STRUCTURE_ID.const.ts +++ b/packages/backend/src/_common/tmp-toulouse/TOULOUSE_STRUCTURE_ID.const.ts @@ -1 +1,2 @@ export const TOULOUSE_STRUCTURE_ID = 1; +export const TOULOUSE_USER_ID = 1; diff --git a/packages/backend/src/_migrations/tmp-toulouse/TUsager.interface.ts b/packages/backend/src/_common/tmp-toulouse/TUsager.interface.ts similarity index 100% rename from packages/backend/src/_migrations/tmp-toulouse/TUsager.interface.ts rename to packages/backend/src/_common/tmp-toulouse/TUsager.interface.ts diff --git a/packages/backend/src/_common/tmp-toulouse/getDateFromXml.ts b/packages/backend/src/_common/tmp-toulouse/getDateFromXml.ts new file mode 100644 index 0000000000..de35678513 --- /dev/null +++ b/packages/backend/src/_common/tmp-toulouse/getDateFromXml.ts @@ -0,0 +1,11 @@ +import { isValid, parse, startOfDay } from "date-fns"; + +export const getDateFromXml = (dateString: string | number): Date => { + const parsedDate = startOfDay( + parse(dateString.toString(), "yyyyMMdd", new Date()) + ); + if (!isValid(parsedDate)) { + throw new Error("CANNOT ADD DATE " + dateString); + } + return parsedDate; +}; diff --git a/packages/backend/src/_common/tmp-toulouse/index.ts b/packages/backend/src/_common/tmp-toulouse/index.ts new file mode 100644 index 0000000000..b4c0868c15 --- /dev/null +++ b/packages/backend/src/_common/tmp-toulouse/index.ts @@ -0,0 +1,5 @@ +// @index('./*', f => `export * from '${f.path}'`) +export * from "./getDateFromXml"; +export * from "./PAYS"; +export * from "./TOULOUSE_STRUCTURE_ID.const"; +export * from "./TUsager.interface"; diff --git a/packages/backend/src/_migrations/1692191990700-generate-temp-tables-migration.ts b/packages/backend/src/_migrations/1692191990700-generate-temp-tables-migration.ts new file mode 100644 index 0000000000..5165f0130c --- /dev/null +++ b/packages/backend/src/_migrations/1692191990700-generate-temp-tables-migration.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AutoMigration1692191990700 implements MigrationInterface { + name = "AutoMigration1692191990700"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "TmpHistorique" ("uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), "id_domicilie" integer, "date" text, "type" character varying, CONSTRAINT "PK_523a02c717798d1433428afd730" PRIMARY KEY ("uuid"))` + ); + await queryRunner.query( + `CREATE INDEX "IDX_9e9c1ff1cb8c52d25db6bf797f" ON "TmpHistorique" ("id_domicilie") ` + ); + await queryRunner.query( + `CREATE INDEX "IDX_3acc64a514fefafef16717cb93" ON "TmpHistorique" ("type") ` + ); + await queryRunner.query( + `CREATE TABLE "TmpCourriers" ("uuid" uuid NOT NULL DEFAULT uuid_generate_v4(), "IDDomicilie" integer, "date" integer, "Date_recup" integer, "motif" integer, CONSTRAINT "PK_8520f03ab40677e4503ae9fdf0a" PRIMARY KEY ("uuid"))` + ); + await queryRunner.query( + `CREATE INDEX "IDX_9b82e742c9c3762d05a73b6a40" ON "TmpCourriers" ("IDDomicilie") ` + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "TmpHistorique"`); + } +} diff --git a/packages/backend/src/_migrations/1692191990701-open-toulouse-data-migration.ts b/packages/backend/src/_migrations/1692191990701-open-toulouse-data-migration.ts index 4b1d16c76b..268f83b955 100644 --- a/packages/backend/src/_migrations/1692191990701-open-toulouse-data-migration.ts +++ b/packages/backend/src/_migrations/1692191990701-open-toulouse-data-migration.ts @@ -11,44 +11,20 @@ export class ManualMigration1692191990701 implements MigrationInterface { const outputFile = domifaConfig().upload.basePath + "/toulouse/usagers.json"; - readFile(inputFile, "utf8", (err, xmlData) => { - if (err) { - console.error( - `Erreur lors de la lecture du fichier XML : ${err.message}` - ); - return; - } + const xmlData = await readFile(inputFile, "utf8"); - const options = { - attributeNamePrefix: "_", - attrNodeName: "attr", - textNodeName: "#text", - ignoreAttributes: false, - parseAttributeValue: true, - }; + const options = { + attributeNamePrefix: "_", + attrNodeName: "attr", + textNodeName: "#text", + ignoreAttributes: false, + parseAttributeValue: true, + }; - const parser = new XMLParser(options); - const jsonData = parser.parse(xmlData); + const parser = new XMLParser(options); + const jsonData = parser.parse(xmlData); - // Écriture du fichier JSON - writeFile( - outputFile, - JSON.stringify(jsonData, null, 2), - "utf8", - (writeErr) => { - if (writeErr) { - console.error( - `Erreur lors de l'écriture du fichier JSON : ${writeErr.message}` - ); - return; - } - console.log( - "Conversion réussie ! Fichier sauvegardé à l'emplacement :" + - outputFile - ); - } - ); - }); + await writeFile(outputFile, JSON.stringify(jsonData, null, 2), "utf8"); } // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/packages/backend/src/_migrations/1692191990702-import-toulouse-usagers-migration.ts b/packages/backend/src/_migrations/1692191990702-import-toulouse-usagers-migration.ts index 8089e871a5..be6151333b 100644 --- a/packages/backend/src/_migrations/1692191990702-import-toulouse-usagers-migration.ts +++ b/packages/backend/src/_migrations/1692191990702-import-toulouse-usagers-migration.ts @@ -1,3 +1,5 @@ +import { isNil } from "lodash"; +import { ucFirst } from "./../usagers/services/custom-docs/buildCustomDoc.service"; import { MigrationInterface } from "typeorm"; import { v4 as uuidv4 } from "uuid"; import { @@ -6,22 +8,30 @@ import { StructureLight, UsagerTypeDom, } from "../_common/model"; -import { usagerRepository, UsagerTable } from "../database"; +import { myDataSource, usagerRepository, UsagerTable } from "../database"; import { usagersCreator } from "../usagers/services"; -import { TUsager } from "./tmp-toulouse/TUsager.interface"; import { domifaConfig } from "../config"; import { readFile } from "fs-extra"; -import { differenceInCalendarDays, isValid, parse, startOfDay } from "date-fns"; +import { differenceInCalendarDays } from "date-fns"; import { resetUsagers } from "../structures/services"; - -const STRUCTURE_ID = 1; +import { + TOULOUSE_STRUCTURE_ID, + TUsager, + PAYS, + getDateFromXml, +} from "../_common/tmp-toulouse"; +import { tmpHistoriqueRepository } from "../database/services/interaction/historiqueRepository.service"; export class ManualMigration1692191990702 implements MigrationInterface { public async up(): Promise { - console.log("2️⃣ Début de l'import des domiciliés"); + if ((await tmpHistoriqueRepository.count()) === 0) { + throw new Error("Chargement des fichiers incomplets"); + } - await resetUsagers({ id: STRUCTURE_ID } as StructureLight); + await resetUsagers({ id: TOULOUSE_STRUCTURE_ID } as StructureLight); + + console.log("2️⃣ Début de l'import des domiciliés"); const filePath = domifaConfig().upload.basePath + "/toulouse/usagers.json"; const jsonData = await readFile(filePath, "utf8"); @@ -50,15 +60,15 @@ export class ManualMigration1692191990702 implements MigrationInterface { const childrens = this.extractChidrens(tmpChildrens); let i = 0; - let usagersToSave = []; - for (const usagerToulouse of usagers) { - if (i % 400 === 0) { - await usagerRepository.save(usagersToSave); - usagersToSave = []; - } + const queryRunner = myDataSource.createQueryRunner(); - if (i % 1000 === 0) { + await queryRunner.startTransaction(); + + for (const usagerToulouse of usagers) { + if (i % 2000 === 0) { + await queryRunner.commitTransaction(); + await queryRunner.startTransaction(); console.log(i + "/" + usagers.length + " dossiers importés"); } i++; @@ -68,8 +78,8 @@ export class ManualMigration1692191990702 implements MigrationInterface { usagerToulouse?.date_creation && usagerToulouse?.du && differenceInCalendarDays( - this.getDate(usagerToulouse?.date_creation), - this.getDate(usagerToulouse?.du) + getDateFromXml(usagerToulouse?.date_creation), + getDateFromXml(usagerToulouse?.du) ) > 0 ) { typeDom = "RENOUVELLEMENT"; @@ -82,45 +92,52 @@ export class ManualMigration1692191990702 implements MigrationInterface { if (statut === "RADIE") { if (usagerToulouse.au) { - dateDebut = this.getDate(usagerToulouse.au); - dateFin = this.getDate(usagerToulouse.au); - dateDecision = this.getDate(usagerToulouse.au); + dateDebut = getDateFromXml(usagerToulouse.au); + dateFin = getDateFromXml(usagerToulouse.au); + dateDecision = getDateFromXml(usagerToulouse.au); } else if (usagerToulouse.dernier_retrait) { - dateDebut = this.getDate(usagerToulouse.dernier_retrait); - dateFin = this.getDate(usagerToulouse.dernier_retrait); - dateDecision = this.getDate(usagerToulouse.dernier_retrait); + dateDebut = getDateFromXml(usagerToulouse.dernier_retrait); + dateFin = getDateFromXml(usagerToulouse.dernier_retrait); + dateDecision = getDateFromXml(usagerToulouse.dernier_retrait); } else { - dateDebut = this.getDate(usagerToulouse.date_creation); - dateFin = this.getDate(usagerToulouse.date_creation); - dateDecision = this.getDate(usagerToulouse.date_creation); + dateDebut = getDateFromXml(usagerToulouse.date_creation); + dateFin = getDateFromXml(usagerToulouse.date_creation); + dateDecision = getDateFromXml(usagerToulouse.date_creation); } } else { - dateDebut = this.getDate(usagerToulouse.du); - dateFin = this.getDate(usagerToulouse.au); - dateDecision = this.getDate(usagerToulouse.du); + dateDebut = getDateFromXml(usagerToulouse.du); + dateFin = getDateFromXml(usagerToulouse.au); + dateDecision = getDateFromXml(usagerToulouse.du); } const lastInteractionDate = usagerToulouse?.dernier_retrait - ? this.getDate(usagerToulouse?.dernier_retrait) + ? getDateFromXml(usagerToulouse?.dernier_retrait) : dateDebut; const partialUsager: Partial = { ref: usagerToulouse.IDDomicilie, - nom: usagerToulouse.Nom, - surnom: usagerToulouse?.Nom_epouse ?? null, - prenom: usagerToulouse.prénom, + nom: usagerToulouse.Nom.trim().toUpperCase(), + surnom: usagerToulouse?.Nom_epouse + ? usagerToulouse?.Nom_epouse.toString().trim().toUpperCase() + : null, + prenom: usagerToulouse.prénom + ? ucFirst(usagerToulouse.prénom).trim() + : "Prénom", sexe: usagerToulouse.genre === 2 ? "homme" : "femme", telephone: { numero: usagerToulouse?.telephone ?? "", countryCode: "FR", }, email: usagerToulouse?.email ?? null, - villeNaissance: usagerToulouse?.lieu_naiss ?? "Non renseigné", + villeNaissance: this.getBirthPlace( + usagerToulouse?.lieu_naiss, + usagerToulouse?.Pays_naissance + ), ayantsDroits: typeof childrens[usagerToulouse.IDDomicilie] !== "undefined" ? childrens[usagerToulouse.IDDomicilie] : [], - dateNaissance: this.getDate(usagerToulouse.date_naissance), + dateNaissance: getDateFromXml(usagerToulouse.date_naissance), customRef: usagerToulouse?.Num_domici.toString() ?? usagerToulouse.IDDomicilie.toString(), @@ -132,7 +149,7 @@ export class ManualMigration1692191990702 implements MigrationInterface { enAttente: false, }, historique: [], - structureId: STRUCTURE_ID, + structureId: TOULOUSE_STRUCTURE_ID, decision: { uuid: uuidv4(), dateDecision, @@ -149,11 +166,13 @@ export class ManualMigration1692191990702 implements MigrationInterface { const usager = new UsagerTable(partialUsager); usagersCreator.setUsagerDefaultAttributes(usager); - usagersToSave.push(usager); + await usagerRepository.save(usager); } - await usagerRepository.save(usagersToSave); - console.log("2️⃣ ✅Import des usagers terminés"); + await queryRunner.commitTransaction(); + await queryRunner.release(); + + console.log("2️⃣ Import des usagers terminés ✅"); } public async down(): Promise { @@ -172,7 +191,7 @@ export class ManualMigration1692191990702 implements MigrationInterface { const ayantDroit: UsagerAyantDroit = { nom: child.Nom, prenom: child.prénom, - dateNaissance: this.getDate(child.date_naissance), + dateNaissance: getDateFromXml(child.date_naissance), lien: "ENFANT", }; if (typeof usagersByRef[child.enfant_de] === "undefined") { @@ -185,11 +204,20 @@ export class ManualMigration1692191990702 implements MigrationInterface { return usagersByRef; }; - public getDate = (dateString: string): Date => { - const parsedDate = startOfDay(parse(dateString, "yyyyMMdd", new Date())); - if (!isValid(parsedDate)) { - throw new Error("CANNOT ADD DATE " + dateString); + public getBirthPlace(villeNaissance?: string, pays?: number): string { + if ( + typeof villeNaissance !== "string" || + isNil(villeNaissance) || + villeNaissance === "" + ) { + return "Non renseigné"; } - return parsedDate; - }; + villeNaissance = villeNaissance.toString().trim(); + villeNaissance = ucFirst(villeNaissance); + + if (pays) { + villeNaissance = villeNaissance + ", " + PAYS[pays]; + } + return villeNaissance; + } } diff --git a/packages/backend/src/_migrations/1692191990703-import-toulouse-entretien-migration.ts b/packages/backend/src/_migrations/1692191990703-import-toulouse-entretien-migration.ts index a185bb2090..552a3ee9b9 100644 --- a/packages/backend/src/_migrations/1692191990703-import-toulouse-entretien-migration.ts +++ b/packages/backend/src/_migrations/1692191990703-import-toulouse-entretien-migration.ts @@ -1,46 +1,47 @@ import { MigrationInterface, QueryRunner } from "typeorm"; -import { usagerEntretienRepository, usagerRepository } from "../database"; - -const STRUCTURE_ID = 1; +import { + myDataSource, + usagerEntretienRepository, + usagerRepository, +} from "../database"; +import { TOULOUSE_STRUCTURE_ID } from "../_common/tmp-toulouse"; export class ManualMigration1692191990703 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - console.log("3️⃣ Création des entretiens commencée"); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async up(_queryRunner: QueryRunner): Promise { + console.log("Suppression des entretiens ... 🏃‍♀️"); + await usagerEntretienRepository.delete({ + structureId: TOULOUSE_STRUCTURE_ID, + }); const usagers = await usagerRepository.find({ - where: { structureId: STRUCTURE_ID }, + where: { structureId: TOULOUSE_STRUCTURE_ID }, select: { uuid: true, ref: true }, }); let i = 0; - let usagersToSave = []; + console.log("Création des entretiens ... 🏃‍♀️"); - console.log(usagers.length); + const queryRunner = myDataSource.createQueryRunner(); + await queryRunner.startTransaction(); for (const usager of usagers) { - if (i % 300 === 0) { - await usagerEntretienRepository.save(usagersToSave); - usagersToSave = []; - } - - if (i % 2000 === 0) { - console.log(i + "/" + usagers.length + " entretien créés"); + i++; + if (i % 4000 === 0) { + await queryRunner.commitTransaction(); + console.log(i + "/" + usagers.length + " entretiens importés"); + await queryRunner.startTransaction(); } - usagersToSave.push({ - structureId: STRUCTURE_ID, + await usagerEntretienRepository.save({ + structureId: TOULOUSE_STRUCTURE_ID, usagerUUID: usager.uuid, usagerRef: usager.ref, }); - i++; } + await queryRunner.release(); - await usagerEntretienRepository.save(usagersToSave); - const test = await queryRunner.query( - `SELECT COUNT (*) FROM usager_entretien where "structureId" = 1` - ); - console.log(test); - console.log("3️⃣ ✅ Création des entretiens commencée"); + console.log("3️⃣ Création des entretiens terminée ✅ "); } public async down(): Promise { diff --git a/packages/backend/src/_migrations/1692214661861-open-toulouse-decisions-migration.ts b/packages/backend/src/_migrations/1692214661861-open-toulouse-decisions-migration.ts deleted file mode 100644 index 58f7a23b3a..0000000000 --- a/packages/backend/src/_migrations/1692214661861-open-toulouse-decisions-migration.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; -import * as fs from "fs-extra"; - -import { domifaConfig } from "../config"; -import { XMLParser } from "fast-xml-parser"; -import { writeFile } from "fs-extra"; -import { usagerRepository } from "../database"; - -const STRUCTURE_ID = 1; - -export class ManualMigration1692214661861 implements MigrationInterface { - public async up(): Promise { - console.log("Récupération des décisions dans le fichier XML"); - await this.splitXML( - `${domifaConfig().upload.basePath}/toulouse/Historique.XML` - ); - } - - public splitXML = async (filePath: string) => { - const xmlString = await fs.readFile(filePath, "utf-8"); - - let parser = new XMLParser({ - attributeNamePrefix: "", - textNodeName: "#text", - ignoreAttributes: false, - }); - - const jsonObj = parser.parse(xmlString); - parser = null; - const historiques = jsonObj.HF_DOCUMENT.Historique; - - const usagers = await usagerRepository.find({ - where: { structureId: STRUCTURE_ID }, - select: ["ref"], - }); - - console.log(usagers.length + " dossiers dans la base"); - - const refList = usagers.map((usager) => usager.ref); - - const decisions = historiques.filter( - (histo: any) => - histo.id_domicilié && - ["creation", "renouv", "cloture", "resiliation"].indexOf(histo.type) !== - -1 && - refList.includes(histo.id_domicilié) - ); - - console.log(decisions.length + " données à importer"); - - const outputFile2 = `${ - domifaConfig().upload.basePath - }toulouse/decisions.json`; - console.log("Ecriture du fichier decisions.json"); - - await writeFile(outputFile2, JSON.stringify(decisions)); - }; - - // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars - public async down(_queryRunner: QueryRunner): Promise { - console.log("DOWN"); - } -} diff --git a/packages/backend/src/_migrations/1692216772744-decisions-migration.ts b/packages/backend/src/_migrations/1692216772744-decisions-migration.ts index cc0f1a2200..cbbc95b170 100644 --- a/packages/backend/src/_migrations/1692216772744-decisions-migration.ts +++ b/packages/backend/src/_migrations/1692216772744-decisions-migration.ts @@ -1,20 +1,12 @@ -import { readFile } from "fs-extra"; -import { MigrationInterface, QueryRunner } from "typeorm"; -import { domifaConfig } from "../config"; +import { In, MigrationInterface, QueryRunner } from "typeorm"; + import { Usager, UsagerDecision, UsagerHistory, UsagerHistoryState, } from "../_common/model"; -import { - addYears, - endOfDay, - isValid, - parse, - startOfDay, - subDays, -} from "date-fns"; +import { addYears, endOfDay, format, startOfDay, subDays } from "date-fns"; import { v4 as uuidv4 } from "uuid"; import { UsagerHistoryTable, @@ -24,7 +16,8 @@ import { usagerRepository, } from "../database"; import { UsagerEntretien } from "@domifa/common"; -import { TOULOUSE_STRUCTURE_ID } from "./tmp-toulouse/TOULOUSE_STRUCTURE_ID.const"; +import { TOULOUSE_STRUCTURE_ID, getDateFromXml } from "../_common/tmp-toulouse"; +import { tmpHistoriqueRepository } from "../database/services/interaction/historiqueRepository.service"; export class ManualMigration1692216772744 implements MigrationInterface { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -36,23 +29,29 @@ export class ManualMigration1692216772744 implements MigrationInterface { await usagerHistoryRepository.delete({ structureId: TOULOUSE_STRUCTURE_ID, }); - const decisionJson = await readFile( - `${domifaConfig().upload.basePath}toulouse/decisions.json`, - "utf-8" - ); - const decisions = JSON.parse(decisionJson); + const decisions = await tmpHistoriqueRepository.find({ + where: { + type: In(["creation", "renouv", "cloture", "resiliation"]), + }, + order: { + id_domicilie: "ASC", + date: "ASC", + }, + }); + const usagersByRef: { [key: string]: UsagerDecision[] } = {}; + const queryRunner = myDataSource.createQueryRunner(); for (const decision of decisions) { - if (typeof usagersByRef[decision.id_domicilié] === "undefined") { - usagersByRef[decision.id_domicilié] = []; + if (typeof usagersByRef[decision.id_domicilie] === "undefined") { + usagersByRef[decision.id_domicilie] = []; } const dateFin = decision.type === "cloture" || decision.type === "resiliation" - ? this.getDate(decision.date) - : addYears(this.getDate(decision.date), 1); + ? getDateFromXml(decision.date) + : addYears(getDateFromXml(decision.date), 1); const newDecision: UsagerDecision = { uuid: uuidv4(), @@ -62,9 +61,9 @@ export class ManualMigration1692216772744 implements MigrationInterface { : "VALIDE", userId: 0, userName: "DomiFa", - dateDebut: this.getDate(decision.date), + dateDebut: getDateFromXml(decision.date), dateFin, - dateDecision: this.getDate(decision.date), + dateDecision: getDateFromXml(decision.date), typeDom: decision.type === "creation" ? "PREMIERE_DOM" : "RENOUVELLEMENT", motif: @@ -77,10 +76,22 @@ export class ManualMigration1692216772744 implements MigrationInterface { : null, }; - usagersByRef[decision.id_domicilié].push(newDecision); + usagersByRef[decision.id_domicilie].push(newDecision); } + let cpt = 0; + + await queryRunner.startTransaction(); for (const ref in usagersByRef) { + cpt++; + if (cpt % 1000 === 0) { + await queryRunner.commitTransaction(); + console.log( + `${cpt} décisions importés ${format(new Date(), "HH:mm:ss")}` + ); + await queryRunner.startTransaction(); + } + const usager = await myDataSource .getRepository(UsagerTable) .findOne({ @@ -88,7 +99,6 @@ export class ManualMigration1692216772744 implements MigrationInterface { ref: parseInt(ref, 10), structureId: 1, }, - select: [ "ref", "rdv", @@ -190,13 +200,6 @@ export class ManualMigration1692216772744 implements MigrationInterface { ]; } - console.log( - "Mise à jour de " + - usager.ref + - " - " + - usager.historique.length + - " decisions" - ); await usagerHistoryRepository.save(usagerHistory); await usagerRepository.update( { @@ -206,15 +209,9 @@ export class ManualMigration1692216772744 implements MigrationInterface { ); } } + await queryRunner.release(); } - public getDate = (dateString: string): Date => { - const parsedDate = startOfDay(parse(dateString, "yyyyMMdd", new Date())); - if (!isValid(parsedDate)) { - throw new Error("CANNOT ADD DATE " + dateString); - } - return parsedDate; - }; // eslint-disable-next-line @typescript-eslint/no-unused-vars public async down(_queryRunner: QueryRunner): Promise { console.log("down"); diff --git a/packages/backend/src/_migrations/1697410497778-open-toulouse-courrier-migration.ts b/packages/backend/src/_migrations/1697410497778-open-toulouse-courrier-migration.ts deleted file mode 100644 index ed019331f4..0000000000 --- a/packages/backend/src/_migrations/1697410497778-open-toulouse-courrier-migration.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { XMLParser } from "fast-xml-parser"; -import { MigrationInterface, QueryRunner } from "typeorm"; -import { domifaConfig } from "../config"; -import { readFile, writeFile } from "fs-extra"; -import { usagerRepository } from "../database"; -import { historiqueRepository } from "../database/services/interaction/historiqueRepository.service"; - -const STRUCTURE_ID = 1; - -export class ManualMigration1697410497778 implements MigrationInterface { - public async up(): Promise { - console.log("Récupération des courriers dans le fichier XML"); - await this.splitXML( - `${domifaConfig().upload.basePath}/toulouse/Historique.XML` - ); - } - - public splitXML = async (filePath: string) => { - console.log("splitXML"); - const xmlString = await readFile(filePath, "utf-8"); - - let parser = new XMLParser({ - attributeNamePrefix: "", - textNodeName: "#text", - ignoreAttributes: false, - }); - - const jsonObj = parser.parse(xmlString); - parser = null; - const historiques = jsonObj.HF_DOCUMENT.Historique; - - const usagers = await usagerRepository.find({ - where: { structureId: STRUCTURE_ID }, - select: ["ref"], - }); - - console.log(usagers.length + " dossiers dans la base"); - - const refList = usagers.map((usager) => usager.ref); - const interactions = historiques.filter( - (histo: any) => histo.id_domicilié && refList.includes(histo.id_domicilié) - ); - - console.log(); - let toSave = []; - - for (let i = 0; i < interactions.length; i++) { - if (i % 400 === 0) { - console.log(`${i}/${interactions.length} enregistrements`); - await historiqueRepository.save(toSave); - toSave = []; - } else { - toSave.push(interactions[i]); - } - } - - const outputFile2 = `${ - domifaConfig().upload.basePath - }toulouse/courriers.json`; - console.log("Ecriture du fichier courriers.json"); - - await writeFile(outputFile2, JSON.stringify(interactions)); - }; - - // eslint-disable-next-line @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars - public async down(_queryRunner: QueryRunner): Promise { - console.log("DOWN"); - } -} diff --git a/packages/backend/src/_migrations/1697659880952-import-passages-migration.ts b/packages/backend/src/_migrations/1697659880952-import-passages-migration.ts new file mode 100644 index 0000000000..db17bd5449 --- /dev/null +++ b/packages/backend/src/_migrations/1697659880952-import-passages-migration.ts @@ -0,0 +1,94 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { interactionRepository } from "../database/services/interaction/interactionRepository.service"; +import { In, MigrationInterface, QueryRunner } from "typeorm"; +import { InteractionsTable, myDataSource, usagerRepository } from "../database"; +import { TOULOUSE_STRUCTURE_ID, getDateFromXml } from "../_common/tmp-toulouse"; +import { tmpHistoriqueRepository } from "../database/services/interaction/historiqueRepository.service"; +import { format } from "date-fns"; + +export class ManualMigration1697659880952 implements MigrationInterface { + public async up(): Promise { + const queryRunner = myDataSource.createQueryRunner(); + + console.log(""); + console.log("Lancement de la migration d'import des passages 🏃‍♂️"); + console.log(""); + + console.log("Réinitialisation des variables de migration"); + await usagerRepository.update({}, { migrated: true }); + await usagerRepository.update( + { structureId: TOULOUSE_STRUCTURE_ID }, + { migrated: false } + ); + + console.log("Suppression des précédents passages"); + await interactionRepository.delete({ + structureId: TOULOUSE_STRUCTURE_ID, + type: "visite", + }); + + const total = await usagerRepository.countMigratedUsagers(); + console.log(total + " usagers à migrer"); + let cpt = 0; + + while ((await usagerRepository.countMigratedUsagers()) > 0) { + let usagerIdsToUpdate = []; + const usagers = await usagerRepository.find({ + where: { structureId: TOULOUSE_STRUCTURE_ID, migrated: false }, + take: 500, + select: ["ref", "uuid", "nom"], + }); + + await queryRunner.startTransaction(); + for (const usager of usagers) { + cpt++; + usagerIdsToUpdate.push(usager.uuid); + const interactions = await tmpHistoriqueRepository.find({ + where: { + type: "courrier", + id_domicilie: usager.ref, + }, + }); + + if (interactions.length > 0) { + const interactionsToSave = interactions.map( + (interaction) => + new InteractionsTable({ + usagerUUID: usager.uuid, + usagerRef: usager.ref, + dateInteraction: getDateFromXml(interaction.date), + type: "visite", + userId: 1200, + userName: "DomiFa", + structureId: TOULOUSE_STRUCTURE_ID, + event: "create", + interactionOutUUID: null, + }) + ); + + await interactionRepository.save(interactionsToSave); + } + } + + await usagerRepository.update( + { uuid: In(usagerIdsToUpdate) }, + { migrated: true } + ); + + usagerIdsToUpdate = []; + console.log( + `${cpt}/${total} dossiers sont les passages sont importés ${format( + new Date(), + "HH:mm:ss" + )}` + ); + await queryRunner.commitTransaction(); + } + + await queryRunner.release(); + } + + public async down(_queryRunner: QueryRunner): Promise { + // + } +} diff --git a/packages/backend/src/_migrations/1697704071500-import-courriers-migration.ts b/packages/backend/src/_migrations/1697704071500-import-courriers-migration.ts new file mode 100644 index 0000000000..fe671f678e --- /dev/null +++ b/packages/backend/src/_migrations/1697704071500-import-courriers-migration.ts @@ -0,0 +1,153 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { In, IsNull, MigrationInterface, QueryRunner } from "typeorm"; +import { + TOULOUSE_STRUCTURE_ID, + TOULOUSE_USER_ID, + getDateFromXml, +} from "../_common/tmp-toulouse"; +import { + interactionRepository, + myDataSource, + structureRepository, + usagerRepository, + userStructureRepository, +} from "../database"; +import { tmpCourriersRepository } from "../database/services/interaction/historiqueRepository.service"; +import { interactionsCreator } from "../interactions/services"; +import { InteractionDto } from "../interactions/dto"; +import { MOTIF } from "../_common/tmp-toulouse/MOTIF.const"; +import { format } from "date-fns"; + +export class ManualMigration1697704071500 implements MigrationInterface { + public async up(): Promise { + const queryRunner = myDataSource.createQueryRunner(); + await queryRunner.startTransaction(); + console.log(""); + console.log("Lancement de la migration d'import des courriers"); + console.log(""); + + console.log("Mise à jour des dossiers"); + await usagerRepository.update( + { structureId: TOULOUSE_STRUCTURE_ID }, + { migrated: false } + ); + + console.log("Suppression des courriers"); + await interactionRepository.delete({ + structureId: TOULOUSE_STRUCTURE_ID, + type: In(["courrierIn", "courrierOut"]), + }); + + console.log("Suppression des courriers temporaires non exploitables"); + await tmpCourriersRepository.delete({ + date: IsNull(), + }); + await queryRunner.commitTransaction(); + + const user: any = await userStructureRepository.findOneBy({ + structureId: TOULOUSE_STRUCTURE_ID, + id: TOULOUSE_USER_ID, + }); + + const structure = await structureRepository.findOneBy({ + id: TOULOUSE_STRUCTURE_ID, + }); + + let cpt = 0; + + user.structure = structure; + + console.log("Début de l'import courriers des usagers"); + + const total = await usagerRepository.countMigratedUsagers(); + + while ((await usagerRepository.countMigratedUsagers()) > 0) { + await queryRunner.startTransaction(); + + const usagers = await usagerRepository.find({ + where: { structureId: TOULOUSE_STRUCTURE_ID, migrated: false }, + take: 400, + }); + + let usagerIdsToUpdate = []; + + for (const usager of usagers) { + cpt++; + usagerIdsToUpdate.push(usager.uuid); + const interactions = await tmpCourriersRepository.find({ + where: { + IDDomicilie: usager.ref, + }, + order: { + date: "ASC", + Date_recup: "ASC", + }, + }); + + if (interactions.length > 0) { + for (const interaction of interactions) { + const newInteraction: InteractionDto = { + usagerRef: usager.ref, + userId: user.id, + userName: user.nom + " " + user.prenom, + type: "courrierIn", + nbCourrier: 1, + content: this.getMotif(interaction.motif), + dateInteraction: getDateFromXml(interaction.date), + }; + + await interactionsCreator.createInteraction({ + interaction: newInteraction, + user, + usager, + }); + + if (interaction?.Date_recup) { + const newInteraction: InteractionDto = { + usagerRef: usager.ref, + userId: user.id, + userName: user.nom + " " + user.prenom, + type: "courrierOut", + nbCourrier: 1, + content: this.getMotif(interaction.motif), + dateInteraction: getDateFromXml(interaction.Date_recup), + }; + + await interactionsCreator.createInteraction({ + interaction: newInteraction, + user, + usager, + }); + } + } + } + } + + await usagerRepository.update( + { uuid: In(usagerIdsToUpdate) }, + { migrated: true } + ); + + usagerIdsToUpdate = []; + console.log( + `${cpt}/${total} dossiers sont les courriers sont importés ${format( + new Date(), + "HH:mm:ss" + )}` + ); + await queryRunner.commitTransaction(); + } + await queryRunner.release(); + } + + public async down(_queryRunner: QueryRunner): Promise { + // + } + + public getMotif(motif?: number) { + if (!motif || motif === 0) { + return ""; + } + return MOTIF[motif] ?? ""; + } +} diff --git a/packages/backend/src/database/entities/interaction/HistoriqueTable.typeorm.ts b/packages/backend/src/database/entities/interaction/HistoriqueTable.typeorm.ts deleted file mode 100644 index 8eff215898..0000000000 --- a/packages/backend/src/database/entities/interaction/HistoriqueTable.typeorm.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"; - -export interface Historique { - IDHistorique: number; - id_domicilié: number; - texte: string; - date: Date; - type: string; - param: string; - param2: string; - utilisateur: string; - tri: number; -} - -@Entity("Historique") -export class HistoriqueTable { - @PrimaryGeneratedColumn() - IDHistorique: number; - - @Column() - id_domicilié: number; - - @Column() - texte: string; - - @Column() - date: Date; - - @Column() - type: string; - - @Column() - param: string; - - @Column() - param2: string; - - @Column() - utilisateur: string; - - @Column() - tri: number; - - public constructor(entity?: Partial) { - Object.assign(this, entity); - } -} diff --git a/packages/backend/src/database/entities/interaction/TmpCourriersTable.typeorm.ts b/packages/backend/src/database/entities/interaction/TmpCourriersTable.typeorm.ts new file mode 100644 index 0000000000..0fa22ccb37 --- /dev/null +++ b/packages/backend/src/database/entities/interaction/TmpCourriersTable.typeorm.ts @@ -0,0 +1,31 @@ +import { Entity, Column, PrimaryGeneratedColumn, Index } from "typeorm"; + +export interface TmpCourriers { + IDDomicilie: number; + motif: number; + date: number; + Date_recup: number; +} + +@Entity("TmpCourriers") +export class TmpCourriersTable { + @PrimaryGeneratedColumn("uuid") + public uuid?: string; + + @Index() + @Column({ type: "integer", nullable: true }) + IDDomicilie: number; + + @Column({ type: "integer", nullable: true }) + date: number; + + @Column({ type: "integer", nullable: true }) + Date_recup: number; + + @Column({ type: "integer", nullable: true }) + motif: number; + + public constructor(entity?: Partial) { + Object.assign(this, entity); + } +} diff --git a/packages/backend/src/database/entities/interaction/TmpHistoriqueTable.typeorm.ts b/packages/backend/src/database/entities/interaction/TmpHistoriqueTable.typeorm.ts new file mode 100644 index 0000000000..52d6869543 --- /dev/null +++ b/packages/backend/src/database/entities/interaction/TmpHistoriqueTable.typeorm.ts @@ -0,0 +1,28 @@ +import { Entity, Column, PrimaryGeneratedColumn, Index } from "typeorm"; + +export interface TmpHistorique { + id_domicilie: number; + date: string; + type: string; +} + +@Entity("TmpHistorique") +export class TmpHistoriqueTable { + @PrimaryGeneratedColumn("uuid") + public uuid?: string; + + @Index() + @Column({ type: "integer", nullable: true }) + id_domicilie: number; + + @Column({ type: "text", nullable: true }) + date: string; + + @Index() + @Column({ nullable: true }) + type: string; + + public constructor(entity?: Partial) { + Object.assign(this, entity); + } +} diff --git a/packages/backend/src/database/services/_postgres/PG_CONNECT_OPTIONS.const.ts b/packages/backend/src/database/services/_postgres/PG_CONNECT_OPTIONS.const.ts index 2ddbd63333..2c17fbdf35 100644 --- a/packages/backend/src/database/services/_postgres/PG_CONNECT_OPTIONS.const.ts +++ b/packages/backend/src/database/services/_postgres/PG_CONNECT_OPTIONS.const.ts @@ -33,7 +33,7 @@ export const PG_CONNECT_OPTIONS: PostgresConnectionOptions = { }, type: "postgres", synchronize: false, - migrationsTransactionMode: "each", + migrationsTransactionMode: "none", migrationsRun: (domifaConfig().envId !== "test" && domifaConfig().cron.enable) || domifaConfig().envId === "local", diff --git a/packages/backend/src/database/services/_postgres/pgRepository.service.ts b/packages/backend/src/database/services/_postgres/pgRepository.service.ts index 85620ad69c..8f883a7dff 100644 --- a/packages/backend/src/database/services/_postgres/pgRepository.service.ts +++ b/packages/backend/src/database/services/_postgres/pgRepository.service.ts @@ -25,7 +25,6 @@ function get | number = T>( typeorm, aggregateAsNumber, countBy, - _parseCounts, }; diff --git a/packages/backend/src/database/services/interaction/historiqueRepository.service.ts b/packages/backend/src/database/services/interaction/historiqueRepository.service.ts index 137cdf0025..7d43461125 100644 --- a/packages/backend/src/database/services/interaction/historiqueRepository.service.ts +++ b/packages/backend/src/database/services/interaction/historiqueRepository.service.ts @@ -1,8 +1,15 @@ import { - Historique, - HistoriqueTable, -} from "../../entities/interaction/HistoriqueTable.typeorm"; + TmpHistorique, + TmpHistoriqueTable, +} from "../../entities/interaction/TmpHistoriqueTable.typeorm"; +import { + TmpCourriers, + TmpCourriersTable, +} from "../../entities/interaction/TmpCourriersTable.typeorm"; import { myDataSource } from "../_postgres"; -export const historiqueRepository = - myDataSource.getRepository(HistoriqueTable); +export const tmpHistoriqueRepository = + myDataSource.getRepository(TmpHistoriqueTable); + +export const tmpCourriersRepository = + myDataSource.getRepository(TmpCourriersTable); diff --git a/packages/backend/src/interactions/services/interactionsCreator.service.ts b/packages/backend/src/interactions/services/interactionsCreator.service.ts index c7b725b890..bac6439c03 100644 --- a/packages/backend/src/interactions/services/interactionsCreator.service.ts +++ b/packages/backend/src/interactions/services/interactionsCreator.service.ts @@ -115,7 +115,7 @@ async function createInteraction({ usagerUUID: usager.uuid, userId: user.id, userName: `${user.prenom} ${user.nom}`, - dateInteraction: now, + dateInteraction: interaction.dateInteraction ?? now, interactionOutUUID: null, event: "create", }; diff --git a/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts b/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts index a00d75ce3b..04d1cd4e09 100644 --- a/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts +++ b/packages/backend/src/usagers/services/custom-docs/buildCustomDoc.service.ts @@ -280,7 +280,7 @@ export function buildCustomDoc({ } export const ucFirst = (value: string) => { - return value === undefined || value === null + return value === undefined || value === null || value === "" ? "" : value.charAt(0).toUpperCase() + value.slice(1); }; diff --git a/yarn.lock b/yarn.lock index 92f8ab9e7d..9468cd61f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2315,6 +2315,7 @@ __metadata: "@types/uuid": ^9.0.4 "@typescript-eslint/eslint-plugin": ^6.0.0 "@typescript-eslint/parser": ^6.0.0 + "@wmfs/xml2csv": ^1.32.0 axios: ^1.4.0 bcryptjs: ^2.4.3 class-transformer: 0.5.1 @@ -2374,6 +2375,7 @@ __metadata: typescript: 4.9.5 uuid: ^9.0.1 xlsx: ^0.18.5 + xml2csv: ^1.0.1 yup: ^0.32.9 yup-phone: ^1.3.2 languageName: unknown @@ -7517,6 +7519,19 @@ __metadata: languageName: node linkType: hard +"@wmfs/xml2csv@npm:^1.32.0": + version: 1.32.0 + resolution: "@wmfs/xml2csv@npm:1.32.0" + dependencies: + debug: 4.3.4 + dottie: 2.0.6 + fs-extra: 11.1.1 + lodash: 4.17.21 + sax: 1.2.4 + checksum: 4e9055f149d0b546344c9bd05fc0a2380c0a72da17561f73b1a4cf5d9cf0c55f9513f716d0a4d891963f949167650cf7edb33d8e547e3f57f84ec6593f1d06ad + languageName: node + linkType: hard + "@xmldom/xmldom@npm:^0.8.6, @xmldom/xmldom@npm:^0.8.8": version: 0.8.9 resolution: "@xmldom/xmldom@npm:0.8.9" @@ -10470,6 +10485,15 @@ __metadata: languageName: node linkType: hard +"debug@npm:3.1.0": + version: 3.1.0 + resolution: "debug@npm:3.1.0" + dependencies: + ms: 2.0.0 + checksum: 0b52718ab957254a5b3ca07fc34543bc778f358620c206a08452251eb7fc193c3ea3505072acbf4350219c14e2d71ceb7bdaa0d3370aa630b50da790458d08b3 + languageName: node + linkType: hard + "debug@npm:4, debug@npm:4.3.4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" @@ -10974,6 +10998,20 @@ __metadata: languageName: node linkType: hard +"dottie@npm:2.0.0": + version: 2.0.0 + resolution: "dottie@npm:2.0.0" + checksum: c05ad2f4b63db537f43a291ba7d84d374a304ae26841497c4da5368ead5cf42d16419c06c2a71b6b1771c8f85180d32434c8e3da09610cec6e63173903d408f0 + languageName: node + linkType: hard + +"dottie@npm:2.0.6": + version: 2.0.6 + resolution: "dottie@npm:2.0.6" + checksum: 4c778df9dc631a1108a32ef390916836814999a7411d10883f4151bd49c9c6934dc329b3f50fc7692849aa75ba87dba880fd54be501a3b39a6b9c23d6f772a09 + languageName: node + linkType: hard + "duck@npm:^0.1.12": version: 0.1.12 resolution: "duck@npm:0.1.12" @@ -12799,6 +12837,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:11.1.1, fs-extra@npm:^11.0.0, fs-extra@npm:^11.1.0, fs-extra@npm:^11.1.1": + version: 11.1.1 + resolution: "fs-extra@npm:11.1.1" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd + languageName: node + linkType: hard + "fs-extra@npm:9.1.0, fs-extra@npm:^9.1.0": version: 9.1.0 resolution: "fs-extra@npm:9.1.0" @@ -12822,17 +12871,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^11.0.0, fs-extra@npm:^11.1.0, fs-extra@npm:^11.1.1": - version: 11.1.1 - resolution: "fs-extra@npm:11.1.1" - dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: fb883c68245b2d777fbc1f2082c9efb084eaa2bbf9fddaa366130d196c03608eebef7fb490541276429ee1ca99f317e2d73e96f5ca0999eefedf5a624ae1edfd - languageName: node - linkType: hard - "fs-extra@npm:^8.1.0": version: 8.1.0 resolution: "fs-extra@npm:8.1.0" @@ -16431,6 +16469,13 @@ __metadata: languageName: node linkType: hard +"lodash@npm:4.17.5": + version: 4.17.5 + resolution: "lodash@npm:4.17.5" + checksum: 9ae12b708f68c54f2701daae072c5e3f648ed7cbe78b9308ce12209cd41053de9856d59df11464d8a3f35c3828a8d9add11051e3efc8bb75672271bb7c9da393 + languageName: node + linkType: hard + "log-symbols@npm:^4.0.0, log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" @@ -17004,6 +17049,13 @@ __metadata: languageName: node linkType: hard +"minimist@npm:0.0.8": + version: 0.0.8 + resolution: "minimist@npm:0.0.8" + checksum: 042f8b626b1fa44dffc23bac55771425ac4ee9d267b56f9064c07713e516e1799f3ba933bb628d2475a210caf7dcdb98161611baa1f0daf49309a944cb4bc48f + languageName: node + linkType: hard + "minimist@npm:^1.1.0, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" @@ -17167,6 +17219,17 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:0.5.1": + version: 0.5.1 + resolution: "mkdirp@npm:0.5.1" + dependencies: + minimist: 0.0.8 + bin: + mkdirp: bin/cmd.js + checksum: ed1ab49bb1d06c88dba7cfe930a3186f2605b5465aab7c8f24119baaba6e38f9ab4ac1695c68f476c65a48df2a69a8495049cd6e26c360ea082151a0771343d2 + languageName: node + linkType: hard + "mkdirp@npm:>=0.5 0, mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.4": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" @@ -20945,7 +21008,7 @@ __metadata: languageName: node linkType: hard -"sax@npm:^1.2.4": +"sax@npm:1.2.4, sax@npm:^1.2.4": version: 1.2.4 resolution: "sax@npm:1.2.4" checksum: d3df7d32b897a2c2f28e941f732c71ba90e27c24f62ee918bd4d9a8cfb3553f2f81e5493c7f0be94a11c1911b643a9108f231dd6f60df3fa9586b5d2e3e9e1fe @@ -24307,6 +24370,19 @@ __metadata: languageName: node linkType: hard +"xml2csv@npm:^1.0.1": + version: 1.0.1 + resolution: "xml2csv@npm:1.0.1" + dependencies: + debug: 3.1.0 + dottie: 2.0.0 + lodash: 4.17.5 + mkdirp: 0.5.1 + sax: 1.2.4 + checksum: 59e833fdce6aaba04a50d97c80cf50d071c11bbff5c42e5e22cb6e7a594eb1eed493fdc00e53a3ff76f1472d6d6373f990d702f6ded13cb50f45e525db5c751e + languageName: node + linkType: hard + "xmlbuilder@npm:^10.0.0": version: 10.1.1 resolution: "xmlbuilder@npm:10.1.1"