diff --git a/apiv2/src/admin/core/referentiel/academie/AcademieMapper.ts b/apiv2/src/admin/core/referentiel/academie/AcademieMapper.ts index 208ad4c801..8e9b77446c 100644 --- a/apiv2/src/admin/core/referentiel/academie/AcademieMapper.ts +++ b/apiv2/src/admin/core/referentiel/academie/AcademieMapper.ts @@ -1,6 +1,6 @@ import { ACADEMIE_COLUMN_NAMES, ImportAcademieModel } from "./Academie.model"; -export class AcademieMapper { +export class AcademieImportMapper { static fromRecord(record: Record): ImportAcademieModel { const dateDerniereModificationSI = this.parseDate(record[ACADEMIE_COLUMN_NAMES.dateDerniereModificationSI]); const dateCreationSI = this.parseDate(record[ACADEMIE_COLUMN_NAMES.dateCreationSI]); @@ -15,7 +15,7 @@ export class AcademieMapper { } static fromRecords(records: Record[]): ImportAcademieModel[] { - return records.map(record => AcademieMapper.fromRecord(record)); + return records.map(record => AcademieImportMapper.fromRecord(record)); } private static parseDate(dateString: string): Date { diff --git a/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.spec.ts b/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.spec.ts index 6783c717bf..41cb607abd 100644 --- a/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.spec.ts +++ b/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.spec.ts @@ -9,13 +9,14 @@ import { AcademieImportService } from '../../AcademieImport.service'; import { ImporterAcademies } from './ImporterAcademies'; import { AcademieGateway } from '../../Academie.gateway'; import { ACADEMIE_COLUMN_NAMES } from '../../Academie.model'; -import { AcademieMapper } from '../../AcademieMapper'; +import { AcademieImportMapper } from '../../AcademieMapper'; describe('ImporterAcademies', () => { let useCase: ImporterAcademies; let academieImportService: AcademieImportService; let academieGateway: AcademieGateway; let fileGateway: FileGateway; + let clockGateway: ClockGateway; const mockDate = "31/07/2024"; const mockDatePlus1 = "01/08/2024"; @@ -28,7 +29,7 @@ describe('ImporterAcademies', () => { [ACADEMIE_COLUMN_NAMES.dateDerniereModificationSI]: mockDate } - const importAcademieModel = AcademieMapper.fromRecord(academieRecord); + const importAcademieModel = AcademieImportMapper.fromRecord(academieRecord); let mockAcademieDb = { ...importAcademieModel, @@ -59,9 +60,10 @@ describe('ImporterAcademies', () => { { provide: ClockGateway, useValue: { - getNowSafeIsoDate: jest.fn().mockReturnValue(mockDate) + getNowSafeIsoDate: jest.fn().mockReturnValue(mockDate), + isValidDate: jest.fn().mockReturnValue(true) } - }, + }, { provide: NotificationGateway, useValue: { @@ -90,6 +92,7 @@ describe('ImporterAcademies', () => { academieImportService = module.get(AcademieImportService); academieGateway = module.get(AcademieGateway); fileGateway = module.get(FileGateway); + clockGateway = module.get(ClockGateway); }); describe('execute', () => { @@ -229,7 +232,7 @@ describe('ImporterAcademies', () => { ...academieRecord, [ACADEMIE_COLUMN_NAMES.dateDerniereModificationSI]: "" }; - + jest.spyOn(clockGateway, 'isValidDate').mockRestore(); jest.spyOn(fileGateway, 'parseXLS').mockResolvedValue([academieRecordEmpty]); const result = await useCase.execute(mockParams); @@ -248,11 +251,12 @@ describe('ImporterAcademies', () => { expect(academieGateway.update).toHaveBeenCalledTimes(0); }); - it('Data Validation - Date creation SI - Invalid format - Invalid date format', async () => { + it('Data Validation - Date modification SI - Invalid format - Invalid date format', async () => { jest.spyOn(fileGateway, 'parseXLS').mockResolvedValue([{ ...academieRecord, [ACADEMIE_COLUMN_NAMES.dateDerniereModificationSI]: "jeudi dernier", }]); + jest.spyOn(clockGateway, 'isValidDate').mockRestore(); const result = await useCase.execute(mockParams); diff --git a/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.ts b/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.ts index 28ac2727f8..051723d652 100644 --- a/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.ts +++ b/apiv2/src/admin/core/referentiel/academie/useCase/ImporterAcademies/ImporterAcademies.ts @@ -1,18 +1,18 @@ import { Inject, Injectable, Logger } from "@nestjs/common"; import { FileGateway } from "@shared/core/File.gateway"; import { UseCase } from "@shared/core/UseCase"; -import { isValidDate } from "snu-lib"; import { ReferentielImportTaskParameters } from "@admin/core/referentiel/ReferentielImportTask.model"; import { AcademieImportRapport, ImportAcademieModel } from "../../Academie.model"; import { AcademieImportService } from "../../AcademieImport.service"; import { AcademieValidationError } from "./AcademieValidationError"; -import { AcademieMapper } from "../../AcademieMapper"; - +import { AcademieImportMapper } from "../../AcademieMapper"; +import { ClockGateway } from "@shared/core/Clock.gateway"; @Injectable() export class ImporterAcademies implements UseCase { constructor(@Inject( ) private readonly academieImportService: AcademieImportService, @Inject(FileGateway) private readonly fileGateway: FileGateway, + @Inject(ClockGateway) private readonly clockGateway: ClockGateway, private readonly logger: Logger, ) {} @@ -57,11 +57,7 @@ export class ImporterAcademies implements UseCase { throw new AcademieValidationError('Invalid format - regionAcademique'); } - if (!academie.dateCreationSI || !isValidDate(academie.dateCreationSI)) { - throw new AcademieValidationError('Invalid format - dateCreationSI'); - } - - if (!academie.dateDerniereModificationSI || !isValidDate(academie.dateDerniereModificationSI)) { + if (!academie.dateDerniereModificationSI || !this.clockGateway.isValidDate(academie.dateDerniereModificationSI)) { throw new AcademieValidationError('Invalid format - dateDerniereModificationSI'); } } @@ -72,7 +68,7 @@ export class ImporterAcademies implements UseCase { defval: "", }); - const academies = AcademieMapper.fromRecords(academiesXLSX); + const academies = AcademieImportMapper.fromRecords(academiesXLSX); return academies; } diff --git a/apiv2/src/admin/core/referentiel/departement/DepartementMapper.ts b/apiv2/src/admin/core/referentiel/departement/DepartementMapper.ts index 93a6b25a46..95b1ff910b 100644 --- a/apiv2/src/admin/core/referentiel/departement/DepartementMapper.ts +++ b/apiv2/src/admin/core/referentiel/departement/DepartementMapper.ts @@ -1,6 +1,6 @@ import { ImportDepartementModel, DEPARTEMENT_COLUMN_NAMES } from "./Departement.model"; -export class DepartementMapper { +export class DepartementImportMapper { static fromRecord(record: Record): ImportDepartementModel { const dateDerniereModificationSI = this.parseDate(record[DEPARTEMENT_COLUMN_NAMES.dateDerniereModificationSI]); const dateCreationSI = this.parseDate(record[DEPARTEMENT_COLUMN_NAMES.dateCreationSI]); @@ -17,7 +17,7 @@ export class DepartementMapper { } static fromRecords(records: Record[]): ImportDepartementModel[] { - return records.map(record => DepartementMapper.fromRecord(record)); + return records.map(record => DepartementImportMapper.fromRecord(record)); } private static parseDate(dateString: string): Date { diff --git a/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.spec.ts b/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.spec.ts index fbad85268d..f1ba2230dd 100644 --- a/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.spec.ts +++ b/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.spec.ts @@ -9,13 +9,14 @@ import { DepartementImportService } from '../../DepartementImport.service'; import { ImporterDepartements } from './ImporterDepartements'; import { DepartementGateway } from '../../Departement.gateway'; import { DEPARTEMENT_COLUMN_NAMES } from '../../Departement.model'; -import { DepartementMapper } from '../../DepartementMapper'; +import { DepartementImportMapper } from '../../DepartementMapper'; describe('ImporterDepartements', () => { let useCase: ImporterDepartements; let departementImportService: DepartementImportService; let departementGateway: DepartementGateway; let fileGateway: FileGateway; + let clockGateway: ClockGateway; const mockDate = "31/07/2024"; const mockDatePlus1 = "01/08/2024"; @@ -30,7 +31,7 @@ describe('ImporterDepartements', () => { [DEPARTEMENT_COLUMN_NAMES.dateDerniereModificationSI]: mockDate } - const importDepartementModel = DepartementMapper.fromRecord(departementRecord); + const importDepartementModel = DepartementImportMapper.fromRecord(departementRecord); let mockDepartementDb = { ...importDepartementModel, @@ -61,7 +62,8 @@ describe('ImporterDepartements', () => { { provide: ClockGateway, useValue: { - getNowSafeIsoDate: jest.fn().mockReturnValue(mockDate) + getNowSafeIsoDate: jest.fn().mockReturnValue(mockDate), + isValidDate: jest.fn().mockReturnValue(true) } }, { @@ -92,6 +94,7 @@ describe('ImporterDepartements', () => { departementImportService = module.get(DepartementImportService); departementGateway = module.get(DepartementGateway); fileGateway = module.get(FileGateway); + clockGateway = module.get(ClockGateway); }); describe('execute', () => { @@ -236,6 +239,7 @@ describe('ImporterDepartements', () => { [DEPARTEMENT_COLUMN_NAMES.dateDerniereModificationSI]: "" }; + jest.spyOn(clockGateway, 'isValidDate').mockRestore(); jest.spyOn(fileGateway, 'parseXLS').mockResolvedValue([departementRecordEmpty]); const result = await useCase.execute(mockParams); @@ -260,6 +264,7 @@ describe('ImporterDepartements', () => { ...departementRecord, [DEPARTEMENT_COLUMN_NAMES.dateDerniereModificationSI]: "jeudi dernier", }]); + jest.spyOn(clockGateway, 'isValidDate').mockRestore(); const result = await useCase.execute(mockParams); diff --git a/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.ts b/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.ts index 2de6fc4cd2..877a43bbd3 100644 --- a/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.ts +++ b/apiv2/src/admin/core/referentiel/departement/useCase/ImporterDepartements/ImporterDepartements.ts @@ -1,17 +1,18 @@ import { Inject, Injectable, Logger } from "@nestjs/common"; import { FileGateway } from "@shared/core/File.gateway"; import { UseCase } from "@shared/core/UseCase"; -import { isValidDate } from "snu-lib"; import { ReferentielImportTaskParameters } from "@admin/core/referentiel/ReferentielImportTask.model"; import { DepartementImportRapport, ImportDepartementModel } from "../../Departement.model"; import { DepartementImportService } from "../../DepartementImport.service"; import { DepartementValidationError } from "./DepartementValidationError"; -import { DepartementMapper } from "../../DepartementMapper"; +import { DepartementImportMapper } from "../../DepartementMapper"; +import { ClockGateway } from "@shared/core/Clock.gateway"; @Injectable() export class ImporterDepartements implements UseCase { constructor(@Inject( ) private readonly departementImportService: DepartementImportService, @Inject(FileGateway) private readonly fileGateway: FileGateway, + @Inject(ClockGateway) private readonly clockGateway: ClockGateway, private readonly logger: Logger, ) {} @@ -60,7 +61,7 @@ export class ImporterDepartements implements UseCase throw new DepartementValidationError('Invalid format - academie'); } - if (!departement.dateDerniereModificationSI || !isValidDate(departement.dateDerniereModificationSI)) { + if (!departement.dateDerniereModificationSI || !this.clockGateway.isValidDate(departement.dateDerniereModificationSI)) { throw new DepartementValidationError('Invalid format - dateDerniereModificationSI'); } } @@ -71,7 +72,7 @@ export class ImporterDepartements implements UseCase defval: "", }); - const departements = DepartementMapper.fromRecords(departementsXLSX); + const departements = DepartementImportMapper.fromRecords(departementsXLSX); return departements; } diff --git a/apiv2/src/admin/core/referentiel/regionAcademique/RegionAcademiqueMapper.ts b/apiv2/src/admin/core/referentiel/regionAcademique/RegionAcademiqueMapper.ts index 85df0e3cf7..625d1c8468 100644 --- a/apiv2/src/admin/core/referentiel/regionAcademique/RegionAcademiqueMapper.ts +++ b/apiv2/src/admin/core/referentiel/regionAcademique/RegionAcademiqueMapper.ts @@ -1,6 +1,6 @@ import { ImportRegionAcademiqueModel, REGION_ACADEMIQUE_COLUMN_NAMES } from "./RegionAcademique.model"; -export class RegionAcademiqueMapper { +export class RegionAcademiqueImportMapper { static fromRecord(record: Record): ImportRegionAcademiqueModel { const dateDerniereModificationSI = this.parseDate(record[REGION_ACADEMIQUE_COLUMN_NAMES.date_derniere_modification_si]); const zone = record[REGION_ACADEMIQUE_COLUMN_NAMES.zone]; @@ -14,7 +14,7 @@ export class RegionAcademiqueMapper { } static fromRecords(records: Record[]): ImportRegionAcademiqueModel[] { - return records.map(record => RegionAcademiqueMapper.fromRecord(record)); + return records.map(record => RegionAcademiqueImportMapper.fromRecord(record)); } private static parseDate(dateString: string): Date { diff --git a/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.spec.ts b/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.spec.ts index 8eb1ac00b5..d1775d9708 100644 --- a/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.spec.ts +++ b/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.spec.ts @@ -9,13 +9,14 @@ import { Logger } from '@nestjs/common'; import { ClockGateway } from '@shared/core/Clock.gateway'; import { NotificationGateway } from '@notification/core/Notification.gateway'; import { REGION_ACADEMIQUE_COLUMN_NAMES } from '../../RegionAcademique.model'; -import { RegionAcademiqueMapper } from '../../RegionAcademiqueMapper'; +import { RegionAcademiqueImportMapper } from '../../RegionAcademiqueMapper'; describe('ImporterRegionsAcademiques', () => { let useCase: ImporterRegionsAcademiques; let regionAcademiqueImportService: RegionAcademiqueImportService; let regionAcademiqueGateway: RegionAcademiqueGateway; let fileGateway: FileGateway; + let clockGateway: ClockGateway; const mockDate = "31/07/2024"; const mockDatePlus1 = "01/08/2024"; @@ -27,7 +28,7 @@ describe('ImporterRegionsAcademiques', () => { [REGION_ACADEMIQUE_COLUMN_NAMES.date_derniere_modification_si]: mockDate } - const importRegionAcademiqueModel = RegionAcademiqueMapper.fromRecord(regionAcademiqueRecord); + const importRegionAcademiqueModel = RegionAcademiqueImportMapper.fromRecord(regionAcademiqueRecord); let mockRegionAcademiqueDb = { ...importRegionAcademiqueModel, @@ -58,7 +59,8 @@ describe('ImporterRegionsAcademiques', () => { { provide: ClockGateway, useValue: { - getNowSafeIsoDate: jest.fn().mockReturnValue(mockDate) + getNowSafeIsoDate: jest.fn().mockReturnValue(mockDate), + isValidDate: jest.fn().mockReturnValue(true) } }, { @@ -90,6 +92,7 @@ describe('ImporterRegionsAcademiques', () => { regionAcademiqueGateway = module.get(RegionAcademiqueGateway); fileGateway = module.get(FileGateway); + clockGateway = module.get(ClockGateway); }); describe('execute', () => { @@ -154,7 +157,7 @@ describe('ImporterRegionsAcademiques', () => { }); }); - describe('no createion, No update', () => { + describe('no creation, No update', () => { it('Empty buffer', async () => { jest.spyOn(fileGateway, 'parseXLS').mockResolvedValue([]); @@ -266,6 +269,7 @@ describe('ImporterRegionsAcademiques', () => { }; jest.spyOn(fileGateway, 'parseXLS').mockResolvedValue([regionAcademiqueRecordEmpty]); + jest.spyOn(clockGateway, 'isValidDate').mockRestore(); const result = await useCase.execute(mockParams); @@ -287,6 +291,7 @@ describe('ImporterRegionsAcademiques', () => { ...regionAcademiqueRecord, [REGION_ACADEMIQUE_COLUMN_NAMES.date_derniere_modification_si]: "jeudi dernier", }]); + jest.spyOn(clockGateway, 'isValidDate').mockRestore(); const result = await useCase.execute(mockParams); @@ -313,7 +318,6 @@ describe('ImporterRegionsAcademiques', () => { }; jest.spyOn(fileGateway, 'parseXLS').mockResolvedValue([regionAcademiqueRecordLessThanMockDate]); - jest.spyOn(regionAcademiqueGateway, 'findByCode').mockResolvedValue(mockRegionAcademiqueDb); const result = await useCase.execute(mockParams); diff --git a/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.ts b/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.ts index 643912ecb9..89877c3a13 100644 --- a/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.ts +++ b/apiv2/src/admin/core/referentiel/regionAcademique/useCase/ImporterRegionsAcademiques/ImporterRegionsAcademiques.ts @@ -1,18 +1,18 @@ import { Inject, Injectable, Logger } from "@nestjs/common"; import { FileGateway } from "@shared/core/File.gateway"; import { UseCase } from "@shared/core/UseCase"; -import { isValidDate } from "snu-lib"; import { RegionAcademiqueImportService } from "../../RegionAcademiqueImport.service"; import { RegionAcademiqueValidationError } from "./RegionAcademiqueValidationError"; -import { RegionAcademiqueMapper } from "../../RegionAcademiqueMapper"; +import { RegionAcademiqueImportMapper } from "../../RegionAcademiqueMapper"; import { ImportRegionAcademiqueModel, RegionAcademiqueImportRapport } from "../../RegionAcademique.model"; import { ReferentielImportTaskParameters } from "@admin/core/referentiel/ReferentielImportTask.model"; - +import { ClockGateway } from "@shared/core/Clock.gateway"; @Injectable() export class ImporterRegionsAcademiques implements UseCase { constructor(@Inject( ) private readonly regionAcademiqueImportService: RegionAcademiqueImportService, @Inject(FileGateway) private readonly fileGateway: FileGateway, + @Inject(ClockGateway) private readonly clockGateway: ClockGateway, private readonly logger: Logger, ) {} @@ -58,7 +58,7 @@ export class ImporterRegionsAcademiques implements UseCase): ImportAcademieModel { - const dateDerniereModificationSI = this.parseDate(record[ACADEMIE_COLUMN_NAMES.dateDerniereModificationSI]); - const dateCreationSI = this.parseDate(record[ACADEMIE_COLUMN_NAMES.dateCreationSI]); - - return { - code: record[ACADEMIE_COLUMN_NAMES.code], - libelle: record[ACADEMIE_COLUMN_NAMES.libelle], - regionAcademique: record[ACADEMIE_COLUMN_NAMES.regionAcademique], - dateCreationSI: dateCreationSI, - dateDerniereModificationSI: dateDerniereModificationSI, - } - } - - static fromRecords(records: Record[]): ImportAcademieModel[] { - return records.map(record => AcademieMapper.fromRecord(record)); - } - - private static parseDate(dateString: string): Date { - const dateParts = dateString.split('/'); - return new Date(`${dateParts[2]}-${dateParts[1]}-${dateParts[0]}`); - } } diff --git a/apiv2/src/shared/core/Clock.gateway.ts b/apiv2/src/shared/core/Clock.gateway.ts index fe8151c045..a533470550 100644 --- a/apiv2/src/shared/core/Clock.gateway.ts +++ b/apiv2/src/shared/core/Clock.gateway.ts @@ -2,6 +2,7 @@ export interface ClockGateway { addDaysToNow(days: number): Date; now(): Date; getNowSafeIsoDate(): string; + isValidDate(date: Date): boolean; } export const ClockGateway = Symbol("ClockGateway"); diff --git a/apiv2/src/shared/infra/Clock.provider.ts b/apiv2/src/shared/infra/Clock.provider.ts index dce5083748..011d6cbe46 100644 --- a/apiv2/src/shared/infra/Clock.provider.ts +++ b/apiv2/src/shared/infra/Clock.provider.ts @@ -14,4 +14,8 @@ export class ClockProvider implements ClockGateway { now() { return new Date(); } + + isValidDate(date:Date): boolean { + return !isNaN(new Date(date).getTime()); + } } diff --git a/packages/lib/src/utils/date.ts b/packages/lib/src/utils/date.ts index 39c9ebe7d5..a2f766daf5 100644 --- a/packages/lib/src/utils/date.ts +++ b/packages/lib/src/utils/date.ts @@ -172,9 +172,6 @@ const formatDateTimeZone = (date) => { * - "31/07/2024" -> Date("2024-07-31") * - "2024-07-31" -> Date("2024-07-31") */ -const isValidDate = (date) => { - return !isNaN(date.getTime()); -} export { MONTHS, @@ -197,5 +194,4 @@ export { formatDateForPostGre, isNowBetweenDates, formatDateTimeZone, - isValidDate, };