Skip to content

Commit e0b2cf5

Browse files
committed
refactor: enhance order store management with backfill tracking and migration
1 parent 31293ea commit e0b2cf5

2 files changed

Lines changed: 52 additions & 11 deletions

File tree

custom_components/rohlikcz/__init__.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,31 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
5050
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
5151
_LOGGER.info("Platforms setup complete")
5252

53-
# If analytics enabled, fetch full order history + enrich in background
54-
if analytics:
55-
async def _fetch_history():
56-
try:
57-
if rohlik_hub.order_store:
53+
# If analytics enabled, run initial backfill or resume interrupted enrichment
54+
if analytics and rohlik_hub.order_store:
55+
store = rohlik_hub.order_store
56+
needs_backfill = not store.backfill_complete
57+
needs_enrichment = (
58+
store.backfill_complete
59+
and (store.unenriched_order_ids or store.uncategorized_product_ids())
60+
)
61+
62+
if needs_backfill:
63+
async def _fetch_history():
64+
try:
5865
await rohlik_hub.fetch_full_order_history(hass=hass)
59-
except Exception as err:
60-
_LOGGER.error("Background order history fetch failed: %s", err)
61-
62-
entry.async_create_background_task(hass, _fetch_history(), "rohlik_fetch_history")
66+
except Exception as err:
67+
_LOGGER.error("Background order history fetch failed: %s", err)
68+
69+
entry.async_create_background_task(hass, _fetch_history(), "rohlik_fetch_history")
70+
elif needs_enrichment:
71+
async def _resume_enrichment():
72+
try:
73+
await rohlik_hub.enrich_order_details(hass=hass)
74+
except Exception as err:
75+
_LOGGER.error("Background enrichment resume failed: %s", err)
76+
77+
entry.async_create_background_task(hass, _resume_enrichment(), "rohlik_resume_enrichment")
6378

6479
# Reload when options change (user reconfigures analytics)
6580
entry.async_on_unload(entry.add_update_listener(_async_reload_entry))

custom_components/rohlikcz/hub.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class OrderStore:
5151

5252
def __init__(self, storage_dir: str, user_id: str, hass: HomeAssistant):
5353
self._path = os.path.join(storage_dir, f"rohlikcz_{user_id}_orders.json")
54-
self._data = {"version": 2, "user_id": user_id, "tracking_since": None, "orders": {}, "product_categories": {}}
54+
self._data = {"version": 3, "user_id": user_id, "tracking_since": None, "backfill_complete": False, "orders": {}, "product_categories": {}}
5555
self._hass = hass
5656

5757
@classmethod
@@ -67,15 +67,28 @@ def _load_sync(self) -> None:
6767
try:
6868
with open(self._path, "r") as f:
6969
self._data = json.load(f)
70+
migrated = False
7071
# Migrate v1 → v2
7172
if self._data.get("version", 1) < 2:
7273
self._data["version"] = 2
7374
if "product_categories" not in self._data:
7475
self._data["product_categories"] = {}
75-
self._save_sync()
76+
migrated = True
7677
_LOGGER.info("Migrated order store from v1 to v2")
7778
elif "product_categories" not in self._data:
7879
self._data["product_categories"] = {}
80+
# Migrate v2 → v3 (add backfill_complete flag)
81+
if self._data.get("version", 1) < 3:
82+
self._data["version"] = 3
83+
# Existing stores with tracking_since already set had a
84+
# successful backfill in a prior run; mark it complete so
85+
# we don't re-download everything on next restart.
86+
if "backfill_complete" not in self._data:
87+
self._data["backfill_complete"] = self._data.get("tracking_since") is not None
88+
migrated = True
89+
_LOGGER.info("Migrated order store from v2 to v3")
90+
if migrated:
91+
self._save_sync()
7992
except (json.JSONDecodeError, OSError) as err:
8093
_LOGGER.error(f"Failed to load order store: {err}")
8194

@@ -143,6 +156,15 @@ def orders(self) -> dict:
143156
def tracking_since(self) -> str | None:
144157
return self._data.get("tracking_since")
145158

159+
@property
160+
def backfill_complete(self) -> bool:
161+
"""Whether the initial full order history download has finished."""
162+
return self._data.get("backfill_complete", False)
163+
164+
def mark_backfill_complete(self) -> None:
165+
"""Mark the initial backfill as done (caller must async_save)."""
166+
self._data["backfill_complete"] = True
167+
146168
def yearly_total(self, year: str) -> float:
147169
"""Sum of order amounts for a given year (e.g. '2026')."""
148170
return sum(
@@ -427,6 +449,10 @@ async def fetch_full_order_history(self, hass=None) -> dict:
427449
if self._order_store:
428450
enrich_stats = await self.enrich_order_details(hass=hass)
429451
enrich_stats["new_orders"] = new_orders
452+
# Mark backfill as done so we don't re-download on next restart
453+
if not self._order_store.backfill_complete:
454+
self._order_store.mark_backfill_complete()
455+
await self._order_store.async_save()
430456
return enrich_stats
431457

432458
return {"total_orders": 0, "new_orders": 0}

0 commit comments

Comments
 (0)