791 lines
32 KiB
Python
791 lines
32 KiB
Python
# -*- coding: UTF-8 -*-
|
|
# This file is part electronic_mail_template module for Tryton.
|
|
# The COPYRIGHT file at the top level of this repository contains
|
|
# the full copyright notices and license terms.
|
|
from decimal import Decimal
|
|
from trytond.pool import Pool
|
|
from itertools import chain
|
|
from trytond.transaction import Transaction
|
|
import requests
|
|
from urllib.parse import urlencode
|
|
from datetime import datetime, date
|
|
from .web_channel import SaleWebChannel
|
|
import json
|
|
import base64
|
|
import hmac
|
|
import hashlib
|
|
|
|
HEADERS = {
|
|
'Accept': 'application/json',
|
|
'Content-type': 'application/json'
|
|
}
|
|
|
|
|
|
# class Shopify(SaleWebChannel):
|
|
# 'Shopify'
|
|
# __name__ = 'sale.web_channel.shopify'
|
|
|
|
# @classmethod
|
|
# def __setup__(cls):
|
|
# super(Shopify, cls).__setup__()
|
|
|
|
# def _get_context(self):
|
|
# print(self)
|
|
# return {
|
|
# 'company': self.company.id,
|
|
# 'user': self.user.id,
|
|
# 'shops': [self.shop.id],
|
|
# 'shop': self.shop.id,
|
|
# 'language': 'es'
|
|
# }
|
|
|
|
# # def _get_user(self):
|
|
# # User = Pool().get('res.user')
|
|
# # user, = User.search(
|
|
# # ('login', '=', 'shopify')
|
|
# # )
|
|
# # return user
|
|
|
|
# def _create_product(self, codes, line={}):
|
|
# pool = Pool()
|
|
# Product = pool.get('product.product')
|
|
# Template = pool.get('product.template')
|
|
# description = line['variant_title']
|
|
# list_price = Decimal(str(round(float(line['price'])/1.19, 2)))
|
|
# sale_price_w_tax = Decimal(str(round(Decimal(line['price']), 2)))
|
|
# create_template = {
|
|
# 'name': line['title'],
|
|
# 'list_price': list_price,
|
|
# 'sale_price_w_tax': sale_price_w_tax,
|
|
# 'type': 'goods',
|
|
# 'salable': True,
|
|
# 'purchasable': True,
|
|
# 'purchase_uom': 1,
|
|
# 'sale_uom': 1,
|
|
# 'default_uom': 1,
|
|
# 'account_category': 7,
|
|
# 'code': codes[0],
|
|
# }
|
|
# 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['email']
|
|
# shipment_address, phone, city = '', '', None
|
|
# if customer.get('default_address'):
|
|
# default_address = customer['default_address']
|
|
# shipment_address = default_address['address1']
|
|
# phone = default_address['phone'] or '000'
|
|
# city_name = default_address['city']
|
|
# if city_name:
|
|
# cities = City.search([
|
|
# ('name', '=', city_name)
|
|
# ])
|
|
# if cities:
|
|
# city = cities[0]
|
|
# customer_name = customer['first_name'] + ' ' + customer['last_name']
|
|
# create_customer = {
|
|
# 'id_reference': str(customer['id']),
|
|
# 'name': customer_name.upper(),
|
|
# 'type_document': '13',
|
|
# 'id_number': default_address['company'],
|
|
# 'addresses': [('create', [{
|
|
# 'street': shipment_address,
|
|
# }])],
|
|
# 'contact_mechanisms': [
|
|
# ('create', [
|
|
# {'type': 'phone', 'value': phone.replace(" ","")},
|
|
# {'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 _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_sale(self, sale_):
|
|
# print('ingresa a crear venta')
|
|
# _pool = Pool()
|
|
# Sale = _pool.get('sale.sale')
|
|
# sales = Sale.search([
|
|
# ('reference', '=', str(sale_['id']))
|
|
# ])
|
|
# if sales:
|
|
# return False
|
|
# SaleLine = _pool.get('sale.line')
|
|
# Party = _pool.get('party.party')
|
|
# User = _pool.get('res.user')
|
|
# if sale_.get('customer'):
|
|
# customer = sale_['customer']
|
|
# dom_party = [('id_number', '=', str(customer['default_address']['company']))]
|
|
# parties = Party.search(dom_party)
|
|
# if parties:
|
|
# party = parties[0]
|
|
# else:
|
|
# party = self._create_party(customer)
|
|
# create_lines = []
|
|
# ctx = self._get_context()
|
|
# user_ = User(ctx['user'])
|
|
# date_created = sale_['created_at'].split('T')
|
|
# year, month, day = date_created[0].split('-')
|
|
# sale_date = date(int(year), int(month), int(day))
|
|
# with Transaction().set_user(ctx['user']):
|
|
# comment = ''
|
|
# try:
|
|
# comment = 'GUIA DE ENVIO NO. ' + sale_['fulfillments'][0].get('tracking_number', '')\
|
|
# if sale_['fulfillment_status'] == 'fulfilled' and sale_['fulfillments'] else ''
|
|
# except:
|
|
# pass
|
|
# sale, = Sale.create([{
|
|
# 'payment_term': 1,
|
|
# 'party': party.id,
|
|
# 'sale_date': sale_date,
|
|
# 'comment': comment,
|
|
# '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 SHOPIFY ' + sale_['name'],
|
|
# 'channel': self.id,
|
|
# 'invoice_type': self.invoice_type,
|
|
# 'pack_id': ''
|
|
# }])
|
|
|
|
# with Transaction().set_context(ctx):
|
|
# create_lines = self.get_sale_lines(sale_, sale)
|
|
# SaleLine.create(create_lines)
|
|
# sale.untaxed_amount_cache = sale.untaxed_amount
|
|
# if sale_['cancel_reason'] is not None:
|
|
# sale.state = 'cancelled'
|
|
# else:
|
|
# Sale.quote([sale])
|
|
# sale.save()
|
|
# if sale_['fulfillment_status'] == 'fulfilled':
|
|
# self.order_fulfilled(sale_, [sale])
|
|
# print('*******************', sale.state)
|
|
# return sale
|
|
|
|
# def get_sale_lines(self, sale_, sale, products_refund=[]):
|
|
# pool = Pool()
|
|
# Product = pool.get('product.product')
|
|
# sale_items = sale_['line_items']
|
|
# products_refund = {}
|
|
# if sale_.get('refunds'):
|
|
# for refunds in sale_['refunds']:
|
|
# for line_items in refunds['refund_line_items']:
|
|
# sku_code = line_items['line_item']['sku']
|
|
# quantity = line_items['quantity']
|
|
# if sku_code.count('+') > 0:
|
|
# codes = sku_code.split('+')
|
|
# for code in codes:
|
|
# if code not in products_refund.keys():
|
|
# products_refund[code] = quantity
|
|
# else:
|
|
# products_refund[code] += quantity
|
|
# else:
|
|
# if sku_code not in products_refund.keys():
|
|
# products_refund[sku_code] = quantity
|
|
# else:
|
|
# products_refund[sku_code] += quantity
|
|
# create_lines = []
|
|
# for line in sale_items:
|
|
# if line['title'] == 'Tip':
|
|
# if self.tip_product:
|
|
# product = self.tip_product
|
|
# total_tip = line['price']
|
|
# create_lines.append({
|
|
# 'sale': sale.id,
|
|
# 'type': 'line',
|
|
# 'unit': product.default_uom.id,
|
|
# 'quantity': 1,
|
|
# 'unit_price': Decimal(total_tip),
|
|
# 'base_price': Decimal(total_tip),
|
|
# 'unit_price_full': Decimal(total_tip),
|
|
# 'product': product.id,
|
|
# 'description': 'BONIFICACION',
|
|
# })
|
|
# else:
|
|
# sku_code = line['sku']
|
|
# if sku_code.count('+') > 0:
|
|
# codes = sku_code.split('+')
|
|
# line['price'] = round(Decimal(line['price']) / 2, 2)
|
|
# discount = round(sum([Decimal(n['amount']) for n in line['discount_allocations']]) / 2, 2)
|
|
# else:
|
|
# codes = [sku_code]
|
|
# discount = round(sum([Decimal(n['amount']) for n in line['discount_allocations']]))
|
|
# products = Product.search([
|
|
# ('code', 'in', codes),
|
|
# ('active', '=', True)
|
|
# ])
|
|
# description = ''
|
|
# if not products:
|
|
# products = self._create_product(codes, line)
|
|
# for product in products:
|
|
# quantity = line['quantity']
|
|
# if products_refund and product.code in products_refund.keys():
|
|
# if products_refund[product.code] < quantity:
|
|
# quantity -= products_refund[product.code]
|
|
# else:
|
|
# continue
|
|
# Tax = pool.get('account.tax')
|
|
# un_price = Tax.reverse_compute((Decimal(line['price']) - Decimal(discount)),
|
|
# product.customer_taxes_used)
|
|
|
|
# create_lines.append({
|
|
# 'sale': sale.id,
|
|
# 'type': 'line',
|
|
# 'unit': product.default_uom.id,
|
|
# 'quantity': quantity,
|
|
# 'base_price': round(Decimal(un_price), 3),
|
|
# 'unit_price': round(Decimal(un_price), 3),
|
|
# 'unit_price_full': round(Decimal(line['price']),2),
|
|
# 'product': product.id,
|
|
# 'taxes': [('add', product.customer_taxes_used)],
|
|
# 'description': description,
|
|
# })
|
|
# if self.freight_product and len(sale_['shipping_lines']) > 0:
|
|
# product = self.freight_product
|
|
# shipping_amount = sale_['shipping_lines'][0]['price']
|
|
# create_lines.append({
|
|
# 'sale': sale.id,
|
|
# 'type': 'line',
|
|
# 'unit': product.default_uom.id,
|
|
# 'quantity': 1,
|
|
# 'base_price': Decimal(shipping_amount),
|
|
# 'unit_price': Decimal(shipping_amount),
|
|
# 'unit_price_full': Decimal(shipping_amount),
|
|
# 'product': product.id,
|
|
# 'description': 'FLETE',
|
|
# })
|
|
# return create_lines
|
|
|
|
# def order_updated(self, data, sales):
|
|
# sale = sales[0]
|
|
# pool = Pool()
|
|
# SaleLine = pool.get('sale.line')
|
|
# Sale = pool.get('sale.sale')
|
|
# lines_to_remove = [line for line in sale.lines]
|
|
# Sale.draft([sale])
|
|
# SaleLine.delete(lines_to_remove)
|
|
|
|
# create_lines = self.get_sale_lines(data, sale)
|
|
# SaleLine.create(create_lines)
|
|
# Sale.quote([sale])
|
|
# if data['fulfillment_status'] == 'fulfilled':
|
|
# self.order_fulfilled(data, [sale])
|
|
# return sale
|
|
|
|
# def order_cancelled(self, data, sales):
|
|
# pool = Pool()
|
|
# Sale = pool.get('sale.sale')
|
|
# sale = sales[0]
|
|
# Sale.draft([sale])
|
|
# Sale.cancel([sale])
|
|
# return sale
|
|
|
|
# def order_fulfilled(self, data, sales):
|
|
# pool = Pool()
|
|
# Sale = pool.get('sale.sale')
|
|
# sale = sales[0]
|
|
# response = False
|
|
# if sale.invoices:
|
|
# return response
|
|
# elif sale.state == 'quotation':
|
|
# Sale.confirm([sale])
|
|
|
|
# if len(sales) > 1:
|
|
# # channel.upload_note(sale, 'Error, al generar factura orden duplicada')
|
|
# return response
|
|
# if data.get('fulfillment_status') == 'fulfilled':
|
|
# track_number = ''
|
|
# try:
|
|
# track_number = str(data['fulfillments'][0]['tracking_number'])
|
|
# except:
|
|
# pass
|
|
# Sale.write([sale], {
|
|
# 'description': sale.description + ' - ' + data['fulfillment_status'],
|
|
# 'comment': 'GUIA DE ENVIO NO. ' + track_number,
|
|
# 'tracking_number': track_number
|
|
# })
|
|
# return sale
|
|
|
|
# @classmethod
|
|
# def get_response(cls, URI, params={}):
|
|
# response = requests.get(URI, headers=HEADERS, params=urlencode(params))
|
|
# return response
|
|
|
|
# @classmethod
|
|
# def verify_webhook_shopify(cls, data, hmac_header, secret):
|
|
# digest = hmac.new(secret.encode('utf-8'), data, hashlib.sha256).digest()
|
|
# genHmac = base64.b64encode(digest)
|
|
# return hmac.compare_digest(genHmac, hmac_header.encode('utf-8'))
|
|
|
|
# @classmethod
|
|
# def request_api(cls, request):
|
|
|
|
# response = {'status': 'error', 'msg': 'Fail in process !!!'}
|
|
# data = request.get_data()
|
|
# action_topic = request.headers.get('X-Shopify-Topic')
|
|
# domain_name = request.headers.get('X-Shopify-Shop-Domain')
|
|
# channels = cls.search([('host_name', '=', domain_name), ])
|
|
# channel = channels[0]
|
|
# hmac_header = request.headers.get('X-Shopify-Hmac-SHA256')
|
|
# verified = cls.verify_webhook_shopify(data, hmac_header, channel.secret_key)
|
|
# if verified:
|
|
# req = data.decode("utf-8")
|
|
# data = json.loads(req)
|
|
# if action_topic.count('create'):
|
|
# res = channel._create_sale(data)
|
|
# if res:
|
|
# response = {'status': 'ok', 'msg': 'Successfull create sale !!!'}
|
|
# else:
|
|
# order_id = data.get('id')
|
|
# Sale = Pool().get('sale.sale')
|
|
# sales = Sale.search([
|
|
# ('reference', '=', str(order_id))
|
|
# ])
|
|
# if not sales:
|
|
# return response
|
|
|
|
# if action_topic.count('fulfilled'):
|
|
# res = channel.order_fulfilled(data, sales)
|
|
# if res:
|
|
# response = {'status': 'ok', 'msg': 'Successfull process sale' + res.number+' in state' + res.state + '!!!' }
|
|
# elif action_topic.count('paid'):
|
|
# pass
|
|
# elif action_topic.count('updated'):
|
|
# res = channel.order_updated(data, sales)
|
|
# if res:
|
|
# response = {'status': 'ok', 'msg': 'Successfull update sale ' + res.number+' in state' + res.state + '!!!' }
|
|
# elif action_topic.count('cancelled'):
|
|
# res = channel.order_cancelled(data, sales)
|
|
# if res:
|
|
# response = {'status': 'ok', 'msg': 'Successfull cancel sale ' + res.number+' in state' + res.state + '!!!' }
|
|
# return response
|
|
|
|
|
|
class Shopify:
|
|
'Shopify'
|
|
|
|
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
|
|
self.freight_product = web_shop.freight_product
|
|
self.invoice_type = web_shop.invoice_type
|
|
|
|
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', '=', 'shopify')
|
|
)
|
|
return user
|
|
|
|
def _create_product(self, codes, line={}):
|
|
pool = Pool()
|
|
Product = pool.get('product.product')
|
|
Template = pool.get('product.template')
|
|
description = line['variant_title']
|
|
list_price = Decimal(str(round(float(line['price'])/1.19, 2)))
|
|
sale_price_w_tax = Decimal(str(round(Decimal(line['price']), 2)))
|
|
create_template = {
|
|
'name': line['title'],
|
|
'list_price': list_price,
|
|
'sale_price_w_tax': sale_price_w_tax,
|
|
'type': 'goods',
|
|
'salable': True,
|
|
'purchasable': True,
|
|
'purchase_uom': 1,
|
|
'sale_uom': 1,
|
|
'default_uom': 1,
|
|
'account_category': 7,
|
|
'code': codes[0],
|
|
}
|
|
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['email']
|
|
shipment_address, phone, city = '', '', None
|
|
if customer.get('default_address'):
|
|
default_address = customer['default_address']
|
|
shipment_address = default_address['address1']
|
|
phone = default_address['phone'] or '000'
|
|
city_name = default_address['city']
|
|
if city_name:
|
|
cities = City.search([
|
|
('name', '=', city_name)
|
|
])
|
|
if cities:
|
|
city = cities[0]
|
|
customer_name = customer['first_name'] + ' ' + customer['last_name']
|
|
create_customer = {
|
|
'id_reference': str(customer['id']),
|
|
'name': customer_name.upper(),
|
|
'type_document': '13',
|
|
'id_number': default_address['company'],
|
|
'addresses': [('create', [{
|
|
'street': shipment_address,
|
|
}])],
|
|
'contact_mechanisms': [
|
|
('create', [
|
|
{'type': 'phone', 'value': phone.replace(" ","")},
|
|
{'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 _create_sale(self, sale_):
|
|
_pool = Pool()
|
|
Sale = _pool.get('sale.sale')
|
|
sales = Sale.search([
|
|
('reference', '=', str(sale_['id']))
|
|
])
|
|
if sales:
|
|
return False
|
|
SaleLine = _pool.get('sale.line')
|
|
Party = _pool.get('party.party')
|
|
User = _pool.get('res.user')
|
|
if sale_.get('customer'):
|
|
customer = sale_['customer']
|
|
dom_party = [('id_number', '=', str(customer['default_address']['company']))]
|
|
parties = Party.search(dom_party)
|
|
if parties:
|
|
party = parties[0]
|
|
else:
|
|
party = self._create_party(customer)
|
|
create_lines = []
|
|
ctx = self._get_context()
|
|
user_ = User(ctx['user'])
|
|
date_created = sale_['created_at'].split('T')
|
|
year, month, day = date_created[0].split('-')
|
|
sale_date = date(int(year), int(month), int(day))
|
|
with Transaction().set_user(ctx['user']):
|
|
comment = ''
|
|
try:
|
|
comment = 'GUIA DE ENVIO NO. ' + sale_['fulfillments'][0].get('tracking_number', '')\
|
|
if sale_['fulfillment_status'] == 'fulfilled' and sale_['fulfillments'] else ''
|
|
except:
|
|
pass
|
|
sale, = Sale.create([{
|
|
'payment_term': 1,
|
|
'party': party.id,
|
|
'sale_date': sale_date,
|
|
'comment': comment,
|
|
'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 SHOPIFY ' + sale_['name'],
|
|
'web_shop': self.id,
|
|
'web_id': str(sale_['id']),
|
|
'invoice_type': self.invoice_type,
|
|
'pack_id': ''
|
|
}])
|
|
|
|
with Transaction().set_context(ctx):
|
|
create_lines = self.get_sale_lines(sale_, sale)
|
|
SaleLine.create(create_lines)
|
|
sale.untaxed_amount_cache = sale.untaxed_amount
|
|
if sale_['cancel_reason'] is not None:
|
|
sale.state = 'cancelled'
|
|
else:
|
|
Sale.quote([sale])
|
|
sale.save()
|
|
if sale_['fulfillment_status'] == 'fulfilled':
|
|
self.order_fulfilled(sale_, [sale])
|
|
print('*******************', sale.state)
|
|
return sale
|
|
|
|
def get_sale_lines(self, sale_, sale, products_refund=[]):
|
|
pool = Pool()
|
|
Product = pool.get('product.product')
|
|
sale_items = sale_['line_items']
|
|
products_refund = {}
|
|
if sale_.get('refunds'):
|
|
for refunds in sale_['refunds']:
|
|
for line_items in refunds['refund_line_items']:
|
|
sku_code = line_items['line_item']['sku']
|
|
quantity = line_items['quantity']
|
|
if sku_code.count('+') > 0:
|
|
codes = sku_code.split('+')
|
|
for code in codes:
|
|
if code not in products_refund.keys():
|
|
products_refund[code] = quantity
|
|
else:
|
|
products_refund[code] += quantity
|
|
else:
|
|
if sku_code not in products_refund.keys():
|
|
products_refund[sku_code] = quantity
|
|
else:
|
|
products_refund[sku_code] += quantity
|
|
create_lines = []
|
|
for line in sale_items:
|
|
if line['title'] == 'Tip':
|
|
if self.tip_product:
|
|
product = self.tip_product
|
|
total_tip = line['price']
|
|
create_lines.append({
|
|
'sale': sale.id,
|
|
'type': 'line',
|
|
'unit': product.default_uom.id,
|
|
'quantity': 1,
|
|
'unit_price': Decimal(total_tip),
|
|
'base_price': Decimal(total_tip),
|
|
'unit_price_full': Decimal(total_tip),
|
|
'product': product.id,
|
|
'description': 'BONIFICACION',
|
|
})
|
|
else:
|
|
sku_code = line['sku']
|
|
if sku_code.count('+') > 0:
|
|
codes = sku_code.split('+')
|
|
line['price'] = round(Decimal(line['price']) / 2, 2)
|
|
discount = round(sum([Decimal(n['amount']) for n in line['discount_allocations']]) / 2, 2)
|
|
else:
|
|
codes = [sku_code]
|
|
discount = round(sum([Decimal(n['amount']) for n in line['discount_allocations']]))
|
|
products = Product.search([
|
|
('code', 'in', codes),
|
|
('active', '=', True)
|
|
])
|
|
description = ''
|
|
if not products:
|
|
products = self._create_product(codes, line)
|
|
for product in products:
|
|
quantity = line['quantity']
|
|
if products_refund and product.code in products_refund.keys():
|
|
if products_refund[product.code] < quantity:
|
|
quantity -= products_refund[product.code]
|
|
else:
|
|
continue
|
|
Tax = pool.get('account.tax')
|
|
un_price = Tax.reverse_compute((Decimal(line['price']) - Decimal(discount)),
|
|
product.customer_taxes_used)
|
|
|
|
create_lines.append({
|
|
'sale': sale.id,
|
|
'type': 'line',
|
|
'unit': product.default_uom.id,
|
|
'quantity': quantity,
|
|
'base_price': round(Decimal(un_price), 3),
|
|
'unit_price': round(Decimal(un_price), 3),
|
|
'unit_price_full': round(Decimal(line['price']),2),
|
|
'product': product.id,
|
|
'taxes': [('add', product.customer_taxes_used)],
|
|
'description': description,
|
|
})
|
|
if self.freight_product and len(sale_['shipping_lines']) > 0:
|
|
product = self.freight_product
|
|
shipping_amount = sale_['shipping_lines'][0]['price']
|
|
create_lines.append({
|
|
'sale': sale.id,
|
|
'type': 'line',
|
|
'unit': product.default_uom.id,
|
|
'quantity': 1,
|
|
'base_price': Decimal(shipping_amount),
|
|
'unit_price': Decimal(shipping_amount),
|
|
'unit_price_full': Decimal(shipping_amount),
|
|
'product': product.id,
|
|
'description': 'FLETE',
|
|
})
|
|
return create_lines
|
|
|
|
def order_updated(self, data, sales):
|
|
sale = sales[0]
|
|
pool = Pool()
|
|
SaleLine = pool.get('sale.line')
|
|
Sale = pool.get('sale.sale')
|
|
lines_to_remove = [line for line in sale.lines]
|
|
Sale.draft([sale])
|
|
SaleLine.delete(lines_to_remove)
|
|
|
|
create_lines = self.get_sale_lines(data, sale)
|
|
SaleLine.create(create_lines)
|
|
Sale.quote([sale])
|
|
if data['fulfillment_status'] == 'fulfilled':
|
|
self.order_fulfilled(data, [sale])
|
|
return sale
|
|
|
|
def order_cancelled(self, data, sales):
|
|
pool = Pool()
|
|
Sale = pool.get('sale.sale')
|
|
sale = sales[0]
|
|
Sale.draft([sale])
|
|
Sale.cancel([sale])
|
|
return sale
|
|
|
|
def order_fulfilled(self, data, sales):
|
|
pool = Pool()
|
|
Sale = pool.get('sale.sale')
|
|
sale = sales[0]
|
|
response = False
|
|
if sale.invoices:
|
|
return response
|
|
elif sale.state == 'quotation':
|
|
Sale.confirm([sale])
|
|
|
|
if len(sales) > 1:
|
|
# channel.upload_note(sale, 'Error, al generar factura orden duplicada')
|
|
return response
|
|
if data.get('fulfillment_status') == 'fulfilled':
|
|
track_number = ''
|
|
try:
|
|
track_number = str(data['fulfillments'][0]['tracking_number'])
|
|
except:
|
|
pass
|
|
Sale.write([sale], {
|
|
'description': sale.description + ' - ' + data['fulfillment_status'],
|
|
'comment': 'GUIA DE ENVIO NO. ' + track_number,
|
|
'tracking_number': track_number
|
|
})
|
|
return sale
|
|
|
|
@classmethod
|
|
def get_response(cls, URI, params={}):
|
|
response = requests.get(URI, headers=HEADERS, params=urlencode(params))
|
|
return response
|
|
|
|
@classmethod
|
|
def verify_webhook_shopify(cls, data, hmac_header, secret):
|
|
digest = hmac.new(secret.encode('utf-8'), data, hashlib.sha256).digest()
|
|
genHmac = base64.b64encode(digest)
|
|
return hmac.compare_digest(genHmac, hmac_header.encode('utf-8'))
|
|
|
|
@classmethod
|
|
def request_api(cls, request):
|
|
|
|
response = {'status': 'error', 'msg': 'Fail in process !!!'}
|
|
data = request.get_data()
|
|
action_topic = request.headers.get('X-Shopify-Topic')
|
|
domain_name = request.headers.get('X-Shopify-Shop-Domain')
|
|
channels = cls.search([('host_name', '=', domain_name), ])
|
|
channel = channels[0]
|
|
hmac_header = request.headers.get('X-Shopify-Hmac-SHA256')
|
|
verified = cls.verify_webhook_shopify(data, hmac_header, channel.secret_key)
|
|
if verified:
|
|
req = data.decode("utf-8")
|
|
data = json.loads(req)
|
|
if action_topic.count('create'):
|
|
res = channel._create_sale(data)
|
|
if res:
|
|
response = {'status': 'ok', 'msg': 'Successfull create sale !!!'}
|
|
else:
|
|
order_id = data.get('id')
|
|
Sale = Pool().get('sale.sale')
|
|
sales = Sale.search([
|
|
('reference', '=', str(order_id))
|
|
])
|
|
if not sales:
|
|
return response
|
|
|
|
if action_topic.count('fulfilled'):
|
|
res = channel.order_fulfilled(data, sales)
|
|
if res:
|
|
response = {'status': 'ok', 'msg': 'Successfull process sale' + res.number+' in state' + res.state + '!!!' }
|
|
elif action_topic.count('paid'):
|
|
pass
|
|
elif action_topic.count('updated'):
|
|
res = channel.order_updated(data, sales)
|
|
if res:
|
|
response = {'status': 'ok', 'msg': 'Successfull update sale ' + res.number+' in state' + res.state + '!!!' }
|
|
elif action_topic.count('cancelled'):
|
|
res = channel.order_cancelled(data, sales)
|
|
if res:
|
|
response = {'status': 'ok', 'msg': 'Successfull cancel sale ' + res.number+' in state' + res.state + '!!!' }
|
|
return response
|