From 6fd8f9e2ea32e0ca4cf07f9c6709e97b91a0cb87 Mon Sep 17 00:00:00 2001 From: El Mau Date: Sun, 14 Jan 2024 22:42:26 -0600 Subject: [PATCH] Add UI for CE --- source/app/controllers/cfdi_xml.py | 36 ++-- source/app/controllers/utils.py | 3 - source/app/models/main.py | 1 - source/static/js/controller/invoices.js | 44 +++- source/static/js/ui/invoices.js | 257 +++++++++++++++++++++++- source/xslt/cadena.xslt | 2 +- source/xslt/comercioexterior20.xslt | 171 ++++++++++++++++ 7 files changed, 485 insertions(+), 29 deletions(-) create mode 100644 source/xslt/comercioexterior20.xslt diff --git a/source/app/controllers/cfdi_xml.py b/source/app/controllers/cfdi_xml.py index d66a39d..cdd2541 100644 --- a/source/app/controllers/cfdi_xml.py +++ b/source/app/controllers/cfdi_xml.py @@ -117,10 +117,10 @@ SAT = { 'schema': ' http://www.sat.gob.mx/CartaPorte20 http://www.sat.gob.mx/sitio_internet/cfd/CartaPorte/CartaPorte20.xsd', }, 'comercioe': { - 'version': '1.1', - 'prefix': 'cce11', - 'xmlns': 'http://www.sat.gob.mx/ComercioExterior11', - 'schema': ' http://www.sat.gob.mx/ComercioExterior11 http://www.sat.gob.mx/sitio_internet/cfd/ComercioExterior11/ComercioExterior11.xsd', + 'version': '2.0', + 'prefix': 'cce20', + 'xmlns': 'http://www.sat.gob.mx/ComercioExterior20', + 'schema': ' http://www.sat.gob.mx/ComercioExterior20 http://www.sat.gob.mx/sitio_internet/cfd/ComercioExterior20/ComercioExterior20.xsd', } } @@ -144,6 +144,7 @@ class CFDI(object): self._comercio_exterior = False self._divisas = '' self._tipo_de_comprobante = '' + self._exportacion = DEFAULT['exportacion'] self.error = '' def _now(self): @@ -198,6 +199,8 @@ class CFDI(object): self._leyendas = bool(datos['complementos'].get('leyendas', False)) self._carta_porte = bool(datos['complementos'].get('cartaporte', False)) self._comercio_exterior = bool(datos['complementos'].get('comercioe', False)) + if self._comercio_exterior: + self._exportacion = datos['complementos']['comercioe'].pop('Exportacion') self._divisas = datos['comprobante'].pop('divisas', '') @@ -288,7 +291,7 @@ class CFDI(object): # ~ cfdi4 if not 'Exportacion' in attributes: - attributes['Exportacion'] = DEFAULT['exportacion'] + attributes['Exportacion'] = self._exportacion self._tipo_de_comprobante = attributes['TipoDeComprobante'] @@ -644,16 +647,9 @@ class CFDI(object): emisor = datos.pop('emisor') # ~ propietario = datos.pop('propietario') receptor = datos.pop('receptor') - destinatario = datos.pop('destinatario') + # ~ destinatario = datos.pop('destinatario') conceptos = datos.pop('mercancias') - # ~ attributes = {} - # ~ attributes['xmlns:{}'.format(pre)] = \ - # ~ 'http://www.sat.gob.mx/ComercioExterior11' - # ~ attributes['xsi:schemaLocation'] = \ - # ~ 'http://www.sat.gob.mx/ComercioExterior11 ' \ - # ~ 'http://www.sat.gob.mx/sitio_internet/cfd/ComercioExterior11/ComercioExterior11.xsd' - attr = {'Version': SAT['comercioe']['version']} attr.update(datos) ce = ET.SubElement( @@ -674,13 +670,13 @@ class CFDI(object): node = ET.SubElement(ce, '{}:Receptor'.format(prefix), attributes) ET.SubElement(node, '{}:Domicilio'.format(prefix), receptor) - attributes = {} - if 'NumRegIdTrib' in destinatario: - attributes = {'NumRegIdTrib': destinatario.pop('NumRegIdTrib')} - if 'Nombre' in destinatario: - attributes.update({'Nombre': destinatario.pop('Nombre')}) - node = ET.SubElement(ce, '{}:Destinatario'.format(prefix), attributes) - ET.SubElement(node, '{}:Domicilio'.format(prefix), destinatario) + # ~ attributes = {} + # ~ if 'NumRegIdTrib' in destinatario: + # ~ attributes = {'NumRegIdTrib': destinatario.pop('NumRegIdTrib')} + # ~ if 'Nombre' in destinatario: + # ~ attributes.update({'Nombre': destinatario.pop('Nombre')}) + # ~ node = ET.SubElement(ce, '{}:Destinatario'.format(prefix), attributes) + # ~ ET.SubElement(node, '{}:Domicilio'.format(prefix), destinatario) node = ET.SubElement(ce, '{}:Mercancias'.format(prefix)) fields = ('Marca', 'Modelo', 'SubModelo', 'NumeroSerie') diff --git a/source/app/controllers/utils.py b/source/app/controllers/utils.py index 00dd02e..d225b4a 100644 --- a/source/app/controllers/utils.py +++ b/source/app/controllers/utils.py @@ -861,9 +861,6 @@ def get_cert(args): def make_xml(data, certificado): cert = SATCertificate(certificado.cer, certificado.key_enc.encode()) - # ~ if DEBUG: - # ~ data['emisor']['Rfc'] = certificado.rfc - # ~ data['emisor']['RegimenFiscal'] = '603' cfdi = CFDI() xml = ET.parse(BytesIO(cfdi.get_xml(data).encode())) diff --git a/source/app/models/main.py b/source/app/models/main.py index 936b765..539f0fe 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -5616,7 +5616,6 @@ class Facturas(BaseModel): data = { 'factura': invoice, 'nombre': 'comercioe', - # ~ 'valores': utils.dumps(values), 'valores': valores, } FacturasComplementos.create(**data) diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index c3943a9..0cf68bd 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -102,7 +102,14 @@ var invoices_controllers = { $$('cmd_carta_add_product').attachEvent('onItemClick', cmd_carta_add_product_click) $$('cmd_carta_copy_from_invoice').attachEvent('onItemClick', cmd_carta_copy_from_invoice_click) $$('cmd_carta_import_json').attachEvent('onItemClick', cmd_carta_import_json_click) + $$('cmd_import_json_comercioe').attachEvent('onItemClick', cmd_import_json_comercioe_click) + $$('cmd_ce_tipo_cambio').attachEvent('onItemClick', cmd_ce_tipo_cambio_click) + $$('cmd_ce_add_propietario').attachEvent('onItemClick', cmd_ce_add_propietario_click) + $$('cmd_ce_add_mercancia').attachEvent('onItemClick', cmd_ce_add_mercancia_click) + $$('grid_ce_propietarios').attachEvent('onItemClick', grid_ce_propietarios_click) + $$('grid_ce_mercancias').attachEvent('onItemClick', grid_ce_mercancias_click) + $$('cmd_show_global_information').attachEvent('onItemClick', cmd_show_global_information_click) webix.extend($$('grid_invoices'), webix.ProgressBar) @@ -907,11 +914,11 @@ function cmd_timbrar_click(id, e, node){ usar_ine = $$('chk_cfdi_usar_ine').getValue() if(usar_ine){ - msg += 'Estas usando el complemento INE

' + msg += 'Estas usando el complemento: INE

' } if($$('chk_cfdi_usar_comercioe').getValue()){ - msg += 'Estas usando el complemento Comercio Exterior

' + msg += 'Estas usando el complemento:
Comercio Exterior

' if(values_comercioe === null){ msg = 'El complemento de Comercio Exterior esta vacío' msg_error(msg) @@ -3000,3 +3007,36 @@ function cmd_save_global_information_click(){ function cmd_win_global_close_click(){ $$('win_global_information').close() } + + +function cmd_ce_tipo_cambio_click(){ + window.open('https://www.banxico.org.mx/tipcamb/llenarTiposCambioAction.do?idioma=sp', '_blank') +} + + +function cmd_ce_add_propietario_click(){ + var g = $$('grid_ce_propietarios') + g.add({delete: '-'}) +} + + +function grid_ce_propietarios_click(id, e, node){ + if(id.column != 'delete'){ + return + } + this.remove(id.row) +} + + +function cmd_ce_add_mercancia_click(){ + var g = $$('grid_ce_mercancias') + g.add({delete: '-'}) +} + + +function grid_ce_mercancias_click(id, e, node){ + if(id.column != 'delete'){ + return + } + this.remove(id.row) +} diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js index 2ad6da8..88942fa 100644 --- a/source/static/js/ui/invoices.js +++ b/source/static/js/ui/invoices.js @@ -1210,13 +1210,266 @@ var controls_carta_porte = [ ] +var opt_ce_exportacion = [ + {id: '02', value: '[02] Definitiva con clave A1'}, + {id: '03', value: '[03] Temporal'}, + {id: '04', value: '[04] Definitiva con clave distinta a A1'}, +] + + +var opt_ce_motivo_traslado = [ + {id: '', value: ''}, + {id: '01', value: '[01] Envío de mercancias facturadas con anterioridad'}, + {id: '02', value: '[02] Reubicación de mercancías propias'}, + {id: '03', value: '[03] Envío de mercancías objeto de contrato de consignación'}, + {id: '04', value: '[04] Envío de mercancías para posterior enajenación'}, + {id: '05', value: '[05] Envío de mercancías propiedad de terceros'}, + {id: '99', value: '[99] Otros'}, +] + + +var opt_ce_clave_pedimento = [ + {id: 'A1', value: '[A1] Definitiva'}, +] + + +var opt_ce_certificado_origen = [ + {id: '0', value: '[0] No funge'}, + {id: '1', value: '[1] Funge'}, +] + + +var opt_ce_incoterm = [ + {id: 'CFR', value: '[CFR] Coste y flete (puerto de destino convenido)'}, + {id: 'CIF', value: '[CIF] Coste, seguro y flete (puerto de destino convenido)'}, + {id: 'CPT', value: '[CPT] Trasnporte pagado hasta el lugar de destino convenido'}, + {id: 'CIP', value: '[CIP] Trasnporte y seguro pagado hasta el lugar de destino convenido'}, + {id: 'DAP', value: '[DAP] Entregada en lugar'}, + {id: 'DDP', value: '[DDP] Entregada derechos pagados en lugar de destino convenido'}, + {id: 'DPU', value: '[DPU] Entregada y descargada en lugar acordado'}, + {id: 'EXW', value: '[EXW] En fábrica (lugar convenido)'}, + {id: 'FCA', value: '[FCA] Franco transportista (lugar designado)'}, + {id: 'FAS', value: '[FAS] Franco al costado del buque (puerto de carga convenido)'}, + {id: 'FOB', value: '[FOB] Franco a bordo (puerto de carga convenido)'}, +] + + +var body_ce_datos_generales = {rows:[ + {cols: [{maxWidth: 15}, + {view: 'richselect', id: 'lst_ce_exportacion', label: 'Exportación: ', + value: '02', labelWidth: 130, minWidth: 400, options: opt_ce_exportacion}, + {view: 'richselect', id: 'lst_ce_motivo_traslado', label: 'Motivo Traslado: ', + labelWidth: 130, minWidth: 500, options: opt_ce_motivo_traslado}, + {}, + {maxWidth: 15}]}, + {cols: [{maxWidth: 15}, + {view: 'richselect', id: 'lst_ce_clave_pedimento', label: 'Clave de Pedimento: ', + value: 'A1', labelWidth: 130, minWidth: 400, maxWidth: 400, options: opt_ce_clave_pedimento}, + {view: 'richselect', id: 'lst_ce_certificado_origen', label: 'Certificado Origen: ', + value: '0', labelWidth: 130, maxWidth: 300, options: opt_ce_certificado_origen}, + {view: 'text', id: 'txt_ce_numero_certificado', label: 'Nº Certificado:', labelWidth: 100}, + {maxWidth: 15}]}, + {cols: [{maxWidth: 15}, + {view: 'text', id: 'txt_ce_numero_exportador', label: 'Nº Exportador: ', + labelWidth: 130, minWidth: 400, maxWidth: 500}, + {view: 'richselect', id: 'lst_ce_incoterm', label: 'Incoterm: ', value: 'CFR', + labelWidth: 130, minWidth: 500, maxWidth: 500, options: opt_ce_incoterm}, + {view: 'text', id: 'txt_ce_observaciones', label: 'Observaciones:', labelWidth: 100}, + {maxWidth: 15}]}, + {cols: [{maxWidth: 15}, + {view: 'text', id: 'txt_ce_total_usd', label: 'Total USD: ', + labelWidth: 130, minWidth: 400, inputAlign: 'right'}, + {view: 'text', id: 'txt_ce_tipo_cambio_usd', label: 'Tipo Cambio USD:', labelWidth: 130, + inputAlign: 'right'}, + {}, + {view: 'button', id: 'cmd_ce_tipo_cambio', label: 'TC Banxico', + type: 'iconButton', autowidth: true, icon: ''}, + {maxWidth: 15}]}, +]} + + +var grid_cols_ce_emisor = [ + {id: 'id', header: 'ID', hidden: true}, + {id: 'Curp', header: 'Curp', editor: 'text', fillspace: 1}, + {id: 'Calle', header: 'Calle *', editor: 'text', fillspace: 1}, + {id: 'NumeroExterior', header: 'Numero Exterior', editor: 'text', fillspace: 1}, + {id: 'NumeroInterior', header: 'Número Interior', editor: 'text', fillspace: 1}, + {id: 'Colonia', header: 'Colonia', editor: 'text', fillspace: 1}, + {id: 'Municipio', header: 'Municipio', editor: 'text', fillspace: 1}, + {id: 'Estado', header: 'Estado *', editor: 'text', fillspace: 1}, + {id: 'Pais', header: 'País *', editor: 'text', fillspace: 1}, + {id: 'CodigoPostal', header: 'C.P. *', editor: 'text', fillspace: 1}, +] + + +var grid_ce_emisor = { + view: 'datatable', + id: 'grid_ce_emisor', + multiselect: false, + adjust: true, + autoheight: true, + headermenu: true, + editable: true, + columns: grid_cols_ce_emisor, + data: [{id: 0}], +} + +var body_ce_emisor = {rows:[ + grid_ce_emisor +]} + + +var grid_cols_ce_propietarios = [ + {id: 'id', header: 'ID', hidden: true}, + {id: 'delete', header: '', width: 30, css: 'delete'}, + {id: 'NumRegIdTrib', header: 'Registro Fiscal', editor: 'text', fillspace: 1}, + {id: 'ResidenciaFiscal', header: 'Residencia Fiscal', editor: 'text', fillspace: 1}, +] + + +var grid_ce_propietarios = { + view: 'datatable', + id: 'grid_ce_propietarios', + multiselect: false, + adjust: true, + autoheight: true, + headermenu: true, + editable: true, + footer: false, + columns: grid_cols_ce_propietarios, +} + + +var body_ce_propietarios = {rows:[ + {cols: [ + {view: 'button', id: 'cmd_ce_add_propietario', label: 'Agregar Propietario', + icon: 'plus', type: 'iconButton', autowidth: true, align: 'center'}, + {}, + ]}, + {maxHeight: 10}, + grid_ce_propietarios +]} + + +var grid_cols_ce_receptor = [ + {id: 'id', header: 'ID', hidden: true}, + {id: 'NumRegIdTrib', header: 'Registro Fiscal', editor: 'text', fillspace: 1}, + {id: 'Calle', header: 'Calle *', editor: 'text', fillspace: 1}, + {id: 'NumeroExterior', header: 'Numero Exterior', editor: 'text', fillspace: 1}, + {id: 'NumeroInterior', header: 'Número Interior', editor: 'text', fillspace: 1}, + {id: 'Colonia', header: 'Colonia', editor: 'text', fillspace: 1}, + {id: 'Municipio', header: 'Municipio', editor: 'text', fillspace: 1}, + {id: 'Estado', header: 'Estado *', editor: 'text', fillspace: 1}, + {id: 'Pais', header: 'País *', editor: 'text', fillspace: 1}, + {id: 'CodigoPostal', header: 'C.P. *', editor: 'text', fillspace: 1}, +] + + +var grid_ce_receptor = { + view: 'datatable', + id: 'grid_ce_receptor', + multiselect: false, + adjust: true, + autoheight: true, + headermenu: true, + editable: true, + columns: grid_cols_ce_receptor, + data: [{id: 0}], +} + + +var body_ce_receptor = {rows:[ + grid_ce_receptor +]} + + +var grid_cols_ce_destinatario = [ + {id: 'id', header: 'ID', hidden: true}, + {id: 'NumRegIdTrib', header: 'Registro Fiscal', editor: 'text', fillspace: 1}, + {id: 'Nombre', header: 'Nombre', editor: 'text', fillspace: 1}, + {id: 'Calle', header: 'Calle *', editor: 'text', fillspace: 1}, + {id: 'NumeroExterior', header: 'No Exterior', editor: 'text', fillspace: 1}, + {id: 'NumeroInterior', header: 'No Interior', editor: 'text', fillspace: 1}, + {id: 'Colonia', header: 'Colonia', editor: 'text', fillspace: 1}, + {id: 'Municipio', header: 'Municipio', editor: 'text', fillspace: 1}, + {id: 'Estado', header: 'Estado *', editor: 'text', fillspace: 1}, + {id: 'Pais', header: 'País *', editor: 'text', fillspace: 1}, + {id: 'CodigoPostal', header: 'C.P. *', editor: 'text', fillspace: 1}, +] + + +var grid_ce_destinatario = { + view: 'datatable', + id: 'grid_ce_destinatario', + multiselect: false, + adjust: true, + autoheight: true, + headermenu: true, + editable: true, + columns: grid_cols_ce_destinatario, + data: [{id: 0}], +} + + +var body_ce_destinatario = {rows:[ + grid_ce_destinatario +]} + + +var grid_cols_ce_mercancias = [ + {id: 'id', header: 'ID', hidden: true}, + {id: 'delete', header: '', width: 30, css: 'delete'}, + {id: 'NoIdentificacion', header: 'Clave', editor: 'text', fillspace: 1}, + {id: 'FraccionArancelaria', header: 'Fraccion Arancelaria', editor: 'text', fillspace: 1}, + {id: 'CantidadAduana', header: 'Cantidad Aduana', editor: 'text', fillspace: 1}, + {id: 'UnidadAduana', header: 'Unidad Aduana', editor: 'text', fillspace: 1}, + {id: 'ValorUnitarioAduana', header: 'PU Aduana', editor: 'text', fillspace: 1}, + {id: 'ValorDolares', header: 'Valor USD', editor: 'text', fillspace: 1}, + {id: 'Marca', header: 'Marca', editor: 'text', hidden: true, fillspace: 1}, + {id: 'Modelo', header: 'Modelo', editor: 'text', hidden: true, fillspace: 1}, + {id: 'SubModelo', header: 'SubModelo', editor: 'text', hidden: true, fillspace: 1}, + {id: 'NumeroSerie', header: 'Serie', editor: 'text', hidden: true, fillspace: 1}, +] + + +var grid_ce_mercancias = { + view: 'datatable', + id: 'grid_ce_mercancias', + multiselect: false, + adjust: true, + autoheight: true, + headermenu: true, + editable: true, + footer: true, + columns: grid_cols_ce_mercancias, +} + + +var body_ce_mercancias = {rows:[ + {cols: [ + {view: 'button', id: 'cmd_ce_add_mercancia', label: 'Agregar Mercancía', + icon: 'plus', type: 'iconButton', autowidth: true, align: 'center'}, + {}, + ]}, + {maxHeight: 10}, + grid_ce_mercancias +]} + + var controls_comercio_exterior = [ {cols: [{maxWidth: 15}, {view: 'checkbox', id: 'chk_cfdi_usar_comercioe', labelWidth: 0, - labelRight: 'Usar el complemento Comercio Exterior'}, {}, + labelRight: 'Usar el complemento Comercio Exterior'}, + {}, {view: 'button', id: 'cmd_import_json_comercioe', label: 'Importar JSON', icon: 'upload', type: 'iconButton', autowidth: true, align: 'center'}, - {maxWidth: 15}]} + {maxWidth: 15}]}, + {view: 'fieldset', label: 'Datos generales', body: body_ce_datos_generales}, + {view: 'fieldset', label: 'Emisor', body: body_ce_emisor}, + {view: 'fieldset', label: 'Propietario', body: body_ce_propietarios}, + {view: 'fieldset', label: 'Receptor', body: body_ce_receptor}, + {view: 'fieldset', label: 'Destinatario', body: body_ce_destinatario}, + {view: 'fieldset', label: 'Mercancías', body: body_ce_mercancias}, ] diff --git a/source/xslt/cadena.xslt b/source/xslt/cadena.xslt index e238e33..218d9d2 100644 --- a/source/xslt/cadena.xslt +++ b/source/xslt/cadena.xslt @@ -11,7 +11,7 @@ - + diff --git a/source/xslt/comercioexterior20.xslt b/source/xslt/comercioexterior20.xslt new file mode 100644 index 0000000..feaeb0e --- /dev/null +++ b/source/xslt/comercioexterior20.xslt @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file