From 6536a86693906769a99869e001a0c1ce9745be95 Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Thu, 12 Dec 2024 11:22:10 +0100 Subject: [PATCH 1/7] feat: made field required, started fixing tests --- .../forms/__tests__/validation.integration.ts | 141 ++++++++++++------ .../__tests__/markAsAccepted.integration.ts | 18 ++- .../__tests__/markAsReceived.integration.ts | 31 ++-- .../markAsTempStorerAccepted.integration.ts | 79 +--------- back/src/forms/validation.ts | 24 ++- 5 files changed, 158 insertions(+), 135 deletions(-) diff --git a/back/src/forms/__tests__/validation.integration.ts b/back/src/forms/__tests__/validation.integration.ts index 3e8adcf851..cf873a7e89 100644 --- a/back/src/forms/__tests__/validation.integration.ts +++ b/back/src/forms/__tests__/validation.integration.ts @@ -988,6 +988,7 @@ describe("receivedInfosSchema", () => { const receivedInfo: ReceivedFormInput = { wasteAcceptationStatus: "ACCEPTED", quantityReceived: 12.5, + quantityRefused: 0, wasteRefusalReason: "", receivedBy: "Jim", receivedAt: new Date("2020-01-17T10:12:00+0100"), @@ -1014,7 +1015,8 @@ describe("receivedInfosSchema", () => { describe("waste is refused", () => { const receivedInfo: ReceivedFormInput = { wasteAcceptationStatus: "REFUSED", - quantityReceived: 0, + quantityReceived: 10, + quantityRefused: 10, wasteRefusalReason: "non conformity", receivedBy: "Joe", receivedAt: new Date("2020-01-17T10:12:00+0100"), @@ -1042,6 +1044,7 @@ describe("receivedInfosSchema", () => { const receivedInfo: ReceivedFormInput = { wasteAcceptationStatus: "PARTIALLY_REFUSED", quantityReceived: 11, + quantityRefused: 6, wasteRefusalReason: "mixed waste", receivedBy: "Bill", receivedAt: new Date("2020-01-17T10:12:00+0100"), @@ -1064,13 +1067,18 @@ describe("receivedInfosSchema", () => { ); }); - it("should be invalid when quantity received is 0", async () => { - const validateFn = () => - receivedInfoSchema.validate({ ...receivedInfo, quantityReceived: 0 }); - await expect(validateFn()).rejects.toThrow( - "Réception : le poids doit être supérieur à 0 lorsque le déchet est accepté ou accepté partiellement" - ); - }); + // TODO: can no longer be tested because error on quantityRefused pops first + // it("should be invalid when quantity received is 0", async () => { + // const validateFn = () => + // receivedInfoSchema.validate({ + // ...receivedInfo, + // quantityReceived: 0, + // quantityRefused: 0 + // }); + // await expect(validateFn()).rejects.toThrow( + // "Réception : le poids doit être supérieur à 0 lorsque le déchet est accepté ou accepté partiellement" + // ); + // }); }); describe("quantityRefused", () => { @@ -1080,7 +1088,7 @@ describe("receivedInfosSchema", () => { signedAt: new Date("2020-01-17T10:12:00+0100") }; - it("quantityRefused is not mandatory", async () => { + it("quantityRefused is required if wasteAcceptationStatus + quantityReceived (PARTIALLY_REFUSED)", async () => { // Given const update = { ...form, @@ -1089,6 +1097,60 @@ describe("receivedInfosSchema", () => { quantityReceived: 10 }; + // When + const validateFn = () => receivedInfoSchema.validate(update); + + // Then + await expect(validateFn()).rejects.toThrow( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused is required if wasteAcceptationStatus + quantityReceived (ACCEPTED)", async () => { + // Given + const update = { + ...form, + wasteAcceptationStatus: "ACCEPTED", + quantityReceived: 10 + }; + + // When + const validateFn = () => receivedInfoSchema.validate(update); + + // Then + await expect(validateFn()).rejects.toThrow( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused is required if wasteAcceptationStatus + quantityReceived (REFUSED)", async () => { + // Given + const update = { + ...form, + wasteAcceptationStatus: "REFUSED", + wasteRefusalReason: "Because", + quantityReceived: 10 + }; + + // When + const validateFn = () => receivedInfoSchema.validate(update); + + // Then + await expect(validateFn()).rejects.toThrow( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused can be 0 if waste is REFUSED and quantityReceived = 0", async () => { + // Given + const update = { + ...form, + wasteAcceptationStatus: "REFUSED", + wasteRefusalReason: "Because", + quantityReceived: 0, + quantityRefused: 0 + }; + // When const isValid = await receivedInfoSchema.validate(update); @@ -1112,24 +1174,21 @@ describe("receivedInfosSchema", () => { ); }); - it.each([null, undefined, 0])( - "waste is ACCEPTED > quantityReceived = 10 > quantityRefused can be %p", - async quantityRefused => { - // Given - const update = { - ...form, - wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 10, - quantityRefused - }; + it("waste is ACCEPTED > quantityReceived = 10 > quantityRefused must equal 0", async () => { + // Given + const update = { + ...form, + wasteAcceptationStatus: "ACCEPTED", + quantityReceived: 10, + quantityRefused: 0 + }; - // When - const isValid = await receivedInfoSchema.validate(update); + // When + const isValid = await receivedInfoSchema.validate(update); - // Then - expect(isValid).toBeTruthy(); - } - ); + // Then + expect(isValid).toBeTruthy(); + }); it.each([5, 10, 15])( "waste is ACCEPTED > quantityReceived = 10 > quantityRefused can NOT be %p", @@ -1152,25 +1211,22 @@ describe("receivedInfosSchema", () => { } ); - it.each([null, undefined, 10])( - "waste is REFUSED > quantityReceived = 10 > quantityRefused can be %p", - async quantityRefused => { - // Given - const update = { - ...form, - wasteAcceptationStatus: "REFUSED", - wasteRefusalReason: "Reason", - quantityReceived: 10, - quantityRefused - }; + it("waste is REFUSED > quantityReceived = 10 > quantityRefused must be quantityReceived", async () => { + // Given + const update = { + ...form, + wasteAcceptationStatus: "REFUSED", + wasteRefusalReason: "Reason", + quantityReceived: 10, + quantityRefused: 10 + }; - // When - const isValid = await receivedInfoSchema.validate(update); + // When + const isValid = await receivedInfoSchema.validate(update); - // Then - expect(isValid).toBeTruthy(); - } - ); + // Then + expect(isValid).toBeTruthy(); + }); it.each([0, 3, 15])( "waste is REFUSED > quantityReceived = 10 > quantityRefused can NOT be %p", @@ -2214,6 +2270,7 @@ describe("processedInfoSchema", () => { const receivedInfo: ReceivedFormInput = { wasteAcceptationStatus: "ACCEPTED", quantityReceived: 12.5, + quantityRefused: 0, wasteRefusalReason: "", receivedBy: "Jim", receivedAt: new Date("2020-01-17T10:12:00+0100"), diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts index 362b872362..3d743c7091 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts @@ -80,6 +80,7 @@ const createAndAcceptForm = async (createOpt, acceptOpt) => { signedBy: "Bill", wasteAcceptationStatus: "ACCEPTED", quantityReceived: 11, + quantityRefused: 0, ...acceptOpt } } @@ -141,7 +142,8 @@ describe("Test Form reception", () => { signedAt: "2019-01-17T10:22:00+0100", signedBy: "Bill", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 11 + quantityReceived: 11, + quantityRefused: 0 } } }); @@ -290,7 +292,8 @@ describe("Test Form reception", () => { signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "REFUSED", wasteRefusalReason: "Lorem ipsum", - quantityReceived: 0 + quantityReceived: 0, + quantityRefused: 0 } } }); @@ -387,7 +390,8 @@ describe("Test Form reception", () => { signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "PARTIALLY_REFUSED", wasteRefusalReason: "Dolor sit amet", - quantityReceived: 12.5 + quantityReceived: 12.5, + quantityRefused: 7 } } }); @@ -399,6 +403,7 @@ describe("Test Form reception", () => { expect(frm.signedBy).toBe("Carol"); expect(frm.wasteRefusalReason).toBe("Dolor sit amet"); expect(frm.quantityReceived?.toNumber()).toBe(12.5); + expect(frm.quantityRefused?.toNumber()).toBe(7); // A StatusLog object is created const logs = await prisma.statusLog.findMany({ @@ -455,7 +460,8 @@ describe("Test Form reception", () => { signedAt: format(signedAt, f), signedBy: "Bill", wasteAcceptationStatus: WasteAcceptationStatus.ACCEPTED, - quantityReceived: 11 + quantityReceived: 11, + quantityRefused: 0 } } }); @@ -540,7 +546,8 @@ describe("Test Form reception", () => { wasteRefusalReason: "Parce que", signedAt: "2019-01-18" as any, signedBy: "John", - quantityReceived: 0 + quantityReceived: 0, + quantityRefused: 0 } } } @@ -702,6 +709,7 @@ describe("Test Form reception", () => { acceptedInfo: { wasteAcceptationStatus: "ACCEPTED", quantityReceived: 1, + quantityRefused: 0, signedAt: new Date("2022-01-01").toISOString() as any, signedBy: "Collecteur annexe 1" } diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts index f692366392..769684efd8 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts @@ -169,7 +169,8 @@ describe("Test Form reception", () => { receivedAt: "2019-01-17T10:22:00+0100", signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 11 + quantityReceived: 11, + quantityRefused: 0 } } }); @@ -221,7 +222,8 @@ describe("Test Form reception", () => { receivedAt: "2019-01-17T10:22:00+0100", signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 0 + quantityReceived: 0, + quantityRefused: 0 } } }); @@ -377,7 +379,8 @@ describe("Test Form reception", () => { signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "REFUSED", wasteRefusalReason: "Lorem ipsum", - quantityReceived: 0 + quantityReceived: 0, + quantityRefused: 0 } } }); @@ -423,7 +426,8 @@ describe("Test Form reception", () => { signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "PARTIALLY_REFUSED", wasteRefusalReason: "Dolor sit amet", - quantityReceived: 12.5 + quantityReceived: 12.5, + quantityRefused: 7 } } }); @@ -435,6 +439,7 @@ describe("Test Form reception", () => { expect(frm.receivedBy).toBe("Carol"); expect(frm.wasteRefusalReason).toBe("Dolor sit amet"); expect(frm.quantityReceived?.toNumber()).toBe(12.5); + expect(frm.quantityRefused?.toNumber()).toBe(7); // A StatusLog object is created const logs = await prisma.statusLog.findMany({ @@ -566,7 +571,8 @@ describe("Test Form reception", () => { receivedBy: "Bill", receivedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 11 + quantityReceived: 11, + quantityRefused: 0 } } }); @@ -635,7 +641,8 @@ describe("Test Form reception", () => { receivedBy: "Bill", receivedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 11 + quantityReceived: 11, + quantityRefused: 0 } } }); @@ -794,7 +801,8 @@ describe("Test Form reception", () => { wasteRefusalReason: "Parce que", receivedAt: "2019-01-18" as any, receivedBy: "John", - quantityReceived: 0 + quantityReceived: 0, + quantityRefused: 0 } } } @@ -885,7 +893,8 @@ describe("Test Form reception", () => { receivedAt: "2019-01-17T10:22:00+0100", signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 50 + quantityReceived: 50, + quantityRefused: 0 } } }); @@ -921,7 +930,8 @@ describe("Test Form reception", () => { receivedAt: "2019-01-17T10:22:00+0100", signedAt: "2019-01-17T10:22:00+0100", wasteAcceptationStatus: "ACCEPTED", - quantityReceived: 30 + quantityReceived: 30, + quantityRefused: 0 } } }); @@ -1030,7 +1040,8 @@ describe("Test Form reception", () => { wasteAcceptationStatus: "ACCEPTED", receivedAt: new Date("2022-01-01").toISOString() as any, receivedBy: "John", - quantityReceived: 1 + quantityReceived: 1, + quantityRefused: 0 } } }); diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts index 048b5f7ff3..956ca38056 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts @@ -75,6 +75,7 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { signedAt: "2018-12-11T00:00:00.000Z", signedBy: "John Doe", quantityReceived: 2.4, + quantityRefused: 0, quantityType: "REAL" } } @@ -118,6 +119,7 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { signedAt: "2018-12-11T00:00:00.000Z", signedBy: "John Doe", quantityReceived: 2.4, + quantityRefused: 0, quantityType: "REAL" } } @@ -173,6 +175,7 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { signedBy: "John Doe", signedAt: "2018-12-11T00:00:00.000Z", quantityReceived: 0, + quantityRefused: 0, quantityType: "REAL" } } @@ -236,6 +239,7 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { signedAt: format(signedAt, f), signedBy: "John Doe", quantityReceived: 2.4, + quantityRefused: 0, quantityType: "REAL" } } @@ -322,7 +326,8 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { signedAt: "2019-01-18" as any, signedBy: "John", quantityType: "REAL", - quantityReceived: 0 + quantityReceived: 0, + quantityRefused: 0 } } }); @@ -654,76 +659,4 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => {
  • Quantité acceptée nette : 1.3 tonnes
  • `) }); }); - - test("[legacy] user can mark BSD as PARTIALLY_REFUSED with quantityRefused = undefined", async () => { - // Given - const { user, company: tempStorerCompany } = await userWithCompanyFactory( - "MEMBER" - ); - - const emitterCompany = await companyFactory(); - const form = await formFactory({ - ownerId: user.id, - opt: { - status: Status.TEMP_STORED, - emitterCompanySiret: emitterCompany.siret, - recipientCompanySiret: tempStorerCompany.siret, - recipientIsTempStorage: true, - forwardedIn: { - create: { readableId: getReadableId(), ownerId: user.id } - }, - receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" - } - }); - - // When - const { mutate } = makeClient(user); - const { errors } = await mutate>( - MARK_AS_TEMP_STORER_ACCEPTED, - { - variables: { - id: form.id, - tempStorerAcceptedInfo: { - wasteAcceptationStatus: WasteAcceptationStatus.PARTIALLY_REFUSED, - wasteRefusalReason: "Thats isn't what I was expecting man !", - signedAt: "2019-01-18" as any, - signedBy: "John Doe", - quantityReceived: 2.4, - quantityType: "REAL" - } - } - } - ); - - // Then - expect(errors).toBeUndefined(); - - const formAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.id } - }); - - expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); - expect(formAfterMutation.wasteAcceptationStatus).toEqual( - "PARTIALLY_REFUSED" - ); - expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); - expect(formAfterMutation.quantityRefused).toBeNull(); - - const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.forwardedIn?.id } - }); - - expect(forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber()).toEqual( - 2.4 - ); - - // Mail - expect.objectContaining({ - subject: `Le déchet de l’entreprise ${form.emitterCompanyName} a été partiellement refusé à réception`, - body: expect.stringContaining(`
  • Quantité réelle présentée nette : 2.4 tonnes
  • -
  • Quantité refusée nette : Non renseignée
  • -
  • Quantité acceptée nette : Non renseignée
  • `) - }); - }); }); diff --git a/back/src/forms/validation.ts b/back/src/forms/validation.ts index 230c04f822..d074776edc 100644 --- a/back/src/forms/validation.ts +++ b/back/src/forms/validation.ts @@ -268,14 +268,29 @@ export const quantityRefused = weight(WeightUnits.Tonne) (value, context) => { const { quantityReceived } = context.parent; - const quantityReceivedIsDefined = - quantityReceived !== null && quantityReceived !== undefined; - const quantityRefusedIsDefined = value !== null && value !== undefined; + const quantityReceivedIsDefined = isDefined(quantityReceived); + const quantityRefusedIsDefined = isDefined(value); if (!quantityReceivedIsDefined && quantityRefusedIsDefined) return false; return true; } ) + .test( + "quantity-is-required", + "La quantité refusée (quantityRefused) est requise", + (value, context) => { + const { wasteAcceptationStatus, quantityReceived } = context.parent; + + // Si le déchet a été accepté ou refusé, il faut préciser la quantité refusée + // On ajoute le check sur la quantityReceived pour laisser les erreurs sur ce champ + // remonter avant les erreurs sur quantityRefused + if (isDefined(wasteAcceptationStatus) && isDefined(quantityReceived)) { + return isDefined(value); + } + + return true; + } + ) .test( "waste-is-accepted", "La quantité refusée (quantityRefused) ne peut être supérieure à zéro si le déchet est accepté (ACCEPTED)", @@ -327,8 +342,7 @@ export const quantityRefused = weight(WeightUnits.Tonne) (value, context) => { const { quantityReceived } = context.parent; - if (quantityReceived === null || quantityReceived === undefined) - return true; + if (!isDefined(quantityReceived)) return true; // Legacy if (value === null || value === undefined) return true; From b54fd06d4884ff25551d041967603ec715d10e0b Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Fri, 7 Feb 2025 10:02:51 +0100 Subject: [PATCH 2/7] feat: added tests --- .../__tests__/markAsAccepted.integration.ts | 323 ++++++++-- .../markAsTempStorerAccepted.integration.ts | 593 +++++++++--------- .../mutations/createFormRevisionRequest.ts | 2 +- 3 files changed, 586 insertions(+), 332 deletions(-) diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts index 3d743c7091..9feb700c80 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts @@ -5,6 +5,7 @@ import { EmptyReturnADR, Status, TransportMode, + User, UserRole, WasteAcceptationStatus } from "@prisma/client"; @@ -725,52 +726,6 @@ describe("Test Form reception", () => { }); }); - it("should accept quantityRefused", async () => { - // Given - const { - emitterCompany, - recipient, - recipientCompany, - form: initialForm - } = await prepareDB(); - const form = await prisma.form.update({ - where: { id: initialForm.id }, - data: { - status: "RECEIVED", - receivedBy: "Bill", - receivedAt: new Date("2019-01-17T10:22:00+0100") - } - }); - await prepareRedis({ - emitterCompany, - recipientCompany - }); - - // When - const { mutate } = makeClient(recipient); - const { errors } = await mutate(MARK_AS_ACCEPTED, { - variables: { - id: form.id, - acceptedInfo: { - signedAt: "2019-01-17T10:22:00+0100", - signedBy: "Bill", - wasteAcceptationStatus: "PARTIALLY_REFUSED", - wasteRefusalReason: "Parce que", - quantityReceived: 11, - quantityRefused: 7 - } - } - }); - - // Then - expect(errors).toBeUndefined(); - const acceptedForm = await prisma.form.findUniqueOrThrow({ - where: { id: form.id } - }); - expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); - expect(acceptedForm.quantityRefused?.toNumber()).toEqual(7); - }); - // Bug was "Cannot destructure property 'prepareVariables' of 'mailTemplate' as it is undefined." // Use-case: // - Create a tmp storage BSD @@ -1189,4 +1144,280 @@ describe("Test Form reception", () => { "Vous ne pouvez préciser de retour à vide ADR que si le mode de transport est route (ROAD) ou null" ); }); + + describe("quantityRefused", () => { + const createBSDD = async () => { + const { + emitterCompany, + recipient, + recipientCompany, + form: initialForm + } = await prepareDB(); + + const form = await prisma.form.update({ + where: { id: initialForm.id }, + data: { + status: "RECEIVED", + receivedBy: "Bill", + receivedAt: new Date("2019-01-17T10:22:00+0100") + } + }); + + await prepareRedis({ + emitterCompany, + recipientCompany + }); + + return { recipient, form }; + }; + + const markBSDDAsAccepted = async ( + recipient: User, + formId: string, + wasteAcceptationStatus: WasteAcceptationStatus, + quantityReceived: number, + quantityRefused: number | null, + wasteRefusalReason?: string | null + ) => { + const { mutate } = makeClient(recipient); + return await mutate(MARK_AS_ACCEPTED, { + variables: { + id: formId, + acceptedInfo: { + signedAt: "2019-01-17T10:22:00+0100", + signedBy: "Bill", + wasteAcceptationStatus, + wasteRefusalReason, + quantityReceived, + quantityRefused + } + } + }); + }; + + describe("wasteAcceptationStatus = ACCEPTED", () => { + it("waste should be accepted", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "ACCEPTED", + 11, + 0 + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused?.toNumber()).toEqual(0); + expect(acceptedForm.wasteAcceptationStatus).toBe("ACCEPTED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + + it("quantityRefused is required", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "ACCEPTED", + 11, + null + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused cannot be > 0", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "ACCEPTED", + 11, + 5 + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) ne peut être supérieure à zéro si le déchet est accepté (ACCEPTED)" + ); + }); + }); + + describe("wasteAcceptationStatus = REFUSED", () => { + it("waste should be refused", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "REFUSED", + 11, + 11, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused?.toNumber()).toEqual(11); + expect(acceptedForm.wasteAcceptationStatus).toBe("REFUSED"); + expect(acceptedForm.status).toBe("REFUSED"); + }); + + it("quantityRefused is required", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused cannot be != quantityReceived", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "REFUSED", + 11, + 5, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être égale à la quantité reçue (quantityReceived) si le déchet est refusé (REFUSED)" + ); + }); + }); + + describe("wasteAcceptationStatus = PARTIALLY_REFUSED", () => { + it("waste should be partially refused", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + 6, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused?.toNumber()).toEqual(6); + expect(acceptedForm.wasteAcceptationStatus).toBe("PARTIALLY_REFUSED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + + it("quantityRefused is required", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused cannot be = quantityReceived", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + 11, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être inférieure à la quantité reçue (quantityReceived) et supérieure à zéro si le déchet est partiellement refusé (PARTIALLY_REFUSED)" + ); + }); + + it("quantityRefused cannot be zero", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + 0, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être inférieure à la quantité reçue (quantityReceived) et supérieure à zéro si le déchet est partiellement refusé (PARTIALLY_REFUSED)" + ); + }); + }); + }); }); diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts index 956ca38056..87133471fa 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts @@ -12,6 +12,7 @@ import { allowedFormats } from "../../../../common/dates"; import { CompanyType, Status, + User, UserRole, WasteAcceptationStatus } from "@prisma/client"; @@ -357,306 +358,328 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { expect(appendix2Forms).toEqual([]); }); - test("user can mark BSD as ACCEPTED and specify quantityRefused = 0", async () => { - // Given - const { user, company: tempStorerCompany } = await userWithCompanyFactory( - "MEMBER" - ); - - const emitterCompany = await companyFactory(); - const form = await formFactory({ - ownerId: user.id, - opt: { - status: Status.TEMP_STORED, - emitterCompanySiret: emitterCompany.siret, - recipientCompanySiret: tempStorerCompany.siret, - recipientIsTempStorage: true, - forwardedIn: { - create: { readableId: getReadableId(), ownerId: user.id } - }, - receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" - } - }); - - // When - const { mutate } = makeClient(user); - const { errors } = await mutate>( - MARK_AS_TEMP_STORER_ACCEPTED, - { - variables: { - id: form.id, - tempStorerAcceptedInfo: { - wasteAcceptationStatus: WasteAcceptationStatus.ACCEPTED, - wasteRefusalReason: "", - signedAt: "2019-01-18" as any, - signedBy: "John Doe", - quantityReceived: 2.4, - quantityRefused: 0, - quantityType: "REAL" - } + describe("quanityRefused", () => { + const createBSDD = async () => { + const { user, company: tempStorerCompany } = await userWithCompanyFactory( + "MEMBER" + ); + + const emitterCompany = await companyFactory(); + const form = await formFactory({ + ownerId: user.id, + opt: { + status: Status.TEMP_STORED, + emitterCompanySiret: emitterCompany.siret, + recipientCompanySiret: tempStorerCompany.siret, + recipientIsTempStorage: true, + forwardedIn: { + create: { readableId: getReadableId(), ownerId: user.id } + }, + receivedBy: "John Doe", + receivedAt: "2018-12-11T00:00:00.000Z" } - } - ); - - // Then - expect(errors).toBeUndefined(); - - const formAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.id } - }); - - expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); - expect(formAfterMutation.wasteAcceptationStatus).toEqual("ACCEPTED"); - expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); - expect(formAfterMutation.quantityRefused?.toNumber()).toEqual(0); - - const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.forwardedIn?.id } - }); - - expect(forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber()).toEqual( - 2.4 - ); - }); - - test("user cannot mark BSD as ACCEPTED and specify quantityRefused != 0", async () => { - // Given - const { user, company: tempStorerCompany } = await userWithCompanyFactory( - "MEMBER" - ); - - const emitterCompany = await companyFactory(); - const form = await formFactory({ - ownerId: user.id, - opt: { - status: Status.TEMP_STORED, - emitterCompanySiret: emitterCompany.siret, - recipientCompanySiret: tempStorerCompany.siret, - recipientIsTempStorage: true, - forwardedIn: { - create: { readableId: getReadableId(), ownerId: user.id } - }, - receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" - } - }); - - // When - const { mutate } = makeClient(user); - const { errors } = await mutate>( - MARK_AS_TEMP_STORER_ACCEPTED, - { - variables: { - id: form.id, - tempStorerAcceptedInfo: { - wasteAcceptationStatus: WasteAcceptationStatus.ACCEPTED, - wasteRefusalReason: "", - signedAt: "2019-01-18" as any, - signedBy: "John Doe", - quantityReceived: 2.4, - quantityRefused: 1, - quantityType: "REAL" - } - } - } - ); - - // Then - expect(errors).not.toBeUndefined(); - expect(errors[0].message).toBe( - "La quantité refusée (quantityRefused) ne peut être supérieure à zéro si le déchet est accepté (ACCEPTED)" - ); - }); - - test("user can mark BSD as REFUSED and specify quantityRefused = quantityReceived", async () => { - // Given - const { user, company: tempStorerCompany } = await userWithCompanyFactory( - "MEMBER" - ); - - const emitterCompany = await companyFactory(); - const form = await formFactory({ - ownerId: user.id, - opt: { - status: Status.TEMP_STORED, - emitterCompanySiret: emitterCompany.siret, - recipientCompanySiret: tempStorerCompany.siret, - recipientIsTempStorage: true, - forwardedIn: { - create: { readableId: getReadableId(), ownerId: user.id } - }, - receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" - } - }); - - // When - const { mutate } = makeClient(user); - const { errors } = await mutate>( - MARK_AS_TEMP_STORER_ACCEPTED, - { - variables: { - id: form.id, - tempStorerAcceptedInfo: { - wasteAcceptationStatus: WasteAcceptationStatus.REFUSED, - wasteRefusalReason: "Thats isn't what I was expecting man !", - signedAt: "2019-01-18" as any, - signedBy: "John Doe", - quantityReceived: 2.4, - quantityRefused: 2.4, - quantityType: "REAL" - } - } - } - ); - - // Then - expect(errors).toBeUndefined(); - - const formAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.id } - }); - - expect(formAfterMutation.status).toEqual("REFUSED"); - expect(formAfterMutation.wasteAcceptationStatus).toEqual("REFUSED"); - expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); - expect(formAfterMutation.quantityRefused?.toNumber()).toEqual(2.4); - - const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.forwardedIn?.id } - }); - - expect(forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber()).toEqual( - 0 - ); - - expect(sendMail as jest.Mock).toHaveBeenCalledWith( - expect.objectContaining({ - subject: `Le déchet de l’entreprise ${form.emitterCompanyName} a été totalement refusé à réception` - }) - ); - }); - - test("user cannot mark BSD as REFUSED and specify quantityRefused != quantityReceived", async () => { - // Given - const { user, company: tempStorerCompany } = await userWithCompanyFactory( - "MEMBER" - ); - - const emitterCompany = await companyFactory(); - const form = await formFactory({ - ownerId: user.id, - opt: { - status: Status.TEMP_STORED, - emitterCompanySiret: emitterCompany.siret, - recipientCompanySiret: tempStorerCompany.siret, - recipientIsTempStorage: true, - forwardedIn: { - create: { readableId: getReadableId(), ownerId: user.id } - }, - receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" - } - }); + }); - // When - const { mutate } = makeClient(user); - const { errors } = await mutate>( - MARK_AS_TEMP_STORER_ACCEPTED, - { - variables: { - id: form.id, - tempStorerAcceptedInfo: { - wasteAcceptationStatus: WasteAcceptationStatus.REFUSED, - wasteRefusalReason: "Thats isn't what I was expecting man !", - signedAt: "2019-01-18" as any, - signedBy: "John Doe", - quantityReceived: 2.4, - quantityRefused: 2.3, - quantityType: "REAL" + return { user, form }; + }; + + const markBSDDAsAccepted = async ( + user: User, + formId: string, + wasteAcceptationStatus: WasteAcceptationStatus, + quantityReceived: number, + quantityRefused: number | null, + wasteRefusalReason?: string | null + ) => { + const { mutate } = makeClient(user); + return await mutate>( + MARK_AS_TEMP_STORER_ACCEPTED, + { + variables: { + id: formId, + tempStorerAcceptedInfo: { + wasteAcceptationStatus, + wasteRefusalReason, + signedAt: "2019-01-18" as any, + signedBy: "John Doe", + quantityReceived, + quantityRefused, + quantityType: "REAL" + } } } - } - ); - - // Then - expect(errors).not.toBeUndefined(); - expect(errors[0].message).toBe( - "La quantité refusée (quantityRefused) doit être égale à la quantité reçue (quantityReceived) si le déchet est refusé (REFUSED)" - ); - }); + ); + }; + + describe("wasteAcceptationStatus = ACCEPTED", () => { + it("waste should be accepted", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.ACCEPTED, + 2.4, + 0 + ); + + // Then + expect(errors).toBeUndefined(); + + const formAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + + expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); + expect(formAfterMutation.wasteAcceptationStatus).toEqual("ACCEPTED"); + expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); + expect(formAfterMutation.quantityRefused?.toNumber()).toEqual(0); + + const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.forwardedIn?.id } + }); + + expect( + forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber() + ).toEqual(2.4); + }); - test("user can mark BSD as PARTIALLY_REFUSED and specify quantityRefused", async () => { - // Given - const { user, company: tempStorerCompany } = await userWithCompanyFactory( - "MEMBER" - ); + it("quantityRefused is required", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.ACCEPTED, + 2.4, + null + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); - const emitterCompany = await companyFactory(); - const form = await formFactory({ - ownerId: user.id, - opt: { - status: Status.TEMP_STORED, - emitterCompanySiret: emitterCompany.siret, - recipientCompanySiret: tempStorerCompany.siret, - recipientIsTempStorage: true, - forwardedIn: { - create: { readableId: getReadableId(), ownerId: user.id } - }, - receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" - } + it("quantityRefused must be zero", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.ACCEPTED, + 2.4, + 1 + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) ne peut être supérieure à zéro si le déchet est accepté (ACCEPTED)" + ); + }); }); - // When - const { mutate } = makeClient(user); - const { errors } = await mutate>( - MARK_AS_TEMP_STORER_ACCEPTED, - { - variables: { - id: form.id, - tempStorerAcceptedInfo: { - wasteAcceptationStatus: WasteAcceptationStatus.PARTIALLY_REFUSED, - wasteRefusalReason: "Thats isn't what I was expecting man !", - signedAt: "2019-01-18" as any, - signedBy: "John Doe", - quantityReceived: 2.4, - quantityRefused: 1.1, - quantityType: "REAL" - } - } - } - ); + describe("wasteAcceptationStatus = REFUSED", () => { + it("waste should be refused", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.REFUSED, + 2.4, + 2.4, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + + const formAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + + expect(formAfterMutation.status).toEqual("REFUSED"); + expect(formAfterMutation.wasteAcceptationStatus).toEqual("REFUSED"); + expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); + expect(formAfterMutation.quantityRefused?.toNumber()).toEqual(2.4); + + const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.forwardedIn?.id } + }); + + expect( + forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber() + ).toEqual(0); + + expect(sendMail as jest.Mock).toHaveBeenCalledWith( + expect.objectContaining({ + subject: `Le déchet de l’entreprise ${form.emitterCompanyName} a été totalement refusé à réception` + }) + ); + }); - // Then - expect(errors).toBeUndefined(); + it("quantityRefused is required", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.REFUSED, + 2.4, + null, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); - const formAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.id } + it("quantityRefused must = quantityReceived", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.REFUSED, + 2.4, + 1, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être égale à la quantité reçue (quantityReceived) si le déchet est refusé (REFUSED)" + ); + }); }); - expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); - expect(formAfterMutation.wasteAcceptationStatus).toEqual( - "PARTIALLY_REFUSED" - ); - expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); - expect(formAfterMutation.quantityRefused?.toNumber()).toEqual(1.1); + describe("wasteAcceptationStatus = PARTIALLY_REFUSED", () => { + it("waste should be partially refused", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.PARTIALLY_REFUSED, + 2.4, + 1.1, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + + const formAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + + expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); + expect(formAfterMutation.wasteAcceptationStatus).toEqual( + "PARTIALLY_REFUSED" + ); + expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); + expect(formAfterMutation.quantityRefused?.toNumber()).toEqual(1.1); + + const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.forwardedIn?.id } + }); + + expect( + forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber() + ).toEqual(1.3); + + // Mail + expect.objectContaining({ + subject: `Le déchet de l’entreprise ${form.emitterCompanyName} a été partiellement refusé à réception`, + body: expect.stringContaining(`
  • Quantité réelle présentée nette : 2.4 tonnes
  • +
  • Quantité refusée nette : 1.1 tonnes
  • +
  • Quantité acceptée nette : 1.3 tonnes
  • `) + }); + }); - const forwardedFormAfterMutation = await prisma.form.findUniqueOrThrow({ - where: { id: form.forwardedIn?.id } - }); + it("quantityRefused is required", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.PARTIALLY_REFUSED, + 2.4, + null, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); - expect(forwardedFormAfterMutation.wasteDetailsQuantity?.toNumber()).toEqual( - 1.3 - ); + it("quantityRefused cannot = 0", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.PARTIALLY_REFUSED, + 2.4, + 0, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être inférieure à la quantité reçue (quantityReceived) et supérieure à zéro si le déchet est partiellement refusé (PARTIALLY_REFUSED)" + ); + }); - // Mail - expect.objectContaining({ - subject: `Le déchet de l’entreprise ${form.emitterCompanyName} a été partiellement refusé à réception`, - body: expect.stringContaining(`
  • Quantité réelle présentée nette : 2.4 tonnes
  • -
  • Quantité refusée nette : 1.1 tonnes
  • -
  • Quantité acceptée nette : 1.3 tonnes
  • `) + it("quantityRefused cannot = quantityReceived", async () => { + // Given + const { user, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.PARTIALLY_REFUSED, + 2.4, + 2.4, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être inférieure à la quantité reçue (quantityReceived) et supérieure à zéro si le déchet est partiellement refusé (PARTIALLY_REFUSED)" + ); + }); }); }); }); diff --git a/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts b/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts index 1158f06896..b5f7687f27 100644 --- a/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts +++ b/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts @@ -467,7 +467,7 @@ const bsddRevisionRequestWasteQuantitiesSchema = yup.object({ .nullable() .test( "is-empty", - "Le champ wasteRefusalReason ne doit pas être rensigné si le déchet est accepté ", + "Le champ wasteRefusalReason ne doit pas être renseigné si le déchet est accepté ", v => !v ) ), From 3d3bffe3a94224011a7905fe726c0e9902d31d6e Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Fri, 7 Feb 2025 14:04:22 +0100 Subject: [PATCH 3/7] feat: added tests --- .../forms/__tests__/validation.integration.ts | 3 +- .../__tests__/markAsAccepted.integration.ts | 104 ++++- .../__tests__/markAsReceived.integration.ts | 427 ++++++++++++++++-- .../markAsTempStorerAccepted.integration.ts | 109 ++++- .../resolvers/mutations/markAsAccepted.ts | 1 + .../resolvers/mutations/markAsReceived.ts | 1 + .../mutations/markAsTempStorerAccepted.ts | 5 +- back/src/forms/validation.ts | 12 +- 8 files changed, 602 insertions(+), 60 deletions(-) diff --git a/back/src/forms/__tests__/validation.integration.ts b/back/src/forms/__tests__/validation.integration.ts index cf873a7e89..858f7741ae 100644 --- a/back/src/forms/__tests__/validation.integration.ts +++ b/back/src/forms/__tests__/validation.integration.ts @@ -1084,11 +1084,12 @@ describe("receivedInfosSchema", () => { describe("quantityRefused", () => { const form = { receivedBy: "Bill", + createdAt: new Date("2020-01-17T10:12:00+0100"), receivedAt: new Date("2020-01-17T10:12:00+0100"), signedAt: new Date("2020-01-17T10:12:00+0100") }; - it("quantityRefused is required if wasteAcceptationStatus + quantityReceived (PARTIALLY_REFUSED)", async () => { + it.only("quantityRefused is required if wasteAcceptationStatus + quantityReceived (PARTIALLY_REFUSED)", async () => { // Given const update = { ...form, diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts index 9feb700c80..6416829997 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsAccepted.integration.ts @@ -1146,7 +1146,7 @@ describe("Test Form reception", () => { }); describe("quantityRefused", () => { - const createBSDD = async () => { + const createBSDD = async (opt?) => { const { emitterCompany, recipient, @@ -1159,7 +1159,9 @@ describe("Test Form reception", () => { data: { status: "RECEIVED", receivedBy: "Bill", - receivedAt: new Date("2019-01-17T10:22:00+0100") + receivedAt: new Date("2019-01-17T10:22:00+0100"), + createdAt: new Date("2025-03-20"), + ...opt } }); @@ -1220,9 +1222,11 @@ describe("Test Form reception", () => { expect(acceptedForm.status).toBe("ACCEPTED"); }); - it("quantityRefused is required", async () => { + it("quantityRefused is required for new BSDs", async () => { // Given - const { recipient, form } = await createBSDD(); + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); // When const { errors } = await markBSDDAsAccepted( @@ -1240,6 +1244,32 @@ describe("Test Form reception", () => { ); }); + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-02-20") + }); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "ACCEPTED", + 11, + null + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused).toBeNull(); + expect(acceptedForm.wasteAcceptationStatus).toBe("ACCEPTED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + it("quantityRefused cannot be > 0", async () => { // Given const { recipient, form } = await createBSDD(); @@ -1287,9 +1317,11 @@ describe("Test Form reception", () => { expect(acceptedForm.status).toBe("REFUSED"); }); - it("quantityRefused is required", async () => { + it("quantityRefused is required for new BSDs", async () => { // Given - const { recipient, form } = await createBSDD(); + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); // When const { errors } = await markBSDDAsAccepted( @@ -1308,6 +1340,33 @@ describe("Test Form reception", () => { ); }); + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused).toBeNull(); + expect(acceptedForm.wasteAcceptationStatus).toBe("REFUSED"); + expect(acceptedForm.status).toBe("REFUSED"); + }); + it("quantityRefused cannot be != quantityReceived", async () => { // Given const { recipient, form } = await createBSDD(); @@ -1356,9 +1415,11 @@ describe("Test Form reception", () => { expect(acceptedForm.status).toBe("ACCEPTED"); }); - it("quantityRefused is required", async () => { + it("quantityRefused is required for new BSDs", async () => { // Given - const { recipient, form } = await createBSDD(); + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); // When const { errors } = await markBSDDAsAccepted( @@ -1377,6 +1438,33 @@ describe("Test Form reception", () => { ); }); + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsAccepted( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused).toBeNull(); + expect(acceptedForm.wasteAcceptationStatus).toBe("PARTIALLY_REFUSED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + it("quantityRefused cannot be = quantityReceived", async () => { // Given const { recipient, form } = await createBSDD(); diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts index 769684efd8..7e339686db 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsReceived.integration.ts @@ -1,5 +1,12 @@ import { format } from "date-fns"; -import { CompanyType, EmitterType, Status, UserRole } from "@prisma/client"; +import { + CompanyType, + EmitterType, + Status, + User, + UserRole, + WasteAcceptationStatus +} from "@prisma/client"; import { resetDatabase } from "../../../../../integration-tests/helper"; import { prisma } from "@td/prisma"; import { sendMail } from "../../../../mailer/mailing"; @@ -1238,46 +1245,6 @@ describe("Test Form reception", () => { }); }); - it("should work with quantityRefused", async () => { - // Given - const { - emitterCompany, - recipient, - recipientCompany, - form: initialForm - } = await prepareDB(); - const form = await prisma.form.update({ - where: { id: initialForm.id }, - data: { currentTransporterOrgId: siretify(3) } - }); - await prepareRedis({ - emitterCompany, - recipientCompany - }); - - // When - const { mutate } = makeClient(recipient); - await mutate(MARK_AS_RECEIVED, { - variables: { - id: form.id, - receivedInfo: { - receivedBy: "Carol", - receivedAt: "2019-01-17T10:22:00+0100", - signedAt: "2019-01-17T10:22:00+0100", - wasteAcceptationStatus: "PARTIALLY_REFUSED", - wasteRefusalReason: "Dolor sit amet", - quantityReceived: 12.5, - quantityRefused: 7.5 - } - } - }); - - // Then - const frm = await prisma.form.findUniqueOrThrow({ where: { id: form.id } }); - expect(frm.quantityReceived?.toNumber()).toEqual(12.5); - expect(frm.quantityRefused?.toNumber()).toEqual(7.5); - }); - it("when final destination refuses a BSD, a mail should be sent", async () => { // Given const emitter = await userWithCompanyFactory("MEMBER"); @@ -1535,4 +1502,382 @@ describe("Test Form reception", () => { // form was not accepted, still resent expect(frm.status).toBe("RESENT"); }); + + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + // TODO + + describe("quantityRefused", () => { + const createBSDD = async (opt?) => { + const { + emitterCompany, + recipient, + recipientCompany, + form: initialForm + } = await prepareDB(); + + const form = await prisma.form.update({ + where: { id: initialForm.id }, + data: { + currentTransporterOrgId: siretify(3), + ...opt + } + }); + + await prepareRedis({ + emitterCompany, + recipientCompany + }); + + return { recipient, form }; + }; + + const markBSDDAsReceived = async ( + recipient: User, + formId: string, + wasteAcceptationStatus: WasteAcceptationStatus, + quantityReceived: number, + quantityRefused: number | null, + wasteRefusalReason?: string | null + ) => { + const { mutate } = makeClient(recipient); + return await mutate(MARK_AS_RECEIVED, { + variables: { + id: formId, + receivedInfo: { + receivedBy: "Carol", + receivedAt: "2019-01-17T10:22:00+0100", + signedAt: "2019-01-17T10:22:00+0100", + wasteAcceptationStatus, + wasteRefusalReason, + quantityReceived, + quantityRefused + } + } + }); + }; + + describe("wasteAcceptationStatus = ACCEPTED", () => { + it("waste should be accepted", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "ACCEPTED", + 11, + 0 + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused?.toNumber()).toEqual(0); + expect(acceptedForm.wasteAcceptationStatus).toBe("ACCEPTED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + + it("quantityRefused is required for new BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "ACCEPTED", + 11, + null + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-02-20") + }); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "ACCEPTED", + 11, + null + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused).toBeNull(); + expect(acceptedForm.wasteAcceptationStatus).toBe("ACCEPTED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + + it("quantityRefused cannot be > 0", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "ACCEPTED", + 11, + 5 + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) ne peut être supérieure à zéro si le déchet est accepté (ACCEPTED)" + ); + }); + }); + + describe("wasteAcceptationStatus = REFUSED", () => { + it("waste should be refused", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "REFUSED", + 11, + 11, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused?.toNumber()).toEqual(11); + expect(acceptedForm.wasteAcceptationStatus).toBe("REFUSED"); + expect(acceptedForm.status).toBe("REFUSED"); + }); + + it("quantityRefused is required for new BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused).toBeNull(); + expect(acceptedForm.wasteAcceptationStatus).toBe("REFUSED"); + expect(acceptedForm.status).toBe("REFUSED"); + }); + + it("quantityRefused cannot be != quantityReceived", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "REFUSED", + 11, + 5, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être égale à la quantité reçue (quantityReceived) si le déchet est refusé (REFUSED)" + ); + }); + }); + + describe("wasteAcceptationStatus = PARTIALLY_REFUSED", () => { + it("waste should be partially refused", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + 6, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused?.toNumber()).toEqual(6); + expect(acceptedForm.wasteAcceptationStatus).toBe("PARTIALLY_REFUSED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + + it("quantityRefused is required for new BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) est requise" + ); + }); + + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { recipient, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + null, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const acceptedForm = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + expect(acceptedForm.quantityReceived?.toNumber()).toEqual(11); + expect(acceptedForm.quantityRefused).toBeNull(); + expect(acceptedForm.wasteAcceptationStatus).toBe("PARTIALLY_REFUSED"); + expect(acceptedForm.status).toBe("ACCEPTED"); + }); + + it("quantityRefused cannot be = quantityReceived", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + 11, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être inférieure à la quantité reçue (quantityReceived) et supérieure à zéro si le déchet est partiellement refusé (PARTIALLY_REFUSED)" + ); + }); + + it("quantityRefused cannot be zero", async () => { + // Given + const { recipient, form } = await createBSDD(); + + // When + const { errors } = await markBSDDAsReceived( + recipient, + form.id, + "PARTIALLY_REFUSED", + 11, + 0, + "Pas bon" + ); + + // Then + expect(errors).not.toBeUndefined(); + expect(errors[0].message).toBe( + "La quantité refusée (quantityRefused) doit être inférieure à la quantité reçue (quantityReceived) et supérieure à zéro si le déchet est partiellement refusé (PARTIALLY_REFUSED)" + ); + }); + }); + }); }); diff --git a/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts b/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts index 87133471fa..f93f6ae2db 100644 --- a/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/markAsTempStorerAccepted.integration.ts @@ -359,7 +359,7 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { }); describe("quanityRefused", () => { - const createBSDD = async () => { + const createBSDD = async (opt?) => { const { user, company: tempStorerCompany } = await userWithCompanyFactory( "MEMBER" ); @@ -376,7 +376,9 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { create: { readableId: getReadableId(), ownerId: user.id } }, receivedBy: "John Doe", - receivedAt: "2018-12-11T00:00:00.000Z" + receivedAt: "2018-12-11T00:00:00.000Z", + createdAt: new Date("2025-03-20"), + ...opt } }); @@ -446,9 +448,11 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { ).toEqual(2.4); }); - it("quantityRefused is required", async () => { + it("quantityRefused is required for new BSDs", async () => { // Given - const { user, form } = await createBSDD(); + const { user, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); // When const { errors } = await markBSDDAsAccepted( @@ -466,6 +470,33 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { ); }); + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { user, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.ACCEPTED, + 2.4, + null + ); + + // Then + expect(errors).toBeUndefined(); + const formAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + + expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); + expect(formAfterMutation.wasteAcceptationStatus).toEqual("ACCEPTED"); + expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); + expect(formAfterMutation.quantityRefused).toBeNull(); + }); + it("quantityRefused must be zero", async () => { // Given const { user, form } = await createBSDD(); @@ -529,9 +560,11 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { ); }); - it("quantityRefused is required", async () => { + it("quantityRefused is required for new BSDs", async () => { // Given - const { user, form } = await createBSDD(); + const { user, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); // When const { errors } = await markBSDDAsAccepted( @@ -550,6 +583,34 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { ); }); + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { user, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.REFUSED, + 2.4, + null, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const formAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + + expect(formAfterMutation.status).toEqual("REFUSED"); + expect(formAfterMutation.wasteAcceptationStatus).toEqual("REFUSED"); + expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); + expect(formAfterMutation.quantityRefused).toBeNull(); + }); + it("quantityRefused must = quantityReceived", async () => { // Given const { user, form } = await createBSDD(); @@ -618,9 +679,11 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { }); }); - it("quantityRefused is required", async () => { + it("quantityRefused is required for new BSDs", async () => { // Given - const { user, form } = await createBSDD(); + const { user, form } = await createBSDD({ + createdAt: new Date("2025-03-20") + }); // When const { errors } = await markBSDDAsAccepted( @@ -639,6 +702,36 @@ describe("{ mutation { markAsTempStorerAccepted } }", () => { ); }); + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const { user, form } = await createBSDD({ + createdAt: new Date("2025-01-20") + }); + + // When + const { errors } = await markBSDDAsAccepted( + user, + form.id, + WasteAcceptationStatus.PARTIALLY_REFUSED, + 2.4, + null, + "Pas bon" + ); + + // Then + expect(errors).toBeUndefined(); + const formAfterMutation = await prisma.form.findUniqueOrThrow({ + where: { id: form.id } + }); + + expect(formAfterMutation.status).toEqual("TEMP_STORER_ACCEPTED"); + expect(formAfterMutation.wasteAcceptationStatus).toEqual( + "PARTIALLY_REFUSED" + ); + expect(formAfterMutation.quantityReceived?.toNumber()).toEqual(2.4); + expect(formAfterMutation.quantityRefused).toBeNull(); + }); + it("quantityRefused cannot = 0", async () => { // Given const { user, form } = await createBSDD(); diff --git a/back/src/forms/resolvers/mutations/markAsAccepted.ts b/back/src/forms/resolvers/mutations/markAsAccepted.ts index 1aa2d898f5..4df82e5581 100644 --- a/back/src/forms/resolvers/mutations/markAsAccepted.ts +++ b/back/src/forms/resolvers/mutations/markAsAccepted.ts @@ -29,6 +29,7 @@ const markAsAcceptedResolver: MutationResolvers["markAsAccepted"] = async ( wasteDetailsPop: form.wasteDetailsPop, wasteDetailsCode: form.wasteDetailsCode, transporters: form.transporters, + createdAt: form.createdAt, ...acceptedInfo }); diff --git a/back/src/forms/resolvers/mutations/markAsReceived.ts b/back/src/forms/resolvers/mutations/markAsReceived.ts index ba5df9b15d..c2c75164f3 100644 --- a/back/src/forms/resolvers/mutations/markAsReceived.ts +++ b/back/src/forms/resolvers/mutations/markAsReceived.ts @@ -71,6 +71,7 @@ const markAsReceivedResolver: MutationResolvers["markAsReceived"] = async ( await receivedInfoSchema.validate({ ...receivedInfo, + createdAt: form.createdAt, transporters }); diff --git a/back/src/forms/resolvers/mutations/markAsTempStorerAccepted.ts b/back/src/forms/resolvers/mutations/markAsTempStorerAccepted.ts index e781e3611e..13231eb4e4 100644 --- a/back/src/forms/resolvers/mutations/markAsTempStorerAccepted.ts +++ b/back/src/forms/resolvers/mutations/markAsTempStorerAccepted.ts @@ -22,7 +22,10 @@ const markAsTempStorerAcceptedResolver: MutationResolvers["markAsTempStorerAccep await checkCanMarkAsTempStored(user, form); - await acceptedInfoSchema.validate(tempStorerAcceptedInfo); + await acceptedInfoSchema.validate({ + createdAt: form.createdAt, + ...tempStorerAcceptedInfo + }); const { quantityType, ...tmpStorerAcceptedInfo } = tempStorerAcceptedInfo; diff --git a/back/src/forms/validation.ts b/back/src/forms/validation.ts index d074776edc..27bffb4290 100644 --- a/back/src/forms/validation.ts +++ b/back/src/forms/validation.ts @@ -78,6 +78,10 @@ import { flattenFormInput } from "./converter"; import { bsddWasteQuantities } from "./helpers/bsddWasteQuantities"; import { isDefined, isDefinedStrict } from "../common/helpers"; +// Date de la MAJ 2025.03.1 rendant la quantité refusée obligatoire +// pour tous les BSDD +const v2024031 = new Date("2025-03-11"); + // set yup default error messages configureYup(); @@ -279,7 +283,13 @@ export const quantityRefused = weight(WeightUnits.Tonne) "quantity-is-required", "La quantité refusée (quantityRefused) est requise", (value, context) => { - const { wasteAcceptationStatus, quantityReceived } = context.parent; + const { wasteAcceptationStatus, quantityReceived, createdAt } = + context.parent; + + // La quantité refusée n'est pas obligatoire pour les BSDs legacy + if (new Date(createdAt).getTime() < new Date(v2024031).getTime()) { + return true; + } // Si le déchet a été accepté ou refusé, il faut préciser la quantité refusée // On ajoute le check sur la quantityReceived pour laisser les erreurs sur ce champ From 9f8eabb186dc4f439734b974e95a01f4b1709e37 Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Fri, 7 Feb 2025 16:00:03 +0100 Subject: [PATCH 4/7] feat: added plus fixed tests --- .../forms/__tests__/validation.integration.ts | 21 +++++++++++++++++-- back/src/forms/examples/fixtures.ts | 4 +++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/back/src/forms/__tests__/validation.integration.ts b/back/src/forms/__tests__/validation.integration.ts index 858f7741ae..e39565b686 100644 --- a/back/src/forms/__tests__/validation.integration.ts +++ b/back/src/forms/__tests__/validation.integration.ts @@ -1084,12 +1084,29 @@ describe("receivedInfosSchema", () => { describe("quantityRefused", () => { const form = { receivedBy: "Bill", - createdAt: new Date("2020-01-17T10:12:00+0100"), + createdAt: new Date("2025-03-20T10:12:00+0100"), receivedAt: new Date("2020-01-17T10:12:00+0100"), signedAt: new Date("2020-01-17T10:12:00+0100") }; - it.only("quantityRefused is required if wasteAcceptationStatus + quantityReceived (PARTIALLY_REFUSED)", async () => { + it("quantityRefused is NOT required for legacy BSDs", async () => { + // Given + const update = { + ...form, + createdAt: new Date("2025-02-20T10:12:00+0100"), + wasteAcceptationStatus: "PARTIALLY_REFUSED", + wasteRefusalReason: "Reason", + quantityReceived: 10 + }; + + // When + const isValid = await receivedInfoSchema.validate(update); + + // Then + expect(isValid).toBeTruthy(); + }); + + it("quantityRefused is required if wasteAcceptationStatus + quantityReceived (PARTIALLY_REFUSED)", async () => { // Given const update = { ...form, diff --git a/back/src/forms/examples/fixtures.ts b/back/src/forms/examples/fixtures.ts index 1fbfc13952..5001955a85 100644 --- a/back/src/forms/examples/fixtures.ts +++ b/back/src/forms/examples/fixtures.ts @@ -138,7 +138,8 @@ const receivedInfoInput = { receivedBy: "Antoine Derieux", receivedAt: "2020-04-05T11:18:00", signedAt: "2020-04-05T12:00:00", - quantityReceived: 1 + quantityReceived: 1, + quantityRefused: 0 }; const processedInfoInput = { @@ -168,6 +169,7 @@ const tempStoredInfosInput = { receivedAt: "2020-05-03T09:00:00", signedAt: "2020-05-03T09:00:00", quantityReceived: 1, + quantityRefused: 0, quantityType: "REAL" }; From b881507a65e169333b518164b36fb9e53c9c92b8 Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Fri, 7 Feb 2025 16:11:40 +0100 Subject: [PATCH 5/7] fix: fixing tests --- .../mutations/__tests__/importPaperForm.integration.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/back/src/forms/resolvers/mutations/__tests__/importPaperForm.integration.ts b/back/src/forms/resolvers/mutations/__tests__/importPaperForm.integration.ts index c0468556b4..2805da7c00 100644 --- a/back/src/forms/resolvers/mutations/__tests__/importPaperForm.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/importPaperForm.integration.ts @@ -108,7 +108,8 @@ describe("mutation / importPaperForm", () => { signedAt: "2019-12-20T00:00:00.000Z" as any, receivedBy: "Mr Destination", wasteAcceptationStatus: WasteAcceptationStatus.ACCEPTED, - quantityReceived: 1.0 + quantityReceived: 1.0, + quantityRefused: 0 }, processedInfo: { processedAt: "2019-12-22T00:00:00.000Z" as any, From 247d95febb9cd08d2f63ceabf8a7a93f770b39ee Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Fri, 7 Feb 2025 18:03:08 +0100 Subject: [PATCH 6/7] fix: starting to fix revision requests --- .../createFormRevisionRequest.integration.ts | 62 +++++++------------ 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts b/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts index 63131c0394..6d35779d17 100644 --- a/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts @@ -300,16 +300,11 @@ describe("Mutation.createFormRevisionRequest", () => { } } }); - expect(errors).toEqual([ - expect.objectContaining({ - message: - "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + - " Il lui appartient de mettre à jour son profil.", - extensions: { - code: "BAD_USER_INPUT" - } - }) - ]); + expect(errors[0].message).toBe( + "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + + " Il lui appartient de mettre à jour son profil." + ); + expect(errors[0].extensions?.code).toBe("BAD_USER_INPUT"); } ); @@ -349,16 +344,12 @@ describe("Mutation.createFormRevisionRequest", () => { } } }); - expect(errors).toEqual([ - expect.objectContaining({ - message: - "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + - " Il lui appartient de mettre à jour son profil.", - extensions: { - code: "BAD_USER_INPUT" - } - }) - ]); + + expect(errors[0].message).toBe( + "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + + " Il lui appartient de mettre à jour son profil." + ); + expect(errors[0].extensions?.code).toBe("BAD_USER_INPUT"); } ); @@ -398,16 +389,11 @@ describe("Mutation.createFormRevisionRequest", () => { } } }); - expect(errors).toEqual([ - expect.objectContaining({ - message: - "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + - " Il lui appartient de mettre à jour son profil.", - extensions: { - code: "BAD_USER_INPUT" - } - }) - ]); + expect(errors[0].message).toBe( + "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + + " Il lui appartient de mettre à jour son profil." + ); + expect(errors[0].extensions?.code).toBe("BAD_USER_INPUT"); } ); @@ -447,16 +433,11 @@ describe("Mutation.createFormRevisionRequest", () => { } } }); - expect(errors).toEqual([ - expect.objectContaining({ - message: - "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + - " Il lui appartient de mettre à jour son profil.", - extensions: { - code: "BAD_USER_INPUT" - } - }) - ]); + expect(errors[0].message).toBe( + "Le sous-profil sélectionné par l'établissement destinataire ne lui permet pas de prendre en charge ce type de déchet." + + " Il lui appartient de mettre à jour son profil." + ); + expect(errors[0].extensions?.code).toBe("BAD_USER_INPUT"); } ); @@ -577,6 +558,7 @@ describe("Mutation.createFormRevisionRequest", () => { readableId: getReadableId(), ownerId: user.id, quantityReceived: 2.4, + quantityRefused: 0, wasteAcceptationStatus: "ACCEPTED", receivedAt: "2022-03-20T00:00:00.000Z", receivedBy: "John Doe", From 7c8a72eb45bc61e3fcf02aca2f3c8dd528bed865 Mon Sep 17 00:00:00 2001 From: GaelFerrand Date: Mon, 10 Feb 2025 10:17:07 +0100 Subject: [PATCH 7/7] feat: added fix for revision requests --- .../createFormRevisionRequest.integration.ts | 68 ++++++++++++++++++- .../mutations/createFormRevisionRequest.ts | 15 +++- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts b/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts index 6d35779d17..6cef12b4b8 100644 --- a/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts +++ b/back/src/forms/resolvers/mutations/__tests__/createFormRevisionRequest.integration.ts @@ -1438,7 +1438,73 @@ describe("Mutation.createFormRevisionRequest", () => { recipientCompanySiret: recipientCompany.siret, wasteAcceptationStatus: Status.ACCEPTED, quantityReceived: 10, - receivedAt: new Date() + receivedAt: new Date(), + createdAt: new Date("2025-04-01") + } + }); + + // When + const { mutate } = makeClient(user); + const { errors } = await mutate< + Pick, + MutationCreateFormRevisionRequestArgs + >(CREATE_FORM_REVISION_REQUEST, { + variables: { + input: { + formId: bsdd.id, + content: { + wasteAcceptationStatus: WasteAcceptationStatus.REFUSED, + wasteRefusalReason: "Raison", + quantityReceived: 10, + quantityRefused: 10 + }, + comment: "A comment", + authoringCompanySiret: company.siret! + } + } + }); + + // Then + expect(errors).toBeUndefined(); + + const revisionRequest = + await prisma.bsddRevisionRequest.findFirstOrThrow({ + where: { bsddId: bsdd.id } + }); + + expect(revisionRequest.wasteAcceptationStatus).toEqual( + WasteAcceptationStatus.REFUSED + ); + expect(revisionRequest.wasteRefusalReason).toEqual("Raison"); + expect(revisionRequest.quantityReceived).toEqual(10); + expect(revisionRequest.quantityRefused).toEqual(10); + } + ); + + it.each([Status.ACCEPTED, Status.TEMP_STORER_ACCEPTED])( + "can review BSD wasteAcceptationStatus without quantityRefused if status is %p for legacy BSDs", + async status => { + // Given + const { company: recipientCompany } = await userWithCompanyFactory( + "ADMIN", + { + companyTypes: [CompanyType.WASTEPROCESSOR], + wasteProcessorTypes: [ + WasteProcessorType.DANGEROUS_WASTES_INCINERATION + ] + } + ); + const { user, company } = await userWithCompanyFactory("ADMIN"); + const bsdd = await formFactory({ + ownerId: user.id, + opt: { + status, + emitterCompanySiret: company.siret, + recipientCompanySiret: recipientCompany.siret, + wasteAcceptationStatus: Status.ACCEPTED, + quantityReceived: 10, + receivedAt: new Date(), + createdAt: new Date("2025-01-01") } }); diff --git a/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts b/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts index b5f7687f27..93851d29e7 100644 --- a/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts +++ b/back/src/forms/resolvers/mutations/createFormRevisionRequest.ts @@ -376,9 +376,15 @@ async function getFlatContent( ); } } else { - await bsddRevisionRequestSchema.validate(flatContent, { - strict: true - }); + await bsddRevisionRequestSchema.validate( + { + ...flatContent, + createdAt: bsdd.createdAt + }, + { + strict: true + } + ); } // Double-check the waste quantities @@ -477,6 +483,9 @@ const bsddRevisionRequestWasteQuantitiesSchema = yup.object({ const bsddRevisionRequestSchema: yup.SchemaOf = yup .object({ + // On a besoin de la date de création pour faire des checks sur + // certains champs (comme quantityRefused) + createdAt: yup.date(), isCanceled: yup.bool().transform(v => (v === null ? false : v)), recipientCap: yup.string().nullable(), wasteDetailsCode: yup