SETTINGS-35: species $/bdft in Settings + taxonomy parent fix (#76)

Add Settings species pricing UI (children of Species grouper by slug,
never hardcoded ids). Map Woo REST parent→parent_id on taxonomy sync;
upsert categories so slab FKs survive re-sync. Tests: parent map, FK-safe
sync, TV-8 0.96×12.50→12.00, Playwright mock e2e. UAT verified on 5060.
This commit is contained in:
Ty
2026-09-20 12:37:52 -07:00
parent b99cbdf194
commit 18c262b5b4
7 changed files with 655 additions and 5 deletions
+45 -5
View File
@@ -20,6 +20,23 @@ def _scoped_tags(tags: list[dict]) -> list[dict]:
return [t for t in tags if t.get("name", "").startswith(("fig-", "feat-"))]
def _normalize_category(c: dict) -> tuple:
"""Map a Woo REST category row into woo_categories insert values.
WooCommerce REST v3 returns `parent` (0 = top-level). Older fixtures may
already use `parent_id`. Never invent ids — only store what the payload carries.
"""
raw_parent = c.get("parent_id", c.get("parent"))
if raw_parent in (0, "0", None, ""):
parent_id = None
else:
parent_id = int(raw_parent)
woo_id = c.get("woo_id", c.get("id"))
if woo_id is not None:
woo_id = int(woo_id)
return (c["id"], c["name"], c["slug"], parent_id, woo_id)
def _subset_hash(categories: list[dict], attributes: list[dict],
terms_by_attr: dict, scoped_tags: list[dict]) -> str:
subset = {
@@ -40,14 +57,37 @@ def sync(client: WooClient, conn) -> dict:
terms_by_attr = {a["id"]: client.get_attribute_terms(a["id"]) for a in attributes}
scoped_tags = _scoped_tags(tags)
# Attributes/tags/terms are not referenced by slabs FKs — safe to rebuild.
conn.execute("DELETE FROM woo_attribute_terms")
conn.execute("DELETE FROM woo_attributes")
conn.execute("DELETE FROM woo_categories")
conn.execute("DELETE FROM woo_tags")
conn.executemany(
"INSERT INTO woo_categories(id, name, slug, parent_id, woo_id) VALUES (?,?,?,?,?)",
[(c["id"], c["name"], c["slug"], c.get("parent_id"), c.get("woo_id")) for c in categories],
)
# Categories: upsert then drop stale rows. A full DELETE fails when slabs or
# pricing_rules still reference species_id (live UAT IntegrityError on test-woo).
cat_rows = [_normalize_category(c) for c in categories]
cat_ids = [r[0] for r in cat_rows]
for row in cat_rows:
conn.execute(
"INSERT INTO woo_categories(id, name, slug, parent_id, woo_id) VALUES (?,?,?,?,?) "
"ON CONFLICT(id) DO UPDATE SET "
"name=excluded.name, slug=excluded.slug, parent_id=excluded.parent_id, woo_id=excluded.woo_id",
row,
)
if cat_ids:
placeholders = ",".join("?" * len(cat_ids))
conn.execute(
f"DELETE FROM woo_categories WHERE id NOT IN ({placeholders}) "
"AND id NOT IN (SELECT species_id FROM slabs WHERE species_id IS NOT NULL) "
"AND id NOT IN (SELECT species_id FROM pricing_rules)",
cat_ids,
)
else:
conn.execute(
"DELETE FROM woo_categories "
"WHERE id NOT IN (SELECT species_id FROM slabs WHERE species_id IS NOT NULL) "
"AND id NOT IN (SELECT species_id FROM pricing_rules)"
)
conn.executemany(
"INSERT INTO woo_attributes(id, name, slug, woo_id) VALUES (?,?,?,?)",
[(a["id"], a["name"], a["slug"], a.get("woo_id")) for a in attributes],