# -*- 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 trytond.model import Workflow, ModelView, ModelSQL, fields from trytond.pyson import Eval, And from datetime import datetime, timedelta from trytond.pool import Pool from trytond.wizard import (Wizard, StateTransition, StateView, Button) from trytond.transaction import Transaction from .exceptions import ErrorSynchronizingSale from trytond.i18n import gettext STATES = { 'readonly': (Eval('state') != 'draft') } CHANNELS = [ ('', ''), ('mercadolibre', 'Mercado Libre'), ('rappi', 'Rappi'), ('melhous', 'Melhous'), ('ifood', 'IFood'), ('shopify', 'Shopify'), ('socialnetwork', 'Social Network'), ('direct', 'Direct'), ('pageweb', 'Page Web'), ('internal', 'Internal'), ('platform', 'Platform'), ('telephone', 'Telephone'), ] TYPE_INVOICE = [ ('', ''), ('C', 'Computador'), ('P', 'POS'), ('M', 'Manual'), ('1', 'Venta Electronica'), ('2', 'Exportacion'), ('3', 'Factura por Contingencia Facturador'), ('4', 'Factura por Contingencia DIAN'), ('91', 'Nota Crédito Eléctronica'), ('92', 'Nota Débito Eléctronica'), ] ORDERS_CREATED = 0 class SaleWebChannel(Workflow, ModelSQL, ModelView): 'Web Channel' __name__ = 'sale.web_channel' _rec_name = 'name' name = fields.Char('Name Channel') channel_name = fields.Selection(CHANNELS, 'Channel', select=True, required=True, states=STATES) company = fields.Many2One('company.company', 'Company', required=True, states=STATES) shop = fields.Many2One('sale.shop', 'Shop', domain=[ ('company', '=', Eval('company')) ], states=STATES) user = fields.Many2One('res.user', 'User', domain=[ ('company', '=', Eval('company')) ], states=STATES) secret_key = fields.Char('Secret Key') app_id = fields.Char('Application ID') redirect_uri = fields.Char('Redirect URI', states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), }) authorization_code = fields.Char('Authorization Code', states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), }) access_token = fields.Char('Access Token', states={ 'invisible': And( Eval('channel_name') != 'mercadolibre', Eval('channel_name') != 'rappi'), }) creation_time = fields.DateTime('Creation Time', states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), }) status_token = fields.Function(fields.Selection([ ('expired', 'Expired'), ('active', 'Active'), ], 'Status Token', readonly=True, states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), }), 'get_status_token') refresh_token = fields.Char('Refresh Token', states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), }) state = fields.Selection([ ('draft', 'Draft'), ('active', 'Active'), ('finished', 'Finished'), ], 'State', select=True, readonly=True) freight_product = fields.Many2One('product.product', 'Freight Product', states=STATES) bonus_product = fields.Many2One('product.product', 'Bonus Product', states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), 'readonly': (Eval('state') != 'draft') }) tip_product = fields.Many2One('product.product', 'Tip Product', states={ 'invisible': (Eval('channel_name') != 'shopify'), 'readonly': (Eval('state') != 'draft') }) generic_product = fields.Many2One('product.product', 'Generic Product', states={ # 'invisible': (Eval('channel_name') != 'shopify'), 'readonly': (Eval('state') != 'draft') }) report = fields.Many2One('ir.action.report', 'Report', states=STATES) invoice_type = fields.Selection(TYPE_INVOICE, 'Type Invoice', states=STATES) seller_id = fields.Char('Seller ID', states={ 'invisible': ~Eval('channel_name').in_(['mercadolibre', 'rappi']), 'readonly': (Eval('state') != 'draft') }) # admin_category = fields.Many2One('product.category', 'Admin Category', # domain=[ # ('accounting', '=', False), # ]) price_list = fields.Many2One('product.price_list', 'Pricelist', ondelete="RESTRICT") template_notification = fields.Many2One( 'email.template', 'Template Notification') api_key = fields.Char('Api Key', states={ 'invisible': (Eval('channel_name') != 'shopify'), }) password_api = fields.Char('Api Password', states={ 'invisible': (Eval('channel_name') != 'shopify'), }) host_name = fields.Char('Host Name', states={ 'invisible': And( Eval('channel_name') != 'shopify', Eval('channel_name') != 'rappi'), }) party = fields.Many2One('party.party', 'party', required=False) payment_term = fields.Many2One('account.invoice.payment_term', 'Payment Term') @classmethod def __setup__(cls): super(SaleWebChannel, cls).__setup__() cls._transitions |= set(( ('draft', 'active'), ('active', 'draft'), ('active', 'finished'), ('finished', 'active'), )) cls._buttons.update({ 'draft': { 'invisible': Eval('state') != 'active', }, 'active': { 'invisible': Eval('state') == 'active', }, 'finished': { 'invisible': Eval('state') != 'active', }, 'refresh_token_b': { 'invisible': And(Eval('channel_name') != 'mercadolibre', Eval('channel_name') != 'rappi'), }, 'synchronize_menu': { 'invisible': And(Eval('channel_name') != 'rappi', Eval('state') == 'active'), }, }) @staticmethod def default_company(): return Transaction().context.get('company') # @classmethod # def import_data(cls, fields_names, data): # return 0 @staticmethod def default_state(): return 'draft' @classmethod @ModelView.button @Workflow.transition('draft') def draft(cls, records): pass @classmethod @ModelView.button @Workflow.transition('active') def active(cls, records): pass @classmethod @ModelView.button @Workflow.transition('finished') def finished(cls, records): pass @classmethod @ModelView.button def synchronize_menu(cls, records): for record in records: if record.channel_name == 'rappi': record.synchronize_menu_rappi() @classmethod @ModelView.button def refresh_token_b(cls, records): if records: for record in records: if record.channel_name == 'mercadolibre': MercadoLibre = Pool().get('sale.web_channel.mercado_libre') channels = MercadoLibre.search([ ('state', '=', 'active'), ('channel_name', '=', 'mercadolibre'), ]) res = channels[0]._validate_token() if record.channel_name == 'rappi': Rappi = Pool().get('sale.web_channel.rappi') channels = Rappi.search([ ('state', '=', 'active'), ('channel_name', '=', 'rappi'), ]) res = channels[0].generate_token_access() print(res, 'fuck yeah!') def send_mail_notification(self, message): Template = Pool().get('email.template') setattr(self, 'message', message) response = Template.send(self.template_notification, self) def get_status_token(self, name): if self.creation_time: now = datetime.now() res = (now - self.creation_time).total_seconds() if res >= 21600: return 'expired' else: return 'active' else: return 'expired' @classmethod def request_api(cls, data): return {} def render_report(self, record): if not self.report: return None Report = Pool().get(self.report.report_name, type='report') report = Report.execute([record.id], {'id': record.id}) ext, data, filename, file_name = report return data 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('sale.web_channel', 'Channel', required=True, domain=[ ('shop', '=', Eval('shop')) ]) operation = fields.Selection([ ('', ''), ('orders_for_day', 'Orders for day'), ('especific_order', 'Especific Orders') ], 'Operation', required=True) name_channel = 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.name_channel = self.channel.channel_name 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.channel_name == 'mercadolibre': MercadoLibre = pool.get('sale.web_channel.mercado_libre') channel = MercadoLibre(channel) if operation == 'especific_order': order_id = self.start.order_id URI = 'https://api.mercadolibre.com/orders/%s?access_token=%s' % ( order_id, channel.access_token) result = MercadoLibre.get_response(URI).json() if not result: raise ErrorSynchronizingSale( gettext('sale_web_channel.msg_error_synchronizing_sale', s=result)) print(result) sale_created = channel.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.channel_name == '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 FinishInvoicesStart(ModelView): 'Finish Invoices Start' __name__ = 'sale_web_channel.finish_invoices.start' company = fields.Many2One('company.company', 'Company', required=True) shop = fields.Many2One('sale.shop', 'Shop', required=True, domain=[ ('company', '=', Eval('company')) ]) channel = fields.Many2One('sale.web_channel', 'Channel', required=True, domain=[ ('shop', '=', Eval('shop')) ]) date = fields.Date('Date', required=True) @staticmethod def default_company(): return Transaction().context.get('company') class FinishInvoices(Wizard): 'Finish Invoices' __name__ = 'sale_web_channel.finish_invoices' start = StateView('sale_web_channel.finish_invoices.start', 'sale_web_channel.finish_invoices_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(FinishInvoices, cls).__setup__() def transition_accept(self): pool = Pool() Invoice = pool.get('account.invoice') Shopify = pool.get('sale.web_channel.shopify') MercadoLibre = pool.get('sale.web_channel.mercado_libre') if self.start.channel == 'mercadolibre': channel = MercadoLibre(self.start.channel) if self.start.channel == 'shopify': channel = Shopify(self.start.channel) date = self.start.date invoices = Invoice.search([ ('state', '=', 'draft'), ('invoice_date', '=', date), ]) for inv in invoices: if not inv.sales: continue sale = inv.sales[0] channel_id = sale.channel.id if channel_id != channel.id: continue Invoice.validate_invoice([inv]) if inv.invoice_type not in ('C', 'P', 'M') and inv.electronic_state != 'authorized': Invoice.submit([inv]) if not inv.cufe: return Invoice.post([inv]) if self.start.channel == 'mercadolibre': channel.upload_note(sale, 'Factura generada') channel.upload_invoice(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' class SynchronizeMenuWizard(Wizard): 'Synchronize Menu' __name__ = 'sale_web_channel.synchronize_menu' start_state = 'synchronize_menu' synchronize_menu = StateTransition() @classmethod def transition_synchronize_menu(self): pool = Pool() active_id = Transaction().context.get('active_id') Chanel = pool.get('sale.web_channel') chanel = Chanel(active_id) print(chanel) if chanel.channel_name == 'rappi': print('ya paso') Rappi = Pool().get('sale.web_channel.rappi') channels = Rappi.search([ ('state', '=', 'active'), ('channel_name', '=', 'rappi'), ]) res = channels[0].synchronize_menu_rappi() print(res, 'fuck yeah') return 'end'