diff --git a/endpoints_rappi.py b/endpoints_rappi.py new file mode 100644 index 0000000..32d9e5a --- /dev/null +++ b/endpoints_rappi.py @@ -0,0 +1,257 @@ +import requests +import json +from datetime import datetime +from collections import namedtuple + +URL_AUTH_DEV = 'https://rests-integrations-dev.auth0.com/oauth/token' +URL_AUTH_PRODUCTION = 'https://rests-integrations.auth0.com/oauth/token' +URL_ENV = 'https://microservices.dev.rappi.com/api/v2/restaurants-integrations-public-api' + +HEADERS = { + 'Accept': 'application/json', + 'Content-type': 'application/json' +} + +ChannelRappi = namedtuple('Channel', [ + 'seller_id', 'app_id', 'store_integration_id', + 'secret_key', 'host_name', 'api_key', 'creation_time']) + +channel = ChannelRappi( + seller_id='iJB9UvxChNgjmvXGgPCbIzUYaYzCf7PJ', + app_id='900152684', + store_integration_id='900152684', + secret_key='Qi-FvBNKoSkxRQn4R-Xf-TLNURZH08FXrPj2XSTvVKSccO2pyQBdn4x1XJhSgr5F', + host_name='', + api_key='', + creation_time='' +) + + +class RappiAPI: + def __init__(self, channel): + self.api_key = channel.api_key + self.url_base = 'https://microservices.dev.rappi.com/api/v2/restaurants-integrations-public-api' + self.url_auth = URL_AUTH_DEV + self.session = requests.Session() + self.session.headers.update({'x-authorization': self.api_key}) + self.session.headers.update({'Content-Type': 'application/json'}) + + def _send_request(self, endpoint=None, method='GET', data: dict = None, auth: bool = False): + if auth: + url = self.url_auth + else: + url = self.url_base + endpoint + try: + if method == 'GET': + response = self.session.get(url, timeout=10) + elif method == 'POST': + response = self.session.post(url, data=json.dumps(data), timeout=10) + elif method == 'PUT': + response = self.session.put(url, data=json.dumps(data), timeout=10) + elif method == 'DELETE': + response = self.session.delete(url, timeout=10) + else: + raise ValueError(f'Method {method} not supported') + + content_type = response.headers.get('Content-Type', '') + # if response.status_code == 200: + if content_type.startswith('application/json'): + return response.json() + else: + return response.text + # else: + # if content_type.startswith('application/json'): + # return response.json() + # else: + # raise RuntimeError(f'Error {response.status_code}: {response.text}') + except requests.exceptions.RequestException as e: + raise RuntimeError(f'Request error: {str(e)}') + + def get_token_access(self, client_id: str, client_secret: str, audience: str): + data = { + "client_id": client_id, + "client_secret": client_secret, + "audience": audience, + "grant_type": "client_credentials" + } + return self._send_request(method='POST', data=data, auth=True) + + def get_info_store(self): + """Get information store + integrationId: It is the id of the store that you assign in the integration. + rappiId: It is the id of the store assigned by Rappi. + name: It is the name of the store. + """ + endpoint = 'stores-pa' + return self._send_request(endpoint=endpoint) + + def get_check_in_code(self, store_id): + """ + Use the endpoint to obtain the following information from the check-in code assigned to your store. + + store_id It is the id of the consulted store. + code It is the store check-in code assigned by Rappi. + created_at It is the creation date of the check-in code assigned for the store. + updated_at It is the update date of the check-in code assigned to the store. + expired_at It is the expiration date of the check-in code assigned to the store + """ + endpoint = f'/stores-pa/{store_id}/check-in-code' + return self._send_request(endpoint=endpoint) + + def get_info_menu_current(self, rappiId): + """ + Products + + id This is Rappi id from the product. + name Product name. + price Product price. + toppings Toppings from the product. + + Toppings + + id This is Rappi id from the topping. + name This is name from the Topping. + price This is price from the Topping. + category This is category information from the Topping. + + Topping Category + + id This is Rappi id from the topping category. + name Topping category name. + """ + endpoint = f'/store/{rappiId}/menu/current' + return self._send_request(endpoint=endpoint) + + def get_menu(self): + """ + + """ + endpoint = '/menu' + return self._send_request(endpoint=endpoint) + + def get_last_menu_store(self, store_id): + endpoint = f'/menu/rappi/{store_id}' + return self._send_request(endpoint=endpoint) + + def get_menu_approved(self, store_id): + endpoint = f'/menu/approved/{store_id}' + return self._send_request(endpoint=endpoint) + + def create_menu_store(self, store_id, items): + """ + NOTE: If menu don't created return response message dict {message: 'reason'} + """ + endpoint = '/menu' + data = { + 'storeId': store_id, + 'items': items, + } + return self._send_request(endpoint=endpoint, method='POST', data=data) + + def get_items_status(self, item_ids: list): + """ + Get item status avalability + Item SKU: This is the SKU you provided for the item to the Rappi + when uploading to the menu. + Item ID: This is the identifier that Rappi provided you when + uploading to the menu. + """ + endpoint = '/availability/items/status' + data = { + 'storeId': self.storeId, + 'item_ids': item_ids, + } + return self._send_request(endpoint=endpoint, method='POST', data=data) + + def set_items_status(self, items_on: list, items_off: list): + """ + Set item status avalability + Item SKU: This is the SKU you provided for the item to the Rappi + when uploading to the menu. + Item ID: This is the identifier that Rappi provided you when + uploading to the menu. + """ + endpoint = '/availability/items/status' + data = { + 'store_integration_id': self.store_integration_id, + 'items': { + 'turn_on': items_on, + 'turn_off': items_off + }, + } + return self._send_request(endpoint=endpoint, method='PUT', data=data) + + # def cancel_order(self, order_id, cancel_reason): + # endpoint = f'/orders/{order_id}/cancel' + # data = {'reason': cancel_reason} + # return self._send_request(endpoint, method='PUT', data=data) + + def get_orders(self): + endpoint = '/orders' + # params = {} + params = {'storeId': channel.app_id} + return self._send_request(endpoint=endpoint, method='GET', data=params) + + def take_order(self, order_id, cookingTime=None): + endpoint = f'/orders/{order_id}/take/{cookingTime}' + return self._send_request(endpoint, method='PUT') + + def reject_order(self, order_id, reason): + # reason optional + # cancel_type + #["ITEM_WRONG_PRICE", "ITEM_NOT_FOUND", "ITEM_OUT_OF_STOCK", "ORDER_MISSING_INFORMATION", "ORDER_MISSING_ADDRESS_INFORMATION", "ORDER_TOTAL_INCORRECT"] + endpoint = f'/orders/{order_id}/reject' + data = {'reason': reason} + return self._send_request(endpoint, method='PUT', data=data) + + def ready_order(self, order_id): + endpoint = f'/orders/{order_id}/ready-for-pickup' + return self._send_request(endpoint, method='POST') + + def get_order_events(self, order_id): + endpoint = f'/orders/{order_id}/events' + return self._send_request(endpoint) + + def get_orders_status_sent(self): + endpoint = '/orders/status/sent' + return self._send_request(endpoint) + + +# Ejemplo de uso + + +print(channel.seller_id, 'this is objetc') +token = { + 'access_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3Jlc3RzLWludGVncmF0aW9ucy1kZXYuYXV0aDAuY29tLyIsInN1YiI6ImlKQjlVdnhDaE5nam12WEdnUENiSXpVWWFZekNmN1BKQGNsaWVudHMiLCJhdWQiOiJodHRwczovL2ludC1wdWJsaWMtYXBpLXYyL2FwaSIsImlhdCI6MTY5MzAxNzExNCwiZXhwIjoxNjkzNjIxOTEyLCJhenAiOiJpSkI5VXZ4Q2hOZ2ptdlhHZ1BDYkl6VVlhWXpDZjdQSiIsInNjb3BlIjoidXBkYXRlOmF2YWlsYWJpbGl0eV9zdG9yZXMgdXBkYXRlOmF2YWlsYWJpbGl0eV9zdG9yZXNfaXRlbXMgdXBkYXRlOmF2YWlsYWJpbGl0eV9zdG9yZXNfaXRlbXNfcmFwcGkgcmVhZDptZW51X3RoaXJkcGFydHkgdXBkYXRlOm1lbnUgcmVhZDptZW51X3JhcHBpIHVwZGF0ZTpvcmRlcnNfcmVhZHlfZm9yX3BpY2t1cCByZWFkOm1lbnVzX3JhcHBpIHJlYWQ6Y29uZmlnIGNyZWF0ZTpjb25maWcgdXBkYXRlOmNvbmZpZyBkZWxldGU6Y29uZmlnIHJlYWQ6b3JkZXJzIHBpY2t1cDpvcmRlciByZWplY3Q6b3JkZXIgdGFrZTpvcmRlciByZWFkOnN0b3JlcyByZWFkOmFwcF9jbGllbnRzIGNyZWF0ZTphcHBfY2xpZW50cyBkZWxldGU6YXBwX2NsaWVudHMgY3JlYXRlOmFwcF9jbGllbnRzX3N0b3JlcyByZWFkOm9yZGVyX2V2ZW50cyBkZWxldGU6YXBwX2NsaWVudHNfc3RvcmVzIGNyZWF0ZTpjbGllbnRzIHJlYWQ6bWVudV9zdGF0dXNfcmFwcGkgcmVhZDphdmFpbGFiaWxpdHlfc3RvcmVzX2l0ZW1zIHJlYWQ6d2ViaG9vayBjcmVhdGU6d2ViaG9vayB1cGRhdGU6d2ViaG9vayBkZWxldGU6d2ViaG9vayB1cGRhdGU6d2ViaG9va19zZWNyZXQiLCJndHkiOiJjbGllbnQtY3JlZGVudGlhbHMifQ.Loh_g9qB3jNhOHxXPVrWgDJQAr7n9DzB6jWbPD_vUDQ', + 'scope': 'update:availability_stores update:availability_stores_items update:availability_stores_items_rappi read:menu_thirdparty update:menu read:menu_rappi update:orders_ready_for_pickup read:menus_rappi read:config create:config update:config delete:config read:orders pickup:order reject:order take:order read:stores read:app_clients create:app_clients delete:app_clients create:app_clients_stores read:order_events delete:app_clients_stores create:clients read:menu_status_rappi read:availability_stores_items read:webhook create:webhook update:webhook delete:webhook update:webhook_secret', 'expires_in': 604798, 'token_type': 'Bearer'} +channel = channel._replace(api_key=token['access_token'], creation_time=datetime.now()) +rappi = RappiAPI(f'Bearer {channel.api_key}', URL_ENV, URL_AUTH_DEV) + +# get token +# token = rappi.get_token_access(channel.seller_id, channel.secret_key, 'https://int-public-api-v2/api') +# print(token, 'validate token') + +# # get menu +# menu = rappi.get_menu() +# print(menu, 'menu in rappi') + +# # get menu approved +# menu_approved = rappi.get_menu_approved(store_id=channel.app_id) +# print(menu_approved, 'menu approved') + +# # get last menu store +# last_menu = rappi.get_last_menu_store(store_id=channel.app_id) +# print(last_menu, 'last menu') + +# create menu +# NOTE: If menu don't created return response message json {message: 'reason'} +items = [] +menu_created = rappi.create_menu_store(store_id=channel.app_id, items=items) +print(menu_created, 'menu created') + +# Order options to call enpoints to manage order client +# get_orders, take_order or reject_order, ready_order + +# # Get orders +# orders = rappi.get_orders() +# print(orders, 'list_orders') diff --git a/routes.py b/routes.py index 6ecab3c..3168a7c 100644 --- a/routes.py +++ b/routes.py @@ -34,7 +34,7 @@ def login_app(request, pool): 'accept': 'application/json', 'content-type': 'application/x-www-form-urlencoded', } - + data = { 'grant_type': 'authorization_code', 'client_id': channel.app_id, @@ -94,6 +94,7 @@ def webhooks_endpoint_mercadolibre(request, pool): def webhooks_endpoint_shopify(request, pool): request_body = request.get_data(as_text=True) payload = json.loads(request_body) - Channel = _pool.get('sale.web_channel.shopify') - res = Channel.request_api(request) - return True \ No newline at end of file + Channel = pool.get('sale.web_channel.shopify') + res = Channel.request_api(payload) + print(res, 'validate') + return True