fix(api): decrement SKU stock only when remaining quantity is sufficient
Prevent oversell by conditioning stock updates and locking SKUs in primary-key order, and record the same concurrent-counter rule in the API spec and agent guide. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
53548196f8
commit
835afbe5e0
@@ -184,11 +184,16 @@ pub async fn insert_item(
|
||||
}
|
||||
|
||||
pub async fn decrement_stock(tx: &mut PgConnection, sku_id: Uuid, qty: i32) -> ApiResult<()> {
|
||||
sqlx::query("UPDATE skus SET stock = stock - $2 WHERE id = $1")
|
||||
.bind(sku_id)
|
||||
.bind(qty)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
let result = sqlx::query(
|
||||
"UPDATE skus SET stock = stock - $2 WHERE id = $1 AND stock >= $2",
|
||||
)
|
||||
.bind(sku_id)
|
||||
.bind(qty)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
if result.rows_affected() == 0 {
|
||||
return Err(ApiError::Conflict("insufficient stock".into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -329,6 +334,7 @@ pub async fn lock_purchasable_skus(
|
||||
JOIN shops sh ON sh.id = p.shop_id
|
||||
WHERE s.id = ANY($1) AND s.active = TRUE
|
||||
AND p.status = 'published' AND sh.status = 'active'
|
||||
ORDER BY s.id
|
||||
FOR UPDATE OF s",
|
||||
)
|
||||
.bind(sku_ids)
|
||||
|
||||
Reference in New Issue
Block a user