Skip to content

Commit

Permalink
[Recette/tra-15501] Permettre la modification des informations d'un c…
Browse files Browse the repository at this point in the history
…ontenant à la signature de son opération et après son traitement pendant 60 jours (#3886)
  • Loading branch information
benoitguigal authored Jan 9, 2025
2 parents 71931cc + d58d508 commit 65eaece
Show file tree
Hide file tree
Showing 17 changed files with 356 additions and 99 deletions.
15 changes: 15 additions & 0 deletions back/src/bsffs/__tests__/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,21 @@ export function createBsffAfterAcceptation(
});
}

export function createBsffAfterRefusal(
companies: Required<BsffFactoryCompanies>,
opts: BsffFactoryOpts = {}
) {
return createBsffBeforeRefusal(companies, {
...opts,
data: { status: BsffStatus.REFUSED, ...opts.data },
packagingData: {
acceptationSignatureAuthor: "Juste Leblanc",
acceptationSignatureDate: new Date().toISOString(),
...opts.packagingData
}
});
}

export function createBsffBeforeOperation(
companies: Required<BsffFactoryCompanies>,
opts: BsffFactoryOpts = {}
Expand Down
33 changes: 33 additions & 0 deletions back/src/bsffs/__tests__/registry.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,39 @@ describe("toGenericWaste", () => {
expect(waste.emitterCompanyCity).toBe("Nantes");
expect(waste.emitterCompanyCountry).toBe("FR");
});

it(
"it should return accepted wasteCode and wasteDescription when there is" +
" only one packaging",
async () => {
const emitter = await userWithCompanyFactory();
const transporter = await userWithCompanyFactory();
const destination = await userWithCompanyFactory();

const bsff = await createBsffAfterAcceptation(
{ emitter, transporter, destination },
{
data: {
wasteCode: "14 06 01*",
wasteDescription: "HFC"
},
packagingData: {
acceptationWasteCode: "14 06 02*",
acceptationWasteDescription: "HFC 2"
}
}
);

const bsffForRegistry = await prisma.bsff.findUniqueOrThrow({
where: { id: bsff.id },
include: RegistryBsffInclude
});
const waste = toGenericWaste(bsffForRegistry);

expect(waste.wasteCode).toEqual("14 06 02*");
expect(waste.wasteDescription).toEqual("HFC 2");
}
);
});

describe("toIncomingWaste", () => {
Expand Down
7 changes: 6 additions & 1 deletion back/src/bsffs/pdf/BsffPdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ function BsffQuantity({
renderEmpty
}: Pick<Props, "bsff" | "renderEmpty">) {
const renderCheckboxState = !renderEmpty;

return (
<div className="BoxCol">
<p>
Expand All @@ -340,7 +341,11 @@ function BsffQuantity({
/>{" "}
Estimée
<br />
"QUANTITÉE ESTIMÉE CONFORMÉMENT AU 5.4.1.1.3.2" de l'ADR 2023
{bsff.weight?.isEstimate && (
<div>
"QUANTITÉE ESTIMÉE CONFORMÉMENT AU 5.4.1.1.3.2 de l'ADR"
</div>
)}
</span>
</div>
<div>Kilogramme(s) : {bsff.weight.value}</div>
Expand Down
2 changes: 1 addition & 1 deletion back/src/bsffs/pdf/generator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export async function buildPdf(bsff: BsffForBuildPdf, renderEmpty?: boolean) {
bsffForPdf = emptyValues(bsffForPdf);
}
const html = ReactDOMServer.renderToStaticMarkup(
<BsffPdf bsff={bsffForPdf} qrCode={qrCode} renderEmpty={true} />
<BsffPdf bsff={bsffForPdf} qrCode={qrCode} renderEmpty={renderEmpty} />
);
return generatePdf(html);
}
17 changes: 15 additions & 2 deletions back/src/bsffs/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,22 @@ export function toGenericWaste(bsff: RegistryBsff): GenericWaste {
country: emitterCompanyCountry
} = splitAddress(bsff.emitterCompanyAddress);

let wasteCode = bsff.wasteCode;
let wasteDescription = bsff.wasteDescription;

if (
bsff.packagings.length === 1 &&
bsff.packagings[0].acceptationSignatureDate
) {
const packaging = bsff.packagings[0];
wasteCode = packaging.acceptationWasteCode ?? wasteCode;
wasteDescription =
packaging.acceptationWasteDescription ?? wasteDescription;
}

return {
wasteDescription: bsff.wasteDescription,
wasteCode: bsff.wasteCode,
wasteDescription,
wasteCode,
wasteIsDangerous: true,
pop: false,
id: bsff.id,
Expand Down
8 changes: 7 additions & 1 deletion back/src/bsffs/repository/bsffPackaging/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,18 @@ export function buildUpdateBsffPackaging(
}
});

if (bsffPackaging.operationSignatureDate && args.data.operationCode) {
if (
// Il s'agit d'un changement sur le code de traitement du contenant
// qui est effectuée suite à la signature de l'opération via une correction.
// Nous devons donc recalculer le statut du BSFF au cas où l'on ait un
// changement Processed -> IntermediatelyProcessed
// ou IntermediatelyProcessed -> Processed
(bsffPackaging.operationSignatureDate && args.data.operationCode) ||
// Il s'agit d'une correction du statut d'acceptation qui est effectuée suite
// à la signature du refus. Nous devons donc recalculer le statut du BSFF au
// cas où il y ait un changement Refused => Accepted, Refused => PartiallyRefused
(bsffPackaging.acceptationSignatureDate && args.data.acceptationStatus)
) {
const bsff = await prisma.bsff.findUniqueOrThrow({
where: { id: bsffPackaging.bsffId },
include: { packagings: true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import makeClient from "../../../../__tests__/testClient";
import {
createBsffAfterOperation,
createBsffAfterReception,
createBsffAfterRefusal,
createBsffBeforeEmission,
createBsffBeforeOperation
} from "../../../__tests__/factories";
Expand Down Expand Up @@ -261,6 +262,105 @@ describe("Mutation.updateBsffPackaging", () => {
]);
});

test(
"less than 60 days after refusal > " +
" it should be possible to update acceptation status",
async () => {
const emitter = await userWithCompanyFactory("MEMBER");
const transporter = await userWithCompanyFactory("MEMBER");
const destination = await userWithCompanyFactory("MEMBER");
const bsff = await createBsffAfterRefusal(
{
emitter,
transporter,
destination
},
{ packagingData: { acceptationSignatureDate: new Date() } }
);

expect(bsff.status).toEqual("REFUSED");

const packagingId = bsff.packagings[0].id;

const { mutate } = makeClient(destination.user);
const { errors } = await mutate<
Pick<Mutation, "updateBsffPackaging">,
MutationUpdateBsffPackagingArgs
>(UPDATE_BSFF_PACKAGING, {
variables: {
id: packagingId,
input: {
numero: "nouveau-numero",
acceptation: {
date: new Date().toISOString() as any,
weight: 2,
status: "ACCEPTED",
refusalReason: null
}
}
}
});
expect(errors).toBeUndefined();

const updatedPackaging = await prisma.bsffPackaging.findUniqueOrThrow({
where: { id: packagingId },
include: { bsff: true }
});
expect(updatedPackaging.acceptationStatus).toEqual("ACCEPTED");
// status of bsff should be recalculated to ACCEPTED
expect(updatedPackaging.bsff.status).toEqual("ACCEPTED");
}
);

test(
"more than 60 days after refusal > " +
" it should not be possible to update acceptation status",
async () => {
const emitter = await userWithCompanyFactory("MEMBER");
const transporter = await userWithCompanyFactory("MEMBER");
const destination = await userWithCompanyFactory("MEMBER");
const bsff = await createBsffAfterRefusal(
{
emitter,
transporter,
destination
},
{ packagingData: { acceptationSignatureDate: new Date(0) } }
);

expect(bsff.status).toEqual("REFUSED");

const packagingId = bsff.packagings[0].id;

const { mutate } = makeClient(destination.user);
const { errors } = await mutate<
Pick<Mutation, "updateBsffPackaging">,
MutationUpdateBsffPackagingArgs
>(UPDATE_BSFF_PACKAGING, {
variables: {
id: packagingId,
input: {
numero: "nouveau-numero",
acceptation: {
date: new Date().toISOString() as any,
weight: 2,
status: "ACCEPTED",
refusalReason: null
}
}
}
});
expect(errors).toEqual([
expect.objectContaining({
message:
"Des champs ont été verrouillés via signature et ne peuvent plus être modifiés :" +
" Le champ acceptationRefusalReason a été verrouillé via signature et ne peut pas être modifié.," +
" Le champ acceptationStatus a été verrouillé via signature et ne peut pas être modifié."
})
]);
}
);

test(
"less than 60 days after operation >" +
" it should be possible to update acceptation and operation fields",
Expand Down
14 changes: 9 additions & 5 deletions back/src/bsffs/validation/bsffPackaging/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ function requireNextDestination(bsffPackaging: ZodBsffPackaging) {
}

function isBsffPackagingFieldSealed(bsffPackaging: ZodBsffPackaging) {
const lastSignatureDate =
bsffPackaging.operationSignatureDate ??
bsffPackaging.acceptationSignatureDate;

if (
!!bsffPackaging.operationSignatureDate &&
!!lastSignatureDate &&
// cas particulier : on ne permet pas de modifier un contenant qui est
// déjà réexpédié, regroupé ou reconditionné
!bsffPackaging.nextPackagingId &&
// tra-15501 Le destinataire peut modifier les informations du contenant
// (acceptation et opération) jusqu'à 60 jours après l'opération
differenceInDays(new Date(), bsffPackaging.operationSignatureDate) <= 60
// (acceptation et opération) jusqu'à 60 jours après l'opération ou le refus
differenceInDays(new Date(), lastSignatureDate) <= 60
) {
return false;
}
Expand All @@ -81,15 +85,15 @@ export const bsffPackagingEditionRules: BsffPackagingEditionRules = {
required: { from: "ACCEPTATION" }
},
acceptationStatus: {
sealed: { from: "ACCEPTATION" },
sealed: { from: "ACCEPTATION", when: isBsffPackagingFieldSealed },
required: { from: "ACCEPTATION" }
},
acceptationWeight: {
sealed: { from: "OPERATION", when: isBsffPackagingFieldSealed },
required: { from: "ACCEPTATION" }
},
acceptationRefusalReason: {
sealed: { from: "ACCEPTATION" },
sealed: { from: "ACCEPTATION", when: isBsffPackagingFieldSealed },
required: {
from: "ACCEPTATION",
when: p =>
Expand Down
Loading

0 comments on commit 65eaece

Please sign in to comment.