diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d7f3db..14b9eb1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+v 1.37.0 [02-mar-2020]
+----------------------
+ - Mejora: Soporte para complemento Leyendas Fiscales
+
+* IMPORTANTE:
+
+Es necesario hacer una migración, y agregar los campos necesarios para mostrar
+las leyendas, mira la carpeta pública con la plantilla de ejemplo.
+```
+git pull origin master
+
+cd source/app/models
+
+python main.py -bk
+
+python main.py -m -r RFC
+```
+
v 1.36.0 [25-feb-2020]
----------------------
diff --git a/VERSION b/VERSION
index 39fc130..bf50e91 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.36.0
+1.37.0
diff --git a/requirements.txt b/requirements.txt
index 6b2a201..d33642b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,6 @@ falcon-multipart
Beaker
Mako
peewee==2.10.2
-Click
logbook
bcrypt
python-dateutil
diff --git a/source/app/controllers/cfdi_xml.py b/source/app/controllers/cfdi_xml.py
index 7054bbe..11fea61 100644
--- a/source/app/controllers/cfdi_xml.py
+++ b/source/app/controllers/cfdi_xml.py
@@ -90,6 +90,12 @@ SAT = {
'xmlns': 'http://www.sat.gob.mx/divisas',
'schema': ' http://www.sat.gob.mx/divisas http://www.sat.gob.mx/sitio_internet/cfd/divisas/divisas.xsd',
},
+ 'leyendas': {
+ 'version': '1.0',
+ 'prefix': 'leyendasFisc',
+ 'xmlns': 'http://www.sat.gob.mx/leyendasFiscales',
+ 'schema': ' http://www.sat.gob.mx/leyendasFiscales http://www.sat.gob.mx/sitio_internet/cfd/leyendasFiscales/leyendasFisc.xsd',
+ },
}
@@ -107,6 +113,7 @@ class CFDI(object):
self._edu = False
self._pagos = False
self._is_nomina = False
+ self._leyendas = False
self._divisas = ''
self.error = ''
@@ -129,8 +136,6 @@ class CFDI(object):
if 'nomina' in datos:
self._nomina(datos['nomina'])
- #~ if 'complementos' in datos:
- #~ self._complementos(datos['complementos'])
return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
@@ -158,6 +163,7 @@ class CFDI(object):
if 'ine' in datos['complementos']:
self._ine = True
self._pagos = bool(datos['complementos'].get('pagos', False))
+ self._leyendas = bool(datos['complementos'].get('leyendas', False))
self._divisas = datos['comprobante'].pop('divisas', '')
@@ -217,9 +223,15 @@ class CFDI(object):
attributes[name] = SAT['pagos']['xmlns']
schema_pagos = SAT['pagos']['schema']
+ schema_leyendas = ''
+ if self._leyendas:
+ name = 'xmlns:{}'.format(SAT['leyendas']['prefix'])
+ attributes[name] = SAT['leyendas']['xmlns']
+ schema_leyendas = SAT['leyendas']['schema']
+
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema'] + \
schema_locales + schema_donativo + schema_ine + schema_edu + \
- schema_divisas + schema_nomina + schema_pagos
+ schema_divisas + schema_nomina + schema_pagos + schema_leyendas
attributes.update(datos)
if not 'Version' in attributes:
@@ -464,6 +476,14 @@ class CFDI(object):
for row in relacionados:
ET.SubElement(node_pago, '{}:DoctoRelacionado'.format(pre), row)
+ if 'leyendas' in datos:
+ pre = SAT['leyendas']['prefix']
+ attributes = {'version': SAT['leyendas']['version']}
+ node_leyend = ET.SubElement(
+ self._complemento, '{}:LeyendasFiscales'.format(pre), attributes)
+ for leyend in datos['leyendas']:
+ ET.SubElement(node_leyend, '{}:Leyenda'.format(pre), leyend)
+
if 'ce' in datos:
pre = 'cce11'
datos = datos.pop('ce')
diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py
index 41a8e3e..3efcfc2 100644
--- a/source/app/controllers/main.py
+++ b/source/app/controllers/main.py
@@ -594,6 +594,29 @@ class AppSATFormaPago(object):
resp.status = falcon.HTTP_200
+class AppSATLeyendaFiscales(object):
+
+ def __init__(self, db):
+ self._db = db
+
+ def on_get(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.sat_leyendas_fiscales_get(values)
+ resp.status = falcon.HTTP_200
+
+ def on_post(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.sat_leyendas_fiscales_post(values)
+ resp.status = falcon.HTTP_200
+
+ def on_delete(self, req, resp):
+ values = req.params
+ if self._db.sat_leyendas_fiscales_delete(values['id']):
+ resp.status = falcon.HTTP_200
+ else:
+ resp.status = falcon.HTTP_204
+
+
class AppSociosCuentasBanco(object):
def __init__(self, db):
diff --git a/source/app/controllers/util.py b/source/app/controllers/util.py
index 0080670..7aa5973 100644
--- a/source/app/controllers/util.py
+++ b/source/app/controllers/util.py
@@ -1087,6 +1087,28 @@ class LIBO(object):
self._set_cell(f'{{divisas.{k}}}', v)
return
+ def _leyendas(self, data):
+ if not data:
+ return
+
+ first = True
+ for row in data:
+ leyenda = row['textoLeyenda']
+ norma = row.get('norma', '')
+ disposicion = row.get('disposicionFiscal', '')
+ if first:
+ first = False
+ cell1 = self._set_cell('{textoLeyenda}', leyenda)
+ cell2 = self._set_cell('{norma}', norma)
+ cell3 = self._set_cell('{disposicionFiscal}', disposicion)
+ else:
+ row = cell1.CellAddress.Row + 1
+ self._sheet.getRows().insertByIndex(row, 1)
+ cell1 = self._set_cell(v=leyenda, cell=cell1)
+ cell2 = self._set_cell(v=norma, cell=cell2)
+ cell3 = self._set_cell(v=disposicion, cell=cell3)
+ return
+
def _nomina(self, data):
if not data:
return
@@ -1314,6 +1336,7 @@ class LIBO(object):
self._ine(data['ine'])
self._divisas(data.get('divisas', {}))
+ self._leyendas(data['leyendas'])
self._cancelado(data['cancelada'])
self._clean()
diff --git a/source/app/controllers/utils.py b/source/app/controllers/utils.py
index ac24815..cceda98 100644
--- a/source/app/controllers/utils.py
+++ b/source/app/controllers/utils.py
@@ -244,10 +244,13 @@ class CfdiToDict(object):
NS = {
'cfdi': 'http://www.sat.gob.mx/cfd/3',
'divisas': 'http://www.sat.gob.mx/divisas',
+ 'leyendasFisc': 'http://www.sat.gob.mx/leyendasFiscales',
}
def __init__(self, xml):
- self._values = {}
+ self._values = {
+ 'leyendas': (),
+ }
self._root = ET.parse(BytesIO(xml.encode())).getroot()
self._get_values()
@@ -260,13 +263,21 @@ class CfdiToDict(object):
return
def _complementos(self):
- complemento = self._root.xpath('//cfdi:Complemento', namespaces=self.NS)[0]
+ path = '//cfdi:Complemento'
+ complemento = self._root.xpath(path, namespaces=self.NS)[0]
- divisas = complemento.xpath('//divisas:Divisas', namespaces=self.NS)
+ path = '//divisas:Divisas'
+ divisas = complemento.xpath(path, namespaces=self.NS)
if divisas:
d = CaseInsensitiveDict(divisas[0].attrib)
d.pop('version', '')
self._values.update({'divisas': d})
+
+ path = '//leyendasFisc:Leyenda'
+ node = complemento.xpath(path, namespaces=self.NS)
+ if node:
+ leyendas = [CaseInsensitiveDict(n.attrib) for n in node]
+ self._values['leyendas'] = leyendas
return
diff --git a/source/app/main.py b/source/app/main.py
index e7afd80..c03b858 100644
--- a/source/app/main.py
+++ b/source/app/main.py
@@ -17,7 +17,7 @@ from controllers.main import (AppEmpresas,
AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco,
AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina,
AppInvoicePay, AppCfdiPay, AppSATBancos, AppSociosCuentasBanco,
- AppSATFormaPago
+ AppSATFormaPago, AppSATLeyendaFiscales
)
@@ -61,6 +61,7 @@ api.add_route('/cfdipay', AppCfdiPay(db))
api.add_route('/satbancos', AppSATBancos(db))
api.add_route('/satformapago', AppSATFormaPago(db))
api.add_route('/socioscb', AppSociosCuentasBanco(db))
+api.add_route('/leyendasfiscales', AppSATLeyendaFiscales(db))
session_options = {
diff --git a/source/app/models/db.py b/source/app/models/db.py
index cff00e8..7d50926 100644
--- a/source/app/models/db.py
+++ b/source/app/models/db.py
@@ -462,6 +462,15 @@ class StorageEngine(object):
def nomina(self, values, user):
return main.CfdiNomina.post(values, user)
+ def sat_leyendas_fiscales_get(self, values):
+ return main.SATLeyendasFiscales.get_values(values)
+
+ def sat_leyendas_fiscales_post(self, values):
+ return main.SATLeyendasFiscales.post(values)
+
+ def sat_leyendas_fiscales_delete(self, values):
+ return main.SATLeyendasFiscales.remove(values)
+
# Companies only in MV
def _get_empresas(self, values):
return main.companies_get()
diff --git a/source/app/models/main.py b/source/app/models/main.py
index f9e1a77..b8f062c 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -308,6 +308,7 @@ def config_timbrar():
'cfdi_add_same_product': Configuracion.get_bool('chk_config_add_same_product'),
'cfdi_tax_locales_truncate': Configuracion.get_bool('chk_config_tax_locales_truncate'),
'cfdi_folio_custom': Configuracion.get_bool('chk_folio_custom'),
+ 'cfdi_leyendasfiscales': Configuracion.get_bool('chk_config_leyendas_fiscales'),
}
return conf
@@ -432,6 +433,7 @@ class Configuracion(BaseModel):
'chk_config_divisas',
'chk_cfg_pays_data_bank',
'chk_usar_nomina',
+ 'chk_config_leyendas_fiscales',
)
data = (Configuracion
.select()
@@ -2478,6 +2480,83 @@ class SATRiesgoPuesto(BaseModel):
return
+class SATLeyendasFiscales(BaseModel):
+ texto_leyenda = TextField(index=True)
+ norma = TextField(default='')
+ disposicion_fiscal = TextField(default='')
+ active = BooleanField(default=True)
+ default = BooleanField(default=False)
+
+ class Meta:
+ order_by = ('texto_leyenda',)
+ indexes = (
+ (('texto_leyenda', 'norma', 'disposicion_fiscal'), True),
+ )
+
+ def _get_all(self, values):
+ rows = (SATLeyendasFiscales.select(
+ SATLeyendasFiscales.id,
+ SQL(" '-' AS delete"),
+ SATLeyendasFiscales.texto_leyenda,
+ SATLeyendasFiscales.norma,
+ SATLeyendasFiscales.disposicion_fiscal)
+ .dicts()
+ )
+ return tuple(rows)
+
+ def _get_active(self, values):
+ rows = (SATLeyendasFiscales.select(
+ SATLeyendasFiscales.id,
+ SATLeyendasFiscales.texto_leyenda,
+ SATLeyendasFiscales.norma,
+ SATLeyendasFiscales.disposicion_fiscal)
+ .where(SATLeyendasFiscales.active==True)
+ .dicts()
+ )
+ return tuple(rows)
+
+ @classmethod
+ def get_by_id(cls, ids):
+ rows = (SATLeyendasFiscales.select(
+ SATLeyendasFiscales.texto_leyenda.alias('textoLeyenda'),
+ SATLeyendasFiscales.norma,
+ SATLeyendasFiscales.disposicion_fiscal.alias('disposicionFiscal'))
+ .where(SATLeyendasFiscales.id.in_(ids))
+ .dicts()
+ )
+ for row in rows:
+ if not row['norma']:
+ del row['norma']
+ if not row['disposicionFiscal']:
+ del row['disposicionFiscal']
+ return tuple(rows)
+
+ @classmethod
+ def get_values(cls, values):
+ opt = values.pop('opt')
+ return getattr(cls, '_get_{}'.format(opt))(cls, values)
+
+ def _new(self, values):
+ try:
+ obj = SATLeyendasFiscales.create(**values)
+ values['id'] = obj.id
+ values['delete'] = '-'
+ result = {'ok': True, 'row': values}
+ except Exception as e:
+ result = {'ok': False, 'msg': 'La Leyenda Fiscal ya existe'}
+ return result
+
+ @classmethod
+ def post(cls, values):
+ opt = values.pop('opt')
+ return getattr(cls, '_{}'.format(opt))(cls, values)
+
+ @classmethod
+ def remove(cls, id):
+ q = SATLeyendasFiscales.delete().where(SATLeyendasFiscales.id==id)
+ return bool(q.execute())
+
+
class TipoCambio(BaseModel):
dia = DateField(default=util.now)
moneda = ForeignKeyField(SATMonedas)
@@ -4641,6 +4720,8 @@ class Facturas(BaseModel):
divisas = ''
values['divisas'] = divisas
+ leyendas_fiscales = utils.loads(values.pop('leyendas_fiscales', '[]'))
+
emisor = Emisor.select()[0]
values['serie'] = cls._get_serie(cls, user, values['serie'])
if Configuracion.get_bool('chk_folio_custom') and folio_custom:
@@ -4665,6 +4746,7 @@ class Facturas(BaseModel):
totals = cls._calculate_totals(cls, obj, productos, tipo_comprobante)
cls._guardar_relacionados(cls, obj, relacionados)
cls._guardar_ine(cls, obj, ine)
+ cls._save_leyendas_fiscales(cls, obj, leyendas_fiscales)
obj.subtotal = totals['subtotal']
obj.descuento = totals['descuento']
obj.total_trasladados = totals['total_trasladados']
@@ -4695,6 +4777,18 @@ class Facturas(BaseModel):
data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg}
return data
+ def _save_leyendas_fiscales(self, invoice, valores):
+ if not valores:
+ return
+
+ data = {
+ 'factura': invoice,
+ 'nombre': 'leyendas',
+ 'valores': utils.dumps(valores),
+ }
+ FacturasComplementos.create(**data)
+ return
+
def _make_xml(self, invoice, auth):
tax_decimals = Configuracion.get_bool('chk_config_tax_decimals')
decimales_precios = Configuracion.get_bool('chk_config_decimales_precios')
@@ -4709,11 +4803,15 @@ class Facturas(BaseModel):
comprobante = {}
relacionados = {}
donativo = {}
- complementos = FacturasComplementos.get_(invoice)
+ complementos = FacturasComplementos.get_by_invoice(invoice)
comprobante['divisas'] = invoice.divisas
if invoice.divisas:
complementos['divisas'] = True
+ if 'leyendas' in complementos:
+ ids = complementos['leyendas']
+ complementos['leyendas'] = SATLeyendasFiscales.get_by_id(ids)
+
if invoice.donativo:
donativo['noAutorizacion'] = emisor.autorizacion
donativo['fechaAutorizacion'] = str(emisor.fecha_autorizacion)
@@ -5854,6 +5952,14 @@ class FacturasComplementos(BaseModel):
)
return {r.nombre: utils.loads(r.valores) for r in query}
+ @classmethod
+ def get_by_invoice(cls, invoice):
+ query = (FacturasComplementos
+ .select()
+ .where(FacturasComplementos.factura==invoice)
+ )
+ return {r.nombre: utils.loads(r.valores) for r in query}
+
class PreFacturasRelacionadas(BaseModel):
factura = ForeignKeyField(PreFacturas, related_name='original')
@@ -9081,7 +9187,7 @@ def _crear_tablas(rfc):
SATNivelesEducativos, SATEstados, SATRiesgoPuesto, SATPeriodicidadPago,
SATOrigenRecurso, SATTipoContrato, SATTipoDeduccion, SATTipoHoras,
SATTipoIncapacidad, SATTipoJornada, SATTipoNomina, SATTipoOtroPago,
- SATTipoPercepcion, SATTipoRegimen,
+ SATTipoPercepcion, SATTipoRegimen, SATLeyendasFiscales,
Socios, SociosCuentasBanco, Contactos, ContactoCorreos,
ContactoDirecciones, Empleados, ContactoTelefonos, Departamentos,
Puestos,
@@ -9151,7 +9257,7 @@ def _migrate_tables(rfc=''):
CfdiNominaOtroPago, CfdiNominaOtros, CfdiNominaPercepciones,
CfdiNominaRelacionados, CfdiNominaSeparacion, CfdiNominaSubcontratos,
CfdiNominaTotales, SATNivelesEducativos, Roles, Permisos,
- SociosCuentasBanco
+ SociosCuentasBanco, SATLeyendasFiscales
]
log.info('Creando tablas nuevas...')
database_proxy.create_tables(tablas, True)
@@ -10375,6 +10481,5 @@ def main(args):
if __name__ == '__main__':
args = _process_command_line_arguments()
main(args)
- # ~ main2()
diff --git a/source/app/settings.py b/source/app/settings.py
index edcf327..b1f5bc7 100644
--- a/source/app/settings.py
+++ b/source/app/settings.py
@@ -47,7 +47,7 @@ except ImportError:
DEBUG = DEBUG
-VERSION = '1.36.0'
+VERSION = '1.37.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 83721b4..310da10 100644
--- a/source/static/js/controller/admin.js
+++ b/source/static/js/controller/admin.js
@@ -92,6 +92,24 @@ var controllers = {
$$('chk_llevar_inventario').attachEvent('onItemClick', chk_config_item_click)
$$('chk_use_packing').attachEvent('onItemClick', chk_config_item_click)
+ //~ Complements
+ $$('chk_usar_nomina').attachEvent('onItemClick', chk_config_item_click)
+ $$('txt_config_nomina_serie').attachEvent('onKeyPress', txt_config_nomina_serie_press)
+ $$('txt_config_nomina_folio').attachEvent('onKeyPress', txt_config_nomina_folio_press)
+
+ $$('chk_config_pagos').attachEvent('onItemClick', chk_config_item_click)
+ $$('chk_cfg_pays_data_bank').attachEvent('onItemClick', chk_config_item_click)
+ $$('txt_config_cfdipay_serie').attachEvent('onKeyPress', txt_config_cfdipay_serie_press)
+ $$('txt_config_cfdipay_folio').attachEvent('onKeyPress', txt_config_cfdipay_folio_press)
+
+ $$('chk_config_divisas').attachEvent('onItemClick', chk_config_item_click)
+ $$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click)
+ $$('chk_config_edu').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)
+
+ //~ Others
$$('chk_config_ocultar_metodo_pago').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_ocultar_condiciones_pago').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_send_zip').attachEvent('onItemClick', chk_config_item_click)
@@ -105,11 +123,7 @@ var controllers = {
$$('chk_config_decimales_precios').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_user_show_doc').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_anticipo').attachEvent('onItemClick', chk_config_item_click)
- $$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click)
- $$('chk_config_edu').attachEvent('onItemClick', chk_config_item_click)
- $$('chk_config_pagos').attachEvent('onItemClick', chk_config_item_click)
- $$('chk_config_divisas').attachEvent('onItemClick', chk_config_item_click)
- $$('chk_cfg_pays_data_bank').attachEvent('onItemClick', chk_config_item_click)
+
$$('chk_usar_punto_de_venta').attachEvent('onItemClick', chk_config_item_click)
$$('chk_ticket_pdf_show').attachEvent('onItemClick', chk_config_item_click)
$$('chk_ticket_direct_print').attachEvent('onItemClick', chk_config_item_click)
@@ -117,11 +131,6 @@ var controllers = {
$$('chk_ticket_total_up').attachEvent('onItemClick', chk_config_item_click)
$$('chk_ticket_user_show_doc').attachEvent('onItemClick', chk_config_item_click)
$$('txt_ticket_printer').attachEvent('onKeyPress', txt_ticket_printer_key_press)
- $$('txt_config_nomina_serie').attachEvent('onKeyPress', txt_config_nomina_serie_press)
- $$('txt_config_nomina_folio').attachEvent('onKeyPress', txt_config_nomina_folio_press)
- $$('txt_config_cfdipay_serie').attachEvent('onKeyPress', txt_config_cfdipay_serie_press)
- $$('txt_config_cfdipay_folio').attachEvent('onKeyPress', txt_config_cfdipay_folio_press)
- $$('chk_usar_nomina').attachEvent('onItemClick', chk_config_item_click)
$$('lst_pac').attachEvent('onChange', lst_pac_on_change)
$$('cmd_subir_bdfl').attachEvent('onItemClick', cmd_subir_bdfl_click)
@@ -471,6 +480,9 @@ function get_config_values(opt){
set_value(key, values[key])
}else{
$$(key).setValue(values[key])
+ if(key=='chk_config_leyendas_fiscales'){
+ admin_config_other_options(key)
+ }
}
})
}
@@ -1816,6 +1828,8 @@ function chk_config_item_click(id, e){
}
})
+ admin_config_other_options(id)
+
}
@@ -2570,3 +2584,109 @@ function lst_pac_on_change(nv, ov){
})
}
}
+
+
+function admin_config_other_options(id){
+ if(id=='chk_config_leyendas_fiscales'){
+ var value = Boolean($$(id).getValue())
+ if(value){
+ $$('cmd_admin_leyendas_fiscales').enable()
+ }else{
+ $$('cmd_admin_leyendas_fiscales').disable()
+ }
+ }
+}
+
+
+function cmd_admin_leyendas_fiscales_click(){
+ admin_ui_leyendas_fiscales.init()
+ $$('win_leyendas_fiscales').show()
+ get_leyendas_fiscales()
+}
+
+
+function get_leyendas_fiscales(){
+ webix.ajax().sync().get('/leyendasfiscales', {'opt': 'all'}, {
+ error:function(text, data, XmlHttpRequest){
+ msg = 'Ocurrio un error, consulta a soporte técnico'
+ msg_error(msg)
+ },
+ success:function(text, data, XmlHttpRequest){
+ var values = data.json()
+ var grid = $$('grid_admin_leyendas_fiscales')
+ grid.clearAll()
+ grid.parse(values)
+ grid.refresh()
+ }
+ })
+}
+
+
+function add_admin_leyenda_fiscal_click(){
+ var form = $$('form_admin_leyendas_fiscales')
+ var grid = $$('grid_admin_leyendas_fiscales')
+
+ if (!form.validate()){
+ msg = 'Valores inválidos'
+ msg_error(msg)
+ return
+ }
+ var values = form.getValues()
+ values['opt'] = 'new'
+
+ var empty = {texto_leyenda: '', norma: '', disposicion_fiscal: ''}
+
+ webix.ajax().post('/leyendasfiscales', values, {
+ error:function(text, data, XmlHttpRequest){
+ msg = 'Ocurrio un error, consulta a soporte técnico'
+ msg_error(msg)
+ },
+ success:function(text, data, XmlHttpRequest){
+ var values = data.json()
+ if(values.ok){
+ msg_ok('Leyenda guardada correctamente')
+ form.setValues(empty)
+ grid.add(values.row)
+ }else{
+ msg_error(values.msg)
+ }
+ }
+ })
+}
+
+
+function grid_admin_leyendas_fiscales_click(id){
+ if(id.column != 'delete'){
+ return
+ }
+
+ msg = '¿Estás seguro de eliminar esta Leyenda Fiscal'
+ webix.confirm({
+ title: 'Eliminar',
+ ok: 'Si',
+ cancel: 'No',
+ type: 'confirm-error',
+ text: msg,
+ callback:function(result){
+ if(result){
+ delete_leyenda_fiscal(id.row)
+ }
+ }
+ })
+
+}
+
+function delete_leyenda_fiscal(id){
+ var grid = $$('grid_admin_leyendas_fiscales')
+
+ webix.ajax().del('/leyendasfiscales', {id: id}, function(text, xml, xhr){
+ msg = 'Leyenda Fiscal eliminada correctamente'
+ if(xhr.status == 200){
+ grid.remove(id)
+ msg_ok(msg)
+ }else{
+ msg = 'No se pudo eliminar'
+ msg_error(msg)
+ }
+ })
+}
diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js
index 1983bcd..a5ccf61 100644
--- a/source/static/js/controller/invoices.js
+++ b/source/static/js/controller/invoices.js
@@ -205,6 +205,13 @@ function default_config(){
}else{
$$('tv_invoice').getTabbar().showOption('INE')
}
+ if(!values.cfdi_leyendasfiscales){
+ $$('tv_invoice').getTabbar().hideOption('Leyendas Fiscales')
+ }else{
+ get_leyendas_fiscales()
+ $$('tv_invoice').getTabbar().showOption('Leyendas Fiscales')
+ }
+ cfg_invoice['leyendasfiscales'] = values.cfdi_leyendasfiscales
cfg_invoice['edu'] = values.cfdi_edu
cfg_invoice['open_pdf'] = values.cfdi_open_pdf
cfg_invoice['tax_locales'] = values.cfdi_tax_locales
@@ -642,6 +649,8 @@ function guardar_y_timbrar(values){
data['notas'] = values.notas
data['folio_custom'] = $$('txt_folio_custom').getValue()
data['divisas'] = $$('opt_divisas').getValue()
+ data['leyendas_fiscales'] = $$('grid_leyendas_fiscales').getSelectedId(true, true)
+ $$('grid_leyendas_fiscales').unselectAll()
var usar_ine = $$('chk_cfdi_usar_ine').getValue()
if(usar_ine){
@@ -709,6 +718,17 @@ function cmd_timbrar_click(id, e, node){
msg += 'El Tipo de Comprobante es Traslado, el total será puesto a 0 (Cero), asegurate de que sea el tipo de comprobante correcto
'
}
+ if(cfg_invoice['leyendasfiscales']){
+ var rows = $$('grid_leyendas_fiscales').getSelectedId(true, true)
+ if(rows.length == 0){
+ msg += 'No se agregará ninguna leyenda fiscal
'
+ }else if(rows.length == 1){
+ msg += 'Se agregará una leyenda fiscal
'
+ }else{
+ msg += 'Se agregarán ' + rows.length + ' leyendas fiscales
'
+ }
+ }
+
msg += '¿Estás seguro de timbrar esta factura?
'
webix.confirm({
@@ -2352,3 +2372,20 @@ function search_by_click(){
search_by(value)
}
}
+
+
+function get_leyendas_fiscales(){
+ webix.ajax().get('/leyendasfiscales', {'opt': 'active'}, {
+ error:function(text, data, XmlHttpRequest){
+ msg = 'Ocurrio un error, consulta a soporte técnico'
+ msg_error(msg)
+ },
+ success:function(text, data, XmlHttpRequest){
+ var values = data.json()
+ var grid = $$('grid_leyendas_fiscales')
+ grid.clearAll()
+ grid.parse(values)
+ grid.refresh()
+ }
+ })
+}
diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js
index 8ffe3eb..43d6f5b 100644
--- a/source/static/js/ui/admin.js
+++ b/source/static/js/ui/admin.js
@@ -784,6 +784,15 @@ var options_admin_complements = [
{view: 'checkbox', id: 'chk_config_edu', labelWidth: 0,
labelRight: 'Usar el complemento EDU'},
{maxWidth: 15}]},
+ {maxHeight: 20},
+ {template: 'Complemento Leyendas Fiscales', type: 'section'},
+ {cols: [{maxWidth: 15},
+ {view: 'checkbox', id: 'chk_config_leyendas_fiscales', labelWidth: 0,
+ labelRight: 'Usar el complemento Leyendas Fiscales'},
+ {view: 'button', id: 'cmd_admin_leyendas_fiscales', label: 'Leyendas Fiscales',
+ type: 'form', align: 'center', autowidth: true, disabled: true},
+ {}, {maxWidth: 15}
+ ]},
]
@@ -1415,3 +1424,73 @@ var body_win_emisor_logo = [
+
+var grid_cols_admin_leyendas_fiscales = [
+ {id: 'id', header: 'ID', hidden: true},
+ {id: 'delete', header: '', width: 30, css: 'delete'},
+ {id: 'texto_leyenda', header: 'Leyenda', fillspace: 1},
+ {id: 'norma', header: 'Norma', fillspace: 1},
+ {id: 'disposicion_fiscal', header: 'Disposición Fiscal', fillspace: 1},
+ //~ {id: 'active', header: 'Activa', template: '{common.checkbox()}',
+ //~ editor: 'checkbox'},
+]
+
+
+var grid_admin_leyendas_fiscales = {
+ view: 'datatable',
+ id: 'grid_admin_leyendas_fiscales',
+ select: 'row',
+ adjust: true,
+ autoheight: true,
+ headermenu: true,
+ columns: grid_cols_admin_leyendas_fiscales,
+ on:{
+ 'data->onStoreUpdated':function(){
+ this.data.each(function(obj, i){
+ obj.delete = '-'
+ })
+ }
+ },
+}
+
+
+var form_controls_admin_leyendas_fiscales = [
+ {cols: [
+ {view: 'text', id: 'txt_texto_leyenda', label: 'Leyenda', width: 200,
+ labelPosition: 'top', name: 'texto_leyenda', required: true},
+ {view: "text", id: 'txt_norma_fiscal', label: 'Norma', width: 200,
+ name: 'norma', labelPosition: 'top'},
+ {view: "text", id: 'txt_disposicion_fiscal', label: 'Disposición',
+ name: 'disposicion_fiscal', labelPosition: 'top', width: 200}
+ ]},
+ {cols: [{},
+ {view: 'button', type: 'form', icon: 'plus', label: 'Agregar', autowidth: true,
+ click: function(){add_admin_leyenda_fiscal_click()}
+ }, {}]},
+ grid_admin_leyendas_fiscales,
+ {},
+ {cols:[{},
+ {view: 'button', value: 'Cerrar', click: "$$('win_leyendas_fiscales').close()"},
+ {}]}
+]
+
+
+var admin_ui_leyendas_fiscales = {
+ init: function(){
+ webix.ui({
+ view: 'window',
+ id: 'win_leyendas_fiscales',
+ head: 'Leyendas Fiscales',
+ width: 800,
+ modal: true,
+ position: 'center',
+ body: {
+ view: 'form', id: 'form_admin_leyendas_fiscales',
+ elements: form_controls_admin_leyendas_fiscales
+ }
+ })
+
+ $$('grid_admin_leyendas_fiscales').attachEvent('onItemClick', grid_admin_leyendas_fiscales_click)
+
+ },
+}
diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js
index 9ff88b3..8e52024 100644
--- a/source/static/js/ui/invoices.js
+++ b/source/static/js/ui/invoices.js
@@ -701,7 +701,7 @@ var opt_tipo_comite = [
]
-var controles_ine = [
+var controls_ine = [
{maxHeight: 15},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_cfdi_usar_ine', labelWidth: 0,
@@ -727,16 +727,45 @@ var controles_ine = [
]
+var grid_cols_leyendas_fiscales = [
+ {id: 'id', header: 'ID', hidden: true},
+ {id: 'texto_leyenda', header: 'Leyenda', fillspace: 2},
+ {id: 'norma', header: 'Norma', fillspace: 1},
+ {id: 'disposicion_fiscal', header: 'Disposición Fiscal', fillspace: 1},
+]
+
+
+var grid_leyendas_fiscales = {
+ view: 'datatable',
+ id: 'grid_leyendas_fiscales',
+ select: 'row',
+ multiselect: true,
+ adjust: true,
+ autoheight: true,
+ headermenu: true,
+ columns: grid_cols_leyendas_fiscales,
+}
+
+var controls_leyendas_fiscales = [
+ {maxHeight: 15},
+ {cols: [{maxWidth: 15},
+ {view: 'label', id: 'lbl_title', label: 'Selecciona las Leyendas Fiscales a integrar en esta factura'},
+ {}]},
+ {maxHeight: 15},
+ grid_leyendas_fiscales,
+]
+
+
var controls_invoices = [
{
view: 'tabview',
id: 'tv_invoice',
- //~ tabbar: {options: ['Generar', 'PreFacturas', 'INE']},
animate: true,
cells: [
{id: 'Generar', rows: controls_generate},
{id: 'PreFacturas', rows: controls_prefactura},
- {id: 'INE', rows: controles_ine},
+ {id: 'INE', rows: controls_ine},
+ {id: 'Leyendas Fiscales', rows: controls_leyendas_fiscales},
]
},
]