diff --git a/__init__.py b/__init__.py
index 8e247c7..ee340b0 100644
--- a/__init__.py
+++ b/__init__.py
@@ -10,6 +10,8 @@ from . import rappi
from . import api_log
from . import ir
from . import routes
+from . import shop
+from . import web
__all__ = ['register', 'routes']
@@ -17,26 +19,27 @@ __all__ = ['register', 'routes']
def register():
Pool.register(
+ web.Shop,
web_channel.SaleWebChannel,
- mercado_libre.MercadoLibre,
- shopify.Shopify,
- rappi.Rappi,
+ # mercado_libre.MercadoLibre,
+ # shopify.Shopify,
+ # rappi.Rappi,
sale.Sale,
- sale.SaleForChannelStart,
- web_channel.SynchronizeChannelOrdersStart,
- web_channel.SynchronizeChannelOrdersDone,
- web_channel.FinishInvoicesStart,
+ # sale.SaleForChannelStart,
+ # web_channel.SynchronizeChannelOrdersStart,
+ # web_channel.SynchronizeChannelOrdersDone,
+ # web_channel.FinishInvoicesStart,
party.Party,
api_log.ApiLog,
ir.Cron,
module='sale_web_channel', type_='model')
Pool.register(
sale.SaleUploadInvoice,
- sale.SaleForChannel,
- web_channel.SynchronizeChannelOrders,
- web_channel.FinishInvoices,
- web_channel.SynchronizeMenuWizard,
+ # sale.SaleForChannel,
+ # web_channel.SynchronizeChannelOrders,
+ # web_channel.FinishInvoices,
+ # web_channel.SynchronizeMenuWizard,
module='sale_web_channel', type_='wizard')
Pool.register(
- sale.SaleForChannelReport,
+ # sale.SaleForChannelReport,
module='sale_web_channel', type_='report')
diff --git a/api_log.py b/api_log.py
index b637f94..89fae30 100644
--- a/api_log.py
+++ b/api_log.py
@@ -10,7 +10,8 @@ STATES = {'readonly': True}
class ApiLog(metaclass=PoolMeta):
"API Log"
__name__ = "api.log"
- channel = fields.Many2One('sale.web_channel', 'channel', states=STATES)
+ web_shop = fields.Many2One('web.shop', 'Web Shop', states=STATES)
+ # channel = fields.Many2One('sale.web_channel', 'channel', states=STATES)
# number = fields.Char('Number Doc', states=STATES)
# order = fields.Char('Order', states=STATES)
# record_date = fields.Date('Record Date', states=STATES)
@@ -25,15 +26,15 @@ class ApiLog(metaclass=PoolMeta):
super(ApiLog, cls).__setup__()
cls._order.insert(0, ('record_date', 'DESC'))
- @classmethod
- def process_log_cron(cls):
- logs = cls.search([
- ('status', '=', 'pending')
- ], limit=10)
- for log in logs:
- data = log.file_json.decode("utf-8")
- res = {}
- if log.channel.channel_name == 'mercadolibre':
- MercadoLibre = Pool().get('sale.web_channel.mercado_libre')
- res = MercadoLibre.request_api(json.loads(data))
- cls.write([log], res)
+ # @classmethod
+ # def process_log_cron(cls):
+ # logs = cls.search([
+ # ('status', '=', 'pending')
+ # ], limit=10)
+ # for log in logs:
+ # data = log.file_json.decode("utf-8")
+ # res = {}
+ # if log.channel.channel_name == 'mercadolibre':
+ # MercadoLibre = Pool().get('sale.web_channel.mercado_libre')
+ # res = MercadoLibre.request_api(json.loads(data))
+ # cls.write([log], res)
diff --git a/endpoints_rappi.py b/endpoints_rappi.py
index 32d9e5a..c5d2d4d 100644
--- a/endpoints_rappi.py
+++ b/endpoints_rappi.py
@@ -2,10 +2,13 @@ import requests
import json
from datetime import datetime
from collections import namedtuple
+from rich import print
+from . import endpoints_rappi
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'
+AUDIENCE = 'https://int-public-api-v2/api'
HEADERS = {
'Accept': 'application/json',
@@ -29,11 +32,23 @@ channel = ChannelRappi(
class RappiAPI:
def __init__(self, channel):
- self.api_key = channel.api_key
+ # 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'})
+ # self.store_name = channel.shop.name
+ self.seller_id = channel.seller_id
+ self.app_id = channel.app_id
+ self.store_integration_id = channel.app_id
self.url_base = 'https://microservices.dev.rappi.com/api/v2/restaurants-integrations-public-api'
self.url_auth = URL_AUTH_DEV
+ self.token = channel.access_token if channel.access_token else ''
self.session = requests.Session()
- self.session.headers.update({'x-authorization': self.api_key})
+ self.session.headers.update({
+ 'x-authorization': 'bearer ' + self.token
+ })
self.session.headers.update({'Content-Type': 'application/json'})
def _send_request(self, endpoint=None, method='GET', data: dict = None, auth: bool = False):
@@ -45,6 +60,7 @@ class RappiAPI:
if method == 'GET':
response = self.session.get(url, timeout=10)
elif method == 'POST':
+ print(data)
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)
@@ -56,8 +72,10 @@ class RappiAPI:
content_type = response.headers.get('Content-Type', '')
# if response.status_code == 200:
if content_type.startswith('application/json'):
+ print(response.json())
return response.json()
else:
+ print(response.text)
return response.text
# else:
# if content_type.startswith('application/json'):
@@ -67,11 +85,11 @@ class RappiAPI:
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):
+ def get_token_access(self, client_id: str, client_secret: str):
data = {
"client_id": client_id,
"client_secret": client_secret,
- "audience": audience,
+ "audience": AUDIENCE,
"grant_type": "client_credentials"
}
return self._send_request(method='POST', data=data, auth=True)
@@ -137,13 +155,13 @@ class RappiAPI:
endpoint = f'/menu/approved/{store_id}'
return self._send_request(endpoint=endpoint)
- def create_menu_store(self, store_id, items):
+ def create_menu_store(self, items):
"""
NOTE: If menu don't created return response message dict {message: 'reason'}
"""
endpoint = '/menu'
data = {
- 'storeId': store_id,
+ 'storeId': self.store_integration_id,
'items': items,
}
return self._send_request(endpoint=endpoint, method='POST', data=data)
@@ -220,12 +238,12 @@ class RappiAPI:
# 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)
+# 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')
@@ -245,9 +263,9 @@ rappi = RappiAPI(f'Bearer {channel.api_key}', URL_ENV, URL_AUTH_DEV)
# 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')
+# 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
diff --git a/rappi.py b/rappi.py
index 98463cc..f84e0a0 100644
--- a/rappi.py
+++ b/rappi.py
@@ -9,14 +9,10 @@ from trytond.transaction import Transaction
from urllib.parse import urlencode
from datetime import datetime, date
from trytond.pyson import Eval
-from .web_channel import SaleWebChannel
-from urllib.parse import urlencode
+from .web import Shop
import json
import requests
-import base64
-import hmac
-import hashlib
-from pprint import pprint
+from . import endpoints_rappi
URL_DEV = 'https://rests-integrations-dev.auth0.com/oauth/token'
@@ -28,18 +24,18 @@ HEADERS = {
}
-class Rappi(SaleWebChannel):
+class Rappi(Shop):
'Rappi'
- __name__ = 'sale.web_channel.rappi'
+ __name__ = 'web.shop.rappi'
@classmethod
def __setup__(cls):
super(Rappi, cls).__setup__()
- cls._buttons.update({
- 'generate_token_access': {
- 'invisible': Eval('state') != 'active',
- },
- })
+ # cls._buttons.update({
+ # 'generate_token_access': {
+ # 'invisible': Eval('state') != 'active',
+ # },
+ # })
def _get_context(self):
print(self)
@@ -52,7 +48,6 @@ class Rappi(SaleWebChannel):
}
def generate_token_access(self):
- print('holis')
token_request = {
"client_id": self.app_id,
"client_secret": self.secret_key,
@@ -68,172 +63,53 @@ class Rappi(SaleWebChannel):
self.save()
def synchronize_menu_rappi(self):
- menu = {
- # 'storeId': self.store_id,
- 'storeId': '900152684',
- 'items': []
- }
- menu_append = menu['items'].append
- pool = Pool()
- Category = pool.get('product.template-product.category')
- # price_list = self.shop.price_list.lines
- # for index, line in enumerate(price_list):
- # if line.category and not line.product:
- # self.create_menu_by_global_category(line, Category)
- # elif not line.category and line.product:
- # # elif line.category and line.product:
- # # pass
- # # else:
- # # raise UserWarning('BAD CONFIGURATION IN LINE ID ', line.id)
+ items = []
+ for category in self.admin_category.childs:
+ items.extend(self.get_products(category))
+ print(items)
+ api_rappi = endpoints_rappi.RappiAPI(self)
+ api_rappi.create_menu_store(items)
- # # menu_append({
- # # 'category': {
- # # 'id': line.product.categories[0].id,
- # # 'maxQty': 0,
- # # 'minQty': 0,
- # # 'name': line.product.categories[0].name,
- # # },
- # # 'children': [],
- # # 'name': line.product.categories[0].name,
- # # 'description': line.product.description if line.product.description else 'no esta disponible',
- # # 'imageUrl': line.product.images[0].image_url if line.product.images else '',
- # # 'price': float(line.price_w_tax_computed),
- # # 'sku': line.product.code,
- # # 'sortingPosition': 0,
- # # "type": "PRODUCT",
- # # # 'maxLimit': '',
- # # })
- # # if hasattr(line.product, 'products_mix') and line.product.products_mix:
- # # for mix in line.product.products_mix:
- # # menu['items'][0]['children'].append({
- # # "category": {
- # # "id": mix.categories[0].id,
- # # "maxQty": 1,
- # # "minQty": 0,
- # # "name": mix.categories[0].name,
- # # "sortingPosition": 0
- # # },
- # # "name": mix.name,
- # # "description": mix.description,
- # # "price": float(mix.list_price),
- # # "sku": mix.id,
- # # "maxLimit": 1,
- # # "sortingPosition": 1,
- # # "type": "PRODUCT"
- # # })
-
- menu = {
- "storeId": "900152684",
- "items": [
- {
- "name": "Grilled Chicken Burger",
- "description": "Grilled chicken burger description",
- "price": 14000,
- "sku": "10",
- "sortingPosition": 0,
- "type": "PRODUCT",
+ def get_products(self, category):
+ children_list = []
+ for child in category.childs:
+ children_list.append({
"category": {
- "id": "2090019638",
- "maxQty": 0,
- "minQty": 0,
- "name": "Burgers",
- "sortingPosition": 0
+ "id": category.id,
+ "maxQty": 0,
+ "minQty": 0,
+ "name": category.name,
+ "sortingPosition": 0,
+ "children": []
},
- "children": [
- {
- "category": {
- "id": "211",
- "maxQty": 1,
- "minQty": 0,
- "name": "Do you want to add?",
- "sortingPosition": 0
- },
- "name": "French Fries",
- "description": "crunchy french fries",
- "price": 5000,
- "sku": "1",
- "maxLimit": 1,
- "sortingPosition": 1,
- "type": "TOPPING"
- },
- {
- "category": {
- "id": "211",
- "maxQty": 1,
- "minQty": 0,
- "name": "Do you want to add?",
- "sortingPosition": 0
- },
- "name": "Potato Wedges",
- "price": 7000,
- "sku": "2",
- "maxLimit": 1,
- "sortingPosition": 1,
- "type": "TOPPING"
- }
- ]
- },
- {
- "name": "Hawaiian Pizza",
- "description": "hawaiian pizza description",
- "price": 18000,
- "sku": "11",
- "sortingPosition": 1,
- "type": "PRODUCT",
- "category": {
- "id": "2090019639",
- "maxQty": 0,
- "minQty": 0,
- "name": "Pizzas",
- "sortingPosition": 1
- },
- "children": []
- }
- ]
- }
- menu_json = json.dumps(menu)
- URL = 'https://microservices.dev.rappi.com/api/v2/restaurants-integrations-public-api/menu'
- token = self.access_token
- headers = {
- 'Content-Type': 'application/json',
- 'x-authorization': 'bearer ' + token,
- }
- pprint(menu_json)
- response = requests.request("POST", URL, headers=headers, data=menu_json)
- pprint(response.text.encode('utf8'))
-
- def create_menu_by_global_category(self, line, Category):
- pass
- # category = Category.search_read([('categories', 'in', '')])
- # dict_menu = {
- # 'category': {
- # 'id': line.product.category.id,
- # 'maxQty': 0,
- # 'minQty': 0,
- # 'name': line.product.category.name,
- # },
-
- # dict_menu['children'].append(dict_child)
- # 'children': [],
- # 'name': line.product.categories[0].name,
- # 'description': line.product.description if line.product.description else 'no esta disponible',
- # 'imageUrl': line.product.images[0].image_url if line.product.images else '',
- # 'price': float(line.price_w_tax_computed),
- # 'sku': line.product.code,
- # 'sortingPosition': 0,
- # "type": "PRODUCT",
- # # 'maxLimit': '',
- # })
-
- def create_menu_by_local_category(self, line):
- if line.product.categories[0]:
- category = {
- 'id': line.product.categories[0].id,
- 'maxQty': 0,
- 'minQty': 0,
- 'name': line.product.categories[0].name,
- 'children': []
- }
- category['children'].append({
-
})
+ children_list[0]['children'] = self.get_products(child)
+ if not category.childs:
+ for product in category.products:
+ children_list.append({
+ "name": product.name,
+ "description": product.description if product.description else 'not available',
+ "price": float(product.list_price),
+ "sku": product.code,
+ "sortingPosition": 0,
+ "type": "PRODUCT",
+ "category": {
+ "id": category.id,
+ "maxQty": 0,
+ "minQty": 0,
+ "name": category.name,
+ "sortingPosition": 0
+ }
+ })
+ return children_list
+
+ # rappi_api = endpoints_rappi.RappiAPI(self)
+ # rappi_api.create_menu_store(self.shop.store_id, items)
+ # menu_json = json.dumps(menu)
+ # URL = 'https://microservices.dev.rappi.com/api/v2/restaurants-integrations-public-api/menu'
+ # token = self.access_token
+ # headers = {
+ # 'Content-Type': 'application/json',
+ # 'x-authorization': 'bearer ' + token,
+ # }
+ # response = requests.request("POST", URL, headers=headers, data=menu_json)
diff --git a/shop.py b/shop.py
new file mode 100644
index 0000000..5908913
--- /dev/null
+++ b/shop.py
@@ -0,0 +1,8 @@
+# This file is part of Tryton. The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from trytond.pool import Pool, PoolMeta
+from trytond.model import fields
+
+
+class SaleShop(metaclass=PoolMeta):
+ __name__ = 'sale.shop'
diff --git a/shop.xml b/shop.xml
new file mode 100644
index 0000000..c443cc7
--- /dev/null
+++ b/shop.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ sale.shop
+
+ shop_form
+
+
+
diff --git a/tryton.cfg b/tryton.cfg
index 87a37a5..f21f57a 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,12 +1,13 @@
[tryton]
version=6.0.3
depends:
+ ir
+ web_shop
sale_pos
product_reference
log
- ir
xml:
- web_channel.xml
+ web.xml
sale.xml
party.xml
api_log.xml
diff --git a/view/sale_web_channel_form.xml b/view/sale_web_channel_form.xml
index effa2d2..f1a0aa5 100644
--- a/view/sale_web_channel_form.xml
+++ b/view/sale_web_channel_form.xml
@@ -18,6 +18,10 @@ The COPYRIGHT file at the top level of this repository contains the full copyrig
+
+
+
+
@@ -55,20 +59,9 @@ The COPYRIGHT file at the top level of this repository contains the full copyrig
-
-
-
-
-
-
-
diff --git a/view/shop_form.xml b/view/shop_form.xml
new file mode 100644
index 0000000..40e6f6f
--- /dev/null
+++ b/view/shop_form.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
diff --git a/view/web_shop_form.xml b/view/web_shop_form.xml
new file mode 100644
index 0000000..75d54f3
--- /dev/null
+++ b/view/web_shop_form.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web.py b/web.py
new file mode 100644
index 0000000..541b849
--- /dev/null
+++ b/web.py
@@ -0,0 +1,131 @@
+from trytond.model import fields, ModelView
+from trytond.pool import PoolMeta, Pool
+from trytond.pyson import Eval, And, Or
+from datetime import datetime, timedelta
+from . import endpoints_rappi
+
+TYPES = [
+ ('', ''),
+ ('mercadolibre', 'Mercado Libre'),
+ ('melhous', 'Melhous'),
+ ('shopify', 'Shopify'),
+ ('rappi', 'Rappi'),
+]
+TYPE_INVOICE = [
+ ('', ''),
+ ('C', 'Computador'),
+ ('P', 'POS'),
+ ('M', 'Manual'),
+ ('1', 'Venta Electronica'),
+ ('2', 'Exportacion'),
+ ('3', 'Factura por Contingencia Facturador'),
+ ('4', 'Factura por Contingencia DIAN'),
+ ('91', 'Nota Crédito Eléctronica'),
+ ('92', 'Nota Débito Eléctronica'),
+]
+
+
+class Shop(metaclass=PoolMeta):
+ __name__ = 'web.shop'
+ secret_key = fields.Char('Secret Key')
+ app_id = fields.Char('Application ID')
+ redirect_uri = fields.Char('Redirect URI', states={
+ 'invisible': (Eval('type') != 'mercadolibre'),
+ })
+ authorization_code = fields.Char('Authorization Code', states={
+ 'invisible': (Eval('type') != 'mercadolibre'),
+ })
+ access_token = fields.Char('Access Token', states={
+ 'invisible': And(
+ Eval('type') != 'mercadolibre',
+ Eval('type') != 'rappi'),
+ })
+ token_create_date = fields.DateTime('Token Create Date', states={
+ 'invisible': (Eval('type') != 'mercadolibre'),
+ })
+ status_token = fields.Function(fields.Selection([
+ ('expired', 'Expired'),
+ ('active', 'Active'),
+ ], 'Status Token', readonly=True, states={
+ 'invisible': (Eval('type') != 'mercadolibre'),
+ }), 'get_status_token')
+ refresh_token = fields.Char('Refresh Token', states={
+ 'invisible': (Eval('type') != 'mercadolibre'),
+ })
+ # state = fields.Selection([
+ # ('draft', 'Draft'),
+ # ('active', 'Active'),
+ # ('finished', 'Finished'),
+ # ], 'State', select=True, readonly=True)
+ freight_product = fields.Many2One('product.product', 'Freight Product')
+ # states=STATES)
+ bonus_product = fields.Many2One('product.product', 'Bonus Product', states={
+ 'invisible': (Eval('type') != 'mercadolibre'),
+ })
+ tip_product = fields.Many2One('product.product', 'Tip Product', states={
+ 'invisible': (Eval('type') != 'shopify'),
+ })
+
+ generic_product = fields.Many2One('product.product', 'Generic Product')
+ # states={
+ # 'invisible': (Eval('type') != 'shopify'),
+ # })
+ report = fields.Many2One('ir.action.report', 'Report')
+ invoice_type = fields.Selection(TYPE_INVOICE, 'Type Invoice')
+ seller_id = fields.Char('Seller ID', states={
+ 'invisible': ~Eval('type').in_(['mercadolibre', 'rappi']),
+ })
+
+ @classmethod
+ def __setup__(cls):
+ super(Shop, cls).__setup__()
+ cls.type.selection = TYPES
+
+ cls._buttons.update({
+ 'generate_token_access': {
+ 'invisible': ~Eval('type').in_(['mercadolibre', 'rappi']),
+ },
+ 'synchronize_products': {
+ 'invisible': ~Eval('type').in_(['mercadolibre', 'rappi']),
+ },
+ })
+
+ def get_status_token(self, name):
+ if self.token_create_date:
+ now = datetime.now()
+ res = (now - self.token_create_date).total_seconds()
+ if res >= 21600:
+ return 'expired'
+ else:
+ return 'active'
+ else:
+ return 'expired'
+
+ @classmethod
+ @ModelView.button
+ def generate_token_access(cls, records):
+ if records:
+ for record in records:
+ if record.type == 'mercadolibre':
+ MercadoLibre = Pool().get('sale.web_channel.mercado_libre')
+ channels = MercadoLibre.search([
+ ('state', '=', 'active'),
+ ('type', '=', 'mercadolibre'),
+ ])
+ if record.type == 'rappi':
+ record.generate_token_access_rappi()
+
+ def generate_token_access_rappi(self):
+ api_rappi = endpoints_rappi.RappiAPI(self)
+ result = api_rappi.get_token_access(self.seller_id, self.secret_key)
+ self.access_token = result['access_token']
+ self.save()
+
+ def synchronize_products(self):
+ if self.type == 'rappi':
+ items = []
+ for category in self.admin_category.childs:
+ items.extend(self.get_products(category))
+ print(items)
+ api_rappi = endpoints_rappi.RappiAPI(self)
+ api_rappi.create_menu_store(items)
diff --git a/web.xml b/web.xml
new file mode 100644
index 0000000..cdce2cc
--- /dev/null
+++ b/web.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ web.shop
+
+ web_shop_form
+
+
+
diff --git a/web_channel.py b/web_channel.py
index 660bad8..1ff982e 100644
--- a/web_channel.py
+++ b/web_channel.py
@@ -110,9 +110,14 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView):
invoice_type = fields.Selection(TYPE_INVOICE, 'Type Invoice',
states=STATES)
seller_id = fields.Char('Seller ID', states={
- 'invisible': (Eval('channel_name') != 'mercadolibre'),
+ 'invisible': ~Eval('channel_name').in_(['mercadolibre', 'rappi']),
'readonly': (Eval('state') != 'draft')
})
+ admin_category = fields.Many2One('product.category', 'Admin Category',
+ domain=[
+ ('accounting', '=', False),
+ ])
+ price_list = fields.Many2One('product.price_list', 'Pricelist', ondelete="RESTRICT")
template_notification = fields.Many2One(
'email.template', 'Template Notification')
api_key = fields.Char('Api Key', states={
@@ -242,7 +247,7 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView):
report = Report.execute([record.id], {'id': record.id})
ext, data, filename, file_name = report
return data
-
+
class SynchronizeChannelOrdersStart(ModelView):
'Synchronize Channel orders Start'