diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a20582..07bb63d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+v 1.47.0 [28-Mar-2022]
+----------------------
+ - Mejora: Soporte basico para complemento Comercio Exterior.
+
+
v 1.46.5 [10-Mar-2022]
----------------------
- Error: Al timbrar nómina con Comercio Digital
diff --git a/VERSION b/VERSION
index ac2d35e..21998d3 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1 @@
-1.46.5
-
+1.47.0
diff --git a/source/app/controllers/cfdi_xml.py b/source/app/controllers/cfdi_xml.py
index d3264c7..5e17926 100644
--- a/source/app/controllers/cfdi_xml.py
+++ b/source/app/controllers/cfdi_xml.py
@@ -102,6 +102,12 @@ SAT = {
'prefix': 'cartaporte20',
'xmlns': 'http://www.sat.gob.mx/CartaPorte20',
'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',
}
}
@@ -122,6 +128,7 @@ class CFDI(object):
self._is_nomina = False
self._leyendas = False
self._carta_porte = False
+ self._comercio_exterior = False
self._divisas = ''
self.error = ''
@@ -174,6 +181,7 @@ class CFDI(object):
self._pagos = bool(datos['complementos'].get('pagos', False))
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))
self._divisas = datos['comprobante'].pop('divisas', '')
@@ -245,10 +253,16 @@ class CFDI(object):
attributes[name] = SAT['cartaporte']['xmlns']
schema_carta_porte = SAT['cartaporte']['schema']
+ schema_comercioe = ''
+ if self._comercio_exterior:
+ name = 'xmlns:{}'.format(SAT['comercioe']['prefix'])
+ attributes[name] = SAT['comercioe']['xmlns']
+ schema_carta_porte = SAT['comercioe']['schema']
+
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema'] + \
schema_locales + schema_donativo + schema_ine + schema_edu + \
schema_divisas + schema_nomina + schema_pagos + schema_leyendas + \
- schema_carta_porte
+ schema_carta_porte + schema_comercioe
attributes.update(datos)
if not 'Version' in attributes:
@@ -556,57 +570,59 @@ class CFDI(object):
for leyend in datos['leyendas']:
ET.SubElement(node_leyend, '{}:Leyenda'.format(pre), leyend)
- if 'ce' in datos:
- pre = 'cce11'
- datos = datos.pop('ce')
+ if self._comercio_exterior:
+ prefix = SAT['comercioe']['prefix']
+ datos = datos.pop('comercioe')
emisor = datos.pop('emisor')
- propietario = datos.pop('propietario')
+ # ~ propietario = datos.pop('propietario')
receptor = datos.pop('receptor')
destinatario = datos.pop('destinatario')
- conceptos = datos.pop('conceptos')
+ 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'
- attributes.update(datos)
+ # ~ 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(
- complemento, '{}:ComercioExterior'.format(pre), attributes)
+ self._complemento, f'{prefix}:ComercioExterior', attr)
attributes = {}
if 'Curp' in emisor:
attributes = {'Curp': emisor.pop('Curp')}
- node = ET.SubElement(ce, '{}:Emisor'.format(pre), attributes)
- ET.SubElement(node, '{}:Domicilio'.format(pre), emisor)
+ node = ET.SubElement(ce, '{}:Emisor'.format(prefix), attributes)
+ ET.SubElement(node, '{}:Domicilio'.format(prefix), emisor)
- if propietario:
- ET.SubElement(ce, '{}:Propietario'.format(pre), propietario)
+ # ~ if propietario:
+ # ~ ET.SubElement(ce, '{}:Propietario'.format(prefix), propietario)
attributes = {}
if 'NumRegIdTrib' in receptor:
attributes = {'NumRegIdTrib': receptor.pop('NumRegIdTrib')}
- node = ET.SubElement(ce, '{}:Receptor'.format(pre), attributes)
- ET.SubElement(node, '{}:Domicilio'.format(pre), receptor)
+ 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(pre), attributes)
- ET.SubElement(node, '{}:Domicilio'.format(pre), destinatario)
+ node = ET.SubElement(ce, '{}:Destinatario'.format(prefix), attributes)
+ ET.SubElement(node, '{}:Domicilio'.format(prefix), destinatario)
- node = ET.SubElement(ce, '{}:Mercancias'.format(pre))
+ node = ET.SubElement(ce, '{}:Mercancias'.format(prefix))
fields = ('Marca', 'Modelo', 'SubModelo', 'NumeroSerie')
for row in conceptos:
detalle = {}
for f in fields:
if f in row:
detalle[f] = row.pop(f)
- concepto = ET.SubElement(node, '{}:Mercancia'.format(pre), row)
+ concepto = ET.SubElement(node, '{}:Mercancia'.format(prefix), row)
if detalle:
ET.SubElement(
- concepto, '{}:DescripcionesEspecificas'.format(pre), detalle)
+ concepto, '{}:DescripcionesEspecificas'.format(prefix), detalle)
return
diff --git a/source/app/models/main.py b/source/app/models/main.py
index bd47931..afd8add 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -344,6 +344,7 @@ def config_timbrar():
'cfdi_ine': Configuracion.get_bool('chk_config_ine'),
'cfdi_edu': Configuracion.get_bool('chk_config_edu'),
'cfdi_carta_porte': Configuracion.get_bool('chk_config_carta_porte'),
+ 'cfdi_comercioe': Configuracion.get_bool('chk_config_comercio_exterior'),
'cfdi_divisas': Configuracion.get_bool('chk_config_divisas'),
'cfdi_metodo_pago': Configuracion.get_bool('chk_config_ocultar_metodo_pago'),
'cfdi_condicion_pago': Configuracion.get_bool('chk_config_ocultar_condiciones_pago'),
@@ -482,6 +483,7 @@ class Configuracion(BaseModel):
'chk_config_ine',
'chk_config_edu',
'chk_config_carta_porte',
+ 'chk_config_comercio_exterior',
'chk_config_pagos',
'chk_config_divisas',
'chk_cfg_pays_data_bank',
@@ -5398,6 +5400,21 @@ class Facturas(BaseModel):
FacturasComplementos.create(**data)
return
+ def _save_comercioe(self, invoice, valores):
+ if not valores:
+ return
+
+ # ~ values = utils.loads(valores)
+
+ data = {
+ 'factura': invoice,
+ 'nombre': 'comercioe',
+ # ~ 'valores': utils.dumps(values),
+ 'valores': valores,
+ }
+ FacturasComplementos.create(**data)
+ return
+
def _get_serie(self, user, default_serie):
if user.sucursal is None:
return default_serie
@@ -5410,6 +5427,7 @@ class Facturas(BaseModel):
relacionados = util.loads(values.pop('relacionados'))
ine = values.pop('ine', {})
cartaporte = values.pop('cartaporte', {})
+ comercioe = values.pop('comercioe', {})
tipo_comprobante = values['tipo_comprobante']
folio_custom = values.pop('folio_custom', '')
divisas = values.pop('divisas', '')
@@ -5453,6 +5471,7 @@ class Facturas(BaseModel):
cls._guardar_relacionados(cls, obj, relacionados)
cls._guardar_ine(cls, obj, ine)
cls._save_cartaporte(cls, obj, cartaporte)
+ cls._save_comercioe(cls, obj, comercioe)
cls._save_leyendas_fiscales(cls, obj, leyendas_fiscales)
obj.subtotal = totals['subtotal']
obj.descuento = totals['descuento']
@@ -11480,4 +11499,3 @@ if __name__ == '__main__':
args = _process_command_line_arguments()
main(args)
-
diff --git a/source/app/settings.py b/source/app/settings.py
index e97cec6..00624bc 100644
--- a/source/app/settings.py
+++ b/source/app/settings.py
@@ -42,7 +42,7 @@ except ImportError:
DEBUG = DEBUG
-VERSION = '1.46.5'
+VERSION = '1.47.0'
EMAIL_SUPPORT = ('soporte@empresalibre.mx',)
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)
diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js
index 164ead8..0016d98 100644
--- a/source/static/js/controller/admin.js
+++ b/source/static/js/controller/admin.js
@@ -115,6 +115,7 @@ var controllers = {
$$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_edu').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_carta_porte').attachEvent('onItemClick', chk_config_item_click)
+ $$('chk_config_comercio_exterior').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_leyendas_fiscales').attachEvent('onItemClick', chk_config_item_click)
$$('cmd_admin_leyendas_fiscales').attachEvent('onItemClick', cmd_admin_leyendas_fiscales_click)
diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js
index e5026ea..e060d42 100644
--- a/source/static/js/controller/invoices.js
+++ b/source/static/js/controller/invoices.js
@@ -22,6 +22,7 @@ var tipo_relacion = ''
var anticipo = false
var donativo = false
var cfg_invoice = new Object()
+var values_comercioe = null
function init_config_invoices(){
@@ -94,6 +95,7 @@ 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)
webix.extend($$('grid_invoices'), webix.ProgressBar)
@@ -224,12 +226,17 @@ function default_config(){
if(!values.cfdi_carta_porte){
$$('tv_invoice').getTabbar().hideOption('Carta Porte')
}else{
- get_leyendas_fiscales()
$$('tv_invoice').getTabbar().showOption('Carta Porte')
}
+ if(!values.cfdi_comercioe){
+ $$('tv_invoice').getTabbar().hideOption('Comercio Exterior')
+ }else{
+ $$('tv_invoice').getTabbar().showOption('Comercio Exterior')
+ }
cfg_invoice['leyendasfiscales'] = values.cfdi_leyendasfiscales
cfg_invoice['edu'] = values.cfdi_edu
cfg_invoice['carta_porte'] = values.cfdi_carta_porte
+ cfg_invoice['comercioe'] = values.cfdi_comercioe
cfg_invoice['open_pdf'] = values.cfdi_open_pdf
cfg_invoice['tax_locales'] = values.cfdi_tax_locales
cfg_invoice['tax_decimals'] = values.cfdi_tax_decimals
@@ -769,10 +776,18 @@ function guardar_y_timbrar(values){
data['cartaporte'] = cartaporte
}
+ var usar_comercioe = $$('chk_cfdi_usar_comercioe').getValue()
+ if(usar_comercioe){
+ data['comercioe'] = values_comercioe
+ }
+
if(!save_invoice(data)){
return
}
+ values_comercioe = null
+ $$('chk_cfdi_usar_comercioe').setValue(false)
+
table_relaciones.clear()
tipo_relacion = ''
anticipo = false
@@ -816,11 +831,21 @@ function cmd_timbrar_click(id, e, node){
}
msg += '
'
}
+
usar_ine = $$('chk_cfdi_usar_ine').getValue()
if(usar_ine){
msg += 'Estas usando el complemento INE
'
}
+ if($$('chk_cfdi_usar_comercioe').getValue()){
+ msg += 'Estas usando el complemento Comercio Exterior
'
+ if(values_comercioe === null){
+ msg = 'El complemento de Comercio Exterior esta vacío'
+ msg_error(msg)
+ return
+ }
+ }
+
if(tipo_comprobante == 'T'){
msg += 'El Tipo de Comprobante es Traslado, el total será puesto a 0 (Cero), asegurate de que sea el tipo de comprobante correcto
'
}
@@ -2815,3 +2840,36 @@ function up_invoice_json_on_after_file_add(obj){
}
$$('win_carta_import_json').close()
}
+
+
+function _set_from_json_comercioe(data){
+ try{
+ values_comercioe = JSON.parse(data)
+ }catch(e){
+ msg_error('Revisa el archivo JSON')
+ webix.alert({
+ title: 'Error al cargar JSON',
+ text: e.message,
+ type: 'alert-error'
+ })
+ return
+ }
+ msg = 'Valores cargados correctamente'
+ msg_ok(msg)
+}
+
+
+function cmd_import_json_comercioe_click(){
+ win_import_json_comercioe.init()
+ $$('win_import_json_comercioe').show()
+}
+
+
+function up_invoice_json_comercioe_on_after_file_add(obj){
+ let reader = new FileReader()
+ reader.readAsText(obj.file)
+ reader.onload = function(){
+ _set_from_json_comercioe(reader.result)
+ }
+ $$('win_import_json_comercioe').close()
+}
diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js
index 4b54347..e9f1e35 100644
--- a/source/static/js/ui/admin.js
+++ b/source/static/js/ui/admin.js
@@ -887,6 +887,11 @@ var options_admin_complements = [
{view: 'checkbox', id: 'chk_config_carta_porte', labelWidth: 0,
labelRight: 'Usar el complemento Carta Porte'},
{maxWidth: 15}]},
+ {template: 'Complemento para Comercio Exterior', type: 'section'},
+ {cols: [{maxWidth: 15},
+ {view: 'checkbox', id: 'chk_config_comercio_exterior', labelWidth: 0,
+ labelRight: 'Usar el complemento Comercio Exterior'},
+ {maxWidth: 15}]},
]
diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js
index 4e60fd2..4e488f2 100644
--- a/source/static/js/ui/invoices.js
+++ b/source/static/js/ui/invoices.js
@@ -1198,6 +1198,16 @@ var controls_carta_porte = [
]
+var controls_comercio_exterior = [
+ {cols: [{maxWidth: 15},
+ {view: 'checkbox', id: 'chk_cfdi_usar_comercioe', labelWidth: 0,
+ 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}]}
+]
+
+
var form_carta_porte = {
type: 'space',
responsive: true,
@@ -1211,6 +1221,19 @@ var form_carta_porte = {
}
+var form_comercio_exterior = {
+ type: 'space',
+ responsive: true,
+ cols: [{
+ view: 'form',
+ id: 'form_comercio_exterior',
+ complexData: true,
+ scroll: true,
+ elements: controls_comercio_exterior,
+ }]
+}
+
+
var controls_invoices = [
{
view: 'tabview',
@@ -1222,6 +1245,7 @@ var controls_invoices = [
{id: 'INE', rows: controls_ine},
{id: 'Leyendas Fiscales', rows: controls_leyendas_fiscales},
{id: 'Carta Porte', rows: [form_carta_porte]},
+ {id: 'Comercio Exterior', rows: [form_comercio_exterior]},
]
},
]
@@ -1368,3 +1392,32 @@ var win_carta_import_json = {
$$('up_invoice_json').attachEvent('onAfterFileAdd', up_invoice_json_on_after_file_add)
}
}
+
+
+var body_upload_json_comercioe = {rows: [
+ {view: 'form', id: 'form_upload_comercioe', rows: [
+ {cols: [{},
+ {view: 'uploader', id: 'up_invoice_json', autosend: false,
+ link: 'lst_upload_invoice', value: 'Seleccionar Archivo',
+ accept:'application/json', upload: ''}, {}]},
+ {cols: [
+ {view: 'list', id: 'lst_upload_invoice', name: 'lst_upload_invoice',
+ type: 'uploader', autoheight: true, borderless: true}]},
+ ]},
+]}
+
+
+var win_import_json_comercioe = {
+ init: function(){
+ webix.ui({
+ view: 'window',
+ id: 'win_import_json_comercioe',
+ width: 400,
+ modal: true,
+ position: 'center',
+ head: 'Importar Comerio Exterior JSON',
+ body: body_upload_json_comercioe,
+ })
+ $$('up_invoice_json').attachEvent('onAfterFileAdd', up_invoice_json_comercioe_on_after_file_add)
+ }
+}