Skip to content

Commit 5bcc38b

Browse files
authored
Merge pull request #19 from offish/v2.0.2
update trade data, prepare for stock
2 parents 8ca6419 + 834de85 commit 5bcc38b

7 files changed

Lines changed: 139 additions & 43 deletions

File tree

express/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
__title__ = "tf2-express"
22
__author__ = "offish"
33
__license__ = "MIT"
4-
__version__ = "2.0.0"
4+
__version__ = "2.0.2"

express/database.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def insert_trade(self, data: dict) -> None:
2424
def get_trades(
2525
self, start_index: int, amount: int
2626
) -> tuple[list[dict], int, int, int]:
27+
# sort newest trades first
2728
all_trades = list(self.trades.find().sort("time_updated", -1))
2829
total = len(all_trades)
2930
intended_end_index = start_index + amount
@@ -65,6 +66,33 @@ def get_item(self, sku: str) -> dict | None:
6566
def get_pricelist(self) -> list[dict]:
6667
return self.items.find()
6768

69+
def get_stock(self, sku: str) -> list[int, int]:
70+
"""returns in_stock, max_stock"""
71+
data = self.__get_data(sku)
72+
73+
return (data.get("in_stock", 0), data.get("max_stock", 0))
74+
75+
def replace_item(self, data: dict) -> None:
76+
self.items.replace_one({"sku": data["sku"]}, data)
77+
78+
def update_stocks(self, stock: dict) -> None:
79+
all_items = self.items.find()
80+
81+
for item in all_items:
82+
sku = item["sku"]
83+
84+
if sku not in stock:
85+
continue
86+
87+
in_stock = stock[sku]
88+
89+
# in_stock is the same, no need to update
90+
if item.get("in_stock", 0) == in_stock:
91+
continue
92+
93+
item["in_stock"] = in_stock
94+
self.replace_item(item)
95+
6896
def add_price(self, sku: str, color: str, image: str, name: str) -> None:
6997
self.items.insert_one(
7098
{

express/express.py

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1+
from .inventory import get_inventory_stock
12
from .database import Database
23
from .options import Options
3-
from .offer import valuate
4+
from .offer import valuate, OfferData
45

6+
from dataclasses import asdict
57
from json import dumps
68
import logging
79
import time
810

911
from steampy.exceptions import InvalidCredentials
1012
from steampy.client import SteamClient
11-
from tf2_utils import Offer, to_refined, refinedify, PricesTF
13+
from tf2_utils import (
14+
Offer,
15+
Inventory,
16+
PricesTF,
17+
to_refined,
18+
refinedify,
19+
account_id_to_steam_id,
20+
)
1221

1322

1423
class Express:
@@ -21,15 +30,17 @@ def __init__(self, bot: dict, options: Options) -> None:
2130
self.client = SteamClient(bot["api_key"])
2231
self.db = Database(options.database)
2332
self.pricer = PricesTF()
33+
self.inventory = Inventory("steamcommunity") # use apikey?
2434

25-
# TODO: make processed and values into offers list[Offer]
26-
self.values = {}
27-
self.processed = []
35+
self.stock = {}
36+
self.processed: list[OfferData] = []
2837
self.last_offer_fetch = 0
2938
self.options = options
3039

3140
self.is_enabled = True
32-
# TODO: add processed_offers, accepted_offers, active_offers for status
41+
self.active_offers = 0
42+
self.processed_offers = 0
43+
self.accepted_offers = 0
3344

3445
self.prices_to_check = []
3546

@@ -90,7 +101,7 @@ def __get_offers(self) -> list[dict]:
90101
"trade_offers_received"
91102
]
92103
except Exception as e:
93-
logging.error(f"Did not get wanted response when getting offers: {e}")
104+
logging.error(f"{e}")
94105
return [{}]
95106

96107
def __get_offer(self, offer_id: str) -> dict:
@@ -126,17 +137,24 @@ def __process_offer(self, offer: dict) -> None:
126137
if not offer_id:
127138
return
128139

129-
if offer_id in self.processed:
140+
for offer_data in self.processed:
141+
if offer_id != offer_data.offer_id:
142+
continue
143+
130144
logging.debug(f"({offer_id}) has already been processed")
131145
return
132146

133147
self.__log_trade("Processing offer", offer_id)
134148

135149
# we assume we wont crash, add to processed now
136150
# so if we return early, we wont process again
137-
self.processed.append(offer_id)
151+
offer_data = OfferData(offer_id)
152+
self.processed.append(offer_data)
138153
logging.debug(f"Added offer {offer_id} to processed list")
139154

155+
self.active_offers += 1
156+
self.processed_offers += 1
157+
140158
trade = Offer(offer)
141159

142160
if not trade.is_active():
@@ -153,10 +171,13 @@ def __process_offer(self, offer: dict) -> None:
153171
their_items = offer["items_to_receive"]
154172
our_items = offer["items_to_give"]
155173

156-
self.values[offer_id] = {
157-
"their_items": their_items,
158-
"our_items": our_items,
159-
}
174+
# add offer data
175+
offer_data.message = offer["message"]
176+
offer_data.steam_id_other = account_id_to_steam_id(offer["accountid_other"])
177+
offer_data.time_created = offer["time_created"]
178+
offer_data.time_updated = offer["time_updated"]
179+
offer_data.their_items = their_items
180+
offer_data.our_items = our_items
160181

161182
# is owner
162183
if partner_steam_id in self.options.owners:
@@ -188,6 +209,10 @@ def __process_offer(self, offer: dict) -> None:
188209
# get mann co key buy and sell price
189210
key_prices = self.db.get_item("5021;6")
190211

212+
# TODO: handle if in_stock + new items would
213+
# surpass max_stock. -100;6 is edge case
214+
# max_stock = -1 is unlimited
215+
191216
# we dont care about unpriced items on their side
192217
their_value, _ = valuate(
193218
self.db, their_items, "buy", all_skus, key_prices, self.options
@@ -213,8 +238,9 @@ def __process_offer(self, offer: dict) -> None:
213238
)
214239
)
215240

216-
self.values[offer_id]["our_value"] = our_value
217-
self.values[offer_id]["their_value"] = their_value
241+
offer_data.their_value = their_value
242+
offer_data.our_value = our_value
243+
offer_data.has_unpriced = has_unpriced
218244

219245
self.__log_trade(summary)
220246

@@ -244,52 +270,45 @@ def __process_offers(self) -> None:
244270
logging.info("No new offers available")
245271
return
246272

247-
logging.info(f"Processing {amount} offers")
273+
# logging.info(f"Processing {amount} offers")
248274

249275
for offer in offers:
250276
self.__process_offer(offer)
251277

252278
def __update_offer_states(self) -> None:
253-
active_offers = 0
279+
if self.active_offers:
280+
logging.info(f"{self.active_offers} offer(s) are still active")
254281

255-
for offer_id in self.processed:
256-
offer = self.__get_offer(offer_id)
282+
for offer_data in self.processed.copy():
283+
offer = self.__get_offer(offer_data.offer_id)
257284
trade = Offer(offer)
258285

286+
offer_data.state = trade.get_state()
287+
259288
if trade.is_active():
260-
active_offers += 1
261289
continue
262290

263-
if not trade.is_active():
264-
self.__log_trade(
265-
f"Offer state changed to {trade.get_state()}", offer_id
266-
)
267-
# we have processed the offer if its not active anymore
268-
self.processed.remove(offer_id)
291+
self.active_offers -= 1
292+
293+
self.__log_trade(
294+
f"Offer state changed to {trade.get_state()}", offer_data.offer_id
295+
)
269296

270297
if trade.is_accepted():
298+
self.accepted_offers += 1
299+
300+
# TODO: increment in_stock, -100;6 edge case
301+
271302
if self.options.save_trades:
272303
logging.info("Saving offer data...")
273304

274-
if offer_id in self.values:
275-
offer["their_items"] = self.values[offer_id]["their_items"]
276-
offer["our_items"] = self.values[offer_id]["our_items"]
277-
offer["our_value"] = self.values[offer_id].get("our_value", 0.0)
278-
offer["their_value"] = self.values[offer_id].get(
279-
"their_value", 0.0
280-
)
281-
282305
if offer.get("tradeid") and self.options.save_receipt:
283-
offer["receipt"] = self.__get_receipt(offer["tradeid"])
306+
offer_data.receipt = self.__get_receipt(offer["tradeid"])
284307

285-
self.db.insert_trade(offer)
308+
self.db.insert_trade(asdict(offer_data))
286309
logging.info("Offer was added to the database")
287310

288-
if offer_id in self.values:
289-
self.values.pop(offer_id)
290-
291-
if active_offers:
292-
logging.info(f"{active_offers} offer(s) are still active")
311+
self.processed.remove(offer_data)
293312

294313
def __append_autopriced_items(self) -> None:
295314
autopriced_items = self.db.get_autopriced()
@@ -308,6 +327,13 @@ def run(self) -> None:
308327
self.__append_autopriced_items()
309328
self.__update_prices()
310329

330+
inventory = self.inventory.fetch(self.steam_id)
331+
self.stock = get_inventory_stock(inventory)
332+
333+
self.db.update_stocks(self.stock)
334+
335+
del inventory
336+
311337
while True:
312338
# bot is disabled
313339
if not self.is_enabled:

express/inventory.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from tf2_utils import map_inventory
2+
3+
4+
def get_inventory_stock(inventory: dict) -> dict:
5+
# {sku: amount}
6+
stock = {}
7+
8+
for item in map_inventory(inventory, True):
9+
sku = item["sku"]
10+
11+
if item["tradable"] != True:
12+
continue
13+
14+
if sku not in stock:
15+
stock[sku] = 1
16+
else:
17+
stock[sku] += 1
18+
19+
return stock

express/offer.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,28 @@
22
from .options import Options
33
from .items import Item
44

5+
from dataclasses import dataclass, field
56
import logging
67

78
from tf2_utils import get_sku, to_scrap
89

910

11+
@dataclass
12+
class OfferData:
13+
offer_id: str
14+
steam_id_other: str = ""
15+
message: str = ""
16+
time_created: int = 0
17+
time_updated: int = 0
18+
their_items: dict = field(default_factory=dict)
19+
our_items: dict = field(default_factory=dict)
20+
our_value: float = 0.0
21+
their_value: float = 0.0
22+
state: str = "Processed"
23+
has_unpriced: bool = True
24+
receipt: dict = field(default_factory=dict)
25+
26+
1027
def valuate(
1128
db: Database,
1229
items: dict,

express/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def summarize_trades(trades: list[dict]) -> list[dict]:
3434
their_items_summary = summarize_items(trade.get("their_items", []))
3535
our_items_summary = summarize_items(trade.get("our_items", []))
3636

37+
# add this to the db so it does not need to be done again?
3738
summary.append(
3839
{
3940
**trade,

templates/trades.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ <h1>Trades</h1>
2020
{% for trade in trades %}
2121
<div>
2222
<br><br>
23-
<h2>Trade #{{ trade.tradeofferid }}</h2>
23+
<h2>Offer #{{ trade.offer_id }}</h2>
2424
{% if trade.message %}
2525
<p>Message: {{ trade.message }}</p>
2626
{% endif %}
27+
<ul>
28+
<li><a href="https://steamcommunity.com/profiles/{{ trade.steam_id_other }}">Steam Profile</a></li>
29+
<li><a href="https://backpack.tf/profiles/{{ trade.steam_id_other }}">BackpackTF</a></li>
30+
<li><a href="https://rep.tf/{{ trade.steam_id_other }}">RepTF</a></li>
31+
</ul>
2732
<p>Created: {{ trade.time_created }}</p>
2833
<p>Accepted: {{ trade.time_updated }}</p>
2934

0 commit comments

Comments
 (0)