Support for tax legends

This commit is contained in:
Mauricio Baeza 2020-03-02 17:27:28 -06:00
commit 763f3c21fb
15 changed files with 501 additions and 27 deletions

View File

@ -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] v 1.36.0 [25-feb-2020]
---------------------- ----------------------

View File

@ -1 +1 @@
1.36.0 1.37.0

View File

@ -3,7 +3,6 @@ falcon-multipart
Beaker Beaker
Mako Mako
peewee==2.10.2 peewee==2.10.2
Click
logbook logbook
bcrypt bcrypt
python-dateutil python-dateutil

View File

@ -90,6 +90,12 @@ SAT = {
'xmlns': 'http://www.sat.gob.mx/divisas', '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', '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._edu = False
self._pagos = False self._pagos = False
self._is_nomina = False self._is_nomina = False
self._leyendas = False
self._divisas = '' self._divisas = ''
self.error = '' self.error = ''
@ -129,8 +136,6 @@ class CFDI(object):
if 'nomina' in datos: if 'nomina' in datos:
self._nomina(datos['nomina']) self._nomina(datos['nomina'])
#~ if 'complementos' in datos:
#~ self._complementos(datos['complementos'])
return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8')) return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
@ -158,6 +163,7 @@ class CFDI(object):
if 'ine' in datos['complementos']: if 'ine' in datos['complementos']:
self._ine = True self._ine = True
self._pagos = bool(datos['complementos'].get('pagos', False)) self._pagos = bool(datos['complementos'].get('pagos', False))
self._leyendas = bool(datos['complementos'].get('leyendas', False))
self._divisas = datos['comprobante'].pop('divisas', '') self._divisas = datos['comprobante'].pop('divisas', '')
@ -217,9 +223,15 @@ class CFDI(object):
attributes[name] = SAT['pagos']['xmlns'] attributes[name] = SAT['pagos']['xmlns']
schema_pagos = SAT['pagos']['schema'] 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'] + \ attributes['xsi:schemaLocation'] = self._sat_cfdi['schema'] + \
schema_locales + schema_donativo + schema_ine + schema_edu + \ 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) attributes.update(datos)
if not 'Version' in attributes: if not 'Version' in attributes:
@ -464,6 +476,14 @@ class CFDI(object):
for row in relacionados: for row in relacionados:
ET.SubElement(node_pago, '{}:DoctoRelacionado'.format(pre), row) 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: if 'ce' in datos:
pre = 'cce11' pre = 'cce11'
datos = datos.pop('ce') datos = datos.pop('ce')

View File

@ -594,6 +594,29 @@ class AppSATFormaPago(object):
resp.status = falcon.HTTP_200 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): class AppSociosCuentasBanco(object):
def __init__(self, db): def __init__(self, db):

View File

@ -1087,6 +1087,28 @@ class LIBO(object):
self._set_cell(f'{{divisas.{k}}}', v) self._set_cell(f'{{divisas.{k}}}', v)
return 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): def _nomina(self, data):
if not data: if not data:
return return
@ -1314,6 +1336,7 @@ class LIBO(object):
self._ine(data['ine']) self._ine(data['ine'])
self._divisas(data.get('divisas', {})) self._divisas(data.get('divisas', {}))
self._leyendas(data['leyendas'])
self._cancelado(data['cancelada']) self._cancelado(data['cancelada'])
self._clean() self._clean()

View File

@ -244,10 +244,13 @@ class CfdiToDict(object):
NS = { NS = {
'cfdi': 'http://www.sat.gob.mx/cfd/3', 'cfdi': 'http://www.sat.gob.mx/cfd/3',
'divisas': 'http://www.sat.gob.mx/divisas', 'divisas': 'http://www.sat.gob.mx/divisas',
'leyendasFisc': 'http://www.sat.gob.mx/leyendasFiscales',
} }
def __init__(self, xml): def __init__(self, xml):
self._values = {} self._values = {
'leyendas': (),
}
self._root = ET.parse(BytesIO(xml.encode())).getroot() self._root = ET.parse(BytesIO(xml.encode())).getroot()
self._get_values() self._get_values()
@ -260,13 +263,21 @@ class CfdiToDict(object):
return return
def _complementos(self): 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: if divisas:
d = CaseInsensitiveDict(divisas[0].attrib) d = CaseInsensitiveDict(divisas[0].attrib)
d.pop('version', '') d.pop('version', '')
self._values.update({'divisas': d}) 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 return

View File

@ -17,7 +17,7 @@ from controllers.main import (AppEmpresas,
AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco, AppDocumentos, AppFiles, AppPreInvoices, AppCuentasBanco,
AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina, AppMovimientosBanco, AppTickets, AppStudents, AppEmployees, AppNomina,
AppInvoicePay, AppCfdiPay, AppSATBancos, AppSociosCuentasBanco, 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('/satbancos', AppSATBancos(db))
api.add_route('/satformapago', AppSATFormaPago(db)) api.add_route('/satformapago', AppSATFormaPago(db))
api.add_route('/socioscb', AppSociosCuentasBanco(db)) api.add_route('/socioscb', AppSociosCuentasBanco(db))
api.add_route('/leyendasfiscales', AppSATLeyendaFiscales(db))
session_options = { session_options = {

View File

@ -462,6 +462,15 @@ class StorageEngine(object):
def nomina(self, values, user): def nomina(self, values, user):
return main.CfdiNomina.post(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 # Companies only in MV
def _get_empresas(self, values): def _get_empresas(self, values):
return main.companies_get() return main.companies_get()

View File

@ -308,6 +308,7 @@ def config_timbrar():
'cfdi_add_same_product': Configuracion.get_bool('chk_config_add_same_product'), '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_tax_locales_truncate': Configuracion.get_bool('chk_config_tax_locales_truncate'),
'cfdi_folio_custom': Configuracion.get_bool('chk_folio_custom'), 'cfdi_folio_custom': Configuracion.get_bool('chk_folio_custom'),
'cfdi_leyendasfiscales': Configuracion.get_bool('chk_config_leyendas_fiscales'),
} }
return conf return conf
@ -432,6 +433,7 @@ class Configuracion(BaseModel):
'chk_config_divisas', 'chk_config_divisas',
'chk_cfg_pays_data_bank', 'chk_cfg_pays_data_bank',
'chk_usar_nomina', 'chk_usar_nomina',
'chk_config_leyendas_fiscales',
) )
data = (Configuracion data = (Configuracion
.select() .select()
@ -2478,6 +2480,83 @@ class SATRiesgoPuesto(BaseModel):
return 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): class TipoCambio(BaseModel):
dia = DateField(default=util.now) dia = DateField(default=util.now)
moneda = ForeignKeyField(SATMonedas) moneda = ForeignKeyField(SATMonedas)
@ -4641,6 +4720,8 @@ class Facturas(BaseModel):
divisas = '' divisas = ''
values['divisas'] = divisas values['divisas'] = divisas
leyendas_fiscales = utils.loads(values.pop('leyendas_fiscales', '[]'))
emisor = Emisor.select()[0] emisor = Emisor.select()[0]
values['serie'] = cls._get_serie(cls, user, values['serie']) values['serie'] = cls._get_serie(cls, user, values['serie'])
if Configuracion.get_bool('chk_folio_custom') and folio_custom: 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) totals = cls._calculate_totals(cls, obj, productos, tipo_comprobante)
cls._guardar_relacionados(cls, obj, relacionados) cls._guardar_relacionados(cls, obj, relacionados)
cls._guardar_ine(cls, obj, ine) cls._guardar_ine(cls, obj, ine)
cls._save_leyendas_fiscales(cls, obj, leyendas_fiscales)
obj.subtotal = totals['subtotal'] obj.subtotal = totals['subtotal']
obj.descuento = totals['descuento'] obj.descuento = totals['descuento']
obj.total_trasladados = totals['total_trasladados'] obj.total_trasladados = totals['total_trasladados']
@ -4695,6 +4777,18 @@ class Facturas(BaseModel):
data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg} data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg}
return data 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): def _make_xml(self, invoice, auth):
tax_decimals = Configuracion.get_bool('chk_config_tax_decimals') tax_decimals = Configuracion.get_bool('chk_config_tax_decimals')
decimales_precios = Configuracion.get_bool('chk_config_decimales_precios') decimales_precios = Configuracion.get_bool('chk_config_decimales_precios')
@ -4709,11 +4803,15 @@ class Facturas(BaseModel):
comprobante = {} comprobante = {}
relacionados = {} relacionados = {}
donativo = {} donativo = {}
complementos = FacturasComplementos.get_(invoice) complementos = FacturasComplementos.get_by_invoice(invoice)
comprobante['divisas'] = invoice.divisas comprobante['divisas'] = invoice.divisas
if invoice.divisas: if invoice.divisas:
complementos['divisas'] = True complementos['divisas'] = True
if 'leyendas' in complementos:
ids = complementos['leyendas']
complementos['leyendas'] = SATLeyendasFiscales.get_by_id(ids)
if invoice.donativo: if invoice.donativo:
donativo['noAutorizacion'] = emisor.autorizacion donativo['noAutorizacion'] = emisor.autorizacion
donativo['fechaAutorizacion'] = str(emisor.fecha_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} 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): class PreFacturasRelacionadas(BaseModel):
factura = ForeignKeyField(PreFacturas, related_name='original') factura = ForeignKeyField(PreFacturas, related_name='original')
@ -9081,7 +9187,7 @@ def _crear_tablas(rfc):
SATNivelesEducativos, SATEstados, SATRiesgoPuesto, SATPeriodicidadPago, SATNivelesEducativos, SATEstados, SATRiesgoPuesto, SATPeriodicidadPago,
SATOrigenRecurso, SATTipoContrato, SATTipoDeduccion, SATTipoHoras, SATOrigenRecurso, SATTipoContrato, SATTipoDeduccion, SATTipoHoras,
SATTipoIncapacidad, SATTipoJornada, SATTipoNomina, SATTipoOtroPago, SATTipoIncapacidad, SATTipoJornada, SATTipoNomina, SATTipoOtroPago,
SATTipoPercepcion, SATTipoRegimen, SATTipoPercepcion, SATTipoRegimen, SATLeyendasFiscales,
Socios, SociosCuentasBanco, Contactos, ContactoCorreos, Socios, SociosCuentasBanco, Contactos, ContactoCorreos,
ContactoDirecciones, Empleados, ContactoTelefonos, Departamentos, ContactoDirecciones, Empleados, ContactoTelefonos, Departamentos,
Puestos, Puestos,
@ -9151,7 +9257,7 @@ def _migrate_tables(rfc=''):
CfdiNominaOtroPago, CfdiNominaOtros, CfdiNominaPercepciones, CfdiNominaOtroPago, CfdiNominaOtros, CfdiNominaPercepciones,
CfdiNominaRelacionados, CfdiNominaSeparacion, CfdiNominaSubcontratos, CfdiNominaRelacionados, CfdiNominaSeparacion, CfdiNominaSubcontratos,
CfdiNominaTotales, SATNivelesEducativos, Roles, Permisos, CfdiNominaTotales, SATNivelesEducativos, Roles, Permisos,
SociosCuentasBanco SociosCuentasBanco, SATLeyendasFiscales
] ]
log.info('Creando tablas nuevas...') log.info('Creando tablas nuevas...')
database_proxy.create_tables(tablas, True) database_proxy.create_tables(tablas, True)
@ -10375,6 +10481,5 @@ def main(args):
if __name__ == '__main__': if __name__ == '__main__':
args = _process_command_line_arguments() args = _process_command_line_arguments()
main(args) main(args)
# ~ main2()

View File

@ -47,7 +47,7 @@ except ImportError:
DEBUG = DEBUG DEBUG = DEBUG
VERSION = '1.36.0' VERSION = '1.37.0'
EMAIL_SUPPORT = ('soporte@empresalibre.mx',) EMAIL_SUPPORT = ('soporte@empresalibre.mx',)
TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION) TITLE_APP = '{} v{}'.format(TITLE_APP, VERSION)

View File

@ -92,6 +92,24 @@ var controllers = {
$$('chk_llevar_inventario').attachEvent('onItemClick', chk_config_item_click) $$('chk_llevar_inventario').attachEvent('onItemClick', chk_config_item_click)
$$('chk_use_packing').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_metodo_pago').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_ocultar_condiciones_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) $$('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_decimales_precios').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_user_show_doc').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_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_usar_punto_de_venta').attachEvent('onItemClick', chk_config_item_click)
$$('chk_ticket_pdf_show').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) $$('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_total_up').attachEvent('onItemClick', chk_config_item_click)
$$('chk_ticket_user_show_doc').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_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) $$('lst_pac').attachEvent('onChange', lst_pac_on_change)
$$('cmd_subir_bdfl').attachEvent('onItemClick', cmd_subir_bdfl_click) $$('cmd_subir_bdfl').attachEvent('onItemClick', cmd_subir_bdfl_click)
@ -471,6 +480,9 @@ function get_config_values(opt){
set_value(key, values[key]) set_value(key, values[key])
}else{ }else{
$$(key).setValue(values[key]) $$(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)
}
})
}

View File

@ -205,6 +205,13 @@ function default_config(){
}else{ }else{
$$('tv_invoice').getTabbar().showOption('INE') $$('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['edu'] = values.cfdi_edu
cfg_invoice['open_pdf'] = values.cfdi_open_pdf cfg_invoice['open_pdf'] = values.cfdi_open_pdf
cfg_invoice['tax_locales'] = values.cfdi_tax_locales cfg_invoice['tax_locales'] = values.cfdi_tax_locales
@ -642,6 +649,8 @@ function guardar_y_timbrar(values){
data['notas'] = values.notas data['notas'] = values.notas
data['folio_custom'] = $$('txt_folio_custom').getValue() data['folio_custom'] = $$('txt_folio_custom').getValue()
data['divisas'] = $$('opt_divisas').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() var usar_ine = $$('chk_cfdi_usar_ine').getValue()
if(usar_ine){ 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<BR><BR>' msg += 'El Tipo de Comprobante es Traslado, el total será puesto a 0 (Cero), asegurate de que sea el tipo de comprobante correcto<BR><BR>'
} }
if(cfg_invoice['leyendasfiscales']){
var rows = $$('grid_leyendas_fiscales').getSelectedId(true, true)
if(rows.length == 0){
msg += 'No se agregará ninguna leyenda fiscal<BR><BR>'
}else if(rows.length == 1){
msg += 'Se agregará una leyenda fiscal<BR><BR>'
}else{
msg += 'Se agregarán ' + rows.length + ' leyendas fiscales<BR><BR>'
}
}
msg += '¿Estás seguro de timbrar esta factura?<BR><BR>' msg += '¿Estás seguro de timbrar esta factura?<BR><BR>'
webix.confirm({ webix.confirm({
@ -2352,3 +2372,20 @@ function search_by_click(){
search_by(value) 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()
}
})
}

View File

@ -784,6 +784,15 @@ var options_admin_complements = [
{view: 'checkbox', id: 'chk_config_edu', labelWidth: 0, {view: 'checkbox', id: 'chk_config_edu', labelWidth: 0,
labelRight: 'Usar el complemento EDU'}, labelRight: 'Usar el complemento EDU'},
{maxWidth: 15}]}, {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)
},
}

View File

@ -701,7 +701,7 @@ var opt_tipo_comite = [
] ]
var controles_ine = [ var controls_ine = [
{maxHeight: 15}, {maxHeight: 15},
{cols: [{maxWidth: 15}, {cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_cfdi_usar_ine', labelWidth: 0, {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 = [ var controls_invoices = [
{ {
view: 'tabview', view: 'tabview',
id: 'tv_invoice', id: 'tv_invoice',
//~ tabbar: {options: ['Generar', 'PreFacturas', 'INE']},
animate: true, animate: true,
cells: [ cells: [
{id: 'Generar', rows: controls_generate}, {id: 'Generar', rows: controls_generate},
{id: 'PreFacturas', rows: controls_prefactura}, {id: 'PreFacturas', rows: controls_prefactura},
{id: 'INE', rows: controles_ine}, {id: 'INE', rows: controls_ine},
{id: 'Leyendas Fiscales', rows: controls_leyendas_fiscales},
] ]
}, },
] ]