[DTP-Worker 20260730_085719] Auto exec · session 20260730_085719
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
"""Generation du graphe JSON-LD schema.org (hand-off pour injection dans les pages).
|
||||
|
||||
Un noeud `Organization` (marque publique · #4) + un noeud `listing_type`
|
||||
(defaut `Residence`) par projet du master.
|
||||
|
||||
ANTI-INVENTION (#6 · #10) : un projet n'expose une `offers`/`price` QUE s'il est
|
||||
`disponible` ET qu'une de ses typologies porte un `prix_depuis_usd` numerique
|
||||
sourcE dans le master. Pour tout statut de `STATUTS_SANS_PRIX` (en_developpement,
|
||||
bientot, en_processus) : AUCUN prix (jamais de chiffre fabrique). Devise = USD
|
||||
(devise primaire #10). Aucune horloge, tri stable -> sortie diffable.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from . import deps
|
||||
|
||||
|
||||
def _is_number(value) -> bool:
|
||||
return isinstance(value, (int, float)) and not isinstance(value, bool)
|
||||
|
||||
|
||||
def _offers_for(projet: dict) -> list[dict]:
|
||||
"""Offres schema.org d'un projet — vide si non `disponible` ou sans prix sourcE."""
|
||||
if projet["statut"] in deps.STATUTS_SANS_PRIX:
|
||||
return []
|
||||
offers = []
|
||||
for typo in projet.get("typologies", []):
|
||||
price = typo.get("prix_depuis_usd")
|
||||
if _is_number(price):
|
||||
offers.append({
|
||||
"@type": "Offer",
|
||||
"name": typo.get("nom"),
|
||||
"price": price,
|
||||
"priceCurrency": deps.DEVISE_PRIMAIRE,
|
||||
"availability": "https://schema.org/InStock",
|
||||
})
|
||||
return offers
|
||||
|
||||
|
||||
def generate(spec: dict, master: dict) -> dict:
|
||||
so = spec["schema_org"]
|
||||
base = spec["site"]["base_url"].rstrip("/")
|
||||
org_id = f"{base}/#organization"
|
||||
org = so["organization"]
|
||||
|
||||
graph: list[dict] = [{
|
||||
"@type": org["type"],
|
||||
"@id": org_id,
|
||||
"name": org["name"],
|
||||
"url": org["url"],
|
||||
}]
|
||||
|
||||
for p in master["projets"]:
|
||||
slug = deps.slugify(p["nom"])
|
||||
node = {
|
||||
"@type": so["listing_type"],
|
||||
"@id": f"{base}/projets/{slug}#residence",
|
||||
"name": p["nom"],
|
||||
"url": f"{base}/projets/{slug}",
|
||||
"brand": {"@id": org_id},
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"addressCountry": so["country_code"],
|
||||
"addressLocality": p["localisation"],
|
||||
},
|
||||
}
|
||||
offers = _offers_for(p)
|
||||
if offers:
|
||||
node["offers"] = offers
|
||||
graph.append(node)
|
||||
|
||||
return {"@context": so["context"], "@graph": graph}
|
||||
Reference in New Issue
Block a user