diff --git a/mercado_libre.py b/mercado_libre.py index 602b24b..59c9a0c 100644 --- a/mercado_libre.py +++ b/mercado_libre.py @@ -12,6 +12,7 @@ from web_channel import SaleWebChannel import json from .exceptions import NotProductFoundError, NotProductFound from trytond.i18n import gettext +from trytond.exceptions import UserError HEADERS = { 'Accept': 'application/json', @@ -181,72 +182,19 @@ class MercadoLibre(SaleWebChannel): dev_sales.append(return_sale) return dev_sales - def _create_sale(self, sale_): + def process_pack(self, sales): + for sale in sales: + sale.state = 'confirmed' + sale.save() + + def create_lines_sale(self, sale, sale_, freight=False): _pool = Pool() - Sale = _pool.get('sale.sale') - sales = Sale.search([ - ('reference', '=', str(sale_['id'])) - ]) - # print(sales[0].number) - - 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 SaleLine = _pool.get('sale.line') - Party = _pool.get('party.party') Product = _pool.get('product.product') - User = _pool.get('res.user') - sfm_id = sale_['shipping']['id'] - shipment_ = self.get_shipment_api(sfm_id) - if sale_.get('buyer'): - 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'][dic.values()[0].lower()] = dic.values()[1] - customer['billing_info']['additional_info'].pop() - party = self._create_party(customer) - sale_items = sale_['order_items'] create_lines = [] + sale_items = sale_['order_items'] 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 '', - }]) - + sfm_id = sale_['shipping']['id'] with Transaction().set_context(ctx): for line in sale_items: item = line['item'] @@ -256,9 +204,11 @@ class MercadoLibre(SaleWebChannel): generic = False if sku_code.count('+') > 0: codes = sku_code.split('+') - line['unit_price'] = Decimal(round((line['unit_price'] / 2), 2)) + line['unit_price'] = Decimal( + round((line['unit_price'] / 2), 2)) else: codes = [sku_code] + products = Product.search([ ('code', 'in', codes), ('active', '=', True) @@ -290,9 +240,10 @@ class MercadoLibre(SaleWebChannel): 'taxes': [('add', product.customer_taxes_used)], 'description': description, }) - if self.freight_product: + 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) + 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({ @@ -306,12 +257,97 @@ class MercadoLibre(SaleWebChannel): 'description': 'FLETE', }) SaleLine.create(create_lines) + return generic + + def _create_sale(self, sale_): + _pool = Pool() + Sale = _pool.get('sale.sale') + + if sale_.get('pack_id'): + sales = self.search([ + ('pack_id', '=', sale_['pack_id']) + ]) + if sales: + self.create_lines_sale( + sales[0], sale_, freight=False) + return False + sales = Sale.search([ + ('reference', '=', str(sale_['id'])) + ]) + + 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'): + 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'][dic.values()[0].lower() + ] = 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' + elif sale_.get('pack_id'): + with Transaction().set_context( + queue_name='process_pack_id', + queue_scheduled_at=10): + self.__class__.__queue__.process_pack([sale]) else: Sale.quote([sale]) - if generic: + if not generic: sale.state = 'confirmed' sale.save() # if shipment_['status'] in ['shipped', 'delivered']: @@ -417,7 +453,8 @@ class MercadoLibre(SaleWebChannel): return response if len(sales) > 1: - channel.upload_note(sale, 'Error, al generar factura orden duplicada') + channel.upload_note( + sale, 'Error, al generar factura orden duplicada') return response if shipment_.get('tracking_number'): @@ -500,4 +537,5 @@ class MercadoLibre(SaleWebChannel): 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) + self.send_mail_notification( + 'error al crear nota en orden ' + sale.reference) diff --git a/message.xml b/message.xml index 0ac8fa3..7508c2c 100644 --- a/message.xml +++ b/message.xml @@ -9,5 +9,8 @@ this repository contains the full copyright notices and license terms. --> Product Generic Not Found, Verify in Configuration + + Error: "(msg)s" + diff --git a/tryton.cfg b/tryton.cfg index 070d0f3..2d4c18c 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -1,5 +1,5 @@ [tryton] -version=6.0.0 +version=6.0.1 depends: sale_pos product_reference diff --git a/web_channel.py b/web_channel.py index 4ae021f..57243d4 100644 --- a/web_channel.py +++ b/web_channel.py @@ -52,9 +52,9 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView): _rec_name = 'name' name = fields.Char('Name Channel') channel_name = fields.Selection(CHANNELS, - 'Channel', select=True, required=True, states=STATES) + 'Channel', select=True, required=True, states=STATES) company = fields.Many2One('company.company', 'Company', required=True, - states=STATES) + states=STATES) shop = fields.Many2One('sale.shop', 'Shop', domain=[ ('company', '=', Eval('company')) ], states=STATES) @@ -90,7 +90,7 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView): ('finished', 'Finished'), ], 'State', select=True, readonly=True) freight_product = fields.Many2One('product.product', 'Freight Product', - states=STATES) + states=STATES) bonus_product = fields.Many2One('product.product', 'Bonus Product', states={ 'invisible': (Eval('channel_name') != 'mercadolibre'), 'readonly': (Eval('state') != 'draft') @@ -111,7 +111,8 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView): 'invisible': (Eval('channel_name') != 'mercadolibre'), 'readonly': (Eval('state') != 'draft') }) - template_notification = fields.Many2One('email.template', 'Template Notification') + template_notification = fields.Many2One( + 'email.template', 'Template Notification') api_key = fields.Char('Api Key', states={ 'invisible': (Eval('channel_name') != 'shopify'), }) @@ -123,7 +124,7 @@ class SaleWebChannel(Workflow, ModelSQL, ModelView): }) party = fields.Many2One('party.party', 'party', required=False) payment_term = fields.Many2One('account.invoice.payment_term', - 'Payment Term') + 'Payment Term') @classmethod def __setup__(cls): @@ -229,9 +230,9 @@ class SynchronizeChannelOrdersStart(ModelView): ('company', '=', Eval('company')) ]) channel = fields.Many2One('sale.web_channel', 'Channel', required=True, - domain=[ - ('shop', '=', Eval('shop')) - ]) + domain=[ + ('shop', '=', Eval('shop')) + ]) operation = fields.Selection([ ('', ''), ('orders_for_day', 'Orders for day'), @@ -268,15 +269,16 @@ 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), - ]) + '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), - ]) + 'sale_web_channel.synchronize_orders_done', [ + Button('Done', 'end', 'tryton-ok', default=True), + ]) @classmethod def __setup__(cls): @@ -300,17 +302,20 @@ class SynchronizeChannelOrders(Wizard): raise ErrorSynchronizingSale( gettext('sale_web_channel.msg_error_synchronizing_sale', s=result)) sale_created = channel._create_sale(result) - 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 sale_created and line.product.code == generic_code and generic_code] - if sale_created and \ - not sale_created.pack_id and \ - sale_created.comment in ['shipped', 'delivered'] and \ - len(product_generic) < 1: - Sale.process([sale_created]) + 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) + 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']: @@ -344,7 +349,7 @@ class SynchronizeChannelOrders(Wizard): 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_created.description.count('fulfilled'): Sale.process([sale_created]) else: date_from = str(self.start.date) + 'T00:00:00.000-00:00' @@ -394,15 +399,16 @@ 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), - ]) + '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), - ]) + 'sale_web_channel.synchronize_orders_done', [ + Button('Done', 'end', 'tryton-ok', default=True), + ]) @classmethod def __setup__(cls):