Initial commit.
This commit is contained in:
commit
628e5c3823
26 changed files with 3478 additions and 0 deletions
56
ocado_grocy/order_state.py
Normal file
56
ocado_grocy/order_state.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""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])
|
||||
Loading…
Add table
Add a link
Reference in a new issue