56 lines
2.9 KiB
Python
56 lines
2.9 KiB
Python
"""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])
|