diff --git a/app/admin_routes.py b/app/admin_routes.py index 9e9d71f..e056d79 100644 --- a/app/admin_routes.py +++ b/app/admin_routes.py @@ -149,6 +149,55 @@ async def inv_delete(sku: str, ident=Depends(require_token), db=Depends(get_db)) return {"ok": True, "deleted": r.rowcount} +class ImportIn(BaseModel): + lines: list[str] + crate_id: int | None = None + price: float | None = None + condition: str | None = None + kind: str = "vinyl" + + +@router.post("/inventory/import") +async def inv_import(body: ImportIn, ident=Depends(require_token), db=Depends(get_db)): + """Bulk stock-IN: each line = Release ID / barcode / catno → resolved against the local disc_release + mirror → a new inventory item. (Distinct from the POS Import, which marks items SOLD.)""" + added, not_found = [], [] + for raw in body.lines: + ln = raw.strip() + if not ln: + continue + rid = title = None + if ln.isdigit(): + r = (await db.execute(text("SELECT id, title FROM disc_release WHERE id=:r"), + {"r": int(ln)})).first() + if r: + rid, title = r[0], r[1] + if not rid: # barcode / identifier + r = (await db.execute(text("""SELECT dr.id, dr.title FROM disc_release_identifier i + JOIN disc_release dr ON dr.id=i.release_id WHERE i.value=:v LIMIT 1"""), {"v": ln})).first() + if r: + rid, title = r[0], r[1] + if not rid: # catalogue number + r = (await db.execute(text("""SELECT dr.id, dr.title FROM disc_release_label l + JOIN disc_release dr ON dr.id=l.release_id WHERE l.catno=:v LIMIT 1"""), {"v": ln})).first() + if r: + rid, title = r[0], r[1] + if not rid: + not_found.append(ln) + continue + sku = "RG" + secrets.token_hex(4).upper() + await db.execute(text(""" + INSERT INTO inventory (sku, store_id, kind, release_id, title, price, qty, in_stock, condition, + crate_id, status, created_at, updated_at) + VALUES (:sku,:s,:kind,:rid,:title,:price,1,true,:cond,:crate,'publish',now(),now()) + ON CONFLICT (sku) DO NOTHING + """), {"sku": sku, "s": ident["store_id"], "kind": body.kind, "rid": rid, "title": title, + "price": body.price, "cond": body.condition, "crate": body.crate_id}) + added.append({"sku": sku, "release_id": rid, "title": title}) + await db.commit() + return {"ok": True, "added": len(added), "items": added, "not_found": not_found} + + @router.post("/inventory/bulk") async def inv_bulk(body: BulkIn, ident=Depends(require_token), db=Depends(get_db)): if not body.skus: diff --git a/site/admin.html b/site/admin.html index a252e93..2359f1a 100644 --- a/site/admin.html +++ b/site/admin.html @@ -134,7 +134,8 @@ async function vInv(){ + '
' + + '' + + '' + '' + '