From ab8a34465f4c9ad188e668064b5bb75b637b50f3 Mon Sep 17 00:00:00 2001 From: Laurent Paoletti Date: Thu, 9 Jan 2025 16:14:02 +0100 Subject: [PATCH] Allow vhu plates edition from signature modal and dashboard --- back/src/bsvhu/converter.ts | 2 + back/src/bsvhu/typeDefs/bsvhu.inputs.graphql | 2 + back/src/bsvhu/typeDefs/bsvhu.objects.graphql | 2 + back/src/bsvhu/validation/rules.ts | 6 +- back/src/bsvhu/validation/schema.ts | 1 - .../Components/BsdCardList/BsdCardList.tsx | 1 + .../TransporterInfoEditModal.tsx | 33 ++- .../Validation/Bsvhu/SignVhuTransport.tsx | 247 +++++++++++------- front/src/Apps/Dashboard/bsdMapper.ts | 9 +- front/src/Apps/Dashboard/dashboardServices.ts | 1 + .../Apps/common/queries/fragments/bsvhu.ts | 3 + front/src/Pages/Dashboard.tsx | 1 + .../BSVhu/WorkflowAction/SignOperation.tsx | 6 +- 13 files changed, 204 insertions(+), 110 deletions(-) diff --git a/back/src/bsvhu/converter.ts b/back/src/bsvhu/converter.ts index 214b4aedf7..5169f3fc30 100644 --- a/back/src/bsvhu/converter.ts +++ b/back/src/bsvhu/converter.ts @@ -150,6 +150,7 @@ export function expandVhuFormFromDb(form: PrismaVhuForm): GraphqlVhuForm { mail: form.transporterCompanyMail, vatNumber: form.transporterCompanyVatNumber }), + customInfo: form.transporterCustomInfo, recepisse: nullIfNoValues({ number: form.transporterRecepisseNumber, department: form.transporterRecepisseDepartment, @@ -370,6 +371,7 @@ function flattenVhuTransporterInput({ transporterCompanyVatNumber: chain(transporter, t => chain(t.company, c => c.vatNumber) ), + transporterCustomInfo: chain(transporter, t => t.customInfo), transporterRecepisseNumber: chain(transporter, t => chain(t.recepisse, r => r.number) ), diff --git a/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql b/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql index b4e5c67686..64f2fc054b 100644 --- a/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql +++ b/back/src/bsvhu/typeDefs/bsvhu.inputs.graphql @@ -282,6 +282,8 @@ input BsvhuTransporterInput { company: CompanyInput "Récépissé transporteur" recepisse: BsvhuRecepisseInput + "Champ libre" + customInfo: String "Informations liés au transport" transport: BsvhuTransportInput } diff --git a/back/src/bsvhu/typeDefs/bsvhu.objects.graphql b/back/src/bsvhu/typeDefs/bsvhu.objects.graphql index 079b7353ca..ea092750d1 100644 --- a/back/src/bsvhu/typeDefs/bsvhu.objects.graphql +++ b/back/src/bsvhu/typeDefs/bsvhu.objects.graphql @@ -107,6 +107,8 @@ type BsvhuTransporter { company: FormCompany "Récépissé transporteur" recepisse: BsvhuRecepisse + "Champ libre" + customInfo: String "Informations liés au transport" transport: BsvhuTransport } diff --git a/back/src/bsvhu/validation/rules.ts b/back/src/bsvhu/validation/rules.ts index b005df4bc5..ad9b867d91 100644 --- a/back/src/bsvhu/validation/rules.ts +++ b/back/src/bsvhu/validation/rules.ts @@ -25,7 +25,6 @@ export type BsvhuEditableFields = Required< | "emitterCustomInfo" | "emitterNotOnTD" | "destinationCustomInfo" - | "transporterCustomInfo" | "emitterEmissionSignatureDate" | "emitterEmissionSignatureAuthor" | "transporterTransportSignatureDate" @@ -541,6 +540,11 @@ export const bsvhuEditionRules: BsvhuEditionRules = { } } }, + transporterCustomInfo: { + readableFieldName: + "les champs d'informations complémentaires du transporteur", + sealed: { from: "TRANSPORT" } + }, ecoOrganismeName: { readableFieldName: "le nom de l'éco-organisme", sealed: { from: "OPERATION" }, diff --git a/back/src/bsvhu/validation/schema.ts b/back/src/bsvhu/validation/schema.ts index 3f639dfc9f..09a682e778 100644 --- a/back/src/bsvhu/validation/schema.ts +++ b/back/src/bsvhu/validation/schema.ts @@ -210,7 +210,6 @@ const rawBsvhuSchema = z.object({ ) .max(2, "Un maximum de 2 plaques d'immatriculation est accepté") .default([]), - ecoOrganismeName: z.string().nullish(), ecoOrganismeSiret: siretSchema(CompanyRole.EcoOrganisme).nullish(), brokerCompanyName: z.string().nullish(), diff --git a/front/src/Apps/Dashboard/Components/BsdCardList/BsdCardList.tsx b/front/src/Apps/Dashboard/Components/BsdCardList/BsdCardList.tsx index b06f81c0ab..bfb0598f36 100644 --- a/front/src/Apps/Dashboard/Components/BsdCardList/BsdCardList.tsx +++ b/front/src/Apps/Dashboard/Components/BsdCardList/BsdCardList.tsx @@ -461,6 +461,7 @@ function BsdCardList({ const hasAutomaticSignature = siretsWithAutomaticSignature?.includes( node?.emitter?.company?.siret ); + return (
  • , MutationUpdateBsvhuArgs>( + UPDATE_VHU_FORM + ); + const onSubmitForm = async data => { if (bsd.type === BsdType.Bsdd) { await updateTransporterInfoBsdd({ @@ -140,17 +149,35 @@ const TransporterInfoEditModal = ({ } } }); + } else if (bsd.type === BsdType.Bsvhu) { + await updateTransporterInfoBsvhu({ + variables: { + id: bsd.id, + input: { + transporter: { + customInfo: data.customInfo, + transport: { plates: formattedPlates } + } + } + } + }); } }; const error = - errorBsdd || errorBsda || errorBsdasri || errorBsff || errorBspaoh; + errorBsdd || + errorBsda || + errorBsdasri || + errorBsff || + errorBspaoh || + errorBsvhu; const loading = loadingBsdd || loadingBsda || loadingBsdasri || loadingBsff || - loadingBspaoh; + loadingBspaoh || + loadingBsvhu; return ( val.trim() !== "", { - message: "Le nom et prénom de l'auteur de la signature est requis" - }) - .pipe( +const transportModes = [ + TransportMode.Road, + TransportMode.Air, + TransportMode.Rail, + TransportMode.River, + TransportMode.Sea +]; + +const schema = z + .object({ + author: z + .string({ + required_error: + "Le nom et prénom de l'auteur de la signature est requis" + }) + .refine(val => val.trim() !== "", { + message: "Le nom et prénom de l'auteur de la signature est requis" + }) + .pipe( + z + .string() + .min( + 2, + "Le nom et prénom de l'auteur de la signature doit comporter au moins 2 caractères" + ) + ), + date: z.coerce + .date({ + required_error: "La date d'émission est requise", + invalid_type_error: "Format de date invalide." + }) + .transform(v => v?.toISOString()), + mode: z.enum(transportModes), + plates: z.preprocess( + val => (Array.isArray(val) ? val : [val]).filter(Boolean), z .string() - .min( - 2, - "Le nom et prénom de l'auteur de la signature doit comporter au moins 2 caractères" - ) - ), - date: z.coerce - .date({ - required_error: "La date d'émission est requise", - invalid_type_error: "Format de date invalide." - }) - .transform(v => v?.toISOString()), - mode: z.string(), - plates: z.preprocess( - val => (Array.isArray(val) ? val : [val]).filter(Boolean), - z - .string() - .array() - .min(1, "La plaque d'immatriculation est requise") - .max(2, "2 plaques d'immatriculation maximum") - ) -}); + .array() + + .max(2, "2 plaques d'immatriculation maximum") + ) + }) + .superRefine((val, ctx) => { + if (val.mode === "ROAD" && !val.plates?.length) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["plates"], + message: `Ce champ est requis pour le transport routier` + }); + } + }); export type ZodBsvhuTransport = z.infer; const SignVhuTransport = ({ bsvhuId, onClose }) => { @@ -74,7 +97,11 @@ const SignVhuTransport = ({ bsvhuId, onClose }) => { } ); - const [signBsvhu, { loading, error }] = useMutation< + const [updateBsvhu, { error: updateError }] = useMutation< + Pick, + MutationUpdateBsvhuArgs + >(UPDATE_VHU_FORM); + const [signBsvhu, { loading, error: signError }] = useMutation< Pick, MutationSignBsvhuArgs >(SIGN_BSVHU); @@ -85,15 +112,19 @@ const SignVhuTransport = ({ bsvhuId, onClose }) => { const initialState = { date: datetimeToYYYYMMDD(TODAY), author: "", - mode: data?.bsvhu?.transporter?.transport?.mode ?? "ROAD", + mode: + data?.bsvhu?.transporter?.transport?.mode && + transportModes.includes(data?.bsvhu?.transporter?.transport?.mode) + ? data?.bsvhu?.transporter?.transport?.mode + : TransportMode.Road, plates: data?.bsvhu?.transporter?.transport?.plates ?? [] }; const methods = useForm({ + mode: "onTouched", values: initialState, - resolver: async (data, context, options) => { - return zodResolver(schema)(data, context, options); - } + resolver: async (data, context, options) => + zodResolver(schema)(data, context, options) }); const { handleSubmit, reset, formState, register } = methods; if (data == null) { @@ -138,74 +169,90 @@ const SignVhuTransport = ({ bsvhuId, onClose }) => { -

    - En qualité de transporteur du déchet, j'atteste que - les informations ci-dessus sont correctes. En signant ce document, - je déclare prendre en charge le déchet. -

    + +
    { + const { author, date, mode, plates } = values; - { - await signBsvhu({ - variables: { - id: bsvhu.id, - input: { - ...data, - type: SignatureTypeInput.Transport + await updateBsvhu({ + variables: { + id: bsvhuId, + input: { + transporter: { + transport: { mode: mode as TransportMode, plates } + } + } } - } - }); - onClose(); - })} - > -
    - -
    -
    - +
    Transport du déchet
    +
    + +
    + -
    -
    -
    - - - +

    + En qualité de transporteur du déchet, j'atteste + que les informations ci-dessus sont correctes. En signant ce + document, je déclare prendre en charge le déchet. +

    +
    + +
    +
    + +
    + +
    + {updateError && ( + + )} + {signError && } +
    + +
    +
    + +
    -
    - -
    - {error && } -
    - -
    -
    - - -
    - + + )} diff --git a/front/src/Apps/Dashboard/bsdMapper.ts b/front/src/Apps/Dashboard/bsdMapper.ts index b2d57e37ae..f4568ee040 100644 --- a/front/src/Apps/Dashboard/bsdMapper.ts +++ b/front/src/Apps/Dashboard/bsdMapper.ts @@ -211,7 +211,7 @@ export const getBsvhuCurrentTransporterInfos = ( transporterNumberPlate: currentTransporter?.transport?.plates?.filter( plate => plate.trim() ), - transporterCustomInfo: "", + transporterCustomInfo: currentTransporter?.customInfo, transporterMode: currentTransporter?.transport?.mode ?? undefined }; }; @@ -350,6 +350,7 @@ const mapBsvhu = (bsvhu: Bsvhu): BsdDisplay => { const wasteCode = bsvhu?.wasteCode; const wasteName = wasteCode === "16 01 04*" ? "VHU non dépollués" : "VHU dépollués"; //16 01 06 + const transporter = bsvhu.transporter || bsvhu["bsvhuTransporter"]; const bsvhuFormatted: BsdDisplay = { id: bsvhu.id, readableid: bsvhu.id, @@ -364,11 +365,13 @@ const mapBsvhu = (bsvhu: Bsvhu): BsdDisplay => { }, emitter: bsvhu.emitter || bsvhu["bsvhuEmitter"], destination: bsvhu.destination || bsvhu["bsvhuDestination"], - transporter: bsvhu.transporter || bsvhu["bsvhuTransporter"], - transporterNumberPlate: "fff", + transporter: transporter, + transporterCustomInfo: transporter?.customInfo, + transporterNumberPlate: transporter?.transport?.plates, updatedAt: bsvhu["bsvhuUpdatedAt"], ecoOrganisme: bsvhu.ecoOrganisme }; + return bsvhuFormatted; }; diff --git a/front/src/Apps/Dashboard/dashboardServices.ts b/front/src/Apps/Dashboard/dashboardServices.ts index 8ec6af3acf..a8bc2e88f6 100644 --- a/front/src/Apps/Dashboard/dashboardServices.ts +++ b/front/src/Apps/Dashboard/dashboardServices.ts @@ -70,6 +70,7 @@ import { sub, differenceInDays } from "date-fns"; export const getBsdView = (bsd): BsdDisplay | null => { const bsdView = formatBsd(bsd); + return bsdView; }; diff --git a/front/src/Apps/common/queries/fragments/bsvhu.ts b/front/src/Apps/common/queries/fragments/bsvhu.ts index 4820536b4a..63e6787c71 100644 --- a/front/src/Apps/common/queries/fragments/bsvhu.ts +++ b/front/src/Apps/common/queries/fragments/bsvhu.ts @@ -21,6 +21,7 @@ export const vhuFragment = gql` plates mode } + customInfo recepisse { number } @@ -84,6 +85,7 @@ export const dashboardVhuFragment = gql` validityLimit isExempted } + customInfo } destination { type @@ -184,6 +186,7 @@ export const FullBsvhuFragment = gql` validityLimit isExempted } + customInfo transport { plates mode diff --git a/front/src/Pages/Dashboard.tsx b/front/src/Pages/Dashboard.tsx index 5c3c5d6921..a041bdd3b4 100644 --- a/front/src/Pages/Dashboard.tsx +++ b/front/src/Pages/Dashboard.tsx @@ -206,6 +206,7 @@ const DashboardPage = () => { }; const bsds = data?.bsds.edges; + const bsdsTotalCount = data?.bsds.totalCount; const hasNextPage = data?.bsds.pageInfo.hasNextPage; const isLoadingBsds = loading; diff --git a/front/src/dashboard/components/BSDList/BSVhu/WorkflowAction/SignOperation.tsx b/front/src/dashboard/components/BSDList/BSVhu/WorkflowAction/SignOperation.tsx index 3bbc2b3c53..b0ba60ee58 100644 --- a/front/src/dashboard/components/BSDList/BSVhu/WorkflowAction/SignOperation.tsx +++ b/front/src/dashboard/components/BSDList/BSVhu/WorkflowAction/SignOperation.tsx @@ -1,7 +1,10 @@ import { useMutation } from "@apollo/client"; import { RedErrorMessage } from "../../../../../common/components"; import Operation from "../../../../../form/bsvhu/Operation"; -import { UPDATE_VHU_FORM } from "../../../../../Apps/common/queries/bsvhu/queries"; +import { + UPDATE_VHU_FORM, + SIGN_BSVHU +} from "../../../../../Apps/common/queries/bsvhu/queries"; import { getComputedState } from "../../../../../Apps/Dashboard/Creation/getComputedState"; import { Field, Form, Formik } from "formik"; import { @@ -13,7 +16,6 @@ import { import React from "react"; import * as yup from "yup"; import { SignBsvhu } from "./SignBsvhu"; -import { SIGN_BSVHU } from "../../../../../Apps/common/queries/bsvhu/queries"; import DateInput from "../../../../../form/common/components/custom-inputs/DateInput"; import { subMonths } from "date-fns"; import { getInitialCompany } from "../../../../../Apps/common/data/initialState";