From 04d80857fea017cd860f989ba677f88b44030cb4 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Mon, 6 Jan 2025 12:54:39 +0100 Subject: [PATCH 1/5] =?UTF-8?q?CSP=20:=20autoriser=20la=20r=C3=A9cup=C3=A9?= =?UTF-8?q?ration=20de=20fichier=20depuis=20github?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- macantine/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/macantine/settings.py b/macantine/settings.py index e638f62e0..339d3d610 100644 --- a/macantine/settings.py +++ b/macantine/settings.py @@ -494,6 +494,7 @@ "wss://client.relay.crisp.chat", "entreprise.data.gouv.fr", "plateforme.adresse.data.gouv.fr", + "raw.githubusercontent.com/betagouv/ma-cantine/", # data/schemas/imports/ ) if DEBUG: CSP_CONNECT_SRC += CSP_DEBUG_DOMAINS From 29424f9aca12cc896e4c15187c01f227020ba94e Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Mon, 6 Jan 2025 12:55:11 +0100 Subject: [PATCH 2/5] =?UTF-8?q?Mise=20=C3=A0=20jour=20du=20schema=20des=20?= =?UTF-8?q?achats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/schemas/imports/achats.json | 88 +++++++++++++++++------- frontend/src/views/PurchasesImporter.vue | 86 ++++++----------------- 2 files changed, 83 insertions(+), 91 deletions(-) diff --git a/data/schemas/imports/achats.json b/data/schemas/imports/achats.json index c282838c3..bfb3d42c3 100644 --- a/data/schemas/imports/achats.json +++ b/data/schemas/imports/achats.json @@ -3,85 +3,121 @@ "fields": [ { "constraints": { + "pattern": "^[0-9]{14}$", "required": true }, - "description": "Le SIRET de la cantine ayant réalisé l'achat", + "description": "La cantine avec ce SIRET doit être déjà enregistrée sur notre plateforme.", + "example": "000 000 000 00000", + "format": "default", "name": "siret", - "pattern": "^[0-9]{14}$", + "title": "Le SIRET de la cantine ayant réalisé l'achat", "type": "string" }, { "constraints": { "required": true }, - "description": "Une description de l'achat", + "description": "", + "example": "Pommes de terre", + "format": "default", "name": "description", + "title": "Une description de l'achat", "type": "string" }, { "constraints": { "required": true }, - "description": "Le nom du fournisseur", + "description": "", + "example": "Le traiteur du village", + "format": "default", "name": "fournisseur", + "title": "Le nom du fournisseur", "type": "string" }, { "constraints": { "required": true }, - "description": "La date de l'achat", + "description": "", + "example": "2022-01-30", "format": "%Y-%m-%d", "name": "date", + "title": "La date de l'achat", "type": "date" }, { "constraints": { "required": true }, - "description": "Le prix HT de l'achat", + "description": "", + "example": "3290.23", + "format": "default", "name": "prix_ht", + "title": "Le prix HT de l'achat", "type": "number" }, { "constraints": { + "enum": [ + "VIANDES_VOLAILLES", + "CHARCUTERIE", + "PRODUITS_DE_LA_MER", + "FRUITS_ET_LEGUMES", + "PRODUITS_LAITIERS", + "BOULANGERIE", + "BOISSONS", + "AUTRES" + ], "required": true }, - "description": "La famille de produits de l'achat", - "enum": [ - "VIANDES_VOLAILLES", - "CHARCUTERIE", - "PRODUITS_DE_LA_MER", - "FRUITS_ET_LEGUMES", - "PRODUITS_LAITIERS", - "BOULANGERIE", - "BOISSONS", - "AUTRES" - ], + "description": "", + "example": "VIANDES_VOLAILLES", + "format": "default", "name": "famille_produits", + "title": "La famille de produits de l'achat", "type": "string" }, { "constraints": { + "enum": [ + "BIO", + "LABEL_ROUGE", + "AOCAOP", + "IGP", + "STG", + "HVE", + "PECHE_DURABLE", + "RUP", + "COMMERCE_EQUITABLE", + "FERMIER", + "EXTERNALITES", + "PERFORMANCE", + "FRANCE", + "SHORT_DISTRIBUTION", + "LOCAL" + ], + "enum_multiple": true, "pattern": "(?:(?:^|;)(BIO|LABEL_ROUGE|AOCAOP|IGP|STG|HVE|PECHE_DURABLE|RUP|COMMERCE_EQUITABLE|FERMIER|EXTERNALITES|PERFORMANCE|FRANCE|SHORT_DISTRIBUTION|LOCAL))+$", - "required": false + "required": true }, - "description": "Les caractéristiques de l'achat", + "description": "", + "example": "BIO,IGP", + "format": "default", "name": "caracteristiques", + "title": "Les caractéristiques de l'achat", "type": "string" }, { "constraints": { + "enum": ["AUTOUR_SERVICE", "DEPARTMENT", "REGION", "AUTRE"], "required": true }, - "description": "La définition de local si l'achat a la caractéristique de LOCAL", - "enum": [ - "AUTOUR_SERVICE", - "DEPARTMENT", - "REGION", - "AUTRE" - ], + "description": "Obligatoire si l'achat a la caractéristique de LOCAL.", + "example": "AUTOUR_SERVICE", + "format": "default", "name": "definition_local", + "title": "La définition de local", "type": "string" } ], diff --git a/frontend/src/views/PurchasesImporter.vue b/frontend/src/views/PurchasesImporter.vue index ad9f53c6a..e30dbeb34 100644 --- a/frontend/src/views/PurchasesImporter.vue +++ b/frontend/src/views/PurchasesImporter.vue @@ -110,12 +110,12 @@ - {{ field.title }} {{ field.name }} + {{ field.title }} {{ field.type }} {{ field.example }} - {{ field.optional ? "✘" : "✔" }} + {{ field.constraints ?? required ? "✔" : "✘" }} @@ -151,14 +151,15 @@ import FileDrop from "@/components/FileDrop" import PurchasesTable from "@/components/PurchasesTable" import validators from "@/validators" -import Constants from "@/constants" + +// script to import the json from https://github.com/betagouv/ma-cantine/blob/import-de-masse-rendre-le-header-obligatoire-achats/data/schemas/imports/achats.json +// and then paste it here export default { name: "ImportPurchases", components: { FileDrop, PurchasesTable }, data() { const user = this.$store.state.loggedUser - const numberFormatExample = "En format 1234/1234.5/1234.56." return { file: undefined, canteens: undefined, @@ -169,73 +170,28 @@ export default { seconds: undefined, importInProgress: false, duplicatePurchases: null, - documentation: [ - { - title: "siret", - name: "SIRET de la cantine ayant réalisé l'achat", - description: "La cantine avec ce SIRET doit être déjà enregistrée sur notre plateforme.", - type: "14 chiffres, avec ou sans espaces", - example: "000 000 000 00000", - }, - { - title: "description", - name: "Description de l'achat", - example: "Pommes de terre", - type: "Texte libre", - }, - { - title: "fournisseur", - name: "Fournisseur", - example: "Le traiteur du village", - type: "Texte libre", - }, - { - title: "date", - name: "Date d'achat", - type: "Date en format AAAA-MM-JJ", - example: "2022-01-30", - }, - { - title: "prix_ht", - name: "Prix HT", - description: numberFormatExample, - type: "Chiffre", - example: "3290.23", - }, - { - title: "famille_produits", - name: "Famille de produits", - description: `Options acceptées : ${Object.keys(Constants.ProductFamilies).map( - (x) => " " + x + "" - )}`, - type: "Texte (choix unique)", - example: `${Object.keys(Constants.ProductFamilies)[0]}`, - }, - { - title: "caracteristiques", - name: "Caractéristiques", - description: `Options acceptées : ${Object.keys(Constants.Characteristics).map( - (x) => " " + x + "" - )}. Spécifiez plusieurs en séparant avec un ,.`, - type: "Texte", - example: `${Object.keys(Constants.Characteristics)[0]},${Object.keys(Constants.Characteristics)[3]}`, - }, - { - title: "definition_local", - name: "Définition de local", - description: `Obligatoire si l'achat a la caractéristique de LOCAL. Options acceptées : ${Object.keys( - Constants.LocalDefinitions - ).map((x) => " " + x + "")}.`, - type: "Texte (choix unique)", - example: `${Object.keys(Constants.LocalDefinitions)[0]}`, - }, - ], + documentation: [], // see mounted validators, isStaff: user.isStaff, duplicateFile: false, } }, + mounted() { + this.fetchSchema() + }, methods: { + fetchSchema() { + console.log("fetchSchema") + fetch( + "https://raw.githubusercontent.com/betagouv/ma-cantine/raphodn/import-de-masse-rendre-le-header-obligatoire-achats-json/data/schemas/imports/achats.json" + ) + .then((response) => response.json()) + .then((json) => { + // console.log(json.fields) + // console.log(this.documentation) + this.documentation = json.fields + }) + }, upload() { this.importInProgress = true this.duplicateFile = false From 095dc7ec333aa6772eeb658facce12a08e5637ed Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Mon, 6 Jan 2025 17:41:45 +0100 Subject: [PATCH 3/5] temp changes frontend --- frontend/src/views/PurchasesImporter.vue | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/frontend/src/views/PurchasesImporter.vue b/frontend/src/views/PurchasesImporter.vue index e30dbeb34..3766f2f93 100644 --- a/frontend/src/views/PurchasesImporter.vue +++ b/frontend/src/views/PurchasesImporter.vue @@ -112,10 +112,20 @@ {{ field.name }} {{ field.title }} - + +

{{ field.description }}

+

+ Options acceptées : {{ field.constraints.enum.join(", ") }}. +

+

+ Spécifiez plusieurs options en séparant avec un + , + . +

+ {{ field.type }} {{ field.example }} - {{ field.constraints ?? required ? "✔" : "✘" }} + {{ field.constraints && field.constraints.required ? "✔" : "✘" }} @@ -152,9 +162,6 @@ import FileDrop from "@/components/FileDrop" import PurchasesTable from "@/components/PurchasesTable" import validators from "@/validators" -// script to import the json from https://github.com/betagouv/ma-cantine/blob/import-de-masse-rendre-le-header-obligatoire-achats/data/schemas/imports/achats.json -// and then paste it here - export default { name: "ImportPurchases", components: { FileDrop, PurchasesTable }, @@ -181,14 +188,11 @@ export default { }, methods: { fetchSchema() { - console.log("fetchSchema") fetch( "https://raw.githubusercontent.com/betagouv/ma-cantine/raphodn/import-de-masse-rendre-le-header-obligatoire-achats-json/data/schemas/imports/achats.json" ) .then((response) => response.json()) .then((json) => { - // console.log(json.fields) - // console.log(this.documentation) this.documentation = json.fields }) }, From 8619a2b6ecf1035698e1f3051870e5ced7505061 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Tue, 7 Jan 2025 08:46:21 +0100 Subject: [PATCH 4/5] Add schema field type mapping --- frontend/src/constants.js | 8 ++++++++ frontend/src/views/PurchasesImporter.vue | 21 +++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/frontend/src/constants.js b/frontend/src/constants.js index 2266866ea..43584c2ff 100644 --- a/frontend/src/constants.js +++ b/frontend/src/constants.js @@ -5,6 +5,14 @@ export default Object.freeze({ ERROR: 3, IDLE: 4, }, + SchemaTypes: { + siret: "14 chiffres, avec ou sans espaces", + string: "Texte", + string_enum: "Texte (choix unique)", + string_enum_multiple: "Texte (choix multiples)", + number: "Chiffre", + date: "Date (au format AAAA-MM-JJ)", + }, DefaultDiagnostics: { id: null, year: null, diff --git a/frontend/src/views/PurchasesImporter.vue b/frontend/src/views/PurchasesImporter.vue index 3766f2f93..90ba99c68 100644 --- a/frontend/src/views/PurchasesImporter.vue +++ b/frontend/src/views/PurchasesImporter.vue @@ -115,7 +115,11 @@

{{ field.description }}

- Options acceptées : {{ field.constraints.enum.join(", ") }}. + Options acceptées : + + {{ item }} + , +

Spécifiez plusieurs options en séparant avec un @@ -123,7 +127,7 @@ .

- {{ field.type }} + {{ getSchemaFieldType(field) }} {{ field.example }} {{ field.constraints && field.constraints.required ? "✔" : "✘" }} @@ -161,6 +165,7 @@ import FileDrop from "@/components/FileDrop" import PurchasesTable from "@/components/PurchasesTable" import validators from "@/validators" +import Constants from "@/constants" export default { name: "ImportPurchases", @@ -196,6 +201,18 @@ export default { this.documentation = json.fields }) }, + getSchemaFieldType(field) { + if (field.name in Constants.SchemaTypes) { + return Constants.SchemaTypes[field.name] + } + if (field.constraints && field.constraints.enum) { + if (field.constraints.enum_multiple) { + return Constants.SchemaTypes[`${field.type}_enum_multiple`] + } + return Constants.SchemaTypes[`${field.type}_enum`] + } + return Constants.SchemaTypes[field.type] + }, upload() { this.importInProgress = true this.duplicateFile = false From 8548751654904bd742deb28a2db7a56ca69877f0 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Tue, 7 Jan 2025 10:58:52 +0100 Subject: [PATCH 5/5] =?UTF-8?q?Passer=20les=20champs=20famille=5Fproduits,?= =?UTF-8?q?=20caracteristiques=20&=20definition=5Flocal=20=C3=A0=20require?= =?UTF-8?q?d=20false?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/schemas/imports/achats.json | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/data/schemas/imports/achats.json b/data/schemas/imports/achats.json index bfb3d42c3..036f290cf 100644 --- a/data/schemas/imports/achats.json +++ b/data/schemas/imports/achats.json @@ -69,7 +69,7 @@ "BOISSONS", "AUTRES" ], - "required": true + "required": false }, "description": "", "example": "VIANDES_VOLAILLES", @@ -99,7 +99,7 @@ ], "enum_multiple": true, "pattern": "(?:(?:^|;)(BIO|LABEL_ROUGE|AOCAOP|IGP|STG|HVE|PECHE_DURABLE|RUP|COMMERCE_EQUITABLE|FERMIER|EXTERNALITES|PERFORMANCE|FRANCE|SHORT_DISTRIBUTION|LOCAL))+$", - "required": true + "required": false }, "description": "", "example": "BIO,IGP", @@ -110,8 +110,13 @@ }, { "constraints": { - "enum": ["AUTOUR_SERVICE", "DEPARTMENT", "REGION", "AUTRE"], - "required": true + "enum": [ + "AUTOUR_SERVICE", + "DEPARTMENT", + "REGION", + "AUTRE" + ], + "required": false }, "description": "Obligatoire si l'achat a la caractéristique de LOCAL.", "example": "AUTOUR_SERVICE",