Skip to content

Commit

Permalink
3128 create collection amount vs program region (#3166)
Browse files Browse the repository at this point in the history
  • Loading branch information
gcarra authored Feb 3, 2025
1 parent 59701c5 commit beaaf90
Show file tree
Hide file tree
Showing 28 changed files with 752 additions and 28 deletions.
2 changes: 2 additions & 0 deletions packages/api/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import GeoCli from "./interfaces/cli/Geo.cli";
import DataBretagneCli from "./interfaces/cli/DataBretagne.cli";
import PaymentFlatCli from "./interfaces/cli/PaymentFlat.cli";
import SireneStockUniteLegaleCli from "./interfaces/cli/SireneStockUniteLegale.cli";
import AmountsVsProgramRegionCli from "./interfaces/cli/AmountsVsProgramRegion.cli";
async function main() {
await connectDB();
await initIndexes();
Expand Down Expand Up @@ -54,6 +55,7 @@ async function main() {
DataBretagneCli,
PaymentFlatCli,
SireneStockUniteLegaleCli,
AmountsVsProgramRegionCli,
];

const args = process.argv.slice(2);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
AMOUNTS_VS_PROGRAM_REGION_DBOS,
AMOUNTS_VS_PROGRAM_REGION_ENTITIES,
} from "../../../../modules/dataViz/amountsVsProgramRegion/__fixtures__/amountsVSProgramRegion.fixture";
import AmountsVsProgramRegionAdapter from "./amountsVsProgramRegion.adapter";
describe("AmountsVsProgramRegionAdapter", () => {
describe("toDbo", () => {
it("should return right mapping", () => {
const actual = AmountsVsProgramRegionAdapter.toDbo(AMOUNTS_VS_PROGRAM_REGION_ENTITIES[0]);
const expected = { ...AMOUNTS_VS_PROGRAM_REGION_DBOS[0], _id: expect.any(Object) };
expect(actual).toEqual(expected);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ObjectId } from "mongodb";
import { AmountsVsProgramRegionDbo } from "../../../../modules/dataViz/amountsVsProgramRegion/entitiyAndDbo/amountsVsProgramRegion.dbo";
import AmountsVsProgramRegionEntity from "../../../../modules/dataViz/amountsVsProgramRegion/entitiyAndDbo/amountsVsProgramRegion.entity";

export default class AmountsVsProgramRegionAdapter {
static toDbo(entity: AmountsVsProgramRegionEntity): AmountsVsProgramRegionDbo {
return {
_id: new ObjectId(),
...entity,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { AmountsVsProgramRegionDbo } from "../../../../modules/dataViz/amountsVsProgramRegion/entitiyAndDbo/amountsVsProgramRegion.dbo";
import AmountsVsProgramRegionEntity from "../../../../modules/dataViz/amountsVsProgramRegion/entitiyAndDbo/amountsVsProgramRegion.entity";
import MongoPort from "../../../../shared/MongoPort";
import AmountsVsProgramRegionAdapter from "./amountsVsProgramRegion.adapter";

export class AmountsVsProgramRegionPort extends MongoPort<AmountsVsProgramRegionDbo> {
collectionName = "dv--montant-programme-region";

public async createIndexes(): Promise<void> {
await this.collection.createIndex({ regionAttachementComptable: 1 });
await this.collection.createIndex({ programme: 1 });
await this.collection.createIndex({ exerciceBudgetaire: 1 });
await this.collection.createIndex(
{ regionAttachementComptable: 1, programme: 1, exerciceBudgetaire: 1 },
{ unique: true },
);
}

public async hasBeenInitialized() {
const dbo = await this.collection.findOne({});
return !!dbo;
}

public insertOne(entity: AmountsVsProgramRegionEntity) {
return this.collection.insertOne(AmountsVsProgramRegionAdapter.toDbo(entity));
}

public upsertOne(entity: AmountsVsProgramRegionEntity) {
const updateDbo = AmountsVsProgramRegionAdapter.toDbo(entity);
const { _id, ...DboWithoutId } = updateDbo;
return this.collection.updateOne(
{
regionAttachementComptable: updateDbo.regionAttachementComptable,
programme: updateDbo.programme,
exerciceBudgetaire: updateDbo.exerciceBudgetaire,
},
{ $set: DboWithoutId },
{ upsert: true },
);
}

public insertMany(entities: AmountsVsProgramRegionEntity[]) {
return this.collection.insertMany(
entities.map(entity => AmountsVsProgramRegionAdapter.toDbo(entity), { ordered: false }),
);
}

public upsertMany(entities: AmountsVsProgramRegionEntity[]) {
const bulkWriteArray = entities.map(entity => {
const updateDbo = AmountsVsProgramRegionAdapter.toDbo(entity);
const { _id, ...DboWithoutId } = updateDbo;
return {
updateOne: {
filter: {
regionAttachementComptable: updateDbo.regionAttachementComptable,
programme: updateDbo.programme,
exerciceBudgetaire: updateDbo.exerciceBudgetaire,
},
update: { $set: DboWithoutId },
upsert: true,
},
};
});

return this.collection.bulkWrite(bulkWriteArray, { ordered: false });
}

public async findAll() {
return (await this.collection.find({})).toArray();
}

public async deleteAll() {
await this.collection.deleteMany({});
}
}

const amountsVsProgrammeRegionPort = new AmountsVsProgramRegionPort();
export default amountsVsProgrammeRegionPort;
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,16 @@ describe("PaymentFlatAdapter", () => {
expect(result).toEqual({ ...PAYMENT_FLAT_DBO_WITH_NULLS, _id: expect.any(ObjectId) });
});
});

describe("dboToEntity", () => {
it("given dbo without nulls, should return a PaymentFlatEntity without nulls", () => {
const result = PaymentsFlatAdapter.dboToEntity(PAYMENT_FLAT_DBO);
expect(result).toEqual(PAYMENT_FLAT_ENTITY);
});
it("given dbo with nulls, should return a PaymentFlatEntity with nulls", () => {
const result = PaymentsFlatAdapter.dboToEntity(PAYMENT_FLAT_DBO_WITH_NULLS);
expect(result).toEqual(PAYMENT_FLAT_ENTITY_WITH_NULLS);
});
});

});
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ObjectId } from "mongodb";
import PaymentFlatEntity from "../../../entities/PaymentFlatEntity";
import PaymentFlatDbo from "./PaymentFlatDbo";
import Siret from "../../../valueObjects/Siret";
import Siren from "../../../valueObjects/Siren";

export default class PaymentsFlatAdapter {
static toDbo(entity: PaymentFlatEntity): PaymentFlatDbo {
Expand Down Expand Up @@ -32,4 +34,34 @@ export default class PaymentsFlatAdapter {
regionAttachementComptable: entity.regionAttachementComptable,
};
}

static dboToEntity(dbo: PaymentFlatDbo): PaymentFlatEntity {
/* question: je suis obligé pour comment je crée l'entité de recalculer regionAttachement,
idVersement and so on. C'est une bonne chose ?
*/
return new PaymentFlatEntity(
dbo.exerciceBudgetaire,
dbo.typeIdEtablissementBeneficiaire,
// to adapt when we will have typeId != siret
new Siret(dbo.idEtablissementBeneficiaire),
dbo.typeIdEntrepriseBeneficiaire,
new Siren(dbo.idEntrepriseBeneficiaire),
dbo.montant,
dbo.dateOperation,
dbo.codeCentreFinancier,
dbo.libelleCentreFinancier,
dbo.attachementComptable,
dbo.ej,
dbo.provider,
dbo.programme,
dbo.numeroProgramme,
dbo.mission,
dbo.ministere,
dbo.sigleMinistere,
dbo.codeAction,
dbo.action,
dbo.codeActivite,
dbo.activite,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export default interface PaymentFlatDbo {
action: string | null;
codeActivite: string | null;
activite: string | null;
codeCentreFinancier: string | null;
libelleCentreFinancier: string | null;
attachementComptable: string | null;
regionAttachementComptable: string | null;
codeCentreFinancier: string | "N/A";
libelleCentreFinancier: string | "N/A" | null;
attachementComptable: string | "N/A";
regionAttachementComptable: string | "N/A" | "code region inconnu";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PAYMENT_FLAT_ENTITY } from "./__fixtures__/paymentFlatEntity.fixture";
import { PAYMENT_FLAT_DBO } from "./__fixtures__/paymentFlatDbo.fixture";
import paymentFlatPort from "./paymentFlat.port";
import { ObjectId } from "mongodb";
import PaymentsFlatAdapter from "./PaymentFlat.adapter";
const mockDeleteMany = jest.fn();
const mockInsertOne = jest.fn();
const mockUpdateOne = jest.fn();
Expand Down Expand Up @@ -40,4 +41,28 @@ describe("PaymentFlat Port", () => {
expect(mockDeleteMany).toHaveBeenCalledWith({});
});
});

describe("cursorFindChorusOnly()", () => {
let mockCursorFind: jest.SpyInstance;
let mockDboToEntity: jest.SpyInstance;
beforeAll(() => {
mockCursorFind = jest.spyOn(paymentFlatPort, "cursorFind").mockImplementation(jest.fn());
mockDboToEntity = jest.spyOn(PaymentsFlatAdapter, "dboToEntity").mockImplementation(jest.fn());
});

afterAll(() => {
jest.restoreAllMocks();
});

it("should call cursorFind with provider filter", () => {
paymentFlatPort.cursorFindChorusOnly();
expect(mockCursorFind).toHaveBeenCalledWith({ provider: "chorus" });
});

it("should call cursorFind with provider and exerciceBudgetaire filter", () => {
const exerciceBudgetaire = 2021;
paymentFlatPort.cursorFindChorusOnly(exerciceBudgetaire);
expect(mockCursorFind).toHaveBeenCalledWith({ provider: "chorus", exerciceBudgetaire: exerciceBudgetaire });
});
});
});
11 changes: 11 additions & 0 deletions packages/api/src/dataProviders/db/paymentFlat/paymentFlat.port.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import MongoPort from "../../../shared/MongoPort";
import PaymentFlatEntity from "../../../entities/PaymentFlatEntity";
import { DefaultObject } from "../../../@types";
import PaymentFlatDbo from "./PaymentFlatDbo";
import PaymentFlatAdapter from "./PaymentFlat.adapter";

Expand Down Expand Up @@ -40,6 +41,16 @@ export class PaymentFlatPort extends MongoPort<PaymentFlatDbo> {
return (await this.collection.find({})).toArray();
}

public cursorFind(query: DefaultObject<unknown> = {}, projection: DefaultObject<unknown> = {}) {
return this.collection.find(query, projection).map(PaymentFlatAdapter.dboToEntity);
}

public cursorFindChorusOnly(exerciceBudgetaire?: number) {
if (!exerciceBudgetaire) {
return this.cursorFind({ provider: "chorus" });
} else return this.cursorFind({ provider: "chorus", exerciceBudgetaire: exerciceBudgetaire });
}

public async deleteAll() {
await this.collection.deleteMany({});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import chorusLinePort from "./chorus.line.port";
import MongoPort from "../../../../shared/MongoPort";
import ChorusLineEntity from "../../../../modules/providers/chorus/entities/ChorusLineEntity";
import { ObjectId } from "mongodb";
import { update } from "lodash";

describe("chorusLinePort", () => {
let mockBulkWrite = jest.fn();

Expand Down
15 changes: 7 additions & 8 deletions packages/api/src/entities/PaymentFlatEntity.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { cp } from "fs";
import PaymentFlatEntity from "./PaymentFlatEntity";
import * as Sentry from "@sentry/node";

Expand All @@ -20,10 +19,10 @@ describe("PaymentFlatEntity", () => {
expect(actual).toEqual(expected);
});

it("should return null for an invalid region code", () => {
it("should return region name not found for an invalid region code", () => {
const actual = PaymentFlatEntity.getRegionAttachementComptable("INVALID");

expect(actual).toBeNull();
const expected = "code region inconnu";
expect(actual).toBe(expected);
});

it("should call Sentry.captureException for an invalid region code", () => {
Expand All @@ -32,10 +31,10 @@ describe("PaymentFlatEntity", () => {
expect(Sentry.captureException).toHaveBeenCalled();
});

it("should return null for a null region code", () => {
const actual = PaymentFlatEntity.getRegionAttachementComptable(null);

expect(actual).toBeNull();
it("should return N/A for a N/A region code", () => {
const actual = PaymentFlatEntity.getRegionAttachementComptable("N/A");
const expected = "N/A";
expect(actual).toBe(expected);
});
});
});
12 changes: 6 additions & 6 deletions packages/api/src/entities/PaymentFlatEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ export default class PaymentFlatEntity {
PAYL: "Pays de la Loire",
};

public static getRegionAttachementComptable(attachementComptable: string | null): string | null {
if (!attachementComptable) return null;
public static getRegionAttachementComptable(attachementComptable: string | "N/A"): string | "N/A" {
if (attachementComptable == "N/A") return "N/A";

const region = PaymentFlatEntity.regionMapping[attachementComptable];
if (region === undefined) {
const errorMessage = `Unknown region code: ${attachementComptable}`;
Sentry.captureException(new Error(errorMessage));
console.error(errorMessage);
return null;
return "code region inconnu";
}
return region;
}
Expand Down Expand Up @@ -136,11 +136,11 @@ export default class PaymentFlatEntity {
},
provider: {
path: [],
adapter: () => "Chorus",
adapter: () => "chorus",
},
};

public regionAttachementComptable: string | null;
public regionAttachementComptable: string | "N/A" | "code region inconnu";
public idVersement: string;
public uniqueId: string;

Expand All @@ -153,7 +153,7 @@ export default class PaymentFlatEntity {
public amount: number,
public operationDate: Date,
public centreFinancierCode: string | "N/A",
public centreFinancierLibelle: string | null,
public centreFinancierLibelle: string | "N/A" | null,
public attachementComptable: string | "N/A",
public ej: string,
public provider: string,
Expand Down
23 changes: 23 additions & 0 deletions packages/api/src/interfaces/cli/AmountsVsProgramRegion.cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { CliStaticInterface } from "../../@types";
import { StaticImplements } from "../../decorators/staticImplements.decorator";
import amountsVsProgramRegionService from "../../modules/dataViz/amountsVsProgramRegion/amountsVsProgramRegion.service";
import CliController from "../../shared/CliController";

@StaticImplements<CliStaticInterface>()
export default class AmountsVsProgramRegionCli extends CliController {
static cmdName = "amounts-vs-program-region";

// should only be used once, then sync with resyncExercise
async init() {
if (await amountsVsProgramRegionService.isCollectionInitialized())
throw new Error("DB already initialized, used resyncExercice instead");

this.logger.logIC("Create all amounts vs program region collection");
return amountsVsProgramRegionService.init();
}

resyncExercice(exerciceBudgetaire: number) {
this.logger.logIC(`Resync amounts vs program region collection for exercice ${exerciceBudgetaire}`);
return amountsVsProgramRegionService.updateCollection(exerciceBudgetaire);
}
}
Loading

0 comments on commit beaaf90

Please sign in to comment.