diff --git a/l10n_uy_account/data/l10n_latam.document.type.csv b/l10n_uy_account/data/l10n_latam.document.type.csv index 21a21e04..3456d606 100644 --- a/l10n_uy_account/data/l10n_latam.document.type.csv +++ b/l10n_uy_account/data/l10n_latam.document.type.csv @@ -44,3 +44,6 @@ dc_nota_de_crédito_de_e_factura_venta_por_cuenta_ajena_contingencia,242,Nota de dc_nota_de_débito_de_e_factura_venta_por_cuenta_ajena_contingencia,243,Nota de Débito de e-Factura Venta por Cuenta Ajena Contingencia,debit_note,ND e-Fac.Cta.Aj.Cotg,base.uy dc_ e_remito_contingencia,281, e-Remito Contingencia,stock_picking,e-Rem.Cotg,base.uy dc_ e_resguardo_contingencia,282, e-Resguardo Contingencia,,E-Resguardo.Cotg,base.uy +dc_e_boleta_de_entrada,151,e-Boleta de entrada,invoice,e-Boleta-entrada,base.uy +dc_cn_e_boleta_de_entrada,152,Nota de crédito de e-Boleta de entrada,credit_note,NC e-Boleta-entrada,base.uy +dc_dn_e_boleta_de_entrada,153,Nota de débito de e-Boleta de entrada,debit_note,ND e-Boleta-entrada,base.uy diff --git a/l10n_uy_edi/models/l10n_uy_cfe.py b/l10n_uy_edi/models/l10n_uy_cfe.py index 1ea8a169..3f33d5b5 100644 --- a/l10n_uy_edi/models/l10n_uy_cfe.py +++ b/l10n_uy_edi/models/l10n_uy_cfe.py @@ -4,7 +4,7 @@ import base64 import stdnum.uy import re - +import xml.etree.ElementTree as ET from odoo import _, fields, models, api from odoo.exceptions import UserError from odoo.tools.safe_eval import safe_eval @@ -578,59 +578,144 @@ def _l10n_uy_get_cfe_serie(self): }) return res + def xml_to_dict(self, xml_string): + root = ET.fromstring(xml_string) + return self.element_to_dict(root) + + def element_to_dict(self, element): + if len(element) == 0: + return element.text + + result = {} + for child in element: + child_data = self.element_to_dict(child) + key = child.tag.replace('{http://cfe.dgi.gub.uy}', '') + if key in result: + if type(result[key]) is list: + result[key].append(child_data) + else: + result[key] = [result[key], child_data] + else: + result[key] = child_data + + return result + @api.model def l10n_uy_get_ucfe_notif(self): # TODO test it # 600 - Consulta de Notificacion Disponible response = self.env.company._l10n_uy_ucfe_inbox_operation('600') - # import pdb; pdb.set_trace() # If there is notifications if response.Resp.CodRta == '00': # response.Resp.TipoNotificacion # 610 - Solicitud de datos de Notificacion response2 = self.env.company._l10n_uy_ucfe_inbox_operation('610', {'IdReq': response.Resp.IdReq}) + print("-------------response 2---------") + print("----------------------") + print("----------------------") + import pprint + pprint.pprint(response2) + import xml.etree.ElementTree as ET + xml_string = response2.Resp.XmlCfeFirmado + data_dict = self.xml_to_dict(xml_string) + print("----------------------") + print("----------data_dict--------------") + print("----------------------") + import pprint + pprint.pprint(data_dict) + invoice_line_ids = [] + for key, value in data_dict.items(): + if isinstance(value, dict): + if value.get('Encabezado'): + l10n_latam_document_type_id = value['Encabezado']['IdDoc']['TipoCFE'] + invoice_date = datetime.strptime(value['Encabezado']['IdDoc']['FchEmis'], '%Y-%m-%d').date() + l10n_latam_document_number = value['Encabezado']['IdDoc']['Nro'] + currency_id = value['Encabezado']['Totales']['TpoMoneda'] + l10n_uy_cfe_uuid = value['CAEData']['CAE_ID'] + partner_vat_RUC = value['Encabezado']['Emisor']['RUCEmisor'] + partner_id = self.env['res.partner'].search([('commercial_partner_id.vat', '=', partner_vat_RUC)], limit=1) + # Si no existe el partner lo creamos + if not partner_id: + partner_name = value['Encabezado']['Emisor']['RznSoc'] + partner_city = value['Encabezado']['Emisor']['Ciudad'] + partner_state_id = value['Encabezado']['Emisor']['Departamento'] + partner_street = value['Encabezado']['Emisor']['DomFiscal'] + state_id = self.env['res.country.state'].search([('name', 'ilike', partner_state_id)], limit=1) + country_id = state_id.country_id + ruc = self.env.ref('l10n_uy_account.it_rut').id + # + partner_id = self.env['res.partner'].create({'name': partner_name, 'vat': partner_vat_RUC, 'city': partner_city, 'street': partner_street, 'state_id': state_id.id, 'country_id': country_id.id, 'l10n_latam_identification_type_id': ruc, 'is_company': True}) + + invoice_line_ids.append(value['Detalle']['Item']) + line_ids = [] + for value in invoice_line_ids: + line_ids.append((0, 0,{'move_type': 'in_invoice', 'name': value['NomItem'], 'quantity': float(value['Cantidad']), 'price_unit': float(value['PrecioUnitario'])})) + + #line_ids = [(0, 0,{'name': item['Item']['NomItem'], 'quantity': float(item['Item']['Cantidad']), 'price_unit': float(item['Item']['PrecioUnitario'])}) for item in invoice_line_ids] + + if not self.env['account.move'].search([('l10n_uy_cfe_uuid', '=', l10n_uy_cfe_uuid)]): + # Facturas + if l10n_latam_document_type_id in ['101', '111', '181', '182', '121', '124', '131', '141', '151']: + move_type = 'in_invoice' + # Notas de crédito + if l10n_latam_document_type_id in ['102', '112', '122', '132', '142', '152']: + move_type = 'in_refund' + if l10n_latam_document_type_id in ['103', '113', '123', '133', '143', '153']: + move_type = 'in_refund' + document_type = self.env['l10n_latam.document.type'].search([('code', '=', l10n_latam_document_type_id)], limit=1).id + self.env['account.move'].create({'move_type': move_type, 'partner_id': partner_id.id, 'invoice_date': invoice_date, 'l10n_latam_document_type_id': document_type, 'l10n_latam_document_number': l10n_latam_document_number,'l10n_uy_cfe_uuid': l10n_uy_cfe_uuid, 'line_ids': line_ids}).action_post() + #response_parsed = etree.fromstring(response2.Resp.XmlCfeFirmado) - xml_response = response2.Resp.XmlCfeFirmado - root = ET.fromstring(xml_response) - print(xml_response) - print("Tipo de CFE:", root.find(".//{http://cfe.dgi.gub.uy}IdDoc")) + #xml_response = response2.Resp.XmlCfeFirmado + #root = ET.fromstring(xml_response) + #print(xml_response) + #print("Tipo de CFE:", root.find(".//{http://cfe.dgi.gub.uy}IdDoc")) # Es necesario indicar el namespace de la etiqueta - factura = {'TipoCfe': 'l10n_latam_document_type_id'} - partner = {'RUCEmisor': 'partner_id.vat'} - res = {} - for key, value in factura.items(): - res.update({value: root.find(".//{http://cfe.dgi.gub.uy}"+key).text}) + #factura = {'TipoCFE': 'l10n_latam_document_type_id', + # 'FchEmis': 'invoice_date', + # 'Nro': 'l10n_latam_document_number', + # 'TpoMoneda': 'currency_id', + # } + #partner = {'RUCEmisor': 'partner_id.vat', + # 'RznSoc': 'partner_id.name', + # 'DomFiscal': 'partner_id.street', + # 'Ciudad': 'partner_id.city',} + #item = {'NomItem':'name', + # 'Cantidad': 'quantity', + # 'PrecioUnitario': 'price_unit', + # } + #res = {} + #for key, value in factura.items(): + # res.update({value: root.find(".//{http://cfe.dgi.gub.uy}"+key+"/*").text}) # revisar si el ruc emisor existe en odoo - for key, value in partner.items(): - res.update({value: root.find(".//{http://cfe.dgi.gub.uy}"+key).text}) - - root.find(".//{http://cfe.dgi.gub.uy}TmstFirma").text - factura["TmstFirma"] = root.find(".//{http://cfe.dgi.gub.uy}TmstFirma").text - factura["Encabezado"] = {} - factura["Encabezado"]["IdDoc"] = {} - factura["Encabezado"]["Emisor"] = {} - factura["Encabezado"]["Totales"] = {} - factura["Detalle"] = {} - factura["Detalle"]["Item"] = {} - factura["CAEData"] = {} - for child in root.findall('.//{http://cfe.dgi.gub.uy}Item/*'): - factura["Detalle"]["Item"][child.tag.split('}')[1]] = child.text - for child in root.findall('.//{http://cfe.dgi.gub.uy}CAEData/*'): - factura["CAEData"][child.tag.split('}')[1]] = child.text - for child in root.findall('.//{http://cfe.dgi.gub.uy}IdDoc/*'): - factura["Encabezado"]["IdDoc"][child.tag.split('}')[1]] = child.text - for child in root.findall('.//{http://cfe.dgi.gub.uy}Emisor/*'): - factura["Encabezado"]["Emisor"][child.tag.split('}')[1]] = child.text - for child in root.findall('.//{http://cfe.dgi.gub.uy}Totales/*'): - factura["Encabezado"]["Totales"][child.tag.split('}')[1]] = child.text - import pdb - pdb.set_trace() - partner = factura['Encabezado']['Emisor']['RUCEmisor'] - self.env['res.partner'].search([('vat','=',partner)],limit=1) + #for key, value in partner.items(): + # res.update({value: root.find(".//{http://cfe.dgi.gub.uy}"+key).text}) + + #root.find(".//{http://cfe.dgi.gub.uy}TmstFirma").text + #factura["TmstFirma"] = root.find(".//{http://cfe.dgi.gub.uy}TmstFirma").text + #factura["Encabezado"] = {} + #factura["Encabezado"]["IdDoc"] = {} + #factura["Encabezado"]["Emisor"] = {} + #factura["Encabezado"]["Totales"] = {} + #factura["Detalle"] = {} + #factura["Detalle"]["Item"] = {} + #factura["CAEData"] = {} + #for child in root.findall('.//{http://cfe.dgi.gub.uy}Item/*'): + # factura["Detalle"]["Item"][child.tag.split('}')[1]] = child.text + #for child in root.findall('.//{http://cfe.dgi.gub.uy}CAEData/*'): + # factura["CAEData"][child.tag.split('}')[1]] = child.text + #for child in root.findall('.//{http://cfe.dgi.gub.uy}IdDoc/*'): + # factura["Encabezado"]["IdDoc"][child.tag.split('}')[1]] = child.text + #for child in root.findall('.//{http://cfe.dgi.gub.uy}Emisor/*'): + # factura["Encabezado"]["Emisor"][child.tag.split('}')[1]] = child.text + #for child in root.findall('.//{http://cfe.dgi.gub.uy}Totales/*'): + # factura["Encabezado"]["Totales"][child.tag.split('}')[1]] = child.text + #partner = factura['Encabezado']['Emisor']['RUCEmisor'] + #self.env['res.partner'].search([('vat','=',partner)],limit=1) # env['account.move'].create({'partner_id': partner_id, 'invoice_date':date, 'line_ids': [(0,0,{'product_id':31}),(0,0,{'product_id':24}),(0,0,{'product_id':231}),(0,0,{'product_id':234})]})._cr.commit() # ('5', 'Aviso de CFE emitido rechazado por DGI'), or @@ -716,10 +801,15 @@ def l10n_uy_get_ucfe_notif(self): raise UserError(_('ERROR: esto es lo que recibimos %s') % response) # TODO 620 - Descartar Notificacion - # response3 = self.company_id._l10n_uy_ucfe_inbox_operation('620', { - # 'idReq': response.Resp.idReq, 'TipoNotificacion': response.Resp.TipoNotificacion}) - # if response3.Resp.CodRta != '00': - # raise UserError(_('ERROR: la notificacion no pudo descartarse %s') % response) + response3 = self.env.company._l10n_uy_ucfe_inbox_operation('620', { + 'IdReq': response.Resp.IdReq, 'TipoNotificacion': response.Resp.TipoNotificacion}) + print("-------------response 3---------") + print("----------------------") + print("----------------------") + import pprint + pprint.pprint(response3) + if response3.Resp.CodRta != '00': + raise UserError(_('ERROR: la notificacion no pudo descartarse %s') % response) def action_cfe_inform_commercial_status(self, rejection=False): # TODO only applies for vendor bills diff --git a/l10n_uy_edi/models/res_company.py b/l10n_uy_edi/models/res_company.py index c1f437ff..24e669d7 100644 --- a/l10n_uy_edi/models/res_company.py +++ b/l10n_uy_edi/models/res_company.py @@ -118,7 +118,7 @@ def _l10n_uy_ucfe_inbox_operation(self, msg_type, extra_req={}, return_transport """ Call Operation get in msg_type for UCFE inbox webservice """ self.ensure_one() # TODO consumir secuencia creada en Odoo - id_req = 1 + id_req = extra_req.get('IdReq') or 1 now = datetime.utcnow() company = self.sudo() data = {'Req': {'TipoMensaje': msg_type, 'CodComercio': company.l10n_uy_ucfe_commerce_code, @@ -129,7 +129,8 @@ def _l10n_uy_ucfe_inbox_operation(self, msg_type, extra_req={}, return_transport 'Tout': '30000'} if extra_req: data.get('Req').update(extra_req) - + import pprint + pprint.pprint(data) res = company._uy_get_client(company.l10n_uy_ucfe_inbox_url, return_transport=return_transport) client = res[0] if isinstance(res, tuple) else res transport = res[1] if isinstance(res, tuple) else False