"""Order-level completion, with conservative migration of the line journal.""" import json import sqlite3 from types import SimpleNamespace from .grocy import align_recorded_lines, item_fingerprint from .pantry import classify from .receipt import parse_document def completed_orders(state, server, archive, config): """Read only: a downloaded receipt alone is never evidence of an import.""" if not state.exists(): return set() with sqlite3.connect(f'{state.resolve().as_uri()}?mode=ro', uri=True) as db: tables = {r[0] for r in db.execute("SELECT name FROM sqlite_master WHERE type='table'")} tracked = dict(db.execute('SELECT order_id,status FROM loaded_orders WHERE server=?', (server,))) if 'loaded_orders' in tables else {} completed = {order for order, status in tracked.items() if status == 'complete'} if 'imports' not in tables: return completed legacy = {r[0] for r in db.execute('SELECT DISTINCT order_id FROM imports WHERE server=?', (server,))} - tracked.keys() for order in legacy: path = archive / f'{order}.json' if not path.exists(): continue try: receipt = parse_document(json.loads(path.read_text())) if receipt.order_id != order: continue receipt = align_recorded_lines(receipt, server, SimpleNamespace(db=db)) rows = {line:(fingerprint,status) for line,fingerprint,status in db.execute( 'SELECT line,fingerprint,status FROM imports WHERE server=? AND order_id=?', (server,order))} if any(status != 'done' for _,status in rows.values()): continue selected = [(line,item) for line,item in enumerate(receipt.items,1) if classify(item,config.get('pantry',{}).get('overrides',{})).include] if all(rows.get(line) == (item_fingerprint(receipt,item),'done') for line,item in selected): completed.add(order) except (ValueError, KeyError, TypeError): # A changed or incomplete receipt needs the normal reconciliation path. continue return completed def mark_orders(state, server, orders, status): if not orders: return state.parent.mkdir(parents=True, exist_ok=True) with sqlite3.connect(state) as db: db.execute('''CREATE TABLE IF NOT EXISTS loaded_orders ( server TEXT NOT NULL, order_id TEXT NOT NULL, status TEXT NOT NULL, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(server,order_id))''') db.executemany('''INSERT INTO loaded_orders(server,order_id,status) VALUES (?,?,?) ON CONFLICT(server,order_id) DO UPDATE SET status=excluded.status, updated_at=CURRENT_TIMESTAMP''', [(server,order,status) for order in orders])