Skip to content

Commit

Permalink
[TRA-15674] Sortir Conditionné pour pipeline de la liste des conditio…
Browse files Browse the repository at this point in the history
…nnements (#3980)
  • Loading branch information
benoitguigal authored Mar 4, 2025
2 parents 279c9f3 + dfb565e commit 9d6db4e
Show file tree
Hide file tree
Showing 38 changed files with 529 additions and 255 deletions.
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ et le projet suit un schéma de versionning inspiré de [Calendar Versioning](ht
- Ajout de l'export du registre sortant V2 [PR 3976](https://github.com/MTES-MCT/trackdechets/pull/3976)
- Ajout d'un paramètre pour les établissements souhaitant pousser automatiquement leurs BSDND dans leurs déclarations [PR3988](https://github.com/MTES-MCT/trackdechets/pull/3988)

#### :nail_care: Breaking Change

- BSDD - Le type de conditionnement PIPELINE est déprécié sur l'enum [Packagings](https://developers.trackdechets.beta.gouv.fr/reference/api-reference/bsdd/enums#packagings). Il est nécessaire de renseigner un nouveau champ booléen `isDirectSupply` sur [FormInput](https://developers.trackdechets.beta.gouv.fr/reference/api-reference/bsdd/inputObjects#forminput) pouvant correspondre à un acheminement par pipeline ou par convoyeur. Aucun conditionnement ne devra être renseigné en cas d'acheminement direct, c'est à dire que lorsque `isDirectSupply` est true, le champ packagingsInfos sur [FormInput](https://developers.trackdechets.beta.gouv.fr/reference/api-reference/bsdd/inputObjects#forminput) devra valoir null ou []. Les données existantes seront migrées de sorte qu'il vous faudra prendre en compte en lecture le nouveau champ `isDirectSupply` sur l'objet [Form](https://developers.trackdechets.beta.gouv.fr/reference/api-reference/bsdd/objects#form). Nous continuerons d'accepter la valeur `PIPELINE` comme type de packagings en écriture mais les données entrantes seront automatiquement converties pour s'adapter au nouveau format de données.

#### :nail_care: Améliorations

- Exports registres V2 : Modale d'export et petites améliorations d'UX [PR 3953](https://github.com/MTES-MCT/trackdechets/pull/3953)
Expand Down
3 changes: 2 additions & 1 deletion back/src/bsds/resolvers/mutations/utils/clone.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,8 @@ export const cloneBsdd = async (
wasteDetailsQuantity: bsdd.wasteDetailsQuantity,
wasteDetailsQuantityType: bsdd.wasteDetailsQuantityType,
wasteDetailsSampleNumber: bsdd.wasteDetailsSampleNumber,
wasteRefusalReason: bsdd.wasteRefusalReason
wasteRefusalReason: bsdd.wasteRefusalReason,
isDirectSupply: bsdd.isDirectSupply
};

const newBsdd = await create(newBsddCreateInput);
Expand Down
3 changes: 3 additions & 0 deletions back/src/common/typeDefs/common.enums.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ enum TransportMode {
SEA
"Autre (utilisé avec Packaging = PIPELINE par exemple)"
OTHER
@deprecated(
reason: "Utiliser `isDirectSupply=true` sans transporteur en cas d'acheminement direct par pipeline ou convoyeur"
)
"Non renseigné. Cas particulier pour des données importés"
UNKNOWN
}
Expand Down
3 changes: 3 additions & 0 deletions back/src/forms/__tests__/compat.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe("simpleFormToBsdd", () => {
isDeleted: form.isDeleted,
isDraft: false,
status: form.status,
isDirectSupply: false,
wasteCode: form.wasteDetailsCode,
wasteIsDangerous: true,
wasteDetailsLandIdentifiers: form.wasteDetailsLandIdentifiers,
Expand Down Expand Up @@ -454,6 +455,7 @@ describe("simpleFormToBsdd", () => {
nextDestinationNotificationNumber: null,
nextDestinationProcessingOperation: null,
status: fullForwardedInForm.status,
isDirectSupply: false,
wasteCode: fullForwardedInForm.wasteDetailsCode,
wasteIsDangerous: true,
wasteDetailsLandIdentifiers:
Expand Down Expand Up @@ -653,6 +655,7 @@ describe("simpleFormToBsdd", () => {
isDeleted: form.isDeleted,
isDraft: form.status === "DRAFT",
status: form.status,
isDirectSupply: false,
wasteCode: form.wasteDetailsCode,
wasteIsDangerous: true,
wasteDetailsLandIdentifiers: form.wasteDetailsLandIdentifiers,
Expand Down
1 change: 1 addition & 0 deletions back/src/forms/__tests__/form-converter.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe("expandFormFromDb", () => {
readableId: form.readableId,
customId: null,
isImportedFromPaper: false,
isDirectSupply: false,
metadata: undefined,
citerneNotWashedOutReason: null,
hasCiterneBeenWashedOut: null,
Expand Down
32 changes: 21 additions & 11 deletions back/src/forms/__tests__/validation.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1739,28 +1739,38 @@ describe("draftFormSchema", () => {
expect(isValid).toEqual(true);
});

it("packaging PIPELINE can be set without any other details", async () => {
it("isDirectSupply=true can be set without any other details", async () => {
const isValid = await draftFormSchema.isValid({
wasteDetailsPackagingInfos: [
{ type: "PIPELINE", numero: null, weight: null, volume: null }
]
isDirectSupply: true,
wasteDetailsPackagingInfos: []
});

expect(isValid).toEqual(true);
});

it("packaging PIPELINE cannot be set with any other packaging", async () => {
it("packaging PIPELINE should not be valid", async () => {
const validateFn = () =>
draftFormSchema.validate({
wasteDetailsPackagingInfos: [
{ type: "PIPELINE", numero: null, weight: null, volume: null }
]
});

await expect(validateFn()).rejects.toThrow(
"Le type de conditionnement PIPELINE n'est pas valide"
);
});

it("isDirectSupply=true cannot be set with any packaging", async () => {
const isValid = await draftFormSchema.isValid({
wasteDetailsPackagingInfos: [
{ type: "PIPELINE", other: null, quantity: null },
{ type: "FUT", other: null, quantity: 1 }
]
isDirectSupply: true,
wasteDetailsPackagingInfos: [{ type: "FUT", other: null, quantity: 1 }]
});

expect(isValid).toEqual(false);
});

it("packaging PIPELINE cannot be set with a transporter", async () => {
it("isDirectSupply=true cannot be set with a transporter", async () => {
const validateFn = () =>
draftFormSchema.validate({
wasteDetailsPackagingInfos: [
Expand All @@ -1770,7 +1780,7 @@ describe("draftFormSchema", () => {
});

await expect(validateFn()).rejects.toThrow(
"Vous ne devez pas spécifier de transporteur dans le cas d'un transport par pipeline"
"Vous ne devez pas spécifier de transporteur dans le cas d'un acheminement direct par pipeline ou convoyeur"
);
});

Expand Down
1 change: 1 addition & 0 deletions back/src/forms/compat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function simpleFormToBsdd(
isDeleted: Boolean(form.isDeleted),
isDraft: form.status == Status.DRAFT,
status: form.status,
isDirectSupply: form.isDirectSupply,
forwardedInId: form.forwardedInId,
wasteCode: form.wasteDetailsCode,
wasteDescription: form.wasteDetailsName,
Expand Down
8 changes: 8 additions & 0 deletions back/src/forms/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { getFirstTransporterSync } from "./database";
import { FormForElastic } from "./elastic";
import { extractPostalCode } from "../common/addresses";
import { bsddWasteQuantities } from "./helpers/bsddWasteQuantities";
import { isDefined } from "../common/helpers";

function flattenDestinationInput(input: {
destination?: DestinationInput | null;
Expand Down Expand Up @@ -427,6 +428,7 @@ export function flattenFormInput(
formInput: Pick<
FormInput,
| "customId"
| "isDirectSupply"
| "emitter"
| "recipient"
| "wasteDetails"
Expand All @@ -437,6 +439,11 @@ export function flattenFormInput(
): Partial<Omit<Prisma.FormCreateInput, "temporaryStorageDetail">> {
return safeInput({
customId: formInput.customId,
// Si `isDirectSupply` est null ou undefined, on omet le champ
// et on laisse le soin à la DB de mettre une valeur par défaut
...(isDefined(formInput.isDirectSupply)
? { isDirectSupply: formInput.isDirectSupply! }
: {}),
...flattenEmitterInput(formInput),
...flattenRecipientInput(formInput),
...flattenWasteDetailsInput(formInput),
Expand Down Expand Up @@ -667,6 +674,7 @@ export function expandFormFromDb(
.map(segment => expandTransportSegmentFromDb(segment)),
transporter: transporter ? expandTransporterFromDb(transporter) : null,
transporters: transporters.map(t => expandTransporterFromDb(t)!),
isDirectSupply: form.isDirectSupply,
recipient: nullIfNoValues<Recipient>({
cap: form.recipientCap,
processingOperation: form.recipientProcessingOperation,
Expand Down
1 change: 1 addition & 0 deletions back/src/forms/edition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export const editionRules: {
wasteDetailsOnuCode: "EMISSION",
wasteDetailsIsSubjectToADR: "EMISSION",
wasteDetailsNonRoadRegulationMention: "EMISSION",
isDirectSupply: "EMISSION",
wasteDetailsPackagingInfos: "EMISSION",
wasteDetailsQuantity: "EMISSION",
wasteDetailsQuantityType: "EMISSION",
Expand Down
16 changes: 12 additions & 4 deletions back/src/forms/pdf/components/BsddPdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,13 @@ export function BsddPdf({
<p>
<strong>4. Conditionnement</strong>
</p>
<PackagingInfosTable
packagingInfos={form.wasteDetails?.packagingInfos ?? []}
/>
{form.isDirectSupply ? (
<p>Acheminement direct par pipeline ou convoyeur</p>
) : (
<PackagingInfosTable
packagingInfos={form.wasteDetails?.packagingInfos ?? []}
/>
)}
</div>

<div className="BoxCol">
Expand Down Expand Up @@ -792,7 +796,11 @@ export function BsddPdf({
<p>
<strong>8. Collecteur-Transporteur</strong>
</p>
<TransporterFormCompanyFields {...form} />
{form.isDirectSupply ? (
<p>Acheminement direct par pipeline ou convoyeur</p>
) : (
<TransporterFormCompanyFields {...form} />
)}
</div>
</div>

Expand Down
4 changes: 2 additions & 2 deletions back/src/forms/registryV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export const toIncomingWasteV2 = (
brokerCompanySiret: bsdd.brokerCompanySiret,
brokerCompanyMail: bsdd.brokerCompanyMail,
brokerRecepisseNumber: bsdd.brokerRecepisseNumber,
isDirectSupply: false,
isDirectSupply: bsdd.isDirectSupply,
transporter1CompanyName: bsdd.transporterCompanyName,
transporter1CompanyGivenName: null,
transporter1CompanySiret: bsdd.transporterCompanySiret?.length
Expand Down Expand Up @@ -526,7 +526,7 @@ export const toOutgoingWasteV2 = (
traderCompanyName: bsdd.traderCompanyName,
traderCompanyMail: bsdd.traderCompanyMail,
traderRecepisseNumber: bsdd.traderRecepisseNumber,
isDirectSupply: false,
isDirectSupply: bsdd.isDirectSupply,
transporter1CompanySiret: bsdd.transporterCompanySiret?.length
? bsdd.transporterCompanySiret
: bsdd.transporterCompanyVatNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
CreateFormInput,
Mutation,
MutationCreateFormArgs,
Packagings,
ParcelNumber
} from "@td/codegen-back";
import {
Expand Down Expand Up @@ -46,6 +47,7 @@ const CREATE_FORM = `
mutation CreateForm($createFormInput: CreateFormInput!) {
createForm(createFormInput: $createFormInput) {
id
isDirectSupply
recipient {
company {
siret
Expand Down Expand Up @@ -1495,68 +1497,74 @@ describe("Mutation.createForm", () => {
]);
});

it("should erase transporter infos in a form with PIPELINE packaging", async () => {
it("should throw validation error when isDirectSypply=true and transporters list is not empty", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
const transporter = await companyFactory();

const createFormInput = {
emitter: {
company: {
siret: company.siret
}
},
wasteDetails: {
packagingInfos: [{ type: "PIPELINE", quantity: 1 }]
},
isDirectSupply: true,
transporter: {
company: { siret: siretify(1) }
company: { siret: transporter.siret }
}
};
const { mutate } = makeClient(user);
const { data } = await mutate<Pick<Mutation, "createForm">>(CREATE_FORM, {
const { errors } = await mutate<
Pick<Mutation, "createForm">,
MutationCreateFormArgs
>(CREATE_FORM, {
variables: { createFormInput }
});

expect(data.createForm.transporter).toMatchObject({
company: null,
mode: "OTHER"
});
expect(errors).toEqual([
expect.objectContaining({
message:
"Vous ne devez pas spécifier de transporteur dans le cas d'un acheminement direct par pipeline ou convoyeur"
})
]);
});

it("should force transporter mode to OTHER with PIPELINE packaging", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
it(
"[deprecated] should empty transporters list and packagings" +
" when packagings input contain PIPELINE",
async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
const transporter = await companyFactory();

const createFormInput = {
emitter: {
company: {
siret: company.siret
}
},
wasteDetails: {
packagingInfos: [{ type: "PIPELINE", quantity: 1 }]
},
transporter: {
mode: "ROAD"
}
};
const { mutate } = makeClient(user);
const { data } = await mutate<Pick<Mutation, "createForm">>(CREATE_FORM, {
variables: { createFormInput }
});
expect(data.createForm).toMatchObject({
transporter: {
mode: "OTHER"
},
wasteDetails: {
packagingInfos: [
{
type: "PIPELINE",
quantity: 1,
other: null
const createFormInput = {
emitter: {
company: {
siret: company.siret
}
]
}
});
});
},
wasteDetails: {
packagingInfos: [{ type: "PIPELINE" as Packagings, quantity: 1 }]
},
transporter: {
company: { siret: transporter.siret }
}
};
const { mutate } = makeClient(user);
const { data } = await mutate<
Pick<Mutation, "createForm">,
MutationCreateFormArgs
>(CREATE_FORM, {
variables: { createFormInput }
});

expect(data.createForm).toMatchObject({
isDirectSupply: true,
wasteDetails: {
packagingInfos: []
},
transporter: null
});
}
);

it("should error if any other packaging type is sent with the PIPELINE type", async () => {
const { user, company } = await userWithCompanyFactory("MEMBER");
Expand All @@ -1582,7 +1590,7 @@ describe("Mutation.createForm", () => {
expect(errors).toEqual([
expect.objectContaining({
message:
"wasteDetailsPackagingInfos ne peut pas à la fois contenir 1 citerne, 1 pipeline ou 1 benne et un autre conditionnement.",
"Aucun conditionnement ne doit être renseigné dans le cadre d'un acheminement direct par pipeline ou convoyeur",
extensions: expect.objectContaining({
code: ErrorCode.BAD_USER_INPUT
})
Expand Down
Loading

0 comments on commit 9d6db4e

Please sign in to comment.