From b1f293749683817ae40d1c8d32a23bebf4bc0137 Mon Sep 17 00:00:00 2001 From: pragati-dreambits Date: Thu, 1 Aug 2024 19:43:01 +0530 Subject: [PATCH 1/4] [MIG]Migrate to v10 --- README.rst | 2 +- bol/__init__.py | 2 +- bol/openapi/api.py | 2 +- bol/retailer/api.py | 14 +++++++------- tests/test_openapi.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 052f4ef..b66e29e 100644 --- a/README.rst +++ b/README.rst @@ -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:: diff --git a/bol/__init__.py b/bol/__init__.py index cd5bbe9..1b33fb9 100644 --- a/bol/__init__.py +++ b/bol/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 3, 0, 'final', 0) +VERSION = (1, 4, 0, 'final', 0) __title__ = 'python-bol-api' __version_info__ = VERSION diff --git a/bol/openapi/api.py b/bol/openapi/api.py index bd41981..5055266 100644 --- a/bol/openapi/api.py +++ b/bol/openapi/api.py @@ -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() diff --git a/bol/retailer/api.py b/bol/retailer/api.py index 5315be1..ff1ef3e 100755 --- a/bol/retailer/api.py +++ b/bol/retailer/api.py @@ -230,7 +230,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 @@ -287,7 +287,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) @@ -352,7 +352,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 @@ -367,14 +367,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 @@ -494,7 +494,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", } ) @@ -514,7 +514,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 diff --git a/tests/test_openapi.py b/tests/test_openapi.py index 804f797..65a9717 100644 --- a/tests/test_openapi.py +++ b/tests/test_openapi.py @@ -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, From 1e343f4746578db73b6113b059bc6adde83c5ba7 Mon Sep 17 00:00:00 2001 From: pragati-dreambits Date: Mon, 5 Aug 2024 18:03:18 +0530 Subject: [PATCH 2/4] [ADD]Added new APIS for Insights --- bol/retailer/api.py | 74 +++++++++++++++++++++++++++++++++++++++++- bol/retailer/models.py | 5 +++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/bol/retailer/api.py b/bol/retailer/api.py index ff1ef3e..c13ed86 100755 --- a/bol/retailer/api.py +++ b/bol/retailer/api.py @@ -20,7 +20,8 @@ Replenishments, TimeSlots, Inventories, - ProductContents + ProductContents, + Insights ) __all__ = ["RetailerAPI"] @@ -298,6 +299,75 @@ 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=None, period=None, number_of_periods=None, name=None): + params = {} + if offer_id: + params["offer-id"] = offer_id + if period: + params["period"] = period + if number_of_periods: + params["number-of-periods"] = number_of_periods + if name: + params["name"] = ','.join(name) + + resp = self.request("GET", path="offer", params=params) + return Insights.parse(self.api, resp.text) + + def getPerformanceIndicators(self, name=None, year=None, week=None): + params = {} + if name: + params["name"] = ','.join(name) + if year: + params["year"] = year + if week: + params["week"] = week + + resp = self.request("GET", path="performance/indicator", params=params) + return Insights.parse(self.api, resp.text) + + def getProductRanks(self, ean=None, date=None, type=None, page=1): + params = {} + if ean: + params["ean"] = ean + if date: + params["date"] = date + if type: + params["type"] = ','.join(type) + if page != 1: + params["page"] = page + + resp = self.request("GET", path="product-ranks", params=params) + return Insights.parse(self.api, resp.text) + + def getSalesForecast(self, offer_id=None, weeks_ahead=None): + params = {} + if offer_id: + params["offer-id"] = offer_id + if weeks_ahead: + params["weeks-ahead"] = weeks_ahead + + resp = self.request("GET", path="sales-forecast", params=params) + return Insights.parse(self.api, resp.text) + + def getSearchTerms(self, search_term=None, period=None, number_of_periods=None, related_search_terms=None): + params = {} + if search_term: + params["search-term"] = search_term + if period: + params["period"] = period + if number_of_periods: + params["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 Insights.parse(self.api, resp.text) + class ReturnsMethods(MethodGroup): def __init__(self, api): super(ReturnsMethods, self).__init__(api, "returns") @@ -444,6 +514,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 = { diff --git a/bol/retailer/models.py b/bol/retailer/models.py index 0c9fb30..c0d5d34 100755 --- a/bol/retailer/models.py +++ b/bol/retailer/models.py @@ -133,6 +133,11 @@ class Product(Model): class Meta: pass +class Insights(Model): + + class Meta: + pass + class additionalService(Model): class Meta: From e72a72ffd4b56198a89bfa36a44508eb750b681f Mon Sep 17 00:00:00 2001 From: pragati-dreambits Date: Tue, 6 Aug 2024 11:51:20 +0530 Subject: [PATCH 3/4] [IMP]Improve the code --- bol/retailer/api.py | 114 ++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/bol/retailer/api.py b/bol/retailer/api.py index c13ed86..2809061 100755 --- a/bol/retailer/api.py +++ b/bol/retailer/api.py @@ -304,69 +304,59 @@ class InsightsMethods(MethodGroup): def __init__(self, api): super(InsightsMethods, self).__init__(api, 'insights') - def getOfferInsights(self, offer_id=None, period=None, number_of_periods=None, name=None): - params = {} - if offer_id: - params["offer-id"] = offer_id - if period: - params["period"] = period - if number_of_periods: - params["number-of-periods"] = number_of_periods - if name: - params["name"] = ','.join(name) - - resp = self.request("GET", path="offer", params=params) - return Insights.parse(self.api, resp.text) - - def getPerformanceIndicators(self, name=None, year=None, week=None): - params = {} - if name: - params["name"] = ','.join(name) - if year: - params["year"] = year - if week: - params["week"] = week - - resp = self.request("GET", path="performance/indicator", params=params) - return Insights.parse(self.api, resp.text) - - def getProductRanks(self, ean=None, date=None, type=None, page=1): - params = {} - if ean: - params["ean"] = ean - if date: - params["date"] = date - if type: - params["type"] = ','.join(type) - if page != 1: - params["page"] = page - - resp = self.request("GET", path="product-ranks", params=params) - return Insights.parse(self.api, resp.text) - - def getSalesForecast(self, offer_id=None, weeks_ahead=None): - params = {} - if offer_id: - params["offer-id"] = offer_id - if weeks_ahead: - params["weeks-ahead"] = weeks_ahead - - resp = self.request("GET", path="sales-forecast", params=params) - return Insights.parse(self.api, resp.text) + 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 Insights.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 Insights.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 Insights.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 - def getSearchTerms(self, search_term=None, period=None, number_of_periods=None, related_search_terms=None): - params = {} - if search_term: - params["search-term"] = search_term - if period: - params["period"] = period - if number_of_periods: - params["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 Insights.parse(self.api, resp.text) + resp = self.request("GET", path="search-terms", params=params) + return Insights.parse(self.api, resp.text) class ReturnsMethods(MethodGroup): def __init__(self, api): From a45613489339f96e2e4aeda7e2db370a2fe4848b Mon Sep 17 00:00:00 2001 From: pragati-dreambits Date: Wed, 7 Aug 2024 21:31:53 +0530 Subject: [PATCH 4/4] [IMP]Improve the code for field mapping --- bol/retailer/api.py | 14 ++++-- bol/retailer/models.py | 109 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/bol/retailer/api.py b/bol/retailer/api.py index 2809061..fa17900 100755 --- a/bol/retailer/api.py +++ b/bol/retailer/api.py @@ -21,7 +21,11 @@ TimeSlots, Inventories, ProductContents, - Insights + Insights, + PerformanceIndicators, + ProductRanks, + SalesForecast, + SearchTerms ) __all__ = ["RetailerAPI"] @@ -323,7 +327,7 @@ def getPerformanceIndicators(self, name, year, week): 'week': week } resp = self.request("GET", path="performance/indicator", params=params) - return Insights.parse(self.api, resp.text) + return PerformanceIndicators.parse(self.api, resp.text) def getProductRanks(self, ean, date, type=None, page=1): if ean and date: @@ -334,7 +338,7 @@ def getProductRanks(self, ean, date, type=None, page=1): params["page"] = page resp = self.request("GET", path="product-ranks", params=params) - return Insights.parse(self.api, resp.text) + return ProductRanks.parse(self.api, resp.text) def getSalesForecast(self, offer_id, weeks_ahead): if offer_id and weeks_ahead: @@ -343,7 +347,7 @@ def getSalesForecast(self, offer_id, weeks_ahead): "weeks-ahead": weeks_ahead } resp = self.request("GET", path="sales-forecast", params=params) - return Insights.parse(self.api, resp.text) + 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: @@ -356,7 +360,7 @@ def getSearchTerms(self, search_term, period, number_of_periods, related_search_ params["related-search-terms"] = related_search_terms resp = self.request("GET", path="search-terms", params=params) - return Insights.parse(self.api, resp.text) + return SearchTerms.parse(self.api, resp.text) class ReturnsMethods(MethodGroup): def __init__(self, api): diff --git a/bol/retailer/models.py b/bol/retailer/models.py index c0d5d34..6112dcd 100755 --- a/bol/retailer/models.py +++ b/bol/retailer/models.py @@ -123,22 +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 Insights(Model): +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