Simulation API

A merchant wants to offer products and maximize profits. Just like on a real online marketplace, he can look at all existing offers, add some own, restock or reprice. First, it has to order products from the producer, which comes with costs. All Pricewars entities are implemented as services, and their interfaces (REST) are described in detail here.

This notebook will present how to use the Pricewars APIs to do all these tasks easily. From registration to buying products, offering them and repricing them. Using this, it is possible to build a powerful merchant.

Note: The code is type-hinted, so using an IDE (e.g. PyCharm/IntelliJ or an IPython/Jupyter notebook) provides you with auto-completion.

If you want to try the following examples, make sure that the Pricewars plattform is running. Either by deploying them individually or by using the docker setup.

The following step is specific for this notebook. It is not necessary if your merchant is in the repository root.


In [9]:
import sys
sys.path.append('../')

Initialize Marketplace API


In [10]:
from api import Marketplace
marketplace = Marketplace()

If the marketplace doesn't run on the default URL, you can change it with the host argument

Register as merchant

In order to act on the marketplace, we need to be a registered merchant. Usually you use the Management UI to register a merchant and remember/keep the merchant_token. However, you can also use an API call.

You will also have to provie an API endpoint for your merchant, which will be called upon sales of products. We will simply use an invalid one, since this is only an example.


In [16]:
registration = marketplace.register(
    'http://nobody:55000/',
    merchant_name='notebook_merchant',
    algorithm_name='human')

registration


Out[16]:
{'merchant_token': 'Qb3JxrP4T1UWyKWHarmPGjsOEkWnkRvA2xT0pt4ItYptsMATEwsTglruWOiHpeRr', 'algorithm_name': 'human', 'merchant_name': 'notebook_merchant', 'api_endpoint_url': 'http://nobody:55000/', 'merchant_id': 'autUGujAXiMPaZCwJcRTI1/8hFDXqH1khg6G8fl2BNU='}

It was not possible to connect to the marketplace if you got the following error:

ConnectionError: HTTPConnectionPool(host='marketplace', port=8080)

In that case, make sure that the marketplace is running and host and port are correct. If host or port are wrong, you can change it by creating a marketplace object with the host argument:

marketplace = Marketplace(host=www.another_host.com:1234)

Check offers on the market


In [19]:
offers = marketplace.get_offers()
offers


Out[19]:
[{'price': 22.75, 'amount': 1953, 'offer_id': 2, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 1}, 'signature': '', 'merchant_id': '79Qj3UKaNep4GpXXtKLFt8Y1hEMTH1KQd+p+wFwvt/I='},
 {'price': 22.65, 'amount': 1934, 'offer_id': 1, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 1}, 'signature': '', 'merchant_id': '9vLjL+h81Nql8ZLBBxnm70SDZZE98IAGAuMaj1JRmC8='},
 {'price': 22.55, 'amount': 20, 'offer_id': 3, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 1}, 'signature': '', 'merchant_id': '8Ezxj8Q/GvFcwa0CT3zoNyr5Hg3ZuNIs+E/LbVn9R3U='}]

The result is a list of Offer objects.


In [20]:
type(offers[0])


Out[20]:
models.Offer.Offer

If you want a state-less merchant, you can set the argument include_empty_offers to True. This will add your own, but out-of-stock offers to be added to the response.

Initialize Producer API

To be able to call authenticated functions (like ordering products), we must provide our merchant token.


In [23]:
from api import Producer
producer = Producer(token=registration.merchant_token)

Order products

Order any amount of units of a product:


In [25]:
order = producer.order(amount=10)
order


Out[25]:
{'billing_amount': 160, 'product': {'amount': 10, 'quality': 1, 'product_id': 1, 'name': 'CD_1', 'time_to_live': -1, 'uid': 11, 'signature': 'g0UFLCYfY5aFni311PuOfwLsAKFyiGW9mVK0HrgFRA0TchE0/CCoAjIXZfgozjMcjJb6+THRJBQQcoYEbqIHIt13Hfomx5yAMP2ndbGvz4tm6FvxNK1m5dmWsIRb9fPiZuhb8TStZuXZlrCEW/Xz4mboW/E0rWbl2ZawhFv18+I=', 'start_of_lifetime': -1}, 'left_in_stock': None, 'stock': -1}

The order contains 10 units of a product. The billing_amount is the total cost that the merchant must pay for this order.


In [26]:
type(order)


Out[26]:
models.Order.Order

Add product to marketplace

To create a new offer, you need a product, a selling price for that offer and guaranteed shipping times.

Let's use a price of 35€ and any shipping times.


In [28]:
from models import Offer

price = 35
shipping_time = {'standard': 5, 'prime': 2}

offer = Offer.from_product(order.product, price, shipping_time)
offer


Out[28]:
{'price': 35, 'amount': 10, 'offer_id': -1, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 2}, 'signature': 'g0UFLCYfY5aFni311PuOfwLsAKFyiGW9mVK0HrgFRA0TchE0/CCoAjIXZfgozjMcjJb6+THRJBQQcoYEbqIHIt13Hfomx5yAMP2ndbGvz4tm6FvxNK1m5dmWsIRb9fPiZuhb8TStZuXZlrCEW/Xz4mboW/E0rWbl2ZawhFv18+I=', 'merchant_id': None}

Send the offer to the marketplace. The accepted offer with its new offer ID is returned.


In [30]:
offer = marketplace.add_offer(offer)
offer


Out[30]:
{'price': 35, 'amount': 10, 'offer_id': 4, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 2}, 'signature': '', 'merchant_id': 'autUGujAXiMPaZCwJcRTI1/8hFDXqH1khg6G8fl2BNU='}

Let's see, if we can find the new offer on the marketplace:


In [31]:
[market_offer for market_offer in marketplace.get_offers() if market_offer.offer_id == offer.offer_id][0]


Out[31]:
{'price': 35.0, 'amount': 10, 'offer_id': 4, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 2}, 'signature': '', 'merchant_id': 'autUGujAXiMPaZCwJcRTI1/8hFDXqH1khg6G8fl2BNU='}

Update product on marketplace

Updating an offer, e.g. changing its price, is a limited API request. According to your simulation/marketplace settings, we can only call it N times per second.


In [33]:
offer.price = 28
marketplace.update_offer(offer)

In [34]:
[market_offer for market_offer in marketplace.get_offers() if market_offer.offer_id == offer.offer_id][0]


Out[34]:
{'price': 28.0, 'amount': 10, 'offer_id': 4, 'quality': 1, 'product_id': 1, 'uid': 11, 'prime': False, 'shipping_time': {'standard': 5, 'prime': 2}, 'signature': '', 'merchant_id': 'autUGujAXiMPaZCwJcRTI1/8hFDXqH1khg6G8fl2BNU='}

Unregister the merchant

You should keep your merchant and the token as long as possible, because it is the reference to all market data (sales, profit, marketshare), offers and products.

However, if you just try things out, like in this sample and don't want to pollute the database with lots of merchants, unregister it. This also removes all offers and products.


In [35]:
marketplace.unregister()

Now, it shouldn't be possible to do authenticated actions.


In [43]:
from api.ApiError import ApiError

offer.price = 35
try:
    marketplace.update_offer(offer)
except ApiError as e:
    print("I can't do that")
    print(e)


I can't do that

Status code: 401
URL: http://marketplace:8080/offers/4
Text: {"message":"Not authorized!","code":401}

In [ ]: