diff --git a/shared/types/src/hasura/contributions.ts b/shared/types/src/hasura/contributions.ts index f4e04d202..5e8c99679 100644 --- a/shared/types/src/hasura/contributions.ts +++ b/shared/types/src/hasura/contributions.ts @@ -135,8 +135,10 @@ export type ContributionMessageBlock = { id: string; label: string; contentAgreement: string; + contentAgreementWithoutLegal: string; contentLegal: string; contentNotHandled: string; + contentNotHandledWithoutLegal: string; }; export type ContributionAgreementMessage = { diff --git a/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateContent.test.ts b/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateContent.test.ts index fc37ac901..70a03a35a 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateContent.test.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateContent.test.ts @@ -39,7 +39,7 @@ describe("generateContent", () => { }; const result: ContributionContent = await generateContent( - mockContributions, + mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution ); @@ -55,7 +55,7 @@ describe("generateContent", () => { }; const result: ContributionContent = await generateContent( - mockContributions, + mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution ); @@ -73,7 +73,7 @@ describe("generateContent", () => { }; await expect( - generateContent(mockContributions, contribution) + generateContent(mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution) ).rejects.toThrowError( `Aucune contribution générique a été retrouvée pour la contribution [10 - 3239] (id générique non trouvé : unknown-type)` ); @@ -88,7 +88,7 @@ describe("generateContent", () => { }; await expect( - generateContent(mockContributions, contribution) + generateContent(mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution) ).rejects.toThrowError( "La contribution [2 - 1516] ne peut pas référencer une générique qui n'a pas de réponse" ); @@ -110,7 +110,7 @@ describe("generateContent", () => { (fetchFicheSp as jest.Mock).mockResolvedValue(mockFicheSpContent); const result: ContributionContent = await generateContent( - mockContributions, + mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution ); @@ -138,7 +138,7 @@ describe("generateContent", () => { (fetchFicheSp as jest.Mock).mockResolvedValue(mockFicheSpContent); const result: ContributionContent = await generateContent( - mockContributions, + mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution ); @@ -158,7 +158,7 @@ describe("generateContent", () => { }; await expect( - generateContent(mockContributions, contribution) + generateContent(mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution) ).rejects.toThrowError( 'Type de contribution generic inconnu "unknown_type" for [GENERIC_UNKNOWN_TYPE]' ); @@ -171,7 +171,7 @@ describe("generateContent", () => { }; const result: ContributionContent = await generateContent( - mockContributions, + mockContributions.find(({id}) => id === contribution.genericAnswerId), contribution ); diff --git a/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateMessageBlock.test.ts b/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateMessageBlock.test.ts index 0cfeed989..78625f11f 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateMessageBlock.test.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateMessageBlock.test.ts @@ -1,4 +1,8 @@ -import { ContributionContentType } from "@socialgouv/cdtn-types"; +import { + ContributionContentType, + ContributionDocumentJson, + DocumentElasticWithSource, +} from "@socialgouv/cdtn-types"; import { fetchMessageBlock } from "../fetchMessageBlock"; import { fetchAgreementMessage } from "../fetchAgreementMessage"; import { generateMessageBlock } from "../generateMessageBlock"; @@ -6,13 +10,14 @@ import { generateMessageBlock } from "../generateMessageBlock"; jest.mock("../fetchMessageBlock"); jest.mock("../fetchAgreementMessage"); -describe("generateMessageBlock", () => { - const mockContribution: any = { - questionId: "123", - contentType: "ANSWER", - idcc: "1234", - }; +const contributionGeneric: DocumentElasticWithSource | undefined = undefined; +const mockContribution: any = { + questionId: "123", + contentType: "ANSWER", + idcc: "1234", +}; +describe("generateMessageBlock", () => { beforeEach(() => { jest.clearAllMocks(); }); @@ -36,6 +41,7 @@ describe("generateMessageBlock", () => { mockContribution.contentType = contentType as ContributionContentType; const result: string | undefined = await generateMessageBlock( + contributionGeneric, mockContribution ); @@ -63,6 +69,7 @@ describe("generateMessageBlock", () => { mockContribution.contentType = contentType as ContributionContentType; mockContribution.idcc = "0000"; const result: string | undefined = await generateMessageBlock( + contributionGeneric, mockContribution ); @@ -75,24 +82,25 @@ describe("generateMessageBlock", () => { mockContribution.contentType = "UNKNOWN_TYPE"; mockContribution.idcc = "1234"; - await expect(generateMessageBlock(mockContribution)).rejects.toThrowError( - "Unknown content type" - ); + await expect( + generateMessageBlock(contributionGeneric, mockContribution) + ).rejects.toThrowError("Unknown content type"); }); it("should throw an error for unknown content type", async () => { mockContribution.contentType = null; mockContribution.idcc = "1234"; - await expect(generateMessageBlock(mockContribution)).rejects.toThrowError( - "Unknown content type" - ); + await expect( + generateMessageBlock(contributionGeneric, mockContribution) + ).rejects.toThrowError("Unknown content type"); }); it("should return undefined if no message block setup for the question", async () => { (fetchMessageBlock as jest.Mock).mockResolvedValue(undefined); const result: string | undefined = await generateMessageBlock( + contributionGeneric, mockContribution ); @@ -107,10 +115,70 @@ describe("generateMessageBlock", () => { ); const result: string | undefined = await generateMessageBlock( + contributionGeneric, mockContribution ); expect(fetchAgreementMessage).toHaveBeenCalledWith("1234"); expect(result).toEqual("fetchedAgreementMessage"); }); + + + }); +describe("Tests avec une contribution generic no cdt", () => { + let mockedContributionGeneric: DocumentElasticWithSource | undefined = undefined; + beforeEach(() => { + mockedContributionGeneric = { + contentType: "GENERIC_NO_CDT", + id: "id", + cdtnId: "cdtnId", + breadcrumbs: [], + title: "", + slug: "", + source: "contributions", + text: "text", + isPublished: true, + excludeFromSearch: false, + metaDescription: "metaDescription", + refs: [], + references: [], + questionIndex: 0, + questionId: "questionId", + questionName: "questionName", + linkedContent: [], + description: "description", + idcc: "0000", + type: "generic-no-cdt", + messageBlockGenericNoCDT: "messageBlockGenericNoCDT", + messageBlockGenericNoCDTUnextendedCC: "messageBlockGenericNoCDTUnextendedCC" + }; + (fetchMessageBlock as jest.Mock).mockResolvedValue({ + contentAgreementWithoutLegal: "agrement without legal", + contentNotHandledWithoutLegal: "content not handled without legal" + }); + (fetchAgreementMessage as jest.Mock).mockResolvedValue(undefined); + }) + it.each(["ANSWER", "SP"])("should throw a contentAgreementWithoutLegal", async (contentType) => { + + mockContribution.contentType = contentType; + mockContribution.idcc = "1234"; + + const messageBloc = await generateMessageBlock(mockedContributionGeneric, mockContribution); + + expect( + messageBloc + ).toEqual("agrement without legal"); + }); + + it.each(["NOTHING", "CDT", "UNFAVOURABLE"])("should throw a contentNotHandledWithoutLegal", async (contentType) => { + mockContribution.contentType = contentType; + mockContribution.idcc = "1234"; + + const messageBloc = await generateMessageBlock(mockedContributionGeneric, mockContribution); + + expect( + messageBloc + ).toEqual("content not handled without legal"); + }); +}) \ No newline at end of file diff --git a/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateReferences.test.ts b/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateReferences.test.ts index b4a8a16d7..1ec49ab3a 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateReferences.test.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/__tests__/generateReferences.test.ts @@ -37,7 +37,7 @@ describe("generateReferences", () => { }, ]; - const result = generateReferences(contributions, contrib); + const result = generateReferences(contributions[0], contrib); expect(result).toEqual([ { @@ -74,7 +74,7 @@ describe("generateReferences", () => { ], }; - const result = generateReferences([], contrib); + const result = generateReferences(undefined, contrib); expect(result).toEqual([ { @@ -92,7 +92,7 @@ describe("generateReferences", () => { const contrib: any = { contentType: "CDT", questionIndex: 1 }; expect(() => { - generateReferences([], contrib); + generateReferences(undefined, contrib); }).toThrowError(); }); diff --git a/targets/export-elasticsearch/src/ingester/contributions/fetchMessageBlock.ts b/targets/export-elasticsearch/src/ingester/contributions/fetchMessageBlock.ts index 56fbebc81..5b80119c9 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/fetchMessageBlock.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/fetchMessageBlock.ts @@ -11,6 +11,8 @@ query get_question($id: uuid!) { contentAgreement contentLegal contentNotHandled + contentAgreementWithoutLegal + contentNotHandledWithoutLegal } } } diff --git a/targets/export-elasticsearch/src/ingester/contributions/generate.ts b/targets/export-elasticsearch/src/ingester/contributions/generate.ts index 043da3339..d6f195b31 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/generate.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/generate.ts @@ -51,13 +51,16 @@ export async function generateContributions( for (let i = 0; i < contributions.length; i++) { const contrib = contributions[i]; + const contribGeneric = contributions.find( + (c) => c.questionId === contrib.questionId && c.idcc === "0000" + ); const highlight = ccnListWithHighlight[parseInt(contrib.idcc)]; - const content = await generateContent(contributions, contrib); + const content = await generateContent(contribGeneric, contrib); - const messageBlock = await generateMessageBlock(contrib); + const messageBlock = await generateMessageBlock(contribGeneric, contrib); - const references = generateReferences(contributions, contrib); + const references = generateReferences(contribGeneric, contrib); const ccUnextended = await fetchAgreementUnextended(); diff --git a/targets/export-elasticsearch/src/ingester/contributions/generateContent.ts b/targets/export-elasticsearch/src/ingester/contributions/generateContent.ts index d60f8495e..f3081a08d 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/generateContent.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/generateContent.ts @@ -6,7 +6,7 @@ import { import { fetchFicheSp } from "./fetchFicheSp"; export const generateContent = async ( - contributions: DocumentElasticWithSource[], + contribGeneric: DocumentElasticWithSource | undefined, contrib: DocumentElasticWithSource ): Promise => { switch (contrib.type) { @@ -29,25 +29,22 @@ export const generateContent = async ( }; } case "cdt": { - const cdtContrib = contributions.find( - (v) => v.id === contrib.genericAnswerId - ); - if (!cdtContrib) { + if (!contribGeneric) { throw new Error( `Aucune contribution générique a été retrouvée pour la contribution [${contrib.questionIndex} - ${contrib.idcc}] (id générique non trouvé : ${contrib.genericAnswerId})` ); } - if (cdtContrib.type === "generic-no-cdt") { + if (contribGeneric.type === "generic-no-cdt") { throw new Error( `La contribution [${contrib.questionIndex} - ${contrib.idcc}] ne peut pas référencer une générique qui n'a pas de réponse` ); } - if (cdtContrib.type === "content") { + if (contribGeneric.type === "content") { return { - content: cdtContrib.content, + content: contribGeneric.content, }; - } else if (cdtContrib.type === "fiche-sp") { - const ficheSpContent = await fetchFicheSp(cdtContrib.ficheSpId); + } else if (contribGeneric.type === "fiche-sp") { + const ficheSpContent = await fetchFicheSp(contribGeneric.ficheSpId); return { url: ficheSpContent.url, date: ficheSpContent.date, @@ -56,7 +53,7 @@ export const generateContent = async ( }; } throw new Error( - `Type de contribution generic inconnu "${cdtContrib.type}" for [${cdtContrib.id}]` + `Type de contribution generic inconnu "${contribGeneric.type}" for [${contribGeneric.id}]` ); } } diff --git a/targets/export-elasticsearch/src/ingester/contributions/generateMessageBlock.ts b/targets/export-elasticsearch/src/ingester/contributions/generateMessageBlock.ts index 836e2ecbd..c07272a6f 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/generateMessageBlock.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/generateMessageBlock.ts @@ -6,6 +6,7 @@ import { fetchMessageBlock } from "./fetchMessageBlock"; import { fetchAgreementMessage } from "./fetchAgreementMessage"; export const generateMessageBlock = async ( + contribGeneric: DocumentElasticWithSource | undefined, contrib: DocumentElasticWithSource ): Promise => { const agreementMessage = await fetchAgreementMessage(contrib.idcc); @@ -21,12 +22,24 @@ export const generateMessageBlock = async ( ) { return messageBlock.contentLegal; } else if (contrib.contentType === "ANSWER" || contrib.contentType === "SP") { + if ( + contribGeneric?.contentType === "GENERIC_NO_CDT" && + messageBlock.contentAgreementWithoutLegal + ) { + return messageBlock.contentAgreementWithoutLegal; + } return messageBlock.contentAgreement; } else if ( contrib.contentType === "NOTHING" || contrib.contentType === "CDT" || contrib.contentType === "UNFAVOURABLE" ) { + if ( + contribGeneric?.contentType === "GENERIC_NO_CDT" && + messageBlock.contentNotHandledWithoutLegal + ) { + return messageBlock.contentNotHandledWithoutLegal; + } return messageBlock.contentNotHandled; } throw new Error("Unknown content type"); diff --git a/targets/export-elasticsearch/src/ingester/contributions/generateReferences.ts b/targets/export-elasticsearch/src/ingester/contributions/generateReferences.ts index 72ffc302c..7efbac860 100644 --- a/targets/export-elasticsearch/src/ingester/contributions/generateReferences.ts +++ b/targets/export-elasticsearch/src/ingester/contributions/generateReferences.ts @@ -6,24 +6,21 @@ import { import { isReferencingGenericContribution } from "./helpers"; export const generateReferences = ( - contributions: DocumentElasticWithSource[], + contribGeneric: DocumentElasticWithSource | undefined, contrib: DocumentElasticWithSource ): ContributionRef[] => { if (isReferencingGenericContribution(contrib.contentType)) { - const cdtContrib = contributions.find( - (v) => v.questionIndex === contrib.questionIndex && v.idcc === "0000" - ); - if (!cdtContrib) { + if (!contribGeneric) { throw new Error( `Aucune contribution générique a été retrouvée pour la question ${contrib.questionIndex}` ); } - if (cdtContrib.type === "generic-no-cdt") { + if (contribGeneric.type === "generic-no-cdt") { throw new Error( `La contribution [${contrib.questionIndex} - ${contrib.idcc}] ne peut pas référencer une générique qui n'a pas de réponse` ); } - const result = [...contrib.references, ...cdtContrib.references]; + const result = [...contrib.references, ...contribGeneric.references]; return removeDuplicates(result); } return contrib.references; diff --git a/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx b/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx index 553adf32a..8fb1b5bda 100644 --- a/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx +++ b/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx @@ -143,6 +143,30 @@ export const EditQuestionForm = ({ /> + + } + aria-controls="Texte applicable si la convention collective est non traitée, non sélectionnée ou si la réponse est dépubliée" + id="contentLegal" + > + + Texte applicable si la convention collective est non + traitée et n'a pas de légal + + + + + + + + + + + } @@ -167,6 +191,30 @@ export const EditQuestionForm = ({ /> + + } + aria-controls="Texte applicable si la convention collective est non traitée, non sélectionnée ou si la réponse est dépubliée" + id="contentLegal" + > + + Texte applicable si la convention collective ne prévoit + rien et n'a pas de légal + + + + + + + + + + + } diff --git a/targets/frontend/src/components/contributions/questions/Question.query.ts b/targets/frontend/src/components/contributions/questions/Question.query.ts index 0346723ce..8b6f989f9 100644 --- a/targets/frontend/src/components/contributions/questions/Question.query.ts +++ b/targets/frontend/src/components/contributions/questions/Question.query.ts @@ -37,6 +37,8 @@ query SelectQuestion($questionId: uuid) { contentAgreement contentLegal contentNotHandled + contentNotHandledWithoutLegal + contentAgreementWithoutLegal id label } diff --git a/targets/frontend/src/components/contributions/type.ts b/targets/frontend/src/components/contributions/type.ts index cfccd33a2..430e602e6 100644 --- a/targets/frontend/src/components/contributions/type.ts +++ b/targets/frontend/src/components/contributions/type.ts @@ -40,7 +40,9 @@ export const messageSchema = z.object({ label: z.string(), contentAgreement: z.string(), contentLegal: z.string(), + contentAgreementWithoutLegal: z.string(), contentNotHandled: z.string(), + contentNotHandledWithoutLegal: z.string(), }); export type Message = z.infer; diff --git a/targets/hasura/metadata/databases/default/tables/contribution_question_messages.yaml b/targets/hasura/metadata/databases/default/tables/contribution_question_messages.yaml index 12e34d656..6f1842f8e 100644 --- a/targets/hasura/metadata/databases/default/tables/contribution_question_messages.yaml +++ b/targets/hasura/metadata/databases/default/tables/contribution_question_messages.yaml @@ -5,22 +5,30 @@ configuration: column_config: content_agreement: custom_name: contentAgreement + content_agreement_without_legal: + custom_name: contentAgreementWithoutLegal content_legal: custom_name: contentLegal content_not_handled: custom_name: contentNotHandled + content_not_handled_without_legal: + custom_name: contentNotHandledWithoutLegal custom_column_names: content_agreement: contentAgreement + content_agreement_without_legal: contentAgreementWithoutLegal content_legal: contentLegal content_not_handled: contentNotHandled + content_not_handled_without_legal: contentNotHandledWithoutLegal custom_root_fields: {} select_permissions: - role: super permission: columns: - content_agreement - - content_not_handled + - content_agreement_without_legal - content_legal + - content_not_handled + - content_not_handled_without_legal - id - label filter: {} diff --git a/targets/hasura/metadata/databases/default/tables/contribution_questions.yaml b/targets/hasura/metadata/databases/default/tables/contribution_questions.yaml index e4cb80ac6..4aa1e27d1 100644 --- a/targets/hasura/metadata/databases/default/tables/contribution_questions.yaml +++ b/targets/hasura/metadata/databases/default/tables/contribution_questions.yaml @@ -4,7 +4,13 @@ table: object_relationships: - name: message using: - foreign_key_constraint_on: message_id + manual_configuration: + column_mapping: + message_id: id + insertion_order: null + remote_table: + name: question_messages + schema: contribution array_relationships: - name: answers using: diff --git a/targets/hasura/migrations/default/1715781737558_alter_table_contribution_question_messages_add_column_content_agreement_without_legal/down.sql b/targets/hasura/migrations/default/1715781737558_alter_table_contribution_question_messages_add_column_content_agreement_without_legal/down.sql new file mode 100644 index 000000000..4515cbf58 --- /dev/null +++ b/targets/hasura/migrations/default/1715781737558_alter_table_contribution_question_messages_add_column_content_agreement_without_legal/down.sql @@ -0,0 +1,2 @@ +alter table "contribution"."question_messages" drop column "content_not_handled_without_legal"; +alter table "contribution"."question_messages" drop column "content_agreement_without_legal"; diff --git a/targets/hasura/migrations/default/1715781737558_alter_table_contribution_question_messages_add_column_content_agreement_without_legal/up.sql b/targets/hasura/migrations/default/1715781737558_alter_table_contribution_question_messages_add_column_content_agreement_without_legal/up.sql new file mode 100644 index 000000000..476444743 --- /dev/null +++ b/targets/hasura/migrations/default/1715781737558_alter_table_contribution_question_messages_add_column_content_agreement_without_legal/up.sql @@ -0,0 +1,13 @@ +alter table "contribution"."question_messages" add column "content_agreement_without_legal" text + null; +alter table "contribution"."question_messages" add column "content_not_handled_without_legal" text + null; + +update contribution.question_messages +set content_not_handled_without_legal = '

Ces informations sont issues de l’analyse de votre convention collective de branche étendue.

D’autres textes ou votre contrat de travail peuvent également prévoir des règles spécifiques sur ce sujet. Plusieurs cas de figure peuvent se présenter :

  • Si un accord d’entreprise (ou de groupe ou d’établissement) traite de ce sujet : c’est ce texte qui s’appliquera ;
  • Dans tous les cas, si le contrat de travail prévoit des règles plus favorables : il s’appliquera.

Attention, d’autres règles non étendues peuvent potentiellement vous être applicables.

', +content_agreement_without_legal = '

Ces informations sont issues de l’analyse des règles prévues par votre convention collective de branche étendue. Si une convention ou un accord d’entreprise (ou de groupe, ou d’établissement) existe dans votre entreprise, il s’appliquera, qu’il soit plus ou moins favorable. Toutefois, si votre contrat de travail contient des règles plus favorables, ce sont celles-ci qui s’appliqueront.

Attention, d’autres règles non étendues peuvent potentiellement vous être applicables.

' +where label = 'Message Bloc 3'; +update contribution.question_messages +set content_not_handled_without_legal = '

Ces informations sont issues de l’analyse de votre convention collective de branche étendue.

D’autres textes ou votre contrat de travail peuvent également prévoir des règles spécifiques sur ce sujet.

Plusieurs cas de figure peuvent se présenter :

  • Si un accord d’entreprise (ou de groupe ou d’établissement) traite de ce sujet : c’est ce texte qui s’appliquera ;
  • Dans tous les cas, si le contrat de travail prévoit des règles plus favorables : il s’appliquera.

Attention, d’autres règles non étendues peuvent potentiellement vous être applicables.

', +content_agreement_without_legal = '

Ces informations sont issues de l’analyse des règles prévues par votre convention collective de branche étendue. Si une convention ou un accord d’entreprise (ou de groupe, ou d’établissement) existant dans votre entreprise prévoit des garanties au moins équivalentes sur le même sujet, elles s’appliqueront, sauf si votre contrat de travail contient des règles plus favorables.

Attention, d’autres règles non étendues peuvent potentiellement vous être applicables.

' +where label = 'Message Bloc 2';