feat(economy): purchase_items primitive + entitlement import seeding

purchase_items: generic atomic debit + mint of several items (fail-closed) for
open-on-buy Store packs (Store BUY returns items immediately) + POST
/economy/purchase-items route. Import: add optional entitlements[] to
ProfileImportRequest, seeding unconsumed packs rows in the same transaction (so a
source's unopened packs become Core entitlements); idempotency via the existing
import fingerprint. Tests: 2 purchase_items unit + endpoint + entitlement-seed
import. Core matrix 45 lib + 116 integration + 9 import green; clippy clean.
This commit is contained in:
OpenFUT Agent
2026-08-13 19:27:06 +00:00
parent d32dc6e3ae
commit bcc4f5104a
6 changed files with 150 additions and 2 deletions
+22
View File
@@ -2776,3 +2776,25 @@ async fn test_economy_insufficient_funds_fail_closed() {
.iter()
.any(|e| e["definition_id"] == "pack-x"));
}
#[tokio::test]
async fn test_economy_purchase_items_debits_and_mints_all() {
let app = build_test_app().await;
auth(&app, "econ-e").await;
let (st, buy) = json_post(
&app,
"/economy/purchase-items",
serde_json::json!({
"cost": 800,
"items": [
{"item_id": "bx-1", "card_id": "d-1"},
{"item_id": "bx-2", "card_id": "d-2"}
]
}),
)
.await;
assert_eq!(st, StatusCode::OK);
assert_eq!(buy["balance"], 4200);
let (_, bal) = json_get(&app, "/economy/balance").await;
assert_eq!(bal["balance"], 4200);
}