fix in mercado_libre
This commit is contained in:
parent
834530c797
commit
b59092a369
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE sale_web_channel RENAME TO web_shop;
|
||||||
|
ALTER TABLE web_shop RENAME COLUMN creation_time TO token_create_date;
|
||||||
|
ALTER TABLE web_shop RENAME COLUMN channel_name TO type;
|
||||||
|
|
20
__init__.py
20
__init__.py
|
@ -9,24 +9,24 @@ from . import shopify
|
||||||
from . import rappi
|
from . import rappi
|
||||||
from . import api_log
|
from . import api_log
|
||||||
from . import ir
|
from . import ir
|
||||||
from . import routes
|
# from . import routes
|
||||||
from . import shop
|
from . import shop
|
||||||
from . import web
|
from . import web
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['register', 'routes']
|
# __all__ = ['register', 'routes']
|
||||||
|
__all__ = ['register']
|
||||||
|
|
||||||
|
|
||||||
def register():
|
def register():
|
||||||
Pool.register(
|
Pool.register(
|
||||||
web_channel.SaleWebChannel,
|
# web_channel.SaleWebChannel,
|
||||||
mercado_libre.MercadoLibre,
|
|
||||||
web.Shop,
|
web.Shop,
|
||||||
# shopify.Shopify,
|
# shopify.Shopify,
|
||||||
sale.Sale,
|
sale.Sale,
|
||||||
# sale.SaleForChannelStart,
|
sale.SaleForChannelStart,
|
||||||
# web_channel.SynchronizeChannelOrdersStart,
|
web.SynchronizeChannelOrdersStart,
|
||||||
# web_channel.SynchronizeChannelOrdersDone,
|
web.SynchronizeChannelOrdersDone,
|
||||||
# web_channel.FinishInvoicesStart,
|
# web_channel.FinishInvoicesStart,
|
||||||
party.Party,
|
party.Party,
|
||||||
api_log.ApiLog,
|
api_log.ApiLog,
|
||||||
|
@ -34,11 +34,11 @@ def register():
|
||||||
module='sale_web_channel', type_='model')
|
module='sale_web_channel', type_='model')
|
||||||
Pool.register(
|
Pool.register(
|
||||||
sale.SaleUploadInvoice,
|
sale.SaleUploadInvoice,
|
||||||
# sale.SaleForChannel,
|
sale.SaleForChannel,
|
||||||
# web_channel.SynchronizeChannelOrders,
|
web.SynchronizeChannelOrders,
|
||||||
# web_channel.FinishInvoices,
|
# web_channel.FinishInvoices,
|
||||||
# web_channel.SynchronizeMenuWizard,
|
# web_channel.SynchronizeMenuWizard,
|
||||||
module='sale_web_channel', type_='wizard')
|
module='sale_web_channel', type_='wizard')
|
||||||
Pool.register(
|
Pool.register(
|
||||||
# sale.SaleForChannelReport,
|
sale.SaleForChannelReport,
|
||||||
module='sale_web_channel', type_='report')
|
module='sale_web_channel', type_='report')
|
||||||
|
|
792
mercado_libre.py
792
mercado_libre.py
|
@ -8,11 +8,13 @@ from trytond.transaction import Transaction
|
||||||
import requests
|
import requests
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from .web_channel import SaleWebChannel
|
# from .web_channel import SaleWebChannel
|
||||||
|
# from .web import Shop
|
||||||
import json
|
import json
|
||||||
from .exceptions import NotProductFoundError, NotProductFound
|
from .exceptions import NotProductFoundError, NotProductFound
|
||||||
from trytond.i18n import gettext
|
from trytond.i18n import gettext
|
||||||
from trytond.exceptions import UserError
|
from trytond.exceptions import UserError
|
||||||
|
from rich import print
|
||||||
|
|
||||||
HEADERS = {
|
HEADERS = {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
@ -20,13 +22,575 @@ HEADERS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MercadoLibre(SaleWebChannel):
|
# class MercadoLibreTwo(Shop):
|
||||||
'MercadoLibre'
|
# 'MercadoLibre'
|
||||||
__name__ = 'sale.web_channel.mercado_libre'
|
# __name__ = 'sale.web_channel.mercado_libre'
|
||||||
|
|
||||||
@classmethod
|
# @classmethod
|
||||||
def __setup__(cls):
|
# def __setup__(cls):
|
||||||
super(MercadoLibre, cls).__setup__()
|
# super(MercadoLibre, cls).__setup__()
|
||||||
|
|
||||||
|
# def _get_context(self):
|
||||||
|
# user_ = self._get_user()
|
||||||
|
# return {
|
||||||
|
# 'company': user_.company.id,
|
||||||
|
# 'user': user_.id,
|
||||||
|
# 'shops': [user_.shop.id],
|
||||||
|
# 'shop': user_.shop.id,
|
||||||
|
# 'language': 'es'
|
||||||
|
# }
|
||||||
|
|
||||||
|
# def _get_user(self):
|
||||||
|
# User = Pool().get('res.user')
|
||||||
|
# user, = User.search([
|
||||||
|
# ('login', '=', 'mercado.libre')
|
||||||
|
# ])
|
||||||
|
# return user
|
||||||
|
|
||||||
|
# def _create_product(self, codes, line={}):
|
||||||
|
# item = line['item']
|
||||||
|
# pool = Pool()
|
||||||
|
# Product = pool.get('product.product')
|
||||||
|
# Template = pool.get('product.template')
|
||||||
|
# description = ''
|
||||||
|
# if item.get('variation_attributes'):
|
||||||
|
# var = item['variation_attributes'][0]
|
||||||
|
# if var['id'] and var['name']:
|
||||||
|
# description = var['id'] + ' ' + var['name']
|
||||||
|
# create_template = {
|
||||||
|
# 'name': item['title'],
|
||||||
|
# 'list_price': line['unit_price'],
|
||||||
|
# 'sale_price_w_tax': line['full_unit_price'],
|
||||||
|
# 'type': 'goods',
|
||||||
|
# 'salable': True,
|
||||||
|
# 'purchasable': True,
|
||||||
|
# 'purchase_uom': 1,
|
||||||
|
# 'sale_uom': 1,
|
||||||
|
# 'default_uom': 1,
|
||||||
|
# 'account_category': 7,
|
||||||
|
# }
|
||||||
|
# template, = Template.create([create_template])
|
||||||
|
# create_product = []
|
||||||
|
# for code in codes:
|
||||||
|
# create_product.append({
|
||||||
|
# 'code': code,
|
||||||
|
# 'description': description,
|
||||||
|
# 'template': template.id
|
||||||
|
# })
|
||||||
|
# return Product.create(create_product)
|
||||||
|
|
||||||
|
# def _create_party(self, customer):
|
||||||
|
# _pool = Pool()
|
||||||
|
# City = _pool.get('party.city_code')
|
||||||
|
# Party = _pool.get('party.party')
|
||||||
|
# PartyObligationTax = _pool.get('party.obligation_tax')
|
||||||
|
# email = customer.get('email', '@')
|
||||||
|
# shipment_address, phone, city = '', '', None
|
||||||
|
# if customer.get('receiver_address'):
|
||||||
|
# receiver_address = customer['receiver_address']
|
||||||
|
# shipment_address = receiver_address['address_line']
|
||||||
|
# phone = receiver_address['receiver_phone'] or '000'
|
||||||
|
# city_name = receiver_address['city']['name']
|
||||||
|
# if city_name:
|
||||||
|
# cities = City.search([
|
||||||
|
# ('name', '=', city_name)
|
||||||
|
# ])
|
||||||
|
# if cities:
|
||||||
|
# city = cities[0]
|
||||||
|
# if customer['billing_info']['doc_type'] == 'NIT':
|
||||||
|
# type_document = '31'
|
||||||
|
# customer_name = customer['billing_info']['business_name']
|
||||||
|
# type_person = 'persona_juridica'
|
||||||
|
# else:
|
||||||
|
# customer_name = customer['billing_info']['first_name'] + ' ' + customer['billing_info']['last_name']
|
||||||
|
# type_document = '13'
|
||||||
|
# type_person = 'persona_natural'
|
||||||
|
|
||||||
|
# create_customer = {
|
||||||
|
# 'id_reference': str(customer['id']),
|
||||||
|
# 'name': customer_name.upper(),
|
||||||
|
# 'type_document': type_document,
|
||||||
|
# 'type_person': type_person,
|
||||||
|
# 'id_number': customer['billing_info']['doc_number'],
|
||||||
|
# 'addresses': [('create', [{
|
||||||
|
# 'street': shipment_address,
|
||||||
|
# }])],
|
||||||
|
# 'contact_mechanisms': [
|
||||||
|
# ('create', [
|
||||||
|
# {'type': 'phone', 'value': phone},
|
||||||
|
# {'type': 'email', 'value': email},
|
||||||
|
# ])
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# if not city:
|
||||||
|
# city = City(149)
|
||||||
|
# create_customer['addresses'][0][1][0]['department_code'] = city.department.id
|
||||||
|
# create_customer['addresses'][0][1][0]['city_code'] = city.id
|
||||||
|
# party, = Party.create([create_customer])
|
||||||
|
# PartyObligationTax.create([{
|
||||||
|
# 'party': party.id,
|
||||||
|
# 'obligation_fiscal': 6,
|
||||||
|
# }])
|
||||||
|
# return party
|
||||||
|
|
||||||
|
# def get_shipment_api(self, shipment_id):
|
||||||
|
# if not shipment_id:
|
||||||
|
# return None
|
||||||
|
# URI = 'https://api.mercadolibre.com/shipments/%s?access_token=%s' % (
|
||||||
|
# shipment_id, self.access_token)
|
||||||
|
# res = self.get_response(URI)
|
||||||
|
# return res.json()
|
||||||
|
|
||||||
|
# def get_billing_info_api(self, order_id):
|
||||||
|
# if not order_id:
|
||||||
|
# return None
|
||||||
|
# URI = 'https://api.mercadolibre.com/orders/%s/billing_info?access_token=%s' % (
|
||||||
|
# order_id, self.access_token)
|
||||||
|
# res = self.get_response(URI)
|
||||||
|
# return res.json()
|
||||||
|
|
||||||
|
# def _return_sale(self, sale):
|
||||||
|
# pool = Pool()
|
||||||
|
# Sale = pool.get('sale.sale')
|
||||||
|
# Date = pool.get('ir.date')
|
||||||
|
# ctx = self._get_context()
|
||||||
|
# dev_sales = []
|
||||||
|
# sales = [sale]
|
||||||
|
# if sale.pack_id:
|
||||||
|
# sales = Sale.search([
|
||||||
|
# ('pack_id', '=', sale.pack_id)
|
||||||
|
# ])
|
||||||
|
# with Transaction().set_context(ctx):
|
||||||
|
# return_sales = Sale.copy(sales)
|
||||||
|
# for return_sale, sale in zip(return_sales, sales):
|
||||||
|
# return_sale.origin = sale
|
||||||
|
# return_sale.reference = sale.reference
|
||||||
|
# return_sale.state = 'draft'
|
||||||
|
# return_sale.sale_date = Date.today()
|
||||||
|
# if sale.invoice_type == '1':
|
||||||
|
# return_sale.invoice_type = '91'
|
||||||
|
# for line in return_sale.lines:
|
||||||
|
# if line.type == 'line':
|
||||||
|
# line.quantity *= -1
|
||||||
|
# line.save()
|
||||||
|
# if return_sale.untaxed_amount_cache:
|
||||||
|
# return_sale.untaxed_amount_cache *= -1
|
||||||
|
# if return_sale.tax_amount_cache:
|
||||||
|
# return_sale.tax_amount_cache *= -1
|
||||||
|
# if return_sale.total_amount_cache:
|
||||||
|
# return_sale.total_amount_cache *= -1
|
||||||
|
# return_sale.save()
|
||||||
|
# Sale.quote([return_sale])
|
||||||
|
# Sale.write([return_sale], {'state': 'confirmed'})
|
||||||
|
# dev_sales.append(return_sale)
|
||||||
|
# return dev_sales
|
||||||
|
|
||||||
|
# def create_lines_sale(self, sale, sale_, freight=False):
|
||||||
|
# _pool = Pool()
|
||||||
|
# SaleLine = _pool.get('sale.line')
|
||||||
|
# Product = _pool.get('product.product')
|
||||||
|
# create_lines = []
|
||||||
|
# sale_items = sale_['order_items']
|
||||||
|
# ctx = self._get_context()
|
||||||
|
# sfm_id = sale_['shipping']['id']
|
||||||
|
# # reference = sale.reference.split(',')
|
||||||
|
# # reference_order = str(sale_['id'])
|
||||||
|
# # if reference_order not in reference:
|
||||||
|
# # sale.referece = sale.reference + ',' + reference_order
|
||||||
|
# # sale.save()
|
||||||
|
# with Transaction().set_context(ctx):
|
||||||
|
# for line in sale_items:
|
||||||
|
# item = line['item']
|
||||||
|
# sku_code = item['seller_sku']
|
||||||
|
|
||||||
|
# if sku_code:
|
||||||
|
# generic = False
|
||||||
|
# if sku_code.count('+') > 0:
|
||||||
|
# codes = sku_code.split('+')
|
||||||
|
# line['unit_price'] = Decimal(
|
||||||
|
# round((line['unit_price'] / 2), 2))
|
||||||
|
# else:
|
||||||
|
# codes = [sku_code]
|
||||||
|
|
||||||
|
# products = Product.search([
|
||||||
|
# ('code', 'in', codes),
|
||||||
|
# ('active', '=', True)
|
||||||
|
# ])
|
||||||
|
# description = ''
|
||||||
|
# if not products:
|
||||||
|
# products = self._create_product(codes, line)
|
||||||
|
# else:
|
||||||
|
# if not self.generic_product:
|
||||||
|
# raise NotProductFoundError(
|
||||||
|
# gettext('sale_web_channel.msg_product_generic_not_found'))
|
||||||
|
# products = [self.generic_product]
|
||||||
|
# generic = True
|
||||||
|
# description = ''
|
||||||
|
# raise NotProductFound(
|
||||||
|
# gettext('sale_web_channel.msg_product_not_found', s=self.generic_product.rec_name))
|
||||||
|
# for product in products:
|
||||||
|
# Tax = _pool.get('account.tax')
|
||||||
|
# un_price = Tax.reverse_compute(Decimal(line['unit_price']),
|
||||||
|
# product.customer_taxes_used)
|
||||||
|
# create_lines.append({
|
||||||
|
# 'sale': sale.id,
|
||||||
|
# 'type': 'line',
|
||||||
|
# 'unit': product.default_uom.id,
|
||||||
|
# 'quantity': line['quantity'],
|
||||||
|
# 'unit_price': round(Decimal(un_price), 3),
|
||||||
|
# 'unit_price_full': Decimal(line['unit_price']),
|
||||||
|
# 'product': product.id,
|
||||||
|
# 'taxes': [('add', product.customer_taxes_used)],
|
||||||
|
# 'description': description,
|
||||||
|
# })
|
||||||
|
# if freight and self.freight_product:
|
||||||
|
# product = self.freight_product
|
||||||
|
# URI = 'https://api.mercadolibre.com/shipments/%s/costs?access_token=%s' % (
|
||||||
|
# sfm_id, self.access_token)
|
||||||
|
# result = self.get_response(URI).json()
|
||||||
|
# shipping_amount = result['receiver']['cost']
|
||||||
|
# create_lines.append({
|
||||||
|
# 'sale': sale.id,
|
||||||
|
# 'type': 'line',
|
||||||
|
# 'unit': product.default_uom.id,
|
||||||
|
# 'quantity': 1,
|
||||||
|
# 'unit_price': Decimal(shipping_amount),
|
||||||
|
# 'unit_price_full': Decimal(shipping_amount),
|
||||||
|
# 'product': product.id,
|
||||||
|
# 'description': 'FLETE',
|
||||||
|
# })
|
||||||
|
# SaleLine.create(create_lines)
|
||||||
|
# return generic
|
||||||
|
|
||||||
|
# def validate_sale(self, sale_):
|
||||||
|
# if sale_.get('pack_id'):
|
||||||
|
# # if not sale_.get('shipping'):
|
||||||
|
# # return
|
||||||
|
# # shipment_id = sale_['shipping']['id']
|
||||||
|
# # URI = 'https://api.mercadolibre.com/shipments/%s/items?access_token=%s' % (
|
||||||
|
# # shipment_id, self.access_token)
|
||||||
|
# # res = self.get_response(URI)
|
||||||
|
# # shipment_items = res.json()
|
||||||
|
# # if len(shipment_items) > 1:
|
||||||
|
# URI = 'https://api.mercadolibre.com/packs/%s?access_token=%s' % (
|
||||||
|
# sale_.get('pack_id'), self.access_token)
|
||||||
|
# response = self.get_response(URI)
|
||||||
|
# response = response.json()
|
||||||
|
# if response.get('orders'):
|
||||||
|
# ids = ''
|
||||||
|
# for item in response['orders']:
|
||||||
|
# order_id = str(item['id'])
|
||||||
|
# if order_id != str(sale_['id']):
|
||||||
|
# URI2 = 'https://api.mercadolibre.com/orders/%s?access_token=%s' % (
|
||||||
|
# order_id, self.access_token)
|
||||||
|
# order = self.get_response(URI2)
|
||||||
|
# sale_order = order.json()
|
||||||
|
# ids += ',' + order_id
|
||||||
|
# sale_['order_items'].extend(sale_order['order_items'])
|
||||||
|
# sale_['id'] = str(sale_['id']) + ids
|
||||||
|
# return self._create_sale(sale_)
|
||||||
|
# else:
|
||||||
|
# return self._create_sale(sale_)
|
||||||
|
# else:
|
||||||
|
# return self._create_sale(sale_)
|
||||||
|
|
||||||
|
# def _create_sale(self, sale_):
|
||||||
|
# _pool = Pool()
|
||||||
|
# Sale = _pool.get('sale.sale')
|
||||||
|
# print(sale_, 'que eres amigo')
|
||||||
|
# reference = '%' + str(sale_['id']).split(',')[0] + '%'
|
||||||
|
# dom = [
|
||||||
|
# ('reference', 'like', reference)
|
||||||
|
# ]
|
||||||
|
# sales = Sale.search(dom)
|
||||||
|
# if sales:
|
||||||
|
# if len(sales) == 1 and sale_['status'] == 'cancelled':
|
||||||
|
# sale = sales[0]
|
||||||
|
# if not sale.invoices:
|
||||||
|
# self.cancel_sales([sale], sale.pack_id)
|
||||||
|
# else:
|
||||||
|
# dev_sales = self._return_sale(sale)
|
||||||
|
# self._finish_sale(dev_sales[0], type='return')
|
||||||
|
# return True
|
||||||
|
# return False
|
||||||
|
# Party = _pool.get('party.party')
|
||||||
|
# User = _pool.get('res.user')
|
||||||
|
# sfm_id = sale_['shipping']['id']
|
||||||
|
# shipment_ = self.get_shipment_api(sfm_id)
|
||||||
|
# if sale_.get('buyer'):
|
||||||
|
# sale_id = str(sale_['id']).split(',')[0]
|
||||||
|
# billing_info = self.get_billing_info_api(sale_id)
|
||||||
|
# customer = sale_['buyer']
|
||||||
|
# dom_party = [('id_reference', '=', str(customer['id']))]
|
||||||
|
# if billing_info and billing_info['billing_info'].get('doc_number'):
|
||||||
|
# dom_party = [('id_number', '=', str(
|
||||||
|
# billing_info['billing_info']['doc_number']))]
|
||||||
|
# parties = Party.search(dom_party)
|
||||||
|
# if parties:
|
||||||
|
# party = parties[0]
|
||||||
|
# else:
|
||||||
|
# customer['receiver_address'] = shipment_['receiver_address']
|
||||||
|
# customer['billing_info'] = billing_info['billing_info']
|
||||||
|
# for dic in customer['billing_info']['additional_info']:
|
||||||
|
# customer['billing_info'][list(dic.values())[0].lower()
|
||||||
|
# ] = list(dic.values())[1]
|
||||||
|
# try:
|
||||||
|
# customer['billing_info']['additional_info'].pop()
|
||||||
|
# except Exception as e:
|
||||||
|
# msg = 'sin informacion de tercero' + e
|
||||||
|
# raise UserError(
|
||||||
|
# gettext('sale_web_channel.msg_billing_info', msg=msg))
|
||||||
|
# party = self._create_party(customer)
|
||||||
|
# ctx = self._get_context()
|
||||||
|
# user_ = User(ctx['user'])
|
||||||
|
# date_created = sale_['date_created'].split('T')
|
||||||
|
# year, month, day = date_created[0].split('-')
|
||||||
|
# sale_date = date(int(year), int(month), int(day))
|
||||||
|
# with Transaction().set_user(ctx['user']):
|
||||||
|
# sale, = Sale.create([{
|
||||||
|
# 'payment_term': 1,
|
||||||
|
# 'party': party.id,
|
||||||
|
# 'sale_date': sale_date,
|
||||||
|
# 'comment': shipment_['status'],
|
||||||
|
# 'state': 'draft',
|
||||||
|
# 'company': ctx['company'],
|
||||||
|
# 'currency': user_.company.currency.id,
|
||||||
|
# 'shop': user_.shop.id,
|
||||||
|
# 'reference': str(sale_['id']),
|
||||||
|
# 'invoice_address': Party.address_get(party, type='invoice'),
|
||||||
|
# 'shipment_address': Party.address_get(party, type='delivery'),
|
||||||
|
# 'description': 'VENTA WEB ',
|
||||||
|
# 'channel': self.id,
|
||||||
|
# 'invoice_type': self.invoice_type,
|
||||||
|
# 'pack_id': str(sale_['pack_id']) if sale_['pack_id'] else '',
|
||||||
|
# }])
|
||||||
|
# generic = self.create_lines_sale(
|
||||||
|
# sale, sale_, freight=True)
|
||||||
|
# sale.untaxed_amount_cache = sale.untaxed_amount
|
||||||
|
# if sale_['status'] == 'cancelled':
|
||||||
|
# sale.state = 'cancelled'
|
||||||
|
# else:
|
||||||
|
# Sale.quote([sale])
|
||||||
|
# if not generic:
|
||||||
|
# sale.state = 'confirmed'
|
||||||
|
# sale.save()
|
||||||
|
# # if shipment_['status'] in ['shipped', 'delivered']:
|
||||||
|
# # self._finish_sale(sale)
|
||||||
|
# return sale
|
||||||
|
|
||||||
|
# def cancel_sales(self, sales, pack_id=None):
|
||||||
|
# Sale = Pool().get('sale.sale')
|
||||||
|
# if pack_id:
|
||||||
|
# sales = Sale.search([('pack_id', '=', pack_id)])
|
||||||
|
# for sale in sales:
|
||||||
|
# sale.state = 'cancelled'
|
||||||
|
# sale.save()
|
||||||
|
|
||||||
|
# def _get_shipment_amount(self, order_id, shipment={}):
|
||||||
|
# URI = 'https://api.mercadolibre.com/orders/%s?access_token=%s' % (
|
||||||
|
# order_id, self.access_token)
|
||||||
|
# res = self.get_response(URI)
|
||||||
|
# sale_ = res.json()
|
||||||
|
# shipping_amount = 0
|
||||||
|
# if sale_.get('payments'):
|
||||||
|
# shipping_amount = sale_['payments'][0]['shipping_cost']
|
||||||
|
# return shipping_amount
|
||||||
|
|
||||||
|
# def get_access_token(self, refresh_token, client_id, client_secret):
|
||||||
|
# params = {'grant_type': 'refresh_token',
|
||||||
|
# 'client_id': client_id,
|
||||||
|
# 'client_secret': client_secret,
|
||||||
|
# 'refresh_token': refresh_token
|
||||||
|
# }
|
||||||
|
|
||||||
|
# uri = 'https://api.mercadolibre.com/oauth/token'
|
||||||
|
|
||||||
|
# response = requests.post(uri, params=urlencode(params),
|
||||||
|
# headers=HEADERS, data=params)
|
||||||
|
# res = response.json()
|
||||||
|
# if res.get('error', None):
|
||||||
|
# raise UserError(res.get('message') + ' Error:' + res.get('error'))
|
||||||
|
# return res['access_token'], res['refresh_token']
|
||||||
|
|
||||||
|
# @classmethod
|
||||||
|
# def get_response(cls, URI, params={}):
|
||||||
|
# response = requests.get(URI, headers=HEADERS, params=urlencode(params))
|
||||||
|
# print(response)
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# def _validate_token(self):
|
||||||
|
# access_token = self.access_token
|
||||||
|
# refresh_token = self.refresh_token
|
||||||
|
# client_id = self.app_id
|
||||||
|
# client_secret = self.secret_key
|
||||||
|
# if self.status_token != 'active':
|
||||||
|
# access_token, refresh_token = self.get_access_token(
|
||||||
|
# refresh_token, client_id, client_secret
|
||||||
|
# )
|
||||||
|
# self.write([self], {'access_token': access_token,
|
||||||
|
# 'refresh_token': refresh_token,
|
||||||
|
# 'creation_time': datetime.now()
|
||||||
|
# })
|
||||||
|
# return access_token, refresh_token, client_id, client_secret
|
||||||
|
|
||||||
|
# @classmethod
|
||||||
|
# def _get_channel(cls):
|
||||||
|
# channels = cls.search([
|
||||||
|
# ('state', '=', 'active'),
|
||||||
|
# ('channel_name', '=', 'mercadolibre'),
|
||||||
|
# ])
|
||||||
|
# if channels:
|
||||||
|
# return channels[0]
|
||||||
|
# else:
|
||||||
|
# return None
|
||||||
|
|
||||||
|
# @classmethod
|
||||||
|
# def request_api(cls, data):
|
||||||
|
# channel = cls._get_channel()
|
||||||
|
# response = {'status': 'error', 'msg_response': 'Fail in process !!!'}
|
||||||
|
# if not channel:
|
||||||
|
# return response
|
||||||
|
# access_token, refresh_token, client_id, client_secret = channel._validate_token()
|
||||||
|
# if data.get('resource') and data['resource'].count('orders'):
|
||||||
|
# order_id = str(data['resource'].replace('/orders/', ''))
|
||||||
|
# URI = 'https://api.mercadolibre.com/orders/%s?access_token=%s' % (
|
||||||
|
# order_id, access_token)
|
||||||
|
# result = cls.get_response(URI).json()
|
||||||
|
# res = channel.validate_sale(result)
|
||||||
|
# if res:
|
||||||
|
# response = {
|
||||||
|
# 'status': 'ok',
|
||||||
|
# 'msg_response': 'Successfull process !!!',
|
||||||
|
# 'order': order_id
|
||||||
|
# }
|
||||||
|
# else:
|
||||||
|
# response = {
|
||||||
|
# 'status': 'ok',
|
||||||
|
# 'msg_response': 'Sale processed before !!!',
|
||||||
|
# 'order': order_id
|
||||||
|
# }
|
||||||
|
# elif data.get('resource') and data['resource'].count('shipments'):
|
||||||
|
# shipment_id = str(data['resource'].replace('/shipments/', ''))
|
||||||
|
# shipment_ = channel.get_shipment_api(shipment_id)
|
||||||
|
# order_id = shipment_['order_id']
|
||||||
|
|
||||||
|
# Sale = Pool().get('sale.sale')
|
||||||
|
# sales = Sale.search([
|
||||||
|
# ('reference', 'ilike', '%' + str(order_id) + '%')
|
||||||
|
# ])
|
||||||
|
# response.update({'order': order_id})
|
||||||
|
# if not sales:
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# sale = sales[0]
|
||||||
|
# if sale.invoices:
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# if len(sales) > 1:
|
||||||
|
# channel.upload_note(
|
||||||
|
# sale, 'Error, al generar factura orden duplicada')
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# if shipment_.get('tracking_number'):
|
||||||
|
# Sale.write([sale], {
|
||||||
|
# 'description': 'GUIA DE ENVIO NO. ' + shipment_['tracking_number'],
|
||||||
|
# 'tracking_number': shipment_['tracking_number']
|
||||||
|
# })
|
||||||
|
# if shipment_['status'] in ['shipped', 'delivered']:
|
||||||
|
# try:
|
||||||
|
# channel._finish_sale(sale)
|
||||||
|
# except:
|
||||||
|
# channel.upload_note(sale, 'Error al finalizar factura')
|
||||||
|
# response = {'status': 'ok',
|
||||||
|
# 'msg_response': 'Successfull process !!!',
|
||||||
|
# 'order': order_id}
|
||||||
|
# else:
|
||||||
|
# return {'status': 'none', 'msg_response': 'Don`t process this topic'}
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# def _finish_sale(self, sale, type='invoice'):
|
||||||
|
# ctx = self._get_context()
|
||||||
|
# pool = Pool()
|
||||||
|
# Sale = pool.get('sale.sale')
|
||||||
|
# Invoice = pool.get('account.invoice')
|
||||||
|
# Date = pool.get('ir.date')
|
||||||
|
# with Transaction().set_context(ctx):
|
||||||
|
# Sale.process([sale])
|
||||||
|
# if not sale.invoices:
|
||||||
|
# return
|
||||||
|
# invoice = sale.invoices[0]
|
||||||
|
# invoice.invoice_date = Date.today()
|
||||||
|
# if type == 'return':
|
||||||
|
# sale_origin = sale.origin
|
||||||
|
# if sale_origin.invoices:
|
||||||
|
# inv_origin = sale_origin.invoices[0]
|
||||||
|
# invoice.credit_note_concept = '2'
|
||||||
|
# invoice.original_invoice = inv_origin.id
|
||||||
|
# invoice.save()
|
||||||
|
# Invoice.validate_invoice([invoice])
|
||||||
|
# if invoice.invoice_type not in ('C', 'P', 'M'):
|
||||||
|
# try:
|
||||||
|
# invoice.submit([invoice])
|
||||||
|
# if not invoice.cufe:
|
||||||
|
# return
|
||||||
|
# except:
|
||||||
|
# self.upload_note(sale, 'Error de envio DIAN')
|
||||||
|
# try:
|
||||||
|
# Invoice.post([invoice])
|
||||||
|
# self.upload_note(sale, 'Factura generada')
|
||||||
|
# self.upload_invoice(sale)
|
||||||
|
# except:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
# def upload_invoice(self, sale):
|
||||||
|
# if not sale.reference or not sale.invoices:
|
||||||
|
# return
|
||||||
|
|
||||||
|
# invoice = sale.invoices[0]
|
||||||
|
# pack_id = sale.reference
|
||||||
|
# if sale.pack_id:
|
||||||
|
# pack_id = sale.pack_id
|
||||||
|
# URI = 'https://api.mercadolibre.com/packs/%s/fiscal_documents?access_token=%s' % (
|
||||||
|
# pack_id, self.access_token)
|
||||||
|
# if sale.uploaded_invoice:
|
||||||
|
# response = requests.delete(URI)
|
||||||
|
|
||||||
|
# report = self.render_report(invoice)
|
||||||
|
# file = {"fiscal_document": report}
|
||||||
|
# response = requests.post(URI, files=file)
|
||||||
|
# print(response.status_code)
|
||||||
|
# message = 'Error al subir factura'
|
||||||
|
# if response.status_code in [200, 201, 202]:
|
||||||
|
# res = response.json()
|
||||||
|
# upload_ids = 'Upload ids: ' + ', '.join(list(res['ids']))
|
||||||
|
# sale.write([sale], {
|
||||||
|
# 'uploaded_invoice': True,
|
||||||
|
# 'document_invoice': upload_ids,
|
||||||
|
# })
|
||||||
|
# message = 'Factura Cargada exitosamente'
|
||||||
|
# self.upload_note(sale, message)
|
||||||
|
|
||||||
|
# def upload_note(self, sale, message):
|
||||||
|
# URI = 'https://api.mercadolibre.com/orders/%s/notes?access_token=%s' % (
|
||||||
|
# sale.reference, self.access_token)
|
||||||
|
|
||||||
|
# params = {"note": message}
|
||||||
|
# request = json.dumps(params)
|
||||||
|
# response = requests.post(URI, headers=HEADERS, data=request)
|
||||||
|
# if not response.status_code in [200, 201, 202]:
|
||||||
|
# self.send_mail_notification(
|
||||||
|
# 'error al crear nota en orden ' + sale.reference)
|
||||||
|
|
||||||
|
|
||||||
|
class MercadoLibre:
|
||||||
|
'MercadoLibre'
|
||||||
|
def __init__(self, web_shop):
|
||||||
|
self.access_token = web_shop.access_token if web_shop.access_token else ''
|
||||||
|
self.generic_product = web_shop.generic_product
|
||||||
|
self.refresh_token = web_shop.refresh_token
|
||||||
|
self.id = web_shop.id
|
||||||
|
self.app_id = web_shop.app_id
|
||||||
|
self.secret_key = web_shop.secret_key
|
||||||
|
|
||||||
def _get_context(self):
|
def _get_context(self):
|
||||||
user_ = self._get_user()
|
user_ = self._get_user()
|
||||||
|
@ -38,13 +602,6 @@ class MercadoLibre(SaleWebChannel):
|
||||||
'language': 'es'
|
'language': 'es'
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_user(self):
|
|
||||||
User = Pool().get('res.user')
|
|
||||||
user, = User.search([
|
|
||||||
('login', '=', 'mercado.libre')
|
|
||||||
])
|
|
||||||
return user
|
|
||||||
|
|
||||||
def _create_product(self, codes, line={}):
|
def _create_product(self, codes, line={}):
|
||||||
item = line['item']
|
item = line['item']
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
|
@ -262,14 +819,6 @@ class MercadoLibre(SaleWebChannel):
|
||||||
|
|
||||||
def validate_sale(self, sale_):
|
def validate_sale(self, sale_):
|
||||||
if sale_.get('pack_id'):
|
if sale_.get('pack_id'):
|
||||||
# if not sale_.get('shipping'):
|
|
||||||
# return
|
|
||||||
# shipment_id = sale_['shipping']['id']
|
|
||||||
# URI = 'https://api.mercadolibre.com/shipments/%s/items?access_token=%s' % (
|
|
||||||
# shipment_id, self.access_token)
|
|
||||||
# res = self.get_response(URI)
|
|
||||||
# shipment_items = res.json()
|
|
||||||
# if len(shipment_items) > 1:
|
|
||||||
URI = 'https://api.mercadolibre.com/packs/%s?access_token=%s' % (
|
URI = 'https://api.mercadolibre.com/packs/%s?access_token=%s' % (
|
||||||
sale_.get('pack_id'), self.access_token)
|
sale_.get('pack_id'), self.access_token)
|
||||||
response = self.get_response(URI)
|
response = self.get_response(URI)
|
||||||
|
@ -285,17 +834,22 @@ class MercadoLibre(SaleWebChannel):
|
||||||
sale_order = order.json()
|
sale_order = order.json()
|
||||||
ids += ',' + order_id
|
ids += ',' + order_id
|
||||||
sale_['order_items'].extend(sale_order['order_items'])
|
sale_['order_items'].extend(sale_order['order_items'])
|
||||||
|
# sale_['id'] = str(sale_['id']) + ids
|
||||||
sale_['id'] = str(sale_['id']) + ids
|
sale_['id'] = str(sale_['id']) + ids
|
||||||
return self._create_sale(sale_)
|
return self._create_sale(sale_)
|
||||||
else:
|
else:
|
||||||
return self._create_sale(sale_)
|
return self._create_sale(sale_)
|
||||||
else:
|
else:
|
||||||
|
print(sale_, 'que carajos')
|
||||||
return self._create_sale(sale_)
|
return self._create_sale(sale_)
|
||||||
|
|
||||||
def _create_sale(self, sale_):
|
def _create_sale(self, sale_):
|
||||||
_pool = Pool()
|
_pool = Pool()
|
||||||
Sale = _pool.get('sale.sale')
|
Sale = _pool.get('sale.sale')
|
||||||
reference = '%' + str(sale_['id']).split(',')[0] + '%'
|
# reference = '%' + str(sale_['id']).split(',')[0] + '%'
|
||||||
|
ids = [str(order['id']) for order in sale_['orders']]
|
||||||
|
reference = ', '.join(ids)
|
||||||
|
print(reference, 'esta es mi referencia')
|
||||||
dom = [
|
dom = [
|
||||||
('reference', 'like', reference)
|
('reference', 'like', reference)
|
||||||
]
|
]
|
||||||
|
@ -357,7 +911,7 @@ class MercadoLibre(SaleWebChannel):
|
||||||
'invoice_address': Party.address_get(party, type='invoice'),
|
'invoice_address': Party.address_get(party, type='invoice'),
|
||||||
'shipment_address': Party.address_get(party, type='delivery'),
|
'shipment_address': Party.address_get(party, type='delivery'),
|
||||||
'description': 'VENTA WEB ',
|
'description': 'VENTA WEB ',
|
||||||
'channel': self.id,
|
'web': self.id,
|
||||||
'invoice_type': self.invoice_type,
|
'invoice_type': self.invoice_type,
|
||||||
'pack_id': str(sale_['pack_id']) if sale_['pack_id'] else '',
|
'pack_id': str(sale_['pack_id']) if sale_['pack_id'] else '',
|
||||||
}])
|
}])
|
||||||
|
@ -375,23 +929,10 @@ class MercadoLibre(SaleWebChannel):
|
||||||
# self._finish_sale(sale)
|
# self._finish_sale(sale)
|
||||||
return sale
|
return sale
|
||||||
|
|
||||||
def cancel_sales(self, sales, pack_id=None):
|
@classmethod
|
||||||
Sale = Pool().get('sale.sale')
|
def get_response(cls, URI, params={}):
|
||||||
if pack_id:
|
response = requests.get(URI, headers=HEADERS, params=urlencode(params))
|
||||||
sales = Sale.search([('pack_id', '=', pack_id)])
|
return response
|
||||||
for sale in sales:
|
|
||||||
sale.state = 'cancelled'
|
|
||||||
sale.save()
|
|
||||||
|
|
||||||
def _get_shipment_amount(self, order_id, shipment={}):
|
|
||||||
URI = 'https://api.mercadolibre.com/orders/%s?access_token=%s' % (
|
|
||||||
order_id, self.access_token)
|
|
||||||
res = self.get_response(URI)
|
|
||||||
sale_ = res.json()
|
|
||||||
shipping_amount = 0
|
|
||||||
if sale_.get('payments'):
|
|
||||||
shipping_amount = sale_['payments'][0]['shipping_cost']
|
|
||||||
return shipping_amount
|
|
||||||
|
|
||||||
def get_access_token(self, refresh_token, client_id, client_secret):
|
def get_access_token(self, refresh_token, client_id, client_secret):
|
||||||
params = {'grant_type': 'refresh_token',
|
params = {'grant_type': 'refresh_token',
|
||||||
|
@ -399,9 +940,7 @@ class MercadoLibre(SaleWebChannel):
|
||||||
'client_secret': client_secret,
|
'client_secret': client_secret,
|
||||||
'refresh_token': refresh_token
|
'refresh_token': refresh_token
|
||||||
}
|
}
|
||||||
|
|
||||||
uri = 'https://api.mercadolibre.com/oauth/token'
|
uri = 'https://api.mercadolibre.com/oauth/token'
|
||||||
|
|
||||||
response = requests.post(uri, params=urlencode(params),
|
response = requests.post(uri, params=urlencode(params),
|
||||||
headers=HEADERS, data=params)
|
headers=HEADERS, data=params)
|
||||||
res = response.json()
|
res = response.json()
|
||||||
|
@ -409,170 +948,13 @@ class MercadoLibre(SaleWebChannel):
|
||||||
raise UserError(res.get('message') + ' Error:' + res.get('error'))
|
raise UserError(res.get('message') + ' Error:' + res.get('error'))
|
||||||
return res['access_token'], res['refresh_token']
|
return res['access_token'], res['refresh_token']
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_response(cls, URI, params={}):
|
|
||||||
response = requests.get(URI, headers=HEADERS, params=urlencode(params))
|
|
||||||
return response
|
|
||||||
|
|
||||||
def _validate_token(self):
|
def _validate_token(self):
|
||||||
access_token = self.access_token
|
access_token = self.access_token
|
||||||
refresh_token = self.refresh_token
|
refresh_token = self.refresh_token
|
||||||
client_id = self.app_id
|
client_id = self.app_id
|
||||||
client_secret = self.secret_key
|
client_secret = self.secret_key
|
||||||
if self.status_token != 'active':
|
access_token, refresh_token = self.get_access_token(
|
||||||
access_token, refresh_token = self.get_access_token(
|
refresh_token, client_id, client_secret
|
||||||
refresh_token, client_id, client_secret
|
)
|
||||||
)
|
# return access_token, refresh_token, client_id, client_secret
|
||||||
self.write([self], {'access_token': access_token,
|
return access_token
|
||||||
'refresh_token': refresh_token,
|
|
||||||
'creation_time': datetime.now()
|
|
||||||
})
|
|
||||||
return access_token, refresh_token, client_id, client_secret
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _get_channel(cls):
|
|
||||||
channels = cls.search([
|
|
||||||
('state', '=', 'active'),
|
|
||||||
('channel_name', '=', 'mercadolibre'),
|
|
||||||
])
|
|
||||||
if channels:
|
|
||||||
return channels[0]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def request_api(cls, data):
|
|
||||||
channel = cls._get_channel()
|
|
||||||
response = {'status': 'error', 'msg_response': 'Fail in process !!!'}
|
|
||||||
if not channel:
|
|
||||||
return response
|
|
||||||
access_token, refresh_token, client_id, client_secret = channel._validate_token()
|
|
||||||
if data.get('resource') and data['resource'].count('orders'):
|
|
||||||
order_id = str(data['resource'].replace('/orders/', ''))
|
|
||||||
URI = 'https://api.mercadolibre.com/orders/%s?access_token=%s' % (
|
|
||||||
order_id, access_token)
|
|
||||||
result = cls.get_response(URI).json()
|
|
||||||
res = channel.validate_sale(result)
|
|
||||||
if res:
|
|
||||||
response = {
|
|
||||||
'status': 'ok',
|
|
||||||
'msg_response': 'Successfull process !!!',
|
|
||||||
'order': order_id
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
response = {
|
|
||||||
'status': 'ok',
|
|
||||||
'msg_response': 'Sale processed before !!!',
|
|
||||||
'order': order_id
|
|
||||||
}
|
|
||||||
elif data.get('resource') and data['resource'].count('shipments'):
|
|
||||||
shipment_id = str(data['resource'].replace('/shipments/', ''))
|
|
||||||
shipment_ = channel.get_shipment_api(shipment_id)
|
|
||||||
order_id = shipment_['order_id']
|
|
||||||
|
|
||||||
Sale = Pool().get('sale.sale')
|
|
||||||
sales = Sale.search([
|
|
||||||
('reference', 'ilike', '%' + str(order_id) + '%')
|
|
||||||
])
|
|
||||||
response.update({'order': order_id})
|
|
||||||
if not sales:
|
|
||||||
return response
|
|
||||||
|
|
||||||
sale = sales[0]
|
|
||||||
if sale.invoices:
|
|
||||||
return response
|
|
||||||
|
|
||||||
if len(sales) > 1:
|
|
||||||
channel.upload_note(
|
|
||||||
sale, 'Error, al generar factura orden duplicada')
|
|
||||||
return response
|
|
||||||
|
|
||||||
if shipment_.get('tracking_number'):
|
|
||||||
Sale.write([sale], {
|
|
||||||
'description': 'GUIA DE ENVIO NO. ' + shipment_['tracking_number'],
|
|
||||||
'tracking_number': shipment_['tracking_number']
|
|
||||||
})
|
|
||||||
if shipment_['status'] in ['shipped', 'delivered']:
|
|
||||||
try:
|
|
||||||
channel._finish_sale(sale)
|
|
||||||
except:
|
|
||||||
channel.upload_note(sale, 'Error al finalizar factura')
|
|
||||||
response = {'status': 'ok',
|
|
||||||
'msg_response': 'Successfull process !!!',
|
|
||||||
'order': order_id}
|
|
||||||
else:
|
|
||||||
return {'status': 'none', 'msg_response': 'Don`t process this topic'}
|
|
||||||
return response
|
|
||||||
|
|
||||||
def _finish_sale(self, sale, type='invoice'):
|
|
||||||
ctx = self._get_context()
|
|
||||||
pool = Pool()
|
|
||||||
Sale = pool.get('sale.sale')
|
|
||||||
Invoice = pool.get('account.invoice')
|
|
||||||
Date = pool.get('ir.date')
|
|
||||||
with Transaction().set_context(ctx):
|
|
||||||
Sale.process([sale])
|
|
||||||
if not sale.invoices:
|
|
||||||
return
|
|
||||||
invoice = sale.invoices[0]
|
|
||||||
invoice.invoice_date = Date.today()
|
|
||||||
if type == 'return':
|
|
||||||
sale_origin = sale.origin
|
|
||||||
if sale_origin.invoices:
|
|
||||||
inv_origin = sale_origin.invoices[0]
|
|
||||||
invoice.credit_note_concept = '2'
|
|
||||||
invoice.original_invoice = inv_origin.id
|
|
||||||
invoice.save()
|
|
||||||
Invoice.validate_invoice([invoice])
|
|
||||||
if invoice.invoice_type not in ('C', 'P', 'M'):
|
|
||||||
try:
|
|
||||||
invoice.submit([invoice])
|
|
||||||
if not invoice.cufe:
|
|
||||||
return
|
|
||||||
except:
|
|
||||||
self.upload_note(sale, 'Error de envio DIAN')
|
|
||||||
try:
|
|
||||||
Invoice.post([invoice])
|
|
||||||
self.upload_note(sale, 'Factura generada')
|
|
||||||
self.upload_invoice(sale)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def upload_invoice(self, sale):
|
|
||||||
if not sale.reference or not sale.invoices:
|
|
||||||
return
|
|
||||||
|
|
||||||
invoice = sale.invoices[0]
|
|
||||||
pack_id = sale.reference
|
|
||||||
if sale.pack_id:
|
|
||||||
pack_id = sale.pack_id
|
|
||||||
URI = 'https://api.mercadolibre.com/packs/%s/fiscal_documents?access_token=%s' % (
|
|
||||||
pack_id, self.access_token)
|
|
||||||
if sale.uploaded_invoice:
|
|
||||||
response = requests.delete(URI)
|
|
||||||
|
|
||||||
report = self.render_report(invoice)
|
|
||||||
file = {"fiscal_document": report}
|
|
||||||
response = requests.post(URI, files=file)
|
|
||||||
print(response.status_code)
|
|
||||||
message = 'Error al subir factura'
|
|
||||||
if response.status_code in [200, 201, 202]:
|
|
||||||
res = response.json()
|
|
||||||
upload_ids = 'Upload ids: ' + ', '.join(list(res['ids']))
|
|
||||||
sale.write([sale], {
|
|
||||||
'uploaded_invoice': True,
|
|
||||||
'document_invoice': upload_ids,
|
|
||||||
})
|
|
||||||
message = 'Factura Cargada exitosamente'
|
|
||||||
self.upload_note(sale, message)
|
|
||||||
|
|
||||||
def upload_note(self, sale, message):
|
|
||||||
URI = 'https://api.mercadolibre.com/orders/%s/notes?access_token=%s' % (
|
|
||||||
sale.reference, self.access_token)
|
|
||||||
|
|
||||||
params = {"note": message}
|
|
||||||
request = json.dumps(params)
|
|
||||||
response = requests.post(URI, headers=HEADERS, data=request)
|
|
||||||
if not response.status_code in [200, 201, 202]:
|
|
||||||
self.send_mail_notification(
|
|
||||||
'error al crear nota en orden ' + sale.reference)
|
|
||||||
|
|
11
sale.py
11
sale.py
|
@ -15,7 +15,7 @@ class Sale(metaclass=PoolMeta):
|
||||||
|
|
||||||
is_paymented = fields.Function(fields.Boolean('Is Paymented'), 'get_is_paymented')
|
is_paymented = fields.Function(fields.Boolean('Is Paymented'), 'get_is_paymented')
|
||||||
products_string = fields.Char('Products String')
|
products_string = fields.Char('Products String')
|
||||||
channel = fields.Many2One('sale.web_channel', 'channel')
|
# channel = fields.Many2One('sale.web_channel', 'channel')
|
||||||
uploaded_invoice = fields.Boolean('uploaded Invoice', readonly=True)
|
uploaded_invoice = fields.Boolean('uploaded Invoice', readonly=True)
|
||||||
document_invoice = fields.Char('Document Invoice')
|
document_invoice = fields.Char('Document Invoice')
|
||||||
tracking_number = fields.Char('Tracking Number')
|
tracking_number = fields.Char('Tracking Number')
|
||||||
|
@ -57,10 +57,11 @@ class Sale(metaclass=PoolMeta):
|
||||||
def quote(cls, sales):
|
def quote(cls, sales):
|
||||||
super(Sale, cls).quote(sales)
|
super(Sale, cls).quote(sales)
|
||||||
for sale in sales:
|
for sale in sales:
|
||||||
if sale.web_shop.type == 'rappi':
|
# if sale.web_shop.type == 'rappi':
|
||||||
print('si entra aqui en quote')
|
# print('si entra aqui en quote')
|
||||||
rappi_rec = rappi.Rappi(sale.web_shop)
|
# rappi_rec = rappi.Rappi(sale.web_shop)
|
||||||
rappi_rec.take_order(sale.web_id, 20)
|
# rappi_rec.take_order(sale.web_id, 20)
|
||||||
|
pass
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def confirm(cls, sales):
|
def confirm(cls, sales):
|
||||||
|
|
|
@ -4,8 +4,8 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<data>
|
<data>
|
||||||
<xpath expr="/form/notebook/page[@id='other']/field[@name='company']"
|
<xpath expr="/form/notebook/page[@id='other']/field[@name='company']"
|
||||||
position="after">
|
position="after">
|
||||||
<label name="channel"/>
|
<!-- <label name="channel"/>
|
||||||
<field name="channel"/>
|
<field name="channel"/> -->
|
||||||
<label name="uploaded_invoice"/>
|
<label name="uploaded_invoice"/>
|
||||||
<field name="uploaded_invoice"/>
|
<field name="uploaded_invoice"/>
|
||||||
<label name="tracking_number"/>
|
<label name="tracking_number"/>
|
||||||
|
|
|
@ -4,7 +4,7 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<data>
|
<data>
|
||||||
<xpath expr="/tree/field[@name='state']"
|
<xpath expr="/tree/field[@name='state']"
|
||||||
position="before">
|
position="before">
|
||||||
<field name="channel"/>
|
<!-- <field name="channel"/> -->
|
||||||
<field name="pack_id"/>
|
<field name="pack_id"/>
|
||||||
<field name="tracking_number"/>
|
<field name="tracking_number"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
|
@ -9,7 +9,7 @@ The COPYRIGHT file at the top level of this repository contains the full copyrig
|
||||||
<label name="channel"/>
|
<label name="channel"/>
|
||||||
<field name="channel" widget="selection"/>
|
<field name="channel" widget="selection"/>
|
||||||
<!-- <label name="name_channel"/> -->
|
<!-- <label name="name_channel"/> -->
|
||||||
<field name="name_channel" invisible="1"/>
|
<field name="type" invisible="1"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
<label name="operation"/>
|
<label name="operation"/>
|
||||||
<field name="operation"/>
|
<field name="operation"/>
|
||||||
|
|
202
web.py
202
web.py
|
@ -1,7 +1,12 @@
|
||||||
from trytond.model import fields, ModelView
|
from trytond.model import fields, ModelView
|
||||||
from trytond.pool import PoolMeta, Pool
|
from trytond.pool import PoolMeta, Pool
|
||||||
from trytond.pyson import Eval, And, Or
|
from trytond.pyson import Eval, And
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from trytond.wizard import (Wizard, StateTransition, StateView, Button)
|
||||||
|
from .exceptions import ErrorSynchronizingSale
|
||||||
|
from trytond.i18n import gettext
|
||||||
|
from trytond.transaction import Transaction
|
||||||
|
from . mercado_libre import MercadoLibre
|
||||||
|
|
||||||
from . import rappi
|
from . import rappi
|
||||||
|
|
||||||
|
@ -25,6 +30,14 @@ TYPE_INVOICE = [
|
||||||
('92', 'Nota Débito Eléctronica'),
|
('92', 'Nota Débito Eléctronica'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# TODO FOR EXECUTE in database
|
||||||
|
"""
|
||||||
|
alter database rename table sale_web_channel to web_shop
|
||||||
|
RENAME COLUMN channel_name by type
|
||||||
|
|
||||||
|
RENAME COLUMN creation_time by token_create_date
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Shop(metaclass=PoolMeta):
|
class Shop(metaclass=PoolMeta):
|
||||||
__name__ = 'web.shop'
|
__name__ = 'web.shop'
|
||||||
|
@ -36,6 +49,9 @@ class Shop(metaclass=PoolMeta):
|
||||||
authorization_code = fields.Char('Authorization Code', states={
|
authorization_code = fields.Char('Authorization Code', states={
|
||||||
'invisible': (Eval('type') != 'mercadolibre'),
|
'invisible': (Eval('type') != 'mercadolibre'),
|
||||||
})
|
})
|
||||||
|
shop = fields.Many2One('sale.shop', 'Shop', domain=[
|
||||||
|
('company', '=', Eval('company'))
|
||||||
|
])
|
||||||
access_token = fields.Char('Access Token', states={
|
access_token = fields.Char('Access Token', states={
|
||||||
'invisible': And(
|
'invisible': And(
|
||||||
Eval('type') != 'mercadolibre',
|
Eval('type') != 'mercadolibre',
|
||||||
|
@ -76,6 +92,17 @@ class Shop(metaclass=PoolMeta):
|
||||||
seller_id = fields.Char('Seller ID', states={
|
seller_id = fields.Char('Seller ID', states={
|
||||||
'invisible': ~Eval('type').in_(['mercadolibre', 'rappi']),
|
'invisible': ~Eval('type').in_(['mercadolibre', 'rappi']),
|
||||||
})
|
})
|
||||||
|
password_api = fields.Char('Api Password', states={
|
||||||
|
'invisible': (Eval('type') != 'shopify'),
|
||||||
|
})
|
||||||
|
host_name = fields.Char('Host Name', states={
|
||||||
|
'invisible': And(
|
||||||
|
Eval('type') != 'shopify',
|
||||||
|
Eval('type') != 'rappi'),
|
||||||
|
})
|
||||||
|
api_key = fields.Char('Api Key', states={
|
||||||
|
'invisible': (Eval('type') != 'shopify'),
|
||||||
|
})
|
||||||
price_list = fields.Many2One('product.price_list', 'Price list', ondelete="RESTRICT")
|
price_list = fields.Many2One('product.price_list', 'Price list', ondelete="RESTRICT")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -112,11 +139,11 @@ class Shop(metaclass=PoolMeta):
|
||||||
if records:
|
if records:
|
||||||
for record in records:
|
for record in records:
|
||||||
if record.type == 'mercadolibre':
|
if record.type == 'mercadolibre':
|
||||||
MercadoLibre = Pool().get('sale.web_channel.mercado_libre')
|
# MercadoLibre = Pool().get('web.shop')
|
||||||
channels = MercadoLibre.search([
|
mercadolibre_rec = MercadoLibre(record)
|
||||||
('state', '=', 'active'),
|
# record.access_token, refresh_token, client_id, client_secret = mercadolibre_rec._validate_token()
|
||||||
('type', '=', 'mercadolibre'),
|
record.access_token = mercadolibre_rec._validate_token()
|
||||||
])
|
record.save()
|
||||||
if record.type == 'rappi':
|
if record.type == 'rappi':
|
||||||
rappi_rec = rappi.Rappi(record)
|
rappi_rec = rappi.Rappi(record)
|
||||||
record.access_token = rappi_rec.get_token_access()['access_token']
|
record.access_token = rappi_rec.get_token_access()['access_token']
|
||||||
|
@ -138,3 +165,166 @@ class Shop(metaclass=PoolMeta):
|
||||||
rappi_rec = rappi.Rappi(record)
|
rappi_rec = rappi.Rappi(record)
|
||||||
rappi_rec.create_sales()
|
rappi_rec.create_sales()
|
||||||
|
|
||||||
|
|
||||||
|
class SynchronizeChannelOrdersStart(ModelView):
|
||||||
|
'Synchronize Channel orders Start'
|
||||||
|
__name__ = 'sale_web_channel.synchronize_orders.start'
|
||||||
|
company = fields.Many2One('company.company', 'Company', required=True)
|
||||||
|
shop = fields.Many2One('sale.shop', 'Shop', required=True, domain=[
|
||||||
|
('company', '=', Eval('company'))
|
||||||
|
])
|
||||||
|
channel = fields.Many2One('web.shop', 'Channel', required=True,
|
||||||
|
domain=[
|
||||||
|
('shop', '=', Eval('shop'))
|
||||||
|
])
|
||||||
|
operation = fields.Selection([
|
||||||
|
('', ''),
|
||||||
|
('orders_for_day', 'Orders for day'),
|
||||||
|
('especific_order', 'Especific Orders')
|
||||||
|
], 'Operation', required=True)
|
||||||
|
type = fields.Selection([
|
||||||
|
('', ''),
|
||||||
|
('shopify', 'Shopify'),
|
||||||
|
('mercadolibre', 'Mercado libre')
|
||||||
|
], 'Name Channel', required=True)
|
||||||
|
order_id = fields.Char('Order ID', states={
|
||||||
|
'invisible': (Eval('operation') != 'especific_order'),
|
||||||
|
'required': (Eval('operation') == 'especific_order'),
|
||||||
|
})
|
||||||
|
date = fields.Date('Date', states={
|
||||||
|
'invisible': (Eval('operation') != 'orders_for_day'),
|
||||||
|
'required': (Eval('operation') == 'orders_for_day'),
|
||||||
|
})
|
||||||
|
date_end = fields.Date('Finish Date', states={
|
||||||
|
'invisible': (Eval('operation') != 'orders_for_day') | (Eval('name_channel') != 'shopify'),
|
||||||
|
'required': (Eval('operation') == 'orders_for_day') & (Eval('name_channel') != 'mercadolibre'),
|
||||||
|
})
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_company():
|
||||||
|
return Transaction().context.get('company')
|
||||||
|
|
||||||
|
@fields.depends('channel')
|
||||||
|
def on_change_channel(self):
|
||||||
|
self.type = self.channel.type if self.channel else None
|
||||||
|
|
||||||
|
|
||||||
|
class SynchronizeChannelOrders(Wizard):
|
||||||
|
'Synchronize Channel Orders'
|
||||||
|
__name__ = 'sale_web_channel.synchronize_orders'
|
||||||
|
start = StateView('sale_web_channel.synchronize_orders.start',
|
||||||
|
'sale_web_channel.synchronize_orders_view_form', [
|
||||||
|
Button('Cancel', 'end', 'tryton-cancel'),
|
||||||
|
Button('Create', 'accept',
|
||||||
|
'tryton-ok', default=True),
|
||||||
|
])
|
||||||
|
accept = StateTransition()
|
||||||
|
done = StateView('sale_web_channel.synchronize_orders.done',
|
||||||
|
'sale_web_channel.synchronize_orders_done', [
|
||||||
|
Button('Done', 'end', 'tryton-ok', default=True),
|
||||||
|
])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __setup__(cls):
|
||||||
|
super(SynchronizeChannelOrders, cls).__setup__()
|
||||||
|
|
||||||
|
def transition_accept(self):
|
||||||
|
pool = Pool()
|
||||||
|
Sale = pool.get('sale.sale')
|
||||||
|
channel = self.start.channel
|
||||||
|
operation = self.start.operation
|
||||||
|
if channel.type == 'mercadolibre':
|
||||||
|
mercado_libre = MercadoLibre(channel)
|
||||||
|
if operation == 'especific_order':
|
||||||
|
order_id = self.start.order_id
|
||||||
|
URI = 'https://api.mercadolibre.com/packs/%s?access_token=%s' % (
|
||||||
|
order_id, channel.access_token)
|
||||||
|
result = mercado_libre.get_response(URI).json()
|
||||||
|
print(result, 'este es el result')
|
||||||
|
if not result:
|
||||||
|
raise ErrorSynchronizingSale(
|
||||||
|
gettext('sale_web_channel.msg_error_synchronizing_sale', s=result))
|
||||||
|
print(result, channel.access_token)
|
||||||
|
sale_created = mercado_libre.validate_sale(result)
|
||||||
|
if sale_created:
|
||||||
|
generic_code = self.start.channel.generic_product.code if self.start.channel.generic_product else None
|
||||||
|
product_generic = [
|
||||||
|
line.product.code for line in sale_created.lines if line.product.code == generic_code and generic_code]
|
||||||
|
if not sale_created.pack_id and \
|
||||||
|
sale_created.comment in ['shipped', 'delivered'] and \
|
||||||
|
len(product_generic) < 1:
|
||||||
|
Sale.process([sale_created])
|
||||||
|
else:
|
||||||
|
date_from = str(self.start.date) + 'T00:00:00.000-00:00'
|
||||||
|
date_to = str(self.start.date + timedelta(days=1)
|
||||||
|
) + 'T00:00:00.000-00:00'
|
||||||
|
URI = 'https://api.mercadolibre.com/orders/search?seller=%s&order.date_created.from=%s&order.date_created.to=%s&access_token=%s&order.status=paid' % (
|
||||||
|
channel.seller_id, date_from, date_to, channel.access_token)
|
||||||
|
result = MercadoLibre.get_response(URI).json()
|
||||||
|
for res in result['results']:
|
||||||
|
sales = Sale.search([('reference', 'like', '%' + str(res['id']) + '%' )])
|
||||||
|
shipment_status = ''
|
||||||
|
if not sales:
|
||||||
|
sale_created = channel.validate_sale(res)
|
||||||
|
shipment_status = sale_created.comment
|
||||||
|
sales = [sale_created]
|
||||||
|
else:
|
||||||
|
sfm_id = res['shipping']['id']
|
||||||
|
shipment_ = channel.get_shipment_api(sfm_id)
|
||||||
|
shipment_status = shipment_['status']
|
||||||
|
if res.get('pack_id') or not shipment_status:
|
||||||
|
continue
|
||||||
|
if shipment_status in ['shipped', 'delivered']:
|
||||||
|
for sale in sales:
|
||||||
|
if not sale.invoices:
|
||||||
|
Sale.process([sale])
|
||||||
|
if channel.type == 'shopify':
|
||||||
|
Shopify = pool.get('sale.web_channel.shopify')
|
||||||
|
|
||||||
|
channel, = Shopify.search([('shop', '=', self.start.shop.id), ])
|
||||||
|
if operation == 'especific_order':
|
||||||
|
order_id = self.start.order_id
|
||||||
|
URI = 'https://%s:%s@%s/admin/api/2020-10/orders.json?status=any&ids=%s' % (
|
||||||
|
channel.api_key, channel.password_api, channel.host_name, order_id)
|
||||||
|
result = Shopify.get_response(URI).json()
|
||||||
|
if not result:
|
||||||
|
raise ErrorSynchronizingSale(
|
||||||
|
gettext('sale_web_channel.msg_error_synchronizing_sale', s=result))
|
||||||
|
sale_created = channel._create_sale(result['orders'][0])
|
||||||
|
if sale_created and \
|
||||||
|
sale_created.description.count('fulfilled'):
|
||||||
|
Sale.process([sale_created])
|
||||||
|
else:
|
||||||
|
date_from = str(self.start.date) + 'T00:00:00.000-00:00'
|
||||||
|
date_to = str(self.start.date_end) + 'T00:00:00.000-00:00'
|
||||||
|
URI = 'https://%s:%s@%s/admin/api/2020-10/orders.json?status=any&created_at_min=%s&created_at_max=%s' % (
|
||||||
|
channel.api_key, channel.password_api, channel.host_name, date_from, date_to)
|
||||||
|
result = Shopify.get_response(URI).json()
|
||||||
|
print('quantity orders----> ', len(result['orders']))
|
||||||
|
|
||||||
|
for res in result['orders']:
|
||||||
|
sales = Sale.search([('reference', '=', str(res['id']))])
|
||||||
|
fulfillment_status = ''
|
||||||
|
if not sales:
|
||||||
|
sale_created = channel._create_sale(res)
|
||||||
|
fulfillment_status = sale_created.description
|
||||||
|
sales = [sale_created]
|
||||||
|
else:
|
||||||
|
fulfillment_status = res['fulfillment_status']
|
||||||
|
if not fulfillment_status:
|
||||||
|
continue
|
||||||
|
if fulfillment_status.count('fulfilled'):
|
||||||
|
for sale in sales:
|
||||||
|
if not sale.invoices:
|
||||||
|
Sale.process([sale])
|
||||||
|
return 'done'
|
||||||
|
|
||||||
|
|
||||||
|
class SynchronizeChannelOrdersDone(ModelView):
|
||||||
|
'Synchronize Channel Orders Done'
|
||||||
|
__name__ = 'sale_web_channel.synchronize_orders.done'
|
||||||
|
result = fields.Char('Result', readonly=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def default_result():
|
||||||
|
return 'successful synchronization'
|
||||||
|
|
17
web.xml
17
web.xml
|
@ -8,5 +8,22 @@ this repository contains the full copyright notices and license terms. -->
|
||||||
<field name="inherit" ref="web_shop.shop_view_form"/>
|
<field name="inherit" ref="web_shop.shop_view_form"/>
|
||||||
<field name="name">web_shop_form</field>
|
<field name="name">web_shop_form</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.action.wizard" id="synchronize_orders_wizard">
|
||||||
|
<field name="name">Synchronize Channel Orders</field>
|
||||||
|
<field name="wiz_name">sale_web_channel.synchronize_orders</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.ui.view" id="synchronize_orders_view_form">
|
||||||
|
<field name="model">sale_web_channel.synchronize_orders.start</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="name">synchronize_orders_view_form</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.ui.view" id="synchronize_orders_done">
|
||||||
|
<field name="model">sale_web_channel.synchronize_orders.done</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="name">synchronize_orders_done</field>
|
||||||
|
</record>
|
||||||
|
<menuitem action="synchronize_orders_wizard" parent="sale.menu_sale"
|
||||||
|
id="menu_synchronize_orders" sequence="100"/>
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|
|
@ -113,10 +113,10 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView):
|
||||||
'invisible': ~Eval('channel_name').in_(['mercadolibre', 'rappi']),
|
'invisible': ~Eval('channel_name').in_(['mercadolibre', 'rappi']),
|
||||||
'readonly': (Eval('state') != 'draft')
|
'readonly': (Eval('state') != 'draft')
|
||||||
})
|
})
|
||||||
admin_category = fields.Many2One('product.category', 'Admin Category',
|
# admin_category = fields.Many2One('product.category', 'Admin Category',
|
||||||
domain=[
|
# domain=[
|
||||||
('accounting', '=', False),
|
# ('accounting', '=', False),
|
||||||
])
|
# ])
|
||||||
price_list = fields.Many2One('product.price_list', 'Pricelist', ondelete="RESTRICT")
|
price_list = fields.Many2One('product.price_list', 'Pricelist', ondelete="RESTRICT")
|
||||||
template_notification = fields.Many2One(
|
template_notification = fields.Many2One(
|
||||||
'email.template', 'Template Notification')
|
'email.template', 'Template Notification')
|
||||||
|
|
Loading…
Reference in New Issue