trytonpsk-sale_web_channel/shopify.py

362 lines
14 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
__all__ = ['Shopify']
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__()
cls._error_messages.update({
'product_not_found': ('Product Not Found'),
})
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 = round(float(line['price'])/1.19, 2)
sale_price_w_tax = round(Decimal(line['price']), 2)
print(list_price)
print(sale_price_w_tax)
create_template = {
'name': line['title'],
'list_price': 1,
'sale_price_w_tax': 1,
'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,
'id_reference': '',
'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_):
_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')
Product = _pool.get('product.product')
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)
sale_items = sale_['line_items']
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']):
sale, = Sale.create([{
'payment_term': 1,
'party': party.id,
'sale_date': sale_date,
'comment': 'GUIA DE ENVIO NO. ' + sale_['fulfillments'][0]['tracking_number']
if sale_['fulfillment_status'] == 'fulfilled' else '',
'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'] +' - '+
sale_['fulfillment_status'] if sale_['fulfillment_status'] == 'fulfilled'
else 'VENTA SHOPIFY ' + sale_['name'],
'channel': self.id,
'invoice_type': self.invoice_type,
'pack_id': ''
}])
with Transaction().set_context(ctx):
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),
'unit_price_full': Decimal(total_tip),
'discount': 0,
'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:
Tax = _pool.get('account.tax')
un_price = Tax.reverse_compute((Decimal(line['price']) - discount),
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': round(Decimal(line['price']),2),
'discount': 0,
'product': product.id,
'taxes': [('add', product.customer_taxes_used)],
'description': description,
})
if self.freight_product:
product = self.freight_product
shipping_amount = sale_['shipping_lines'][0]['price']
create_lines.append({
'sale': sale.id,
'type': 'line',
'unit': product.default_uom.id,
'discount': 0,
'quantity': 1,
'unit_price': Decimal(shipping_amount),
'unit_price_full': Decimal(shipping_amount),
'product': product.id,
'description': 'FLETE',
})
SaleLine.create(create_lines)
sale.untaxed_amount_cache = sale.untaxed_amount
if sale_['cancel_reason'] != None:
sale.state = 'cancel'
else:
Sale.quote([sale])
print('*******************', sale.state )
sale.save()
return sale
@classmethod
def get_response(cls, URI, params={}):
response = requests.get(URI, headers=HEADERS, params=urlencode(params))
return response
@classmethod
def _get_channel(cls):
channels = cls.search([
('state', '=', 'active'),
('channel_name', '=', 'shopify'),
])
if channels:
return channels[0]
else:
return None
@classmethod
def request_api(cls, data, header):
response = {'status': 'error', 'msg': 'Fail in process !!!'}
channel = cls._get_channel()
if not channel:
return response
if header.count('create'):
res = channel._create_sale(data)
if res:
response = {'status': 'ok', 'msg': 'Successfull create sale !!!'}
elif header.count('fulfilled'):
cls.order_fulfilled(data)
response = {'status': 'ok', 'msg': 'Successfull process sale !!!'}
elif header.count('paid'):
pass
elif header.count('updated'):
pass
elif header.coun('cancelled'):
cls.order_cancelled(data)
response = {'status': 'ok', 'msg': 'Successfull cancel sale !!!'}
return response
@classmethod
def order_cancelled(cls, data):
order_id = data.get('id')
Sale = Pool().get('sale.sale')
sales = Sale.search([
('reference', '=', str(order_id))
])
if not sales:
return response
Sale.cancel(sales)
@classmethod
def order_fulfilled(cls, data):
order_id = data.get('id')
Sale = Pool().get('sale.sale')
sales = Sale.search([
('reference', '=', str(order_id))
])
if not sales:
return response
sale = sales[0]
if sale.invoices:
return response
else:
Sale.confirm([sales])
if len(sales) > 1:
# channel.upload_note(sale, 'Error, al generar factura orden duplicada')
return response
if data.get('fulfillment_status') == 'fulfilled':
Sale.write([sale], {
'description': sale.description +' - '+ data['fulfillment_status'],
'comment': 'GUIA DE ENVIO NO. ' + data['fulfillments'][0]['tracking_number'],
'tracking_number': data['fulfillments'][0]['tracking_number']
})