fifa17-recon: transfer market sell/list flow (stateful, tested)
Complete the market loop (browse + buy + sell). POST auctionhouse (FutISStart)
lists an owned club item -> profile.listings + returns {id:tradeId}. tradePile
builds a validated auction record per listing from the owned item + prices
(freeze-safe, same 0x18013e410 shape). DELETE trade/{id} removes the listing.
fut_store gains list_for_sale/listings/remove_listing (tradeId space 900500000+).
test_market_buy.py extended with sell/delist checks (temp profile, no real-save
mutation): list -> tradePile shows it with prices -> delist empties it. All pass.
Read-only contract suite still 311/311. Functional (FIFA's exact sell params)
pending live test; freeze-safe by construction.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PN5bmpDVQR1aXgefyWAt7o
This commit is contained in:
@@ -190,7 +190,7 @@ ROUTES = [
|
||||
(re.compile(G + r"/watchList"), lambda m, h: watchlist_route(h)),
|
||||
(re.compile(G + r"/auctionhouse"), lambda m, h: auctionhouse_route(h)),
|
||||
(re.compile(G + r"/marketdata"), lambda m, h: (200, {"minPrice": 150, "maxPrice": 15000})),
|
||||
(re.compile(r"/ut/delete/game/[^/]+/trade"), lambda m, h: (200, {})),
|
||||
(re.compile(r"/ut/delete/game/[^/]+/trade"), lambda m, h: delete_trade_route(h)),
|
||||
(re.compile(r"/ut/delete/game/[^/]+/watchList"), lambda m, h: (200, {})),
|
||||
(re.compile(G + r"/club"), lambda m, h: (200, {"itemData": STORE.items()})),
|
||||
]
|
||||
@@ -383,6 +383,16 @@ def auctionhouse_route(h):
|
||||
# POST = FutISStart (list item for sale) -> {"id": new tradeId}
|
||||
# PUT = .../relist (relist all expired) -> ack {}
|
||||
if h.command == "POST":
|
||||
# FutISStart: list an owned club item for sale -> {"id": tradeId}
|
||||
try:
|
||||
b = json.loads(h._body.decode()) if getattr(h, "_body", b"") else {}
|
||||
except Exception:
|
||||
b = {}
|
||||
item_id = (b.get("itemData") or {}).get("id") or b.get("itemId")
|
||||
if item_id:
|
||||
tid = STORE.list_for_sale(item_id, b.get("startingBid", 150), b.get("buyNowPrice", 0))
|
||||
log(" MARKET: listed item %s -> tradeId %d" % (item_id, tid))
|
||||
return 200, {"id": tid}
|
||||
return 200, {"id": STORE.new_item_id()}
|
||||
if h.command == "PUT":
|
||||
return 200, {}
|
||||
@@ -427,8 +437,31 @@ def trade_route(h):
|
||||
|
||||
|
||||
def tradepile_route(h):
|
||||
# The user's OWN sale pile -- empty until they list something (no live sell flow yet).
|
||||
return 200, {"auctionInfo": [], "credits": STORE.coins(), "total": 0}
|
||||
# The user's OWN sale pile: build a validated auction record per active listing
|
||||
# from the owned club item + its list prices. Freeze-safe (same record shape).
|
||||
by_id = {it["id"]: it for it in STORE.items()}
|
||||
seller = STORE.profile().get("personaName", "OpenFUT")
|
||||
recs = []
|
||||
for l in STORE.listings():
|
||||
it = by_id.get(l["itemId"])
|
||||
if not it:
|
||||
continue
|
||||
card = dict(it); card["itemState"] = "listFS"
|
||||
recs.append({
|
||||
"tradeId": l["tradeId"], "itemData": card, "tradeState": "active",
|
||||
"buyNowPrice": l.get("buyNowPrice", 0), "startingBid": l.get("startingBid", 150),
|
||||
"currentBid": 0, "bidState": "none", "expires": 3600,
|
||||
"sellerName": seller, "sellerEstablished": 1, "watched": False, "coinsProcessed": 0,
|
||||
})
|
||||
return 200, {"auctionInfo": recs, "credits": STORE.coins(), "total": len(recs)}
|
||||
|
||||
|
||||
def delete_trade_route(h):
|
||||
# DELETE ut/delete/game/fifa17/trade/{id} -- remove a listing from the sale pile.
|
||||
m = re.search(r"/trade/(\d+)", h.path)
|
||||
if m:
|
||||
STORE.remove_listing(int(m.group(1)))
|
||||
return 200, {}
|
||||
|
||||
|
||||
def watchlist_route(h):
|
||||
|
||||
Reference in New Issue
Block a user