5fa1e34914
Build and push image / build (push) Successful in 57s
Replaces the unified audit system with two purpose-built flows: - Weigh Ins: rebranded audit flow for bulk products (Flower, Concentrate, Tincture) with scale weigh, container weigh, and estimate modes - Bin Checks: new bin-level presence check — select a bin, scan every item, resolve discrepancies (wrong bin, unknown, missing), auto-records presence audits on verified items Adds cadence_days and last_checked to bins table, with per-bin overdue tracking on the dashboard and bins view. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
154 lines
3.9 KiB
TypeScript
154 lines
3.9 KiB
TypeScript
import { Router } from "express";
|
|
import { db } from "../db.js";
|
|
|
|
export const bootstrapRouter: Router = Router();
|
|
|
|
type ProductRow = {
|
|
id: string;
|
|
sku: string;
|
|
strain_id: string;
|
|
brand_id: string | null;
|
|
type: string;
|
|
kind: string;
|
|
created_at: string;
|
|
};
|
|
|
|
type InventoryRow = {
|
|
id: string;
|
|
asset_id: string;
|
|
product_id: string;
|
|
shop_id: string | null;
|
|
bin_id: string | null;
|
|
price: number;
|
|
thc: number;
|
|
cbd: number;
|
|
total_cannabinoids: number;
|
|
weight: number;
|
|
container_weight: number | null;
|
|
last_audit_weight: number | null;
|
|
count_original: number;
|
|
count_last_audit: number | null;
|
|
unit_weight: number;
|
|
purchase_date: string;
|
|
status: string;
|
|
consumed_date: string | null;
|
|
gone_date: string | null;
|
|
checkout_date: string | null;
|
|
prev_bin_id: string | null;
|
|
rating: number | null;
|
|
notes: string | null;
|
|
};
|
|
|
|
type StrainRow = {
|
|
id: string;
|
|
name: string;
|
|
default_thc: number | null;
|
|
default_cbd: number | null;
|
|
default_total_cannabinoids: number | null;
|
|
notes: string | null;
|
|
};
|
|
|
|
type AuditRow = {
|
|
id: number;
|
|
inventory_id: string;
|
|
date: string;
|
|
mode: string;
|
|
value: number;
|
|
prev_value: number | null;
|
|
confirmed_by: string | null;
|
|
};
|
|
|
|
bootstrapRouter.get("/bootstrap", (_req, res) => {
|
|
const products = db
|
|
.prepare<[], ProductRow>("SELECT * FROM products ORDER BY id")
|
|
.all();
|
|
const inventory = db
|
|
.prepare<[], InventoryRow>("SELECT * FROM inventory_items ORDER BY id")
|
|
.all();
|
|
const audits = db
|
|
.prepare<[], AuditRow>("SELECT * FROM audits ORDER BY inventory_id, date")
|
|
.all();
|
|
const shops = db.prepare("SELECT * FROM shops ORDER BY id").all();
|
|
const brands = db.prepare("SELECT * FROM brands ORDER BY id").all();
|
|
const binsRaw = db.prepare("SELECT id, name, capacity, cadence_days, last_checked FROM bins ORDER BY id").all() as { id: string; name: string; capacity: number; cadence_days: number; last_checked: string | null }[];
|
|
const bins = binsRaw.map((b) => ({
|
|
id: b.id,
|
|
name: b.name,
|
|
capacity: b.capacity,
|
|
cadenceDays: b.cadence_days,
|
|
lastChecked: b.last_checked,
|
|
}));
|
|
const strains = db
|
|
.prepare<[], StrainRow>("SELECT * FROM strains ORDER BY name COLLATE NOCASE")
|
|
.all();
|
|
|
|
const auditsByInventory = new Map<string, AuditRow[]>();
|
|
for (const a of audits) {
|
|
const arr = auditsByInventory.get(a.inventory_id) ?? [];
|
|
arr.push(a);
|
|
auditsByInventory.set(a.inventory_id, arr);
|
|
}
|
|
|
|
const productsOut = products.map((p) => ({
|
|
id: p.id,
|
|
sku: p.sku,
|
|
strainId: p.strain_id,
|
|
brandId: p.brand_id,
|
|
type: p.type,
|
|
kind: p.kind,
|
|
createdAt: p.created_at,
|
|
}));
|
|
|
|
const inventoryOut = inventory.map((i) => ({
|
|
id: i.id,
|
|
assetId: i.asset_id,
|
|
productId: i.product_id,
|
|
shopId: i.shop_id,
|
|
binId: i.bin_id,
|
|
price: i.price,
|
|
thc: i.thc,
|
|
cbd: i.cbd,
|
|
totalCannabinoids: i.total_cannabinoids,
|
|
weight: i.weight,
|
|
containerWeight: i.container_weight,
|
|
lastAuditWeight: i.last_audit_weight,
|
|
countOriginal: i.count_original,
|
|
countLastAudit: i.count_last_audit,
|
|
unitWeight: i.unit_weight,
|
|
purchaseDate: i.purchase_date,
|
|
status: i.status,
|
|
consumedDate: i.consumed_date,
|
|
goneDate: i.gone_date,
|
|
checkoutDate: i.checkout_date,
|
|
prevBinId: i.prev_bin_id,
|
|
rating: i.rating,
|
|
notes: i.notes,
|
|
audits: (auditsByInventory.get(i.id) ?? []).map((a) => ({
|
|
date: a.date,
|
|
mode: a.mode,
|
|
value: a.value,
|
|
prev: a.prev_value,
|
|
confirmedBy: a.confirmed_by,
|
|
})),
|
|
}));
|
|
|
|
const strainsOut = strains.map((s) => ({
|
|
id: s.id,
|
|
name: s.name,
|
|
defaultThc: s.default_thc,
|
|
defaultCbd: s.default_cbd,
|
|
defaultTotalCannabinoids: s.default_total_cannabinoids,
|
|
notes: s.notes,
|
|
}));
|
|
|
|
res.json({
|
|
products: productsOut,
|
|
inventoryItems: inventoryOut,
|
|
shops,
|
|
brands,
|
|
bins,
|
|
strains: strainsOut,
|
|
today: new Date().toISOString().slice(0, 10),
|
|
});
|
|
});
|