Skip to content

Commit

Permalink
Merge pull request #3725 from MTES-MCT/tra-13971/bsdd-restrictions
Browse files Browse the repository at this point in the history
[TRA-13971] Restreindre les TTR et Installations de traitement à être visés sur un BSDD selon leur type de profil
  • Loading branch information
providenz authored Nov 12, 2024
2 parents 99bb25c + ceca7df commit e2a12fa
Show file tree
Hide file tree
Showing 36 changed files with 1,969 additions and 201 deletions.
5 changes: 4 additions & 1 deletion .env.model
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,7 @@ GERICO_API_KEY="***"
# Slug to receive gerico webhooks
GERICO_WEBHOOK_SLUG="/lorem"
# Token to authenticate gerico webhooks
GERICO_WEBHOOK_TOKEN="***"
GERICO_WEBHOOK_TOKEN="***"

# For testing purposes, optional and defaulted to november 2024 release date: "2024-11-13T00:00:00.000Z"
VERIFY_DESTINATION_PROFILES_FOR_BSDD_CREATED_AFTER="2024-10-26:00:00.000Z"
2 changes: 2 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,5 @@ env:
S3_SECRET_ACCESS_KEY: password
S3_REGISTRY_ERRORS_BUCKET: registry-errors-integration
S3_REGISTRY_IMPORTS_BUCKET: registry-imports-integration
VERIFY_DESTINATION_PROFILES_FOR_BSDD_CREATED_AFTER: 2024-10-30T00:00:00.000Z

9 changes: 3 additions & 6 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,22 @@ Les changements importants de Trackdéchets sont documentés dans ce fichier.

Le format est basé sur [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
et le projet suit un schéma de versionning inspiré de [Calendar Versioning](https://calver.org/).
[2024.11.1] 19/11/2024

#### :house: Interne

- Amélioration de l'interface d'admin [PR 3735](https://github.com/MTES-MCT/trackdechets/pull/3735)

# [2024.11.1] 19/11/2024
[2024.11.1] 19/11/2024

#### :boom: Breaking changes

- Le champ "Numéro de notification" est obligatoire lorsque la destination ultérieure renseignée est étrangère [PR 3719](https://github.com/MTES-MCT/trackdechets/pull/3719)
- La présence d'une quantité reçue est requise pour passer du statut SENT à ACCEPTED via la mutation markAsReceived [PR 3720](https://github.com/MTES-MCT/trackdechets/pull/3720)
- Restriction des TTR et Installations de traitement à être visés sur un BSDD selon leur type de profil [PR 3725](https://github.com/MTES-MCT/trackdechets/pull/3725)

#### :bug: Corrections de bugs

- Corrige l'indexation des annexes 1 orphelines et draft [PR 3721](https://github.com/MTES-MCT/trackdechets/pull/3721)

#### :house: Interne

- Amélioration de l'interface d'admin [PR 3735](https://github.com/MTES-MCT/trackdechets/pull/3735)
- Modification de la query controlBsds et fermeture de la query bsds aux comptes gouvernementaux [PR 3270](https://github.com/MTES-MCT/trackdechets/pull/3270)

# [2024.10.1] 22/10/2024
Expand Down
50 changes: 39 additions & 11 deletions back/src/__tests__/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
Prisma,
Company,
TransportMode,
UserNotification
UserNotification,
WasteProcessorType,
CollectorType,
CompanyType
} from "@prisma/client";
import { prisma } from "@td/prisma";
import { hashToken } from "../utils";
Expand Down Expand Up @@ -193,6 +196,9 @@ export const destinationFactory = async (
...companyOpts,
companyTypes: {
set: [CompanyType.WASTEPROCESSOR]
},
wasteProcessorTypes: {
set: [WasteProcessorType.DANGEROUS_WASTES_INCINERATION]
}
}
);
Expand Down Expand Up @@ -414,7 +420,17 @@ export const bsddTransporterFactory = async ({
return transporter;
};

export const upsertBaseSiret = async siret => {
export const upsertBaseSiret = async ({
siret,
companyTypes = ["TRANSPORTER", "WASTEPROCESSOR", "WORKER"],
wasteProcessorTypes = [],
collectorTypes = []
}: {
siret: string;
companyTypes?: CompanyType[];
wasteProcessorTypes?: WasteProcessorType[];
collectorTypes?: CollectorType[];
}) => {
const exists = await prisma.company.findUnique({ where: { siret } });
if (!exists) {
// Using prisma.upsert gives us "Unique constraint failed on the fields: (`siret`)"
Expand All @@ -425,7 +441,13 @@ export const upsertBaseSiret = async siret => {
orgId: siret,
siret,
companyTypes: {
set: ["TRANSPORTER", "WASTEPROCESSOR", "WORKER"]
set: companyTypes
},
wasteProcessorTypes: {
set: wasteProcessorTypes
},
collectorTypes: {
set: collectorTypes
},
name: `company_${siret}`,
securityCode: 1234,
Expand All @@ -450,10 +472,16 @@ export const formFactory = async ({
opt?: Partial<Prisma.FormCreateInput>;
}) => {
// Those sirets are required for the form to be updatable
await upsertBaseSiret(
(formdata.transporters!.create! as any).transporterCompanySiret as any
);
await upsertBaseSiret(formdata.recipientCompanySiret);

await upsertBaseSiret({
siret: (formdata.transporters!.create! as any).transporterCompanySiret
});

// recipient needs appropriate profiles and subprofiles
await upsertBaseSiret({
siret: formdata.recipientCompanySiret!,
wasteProcessorTypes: [WasteProcessorType.DANGEROUS_WASTES_INCINERATION]
});

const ownerCompanies = await getUserCompanies(ownerId);
const ownerOrgIds = ownerCompanies.map(company => company.orgId);
Expand Down Expand Up @@ -513,10 +541,10 @@ export const formWithTempStorageFactory = async ({
opt?: Partial<Prisma.FormCreateInput>;
forwardedInOpts?: Partial<Prisma.FormCreateInput>;
}) => {
await upsertBaseSiret(
(forwardedInData.transporters?.create as any).transporterCompanySiret
);
await upsertBaseSiret(forwardedInData.recipientCompanySiret);
await upsertBaseSiret({
siret: (forwardedInData.transporters?.create as any).transporterCompanySiret
});
await upsertBaseSiret({ siret: forwardedInData.recipientCompanySiret! });

const forwardedCreateInput: Omit<
Prisma.FormCreateInput,
Expand Down
2 changes: 2 additions & 0 deletions back/src/__tests__/testWorkflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ async function testWorkflow(workflow: Workflow) {
for (const workflowCompany of workflow.companies) {
const { user, company } = await userWithCompanyFactory("MEMBER", {
companyTypes: workflowCompany.companyTypes,
wasteProcessorTypes: workflowCompany.wasteProcessorTypes ?? [],
collectorTypes: workflowCompany.collectorTypes ?? [],
...(workflowCompany?.opt || {})
});
if (workflowCompany.companyTypes.includes("ECO_ORGANISME")) {
Expand Down
4 changes: 3 additions & 1 deletion back/src/activity-events/bsdd/__tests__/bsdd.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import makeClient from "../../../__tests__/testClient";
import { getStream } from "../../data";
import { getFirstTransporterSync } from "../../../forms/database";
import { WasteProcessorType, CompanyType } from "@prisma/client";

const CREATE_FORM = `
mutation CreateForm($createFormInput: CreateFormInput!) {
Expand Down Expand Up @@ -55,7 +56,8 @@ describe("ActivityEvent.Bsdd", () => {
const { company: destinationCompany } = await userWithCompanyFactory(
"MEMBER",
{
companyTypes: { set: ["WASTEPROCESSOR", "TRANSPORTER"] }
companyTypes: [CompanyType.WASTEPROCESSOR],
wasteProcessorTypes: [WasteProcessorType.DANGEROUS_WASTES_INCINERATION]
}
);
const transporterCompany = await companyFactory({
Expand Down
12 changes: 6 additions & 6 deletions back/src/bsda/__tests__/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ export const bsdaFactory = async ({
contactPhone: bsdaObject.emitterCompanyPhone ?? undefined,
contactEmail: bsdaObject.emitterCompanyMail ?? undefined
});
await upsertBaseSiret(
(
await upsertBaseSiret({
siret: (
bsdaObject.transporters!
.create! as Prisma.BsdaTransporterCreateWithoutBsdaInput
).transporterCompanySiret // Prisma.BsdaTransporterCreateWithoutBsdaInput[] is wrongly infered
);
await upsertBaseSiret(bsdaObject.destinationCompanySiret);
await upsertBaseSiret(bsdaObject.workerCompanySiret);
).transporterCompanySiret! // Prisma.BsdaTransporterCreateWithoutBsdaInput[] is wrongly infered
});
await upsertBaseSiret({ siret: bsdaObject.destinationCompanySiret! });
await upsertBaseSiret({ siret: bsdaObject.workerCompanySiret! });

const data: Prisma.BsdaCreateInput = {
...bsdaObject,
Expand Down
19 changes: 14 additions & 5 deletions back/src/bsds/resolvers/queries/__tests__/bsds.bsdd.integration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Company, User, UserRole } from "@prisma/client";
import {
Company,
User,
UserRole,
WasteProcessorType,
CompanyType
} from "@prisma/client";
import {
Query,
QueryBsdsArgs,
Expand Down Expand Up @@ -84,17 +90,17 @@ describe("Query.bsds workflow", () => {
beforeAll(async () => {
emitter = await userWithCompanyFactory(UserRole.ADMIN, {
companyTypes: {
set: ["PRODUCER"]
set: [CompanyType.PRODUCER]
}
});
intermediary = await userWithCompanyFactory(UserRole.MEMBER, {
companyTypes: {
set: ["TRANSPORTER"]
set: [CompanyType.TRANSPORTER]
}
});
transporter = await userWithCompanyFactory(UserRole.ADMIN, {
companyTypes: {
set: ["TRANSPORTER"]
set: [CompanyType.TRANSPORTER]
}
});
await transporterReceiptFactory({
Expand All @@ -103,7 +109,10 @@ describe("Query.bsds workflow", () => {

recipient = await userWithCompanyFactory(UserRole.ADMIN, {
companyTypes: {
set: ["WASTEPROCESSOR"]
set: [CompanyType.WASTEPROCESSOR]
},
wasteProcessorTypes: {
set: [WasteProcessorType.DANGEROUS_WASTES_INCINERATION]
}
});
(searchCompany as jest.Mock).mockResolvedValue({
Expand Down
6 changes: 3 additions & 3 deletions back/src/bspaoh/__tests__/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ export const bspaohFactory = async ({
const destinationCompanySiret = siretify(2);
const transporterCompanySiret = siretify(3);

await upsertBaseSiret(emitterCompanySiret);
await upsertBaseSiret(destinationCompanySiret);
await upsertBaseSiret(transporterCompanySiret);
await upsertBaseSiret({ siret: emitterCompanySiret });
await upsertBaseSiret({ siret: destinationCompanySiret });
await upsertBaseSiret({ siret: transporterCompanySiret });

await prisma.company.update({
where: { siret: destinationCompanySiret },
Expand Down
58 changes: 55 additions & 3 deletions back/src/common/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ import {
} from "../companies/validation";
import { CompanyInput } from "../generated/graphql/types";
import { prisma } from "@td/prisma";
import { isForeignVat, isFRVat, isSiret, isVat } from "@td/constants";
import {
isForeignVat,
isFRVat,
isSiret,
isVat,
isDangerous
} from "@td/constants";
import { isBase64 } from "../utils";
import { Decimal } from "decimal.js";

import {
canProcessDangerousWaste,
canProcessNonDangerousWaste
} from "../companies/companyProfilesRules";
// Poids maximum en tonnes tout mode de transport confondu
export const MAX_WEIGHT_TONNES = 50000;

Expand Down Expand Up @@ -176,6 +185,7 @@ type SiretTests = {
role?: "DESTINATION" | "TRANSPORTER" | "WASTE_VEHICLES"
) => yup.TestConfig<string>;
isNotDormant: yup.TestConfig<string>;
destinationHasAppropriateSubProfiles: yup.TestConfig<string>;
};

export const siretConditions: SiretConditions = {
Expand Down Expand Up @@ -214,7 +224,14 @@ export const siretConditions: SiretConditions = {
}
};

const { VERIFY_COMPANY } = process.env;
const { VERIFY_COMPANY, VERIFY_DESTINATION_PROFILES_FOR_BSDD_CREATED_AFTER } =
process.env;

// Date de la MAJ 2024.11.1 qui rend obligatoire certtains sous profils pour traiter les déchets dangereux et non dangereux
const v20241101 = new Date(
VERIFY_DESTINATION_PROFILES_FOR_BSDD_CREATED_AFTER ||
"2024-11-19T00:00:00.000Z"
);

export const siretTests: SiretTests = {
isRegistered: role => ({
Expand Down Expand Up @@ -302,6 +319,41 @@ export const siretTests: SiretTests = {
}
return company.isDormantSince == null;
}
},
destinationHasAppropriateSubProfiles: {
name: "destination-has-appropriate-subprofiles",
message: () =>
"Les autorisations de l'établissement de destination ne semblent pas correspondre à la caractérisation du déchet " +
"renseigné. Merci de bien vouloir procéder à la mise à jour du profil de l'établissement ou modifier le type de " +
"déchet sans quoi le bordereau ne pourra être enregistré.",
test: async (siret, ctx) => {
if (!siret) return true;

// do not run on existing bsdds created before release v20241101
const bsddCreatedAt = ctx.parent.createdAt || new Date(); // new bsd do not have a createdAt yet
const isCreatedAfterV202411011 =
bsddCreatedAt.getTime() - v20241101.getTime() > 0;

if (!isCreatedAfterV202411011) {
return true;
}

const hasDangerousWaste =
isDangerous(ctx.parent.wasteDetailCode) ||
ctx.parent.wasteDetailsPop ||
ctx.parent.wasteDetailsIsDangerous;

const company = await prisma.company.findUnique({
where: { siret }
});
if (company === null) {
return true; // catched by siretTests.isRegistered
}

return hasDangerousWaste
? canProcessDangerousWaste(company)
: canProcessNonDangerousWaste(company);
}
}
};

Expand Down
8 changes: 7 additions & 1 deletion back/src/common/workflow.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ export type Workflow = {
// Longer description of the workflow explaining the traceability use case;
description?: string;
// Name and profile of the companies involved in the workflow
companies: { name: string; companyTypes: string[]; opt?: any }[];
companies: {
name: string;
companyTypes: string[];
wasteProcessorTypes?: string[];
collectorTypes?: string[];
opt?: any;
}[];
// List of steps to be applied to the BSD
steps: WorkflowStep[];
// Mocked context used in the documentation code examples
Expand Down
Loading

0 comments on commit e2a12fa

Please sign in to comment.