Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ JSON data is returned "as is":
Retailer API
============

Supports the BOL Api v8, documented here: https://api.bol.com/retailer/public/Retailer-API/selling-on-bolcom-processflow.html
Supports the BOL Api v10, documented here: https://api.bol.com/retailer/public/Retailer-API/selling-on-bolcom-processflow.html

Instantiate the API::

Expand Down
2 changes: 1 addition & 1 deletion bol/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = (1, 3, 0, 'final', 0)
VERSION = (1, 4, 0, 'final', 0)

__title__ = 'python-bol-api'
__version_info__ = VERSION
Expand Down
2 changes: 1 addition & 1 deletion bol/openapi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class OpenAPI(object):
def __init__(self, api_key, timeout=None, session=None):
self.api_key = api_key
self.url = 'https://api.bol.com'
self.version = 'v4'
self.version = 'v10'
self.catalog = CatalogMethods(self)
self.timeout = timeout
self.session = session or requests.Session()
Expand Down
82 changes: 74 additions & 8 deletions bol/retailer/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
Replenishments,
TimeSlots,
Inventories,
ProductContents
ProductContents,
Insights,
PerformanceIndicators,
ProductRanks,
SalesForecast,
SearchTerms
)

__all__ = ["RetailerAPI"]
Expand Down Expand Up @@ -230,7 +235,7 @@ def createShippingLabel(self, orderitems_list, label_id):

def getShippingLabel(self, shipping_label_id):
headers = {
"accept": "application/vnd.retailer.v8+pdf"
"accept": "application/vnd.retailer.v10+pdf"
}
response = self.request('GET', path=str(shipping_label_id), headers=headers)
return response
Expand Down Expand Up @@ -287,7 +292,7 @@ def requestExportFile(self):

def getOffersFile(self, export_id):
headers = {
"accept": "application/vnd.retailer.v8+csv"
"accept": "application/vnd.retailer.v10+csv"
}
response = self.request('GET', path='export/{}'.format(export_id),
headers=headers)
Expand All @@ -298,6 +303,65 @@ def deleteOffers(self, offer_id):
return ProcessStatus.parse(self.api, response.text)


class InsightsMethods(MethodGroup):

def __init__(self, api):
super(InsightsMethods, self).__init__(api, 'insights')

def getOfferInsights(self, offer_id, period, number_of_periods, name):
if offer_id and period and number_of_periods and name and isinstance(name, list):
params = {
'offer-id': offer_id,
'period': period,
'number-of-periods': number_of_periods,
'name': ','.join(name),
}
resp = self.request("GET", path="offer", params=params)
return Insights.parse(self.api, resp.text)

def getPerformanceIndicators(self, name, year, week):
if name and isinstance(name, list) and year and week:
params = {
'name': ','.join(name),
'year': year,
'week': week
}
resp = self.request("GET", path="performance/indicator", params=params)
return PerformanceIndicators.parse(self.api, resp.text)

def getProductRanks(self, ean, date, type=None, page=1):
if ean and date:
params = {'ean': ean, 'date': date}
if type:
params["type"] = ','.join(type)
if page != 1:
params["page"] = page

resp = self.request("GET", path="product-ranks", params=params)
return ProductRanks.parse(self.api, resp.text)

def getSalesForecast(self, offer_id, weeks_ahead):
if offer_id and weeks_ahead:
params = {
"offer-id": offer_id,
"weeks-ahead": weeks_ahead
}
resp = self.request("GET", path="sales-forecast", params=params)
return SalesForecast.parse(self.api, resp.text)

def getSearchTerms(self, search_term, period, number_of_periods, related_search_terms=None):
if search_term and period and number_of_periods:
params = {
"search-term": search_term,
"period": period,
"number-of-periods": number_of_periods
}
if related_search_terms:
params["related-search-terms"] = related_search_terms

resp = self.request("GET", path="search-terms", params=params)
return SearchTerms.parse(self.api, resp.text)

class ReturnsMethods(MethodGroup):
def __init__(self, api):
super(ReturnsMethods, self).__init__(api, "returns")
Expand Down Expand Up @@ -352,7 +416,7 @@ def getProductLabels(self, labelFormat, products):
}

headers = {
"accept": "application/vnd.retailer.v8+pdf"
"accept": "application/vnd.retailer.v10+pdf"
}
response = self.request("POST", path="product-labels", headers=headers, json=params)
return response
Expand All @@ -367,14 +431,14 @@ def update(self, replenishment_id, **param):

def getLoadCarrierLabels(self, replenishment_id, label_type="WAREHOUSE"):
headers = {
"accept": "application/vnd.retailer.v8+pdf"
"accept": "application/vnd.retailer.v10+pdf"
}
response = self.request("GET", path='{}/load-carrier-labels'.format(replenishment_id), headers=headers, json=label_type)
return response

def getPickList(self, replenishment_id):
headers = {
"accept": "application/vnd.retailer.v8+pdf"
"accept": "application/vnd.retailer.v10+pdf"
}
response = self.request("GET", path='{}/pick-list'.format(replenishment_id), headers=headers)
return response
Expand Down Expand Up @@ -444,6 +508,8 @@ def __init__(
self.transports = TransportMethods(self)
self.session = session or requests.Session()
self.session.headers.update({"Accept": "application/json"})
self.insights = InsightsMethods(self)


def login(self, client_id, client_secret):
data = {
Expand Down Expand Up @@ -494,7 +560,7 @@ def set_access_token(self, access_token):
self.session.headers.update(
{
"Authorization": "Bearer " + access_token,
"Accept": "application/vnd.retailer.v8+json",
"Accept": "application/vnd.retailer.v10+json",
}
)

Expand All @@ -514,7 +580,7 @@ def request(self, method, uri, params={}, **kwargs):
# If these headers are not added, the api returns a 400
# Reference:
# https://api.bol.com/retailer/public/conventions/index.html
content_header = "application/vnd.retailer.v8+json"
content_header = "application/vnd.retailer.v10+json"

request_kwargs["headers"].update({
"content-type": content_header
Expand Down
112 changes: 111 additions & 1 deletion bol/retailer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,127 @@ class Meta:


class Offer(Model):

class Meta:
pass


class Product(Model):
class Meta:
pass


class Country(Model):
class Meta:
pass


class Countries(ModelList):
class Meta:
item_type = Country


class PeriodData(Model):
class Meta:
pass


class TotalData(Model):
class Meta:
pass


class Period(Model):
class Meta:
countries = ModelField(Countries)
total = RawField()
period = ModelField(PeriodData)


class Periods(ModelList):
class Meta:
item_type = Period


class Insight(Model):
class Meta:
countries = ModelField(Countries)
periods = ModelField(Periods)


class Insights(ModelList):
class Meta:
item_type = Insight
items_key = "offerInsights"


class Score(Model):
class Meta:
pass


class Norm(Model):
class Meta:
pass


class Details(Model):
class Meta:
period = ModelField(PeriodData)
score = ModelField(Score)
norm = ModelField(Norm)


class PerformanceIndicator(Model):
class Meta:
details = ModelField(Details)


class PerformanceIndicators(ModelList):
class Meta:
item_type = PerformanceIndicator
items_key = "performanceIndicators"


class ProductRank(Model):
class Meta:
pass


class ProductRanks(ModelList):
class Meta:
item_type = ProductRank
items_key = "ranks"


class SalesForecast(Model):
class Meta:
countries = ModelField(Countries)
periods = ModelField(Periods)
total = ModelField(TotalData)


class RelatedSearchTerm(Model):
class Meta:
pass


class RelatedSearchTerms(ModelList):
class Meta:
item_type = RelatedSearchTerm


class SearchTermsData(Model):
class Meta:
countries = ModelField(Countries)
periods = ModelField(Periods)
relatedSearchTerms = ModelField(RelatedSearchTerms)


class SearchTerms(Model):
class Meta:
searchTerms = ModelField(SearchTermsData)


class additionalService(Model):
class Meta:
pass
Expand Down
2 changes: 1 addition & 1 deletion tests/test_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
}


@urlmatch(path=r'/catalog/v4/products/1,2$')
@urlmatch(path=r'/catalog/v10/products/1,2$')
def products_stub(url, request):
return {
'status_code': 200,
Expand Down