Skip to content

1.1.0

🚀 New Features

  • Statistics Page (Frontend): New dashboard tab with four sections: Overview (pipeline explanation), Shopping Table (cron scheduler + manual sync), Sheet Settings, and a Metabase link
  • Shopping Table Cron System: Automated import from Google Sheets via APScheduler — start/stop/status via dedicated endpoints (/cron/start, /cron/stop, /cron/status) and a manual trigger (/populate)
  • read_shopping_table_data Endpoint: Reads articles directly from the configured Google Sheet and returns them as a structured list (including type coercion for dates, booleans, floats, and ints)
  • Sheet Settings with Caching: Frontend caches sheet settings (column_mapping) with a 5-minute TTL in localStorage to reduce API calls
  • Upsert Logic for Shopping Table: Duplicate rows are prevented — existing entries are matched by datum + asin_sku (fallback: datum + name) and updated instead of re-inserted

🔧 Improvements

  • Sheets_Manager Refactoring: Column references are now resolved dynamically via column_mapping: Dict[str, str] from sheet settings instead of hardcoded properties
  • 429 Rate Limiting with Retry: New retry_on_429 decorator with exponential backoff (max 5 attempts, base 1s + jitter) applied to all Google Sheets API calls
  • Date Normalisation: datum values are cleaned before writing to the DB — timestamps are truncated to date-only, multiple input formats are supported (DD.MM.YYYY, YYYY-MM-DD, etc.)
  • ek_ort Cleaning: Unicode symbols and control characters (e.g. ✅) are automatically stripped from the supplier field, surrounding whitespace is trimmed
  • API Date Format: datum is serialised as DD.MM.YYYY in API responses

🐛 Bug Fixes

  • Import Error: cannot import name 'sheets' from 'crud.sheets' — wrong export name used (sheetssheet_settings)
  • _get_settings() Method: Removed call to non-existent get_settings() method; sheet settings must now always be passed via the constructor
  • lifespan Error: Missing yield in the @asynccontextmanager block in main.py caused TypeError: 'coroutine' object is not an async iterator
  • SQLAlchemy Column(description=...): Invalid keyword argument removed from schemas/sheets.py and schemas/shopping_table.py
  • datum Column Type: SQLAlchemy schema used DateTime instead of Date — corrected to Date

SQL

  • sheet_settings_v2.sql
  • shopping_table.sql