feat(baserow): add formulas pass + related field naming to seed
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
Some checks are pending
CI / Lint bridge (Biome) (push) Waiting to run
CI / Type-check bridge (push) Blocked by required conditions
CI / Tests unit bridge (push) Blocked by required conditions
CI / Tests integration bridge (push) Blocked by required conditions
CI / Security scan (push) Waiting to run
CI / Docker build + healthcheck (push) Blocked by required conditions
- schema.json : 17 formulas (rollups + heures_restantes) ajoutees + related_field_name explicite sur les 10 liens - seed.py : 3 nouveaux methodes (create_formula_field, rename_field, create_link_field returns dict) - seed.py : pass 5/6 renomme automatiquement les related fields apres link creation - seed.py : pass 6/6 cree les formulas (idempotent) - README.md : section formulas updated Iteration 2 du plan Fast-App couverte. Apres seed, les rollups (formation_heures_attribuees, personne_heures_restantes_total, etc.) sont automatiques.
This commit is contained in:
parent
6724be6c85
commit
a0266b886c
3 changed files with 71 additions and 15 deletions
|
|
@ -69,7 +69,9 @@ Pour reset complet : drop la database via l'UI Baserow, puis relancer.
|
||||||
|
|
||||||
`schema.json` decrit les 9 tables + 10 liens FK. Format JSON declaratif, modifiable.
|
`schema.json` decrit les 9 tables + 10 liens FK. Format JSON declaratif, modifiable.
|
||||||
|
|
||||||
Les **formulas** (rollups, heures_restantes, etc.) ne sont **pas** crees par ce seed (Phase 1 = structure seule). Elles seront ajoutees en iteration 2 du plan Fast-App via un seed-formulas.py separe.
|
Les **formulas** (rollups, heures_restantes, etc.) sont creees au pass 6/6. Le schema declaratif inclut 17 formulas dans `schema.json` (section `formulas`).
|
||||||
|
|
||||||
|
Si une formula echoue (syntaxe Baserow strict), le seed s'arrete et affiche l'erreur — corrige le `schema.json` et re-run.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,16 +187,34 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [
|
"links": [
|
||||||
{"from_table": "bloc", "from_field": "bloc_formation", "to_table": "formation"},
|
{"from_table": "bloc", "from_field": "bloc_formation", "to_table": "formation", "related_field_name": "formation_blocs"},
|
||||||
{"from_table": "module", "from_field": "module_bloc", "to_table": "bloc"},
|
{"from_table": "module", "from_field": "module_bloc", "to_table": "bloc", "related_field_name": "bloc_modules"},
|
||||||
{"from_table": "attribution", "from_field": "attribution_module", "to_table": "module"},
|
{"from_table": "attribution", "from_field": "attribution_module", "to_table": "module", "related_field_name": "module_attributions"},
|
||||||
{"from_table": "attribution", "from_field": "attribution_personne", "to_table": "personne"},
|
{"from_table": "attribution", "from_field": "attribution_personne", "to_table": "personne", "related_field_name": "personne_attributions"},
|
||||||
{"from_table": "projet", "from_field": "projet_client", "to_table": "client"},
|
{"from_table": "projet", "from_field": "projet_client", "to_table": "client", "related_field_name": "client_projets"},
|
||||||
{"from_table": "projet", "from_field": "projet_formation_pedagogique", "to_table": "formation"},
|
{"from_table": "projet", "from_field": "projet_formation_pedagogique", "to_table": "formation", "related_field_name": "formation_projets_pedagogiques"},
|
||||||
{"from_table": "tache", "from_field": "tache_projet", "to_table": "projet"},
|
{"from_table": "tache", "from_field": "tache_projet", "to_table": "projet", "related_field_name": "projet_taches"},
|
||||||
{"from_table": "tache", "from_field": "tache_assignee", "to_table": "personne"},
|
{"from_table": "tache", "from_field": "tache_assignee", "to_table": "personne", "related_field_name": "personne_taches_assignees"},
|
||||||
{"from_table": "intervention", "from_field": "intervention_tache", "to_table": "tache"},
|
{"from_table": "intervention", "from_field": "intervention_tache", "to_table": "tache", "related_field_name": "tache_interventions"},
|
||||||
{"from_table": "intervention", "from_field": "intervention_personne", "to_table": "personne"}
|
{"from_table": "intervention", "from_field": "intervention_personne", "to_table": "personne", "related_field_name": "personne_interventions"}
|
||||||
],
|
],
|
||||||
"_note_phase_2": "Les formulas (rollups, heures_restantes) seront ajoutees en iteration 2 du plan Fast-App. Phase 1 = structure + liens seuls."
|
"formulas": [
|
||||||
|
{"table": "module", "name": "module_heures_prevues_active", "expression": "if(field('module_statut') = 'annule', 0, field('module_heures_prevues'))"},
|
||||||
|
{"table": "attribution", "name": "attribution_heures_attribuees_active", "expression": "if(field('attribution_statut') = 'annule', 0, field('attribution_heures_attribuees'))"},
|
||||||
|
{"table": "intervention", "name": "intervention_heures_active", "expression": "if(field('intervention_statut') = 'annule', 0, field('intervention_heures'))"},
|
||||||
|
{"table": "bloc", "name": "bloc_heures_attribuees", "expression": "sum(lookup('bloc_modules', 'module_heures_prevues_active'))"},
|
||||||
|
{"table": "bloc", "name": "bloc_heures_restantes", "expression": "field('bloc_heures_prevues') - field('bloc_heures_attribuees')"},
|
||||||
|
{"table": "module", "name": "module_heures_attribuees", "expression": "sum(lookup('module_attributions', 'attribution_heures_attribuees_active'))"},
|
||||||
|
{"table": "module", "name": "module_heures_realisees", "expression": "sum(lookup('module_attributions', 'attribution_heures_realisees'))"},
|
||||||
|
{"table": "formation", "name": "formation_heures_attribuees", "expression": "sum(lookup('formation_blocs', 'bloc_heures_prevues'))"},
|
||||||
|
{"table": "formation", "name": "formation_heures_restantes", "expression": "field('formation_heures_totales') - field('formation_heures_attribuees')"},
|
||||||
|
{"table": "personne", "name": "personne_heures_attribuees_formation", "expression": "sum(lookup('personne_attributions', 'attribution_heures_attribuees_active'))"},
|
||||||
|
{"table": "personne", "name": "personne_heures_attribuees_agence", "expression": "sum(lookup('personne_interventions', 'intervention_heures_active'))"},
|
||||||
|
{"table": "personne", "name": "personne_heures_restantes_formation", "expression": "(field('personne_capacite_annuelle') * field('personne_split_formation_pct') / 100) - field('personne_heures_attribuees_formation')"},
|
||||||
|
{"table": "personne", "name": "personne_heures_restantes_agence", "expression": "(field('personne_capacite_annuelle') * field('personne_split_agence_pct') / 100) - field('personne_heures_attribuees_agence')"},
|
||||||
|
{"table": "personne", "name": "personne_heures_restantes_total", "expression": "field('personne_capacite_annuelle') - field('personne_heures_attribuees_formation') - field('personne_heures_attribuees_agence')"},
|
||||||
|
{"table": "tache", "name": "tache_heures_realisees", "expression": "sum(lookup('tache_interventions', 'intervention_heures_active'))"},
|
||||||
|
{"table": "projet", "name": "projet_heures_realisees", "expression": "sum(lookup('projet_taches', 'tache_heures_realisees'))"},
|
||||||
|
{"table": "projet", "name": "projet_heures_restantes", "expression": "field('projet_charge_heures') - field('projet_heures_realisees')"}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ class BaserowSeed:
|
||||||
payload["long_text_enable_rich_text"] = True
|
payload["long_text_enable_rich_text"] = True
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def create_link_field(self, from_table_id: int, name: str, to_table_id: int) -> int:
|
def create_link_field(self, from_table_id: int, name: str, to_table_id: int) -> dict[str, Any]:
|
||||||
r = self.session.post(
|
r = self.session.post(
|
||||||
f"{self.base_url}/api/database/fields/table/{from_table_id}/",
|
f"{self.base_url}/api/database/fields/table/{from_table_id}/",
|
||||||
headers=self._headers(),
|
headers=self._headers(),
|
||||||
|
|
@ -158,6 +158,25 @@ class BaserowSeed:
|
||||||
if r.status_code >= 300:
|
if r.status_code >= 300:
|
||||||
print(f" [ERROR] link {name} resp={r.text}")
|
print(f" [ERROR] link {name} resp={r.text}")
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
def rename_field(self, field_id: int, new_name: str) -> None:
|
||||||
|
r = self.session.patch(
|
||||||
|
f"{self.base_url}/api/database/fields/{field_id}/",
|
||||||
|
headers=self._headers(),
|
||||||
|
json={"name": new_name},
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
|
||||||
|
def create_formula_field(self, table_id: int, name: str, expression: str) -> int:
|
||||||
|
r = self.session.post(
|
||||||
|
f"{self.base_url}/api/database/fields/table/{table_id}/",
|
||||||
|
headers=self._headers(),
|
||||||
|
json={"name": name, "type": "formula", "formula": expression},
|
||||||
|
)
|
||||||
|
if r.status_code >= 300:
|
||||||
|
print(f" [ERROR] formula {name} expr={expression} resp={r.text}")
|
||||||
|
r.raise_for_status()
|
||||||
return r.json()["id"]
|
return r.json()["id"]
|
||||||
|
|
||||||
def seed(self, schema: dict[str, Any]) -> None:
|
def seed(self, schema: dict[str, Any]) -> None:
|
||||||
|
|
@ -183,7 +202,7 @@ class BaserowSeed:
|
||||||
table_ids[tname] = tid
|
table_ids[tname] = tid
|
||||||
self._sync_fields(tid, table)
|
self._sync_fields(tid, table)
|
||||||
|
|
||||||
print(f"\n[5/5] Link fields (2nd pass)")
|
print(f"\n[5/6] Link fields (2nd pass)")
|
||||||
for link in schema["links"]:
|
for link in schema["links"]:
|
||||||
from_id = table_ids[link["from_table"]]
|
from_id = table_ids[link["from_table"]]
|
||||||
to_id = table_ids[link["to_table"]]
|
to_id = table_ids[link["to_table"]]
|
||||||
|
|
@ -191,14 +210,31 @@ class BaserowSeed:
|
||||||
if link["from_field"] in existing_fields:
|
if link["from_field"] in existing_fields:
|
||||||
print(f" [link] Reuse {link['from_table']}.{link['from_field']} -> {link['to_table']}")
|
print(f" [link] Reuse {link['from_table']}.{link['from_field']} -> {link['to_table']}")
|
||||||
continue
|
continue
|
||||||
self.create_link_field(from_id, link["from_field"], to_id)
|
link_field = self.create_link_field(from_id, link["from_field"], to_id)
|
||||||
print(f" [link] Created {link['from_table']}.{link['from_field']} -> {link['to_table']}")
|
print(f" [link] Created {link['from_table']}.{link['from_field']} -> {link['to_table']}")
|
||||||
|
related_id = link_field.get("link_row_related_field_id") or link_field.get("link_row_related_field")
|
||||||
|
related_name = link.get("related_field_name")
|
||||||
|
if related_name and related_id:
|
||||||
|
self.rename_field(related_id, related_name)
|
||||||
|
print(f" [link] Renamed related field id={related_id} -> '{related_name}'")
|
||||||
|
|
||||||
|
print(f"\n[6/6] Formula fields (3rd pass)")
|
||||||
|
for f in schema.get("formulas", []):
|
||||||
|
tname = f["table"]
|
||||||
|
tid = table_ids[tname]
|
||||||
|
existing_fields = {x["name"]: x for x in self.list_fields(tid)}
|
||||||
|
if f["name"] in existing_fields:
|
||||||
|
print(f" [formula] Reuse {tname}.{f['name']}")
|
||||||
|
continue
|
||||||
|
self.create_formula_field(tid, f["name"], f["expression"])
|
||||||
|
print(f" [formula] Created {tname}.{f['name']}")
|
||||||
|
|
||||||
print("\n=== Seed OK ===")
|
print("\n=== Seed OK ===")
|
||||||
print(f" Workspace: {schema['workspace_name']}")
|
print(f" Workspace: {schema['workspace_name']}")
|
||||||
print(f" Database : {schema['database_name']}")
|
print(f" Database : {schema['database_name']}")
|
||||||
print(f" Tables : {len(table_ids)}")
|
print(f" Tables : {len(table_ids)}")
|
||||||
print(f" Links : {len(schema['links'])}")
|
print(f" Links : {len(schema['links'])}")
|
||||||
|
print(f" Formulas : {len(schema.get('formulas', []))}")
|
||||||
|
|
||||||
def _sync_fields(self, table_id: int, table_def: dict[str, Any]) -> None:
|
def _sync_fields(self, table_id: int, table_def: dict[str, Any]) -> None:
|
||||||
existing = {f["name"]: f for f in self.list_fields(table_id)}
|
existing = {f["name"]: f for f in self.list_fields(table_id)}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue