use rust_decimal::Decimal;
use sqlx::{PgPool, Row};
use uuid::Uuid;
use backbone_inventory::application::service::inventory_gl::{
AccountingPostEnvelope, GlPostAck, GlPostRejected, GlPostSink,
};
use backbone_inventory::application::service::inventory_move_engine::{
BackorderPolicy, MoveGlDirective, NewStockMove,
};
use backbone_inventory::application::service::inventory_read::InventoryReadService;
use backbone_inventory::application::service::inventory_write_service::{
InventoryError, InventoryWriteService, NewWarehouse,
};
struct StubGl;
#[async_trait::async_trait]
impl GlPostSink for StubGl {
async fn post(&self, _e: &AccountingPostEnvelope) -> Result<GlPostAck, GlPostRejected> {
Ok(GlPostAck { post_id: Uuid::new_v4(), journal_id: Uuid::new_v4(), idempotent_reuse: false })
}
}
fn d(s: &str) -> Decimal { Decimal::from_str_exact(s).unwrap() }
fn uq(p: &str) -> String { format!("{p}-{}", &Uuid::new_v4().simple().to_string()[..8]) }
async fn pool() -> PgPool {
let url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgresql://postgres:postgres@localhost:5433/backbone_inventory".to_string());
PgPool::connect(&url).await.expect("connect DB")
}
fn no_gl() -> MoveGlDirective { MoveGlDirective::default() }
fn out_gl() -> MoveGlDirective {
MoveGlDirective {
cogs_account_id: Some(Uuid::new_v4()),
inventory_account_id: Some(Uuid::new_v4()),
grir_account_id: Some(Uuid::new_v4()),
adjustment_account_id: Some(Uuid::new_v4()),
currency: "IDR".into(),
}
}
async fn warehouse(w: &InventoryWriteService) -> Uuid {
w.create_warehouse(NewWarehouse {
code: uq("WH"), name: uq("Main"),
warehouse_type: None, parent_warehouse_id: None, is_group: false,
}).await.unwrap()
}
async fn loc(pool: &PgPool, usage: &str, wh: Option<Uuid>) -> Uuid {
let id = Uuid::new_v4();
let name = uq("LOC");
sqlx::query(
r#"INSERT INTO inventory.locations
(id, name, complete_name, usage, parent_path, warehouse_id)
VALUES ($1,$2,$3,$4::location_usage,$5,$6)"#,
)
.bind(id).bind(&name).bind(&name).bind(usage).bind("").bind(wh)
.execute(pool).await.unwrap();
id
}
async fn seed_quant(pool: &PgPool, item: Uuid, location: Uuid, qty: &str) {
sqlx::query(
r#"INSERT INTO inventory.stock_quants
(id, item_id, location_id, quantity, reserved_quantity, available_quantity)
VALUES ($1,$2,$3,$4,0,$4)"#,
)
.bind(Uuid::new_v4()).bind(item).bind(location).bind(d(qty))
.execute(pool).await.unwrap();
}
async fn seed_bin(pool: &PgPool, item: Uuid, wh: Uuid, qty: &str, rate: &str) {
sqlx::query(
r#"INSERT INTO inventory.bins
(id, item_id, warehouse_id, actual_qty, reserved_qty, valuation_rate, stock_value)
VALUES ($1,$2,$3,$4,0,$5,$6)"#,
)
.bind(Uuid::new_v4()).bind(item).bind(wh)
.bind(d(qty)).bind(d(rate)).bind(d(qty) * d(rate))
.execute(pool).await.unwrap();
}
fn new_move(item: Uuid, src: Uuid, dst: Uuid, qty: &str) -> NewStockMove {
NewStockMove {
name: uq("MV"),
item_id: item,
demand_qty: d(qty),
price_unit: Decimal::ZERO,
procure_method: "make_to_stock".into(),
picking_id: None,
origin: None,
location_id: src,
location_dest_id: dst,
partner_id: None,
warehouse_id: None,
orderpoint_id: None,
move_orig_ids: vec![],
move_dest_ids: vec![],
is_inventory: false,
scrapped: false,
forced_value: None,
}
}
async fn move_state(pool: &PgPool, id: Uuid) -> String {
let s: String = sqlx::query_scalar("SELECT state::text FROM inventory.stock_moves WHERE id=$1")
.bind(id).fetch_one(pool).await.unwrap();
s
}
async fn quant_at(pool: &PgPool, item: Uuid, location: Uuid) -> (Decimal, Decimal) {
let row = sqlx::query(
r#"SELECT COALESCE(SUM(quantity),0) AS q, COALESCE(SUM(reserved_quantity),0) AS r
FROM inventory.stock_quants
WHERE item_id=$1 AND location_id=$2 AND (metadata->>'deleted_at') IS NULL"#,
)
.bind(item).bind(location)
.fetch_one(pool).await.unwrap();
(row.get::<Decimal,_>("q"), row.get::<Decimal,_>("r"))
}
async fn bin_at(pool: &PgPool, item: Uuid, wh: Uuid) -> (Decimal, Decimal, Decimal) {
let row = sqlx::query(
"SELECT actual_qty, valuation_rate, stock_value FROM inventory.bins WHERE item_id=$1 AND warehouse_id=$2",
)
.bind(item).bind(wh).fetch_one(pool).await.unwrap();
(row.get("actual_qty"), row.get("valuation_rate"), row.get("stock_value"))
}
#[tokio::test]
async fn lifecycle_confirm_assign_done() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, stock, "10").await;
seed_bin(&pool, item, wh, "10", "100").await;
let mv = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
assert_eq!(move_state(&pool, mv).await, "draft", "create lands draft — no state at insert (spec §1)");
assert_eq!(w.action_confirm(mv).await.unwrap(), "confirmed");
let a = w.action_assign(mv).await.unwrap();
assert_eq!(a.state, "assigned", "10 on hand covers demand 6");
assert_eq!(a.reserved_qty, d("6"));
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("10"), d("6")));
let read = InventoryReadService::new(pool.clone());
let avail = read.quant_availability(item, stock).await.unwrap();
assert_eq!(avail.available_qty, d("4"), "T2: available = quantity - reserved as a read");
assert_eq!(avail.on_hand_qty, d("10"));
let out = w.action_done(mv, BackorderPolicy::Always, &out_gl(), &StubGl).await.unwrap();
assert_eq!(out.done_qty, d("6"));
assert!(out.backorder_move_id.is_none(), "full validate mints no backorder");
assert_eq!(out.sle_count, 1, "OUT leg only (customer destination holds no bin)");
assert!(out.gl_posted, "COGS shape posts through the AccountingPost seam");
assert_eq!(out.gl_amount, d("600.00"), "6 * current average 100");
assert_eq!(move_state(&pool, mv).await, "done");
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("4"), d("0")), "reserved step released, available step moved 6");
let (bq, brate, bval) = bin_at(&pool, item, wh).await;
assert_eq!(bq, d("4.0000"));
assert_eq!(brate, d("100.000000"), "outflow never reblends the rate");
assert_eq!(bval, d("400.00"));
}
#[tokio::test]
async fn competing_reservations_one_counter() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, stock, "10").await;
seed_bin(&pool, item, wh, "10", "100").await;
let a = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
let b = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
w.action_confirm(a).await.unwrap();
w.action_confirm(b).await.unwrap();
let oa = w.action_assign(a).await.unwrap();
assert_eq!(oa.state, "assigned");
let ob = w.action_assign(b).await.unwrap();
assert_eq!(ob.state, "partially_available", "only 4 remain free — never an over-reserve");
assert_eq!(ob.reserved_qty, d("4"));
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!(r, d("10"), "reserved == on-hand exactly (R22: reserved can never exceed it)");
assert_eq!(q, d("10"));
w.action_done(a, BackorderPolicy::Never, &no_gl(), &StubGl).await.unwrap();
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("4"), d("4")), "A consumed 6 physically; B's live line still holds 4");
}
#[tokio::test]
async fn backorder_split_on_partial_done() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, stock, "10").await;
seed_bin(&pool, item, wh, "10", "100").await;
let mv = w.create_move(new_move(item, stock, customer, "10")).await.unwrap();
w.action_confirm(mv).await.unwrap();
w.action_assign(mv).await.unwrap();
sqlx::query("UPDATE inventory.stock_move_lines SET quantity=6 WHERE move_id=$1")
.bind(mv).execute(&pool).await.unwrap();
let out = w.action_done(mv, BackorderPolicy::Always, &no_gl(), &StubGl).await.unwrap();
assert_eq!(out.done_qty, d("6"));
let child = out.backorder_move_id.expect("backorder minted");
let (demand, state, origs): (Decimal, String, Vec<Uuid>) = sqlx::query_as(
"SELECT demand_qty, state::text, move_orig_ids FROM inventory.stock_moves WHERE id=$1",
)
.bind(child).fetch_one(&pool).await.unwrap();
assert_eq!(demand, d("4"));
assert_eq!(state, "assigned", "Always mints the backorder confirmed + reserved (reserve on mint)");
assert_eq!(origs, vec![mv], "chained to its parent (done-qty propagation walks this)");
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("4"), d("4")), "self-heal released the stranded 4; the backorder re-reserved it");
w.unreserve_move(child).await.unwrap();
let mv2 = w.create_move(new_move(item, stock, customer, "2")).await.unwrap();
w.action_confirm(mv2).await.unwrap();
w.action_assign(mv2).await.unwrap();
sqlx::query("UPDATE inventory.stock_move_lines SET quantity=1 WHERE move_id=$1")
.bind(mv2).execute(&pool).await.unwrap();
let out2 = w.action_done(mv2, BackorderPolicy::Never, &no_gl(), &StubGl).await.unwrap();
assert!(out2.backorder_move_id.is_none());
}
#[tokio::test]
async fn v7_out_valued_before_in_after() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh1 = warehouse(&w).await;
let wh2 = warehouse(&w).await;
let src = loc(&pool, "internal", Some(wh1)).await;
let dst = loc(&pool, "internal", Some(wh2)).await;
seed_quant(&pool, item, src, "10").await;
seed_bin(&pool, item, wh1, "10", "100").await;
seed_quant(&pool, item, dst, "5").await;
seed_bin(&pool, item, wh2, "5", "60").await;
let mv = w.create_move(new_move(item, src, dst, "4")).await.unwrap();
w.action_confirm(mv).await.unwrap();
w.action_assign(mv).await.unwrap();
let out = w.action_done(mv, BackorderPolicy::Never, &out_gl(), &StubGl).await.unwrap();
assert_eq!(out.sle_count, 2, "paired OUT + IN legs");
assert!(!out.gl_posted, "internal cross-warehouse move posts no GL (value-neutral)");
let (q1, r1, v1) = bin_at(&pool, item, wh1).await;
assert_eq!(q1, d("6.0000"));
assert_eq!(r1, d("100.000000"));
assert_eq!(v1, d("600.00"));
let (q2, r2, v2) = bin_at(&pool, item, wh2).await;
assert_eq!(q2, d("9.0000"));
assert_eq!(v2, d("700.00"), "carried value 4*100 blends into 300");
assert_eq!(r2, (d("700.00") / d("9")).round_dp(6), "moving average reblend");
assert_eq!(v1 + v2, d("1300.00"));
assert_eq!(quant_at(&pool, item, src).await, (d("6"), d("0")));
assert_eq!(quant_at(&pool, item, dst).await, (d("9"), d("0")));
}
#[tokio::test]
async fn inbound_move_receipt_shape() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let supplier = loc(&pool, "supplier", None).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let mut input = new_move(item, supplier, stock, "8");
input.price_unit = d("25");
let mv = w.create_move(input).await.unwrap();
w.action_confirm(mv).await.unwrap();
let a = w.action_assign(mv).await.unwrap();
assert_eq!(a.state, "assigned", "incoming supply needs no reservation");
assert_eq!(a.reserved_qty, d("8"));
let out = w.action_done(mv, BackorderPolicy::Never, &out_gl(), &StubGl).await.unwrap();
assert_eq!(out.done_qty, d("8"));
assert_eq!(out.sle_count, 1, "IN leg only");
assert!(out.gl_posted, "receipt shape: Dr Inventory / Cr GR/IR");
assert_eq!(out.gl_amount, d("200.00"), "8 * 25");
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("8"), d("0")));
let (bq, brate, bval) = bin_at(&pool, item, wh).await;
assert_eq!((bq, brate, bval), (d("8.0000"), d("25.000000"), d("200.00")));
}
#[tokio::test]
async fn waiting_gate_releases_when_parents_done() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh1 = warehouse(&w).await;
let wh2 = warehouse(&w).await;
let src = loc(&pool, "internal", Some(wh1)).await;
let mid = loc(&pool, "internal", Some(wh2)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, src, "5").await;
seed_bin(&pool, item, wh1, "5", "50").await;
let parent = w.create_move(new_move(item, src, mid, "5")).await.unwrap();
let mut child_input = new_move(item, mid, customer, "5");
child_input.move_orig_ids = vec![parent];
let child = w.create_move(child_input).await.unwrap();
assert_eq!(w.action_confirm(parent).await.unwrap(), "confirmed");
assert_eq!(w.action_confirm(child).await.unwrap(), "waiting", "parent not done — child waits");
w.action_assign(parent).await.unwrap();
w.action_done(parent, BackorderPolicy::Never, &no_gl(), &StubGl).await.unwrap();
assert_eq!(move_state(&pool, child).await, "confirmed", "all parents done — child released");
}
#[tokio::test]
async fn cancel_releases_reservation() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, stock, "10").await;
let mv = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
w.action_confirm(mv).await.unwrap();
w.action_assign(mv).await.unwrap();
let released = w.action_cancel(mv).await.unwrap();
assert_eq!(released, d("6"));
assert_eq!(move_state(&pool, mv).await, "cancel");
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("10"), d("0")), "stock untouched, reservation freed");
}
#[tokio::test]
async fn guards_reject_bad_transitions() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
let err = w.create_move(new_move(item, stock, stock, "1")).await.unwrap_err();
assert!(matches!(err, InventoryError::SameLocation { .. }));
let err = w.create_move(new_move(item, stock, customer, "-1")).await.unwrap_err();
assert!(matches!(err, InventoryError::NegativeQuantity));
let view = loc(&pool, "view", None).await;
let err = w.create_move(new_move(item, view, customer, "1")).await.unwrap_err();
assert!(matches!(err, InventoryError::ViewLocationHoldsNoStock { .. }));
let mv = w.create_move(new_move(item, stock, customer, "1")).await.unwrap();
let err = w.action_assign(mv).await.unwrap_err();
assert!(matches!(err, InventoryError::WrongMoveState { .. }), "assign on draft is refused");
w.action_confirm(mv).await.unwrap();
let err = w.action_confirm(mv).await.unwrap_err();
assert!(matches!(err, InventoryError::WrongMoveState { .. }), "confirm twice is refused");
let err = w.action_done(mv, BackorderPolicy::Never, &no_gl(), &StubGl).await.unwrap_err();
assert!(matches!(err, InventoryError::MoveLinesRequired { .. }), "R24: done needs lines");
let err = w.action_done(mv, BackorderPolicy::Never, &no_gl(), &StubGl).await.unwrap_err();
assert!(matches!(err, InventoryError::MoveLinesRequired { .. }));
}
#[tokio::test]
async fn competing_reservations_exactly_one_winner() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, stock, "6").await;
seed_bin(&pool, item, wh, "6", "10").await;
let a = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
let b = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
w.action_confirm(a).await.unwrap();
w.action_confirm(b).await.unwrap();
let oa = w.action_assign(a).await.unwrap();
assert_eq!((oa.state.as_str(), oa.reserved_qty), ("assigned", d("6")), "the winner takes all 6");
let ob = w.action_assign(b).await.unwrap();
assert_eq!((ob.state.as_str(), ob.reserved_qty), ("confirmed", d("0")),
"the loser sees insufficient available: nothing free to reserve, state stays confirmed");
let (q, r) = quant_at(&pool, item, stock).await;
assert_eq!((q, r), (d("6"), d("6")));
let avail: Decimal = sqlx::query_scalar(
"SELECT available_quantity FROM inventory.stock_quants WHERE item_id=$1 AND location_id=$2",
).bind(item).bind(stock).fetch_one(&pool).await.unwrap();
assert_eq!(avail, d("0"), "available = quantity - reserved, a read not a second writer");
let live: i64 = sqlx::query_scalar(
"SELECT COUNT(*) FROM inventory.stock_move_lines l JOIN inventory.stock_moves m ON m.id=l.move_id \
WHERE m.id = ANY($1::uuid[]) AND l.quantity > 0",
).bind(vec![a, b]).fetch_one(&pool).await.unwrap();
assert_eq!(live, 1, "exactly one mirror line lives — the loser minted none");
sqlx::query("UPDATE inventory.stock_quants SET quantity=6, available_quantity=6, reserved_quantity=0 \
WHERE item_id=$1 AND location_id=$2")
.bind(item).bind(stock).execute(&pool).await.unwrap();
let c = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
let e = w.create_move(new_move(item, stock, customer, "6")).await.unwrap();
w.action_confirm(c).await.unwrap();
w.action_confirm(e).await.unwrap();
let (oc, oe) = tokio::join!(w.action_assign(c), w.action_assign(e));
let (oc, oe) = (oc.unwrap(), oe.unwrap());
let assigned: Vec<&str> = [&oc, &oe].iter().map(|o| o.state.as_str()).filter(|s| *s == "assigned").collect();
assert_eq!(assigned.len(), 1, "exactly one winner even under the race: {:?}", (&oc.state, &oe.state));
assert_eq!(oc.reserved_qty + oe.reserved_qty, d("6"), "no over-reserve: the pair reserved exactly the free 6");
let (_, r2) = quant_at(&pool, item, stock).await;
assert_eq!(r2, d("6"), "the authoritative counter equals the free stock taken");
}
#[tokio::test]
async fn virtual_counterparts_carry_no_quant_rows() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let production = loc(&pool, "production", None).await;
let vendor = loc(&pool, "supplier", None).await;
seed_quant(&pool, item, stock, "5").await;
seed_bin(&pool, item, wh, "5", "100").await;
let mv = w.create_move(new_move(item, stock, production, "5")).await.unwrap();
w.action_confirm(mv).await.unwrap();
w.action_assign(mv).await.unwrap();
let out = w.action_done(mv, BackorderPolicy::Always, &no_gl(), &StubGl).await.unwrap();
assert_eq!(out.done_qty, d("5"));
let (pq, pr) = quant_at(&pool, item, production).await;
assert_eq!((pq, pr), (d("0"), d("0")), "virtual destination holds no quant row");
let (sq, sr) = quant_at(&pool, item, stock).await;
assert_eq!((sq, sr), (d("0"), d("0")), "the internal source was drawn to zero");
let wh2 = warehouse(&w).await;
let shelf = loc(&pool, "internal", Some(wh2)).await;
let rcv = w.create_move(new_move(item, vendor, shelf, "5")).await.unwrap();
w.action_confirm(rcv).await.unwrap();
w.action_assign(rcv).await.unwrap(); let out2 = w.action_done(rcv, BackorderPolicy::Always, &no_gl(), &StubGl).await.unwrap();
assert_eq!(out2.done_qty, d("5"));
let (vq, vr) = quant_at(&pool, item, vendor).await;
assert_eq!((vq, vr), (d("0"), d("0")), "virtual source holds no quant row");
let (hq, hr) = quant_at(&pool, item, shelf).await;
assert_eq!((hq, hr), (d("5"), d("0")), "internal destination materialized the supply");
}
#[tokio::test]
async fn cancel_frees_every_descendants_reservation() {
let pool = pool().await;
let w = InventoryWriteService::new(pool.clone());
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let customer = loc(&pool, "customer", None).await;
seed_quant(&pool, item, stock, "10").await;
let grandchild = w.create_move(new_move(item, stock, customer, "1")).await.unwrap();
w.action_confirm(grandchild).await.unwrap();
let mut child_input = new_move(item, stock, customer, "4");
child_input.move_dest_ids = vec![grandchild];
let child = w.create_move(child_input).await.unwrap();
w.action_confirm(child).await.unwrap();
w.action_assign(child).await.unwrap();
assert_eq!(quant_at(&pool, item, stock).await.1, d("4"), "the child holds its reservation");
let mut parent_input = new_move(item, stock, customer, "2");
parent_input.move_dest_ids = vec![child];
let parent = w.create_move(parent_input).await.unwrap();
w.action_confirm(parent).await.unwrap();
w.action_cancel(parent).await.unwrap();
assert_eq!(move_state(&pool, child).await, "cancel");
assert_eq!(move_state(&pool, grandchild).await, "cancel", "the cancel reaches the grandchild");
assert_eq!(quant_at(&pool, item, stock).await, (d("10"), d("0")), "the child's reservation is freed");
}
#[tokio::test]
async fn concurrent_first_counts_make_one_quant() {
let pool = pool().await;
let w = std::sync::Arc::new(InventoryWriteService::new(pool.clone()));
let item = Uuid::new_v4();
let wh = warehouse(&w).await;
let stock = loc(&pool, "internal", Some(wh)).await;
let counts: Vec<_> = (0..10)
.map(|i| {
let w = w.clone();
tokio::spawn(async move { w.stage_quant_count(item, stock, Decimal::from(i)).await })
})
.collect();
for c in counts {
c.await.unwrap().unwrap();
}
let quants: i64 = sqlx::query_scalar(
"SELECT count(*) FROM inventory.stock_quants WHERE item_id=$1 AND location_id=$2 AND (metadata->>'deleted_at') IS NULL",
)
.bind(item).bind(stock).fetch_one(&pool).await.unwrap();
assert_eq!(quants, 1, "one quant per (item, location)");
}