Skip to content

Commit 5c36ebe

Browse files
feat: permet l'accès en lecture seul au nouvel OC
1 parent 95a7aa9 commit 5c36ebe

20 files changed

+388
-115
lines changed
Lines changed: 132 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
1+
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
22
import { defineComponent, markRaw } from "vue";
33
import { createTestingPinia } from "@pinia/testing";
44
import { flushPromises, mount } from "@vue/test-utils";
@@ -12,15 +12,19 @@ import {
1212
CERTIFICATION_BODY_DECISION,
1313
LEVEL_AB,
1414
LEVEL_C1,
15+
LEVEL_C2,
16+
LEVEL_C3,
1517
LEVEL_CONVENTIONAL,
1618
} from "@/referentiels/ab.js";
1719

1820
import record from "@/utils/__fixtures__/record-with-features.json" assert { type: "json" };
1921
import EditForm from "@/components/forms/SingleItemCertificationBodyForm.vue";
2022
import TableComponent from "@/components/records/Table/index.vue";
23+
import { useUserStore } from "@/stores/user";
2124

2225
const pinia = createTestingPinia({ createSpy: vi.fn, stubActions: false });
2326
const recordStore = useRecordStore(pinia);
27+
const userStore = useUserStore(pinia);
2428
const permissions = usePermissions(pinia);
2529
const storage = useCartoBioStorage(pinia);
2630

@@ -51,97 +55,146 @@ describe("SingleItemCertificationBodyForm", () => {
5155
document.body.outerHTML = "";
5256
});
5357

54-
test("we assign a certification state", async () => {
55-
const form = wrapper.getComponent(EditForm);
56-
57-
// if "Conventionnel", there is no date field
58-
await form.find(`#conversion-${LEVEL_CONVENTIONAL}`).setValue();
59-
expect(form.find("#engagement_date").exists()).toEqual(false);
58+
describe("item is not readonly", async () => {
59+
beforeAll(async () => {
60+
userStore.user = {
61+
organismeCertificateur: {
62+
id: 1,
63+
},
64+
};
65+
});
66+
test("we assign a certification state", async () => {
67+
const form = wrapper.getComponent(EditForm);
6068

61-
// if AB, date field is not mandatory
62-
await form.find(`#conversion-${LEVEL_AB}`).setValue();
63-
expect(form.find("#engagement_date").attributes()).not.toHaveProperty("required");
69+
// if "Conventionnel", there is no date field
70+
await form.find(`#conversion-${LEVEL_CONVENTIONAL}`).setValue();
71+
expect(form.find("#engagement_date").exists()).toEqual(false);
6472

65-
// date field is mandatory otherwise
66-
await form.find(`#conversion-${LEVEL_C1}`).setValue();
67-
expect(form.find("#engagement_date").attributes()).toHaveProperty("required", "");
68-
});
73+
// if AB, date field is not mandatory
74+
await form.find(`#conversion-${LEVEL_AB}`).setValue();
75+
expect(form.find("#engagement_date").attributes()).not.toHaveProperty("required");
6976

70-
test("we toggle expanded annotations", async () => {
71-
const form = wrapper.getComponent(EditForm);
77+
// date field is mandatory otherwise
78+
await form.find(`#conversion-${LEVEL_C1}`).setValue();
79+
expect(form.find("#engagement_date").attributes()).toHaveProperty("required", "");
80+
});
7281

73-
// We have all the tags tags and no expand button
74-
expect(form.findAll(".fr-tags-group--annotations > .annotation-choice")).toHaveLength(5);
75-
expect(form.find(".fr-tags-group--annotations > .annotation--more").attributes()).toHaveProperty("hidden");
82+
test("we toggle expanded annotations", async () => {
83+
const form = wrapper.getComponent(EditForm);
7684

77-
// expect(form.find('.fr-tags-group--annotations > .annotation--more').attributes()).not.toHaveProperty('hidden')
78-
// await form.find('.fr-tags-group--annotations > .annotation--more button').trigger('click')
85+
// We have all the tags tags and no expand button
86+
expect(form.findAll(".fr-tags-group--annotations > .annotation-choice")).toHaveLength(5);
87+
expect(form.find(".fr-tags-group--annotations > .annotation--more").attributes()).toHaveProperty("hidden");
7988

80-
const expectedChoices = Object.keys(AnnotationTags);
81-
expect(form.findAll(".fr-tags-group--annotations > .annotation-choice")).toHaveLength(expectedChoices.length);
82-
});
89+
// expect(form.find('.fr-tags-group--annotations > .annotation--more').attributes()).not.toHaveProperty('hidden')
90+
// await form.find('.fr-tags-group--annotations > .annotation--more button').trigger('click')
8391

84-
test("we select three choices, and two reasons", async () => {
85-
const form = wrapper.getComponent(EditForm);
92+
const expectedChoices = Object.keys(AnnotationTags);
93+
expect(form.findAll(".fr-tags-group--annotations > .annotation-choice")).toHaveLength(expectedChoices.length);
94+
});
8695

87-
// We have 5 tags
88-
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.DOWNGRADED} button`).trigger("click");
89-
await form
90-
.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.REDUCED_CONVERSION_PERIOD} button`)
91-
.trigger("click");
92-
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.RISKY} button`).trigger("click");
96+
test("we select three choices, and two reasons", async () => {
97+
const form = wrapper.getComponent(EditForm);
98+
99+
// We have 5 tags
100+
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.DOWNGRADED} button`).trigger("click");
101+
await form
102+
.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.REDUCED_CONVERSION_PERIOD} button`)
103+
.trigger("click");
104+
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.RISKY} button`).trigger("click");
105+
106+
expect(form.find("#downgraded_state").element.value).toEqual(CERTIFICATION_BODY_DECISION.PENDING);
107+
expect(form.find("#downgraded_state").element.selectedOptions[0].textContent).toEqual("En cours de traitement");
108+
109+
expect(form.find("#reduced_conversion_period_state").element.value).toEqual(CERTIFICATION_BODY_DECISION.PENDING);
110+
expect(form.find("#reduced_conversion_period_state").element.selectedOptions[0].textContent).toEqual(
111+
"En cours de traitement",
112+
);
113+
114+
// we toggle and cancel the tag
115+
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.SURVEYED} button`).trigger("click");
116+
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.SURVEYED} button`).trigger("click");
117+
118+
await form.find("#reduced_conversion_period_state").setValue(CERTIFICATION_BODY_DECISION.REJECTED);
119+
await form.find("#downgraded_state").setValue(CERTIFICATION_BODY_DECISION.ACCEPTED);
120+
121+
// click and assess server update
122+
axios.__createMock.patch.mockResolvedValueOnce({ data: record });
123+
axios.__createMock.get.mockResolvedValueOnce({ data: record });
124+
await form.find(".fr-modal__footer button.fr-btn").trigger("click");
125+
126+
await flushPromises();
127+
expect(wrapper.findComponent(EditForm).exists()).toEqual(false);
128+
expect(axios.__createMock.patch).toHaveBeenCalled();
129+
expect(axios.__createMock.patch.mock.lastCall).toMatchObject([
130+
"/v2/audits/054f0d70-c3da-448f-823e-81fcf7c2bf6e/parcelles/2",
131+
{
132+
properties: {
133+
annotations: [
134+
{
135+
code: ANNOTATIONS.DOWNGRADED,
136+
metadata: {
137+
[ANNOTATIONS.METADATA_STATE]: CERTIFICATION_BODY_DECISION.ACCEPTED,
138+
},
139+
},
140+
{
141+
code: ANNOTATIONS.REDUCED_CONVERSION_PERIOD,
142+
metadata: {
143+
[ANNOTATIONS.METADATA_STATE]: CERTIFICATION_BODY_DECISION.REJECTED,
144+
},
145+
},
146+
{
147+
code: ANNOTATIONS.RISKY,
148+
},
149+
],
150+
},
151+
},
152+
{
153+
headers: {
154+
"If-Unmodified-Since": expect.any(String),
155+
},
156+
},
157+
]);
158+
});
159+
});
93160

94-
expect(form.find("#downgraded_state").element.value).toEqual(CERTIFICATION_BODY_DECISION.PENDING);
95-
expect(form.find("#downgraded_state").element.selectedOptions[0].textContent).toEqual("En cours de traitement");
161+
describe("item is readonly", async () => {
162+
beforeAll(async () => {
163+
userStore.user = {
164+
organismeCertificateur: {
165+
id: 2,
166+
},
167+
};
168+
});
169+
test("certification state are disabled", async () => {
170+
const form = wrapper.getComponent(EditForm);
171+
172+
expect(form.find(`#conversion-${LEVEL_CONVENTIONAL}`).isDisabled()).toEqual(true);
173+
expect(form.find(`#conversion-${LEVEL_C1}`).isDisabled()).toEqual(true);
174+
expect(form.find(`#conversion-${LEVEL_C2}`).isDisabled()).toEqual(true);
175+
expect(form.find(`#conversion-${LEVEL_C3}`).isDisabled()).toEqual(true);
176+
expect(form.find(`#conversion-${LEVEL_AB}`).isDisabled()).toEqual(true);
177+
});
96178

97-
expect(form.find("#reduced_conversion_period_state").element.value).toEqual(CERTIFICATION_BODY_DECISION.PENDING);
98-
expect(form.find("#reduced_conversion_period_state").element.selectedOptions[0].textContent).toEqual(
99-
"En cours de traitement",
100-
);
179+
test("annotations are disabled", async () => {
180+
const form = wrapper.getComponent(EditForm);
101181

102-
// we toggle and cancel the tag
103-
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.SURVEYED} button`).trigger("click");
104-
await form.find(`.fr-tags-group--annotations > .annotation--${ANNOTATIONS.SURVEYED} button`).trigger("click");
182+
// We have all the tags tags and no expand button
183+
expect(form.findAll(".fr-tags-group--annotations > .annotation-choice")).toHaveLength(5);
184+
expect(form.find(".fr-tags-group--annotations > .annotation--more").attributes()).toHaveProperty("hidden");
105185

106-
await form.find("#reduced_conversion_period_state").setValue(CERTIFICATION_BODY_DECISION.REJECTED);
107-
await form.find("#downgraded_state").setValue(CERTIFICATION_BODY_DECISION.ACCEPTED);
186+
// expect(form.find('.fr-tags-group--annotations > .annotation--more').attributes()).not.toHaveProperty('hidden')
187+
// await form.find('.fr-tags-group--annotations > .annotation--more button').trigger('click')
108188

109-
// click and assess server update
110-
axios.__createMock.patch.mockResolvedValueOnce({ data: record });
111-
axios.__createMock.get.mockResolvedValueOnce({ data: record });
112-
await form.find(".fr-modal__footer button.fr-btn").trigger("click");
189+
const expectedChoices = Object.keys(AnnotationTags);
190+
expect(form.findAll(".fr-tags-group--annotations > .annotation-choice")).toHaveLength(expectedChoices.length);
113191

114-
await flushPromises();
115-
expect(wrapper.findComponent(EditForm).exists()).toEqual(false);
116-
expect(axios.__createMock.patch).toHaveBeenCalled();
117-
expect(axios.__createMock.patch.mock.lastCall).toMatchObject([
118-
"/v2/audits/054f0d70-c3da-448f-823e-81fcf7c2bf6e/parcelles/2",
119-
{
120-
properties: {
121-
annotations: [
122-
{
123-
code: ANNOTATIONS.DOWNGRADED,
124-
metadata: {
125-
[ANNOTATIONS.METADATA_STATE]: CERTIFICATION_BODY_DECISION.ACCEPTED,
126-
},
127-
},
128-
{
129-
code: ANNOTATIONS.REDUCED_CONVERSION_PERIOD,
130-
metadata: {
131-
[ANNOTATIONS.METADATA_STATE]: CERTIFICATION_BODY_DECISION.REJECTED,
132-
},
133-
},
134-
{
135-
code: ANNOTATIONS.RISKY,
136-
},
137-
],
138-
},
139-
},
140-
{
141-
headers: {
142-
"If-Unmodified-Since": expect.any(String),
143-
},
144-
},
145-
]);
192+
const annotations = form.findAll(".fr-tags-group--annotations > .annotation-choice > button");
193+
expect(annotations[0].isDisabled()).toEqual(true);
194+
expect(annotations[1].isDisabled()).toEqual(true);
195+
expect(annotations[2].isDisabled()).toEqual(true);
196+
expect(annotations[3].isDisabled()).toEqual(true);
197+
expect(annotations[4].isDisabled()).toEqual(true);
198+
});
146199
});
147200
});

src/components/forms/SingleItemCertificationBodyForm.vue

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
:required="requiredName"
1313
:class="{ 'fr-input--error': nameErrors.size }"
1414
ref="autofocusedElement"
15+
:disabled="readonly"
1516
/>
1617
<div v-for="[id, result] in nameErrors" :key="id" class="fr-hint-text fr-error-text">
1718
{{ result.errorMessage }}.
@@ -41,6 +42,7 @@
4142
:feature-id="feature.properties.id"
4243
:cultures="patch.cultures"
4344
@change="($cultures) => (patch.cultures = $cultures)"
45+
:disabled-input="readonly"
4446
/>
4547
</AccordionSection>
4648
</AccordionGroup>
@@ -53,7 +55,7 @@
5355
>
5456
<ConversionLevelSelector
5557
:feature-id="feature.properties.id"
56-
:readonly="!permissions.canChangeConversionLevel"
58+
:readonly="!permissions.canChangeConversionLevel || readonly"
5759
v-model="patch.conversion_niveau"
5860
/>
5961

@@ -78,9 +80,10 @@
7880
v-if="permissions.canAddAnnotations"
7981
v-model="patch.annotations"
8082
:feature-id="feature.properties.id"
83+
:readonly="readonly"
8184
/>
8285

83-
<div class="fr-input-group">
86+
<div v-if="!readonly" class="fr-input-group">
8487
<label class="fr-label" for="auditeur_notes">Vos notes de certification (facultatif)</label>
8588
<textarea class="fr-input" id="auditeur_notes" name="auditeur_notes" v-model="patch.auditeur_notes" />
8689
</div>
@@ -92,7 +95,9 @@
9295

9396
<template #footer>
9497
<div class="fr-input-group">
95-
<button class="fr-btn" type="submit" form="single-feature-edit-form">Enregistrer</button>
98+
<button class="fr-btn" type="submit" form="single-feature-edit-form">
99+
{{ readonly ? "Fermer" : "Enregistrer" }}
100+
</button>
96101
</div>
97102
</template>
98103
</Modal>
@@ -130,6 +135,10 @@ const props = defineProps({
130135
type: Boolean,
131136
default: false,
132137
},
138+
readonly: {
139+
type: Boolean,
140+
default: false,
141+
},
133142
});
134143
const emit = defineEmits(["submit", "close"]);
135144
@@ -159,6 +168,10 @@ function requiresAction(properties) {
159168
}
160169
161170
const validate = () => {
171+
if (props.readonly) {
172+
emit("close");
173+
return;
174+
}
162175
const set = featuresSet.byFeature(props.feature.id, true);
163176
164177
if (set.size) {
@@ -169,7 +182,7 @@ const validate = () => {
169182
};
170183
171184
function handleClose() {
172-
if (featuresSet.isDirty) {
185+
if (featuresSet.isDirty && !props.readonly) {
173186
showCancelModal.value = true;
174187
} else {
175188
emit("close");
@@ -179,6 +192,10 @@ function handleClose() {
179192
onBeforeUnmount(() => featuresSet.setCandidate([]));
180193
181194
watch(patch, (properties) => {
195+
if (props.readonly) {
196+
return;
197+
}
198+
182199
featuresSet.setCandidate([
183200
{
184201
id: props.feature.id,

src/components/forms/fields/AnnotationsSelector.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
type="button"
1717
:aria-pressed="isSelected(annotationId)"
1818
@click="toggleAnnotation(annotationId)"
19+
:disabled="readonly"
1920
>
2021
{{ annotation.label }}
2122
</button>
@@ -93,6 +94,10 @@ const props = defineProps({
9394
required: true,
9495
default: () => [],
9596
},
97+
readonly: {
98+
type: Boolean,
99+
default: false,
100+
},
96101
});
97102
98103
const isUserExpanded = ref(false);

src/components/forms/fields/ConversionLevelSelector.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const props = defineProps({
3636
},
3737
readonly: {
3838
type: Boolean,
39-
default: () => false,
39+
default: false,
4040
},
4141
});
4242

src/components/forms/fields/CultureSelector.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ const props = defineProps({
9292
},
9393
disabledInput: {
9494
type: Boolean,
95-
default: () => false,
95+
default: false,
9696
},
9797
});
9898

src/components/forms/fields/CultureTypeSelector.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const props = defineProps({
5353
},
5454
disabledInput: {
5555
type: Boolean,
56-
default: () => false,
56+
default: false,
5757
},
5858
});
5959

0 commit comments

Comments
 (0)