diff --git a/taxes_az/master_data/sync.py b/taxes_az/master_data/sync.py index 143550f..92c8a94 100644 --- a/taxes_az/master_data/sync.py +++ b/taxes_az/master_data/sync.py @@ -263,7 +263,7 @@ def sync_items() -> dict: root = _resolve_item_group_root() print(f"[taxes_az] Item: resolved tree root = {root!r}, {len(records)} shipped item(s)") - inserted = existed = missing_group = 0 + inserted = existed = missing_group = failed = 0 for rec in records: name = rec.get("name") or rec.get("item_code") @@ -282,13 +282,28 @@ def sync_items() -> dict: missing_group += 1 continue - doc = frappe.new_doc("Item") - doc.update(rec) - doc.item_group = group - doc.name = name - doc.flags.name_set = True - doc.flags.ignore_permissions = True - doc.insert(ignore_if_duplicate=True) + # Isolate each insert in a savepoint: on a bare/half-provisioned site a + # missing link (e.g. UOM 'Litre') raises LinkValidationError, and an + # unhandled exception here would abort the whole `bench migrate`. Master + # data must never do that — roll back just this item and carry on. The + # item stays missing and a later migrate (once the site is complete) + # will create it, since sync only inserts items that don't exist yet. + frappe.db.savepoint("taxes_az_item") + try: + doc = frappe.new_doc("Item") + doc.update(rec) + doc.item_group = group + doc.name = name + doc.flags.name_set = True + doc.flags.ignore_permissions = True + doc.insert(ignore_if_duplicate=True) + except Exception as e: + frappe.db.rollback(save_point="taxes_az_item") + frappe.clear_last_message() + print(f"[taxes_az] Item '{name}': insert FAILED — SKIPPED ({e})") + failed += 1 + continue + frappe.db.release_savepoint("taxes_az_item") print(f"[taxes_az] Item: created {name!r} ({rec.get('item_name')}) in {group!r}") inserted += 1 @@ -296,13 +311,14 @@ def sync_items() -> dict: frappe.db.commit() print( f"[taxes_az] Item: created {inserted}, already existed {existed}, " - f"skipped (missing group) {missing_group}" + f"skipped (missing group) {missing_group}, failed {failed}" ) return { "doctype": "Item", "inserted": inserted, "existed": existed, "missing_group": missing_group, + "failed": failed, }