From 789ef6985cb83e3417a21ce14229d3e277be5128 Mon Sep 17 00:00:00 2001
From: silto
Date: Tue, 8 Oct 2024 18:26:54 +0200
Subject: [PATCH] [TRA 14644] - Ajout d'Eco-organisme sur BSVHU (#3619)
* feat(BSVHU): add support for eco organisme on BSVHU
* fix(BSVHU/BSDA/BSDD/BSDASRI): add/fix ecoorganisme sirenification
* test(BSVHU): add tests for eco-organisme, remove changes on sirenify that where getting infos from EcoOrganisme table (useless)
* fix(BSVHU): refine paths on refinements
* fix(Refinements): make not dormant refinement explicitly for emitters
* feat(Libs): add object creation script
* fix(BSVHU/BSDASRI): fix tests
* fix(BSDs): fix test, make sirenify not overwrite eco organisme name if the company doesn't exist
* fix(BSVHU): fix tests
* fix(Object-creator): change object creator to compile
* docs(Changelog): update Changelog
---
CONTRIBUTING.md | 6 ++
Changelog.md | 4 +
back/src/__tests__/factories.ts | 24 +++++-
back/src/__tests__/testWorkflow.ts | 5 +-
back/src/bsda/validation/refinements.ts | 42 +++--------
back/src/bsda/validation/sirenify.ts | 74 +++++++++++++------
.../createBsdasriEcoOrganisme.integration.ts | 12 ++-
.../__tests__/updateBsdasri.integration.ts | 12 ++-
back/src/bsdasris/sirenify.ts | 22 ++++--
back/src/bsffs/validation/bsff/refinements.ts | 4 +-
back/src/bsvhu/__tests__/bsvhuEdition.test.ts | 12 ++-
.../bsvhu/__tests__/elastic.integration.ts | 6 ++
back/src/bsvhu/__tests__/factories.vhu.ts | 16 +++-
.../bsvhu/__tests__/registry.integration.ts | 28 ++++++-
back/src/bsvhu/converter.ts | 17 ++++-
back/src/bsvhu/elastic.ts | 8 +-
back/src/bsvhu/pdf/components/BsvhuPdf.tsx | 10 +++
back/src/bsvhu/permissions.ts | 9 +++
back/src/bsvhu/registry.ts | 8 +-
.../__tests__/createBsvhu.integration.ts | 72 +++++++++++++++++-
.../__tests__/duplicateBsvhu.integration.ts | 15 +++-
.../queries/__tests__/bsvhu.integration.ts | 4 +
.../__tests__/bsvhumetadata.integration.ts | 2 +-
back/src/bsvhu/typeDefs/bsvhu.inputs.graphql | 8 ++
back/src/bsvhu/typeDefs/bsvhu.objects.graphql | 9 +++
.../__tests__/validation.integration.ts | 40 +++++++++-
back/src/bsvhu/validation/helpers.ts | 5 +-
back/src/bsvhu/validation/refinements.ts | 12 ++-
back/src/bsvhu/validation/rules.ts | 14 ++++
back/src/bsvhu/validation/schema.ts | 2 +
back/src/bsvhu/validation/sirenify.ts | 9 +++
back/src/bsvhu/validation/types.ts | 1 +
back/src/common/validation/zod/refinement.ts | 50 ++++++++++++-
back/src/common/validation/zod/schema.ts | 2 +-
back/src/companies/sirenify.ts | 42 ++++++-----
.../typeDefs/company.objects.graphql | 1 +
back/src/forms/sirenify.ts | 23 ++++--
libs/back/object-creator/.eslintrc.json | 18 +++++
libs/back/object-creator/project.json | 54 ++++++++++++++
libs/back/object-creator/src/main.ts | 54 ++++++++++++++
libs/back/object-creator/src/objects.ts | 26 +++++++
libs/back/object-creator/tsconfig.app.json | 9 +++
libs/back/object-creator/tsconfig.json | 14 ++++
.../migration.sql | 9 +++
.../migration.sql | 2 +
libs/back/prisma/src/schema.prisma | 64 ++++++++--------
46 files changed, 727 insertions(+), 153 deletions(-)
create mode 100644 libs/back/object-creator/.eslintrc.json
create mode 100644 libs/back/object-creator/project.json
create mode 100644 libs/back/object-creator/src/main.ts
create mode 100644 libs/back/object-creator/src/objects.ts
create mode 100644 libs/back/object-creator/tsconfig.app.json
create mode 100644 libs/back/object-creator/tsconfig.json
create mode 100644 libs/back/prisma/src/migrations/20240924172106_bsvhu_ecoorganisme/migration.sql
create mode 100644 libs/back/prisma/src/migrations/20240924183924_ecoorganisme_handle_bsvhu/migration.sql
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d59b3eb1b4..3fe9285591 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -740,6 +740,12 @@ Pour palier à ce problème, il est possible de nourrir la base de donnée Prism
3.2 Dans le container `td-api`: `npx prisma db push --preview-feature` pour recréer les tables
4. Dans le container `td-api`: `npx prisma db seed --preview-feature` pour nourrir la base de données.
+### Ajouter un objet spécifique dans la base de données
+
+Au cas où il serait nécessaire d'ajouter un objet à la base de données, vous pouvez utiliser le script "object-creator". Pour celà, modifiez le fichier `libs/back/object-creator/src/objects.ts` en ajoutant des objets en respectant le format démontré en exemple.
+
+Vous pouvez ensuite utiliser `npx nx run object-creator:run` et si tout se passe bien, les objets seront créés dans la base de donnée spécifiée dans la variable d'environnement "DATABASE_URL".
+
### Ajouter une nouvelle icône
Les icônes utilisées dans l'application front viennent de https://streamlineicons.com/.
diff --git a/Changelog.md b/Changelog.md
index 12114dc5a5..c1499e108c 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -7,6 +7,10 @@ et le projet suit un schéma de versionning inspiré de [Calendar Versioning](ht
# [2024.10.1] 22/10/2024
+#### :rocket: Nouvelles fonctionnalités
+
+- Ajout d'Eco-organisme sur BSVHU [PR 3619](https://github.com/MTES-MCT/trackdechets/pull/3619)
+
#### :bug: Corrections de bugs
- Documentation API Developers : Page Not Found, si on n'y accède pas via l'arborescence [PR 3621](https://github.com/MTES-MCT/trackdechets/pull/3621)
diff --git a/back/src/__tests__/factories.ts b/back/src/__tests__/factories.ts
index 742e666601..e88bf2f82e 100644
--- a/back/src/__tests__/factories.ts
+++ b/back/src/__tests__/factories.ts
@@ -521,20 +521,36 @@ export const applicationFactory = async (openIdEnabled?: boolean) => {
export const ecoOrganismeFactory = async ({
siret,
- handleBsdasri = false
+ handle,
+ createAssociatedCompany
}: {
siret?: string;
- handleBsdasri?: boolean;
+ handle?: {
+ handleBsdasri?: boolean;
+ handleBsda?: boolean;
+ handleBsvhu?: boolean;
+ };
+ createAssociatedCompany?: boolean;
}) => {
+ const { handleBsdasri, handleBsda, handleBsvhu } = handle ?? {};
const ecoOrganismeIndex = (await prisma.ecoOrganisme.count()) + 1;
const ecoOrganisme = await prisma.ecoOrganisme.create({
data: {
address: "",
name: `Eco-Organisme ${ecoOrganismeIndex}`,
- siret: siret ?? siretify(ecoOrganismeIndex),
- handleBsdasri
+ siret: siret ?? siretify(),
+ handleBsdasri,
+ handleBsda,
+ handleBsvhu
}
});
+ if (createAssociatedCompany) {
+ // create the related company so sirenify works as expected
+ await companyFactory({
+ siret: ecoOrganisme.siret,
+ name: `Eco-Organisme ${ecoOrganismeIndex}`
+ });
+ }
return ecoOrganisme;
};
diff --git a/back/src/__tests__/testWorkflow.ts b/back/src/__tests__/testWorkflow.ts
index 2678586d3f..4317e28461 100644
--- a/back/src/__tests__/testWorkflow.ts
+++ b/back/src/__tests__/testWorkflow.ts
@@ -19,7 +19,10 @@ async function testWorkflow(workflow: Workflow) {
});
if (workflowCompany.companyTypes.includes("ECO_ORGANISME")) {
// create ecoOrganisme to allow its user to perform api calls
- await ecoOrganismeFactory({ siret: company.siret!, handleBsdasri: true });
+ await ecoOrganismeFactory({
+ siret: company.siret!,
+ handle: { handleBsdasri: true }
+ });
}
if (
workflowCompany.companyTypes.includes("TRANSPORTER") &&
diff --git a/back/src/bsda/validation/refinements.ts b/back/src/bsda/validation/refinements.ts
index cc0364f0d1..5398f9e8f0 100644
--- a/back/src/bsda/validation/refinements.ts
+++ b/back/src/bsda/validation/refinements.ts
@@ -15,6 +15,7 @@ import {
Bsda,
BsdaStatus,
BsdaType,
+ BsdType,
Company,
CompanyType
} from "@prisma/client";
@@ -26,7 +27,8 @@ import { prisma } from "@td/prisma";
import { isWorker } from "../../companies/validation";
import {
isDestinationRefinement,
- isNotDormantRefinement,
+ isEcoOrganismeRefinement,
+ isEmitterNotDormantRefinement,
isRegisteredVatNumberRefinement,
isTransporterRefinement,
refineSiretAndGetCompany
@@ -259,36 +261,6 @@ export const checkRequiredFields: (
};
};
-async function refineAndGetEcoOrganisme(siret: string | null | undefined, ctx) {
- if (!siret) return null;
- const ecoOrganisme = await prisma.ecoOrganisme.findUnique({
- where: { siret }
- });
-
- if (ecoOrganisme === null) {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: `L'éco-organisme avec le SIRET ${siret} n'est pas référencé sur Trackdéchets`
- });
- }
-
- return ecoOrganisme;
-}
-
-async function isBsdaEcoOrganismeRefinement(
- siret: string | null | undefined,
- ctx: RefinementCtx
-) {
- const ecoOrganisme = await refineAndGetEcoOrganisme(siret, ctx);
-
- if (ecoOrganisme && !ecoOrganisme?.handleBsda) {
- ctx.addIssue({
- code: z.ZodIssueCode.custom,
- message: `L'éco-organisme avec le SIRET ${siret} n'est pas autorisé à apparaitre sur un BSDA`
- });
- }
-}
-
async function checkEmitterIsNotEcoOrganisme(
siret: string | null | undefined,
ctx: RefinementCtx
@@ -327,7 +299,7 @@ export const checkCompanies: Refinement = async (
);
};
- await isNotDormantRefinement(bsda.emitterCompanySiret, zodContext);
+ await isEmitterNotDormantRefinement(bsda.emitterCompanySiret, zodContext);
await isDestinationRefinement(
bsda.destinationCompanySiret,
zodContext,
@@ -355,7 +327,11 @@ export const checkCompanies: Refinement = async (
);
}
await isWorkerRefinement(bsda.workerCompanySiret, zodContext);
- await isBsdaEcoOrganismeRefinement(bsda.ecoOrganismeSiret, zodContext);
+ await isEcoOrganismeRefinement(
+ bsda.ecoOrganismeSiret,
+ BsdType.BSDA,
+ zodContext
+ );
await checkEmitterIsNotEcoOrganisme(bsda.emitterCompanySiret, zodContext);
};
diff --git a/back/src/bsda/validation/sirenify.ts b/back/src/bsda/validation/sirenify.ts
index 2711bb483f..fcbc0b56b0 100644
--- a/back/src/bsda/validation/sirenify.ts
+++ b/back/src/bsda/validation/sirenify.ts
@@ -1,6 +1,9 @@
import { ParsedZodBsda, ParsedZodBsdaTransporter } from "./schema";
import { CompanyInput } from "../../generated/graphql/types";
-import { nextBuildSirenify } from "../../companies/sirenify";
+import {
+ nextBuildSirenify,
+ NextCompanyInputAccessor
+} from "../../companies/sirenify";
import { getSealedFields } from "./rules";
import {
BsdaValidationContext,
@@ -11,11 +14,11 @@ import {
const sirenifyBsdaAccessors = (
bsda: ParsedZodBsda,
sealedFields: string[] // Tranformations should not be run on sealed fields
-) => [
+): NextCompanyInputAccessor[] => [
{
siret: bsda?.emitterCompanySiret,
skip: sealedFields.includes("emitterCompanySiret"),
- setter: (input, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.emitterCompanyName = companyInput.name;
input.emitterCompanyAddress = companyInput.address;
}
@@ -23,7 +26,7 @@ const sirenifyBsdaAccessors = (
{
siret: bsda?.destinationCompanySiret,
skip: sealedFields.includes("destinationCompanySiret"),
- setter: (input, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.destinationCompanyName = companyInput.name;
input.destinationCompanyAddress = companyInput.address;
}
@@ -31,7 +34,7 @@ const sirenifyBsdaAccessors = (
{
siret: bsda?.workerCompanySiret,
skip: sealedFields.includes("workerCompanySiret"),
- setter: (input, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.workerCompanyName = companyInput.name;
input.workerCompanyAddress = companyInput.address;
}
@@ -39,30 +42,53 @@ const sirenifyBsdaAccessors = (
{
siret: bsda?.brokerCompanySiret,
skip: sealedFields.includes("brokerCompanySiret"),
- setter: (input, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.brokerCompanyName = companyInput.name;
input.brokerCompanyAddress = companyInput.address;
}
},
- ...(bsda.intermediaries ?? []).map((_, idx) => ({
- siret: bsda.intermediaries![idx].siret,
- skip: sealedFields.includes("intermediaries"),
- setter: (input, companyInput: CompanyInput) => {
- const intermediary = input.intermediaries[idx];
- intermediary.name = companyInput.name;
- intermediary.address = companyInput.address;
- }
- })),
- ...(bsda.transporters ?? []).map((_, idx) => ({
- siret: bsda.transporters![idx].transporterCompanySiret,
- // FIXME skip conditionnaly based on transporter signatures
- skip: false,
- setter: (input, companyInput: CompanyInput) => {
- const transporter = input.transporters[idx];
- transporter.transporterCompanyName = companyInput.name;
- transporter.transporterCompanyAddress = companyInput.address;
+ {
+ siret: bsda?.ecoOrganismeSiret,
+ skip: sealedFields.includes("ecoOrganismeSiret"),
+ setter: (input, companyInput) => {
+ if (companyInput.name) {
+ input.ecoOrganismeName = companyInput.name;
+ }
}
- }))
+ },
+ ...(bsda.intermediaries ?? []).map(
+ (_, idx) =>
+ ({
+ siret: bsda.intermediaries![idx].siret,
+ skip: sealedFields.includes("intermediaries"),
+ setter: (input, companyInput) => {
+ const intermediary = input.intermediaries![idx];
+ if (companyInput.name) {
+ intermediary!.name = companyInput.name;
+ }
+ if (companyInput.address) {
+ intermediary!.address = companyInput.address;
+ }
+ }
+ } as NextCompanyInputAccessor)
+ ),
+ ...(bsda.transporters ?? []).map(
+ (_, idx) =>
+ ({
+ siret: bsda.transporters![idx].transporterCompanySiret,
+ // FIXME skip conditionnaly based on transporter signatures
+ skip: false,
+ setter: (input, companyInput) => {
+ const transporter = input.transporters![idx];
+ if (companyInput.name) {
+ transporter!.transporterCompanyName = companyInput.name;
+ }
+ if (companyInput.address) {
+ transporter!.transporterCompanyAddress = companyInput.address;
+ }
+ }
+ } as NextCompanyInputAccessor)
+ )
];
export const sirenifyBsda: (
diff --git a/back/src/bsdasris/resolvers/mutations/__tests__/createBsdasriEcoOrganisme.integration.ts b/back/src/bsdasris/resolvers/mutations/__tests__/createBsdasriEcoOrganisme.integration.ts
index 9a5493f98e..163261ffa0 100644
--- a/back/src/bsdasris/resolvers/mutations/__tests__/createBsdasriEcoOrganisme.integration.ts
+++ b/back/src/bsdasris/resolvers/mutations/__tests__/createBsdasriEcoOrganisme.integration.ts
@@ -129,7 +129,9 @@ describe("Mutation.createDasri", () => {
]);
});
it("create a dasri with an eco-organisme (eco-org user)", async () => {
- const ecoOrg = await ecoOrganismeFactory({ handleBsdasri: true });
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsdasri: true }
+ });
const { user } = await userWithCompanyFactory("MEMBER", {
siret: ecoOrg.siret
});
@@ -178,7 +180,9 @@ describe("Mutation.createDasri", () => {
expect(data.createBsdasri.ecoOrganisme?.siret).toEqual(ecoOrg.siret);
});
it("create a dasri with an eco-organisme and an unregistered emitter(eco-org user)", async () => {
- const ecoOrg = await ecoOrganismeFactory({ handleBsdasri: true });
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsdasri: true }
+ });
const { user } = await userWithCompanyFactory("MEMBER", {
siret: ecoOrg.siret
});
@@ -229,7 +233,9 @@ describe("Mutation.createDasri", () => {
expect(data.createBsdasri.emitter?.company?.siret).toEqual(siret);
});
it("create a dasri with an eco-organism (emitter user)", async () => {
- const ecoOrg = await ecoOrganismeFactory({ handleBsdasri: true });
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsdasri: true }
+ });
const { company: ecoOrgCompany } = await userWithCompanyFactory("MEMBER", {
siret: ecoOrg.siret
});
diff --git a/back/src/bsdasris/resolvers/mutations/__tests__/updateBsdasri.integration.ts b/back/src/bsdasris/resolvers/mutations/__tests__/updateBsdasri.integration.ts
index 2d9cb7ca88..f5855a8e93 100644
--- a/back/src/bsdasris/resolvers/mutations/__tests__/updateBsdasri.integration.ts
+++ b/back/src/bsdasris/resolvers/mutations/__tests__/updateBsdasri.integration.ts
@@ -323,7 +323,9 @@ describe("Mutation.updateBsdasri", () => {
it("should allow eco organisme fields update for INITIAL bsdasris", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
- const ecoOrg = await ecoOrganismeFactory({ handleBsdasri: true });
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsdasri: true }
+ });
const { company: ecoOrgCompany } = await userWithCompanyFactory("MEMBER", {
siret: ecoOrg.siret
});
@@ -355,7 +357,9 @@ describe("Mutation.updateBsdasri", () => {
it("should allow eco organisme fields nulling for INITIAL bsdasris", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
- const ecoOrg = await ecoOrganismeFactory({ handleBsdasri: true });
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsdasri: true }
+ });
const { company: ecoOrgCompany } = await userWithCompanyFactory("MEMBER", {
siret: ecoOrg.siret
});
@@ -430,7 +434,9 @@ describe("Mutation.updateBsdasri", () => {
});
it("should disallow eco organisme fields update after emission signature", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
- const ecoOrg = await ecoOrganismeFactory({ handleBsdasri: true });
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsdasri: true }
+ });
const destination = await userWithCompanyFactory("MEMBER");
await userWithCompanyFactory("MEMBER", {
diff --git a/back/src/bsdasris/sirenify.ts b/back/src/bsdasris/sirenify.ts
index 24abc56877..37478152cd 100644
--- a/back/src/bsdasris/sirenify.ts
+++ b/back/src/bsdasris/sirenify.ts
@@ -1,5 +1,8 @@
import { Prisma } from "@prisma/client";
-import buildSirenify, { nextBuildSirenify } from "../companies/sirenify";
+import buildSirenify, {
+ nextBuildSirenify,
+ NextCompanyInputAccessor
+} from "../companies/sirenify";
import { BsdasriInput, CompanyInput } from "../generated/graphql/types";
const accessors = (input: BsdasriInput) => [
@@ -31,11 +34,11 @@ export const sirenify = buildSirenify(accessors);
const bsdasriCreateInputAccessors = (
input: Prisma.BsdasriCreateInput,
sealedFields: string[] = [] // Tranformations should not be run on sealed fields
-) => [
+): NextCompanyInputAccessor[] => [
{
siret: input?.emitterCompanySiret,
skip: sealedFields.includes("emitterCompanySiret"),
- setter: (input: Prisma.BsdasriCreateInput, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.emitterCompanyName = companyInput.name;
input.emitterCompanyAddress = companyInput.address;
}
@@ -43,7 +46,7 @@ const bsdasriCreateInputAccessors = (
{
siret: input?.transporterCompanySiret,
skip: sealedFields.includes("transporterCompanySiret"),
- setter: (input: Prisma.BsdasriCreateInput, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.transporterCompanyName = companyInput.name;
input.transporterCompanyAddress = companyInput.address;
}
@@ -51,10 +54,19 @@ const bsdasriCreateInputAccessors = (
{
siret: input?.destinationCompanySiret,
skip: sealedFields.includes("destinationCompanySiret"),
- setter: (input: Prisma.BsdasriCreateInput, companyInput: CompanyInput) => {
+ setter: (input, companyInput) => {
input.destinationCompanyName = companyInput.name;
input.destinationCompanyAddress = companyInput.address;
}
+ },
+ {
+ siret: input?.ecoOrganismeSiret,
+ skip: sealedFields.includes("ecoOrganismeSiret"),
+ setter: (input, companyInput) => {
+ if (companyInput.name) {
+ input.ecoOrganismeName = companyInput.name;
+ }
+ }
}
];
diff --git a/back/src/bsffs/validation/bsff/refinements.ts b/back/src/bsffs/validation/bsff/refinements.ts
index 97e461a51c..6e5dcfecab 100644
--- a/back/src/bsffs/validation/bsff/refinements.ts
+++ b/back/src/bsffs/validation/bsff/refinements.ts
@@ -32,7 +32,7 @@ import { OPERATION } from "../../constants";
import { BsffOperationCode } from "../../../generated/graphql/types";
import {
isDestinationRefinement,
- isNotDormantRefinement,
+ isEmitterNotDormantRefinement,
isRegisteredVatNumberRefinement,
isTransporterRefinement
} from "../../../common/validation/zod/refinement";
@@ -55,7 +55,7 @@ export const checkCompanies: Refinement = async (
bsff,
zodContext
) => {
- await isNotDormantRefinement(bsff.emitterCompanySiret, zodContext);
+ await isEmitterNotDormantRefinement(bsff.emitterCompanySiret, zodContext);
await isDestinationRefinement(bsff.destinationCompanySiret, zodContext);
for (const transporter of bsff.transporters ?? []) {
diff --git a/back/src/bsvhu/__tests__/bsvhuEdition.test.ts b/back/src/bsvhu/__tests__/bsvhuEdition.test.ts
index 482f6fd42f..29bc55ac76 100644
--- a/back/src/bsvhu/__tests__/bsvhuEdition.test.ts
+++ b/back/src/bsvhu/__tests__/bsvhuEdition.test.ts
@@ -1,6 +1,7 @@
import {
BsvhuDestinationInput,
BsvhuDestinationType,
+ BsvhuEcoOrganismeInput,
BsvhuEmitterInput,
BsvhuIdentificationInput,
BsvhuInput,
@@ -17,7 +18,7 @@ import { bsvhuEditionRules } from "../validation/rules";
import { graphQlInputToZodBsvhu } from "../validation/helpers";
describe("edition", () => {
- test("an edition rule should be defined for every key in BsdaInput", () => {
+ test("an edition rule should be defined for every key in BsvhuInput", () => {
// Create a dummy BSDVHU input where every possible key is present
// The typing will break whenever a field is added or modified
// to BsvhuInput so that we think of adding an entry to the edition rules
@@ -96,6 +97,11 @@ describe("edition", () => {
operation
};
+ const ecoOrganisme: Required = {
+ siret: "xxx",
+ name: "yyy"
+ };
+
const input: Required = {
emitter,
wasteCode: "",
@@ -104,7 +110,9 @@ describe("edition", () => {
quantity: 1,
weight,
transporter,
- destination
+ destination,
+ intermediaries: [company],
+ ecoOrganisme
};
const flatInput = graphQlInputToZodBsvhu(input);
for (const key of Object.keys(flatInput)) {
diff --git a/back/src/bsvhu/__tests__/elastic.integration.ts b/back/src/bsvhu/__tests__/elastic.integration.ts
index 4ab671918c..c622cc5391 100644
--- a/back/src/bsvhu/__tests__/elastic.integration.ts
+++ b/back/src/bsvhu/__tests__/elastic.integration.ts
@@ -30,6 +30,7 @@ describe("toBsdElastic > companies Names & OrgIds", () => {
let elasticBsvhu: BsdElastic;
let intermediary1: Company;
let intermediary2: Company;
+ let ecoOrganisme: Company;
beforeAll(async () => {
// Given
@@ -43,6 +44,7 @@ describe("toBsdElastic > companies Names & OrgIds", () => {
});
intermediary1 = await companyFactory({ name: "Intermediaire 1" });
intermediary2 = await companyFactory({ name: "Intermediaire 2" });
+ ecoOrganisme = await companyFactory({ name: "Eco organisme" });
bsvhu = await bsvhuFactory({
opt: {
@@ -53,6 +55,8 @@ describe("toBsdElastic > companies Names & OrgIds", () => {
transporterCompanyVatNumber: transporter.vatNumber,
destinationCompanyName: destination.name,
destinationCompanySiret: destination.siret,
+ ecoOrganismeName: ecoOrganisme.name,
+ ecoOrganismeSiret: ecoOrganisme.siret,
intermediaries: {
createMany: {
data: [
@@ -75,6 +79,7 @@ describe("toBsdElastic > companies Names & OrgIds", () => {
expect(elasticBsvhu.companyNames).toContain(destination.name);
expect(elasticBsvhu.companyNames).toContain(intermediary1.name);
expect(elasticBsvhu.companyNames).toContain(intermediary2.name);
+ expect(elasticBsvhu.companyNames).toContain(ecoOrganisme.name);
});
test("companyOrgIds > should contain the orgIds of ALL BSVHU companies", async () => {
@@ -84,5 +89,6 @@ describe("toBsdElastic > companies Names & OrgIds", () => {
expect(elasticBsvhu.companyOrgIds).toContain(destination.siret);
expect(elasticBsvhu.companyOrgIds).toContain(intermediary1.siret);
expect(elasticBsvhu.companyOrgIds).toContain(intermediary2.siret);
+ expect(elasticBsvhu.companyOrgIds).toContain(ecoOrganisme.siret);
});
});
diff --git a/back/src/bsvhu/__tests__/factories.vhu.ts b/back/src/bsvhu/__tests__/factories.vhu.ts
index f77a861a64..c205ef7466 100644
--- a/back/src/bsvhu/__tests__/factories.vhu.ts
+++ b/back/src/bsvhu/__tests__/factories.vhu.ts
@@ -6,7 +6,11 @@ import {
} from "@prisma/client";
import getReadableId, { ReadableIdPrefix } from "../../forms/readableId";
import { prisma } from "@td/prisma";
-import { companyFactory, siretify } from "../../__tests__/factories";
+import {
+ companyFactory,
+ ecoOrganismeFactory,
+ siretify
+} from "../../__tests__/factories";
import { BsvhuForElastic, BsvhuForElasticInclude } from "../elastic";
export const bsvhuFactory = async ({
@@ -20,11 +24,16 @@ export const bsvhuFactory = async ({
const destinationCompany = await companyFactory({
companyTypes: ["WASTE_VEHICLES"]
});
+ const ecoOrganisme = await ecoOrganismeFactory({
+ handle: { handleBsvhu: true },
+ createAssociatedCompany: true
+ });
const created = await prisma.bsvhu.create({
data: {
...getVhuFormdata(),
transporterCompanySiret: transporterCompany.siret,
destinationCompanySiret: destinationCompany.siret,
+ ecoOrganismeSiret: ecoOrganisme.siret,
...opt
},
include: {
@@ -85,7 +94,10 @@ const getVhuFormdata = (): Prisma.BsvhuCreateInput => ({
destinationReceptionWeight: null,
destinationReceptionAcceptationStatus: null,
destinationReceptionRefusalReason: null,
- destinationOperationCode: null
+ destinationOperationCode: null,
+
+ ecoOrganismeSiret: siretify(4),
+ ecoOrganismeName: "Eco-Organisme"
});
export const toIntermediaryCompany = (company: Company, contact = "toto") => ({
diff --git a/back/src/bsvhu/__tests__/registry.integration.ts b/back/src/bsvhu/__tests__/registry.integration.ts
index e57cb1e192..46aa51a1f3 100644
--- a/back/src/bsvhu/__tests__/registry.integration.ts
+++ b/back/src/bsvhu/__tests__/registry.integration.ts
@@ -9,7 +9,7 @@ import {
} from "../registry";
import { bsvhuFactory, toIntermediaryCompany } from "./factories.vhu";
import { resetDatabase } from "../../../integration-tests/helper";
-import { companyFactory } from "../../__tests__/factories";
+import { companyFactory, ecoOrganismeFactory } from "../../__tests__/factories";
import { RegistryBsvhuInclude } from "../../registry/elastic";
describe("toGenericWaste", () => {
@@ -559,6 +559,32 @@ describe("toAllWaste", () => {
expect(waste.intermediary3CompanyName).toBe(null);
expect(waste.intermediary3CompanySiret).toBe(null);
});
+
+ it("should contain ecoOrganisme infos", async () => {
+ // Given
+ const ecoOrganisme = await ecoOrganismeFactory({
+ handle: { handleBsvhu: true }
+ });
+
+ const bsvhu = await bsvhuFactory({
+ opt: {
+ ecoOrganismeSiret: ecoOrganisme.siret,
+ ecoOrganismeName: ecoOrganisme.name
+ }
+ });
+
+ // When
+ const bsvhuForRegistry = await prisma.bsvhu.findUniqueOrThrow({
+ where: { id: bsvhu.id },
+ include: RegistryBsvhuInclude
+ });
+ const waste = toAllWaste(bsvhuForRegistry);
+
+ // Then
+ expect(waste).not.toBeUndefined();
+ expect(waste.ecoOrganismeSiren).toBe(ecoOrganisme.siret.substring(0, 9));
+ expect(waste.ecoOrganismeName).toBe(ecoOrganisme.name);
+ });
});
describe("getTransportersData", () => {
diff --git a/back/src/bsvhu/converter.ts b/back/src/bsvhu/converter.ts
index 6909954f48..38d6b11d2a 100644
--- a/back/src/bsvhu/converter.ts
+++ b/back/src/bsvhu/converter.ts
@@ -22,7 +22,8 @@ import {
BsvhuNextDestination,
BsvhuTransport,
BsvhuTransportInput,
- CompanyInput
+ CompanyInput,
+ BsvhuEcoOrganisme
} from "../generated/graphql/types";
import {
Prisma,
@@ -160,6 +161,10 @@ export function expandVhuFormFromDb(form: PrismaVhuForm): GraphqlVhuForm {
takenOverAt: processDate(form.transporterTransportTakenOverAt)
})
}),
+ ecoOrganisme: nullIfNoValues({
+ name: form.ecoOrganismeName,
+ siret: form.ecoOrganismeSiret
+ }),
metadata: null as any
};
}
@@ -169,6 +174,7 @@ export function flattenVhuInput(formInput: BsvhuInput) {
...flattenVhuEmitterInput(formInput),
...flattenVhuDestinationInput(formInput),
...flattenVhuTransporterInput(formInput),
+ ...flattenVhuEcoOrganismeInput(formInput),
packaging: chain(formInput, f => f.packaging),
wasteCode: chain(formInput, f => f.wasteCode),
quantity: chain(formInput, f => f.quantity),
@@ -341,6 +347,15 @@ function flattenVhuTransporterInput({
};
}
+function flattenVhuEcoOrganismeInput({
+ ecoOrganisme
+}: Pick) {
+ return {
+ ecoOrganismeName: chain(ecoOrganisme, e => e.name),
+ ecoOrganismeSiret: chain(ecoOrganisme, e => e.siret)
+ };
+}
+
function flattenTransporterTransportInput(
input:
| {
diff --git a/back/src/bsvhu/elastic.ts b/back/src/bsvhu/elastic.ts
index 60745af50a..0ff61c929c 100644
--- a/back/src/bsvhu/elastic.ts
+++ b/back/src/bsvhu/elastic.ts
@@ -29,6 +29,7 @@ export async function getBsvhuForElastic(
type ElasticSirets = {
emitterCompanySiret: string | null | undefined;
+ ecoOrganismeSiret: string | null | undefined;
destinationCompanySiret: string | null | undefined;
transporterCompanySiret: string | null | undefined;
intermediarySiret1?: string | null | undefined;
@@ -54,6 +55,7 @@ const getBsvhuSirets = (bsvhu: BsvhuForElastic): ElasticSirets => {
const bsvhuSirets: ElasticSirets = {
emitterCompanySiret: bsvhu.emitterCompanySiret,
destinationCompanySiret: bsvhu.destinationCompanySiret,
+ ecoOrganismeSiret: bsvhu.ecoOrganismeSiret,
transporterCompanySiret: getTransporterCompanyOrgId(bsvhu),
...intermediarySirets
};
@@ -210,8 +212,8 @@ export function toBsdElastic(bsvhu: BsvhuForElastic): BsdElastic {
traderCompanySiret: "",
traderCompanyAddress: "",
- ecoOrganismeName: "",
- ecoOrganismeSiret: "",
+ ecoOrganismeName: bsvhu.ecoOrganismeName ?? "",
+ ecoOrganismeSiret: bsvhu.ecoOrganismeSiret ?? "",
nextDestinationCompanyName:
bsvhu.destinationOperationNextDestinationCompanyName ?? "",
@@ -247,6 +249,7 @@ export function toBsdElastic(bsvhu: BsvhuForElastic): BsdElastic {
bsvhu.emitterCompanyName,
bsvhu.transporterCompanyName,
bsvhu.destinationCompanyName,
+ bsvhu.ecoOrganismeName,
...bsvhu.intermediaries.map(intermediary => intermediary.name)
]
.filter(Boolean)
@@ -256,6 +259,7 @@ export function toBsdElastic(bsvhu: BsvhuForElastic): BsdElastic {
bsvhu.transporterCompanySiret,
bsvhu.transporterCompanyVatNumber,
bsvhu.destinationCompanySiret,
+ bsvhu.ecoOrganismeSiret,
...bsvhu.intermediaries.map(intermediary => intermediary.siret),
...bsvhu.intermediaries.map(intermediary => intermediary.vatNumber)
].filter(Boolean)
diff --git a/back/src/bsvhu/pdf/components/BsvhuPdf.tsx b/back/src/bsvhu/pdf/components/BsvhuPdf.tsx
index 00f8027adb..de28bfb96a 100644
--- a/back/src/bsvhu/pdf/components/BsvhuPdf.tsx
+++ b/back/src/bsvhu/pdf/components/BsvhuPdf.tsx
@@ -107,6 +107,16 @@ export function BsvhuPdf({ bsvhu, qrCode, renderEmpty }: Props) {
Nom de la personne à contacter : {bsvhu.emitter?.company?.contact}
+ {bsvhu?.ecoOrganisme?.siret && (
+
+ Eco-organisme désigné :{" "}
+
+ Raison sociale : {bsvhu.ecoOrganisme?.name}
+
+ SIREN : {bsvhu.ecoOrganisme?.siret?.substring(0, 9)}
+
+
+ )}
{/* End Emitter */}
{/* Recipient */}
diff --git a/back/src/bsvhu/permissions.ts b/back/src/bsvhu/permissions.ts
index 852009b779..b73d8f1dc7 100644
--- a/back/src/bsvhu/permissions.ts
+++ b/back/src/bsvhu/permissions.ts
@@ -11,6 +11,7 @@ function readers(bsvhu: Bsvhu): string[] {
bsvhu.destinationCompanySiret,
bsvhu.transporterCompanySiret,
bsvhu.transporterCompanyVatNumber,
+ bsvhu.ecoOrganismeSiret,
...bsvhu.intermediariesOrgIds
].filter(Boolean);
}
@@ -27,6 +28,8 @@ function contributors(bsvhu: Bsvhu, input?: BsvhuInput): string[] {
const updateTransporterCompanySiret = input?.transporter?.company?.siret;
const updateTransporterCompanyVatNumber =
input?.transporter?.company?.vatNumber;
+ const updateEcoOrganismeCompanySiret = input?.ecoOrganisme?.siret;
+
const updateIntermediaries = (input?.intermediaries ?? []).flatMap(i => [
i.siret,
i.vatNumber
@@ -52,6 +55,10 @@ function contributors(bsvhu: Bsvhu, input?: BsvhuInput): string[] {
? updateTransporterCompanyVatNumber
: bsvhu.transporterCompanyVatNumber;
+ const ecoOrganismeCompanySiret =
+ updateEcoOrganismeCompanySiret !== undefined
+ ? updateEcoOrganismeCompanySiret
+ : bsvhu.ecoOrganismeSiret;
const intermediariesOrgIds =
input?.intermediaries !== undefined
? updateIntermediaries
@@ -62,6 +69,7 @@ function contributors(bsvhu: Bsvhu, input?: BsvhuInput): string[] {
destinationCompanySiret,
transporterCompanySiret,
transporterCompanyVatNumber,
+ ecoOrganismeCompanySiret,
...intermediariesOrgIds
].filter(Boolean);
}
@@ -72,6 +80,7 @@ function contributors(bsvhu: Bsvhu, input?: BsvhuInput): string[] {
function creators(input: BsvhuInput) {
return [
input.emitter?.company?.siret,
+ input.ecoOrganisme?.siret,
input.transporter?.company?.siret,
input.transporter?.company?.vatNumber,
input.destination?.company?.siret
diff --git a/back/src/bsvhu/registry.ts b/back/src/bsvhu/registry.ts
index fc6b3cc5e4..eb795ee62d 100644
--- a/back/src/bsvhu/registry.ts
+++ b/back/src/bsvhu/registry.ts
@@ -119,6 +119,10 @@ export function getRegistryFields(
registryFields.isTransportedWasteFor.push(bsvhu.transporterCompanySiret);
registryFields.isAllWasteFor.push(bsvhu.transporterCompanySiret);
}
+ if (bsvhu.ecoOrganismeSiret) {
+ registryFields.isOutgoingWasteFor.push(bsvhu.ecoOrganismeSiret);
+ registryFields.isAllWasteFor.push(bsvhu.ecoOrganismeSiret);
+ }
if (bsvhu.intermediaries?.length) {
for (const intermediary of bsvhu.intermediaries) {
const intermediaryOrgId = getIntermediaryCompanyOrgId(intermediary);
@@ -172,8 +176,8 @@ export function toGenericWaste(bsvhu: RegistryBsvhu): GenericWaste {
id: bsvhu.id,
createdAt: bsvhu.createdAt,
updatedAt: bsvhu.createdAt,
- ecoOrganismeName: null,
- ecoOrganismeSiren: null,
+ ecoOrganismeName: bsvhu.ecoOrganismeName,
+ ecoOrganismeSiren: bsvhu.ecoOrganismeSiret?.slice(0, 9),
bsdType: "BSVHU",
bsdSubType: getBsvhuSubType(bsvhu),
status: bsvhu.status,
diff --git a/back/src/bsvhu/resolvers/mutations/__tests__/createBsvhu.integration.ts b/back/src/bsvhu/resolvers/mutations/__tests__/createBsvhu.integration.ts
index 3314fe114f..c28fb8d839 100644
--- a/back/src/bsvhu/resolvers/mutations/__tests__/createBsvhu.integration.ts
+++ b/back/src/bsvhu/resolvers/mutations/__tests__/createBsvhu.integration.ts
@@ -6,7 +6,8 @@ import {
siretify,
userFactory,
userWithCompanyFactory,
- transporterReceiptFactory
+ transporterReceiptFactory,
+ ecoOrganismeFactory
} from "../../../../__tests__/factories";
import makeClient from "../../../../__tests__/testClient";
import gql from "graphql-tag";
@@ -46,6 +47,10 @@ const CREATE_VHU_FORM = gql`
intermediaries {
siret
}
+ ecoOrganisme {
+ siret
+ name
+ }
weight {
value
}
@@ -311,6 +316,71 @@ describe("Mutation.Vhu.create", () => {
);
});
+ it("should create a bsvhu with eco-organisme", async () => {
+ const { user, company } = await userWithCompanyFactory("MEMBER");
+ const destinationCompany = await companyFactory({
+ companyTypes: ["WASTE_VEHICLES"]
+ });
+
+ const ecoOrganisme = await ecoOrganismeFactory({
+ handle: { handleBsvhu: true },
+ createAssociatedCompany: true
+ });
+
+ const input = {
+ emitter: {
+ company: {
+ siret: company.siret,
+ name: "The crusher",
+ address: "Rue de la carcasse",
+ contact: "Un centre VHU",
+ phone: "0101010101",
+ mail: "emitter@mail.com"
+ },
+ agrementNumber: "1234"
+ },
+ wasteCode: "16 01 06",
+ packaging: "UNITE",
+ identification: {
+ numbers: ["123", "456"],
+ type: "NUMERO_ORDRE_REGISTRE_POLICE"
+ },
+ quantity: 2,
+ weight: {
+ isEstimate: false,
+ value: 1.3
+ },
+ destination: {
+ type: "BROYEUR",
+ plannedOperationCode: "R 12",
+ company: {
+ siret: destinationCompany.siret,
+ name: "destination",
+ address: "address",
+ contact: "contactEmail",
+ phone: "contactPhone",
+ mail: "contactEmail@mail.com"
+ },
+ agrementNumber: "9876"
+ },
+ ecoOrganisme: {
+ siret: ecoOrganisme.siret,
+ name: ecoOrganisme.name
+ }
+ };
+ const { mutate } = makeClient(user);
+ const { data } = await mutate>(
+ CREATE_VHU_FORM,
+ {
+ variables: {
+ input
+ }
+ }
+ );
+ expect(data.createBsvhu.id).toBeDefined();
+ expect(data.createBsvhu.ecoOrganisme!.siret).toBe(ecoOrganisme.siret);
+ });
+
it("should create a bsvhu with intermediary", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
const destinationCompany = await companyFactory({
diff --git a/back/src/bsvhu/resolvers/mutations/__tests__/duplicateBsvhu.integration.ts b/back/src/bsvhu/resolvers/mutations/__tests__/duplicateBsvhu.integration.ts
index 832656319c..7065d80925 100644
--- a/back/src/bsvhu/resolvers/mutations/__tests__/duplicateBsvhu.integration.ts
+++ b/back/src/bsvhu/resolvers/mutations/__tests__/duplicateBsvhu.integration.ts
@@ -3,6 +3,7 @@ import { xDaysAgo } from "../../../../utils";
import { resetDatabase } from "../../../../../integration-tests/helper";
import {
companyFactory,
+ ecoOrganismeFactory,
transporterReceiptFactory,
userWithCompanyFactory
} from "../../../../__tests__/factories";
@@ -82,6 +83,10 @@ describe("mutaion.duplicateBsvhu", () => {
const intermediary = await companyFactory();
+ const ecoOrganisme = await ecoOrganismeFactory({
+ handle: { handleBsvhu: true }
+ });
+
const bsvhu = await bsvhuFactory({
opt: {
emitterIrregularSituation: false,
@@ -125,7 +130,9 @@ describe("mutaion.duplicateBsvhu", () => {
}
]
}
- }
+ },
+ ecoOrganismeSiret: ecoOrganisme.siret,
+ ecoOrganismeName: ecoOrganisme.name
}
});
const { mutate } = makeClient(emitter.user);
@@ -195,6 +202,8 @@ describe("mutaion.duplicateBsvhu", () => {
transporterCustomInfo,
transporterTransportPlates,
transporterRecepisseIsExempted,
+ ecoOrganismeSiret,
+ ecoOrganismeName,
...rest
} = bsvhu;
@@ -283,7 +292,9 @@ describe("mutaion.duplicateBsvhu", () => {
transporterTransportTakenOverAt,
transporterCustomInfo,
transporterTransportPlates,
- transporterRecepisseIsExempted
+ transporterRecepisseIsExempted,
+ ecoOrganismeSiret,
+ ecoOrganismeName
});
// make sure this test breaks when a new field is added to the Bsvhu model
diff --git a/back/src/bsvhu/resolvers/queries/__tests__/bsvhu.integration.ts b/back/src/bsvhu/resolvers/queries/__tests__/bsvhu.integration.ts
index 9a4c4fe2d3..c3684d4e4f 100644
--- a/back/src/bsvhu/resolvers/queries/__tests__/bsvhu.integration.ts
+++ b/back/src/bsvhu/resolvers/queries/__tests__/bsvhu.integration.ts
@@ -40,6 +40,10 @@ query GetBsvhu($id: ID!) {
number
}
}
+ ecoOrganisme {
+ name
+ siret
+ }
weight {
value
}
diff --git a/back/src/bsvhu/resolvers/queries/__tests__/bsvhumetadata.integration.ts b/back/src/bsvhu/resolvers/queries/__tests__/bsvhumetadata.integration.ts
index 8d344bb4ea..e0d2ef78c2 100644
--- a/back/src/bsvhu/resolvers/queries/__tests__/bsvhumetadata.integration.ts
+++ b/back/src/bsvhu/resolvers/queries/__tests__/bsvhumetadata.integration.ts
@@ -161,6 +161,6 @@ describe("Query.Bsvhu", () => {
variables: { id: bsd.id }
});
- expect(data.bsvhu.metadata?.fields?.sealed?.length).toBe(58);
+ expect(data.bsvhu.metadata?.fields?.sealed?.length).toBe(60);
});
});
diff --git a/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql b/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql
index 172c0b01ff..619723b271 100644
--- a/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql
+++ b/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql
@@ -96,6 +96,9 @@ input BsvhuInput {
Le nombre maximal d'intermédiaires sur un bordereau est de 3.
"""
intermediaries: [CompanyInput!]
+
+ "Eco-organisme"
+ ecoOrganisme: BsvhuEcoOrganismeInput
}
input BsvhuEmitterInput {
@@ -109,6 +112,11 @@ input BsvhuEmitterInput {
company: BsvhuCompanyInput
}
+input BsvhuEcoOrganismeInput {
+ name: String!
+ siret: String!
+}
+
"Extension de CompanyInput ajoutant des champs d'adresse séparés"
input BsvhuCompanyInput {
"""
diff --git a/back/src/bsvhu/typeDefs/bsvhu.objects.graphql b/back/src/bsvhu/typeDefs/bsvhu.objects.graphql
index aef6bc68d6..3106fb537a 100644
--- a/back/src/bsvhu/typeDefs/bsvhu.objects.graphql
+++ b/back/src/bsvhu/typeDefs/bsvhu.objects.graphql
@@ -62,6 +62,9 @@ type Bsvhu {
"""
intermediaries: [FormCompany!]
+ "Eco-organisme"
+ ecoOrganisme: BsvhuEcoOrganisme
+
metadata: BsvhuMetadata!
}
@@ -82,6 +85,12 @@ type BsvhuEmission {
signature: Signature
}
+"Information sur l'éco-organisme responsable du BSVHU"
+type BsvhuEcoOrganisme {
+ name: String!
+ siret: String!
+}
+
type BsvhuTransporter {
"Coordonnées de l'entreprise de transport"
company: FormCompany
diff --git a/back/src/bsvhu/validation/__tests__/validation.integration.ts b/back/src/bsvhu/validation/__tests__/validation.integration.ts
index e8a7ca65b8..7cee23b741 100644
--- a/back/src/bsvhu/validation/__tests__/validation.integration.ts
+++ b/back/src/bsvhu/validation/__tests__/validation.integration.ts
@@ -1,7 +1,8 @@
-import { Company, OperationMode } from "@prisma/client";
+import { Company, EcoOrganisme, OperationMode } from "@prisma/client";
import { resetDatabase } from "../../../../integration-tests/helper";
import {
companyFactory,
+ ecoOrganismeFactory,
transporterReceiptFactory
} from "../../../__tests__/factories";
import { CompanySearchResult } from "../../../companies/types";
@@ -35,6 +36,7 @@ describe("BSVHU validation", () => {
let foreignTransporter: Company;
let transporterCompany: Company;
let intermediaryCompany: Company;
+ let ecoOrganisme: EcoOrganisme;
beforeAll(async () => {
const emitterCompany = await companyFactory({ companyTypes: ["PRODUCER"] });
transporterCompany = await companyFactory({
@@ -51,12 +53,16 @@ describe("BSVHU validation", () => {
intermediaryCompany = await companyFactory({
companyTypes: ["INTERMEDIARY"]
});
-
+ ecoOrganisme = await ecoOrganismeFactory({
+ handle: { handleBsvhu: true },
+ createAssociatedCompany: true
+ });
const prismaBsvhu = await bsvhuFactory({
opt: {
emitterCompanySiret: emitterCompany.siret,
transporterCompanySiret: transporterCompany.siret,
destinationCompanySiret: destinationCompany.siret,
+ ecoOrganismeSiret: ecoOrganisme.siret,
intermediaries: {
create: [toIntermediaryCompany(intermediaryCompany)]
}
@@ -408,6 +414,30 @@ describe("BSVHU validation", () => {
}
});
+ test("when ecoOrganisme isn't authorized for BSVHU", async () => {
+ const ecoOrg = await ecoOrganismeFactory({
+ handle: { handleBsda: true }
+ });
+ const data: ZodBsvhu = {
+ ...bsvhu,
+ ecoOrganismeSiret: ecoOrg.siret
+ };
+ expect.assertions(1);
+
+ try {
+ await parseBsvhuAsync(data, {
+ ...context,
+ currentSignatureType: "TRANSPORT"
+ });
+ } catch (err) {
+ expect((err as ZodError).issues).toEqual([
+ expect.objectContaining({
+ message: `L'éco-organisme avec le SIRET ${ecoOrg.siret} n'est pas autorisé à apparaitre sur un BSVHU`
+ })
+ ]);
+ }
+ });
+
describe("Emitter transports own waste", () => {
it("allowed if exemption", async () => {
const data: ZodBsvhu = {
@@ -577,7 +607,8 @@ describe("BSVHU validation", () => {
[bsvhu.emitterCompanySiret!]: searchResult("émetteur"),
[bsvhu.transporterCompanySiret!]: searchResult("transporteur"),
[bsvhu.destinationCompanySiret!]: searchResult("destinataire"),
- [intermediaryCompany.siret!]: searchResult("intermédiaire")
+ [intermediaryCompany.siret!]: searchResult("intermédiaire"),
+ [ecoOrganisme.siret!]: searchResult("ecoOrganisme")
};
(searchCompany as jest.Mock).mockImplementation((clue: string) => {
return Promise.resolve(searchResults[clue]);
@@ -611,6 +642,9 @@ describe("BSVHU validation", () => {
expect(sirenified.intermediaries![0].address).toEqual(
searchResults[intermediaryCompany.siret!].address
);
+ expect(sirenified.ecoOrganismeName).toEqual(
+ searchResults[ecoOrganisme.siret!].name
+ );
});
it("should not overwrite `name` and `address` based on SIRENE data for sealed fields", async () => {
const searchResults = {
diff --git a/back/src/bsvhu/validation/helpers.ts b/back/src/bsvhu/validation/helpers.ts
index c641503d78..46ca506bcb 100644
--- a/back/src/bsvhu/validation/helpers.ts
+++ b/back/src/bsvhu/validation/helpers.ts
@@ -113,7 +113,10 @@ export async function getBsvhuUserFunctions(
(bsvhu.transporterCompanySiret != null &&
orgIds.includes(bsvhu.transporterCompanySiret)) ||
(bsvhu.transporterCompanyVatNumber != null &&
- orgIds.includes(bsvhu.transporterCompanyVatNumber))
+ orgIds.includes(bsvhu.transporterCompanyVatNumber)),
+ isEcoOrganisme:
+ bsvhu.ecoOrganismeSiret != null &&
+ orgIds.includes(bsvhu.ecoOrganismeSiret)
};
}
diff --git a/back/src/bsvhu/validation/refinements.ts b/back/src/bsvhu/validation/refinements.ts
index acd1373602..57b4c9c75c 100644
--- a/back/src/bsvhu/validation/refinements.ts
+++ b/back/src/bsvhu/validation/refinements.ts
@@ -10,11 +10,12 @@ import {
import { getSignatureAncestors } from "./helpers";
import { isArray } from "../../common/dataTypes";
import { capitalize } from "../../common/strings";
-import { WasteAcceptationStatus } from "@prisma/client";
+import { BsdType, WasteAcceptationStatus } from "@prisma/client";
import {
destinationOperationModeRefinement,
isDestinationRefinement,
- isNotDormantRefinement,
+ isEcoOrganismeRefinement,
+ isEmitterNotDormantRefinement,
isRegisteredVatNumberRefinement,
isTransporterRefinement
} from "../../common/validation/zod/refinement";
@@ -33,7 +34,7 @@ export const checkCompanies: Refinement = async (
bsvhu,
zodContext
) => {
- await isNotDormantRefinement(bsvhu.emitterCompanySiret, zodContext);
+ await isEmitterNotDormantRefinement(bsvhu.emitterCompanySiret, zodContext);
await isDestinationRefinement(
bsvhu.destinationCompanySiret,
zodContext,
@@ -51,6 +52,11 @@ export const checkCompanies: Refinement = async (
bsvhu.transporterCompanyVatNumber,
zodContext
);
+ await isEcoOrganismeRefinement(
+ bsvhu.ecoOrganismeSiret,
+ BsdType.BSVHU,
+ zodContext
+ );
};
export const checkWeights: Refinement = (
diff --git a/back/src/bsvhu/validation/rules.ts b/back/src/bsvhu/validation/rules.ts
index 1b6e5bafde..16157624e3 100644
--- a/back/src/bsvhu/validation/rules.ts
+++ b/back/src/bsvhu/validation/rules.ts
@@ -511,6 +511,20 @@ export const bsvhuEditionRules: BsvhuEditionRules = {
// from: "TRANSPORT"
// }
},
+ ecoOrganismeName: {
+ readableFieldName: "le nom de l'éco-organisme",
+ sealed: { from: "OPERATION" },
+ path: ["ecoOrganisme", "name"],
+ required: {
+ from: "TRANSPORT",
+ when: bsvhu => !!bsvhu.ecoOrganismeSiret
+ }
+ },
+ ecoOrganismeSiret: {
+ readableFieldName: "le SIRET de l'éco-organisme",
+ sealed: { from: "OPERATION" },
+ path: ["ecoOrganisme", "siret"]
+ },
intermediaries: {
readableFieldName: "les intermédiaires",
sealed: { from: "TRANSPORT" },
diff --git a/back/src/bsvhu/validation/schema.ts b/back/src/bsvhu/validation/schema.ts
index 018b1fbef8..aa6f80c9f9 100644
--- a/back/src/bsvhu/validation/schema.ts
+++ b/back/src/bsvhu/validation/schema.ts
@@ -182,6 +182,8 @@ const rawBsvhuSchema = z.object({
.boolean()
.nullish()
.transform(v => Boolean(v)),
+ ecoOrganismeName: z.string().nullish(),
+ ecoOrganismeSiret: siretSchema(CompanyRole.EcoOrganisme).nullish(),
intermediaries: z
.array(intermediarySchema)
.nullish()
diff --git a/back/src/bsvhu/validation/sirenify.ts b/back/src/bsvhu/validation/sirenify.ts
index ddd01cfb7a..06bb4783ed 100644
--- a/back/src/bsvhu/validation/sirenify.ts
+++ b/back/src/bsvhu/validation/sirenify.ts
@@ -49,6 +49,15 @@ const sirenifyBsvhuAccessors = (
input.transporterCompanyAddress = companyInput.address;
}
},
+ {
+ siret: bsvhu?.ecoOrganismeSiret,
+ skip: sealedFields.includes("ecoOrganismeSiret"),
+ setter: (input, companyInput) => {
+ if (companyInput.name) {
+ input.ecoOrganismeName = companyInput.name;
+ }
+ }
+ },
...(bsvhu.intermediaries ?? []).map(
(_, idx) =>
({
diff --git a/back/src/bsvhu/validation/types.ts b/back/src/bsvhu/validation/types.ts
index a2dfb7ecf6..c26110df02 100644
--- a/back/src/bsvhu/validation/types.ts
+++ b/back/src/bsvhu/validation/types.ts
@@ -7,6 +7,7 @@ export type BsvhuUserFunctions = {
isEmitter: boolean;
isDestination: boolean;
isTransporter: boolean;
+ isEcoOrganisme: boolean;
};
export type BsvhuValidationContext = {
diff --git a/back/src/common/validation/zod/refinement.ts b/back/src/common/validation/zod/refinement.ts
index f34986fd7f..6a7d5abc3c 100644
--- a/back/src/common/validation/zod/refinement.ts
+++ b/back/src/common/validation/zod/refinement.ts
@@ -7,7 +7,7 @@ import {
isWasteVehicles
} from "../../../companies/validation";
import { prisma } from "@td/prisma";
-import { Company, CompanyVerificationStatus } from "@prisma/client";
+import { BsdType, Company, CompanyVerificationStatus } from "@prisma/client";
import { getOperationModesFromOperationCode } from "../../operationModes";
import { CompanyRole, pathFromCompanyRole } from "./schema";
@@ -73,6 +73,27 @@ export async function refineSiretAndGetCompany(
return company;
}
+
+export async function refineAndGetEcoOrganisme(
+ siret: string | null | undefined,
+ ctx: RefinementCtx
+) {
+ if (!siret) return null;
+ const ecoOrganisme = await prisma.ecoOrganisme.findUnique({
+ where: { siret }
+ });
+
+ if (ecoOrganisme === null) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ path: ["ecoOrganisme", "siret"],
+ message: `L'éco-organisme avec le SIRET ${siret} n'est pas référencé sur Trackdéchets`
+ });
+ }
+
+ return ecoOrganisme;
+}
+
export const isRegisteredVatNumberRefinement = async (
vatNumber: string | null | undefined,
ctx: RefinementCtx
@@ -159,7 +180,7 @@ export async function isDestinationRefinement(
}
}
-export async function isNotDormantRefinement(
+export async function isEmitterNotDormantRefinement(
siret: string | null | undefined,
ctx: RefinementCtx
) {
@@ -171,6 +192,7 @@ export async function isNotDormantRefinement(
if (company?.isDormantSince) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
+ path: pathFromCompanyRole(CompanyRole.Emitter),
message: `L'établissement avec le SIRET ${siret} est en sommeil sur Trackdéchets, il n'est pas possible de le mentionner sur un bordereau`
});
}
@@ -205,3 +227,27 @@ export function destinationOperationModeRefinement(
}
}
}
+
+export async function isEcoOrganismeRefinement(
+ siret: string | null | undefined,
+ bsdType: BsdType,
+ ctx: RefinementCtx
+) {
+ const ecoOrganisme = await refineAndGetEcoOrganisme(siret, ctx);
+
+ if (ecoOrganisme) {
+ if (bsdType === BsdType.BSDA && !ecoOrganisme.handleBsda) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ path: pathFromCompanyRole(CompanyRole.EcoOrganisme),
+ message: `L'éco-organisme avec le SIRET ${siret} n'est pas autorisé à apparaitre sur un BSDA`
+ });
+ } else if (bsdType === BsdType.BSVHU && !ecoOrganisme.handleBsvhu) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ path: pathFromCompanyRole(CompanyRole.EcoOrganisme),
+ message: `L'éco-organisme avec le SIRET ${siret} n'est pas autorisé à apparaitre sur un BSVHU`
+ });
+ }
+ }
+}
diff --git a/back/src/common/validation/zod/schema.ts b/back/src/common/validation/zod/schema.ts
index b853a23e27..35510c29e5 100644
--- a/back/src/common/validation/zod/schema.ts
+++ b/back/src/common/validation/zod/schema.ts
@@ -22,7 +22,7 @@ export const pathFromCompanyRole = (companyRole?: CompanyRole): string[] => {
case CompanyRole.Destination:
return ["destination", "company", "siret"];
case CompanyRole.EcoOrganisme:
- return ["ecoOrganisme", "company", "siret"];
+ return ["ecoOrganisme", "siret"];
case CompanyRole.Broker:
return ["broker", "company", "siret"];
case CompanyRole.Worker:
diff --git a/back/src/companies/sirenify.ts b/back/src/companies/sirenify.ts
index cce4905734..92fdb87777 100644
--- a/back/src/companies/sirenify.ts
+++ b/back/src/companies/sirenify.ts
@@ -140,41 +140,47 @@ export function nextBuildSirenify(
// check if we found a corresponding companySearchResult based on siret
const companySearchResults = await Promise.all(
- accessors.map(({ siret, skip }) =>
- !skip && siret ? searchCompanyFailFast(siret) : null
- )
+ accessors.map(({ siret, skip }) => {
+ if (skip || !siret) {
+ return null;
+ }
+ return searchCompanyFailFast(siret);
+ })
);
// make a copy to avoid mutating initial data
const sirenifiedInput = { ...input };
for (const [idx, companySearchResult] of companySearchResults.entries()) {
+ const { setter } = accessors[idx];
+ if (!companySearchResult) {
+ continue;
+ }
+ const company = companySearchResult as CompanySearchResult;
if (
- !companySearchResult ||
- companySearchResult.statutDiffusionEtablissement ===
- ("P" as StatutDiffusionEtablissement)
- )
+ company.statutDiffusionEtablissement ===
+ ("P" as StatutDiffusionEtablissement)
+ ) {
continue;
- if (companySearchResult.etatAdministratif === "F") {
+ }
+ if (company.etatAdministratif === "F") {
throw new UserInputError(
- `L'établissement ${companySearchResult.siret} est fermé selon le répertoire SIRENE`
+ `L'établissement ${company.siret} est fermé selon le répertoire SIRENE`
);
}
- if (companySearchResult.isDormant) {
+ if (company.isDormant) {
throw new UserInputError(
- `L'établissement ${companySearchResult.siret} est en sommeil sur Trackdéchets. Il n'est pas possible de le mentionner dans un BSD.`
+ `L'établissement ${company.siret} est en sommeil sur Trackdéchets. Il n'est pas possible de le mentionner dans un BSD.`
);
}
- const { setter } = accessors[idx];
-
setter(sirenifiedInput, {
- name: companySearchResult.name,
- address: companySearchResult.address,
- city: companySearchResult.addressCity,
- postalCode: companySearchResult.addressPostalCode,
- street: companySearchResult.addressVoie
+ name: company.name,
+ address: company.address,
+ city: company.addressCity,
+ postalCode: company.addressPostalCode,
+ street: company.addressVoie
});
}
diff --git a/back/src/companies/typeDefs/company.objects.graphql b/back/src/companies/typeDefs/company.objects.graphql
index bb52547b40..6fce74cd92 100644
--- a/back/src/companies/typeDefs/company.objects.graphql
+++ b/back/src/companies/typeDefs/company.objects.graphql
@@ -496,6 +496,7 @@ type EcoOrganisme {
handleBsdasri: Boolean
handleBsda: Boolean
+ handleBsvhu: Boolean
}
"""
diff --git a/back/src/forms/sirenify.ts b/back/src/forms/sirenify.ts
index 92d98d0f48..c62846e064 100644
--- a/back/src/forms/sirenify.ts
+++ b/back/src/forms/sirenify.ts
@@ -1,5 +1,8 @@
import { Prisma } from "@prisma/client";
-import buildSirenify, { nextBuildSirenify } from "../companies/sirenify";
+import buildSirenify, {
+ nextBuildSirenify,
+ NextCompanyInputAccessor
+} from "../companies/sirenify";
import {
CompanyInput,
CreateFormInput,
@@ -127,7 +130,7 @@ export const sirenifyTransporterInput = buildSirenify(
const formCreateInputAccessors = (
formCreateInput: Prisma.FormCreateInput,
sealedFields: string[] = [] // Tranformations should not be run on sealed fields
-) => [
+): NextCompanyInputAccessor[] => [
{
siret: formCreateInput?.emitterCompanySiret,
skip: sealedFields.includes("emitterCompanySiret"),
@@ -164,7 +167,9 @@ const formCreateInputAccessors = (
siret: formCreateInput?.ecoOrganismeSiret,
skip: sealedFields.includes("ecoOrganismeSiret"),
setter: (formCreateInput, companyInput: CompanyInput) => {
- formCreateInput.ecoOrganismeName = companyInput.name;
+ if (companyInput.name) {
+ formCreateInput.ecoOrganismeName = companyInput.name;
+ }
}
},
...(
@@ -194,10 +199,14 @@ const formCreateInputAccessors = (
)?.transporterCompanySiret ||
sealedFields.includes("transporterCompanySiret"),
setter: (formCreateInput, companyInput: CompanyInput) => {
- formCreateInput.transporters.create.transporterCompanyName =
- companyInput.name;
- formCreateInput.transporters.create.transporterCompanyAddress =
- companyInput.address;
+ (
+ formCreateInput.transporters
+ ?.create as Prisma.BsddTransporterCreateWithoutFormInput
+ ).transporterCompanyName = companyInput.name;
+ (
+ formCreateInput.transporters
+ ?.create as Prisma.BsddTransporterCreateWithoutFormInput
+ ).transporterCompanyAddress = companyInput.address;
}
}
];
diff --git a/libs/back/object-creator/.eslintrc.json b/libs/back/object-creator/.eslintrc.json
new file mode 100644
index 0000000000..3456be9b90
--- /dev/null
+++ b/libs/back/object-creator/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+ "extends": ["../../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.ts", "*.tsx"],
+ "rules": {}
+ },
+ {
+ "files": ["*.js", "*.jsx"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/libs/back/object-creator/project.json b/libs/back/object-creator/project.json
new file mode 100644
index 0000000000..48f86d059a
--- /dev/null
+++ b/libs/back/object-creator/project.json
@@ -0,0 +1,54 @@
+{
+ "name": "object-creator",
+ "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+ "sourceRoot": "libs/back/object-creator/src",
+ "projectType": "application",
+ "targets": {
+ "build": {
+ "executor": "@nx/esbuild:esbuild",
+ "outputs": ["{options.outputPath}"],
+ "defaultConfiguration": "production",
+ "options": {
+ "platform": "node",
+ "outputPath": "dist/libs/back/object-creator",
+ "format": ["cjs"],
+ "bundle": false,
+ "main": "libs/back/object-creator/src/main.ts",
+ "tsConfig": "libs/back/object-creator/tsconfig.app.json",
+ "assets": ["libs/back/object-creator/src/assets"],
+ "generatePackageJson": true,
+ "esbuildOptions": {
+ "sourcemap": true,
+ "outExtension": {
+ ".js": ".js"
+ }
+ }
+ },
+ "configurations": {
+ "development": {},
+ "production": {
+ "esbuildOptions": {
+ "sourcemap": false,
+ "outExtension": {
+ ".js": ".js"
+ }
+ }
+ }
+ }
+ },
+ "run": {
+ "executor": "@nx/js:node",
+ "defaultConfiguration": "development",
+ "options": {
+ "buildTarget": "object-creator:build",
+ "watch": false
+ },
+ "configurations": {
+ "development": {
+ "buildTarget": "object-creator:build:development"
+ }
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/libs/back/object-creator/src/main.ts b/libs/back/object-creator/src/main.ts
new file mode 100644
index 0000000000..d8cd53a8e9
--- /dev/null
+++ b/libs/back/object-creator/src/main.ts
@@ -0,0 +1,54 @@
+import { unescape } from "node:querystring";
+import objects from "./objects";
+import { PrismaClient } from "@prisma/client";
+
+const { DATABASE_URL } = process.env;
+
+/*
+ Database clients init
+*/
+
+if (!DATABASE_URL) {
+ throw new Error("DATABASE_URL is not defined");
+}
+
+function getDbUrlWithSchema(rawDatabaseUrl: string) {
+ try {
+ const dbUrl = new URL(rawDatabaseUrl);
+ dbUrl.searchParams.set("schema", "default$default");
+
+ return unescape(dbUrl.href); // unescape needed because of the `$`
+ } catch (err) {
+ return "";
+ }
+}
+
+const prisma = new PrismaClient({
+ datasources: {
+ db: { url: getDbUrlWithSchema(DATABASE_URL) }
+ },
+ log: []
+});
+
+/*
+ The main Run method
+*/
+const run = async () => {
+ for (let index = 0; index < objects.length; index++) {
+ try {
+ const newObj = objects[index];
+ await prisma[newObj.type].create({
+ data: newObj.object
+ });
+ console.log(`saved object ${index + 1}`);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ console.log(
+ "ALL DONE ! remember to reindex to elastic if needed ( > npx nx run back:reindex-all-bsds-bulk -- -f )"
+ );
+};
+
+run();
diff --git a/libs/back/object-creator/src/objects.ts b/libs/back/object-creator/src/objects.ts
new file mode 100644
index 0000000000..a42bc99a84
--- /dev/null
+++ b/libs/back/object-creator/src/objects.ts
@@ -0,0 +1,26 @@
+import { PrismaClient, Prisma } from "@prisma/client";
+
+type DataType = Prisma.Args<
+ PrismaClient[M],
+ "create"
+>["data"];
+
+type CreationObject = {
+ type: M;
+ object: DataType;
+};
+const objects = [
+ {
+ type: "ecoOrganisme",
+ object: {
+ siret: "00000000000013",
+ name: "Mon éco-organisme",
+ address: "12 RUE DES PINSONS 75012 PARIS",
+ handleBsdasri: false,
+ handleBsda: false,
+ handleBsvhu: true
+ }
+ } as CreationObject<"ecoOrganisme">
+];
+
+export default objects;
diff --git a/libs/back/object-creator/tsconfig.app.json b/libs/back/object-creator/tsconfig.app.json
new file mode 100644
index 0000000000..762205a8de
--- /dev/null
+++ b/libs/back/object-creator/tsconfig.app.json
@@ -0,0 +1,9 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../../dist/out-tsc",
+ "module": "commonjs",
+ "types": ["node"]
+ },
+ "include": ["src/**/*.ts"]
+}
diff --git a/libs/back/object-creator/tsconfig.json b/libs/back/object-creator/tsconfig.json
new file mode 100644
index 0000000000..089e304e98
--- /dev/null
+++ b/libs/back/object-creator/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json"
+ }
+ ],
+ "compilerOptions": {
+ "esModuleInterop": true,
+ "noErrorTruncation": true
+ }
+}
diff --git a/libs/back/prisma/src/migrations/20240924172106_bsvhu_ecoorganisme/migration.sql b/libs/back/prisma/src/migrations/20240924172106_bsvhu_ecoorganisme/migration.sql
new file mode 100644
index 0000000000..5b431af16e
--- /dev/null
+++ b/libs/back/prisma/src/migrations/20240924172106_bsvhu_ecoorganisme/migration.sql
@@ -0,0 +1,9 @@
+-- AlterTable
+ALTER TABLE "Bsvhu" ADD COLUMN "ecoOrganismeName" TEXT,
+ADD COLUMN "ecoOrganismeSiret" TEXT;
+
+-- CreateIndex
+CREATE INDEX "_BsdaEcoOrganismeSiretIdx" ON "Bsda"("ecoOrganismeSiret");
+
+-- CreateIndex
+CREATE INDEX "_BsvhuEcoOrganismeSiretIdx" ON "Bsvhu"("ecoOrganismeSiret");
diff --git a/libs/back/prisma/src/migrations/20240924183924_ecoorganisme_handle_bsvhu/migration.sql b/libs/back/prisma/src/migrations/20240924183924_ecoorganisme_handle_bsvhu/migration.sql
new file mode 100644
index 0000000000..acb15efba7
--- /dev/null
+++ b/libs/back/prisma/src/migrations/20240924183924_ecoorganisme_handle_bsvhu/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "EcoOrganisme" ADD COLUMN "handleBsvhu" BOOLEAN NOT NULL DEFAULT false;
diff --git a/libs/back/prisma/src/schema.prisma b/libs/back/prisma/src/schema.prisma
index 81a46eda36..89c5e6859a 100644
--- a/libs/back/prisma/src/schema.prisma
+++ b/libs/back/prisma/src/schema.prisma
@@ -392,6 +392,7 @@ model EcoOrganisme {
address String
handleBsdasri Boolean @default(false)
handleBsda Boolean @default(false)
+ handleBsvhu Boolean @default(false)
}
// Permet de faire le lien entre un bordereau "initial" et le ou
@@ -422,14 +423,14 @@ model BsddFinalOperation {
}
model Form {
- id String @id @default(cuid()) @db.VarChar(30)
- rowNumber Int @unique(map: "Form_rowNumber_ukey") @default(autoincrement())
- createdAt DateTime @default(now()) @db.Timestamptz(6)
- updatedAt DateTime @updatedAt @db.Timestamptz(6)
- readableId String @unique(map: "Form.readableId._UNIQUE")
+ id String @id @default(cuid()) @db.VarChar(30)
+ rowNumber Int @unique(map: "Form_rowNumber_ukey") @default(autoincrement())
+ createdAt DateTime @default(now()) @db.Timestamptz(6)
+ updatedAt DateTime @updatedAt @db.Timestamptz(6)
+ readableId String @unique(map: "Form.readableId._UNIQUE")
customId String?
- isDeleted Boolean? @default(false)
- status Status @default(DRAFT)
+ isDeleted Boolean? @default(false)
+ status Status @default(DRAFT)
emitterType EmitterType?
emitterPickupSite String?
emitterCompanyName String?
@@ -443,8 +444,8 @@ model Form {
emitterWorkSiteCity String?
emitterWorkSitePostalCode String?
emitterWorkSiteInfos String?
- emitterIsPrivateIndividual Boolean? @default(false)
- emitterIsForeignShip Boolean? @default(false)
+ emitterIsPrivateIndividual Boolean? @default(false)
+ emitterIsForeignShip Boolean? @default(false)
emitterCompanyOmiNumber String?
recipientCap String?
recipientProcessingOperation String?
@@ -454,18 +455,18 @@ model Form {
recipientCompanyContact String?
recipientCompanyPhone String?
recipientCompanyMail String?
- recipientIsTempStorage Boolean? @default(false)
+ recipientIsTempStorage Boolean? @default(false)
wasteDetailsCode String?
wasteDetailsName String?
wasteDetailsOnuCode String?
- wasteDetailsQuantity Decimal? @db.Decimal(65, 30)
+ wasteDetailsQuantity Decimal? @db.Decimal(65, 30)
wasteDetailsQuantityType QuantityType?
wasteDetailsConsistence Consistence?
- wasteDetailsPackagingInfos Json @default("[]")
- wasteDetailsPop Boolean @default(false)
+ wasteDetailsPackagingInfos Json @default("[]")
+ wasteDetailsPop Boolean @default(false)
wasteDetailsSampleNumber String?
- wasteDetailsIsDangerous Boolean @default(false)
- wasteDetailsParcelNumbers Json? @default("[]")
+ wasteDetailsIsDangerous Boolean @default(false)
+ wasteDetailsParcelNumbers Json? @default("[]")
wasteDetailsAnalysisReferences String[]
wasteDetailsLandIdentifiers String[]
traderCompanyName String?
@@ -476,7 +477,7 @@ model Form {
traderCompanyMail String?
traderReceipt String?
traderDepartment String?
- traderValidityLimit DateTime? @db.Timestamptz(6)
+ traderValidityLimit DateTime? @db.Timestamptz(6)
ecoOrganismeName String?
ecoOrganismeSiret String?
brokerCompanyName String?
@@ -487,7 +488,7 @@ model Form {
brokerCompanyMail String?
brokerReceipt String?
brokerDepartment String?
- brokerValidityLimit DateTime? @db.Timestamptz(6)
+ brokerValidityLimit DateTime? @db.Timestamptz(6)
nextDestinationProcessingOperation String?
nextDestinationCompanyName String?
nextDestinationCompanySiret String?
@@ -496,31 +497,31 @@ model Form {
nextDestinationCompanyPhone String?
nextDestinationCompanyMail String?
nextDestinationCompanyCountry String?
- nextDestinationCompanyVatNumber String? @db.VarChar(30)
+ nextDestinationCompanyVatNumber String? @db.VarChar(30)
nextDestinationNotificationNumber String?
nextDestinationCompanyExtraEuropeanId String?
nextTransporterOrgId String?
- emittedAt DateTime? @db.Timestamptz(6)
+ emittedAt DateTime? @db.Timestamptz(6)
emittedBy String?
emittedByEcoOrganisme Boolean?
- takenOverAt DateTime? @db.Timestamptz(6)
+ takenOverAt DateTime? @db.Timestamptz(6)
takenOverBy String?
- signedAt DateTime? @db.Timestamptz(6)
+ signedAt DateTime? @db.Timestamptz(6)
signedBy String?
- isImportedFromPaper Boolean @default(false)
+ isImportedFromPaper Boolean @default(false)
quantityReceivedType QuantityType?
signedByTransporter Boolean?
- sentAt DateTime? @db.Timestamptz(6)
+ sentAt DateTime? @db.Timestamptz(6)
sentBy String?
- isAccepted Boolean? @default(false)
+ isAccepted Boolean? @default(false)
wasteAcceptationStatus WasteAcceptationStatus?
wasteRefusalReason String?
receivedBy String?
- receivedAt DateTime? @db.Timestamptz(6)
- quantityReceived Decimal? @db.Decimal(65, 30)
- quantityRefused Decimal? @db.Decimal(65, 30)
+ receivedAt DateTime? @db.Timestamptz(6)
+ quantityReceived Decimal? @db.Decimal(65, 30)
+ quantityRefused Decimal? @db.Decimal(65, 30)
processedBy String?
- processedAt DateTime? @db.Timestamptz(6)
+ processedAt DateTime? @db.Timestamptz(6)
processingOperationDone String?
processingOperationDescription String?
noTraceability Boolean?
@@ -1064,6 +1065,9 @@ model Bsvhu {
transporterTransportPlates String[]
transporterRecepisseIsExempted Boolean?
+ ecoOrganismeName String?
+ ecoOrganismeSiret String?
+
intermediaries IntermediaryBsvhuAssociation[]
// Denormalized fields, storing sirets to speed up queries and avoid expensive joins
@@ -1075,6 +1079,7 @@ model Bsvhu {
@@index([destinationCompanySiret], map: "_BsvhuDestinationCompanySiretIdx")
@@index([transporterCompanySiret], map: "_BsvhuTransporterCompanySiretIdx")
@@index([transporterCompanyVatNumber], map: "_BsvhuTransporterCompanyVatNumberIdx")
+ @@index([ecoOrganismeSiret], map: "_BsvhuEcoOrganismeSiretIdx")
@@index([intermediariesOrgIds], map: "_BsvhuIntermediariesOrgIdsIdx", type: Gin)
@@index([status], map: "_BsvhuStatusIdx")
@@index([updatedAt], map: "_BsvhuUpdatedAtIdx")
@@ -1645,6 +1650,7 @@ model Bsda {
@@index([brokerCompanySiret], map: "_BsdaBrokerCompanySiretIdx")
@@index([destinationCompanySiret], map: "_BsdaDestinationCompanySiretIdx")
@@index([workerCompanySiret], map: "_BsdaWorkerCompanySiretIdx")
+ @@index([ecoOrganismeSiret], map: "_BsdaEcoOrganismeSiretIdx")
@@index([destinationOperationNextDestinationCompanySiret], map: "_BsdaDestinationOperationNextDestinationCompanySiretIdx")
@@index([status], map: "_BsdaStatusIdx")
@@index([groupedInId], map: "_BsdaGroupedInIdIdx")
@@ -2141,4 +2147,4 @@ enum EmptyReturnADR {
EMPTY_RETURN_NOT_WASHED
EMPTY_VEHICLE
EMPTY_CITERNE
-}
\ No newline at end of file
+}