Merge branch 'feature/66_seo' into dev
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
#### 2.5.0 ()
|
||||||
|
|
||||||
|
- Renforcement du SEO avec une arborescence permettant l'accès aux marchés et des snippets JSON-LD
|
||||||
|
|
||||||
##### 2.4.1 (22 janvier 2026)
|
##### 2.4.1 (22 janvier 2026)
|
||||||
|
|
||||||
- Meilleure gestion des colonnes absentes du schéma
|
- Meilleure gestion des colonnes absentes du schéma
|
||||||
|
|||||||
+7
-1
@@ -13,6 +13,10 @@ development = os.getenv("DEVELOPMENT").lower() == "true"
|
|||||||
|
|
||||||
meta_tags = [
|
meta_tags = [
|
||||||
{"name": "viewport", "content": "width=device-width, initial-scale=1"},
|
{"name": "viewport", "content": "width=device-width, initial-scale=1"},
|
||||||
|
{
|
||||||
|
"name": "keywords",
|
||||||
|
"content": "commande publique, decp, marchés publics, données essentielles",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if development:
|
if development:
|
||||||
@@ -25,6 +29,7 @@ app = Dash(
|
|||||||
compress=True,
|
compress=True,
|
||||||
meta_tags=meta_tags,
|
meta_tags=meta_tags,
|
||||||
)
|
)
|
||||||
|
|
||||||
# COSMO (belle font, blue),
|
# COSMO (belle font, blue),
|
||||||
# UNITED (rouge, ubuntu font),
|
# UNITED (rouge, ubuntu font),
|
||||||
# LUMEN (gros séparateur, blue clair),
|
# LUMEN (gros séparateur, blue clair),
|
||||||
@@ -142,7 +147,8 @@ navbar = dbc.Navbar(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
for page in page_registry.values()
|
for page in page_registry.values()
|
||||||
if page["name"] not in ["Acheteur", "Titulaire", "Marché"]
|
if page["name"]
|
||||||
|
in ["Recherche", "À propos", "Tableau", "Statistiques"]
|
||||||
],
|
],
|
||||||
className="ms-auto",
|
className="ms-auto",
|
||||||
navbar=True,
|
navbar=True,
|
||||||
|
|||||||
@@ -254,7 +254,8 @@ summary > h3 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CSS for the /a-propos page Layout and Table of Contents */
|
/* CSS for the /a-propos page Layout and Table of Contents
|
||||||
|
Généré par Gemini 3.0 Pro */
|
||||||
|
|
||||||
.a-propos-container {
|
.a-propos-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
+10
-2
@@ -169,14 +169,22 @@ def get_sources_tables(source_path) -> html.Div:
|
|||||||
+ pl.lit("</a>")
|
+ pl.lit("</a>")
|
||||||
).alias("nom")
|
).alias("nom")
|
||||||
)
|
)
|
||||||
df = df.drop("url")
|
df = df.drop("url", "unique")
|
||||||
df = df.sort(by=["nb_marchés"], descending=True)
|
df = df.sort(by=["nb_marchés"], descending=True)
|
||||||
|
|
||||||
|
columns = {
|
||||||
|
"nom": "Nom de la source",
|
||||||
|
"organisation": "Responsable de publication",
|
||||||
|
"nb_marchés": "Nb de marchés",
|
||||||
|
"nb_acheteurs": "Nb d'acheteurs",
|
||||||
|
"code": "Code",
|
||||||
|
}
|
||||||
|
|
||||||
datatable = dash_table.DataTable(
|
datatable = dash_table.DataTable(
|
||||||
id="source_table",
|
id="source_table",
|
||||||
columns=[
|
columns=[
|
||||||
{
|
{
|
||||||
"name": i,
|
"name": columns[i],
|
||||||
"id": i,
|
"id": i,
|
||||||
"presentation": "markdown",
|
"presentation": "markdown",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -122,6 +122,14 @@ Rien d’exceptionnel, je respecte simplement la loi, qui dit que certains outil
|
|||||||
|
|
||||||
J’utilise pour cela [Matomo](https://matomo.org/), un outil [libre](https://matomo.org/free-software/), paramétré pour être en conformité avec [la recommandation « Cookies »](https://www.cnil.fr/fr/solutions-pour-les-cookies-de-mesure-daudience) de la CNIL. Cela signifie que votre adresse IP, par exemple, est anonymisée avant d’être enregistrée. Il m’est donc impossible d’associer vos visites sur ce site à votre personne."""
|
J’utilise pour cela [Matomo](https://matomo.org/), un outil [libre](https://matomo.org/free-software/), paramétré pour être en conformité avec [la recommandation « Cookies »](https://www.cnil.fr/fr/solutions-pour-les-cookies-de-mesure-daudience) de la CNIL. Cela signifie que votre adresse IP, par exemple, est anonymisée avant d’être enregistrée. Il m’est donc impossible d’associer vos visites sur ce site à votre personne."""
|
||||||
),
|
),
|
||||||
|
html.H4(
|
||||||
|
"Liste des marchés par département", id="liste_marches"
|
||||||
|
),
|
||||||
|
dcc.Markdown(
|
||||||
|
"""
|
||||||
|
- [Marchés par département](/departements)
|
||||||
|
"""
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
# Table of Contents Column
|
# Table of Contents Column
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from src.callbacks import get_top_org_table
|
|||||||
from src.figures import DataTable, point_on_map
|
from src.figures import DataTable, point_on_map
|
||||||
from src.utils import (
|
from src.utils import (
|
||||||
df,
|
df,
|
||||||
|
df_acheteurs,
|
||||||
filter_table_data,
|
filter_table_data,
|
||||||
format_number,
|
format_number,
|
||||||
get_annuaire_data,
|
get_annuaire_data,
|
||||||
@@ -20,7 +21,12 @@ from src.utils import (
|
|||||||
|
|
||||||
|
|
||||||
def get_title(acheteur_id: str = None) -> str:
|
def get_title(acheteur_id: str = None) -> str:
|
||||||
return f"Acheteur {acheteur_id} | decp.info"
|
acheteur_nom = (
|
||||||
|
df_acheteurs.filter(pl.col("acheteur_id") == acheteur_id)
|
||||||
|
.select("acheteur_nom")
|
||||||
|
.item()
|
||||||
|
)
|
||||||
|
return f"Marchés publics attribués par {acheteur_nom} | decp.info"
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import polars as pl
|
||||||
|
from dash import Input, Output, callback, dcc, html, register_page
|
||||||
|
|
||||||
|
from src.utils import departements, df_acheteurs_departement, df_titulaires_departement
|
||||||
|
|
||||||
|
name = "Département"
|
||||||
|
|
||||||
|
|
||||||
|
def get_title(code):
|
||||||
|
return f"Marchés publics de {departements[code]['departement']} | decp.info"
|
||||||
|
|
||||||
|
|
||||||
|
def get_description(code):
|
||||||
|
return f"Marchés publics passés dans le département {departements[code]['departement']} | decp.info"
|
||||||
|
|
||||||
|
|
||||||
|
register_page(
|
||||||
|
__name__,
|
||||||
|
path_template="/departements/<code>",
|
||||||
|
title=get_title,
|
||||||
|
description=get_description,
|
||||||
|
order=50,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
|
||||||
|
layout = html.Div(
|
||||||
|
[
|
||||||
|
dcc.Location(id="departement_url", refresh="callback-nav"),
|
||||||
|
html.Div(id="departement_marches"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@callback(
|
||||||
|
Output(component_id="departement_marches", component_property="children"),
|
||||||
|
Input(component_id="departement_url", component_property="pathname"),
|
||||||
|
)
|
||||||
|
def departement_marches(url):
|
||||||
|
departement = url.split("/")[-1]
|
||||||
|
|
||||||
|
def make_link_list(org_type) -> list:
|
||||||
|
link_list = []
|
||||||
|
if org_type == "acheteur":
|
||||||
|
df = df_acheteurs_departement
|
||||||
|
elif org_type == "titulaire":
|
||||||
|
df = df_titulaires_departement
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
df = df.filter(pl.col(f"{org_type}_departement_code") == departement)
|
||||||
|
|
||||||
|
for row in df.iter_rows(named=True):
|
||||||
|
li = html.Li(
|
||||||
|
[
|
||||||
|
dcc.Link(
|
||||||
|
row[f"{org_type}_nom"],
|
||||||
|
href=url + f"/{org_type}/{row[f'{org_type}_id']}",
|
||||||
|
title=f"Marchés publics de {row[f'{org_type}_nom']}",
|
||||||
|
),
|
||||||
|
" ",
|
||||||
|
dcc.Link(
|
||||||
|
"(page dédiée)",
|
||||||
|
href=f"/{org_type}s/{row[f'{org_type}_id']}",
|
||||||
|
title=f"Page dédiée aux marchés publics de {row[f'{org_type}_nom']}",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
link_list.append(li)
|
||||||
|
return link_list
|
||||||
|
|
||||||
|
content = [
|
||||||
|
html.H3("Acheteurs publics du département"),
|
||||||
|
html.Ul(make_link_list("acheteur")),
|
||||||
|
html.H3("Titulaires du département"),
|
||||||
|
html.Ul(make_link_list("titulaire")),
|
||||||
|
]
|
||||||
|
|
||||||
|
return content
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from dash import dcc, html, register_page
|
||||||
|
|
||||||
|
from src.utils import departements
|
||||||
|
|
||||||
|
name = "Départements"
|
||||||
|
|
||||||
|
register_page(
|
||||||
|
__name__,
|
||||||
|
path="/departements",
|
||||||
|
title="Marchés par département | decp.info",
|
||||||
|
name="Départements",
|
||||||
|
description="Tous les marchés publics, classés par départements",
|
||||||
|
)
|
||||||
|
|
||||||
|
layout = html.Div(
|
||||||
|
[
|
||||||
|
html.H3("Départements"),
|
||||||
|
html.Ul(
|
||||||
|
[
|
||||||
|
html.Li(dcc.Link(d["departement"], href=f"/departements/{k}"))
|
||||||
|
for k, d in departements.items()
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import polars as pl
|
||||||
|
from dash import Input, Output, callback, dcc, html, register_page
|
||||||
|
|
||||||
|
from src.utils import (
|
||||||
|
df_acheteurs,
|
||||||
|
df_acheteurs_marches,
|
||||||
|
df_titulaires,
|
||||||
|
df_titulaires_marches,
|
||||||
|
)
|
||||||
|
|
||||||
|
name = "Liste des marchés publics"
|
||||||
|
|
||||||
|
|
||||||
|
def make_org_nom_verbe(org_type, org_id) -> tuple:
|
||||||
|
if org_type == "titulaire":
|
||||||
|
df = df_titulaires
|
||||||
|
verbe = "remportés"
|
||||||
|
elif org_type == "acheteur":
|
||||||
|
df = df_acheteurs
|
||||||
|
verbe = "attribués"
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
org_nom = (
|
||||||
|
df.filter(pl.col(f"{org_type}_id") == org_id).select(f"{org_type}_nom").item()
|
||||||
|
)
|
||||||
|
|
||||||
|
return org_nom, verbe
|
||||||
|
|
||||||
|
|
||||||
|
def get_title(code, org_type, org_id):
|
||||||
|
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||||
|
|
||||||
|
return f"Marchés publics {verbe} par {org_nom} | decp.info"
|
||||||
|
|
||||||
|
|
||||||
|
def get_description(code, org_type, org_id):
|
||||||
|
org_nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||||
|
|
||||||
|
return f"Liste complète des marchés publics {verbe} par {org_nom} et publiés par decp.info. Cliquez sur les liens pour consulter les détails de chaque marché."
|
||||||
|
|
||||||
|
|
||||||
|
register_page(
|
||||||
|
__name__,
|
||||||
|
path_template="/departements/<code>/<org_type>/<org_id>",
|
||||||
|
title=get_title,
|
||||||
|
description=get_description,
|
||||||
|
order=40,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
|
||||||
|
layout = html.Div(
|
||||||
|
[
|
||||||
|
dcc.Location(id="liste_marches_url", refresh="callback-nav"),
|
||||||
|
html.Div(id="liste_marches"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@callback(
|
||||||
|
Output(component_id="liste_marches", component_property="children"),
|
||||||
|
Input(component_id="liste_marches_url", component_property="pathname"),
|
||||||
|
)
|
||||||
|
def liste_marches(url):
|
||||||
|
org_type = url.split("/")[-2]
|
||||||
|
org_id = url.split("/")[-1]
|
||||||
|
|
||||||
|
def make_link_list() -> list:
|
||||||
|
link_list = []
|
||||||
|
if org_type == "acheteur":
|
||||||
|
df = df_acheteurs_marches
|
||||||
|
elif org_type == "titulaire":
|
||||||
|
df = df_titulaires_marches
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
df = df.filter(pl.col(f"{org_type}_id") == org_id)
|
||||||
|
|
||||||
|
for row in df.iter_rows(named=True):
|
||||||
|
li = html.Li(
|
||||||
|
[
|
||||||
|
dcc.Link(
|
||||||
|
row["objet"],
|
||||||
|
href=f"/marches/{row['uid']}",
|
||||||
|
title=f"Marchés public attribué : {row['objet']}",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
link_list.append(li)
|
||||||
|
return link_list
|
||||||
|
|
||||||
|
nom, verbe = make_org_nom_verbe(org_type, org_id)
|
||||||
|
|
||||||
|
content = [
|
||||||
|
html.H3(f"Marchés publics {verbe} par {nom}"),
|
||||||
|
html.Ul(make_link_list()),
|
||||||
|
]
|
||||||
|
|
||||||
|
return content
|
||||||
+5
-6
@@ -34,9 +34,7 @@ layout = [
|
|||||||
dcc.Store(id="marche_data"),
|
dcc.Store(id="marche_data"),
|
||||||
dcc.Store(id="titulaires_data"),
|
dcc.Store(id="titulaires_data"),
|
||||||
dcc.Location(id="marche_url", refresh="callback-nav"),
|
dcc.Location(id="marche_url", refresh="callback-nav"),
|
||||||
html.Script(
|
html.Script(type="application/ld+json", id="marche_jsonld"),
|
||||||
type="application/ld+json", id="marche_jsonld", children=['{"test": "1"}']
|
|
||||||
),
|
|
||||||
dbc.Container(
|
dbc.Container(
|
||||||
className="marche_infos",
|
className="marche_infos",
|
||||||
children=[
|
children=[
|
||||||
@@ -114,7 +112,7 @@ def get_marche_data(url) -> tuple[dict, list]:
|
|||||||
Input("titulaires_data", "data"),
|
Input("titulaires_data", "data"),
|
||||||
)
|
)
|
||||||
def update_marche_info(marche, titulaires):
|
def update_marche_info(marche, titulaires):
|
||||||
def make_parameter(col):
|
def make_parameter(col, bold=True):
|
||||||
column_object = data_schema.get(col)
|
column_object = data_schema.get(col)
|
||||||
column_name = column_object.get("title") if column_object else col
|
column_name = column_object.get("title") if column_object else col
|
||||||
|
|
||||||
@@ -158,10 +156,11 @@ def update_marche_info(marche, titulaires):
|
|||||||
else:
|
else:
|
||||||
value = ""
|
value = ""
|
||||||
|
|
||||||
param_content = html.P([column_name, " : ", html.Strong(value)])
|
value = html.Strong(value) if bold else value
|
||||||
|
param_content = html.P([column_name, " : ", value])
|
||||||
return param_content
|
return param_content
|
||||||
|
|
||||||
marche_objet = make_parameter("objet")
|
marche_objet = make_parameter("objet", bold=False)
|
||||||
|
|
||||||
marche_infos = [
|
marche_infos = [
|
||||||
make_parameter("id"),
|
make_parameter("id"),
|
||||||
|
|||||||
+60
-2
@@ -18,8 +18,9 @@ from src.utils import (
|
|||||||
)
|
)
|
||||||
from utils import prepare_table_data
|
from utils import prepare_table_data
|
||||||
|
|
||||||
update_date = os.path.getmtime(os.getenv("DATA_FILE_PARQUET_PATH"))
|
update_date_timestamp = os.path.getmtime(os.getenv("DATA_FILE_PARQUET_PATH"))
|
||||||
update_date = datetime.fromtimestamp(update_date).strftime("%d/%m/%Y")
|
update_date = datetime.fromtimestamp(update_date_timestamp).strftime("%d/%m/%Y")
|
||||||
|
update_date_iso = datetime.fromtimestamp(update_date_timestamp).isoformat()
|
||||||
|
|
||||||
|
|
||||||
name = "Tableau"
|
name = "Tableau"
|
||||||
@@ -48,6 +49,63 @@ datatable = html.Div(
|
|||||||
|
|
||||||
layout = [
|
layout = [
|
||||||
dcc.Location(id="tableau_url", refresh=False),
|
dcc.Location(id="tableau_url", refresh=False),
|
||||||
|
html.Script(
|
||||||
|
type="application/ld+json",
|
||||||
|
id="dataset_jsonld",
|
||||||
|
children=[
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org/",
|
||||||
|
"@type": "Dataset",
|
||||||
|
"name": "Données essentielles des marchés publics français (DECP)",
|
||||||
|
"description": "Données de marchés publics exhaustives décrivant les marchés publics attribués en France depuis 2018.",
|
||||||
|
"url": "https://decp.info",
|
||||||
|
"sameAs": "https://www.data.gouv.fr/datasets/608c055b35eb4e6ee20eb325",
|
||||||
|
"keywords": [
|
||||||
|
"marchés publics",
|
||||||
|
"commande publique",
|
||||||
|
"decp",
|
||||||
|
"public procurement",
|
||||||
|
],
|
||||||
|
"license": "https://www.etalab.gouv.fr/licence-ouverte-open-licence",
|
||||||
|
"isAccessibleForFree": True,
|
||||||
|
"creator": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"url": "https://colmo.tech",
|
||||||
|
"name": "Colmo",
|
||||||
|
"sameAs": "https://annuaire-entreprises.data.gouv.fr/entreprise/colmo-989393350",
|
||||||
|
"contactPoint": {
|
||||||
|
"@type": "ContactPoint",
|
||||||
|
"contactType": "Support et contact commercial",
|
||||||
|
"email": "colin@colmo.tech",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"includedInDataCatalog": {
|
||||||
|
"@type": "DataCatalog",
|
||||||
|
"name": "data.gouv.fr",
|
||||||
|
},
|
||||||
|
"distribution": [
|
||||||
|
{
|
||||||
|
"@type": "DataDownload",
|
||||||
|
"encodingFormat": "CSV",
|
||||||
|
"contentUrl": "https://www.data.gouv.fr/api/1/datasets/r/22847056-61df-452d-837d-8b8ceadbfc52",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "DataDownload",
|
||||||
|
"encodingFormat": "Parquet",
|
||||||
|
"contentUrl": "https://www.data.gouv.fr/api/1/datasets/r/11cea8e8-df3e-4ed1-932b-781e2635e432",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"temporalCoverage": f"2018-01-01/{update_date_iso[:10]}",
|
||||||
|
"spatialCoverage": {
|
||||||
|
"@type": "Place",
|
||||||
|
"address": {"countryCode": "FR"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indent=2,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
html.Div(
|
html.Div(
|
||||||
html.Details(
|
html.Details(
|
||||||
children=[
|
children=[
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from src.callbacks import get_top_org_table
|
|||||||
from src.figures import DataTable, point_on_map
|
from src.figures import DataTable, point_on_map
|
||||||
from src.utils import (
|
from src.utils import (
|
||||||
df,
|
df,
|
||||||
|
df_titulaires,
|
||||||
filter_table_data,
|
filter_table_data,
|
||||||
format_number,
|
format_number,
|
||||||
get_annuaire_data,
|
get_annuaire_data,
|
||||||
@@ -20,7 +21,12 @@ from src.utils import (
|
|||||||
|
|
||||||
|
|
||||||
def get_title(titulaire_id: str = None) -> str:
|
def get_title(titulaire_id: str = None) -> str:
|
||||||
return f"Titulaire {titulaire_id} | decp.info"
|
titulaire_nom = (
|
||||||
|
df_titulaires.filter(pl.col("titulaire_id") == titulaire_id)
|
||||||
|
.select("titulaire_nom")
|
||||||
|
.item()
|
||||||
|
)
|
||||||
|
return f"Marchés publics remportés par {titulaire_nom} | decp.info"
|
||||||
|
|
||||||
|
|
||||||
register_page(
|
register_page(
|
||||||
|
|||||||
+44
-24
@@ -145,11 +145,12 @@ def format_number(number) -> str:
|
|||||||
return number
|
return number
|
||||||
|
|
||||||
|
|
||||||
def unformat_montant(number: str) -> int:
|
def unformat_montant(number: str) -> float:
|
||||||
number = number.replace(" €", "")
|
number = number.replace(" €", "")
|
||||||
number = number.replace(" €", "").replace(" ", "")
|
number = number.replace(" €", "").replace(" ", "")
|
||||||
|
number = number.replace(",", ".")
|
||||||
number = number.strip()
|
number = number.strip()
|
||||||
return int(number)
|
return float(number)
|
||||||
|
|
||||||
|
|
||||||
def format_values(dff: pl.DataFrame) -> pl.DataFrame:
|
def format_values(dff: pl.DataFrame) -> pl.DataFrame:
|
||||||
@@ -701,27 +702,6 @@ def invert_columns(columns):
|
|||||||
return inverted_columns
|
return inverted_columns
|
||||||
|
|
||||||
|
|
||||||
df: pl.DataFrame = get_decp_data()
|
|
||||||
schema = df.collect_schema()
|
|
||||||
|
|
||||||
df_acheteurs = get_org_data(df, "acheteur")
|
|
||||||
df_titulaires = get_org_data(df, "titulaire")
|
|
||||||
|
|
||||||
departements = get_departements()
|
|
||||||
domain_name = (
|
|
||||||
"test.decp.info" if os.getenv("DEVELOPMENT").lower() == "true" else "decp.info"
|
|
||||||
)
|
|
||||||
meta_content = {
|
|
||||||
"image_url": f"https://{domain_name}/assets/decp.info.png",
|
|
||||||
"title": "decp.info - exploration des marchés publics français",
|
|
||||||
"description": (
|
|
||||||
"Explorez et analysez les données des marchés publics français avec cet outil libre et gratuit. "
|
|
||||||
"Pour une commande publique accessible à toutes et tous."
|
|
||||||
),
|
|
||||||
}
|
|
||||||
data_schema = get_data_schema()
|
|
||||||
|
|
||||||
|
|
||||||
def make_org_jsonld(org_id, org_type, org_name=None, type_org_id="SIRET") -> dict:
|
def make_org_jsonld(org_id, org_type, org_name=None, type_org_id="SIRET") -> dict:
|
||||||
org_types = {"acheteur": "GovernmentOrganization", "titulaire": "Organization"}
|
org_types = {"acheteur": "GovernmentOrganization", "titulaire": "Organization"}
|
||||||
address = None
|
address = None
|
||||||
@@ -747,7 +727,8 @@ def make_org_jsonld(org_id, org_type, org_name=None, type_org_id="SIRET") -> dic
|
|||||||
jsonld = {
|
jsonld = {
|
||||||
"@type": org_types[org_type],
|
"@type": org_types[org_type],
|
||||||
"name": org_name,
|
"name": org_name,
|
||||||
"url": f"https://decp.info/titulaires/{org_id}",
|
"url": f"https://decp.info/{org_type}s/{org_id}",
|
||||||
|
"sameAs": f"https://annuaire-entreprises.data.gouv.fr/etablissement/{org_id}",
|
||||||
"identifier": {
|
"identifier": {
|
||||||
"@type": "PropertyValue",
|
"@type": "PropertyValue",
|
||||||
"propertyID": type_org_id.lower(),
|
"propertyID": type_org_id.lower(),
|
||||||
@@ -759,3 +740,42 @@ def make_org_jsonld(org_id, org_type, org_name=None, type_org_id="SIRET") -> dic
|
|||||||
jsonld["address"] = address
|
jsonld["address"] = address
|
||||||
|
|
||||||
return jsonld
|
return jsonld
|
||||||
|
|
||||||
|
|
||||||
|
df: pl.DataFrame = get_decp_data()
|
||||||
|
schema = df.collect_schema()
|
||||||
|
|
||||||
|
df_acheteurs = get_org_data(df, "acheteur")
|
||||||
|
df_titulaires = get_org_data(df, "titulaire")
|
||||||
|
df_acheteurs_departement: pl.DataFrame = (
|
||||||
|
df_acheteurs.select(["acheteur_id", "acheteur_nom", "acheteur_departement_code"])
|
||||||
|
.unique()
|
||||||
|
.sort("acheteur_nom")
|
||||||
|
)
|
||||||
|
df_titulaires_departement: pl.DataFrame = (
|
||||||
|
df_titulaires.select(
|
||||||
|
["titulaire_id", "titulaire_nom", "titulaire_departement_code"]
|
||||||
|
)
|
||||||
|
.unique()
|
||||||
|
.sort("titulaire_nom")
|
||||||
|
)
|
||||||
|
df_acheteurs_marches: pl.DataFrame = (
|
||||||
|
df.select("uid", "objet", "acheteur_id").unique().sort("acheteur_id")
|
||||||
|
)
|
||||||
|
df_titulaires_marches: pl.DataFrame = (
|
||||||
|
df.select("uid", "objet", "titulaire_id").unique().sort("titulaire_id")
|
||||||
|
)
|
||||||
|
|
||||||
|
departements = get_departements()
|
||||||
|
domain_name = (
|
||||||
|
"test.decp.info" if os.getenv("DEVELOPMENT").lower() == "true" else "decp.info"
|
||||||
|
)
|
||||||
|
meta_content = {
|
||||||
|
"image_url": f"https://{domain_name}/assets/decp.info.png",
|
||||||
|
"title": "decp.info - exploration des marchés publics français",
|
||||||
|
"description": (
|
||||||
|
"Explorez et analysez les données des marchés publics français avec cet outil libre et gratuit. "
|
||||||
|
"Pour une commande publique accessible à toutes et tous."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
data_schema = get_data_schema()
|
||||||
|
|||||||
Reference in New Issue
Block a user