fix(market): returning an item to the club ends its auction; close the panel probe
CLOSES the active-own-auction Actions-panel investigation. Live client plus the RE corpus plus historical FUT behaviour all agree: an active auction is COMMITTED until sale or expiry and is not seller-actionable, while an expired unsold item becomes actionable (relist / return to club). Every observation fits that lifecycle -- active+frozen expires was non-selectable, expired was selectable and relisted fine, relisting made it active and non-selectable again, and the client never emits a cancel. Documented with confidence tags, and the dead ends are named so they are not retried: MAY_BE_REMOVED is a constant 1, and the eight-flag array is the CLUB-CARD menu with no auction-cancellation flag in it. Implements the return-to-club transition that closure exposes. A pile move to `club` now cancels any ACTIVE listing on that item, because the auction that put the card in the pile has to end with it. Otherwise the pile reads `club` while the row stays `active`, so the card is filtered out of /club (exclusion keys on active listings) AND still rendered in the Transfer List: the move appears to do nothing. This is the same limbo class as the earlier pile-vs-listing bug, found by reasoning about the transition rather than by another live failure. Scoped to `active` only: a `reserved` row is mid-sale and a `sold` row is already gone, so cancelling either would let one card be both sold and returned. Two tests cover exactly that boundary. 338 tests pass, 0 failed, clippy clean.
This commit is contained in:
@@ -592,6 +592,33 @@ impl MarketStore {
|
||||
}
|
||||
self.get_listing(listing_id).await
|
||||
}
|
||||
|
||||
/// Cancel any `active` listing held by a Core owned item, returning how many
|
||||
/// rows were cancelled (0 when the item has no live auction).
|
||||
///
|
||||
/// This is the RETURN-TO-CLUB transition: the client sends a pile move for an
|
||||
/// expired transfer-list item, and the auction that put it there has to end with
|
||||
/// it. Without this the pile says `club` while the listing row stays `active`,
|
||||
/// so the card is still filtered out of `/club` AND still rendered in the
|
||||
/// Transfer List — the item appears not to move at all.
|
||||
///
|
||||
/// Deliberately scoped to `active`: a `reserved` row is mid-sale and a `sold`
|
||||
/// row is already gone, and cancelling either would let a card be both sold and
|
||||
/// returned.
|
||||
pub async fn cancel_active_for_core_item(
|
||||
&self,
|
||||
core_item_id: &str,
|
||||
) -> Result<u64, MarketError> {
|
||||
Ok(sqlx::query(
|
||||
"UPDATE listings SET state = 'cancelled' \
|
||||
WHERE core_item_id = ? AND state = 'active'",
|
||||
)
|
||||
.bind(core_item_id)
|
||||
.execute(&self.pool)
|
||||
.await
|
||||
.map_err(db)?
|
||||
.rows_affected())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user