def user_cart_checkout(_id): users = mongo.db.users items = mongo.db.items user = users.find_and_modify( {'_id': _id, 'trading': False}, {'$set': {'cart': []}}, fields={'cart': 1, 'items': 1}, ) if not user or not user.get('cart'): return False, 'no cart or user is trading' cart = user.get('cart', {}) item_count = len(user.get('items', {})) if item_count > ITEM_LIMIT: return previous_gold = mongo.db.users.find_one( {'_id': _id}, {'credits': 1} ).get('credits', 0) # add items back to cart if we don't end up checking out errors = [] added = [] for item in cart: item_count += 1 if item_count > ITEM_LIMIT: return query = { 'class_id': item['class_id'], 'instance_id': item['instance_id'], } item = lookup_single(query) if item: price = item.get('price') if not price: errors.append((item, 'no price set')) continue short_keys = { 'app_id', 'context_id', 'class_id', 'instance_id', } short_item = {} for key in short_keys: short_item[key] = item[key] # subtract money from user old = users.find_and_modify( {'_id': _id, 'credits': {'$gte': price}}, {'$inc': {'credits': -price}}, fields={'inventory': 0}, ) if not old: # couldn't afford it errors.append((item, 'not enough gold')) continue # modify stock available query = short_item.copy() query.update({'available': {'$gt': 0}}) old = items.find_and_modify(query, {'$inc': {'available': -1}}) if not old: # not enough of item available, refund money users.update({'_id': _id}, {'$inc': {'credits': price}}) errors.append((item, 'out of stock')) continue # TODO: adjust hotness here # add to the user's item pool users.update( {'_id': _id}, {'$push': {'items': short_item}}, ) # add the price back in so we'll have it for the ledger short_item['price'] = price added.append(short_item) # TODO: do something with errored items here? mongo.db.ledger.insert({ 'user_id': _id, 'items': added, 'change': -sum(item['price'] for item in added), 'previous': previous_gold, 'time': time.time(), }) return True, 'success'