Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corrections cahier de recette Annexe 2 et entreposage provisoire #4014

Merged
merged 8 commits into from
Mar 7, 2025
3 changes: 2 additions & 1 deletion back/src/forms/__tests__/form-converter.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ describe("expandFormFromDb", () => {
wasteAcceptationStatus: null,
wasteRefusalReason: null,
receivedAt: null,
receivedBy: null
receivedBy: null,
signedAt: null
},
destination: {
cap: "CAP",
Expand Down
3 changes: 2 additions & 1 deletion back/src/forms/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,8 @@ export function expandFormFromDb(
wasteAcceptationStatus: form.wasteAcceptationStatus,
wasteRefusalReason: form.wasteRefusalReason,
receivedAt: processDate(form.receivedAt),
receivedBy: form.receivedBy
receivedBy: form.receivedBy,
signedAt: form.signedAt
},
transporter: forwardedInTransporter
? expandTransporterFromDb(forwardedInTransporter)
Expand Down
4 changes: 3 additions & 1 deletion back/src/forms/pdf/components/BsddPdf.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,9 @@ export function BsddPdf({
</p>
<AcceptationFields
{...form.temporaryStorageDetail?.temporaryStorer}
signedAt={form.signedAt} //check this
signedAt={
form.temporaryStorageDetail?.temporaryStorer?.signedAt
}
/>
<p>
Nom :{" "}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ describe("signTransportForm", () => {
it("should sign transport from temporary storage", async () => {
const temporaryStorage = await userWithCompanyFactory("ADMIN");
const transporter = await userWithCompanyFactory("ADMIN");
await transporterReceiptFactory({ company: transporter.company });
const emittedAt = new Date("2018-12-11T00:00:00.000Z");
const takenOverAt = new Date("2018-12-12T00:00:00.000Z");

Expand Down Expand Up @@ -499,6 +500,7 @@ describe("signTransportForm", () => {
it("should sign transport from temporary storage when plates are valid", async () => {
const temporaryStorage = await userWithCompanyFactory("ADMIN");
const transporter = await userWithCompanyFactory("ADMIN");
await transporterReceiptFactory({ company: transporter.company });
const emittedAt = new Date("2018-12-11T00:00:00.000Z");
const takenOverAt = new Date("2018-12-12T00:00:00.000Z");

Expand Down Expand Up @@ -555,6 +557,7 @@ describe("signTransportForm", () => {
it("should throw an error when signing transport from temporary storage and plates are invalid", async () => {
const temporaryStorage = await userWithCompanyFactory("ADMIN");
const transporter = await userWithCompanyFactory("ADMIN");
await transporterReceiptFactory({ company: transporter.company });
const emittedAt = new Date("2018-12-11T00:00:00.000Z");
const takenOverAt = new Date("2018-12-12T00:00:00.000Z");

Expand Down Expand Up @@ -604,6 +607,7 @@ describe("signTransportForm", () => {
it("should sign transport from temporary storage with security code", async () => {
const temporaryStorage = await userWithCompanyFactory("ADMIN");
const transporter = await userWithCompanyFactory("ADMIN");
await transporterReceiptFactory({ company: transporter.company });
const emittedAt = new Date("2018-12-11T00:00:00.000Z");
const takenOverAt = new Date("2018-12-12T00:00:00.000Z");

Expand Down Expand Up @@ -701,6 +705,115 @@ describe("signTransportForm", () => {
expect(errors).not.toBeUndefined();
});

it("should throw an error when signing transport from temporary storage if plates are not provided and mode is ROAD", async () => {
const temporaryStorage = await userWithCompanyFactory("ADMIN");
const transporter = await userWithCompanyFactory("ADMIN");
await transporterReceiptFactory({ company: transporter.company });
const emittedAt = new Date("2018-12-11T00:00:00.000Z");
const takenOverAt = new Date("2018-12-12T00:00:00.000Z");
const form = await formWithTempStorageFactory({
ownerId: temporaryStorage.user.id,
opt: {
status: "SIGNED_BY_TEMP_STORER",
recipientCompanySiret: temporaryStorage.company.siret,
recipientCompanyName: temporaryStorage.company.name
},
forwardedInOpts: {
emittedAt: emittedAt,
emittedBy: temporaryStorage.user.name,
transporters: {
create: {
transporterCompanySiret: transporter.company.siret,
transporterCompanyName: transporter.company.name,
transporterTransportMode: "ROAD",
transporterNumberPlate: null,
number: 1
}
}
}
});

const { mutate } = makeClient(transporter.user);
const { errors } = await mutate<
Pick<Mutation, "signTransportForm">,
MutationSignTransportFormArgs
>(SIGN_TRANSPORT_FORM, {
variables: {
id: form.id,
input: {
takenOverAt: takenOverAt.toISOString() as unknown as Date,
takenOverBy: transporter.user.name,
transporterNumberPlate: null
}
}
});

expect(errors).toEqual([
expect.objectContaining({
message: "La plaque d'immatriculation est requise"
})
]);
});

it("should sign transport from temporary storage if plates are not provided and mode is not ROAD", async () => {
const temporaryStorage = await userWithCompanyFactory("ADMIN");
const transporter = await userWithCompanyFactory("ADMIN");
await transporterReceiptFactory({ company: transporter.company });
const emittedAt = new Date("2018-12-11T00:00:00.000Z");
const takenOverAt = new Date("2018-12-12T00:00:00.000Z");
const form = await formWithTempStorageFactory({
ownerId: temporaryStorage.user.id,
opt: {
status: "SIGNED_BY_TEMP_STORER",
recipientCompanySiret: temporaryStorage.company.siret,
recipientCompanyName: temporaryStorage.company.name
},
forwardedInOpts: {
emittedAt: emittedAt,
emittedBy: temporaryStorage.user.name,
transporters: {
create: {
transporterCompanySiret: transporter.company.siret,
transporterCompanyName: transporter.company.name,
transporterTransportMode: "SEA",
transporterNumberPlate: null,
number: 1
}
}
}
});

const { mutate } = makeClient(transporter.user);
const { data, errors } = await mutate<
Pick<Mutation, "signTransportForm">,
MutationSignTransportFormArgs
>(SIGN_TRANSPORT_FORM, {
variables: {
id: form.id,
input: {
takenOverAt: takenOverAt.toISOString() as unknown as Date,
takenOverBy: transporter.user.name,
transporterNumberPlate: null
}
}
});

expect(errors).toBeUndefined();

expect(data.signTransportForm).toEqual(
expect.objectContaining({
status: "RESENT",
temporaryStorageDetail: expect.objectContaining({
signedAt: takenOverAt.toISOString(),
signedBy: temporaryStorage.user.name,

takenOverAt: takenOverAt.toISOString(),
takenOverBy: transporter.user.name
})
})
);
});

it("should throw an error if signed by an intermediary", async () => {
const intermediary = await userWithCompanyFactory("ADMIN");
const emitter = await userWithCompanyFactory("ADMIN");
Expand Down
39 changes: 23 additions & 16 deletions back/src/forms/resolvers/mutations/signTransportForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { getFormRepository } from "../../repository";
import { getTransporterCompanyOrgId } from "@td/constants";
import { runInTransaction } from "../../../common/repository/helper";
import { sumPackagingInfos } from "../../repository/helper";
import { validateBeforeTransport, plateSchemaFn } from "../../validation";
import { validateBeforeTransport, transporterSchemaFn } from "../../validation";
import { Permission } from "../../../permissions";
import { enqueueUpdatedBsdToIndex } from "../../../queue/producers/elastic";
import { recipifyFormInput } from "../../recipify";
Expand Down Expand Up @@ -333,12 +333,30 @@ const signatures: Partial<
const existingFullForm = await getFullForm(existingForm);

const transporter = getFirstTransporterSync(existingFullForm.forwardedIn!);
const signingTransporterOrgId = getTransporterCompanyOrgId(transporter)!;
await checkCanSignFor(
getTransporterCompanyOrgId(transporter)!,
signingTransporterOrgId,
user,
Permission.BsdCanSignTransport,
args.securityCode
);
const transporterNumberPlate =
args.input.transporterNumberPlate ?? transporter?.transporterNumberPlate;

const transporterTransportMode =
args.input.transporterTransportMode ??
transporter?.transporterTransportMode;

const transporterSchema = transporterSchemaFn({ signingTransporterOrgId });

const receiptFields = await getFormReceiptField(transporter);

await transporterSchema.validate({
...transporter,
transporterNumberPlate,
transporterTransportMode,
...receiptFields
});

const formUpdateInput: Prisma.FormUpdateInput = {
forwardedIn: {
Expand All @@ -349,9 +367,9 @@ const signatures: Partial<
transporters: {
updateMany: {
data: {
transporterNumberPlate:
args.input.transporterNumberPlate ??
transporter?.transporterNumberPlate
transporterNumberPlate,
transporterTransportMode,
...receiptFields
},
where: { number: 1 }
}
Expand All @@ -365,17 +383,6 @@ const signatures: Partial<
}
};

await plateSchemaFn().validate(
{
transporterNumberPlate:
args.input.transporterNumberPlate ??
transporter?.transporterNumberPlate
},
{
abortEarly: false
}
);

const updatedForm = await getFormRepository(user).update(
{ id: existingFullForm.id, status: existingFullForm.status },
{
Expand Down
3 changes: 2 additions & 1 deletion back/src/forms/typeDefs/bsdd.objects.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -376,9 +376,10 @@ type TemporaryStorer {
quantityAccepted: Float
wasteAcceptationStatus: WasteAcceptationStatus
wasteRefusalReason: String

receivedAt: DateTime
receivedBy: String
"Date à laquelle le déchet a été accepté ou refusé (case 13)"
signedAt: DateTime
}

"Destination finale après entreposage provisoire ou reconditionement"
Expand Down
13 changes: 0 additions & 13 deletions back/src/forms/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1069,19 +1069,6 @@ export const validatePlates = (transporterNumberPlate: string) => {
return true;
};

// Schema dedicated to validate plates on signTransportForm SIGNED_BY_TEMP_STORER
export const plateSchemaFn = () =>
yup.object({
transporterNumberPlate: yup
.string()
.nullable()
.test(transporterNumberPlate => {
return transporterNumberPlate
? validatePlates(transporterNumberPlate)
: true;
})
});

export const transporterSchemaFn: FactorySchemaOf<
Pick<FormValidationContext, "signingTransporterOrgId">,
Transporter
Expand Down
2 changes: 1 addition & 1 deletion front/src/Apps/Dashboard/dashboardServices.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ describe("dashboardServices", () => {
}
},
permissions,
"actTab"
"toCollectTab"
);
expect(result).toEqual(SIGNER);
});
Expand Down
2 changes: 1 addition & 1 deletion front/src/Apps/Dashboard/dashboardServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ export const getSignByProducerBtnLabel = (
isSameSiretTransporter(currentSiret, bsd) &&
permissions.includes(UserPermission.BsdCanSignTransport)
) {
if (isBsdd(bsd.type)) {
if (isBsdd(bsd.type) && isToCollectTab) {
return SIGNER;
}
if (isBsdasri(bsd.type)) {
Expand Down
13 changes: 10 additions & 3 deletions front/src/Apps/Forms/Components/PackagingList/PackagingForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,16 @@ function PackagingForm({
packagingsLength > 1
? // Un conditionnement en citerne ou benne exclut le mélange avec
// tout autre type de conditionnement
packagingTypeOptions.filter(
o => o.value !== Packagings.Citerne && o.value !== Packagings.Benne
)
packagingTypeOptions.filter(o => {
return (
// tra-16064 - cas particulier si les conditionnements ont été calculés
// automatiquement à partir de la liste des annexes 2, on peut se retrouver
// avec des conditionnements incohérents et on veut quand même pouvoir afficher
// Citerne ou Benne dans la liste des options disponibles.
o.value === packaging.type ||
(o.value !== Packagings.Citerne && o.value !== Packagings.Benne)
);
})
: packagingTypeOptions;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ export function FormJourneySummary({ form }: FormJourneySummaryProps) {
variant={
form.temporaryStorageDetail.emittedAt
? "complete"
: (form.transporters ?? []).every(t => Boolean(t.takenOverAt))
: (form.isDirectSupply && form.emittedAt) ||
(!form.isDirectSupply &&
(form.transporters ?? []).every(t =>
Boolean(t.takenOverAt)
))
? // Actif si tous les transporteurs ont signé, sinon en attente
"active"
: "incomplete"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ export function FormWasteEmissionSummary({
.filter((name, index, fields) => fields.indexOf(name) === index)
);

// On ne doit pas pouvoir éditer la liste des contenants ou la plaque immat
// lors d'un acheminement direct par pipeline ou convoyeur sauf s'il s'agit
// de la signature du TTR après entreposage provisoire
const isDirectSupply =
form.temporaryStorageDetail && form.emittedAt ? false : form.isDirectSupply;

return (
<>
<DataList>
Expand Down Expand Up @@ -104,7 +110,7 @@ export function FormWasteEmissionSummary({
</button>
</DataListDescription>
</DataListItem>
{!form.isDirectSupply && (
{!isDirectSupply && (
<DataListItem>
<DataListTerm>Contenant(s)</DataListTerm>
<DataListDescription>
Expand Down Expand Up @@ -157,22 +163,23 @@ export function FormWasteEmissionSummary({
</DataListDescription>
</DataListItem>
)}
{form.emitter?.type !== EmitterType.Appendix1Producer && (
<DataListItem>
<DataListTerm>Plaque d'immatriculation</DataListTerm>
<DataListDescription>
{values.transporterNumberPlate}
{form.emitter?.type !== EmitterType.Appendix1Producer &&
!isDirectSupply && (
<DataListItem>
<DataListTerm>Plaque d'immatriculation</DataListTerm>
<DataListDescription>
{values.transporterNumberPlate}

<button
type="button"
onClick={() => addField("transporterNumberPlate")}
className="tw-ml-2"
>
<IconPaperWrite color="blue" />
</button>
</DataListDescription>
</DataListItem>
)}
<button
type="button"
onClick={() => addField("transporterNumberPlate")}
className="tw-ml-2"
>
<IconPaperWrite color="blue" />
</button>
</DataListDescription>
</DataListItem>
)}
</DataList>
{fields.length > 0 && (
<div className="tw-mb-4">
Expand Down
Loading