commit
c85bd0826e
|
@ -6,6 +6,19 @@ __pycache__/
|
|||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
conf.py
|
||||
source/fixtures
|
||||
source/media
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
docs/
|
||||
*.ods
|
||||
*.xlsx
|
||||
|
||||
credenciales.conf
|
||||
*.sqlite
|
||||
*.sql
|
||||
rfc.db
|
||||
configpac.py
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
falcon
|
||||
falcon-multipart
|
||||
Beaker
|
||||
Mako
|
||||
peewee
|
||||
click
|
||||
logbook
|
||||
bcrypt
|
||||
python-dateutil
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
from peewee import SqliteDatabase
|
||||
|
||||
|
||||
DEBUG = True
|
||||
ID_SUPPORT = ''
|
||||
|
||||
DATABASE = None
|
||||
if DEBUG:
|
||||
DATABASE = SqliteDatabase('empresalibre.sqlite')
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env python
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import datetime
|
||||
from xml.etree import ElementTree as ET
|
||||
from xml.dom.minidom import parseString
|
||||
|
||||
from logbook import Logger
|
||||
|
||||
#~ from settings import DEBUG
|
||||
|
||||
|
||||
log = Logger('XML')
|
||||
CFDI_ACTUAL = 'cfdi33'
|
||||
NOMINA_ACTUAL = 'nomina12'
|
||||
|
||||
SAT = {
|
||||
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'cfdi32': {
|
||||
'version': '3.2',
|
||||
'prefix': 'cfdi',
|
||||
'xmlns': 'http://www.sat.gob.mx/cfd/3',
|
||||
'schema': 'http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv32.xsd',
|
||||
},
|
||||
'cfdi33': {
|
||||
'version': '3.3',
|
||||
'prefix': 'cfdi',
|
||||
'xmlns': 'http://www.sat.gob.mx/cfd/3',
|
||||
'schema': 'http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd',
|
||||
},
|
||||
'nomina11': {
|
||||
'version': '1.1',
|
||||
'prefix': 'nomina',
|
||||
'xmlns': 'http://www.sat.gob.mx/nomina',
|
||||
'schema': 'http://www.sat.gob.mx/nomina http://www.sat.gob.mx/sitio_internet/cfd/nomina/nomina11.xsd',
|
||||
},
|
||||
'nomina12': {
|
||||
'version': '1.2',
|
||||
'prefix': 'nomina',
|
||||
'xmlns': 'http://www.sat.gob.mx/nomina12',
|
||||
'schema': 'http://www.sat.gob.mx/nomina12 http://www.sat.gob.mx/sitio_internet/cfd/nomina/nomina12.xsd',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class CFDI(object):
|
||||
|
||||
def __init__(self, version=CFDI_ACTUAL):
|
||||
self._sat_cfdi = SAT[version]
|
||||
self._xsi = SAT['xsi']
|
||||
self._pre = self._sat_cfdi['prefix']
|
||||
self._cfdi = None
|
||||
self.error = ''
|
||||
|
||||
def _now(self):
|
||||
return datetime.datetime.now().isoformat()[:19]
|
||||
|
||||
def get_xml(self, datos):
|
||||
if not self._validate(datos):
|
||||
return ''
|
||||
|
||||
self._comprobante(datos['comprobante'])
|
||||
self._emisor(datos['emisor'])
|
||||
self._receptor(datos['receptor'])
|
||||
self._conceptos(datos['conceptos'])
|
||||
self._impuestos(datos['impuestos'])
|
||||
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'))
|
||||
|
||||
def add_sello(self, sello):
|
||||
self._cfdi.attrib['Sello'] = sello
|
||||
return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
|
||||
|
||||
def _to_pretty_xml(self, source):
|
||||
tree = parseString(source)
|
||||
xml = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
||||
return xml
|
||||
|
||||
def _validate(self, datos):
|
||||
if 'nomina' in datos:
|
||||
return self._validate_nomina(datos)
|
||||
return True
|
||||
|
||||
def _validate_nomina(self, datos):
|
||||
comprobante = datos['comprobante']
|
||||
|
||||
validators = (
|
||||
('MetodoDePago', 'NA'),
|
||||
('TipoCambio', '1'),
|
||||
('Moneda', 'MXN'),
|
||||
('TipoDeComprobante', 'egreso'),
|
||||
)
|
||||
for f, v in validators:
|
||||
if f in comprobante:
|
||||
if v != comprobante[f]:
|
||||
msg = 'El atributo: {}, debe ser: {}'.format(f, v)
|
||||
self.error = msg
|
||||
return False
|
||||
return True
|
||||
|
||||
def _comprobante(self, datos):
|
||||
attributes = {}
|
||||
attributes['xmlns:{}'.format(self._pre)] = self._sat_cfdi['xmlns']
|
||||
attributes['xmlns:xsi'] = self._xsi
|
||||
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema']
|
||||
attributes.update(datos)
|
||||
|
||||
#~ if DEBUG:
|
||||
#~ attributes['Fecha'] = self._now()
|
||||
#~ attributes['NoCertificado'] = CERT_NUM
|
||||
|
||||
if not 'Version' in attributes:
|
||||
attributes['Version'] = self._sat_cfdi['version']
|
||||
if not 'Fecha' in attributes:
|
||||
attributes['Fecha'] = self._now()
|
||||
|
||||
self._cfdi = ET.Element('{}:Comprobante'.format(self._pre), attributes)
|
||||
return
|
||||
|
||||
def _emisor(self, datos):
|
||||
#~ if DEBUG:
|
||||
#~ datos['Rfc'] = RFC_TEST
|
||||
|
||||
node_name = '{}:Emisor'.format(self._pre)
|
||||
emisor = ET.SubElement(self._cfdi, node_name, datos)
|
||||
return
|
||||
|
||||
def _receptor(self, datos):
|
||||
node_name = '{}:Receptor'.format(self._pre)
|
||||
emisor = ET.SubElement(self._cfdi, node_name, datos)
|
||||
return
|
||||
|
||||
def _conceptos(self, datos):
|
||||
conceptos = ET.SubElement(self._cfdi, '{}:Conceptos'.format(self._pre))
|
||||
for row in datos:
|
||||
complemento = {}
|
||||
if 'complemento' in row:
|
||||
complemento = row.pop('complemento')
|
||||
|
||||
taxes = {}
|
||||
if 'impuestos' in row:
|
||||
taxes = row.pop('impuestos')
|
||||
node_name = '{}:Concepto'.format(self._pre)
|
||||
concepto = ET.SubElement(conceptos, node_name, row)
|
||||
|
||||
if taxes:
|
||||
node_name = '{}:Impuestos'.format(self._pre)
|
||||
impuestos = ET.SubElement(concepto, node_name)
|
||||
if 'traslados' in taxes and taxes['traslados']:
|
||||
node_name = '{}:Traslados'.format(self._pre)
|
||||
traslados = ET.SubElement(impuestos, node_name)
|
||||
for traslado in taxes['traslados']:
|
||||
ET.SubElement(
|
||||
traslados, '{}:Traslado'.format(self._pre), traslado)
|
||||
if 'retenciones' in taxes and taxes['retenciones']:
|
||||
node_name = '{}:Retenciones'.format(self._pre)
|
||||
retenciones = ET.SubElement(impuestos, node_name)
|
||||
for retencion in taxes['retenciones']:
|
||||
ET.SubElement(
|
||||
retenciones, '{}:Retencion'.format(self._pre), retencion)
|
||||
|
||||
if 'InformacionAduanera' in row:
|
||||
for field in fields:
|
||||
if field in row['InformacionAduanera']:
|
||||
attributes[field] = row['InformacionAduanera'][field]
|
||||
if attributes:
|
||||
node_name = '{}:InformacionAduanera'.format(self._pre)
|
||||
ET.SubElement(concepto, node_name, attributes)
|
||||
|
||||
if 'CuentaPredial' in row:
|
||||
attributes = {'numero': row['CuentaPredial']}
|
||||
node_name = '{}:CuentaPredial'.format(self._pre)
|
||||
ET.SubElement(concepto, node_name, attributes)
|
||||
|
||||
if 'autRVOE' in row:
|
||||
fields = (
|
||||
'version',
|
||||
'nombreAlumno',
|
||||
'CURP',
|
||||
'nivelEducativo',
|
||||
'autRVOE',
|
||||
)
|
||||
for field in fields:
|
||||
if field in row['autRVOE']:
|
||||
attributes[field] = row['autRVOE'][field]
|
||||
node_name = '{}:ComplementoConcepto'.format(self._pre)
|
||||
complemento = ET.SubElement(concepto, node_name)
|
||||
ET.SubElement(complemento, 'iedu:instEducativas', attributes)
|
||||
return
|
||||
|
||||
def _impuestos(self, datos):
|
||||
if not datos:
|
||||
node_name = '{}:Impuestos'.format(self._pre)
|
||||
ET.SubElement(self._cfdi, node_name)
|
||||
return
|
||||
|
||||
attributes = {}
|
||||
fields = ('TotalImpuestosTrasladados', 'TotalImpuestosRetenidos')
|
||||
for field in fields:
|
||||
if field in datos:
|
||||
attributes[field] = datos[field]
|
||||
node_name = '{}:Impuestos'.format(self._pre)
|
||||
impuestos = ET.SubElement(self._cfdi, node_name, attributes)
|
||||
|
||||
if 'retenciones' in datos and datos['retenciones']:
|
||||
retenciones = ET.SubElement(impuestos, '{}:Retenciones'.format(self._pre))
|
||||
for row in datos['retenciones']:
|
||||
ET.SubElement(retenciones, '{}:Retencion'.format(self._pre), row)
|
||||
|
||||
if 'traslados' in datos and datos['traslados']:
|
||||
traslados = ET.SubElement(impuestos, '{}:Traslados'.format(self._pre))
|
||||
for row in datos['traslados']:
|
||||
ET.SubElement(traslados, '{}:Traslado'.format(self._pre), row)
|
||||
return
|
||||
|
||||
def _nomina(self, datos):
|
||||
sat_nomina = SAT[NOMINA_ACTUAL]
|
||||
pre = sat_nomina['prefix']
|
||||
complemento = ET.SubElement(self._cfdi, '{}:Complemento'.format(self._pre))
|
||||
|
||||
emisor = datos.pop('Emisor', None)
|
||||
receptor = datos.pop('Receptor', None)
|
||||
percepciones = datos.pop('Percepciones', None)
|
||||
deducciones = datos.pop('Deducciones', None)
|
||||
|
||||
attributes = {}
|
||||
attributes['xmlns:{}'.format(pre)] = sat_nomina['xmlns']
|
||||
attributes['xsi:schemaLocation'] = sat_nomina['schema']
|
||||
attributes.update(datos)
|
||||
|
||||
if not 'Version' in attributes:
|
||||
attributes['Version'] = sat_nomina['version']
|
||||
|
||||
nomina = ET.SubElement(complemento, '{}:Nomina'.format(pre), attributes)
|
||||
if emisor:
|
||||
ET.SubElement(nomina, '{}:Emisor'.format(pre), emisor)
|
||||
if receptor:
|
||||
ET.SubElement(nomina, '{}:Receptor'.format(pre), receptor)
|
||||
if percepciones:
|
||||
detalle = percepciones.pop('detalle', None)
|
||||
percepciones = ET.SubElement(nomina, '{}:Percepciones'.format(pre), percepciones)
|
||||
for row in detalle:
|
||||
ET.SubElement(percepciones, '{}:Percepcion'.format(pre), row)
|
||||
if deducciones:
|
||||
detalle = deducciones.pop('detalle', None)
|
||||
deducciones = ET.SubElement(nomina, '{}:Deducciones'.format(pre), deducciones)
|
||||
for row in detalle:
|
||||
ET.SubElement(deducciones, '{}:Deduccion'.format(pre), row)
|
||||
return
|
||||
|
||||
def _complementos(self, datos):
|
||||
complemento = ET.SubElement(self._cfdi, '{}:Complemento'.format(self._pre))
|
||||
if 'ce' in datos:
|
||||
pre = 'cce11'
|
||||
datos = datos.pop('ce')
|
||||
emisor = datos.pop('emisor')
|
||||
propietario = datos.pop('propietario')
|
||||
receptor = datos.pop('receptor')
|
||||
destinatario = datos.pop('destinatario')
|
||||
conceptos = datos.pop('conceptos')
|
||||
|
||||
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)
|
||||
ce = ET.SubElement(
|
||||
complemento, '{}:ComercioExterior'.format(pre), attributes)
|
||||
|
||||
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)
|
||||
|
||||
if propietario:
|
||||
ET.SubElement(ce, '{}:Propietario'.format(pre), 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)
|
||||
|
||||
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, '{}:Mercancias'.format(pre))
|
||||
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)
|
||||
if detalle:
|
||||
ET.SubElement(
|
||||
concepto, '{}:DescripcionesEspecificas'.format(pre), detalle)
|
||||
return
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import falcon
|
||||
from models.main import get_cp
|
||||
|
||||
|
||||
class AppPostalCode(object):
|
||||
|
||||
def on_get(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = get_cp(values['cp'])
|
||||
resp.status = falcon.HTTP_200
|
|
@ -0,0 +1,213 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import falcon
|
||||
from middleware import get_template
|
||||
|
||||
|
||||
class AppLogin(object):
|
||||
template = 'login.html'
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
@falcon.after(get_template)
|
||||
def on_get(self, req, resp):
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp):
|
||||
session = req.env['beaker.session']
|
||||
values = req.params
|
||||
result = self._db.authenticate(values)
|
||||
if result['login']:
|
||||
session.save()
|
||||
session['user'] = result['user']
|
||||
session['rfc'] = values['rfc']
|
||||
req.context['result'] = result
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
|
||||
class AppLogout(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp):
|
||||
session = req.env['beaker.session']
|
||||
session.delete()
|
||||
resp.status = falcon.HTTP_200
|
||||
raise falcon.HTTPTemporaryRedirect('/')
|
||||
|
||||
|
||||
class AppAdmin(object):
|
||||
template = 'admin.html'
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
@falcon.after(get_template)
|
||||
def on_get(self, req, resp):
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
|
||||
class AppMain(object):
|
||||
template = 'main.html'
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
@falcon.after(get_template)
|
||||
def on_get(self, req, resp):
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
|
||||
class AppValues(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp, table):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.get_values(table, values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp, table):
|
||||
file_object = req.get_param('upload')
|
||||
if file_object is None:
|
||||
session = req.env['beaker.session']
|
||||
values = req.params
|
||||
req.context['result'] = self._db.validate_cert(values, session)
|
||||
else:
|
||||
req.context['result'] = self._db.add_cert(file_object)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
|
||||
|
||||
class AppPartners(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.get_partners(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.partner(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_delete(self, req, resp):
|
||||
values = req.params
|
||||
if self._db.delete('partner', values['id']):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_204
|
||||
|
||||
|
||||
class AppProducts(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.get_products(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.product(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_delete(self, req, resp):
|
||||
values = req.params
|
||||
if self._db.delete('product', values['id']):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_204
|
||||
|
||||
|
||||
class AppInvoices(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.get_invoices(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.invoice(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_delete(self, req, resp):
|
||||
values = req.params
|
||||
if self._db.delete('invoice', values['id']):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_204
|
||||
|
||||
|
||||
class AppEmisor(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp):
|
||||
values = req.params
|
||||
session = req.env['beaker.session']
|
||||
req.context['result'] = self._db.get_emisor(session['rfc'])
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.emisor(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_delete(self, req, resp):
|
||||
values = req.params
|
||||
if self._db.delete('invoice', values['id']):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_204
|
||||
|
||||
|
||||
class AppFolios(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
|
||||
def on_get(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.get_folios()
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_post(self, req, resp):
|
||||
values = req.params
|
||||
req.context['result'] = self._db.add_folios(values)
|
||||
resp.status = falcon.HTTP_200
|
||||
|
||||
def on_delete(self, req, resp):
|
||||
values = req.params
|
||||
if self._db.delete('folios', values['id']):
|
||||
resp.status = falcon.HTTP_200
|
||||
else:
|
||||
resp.status = falcon.HTTP_204
|
||||
|
||||
|
||||
class AppDocumentos(object):
|
||||
|
||||
def __init__(self, db):
|
||||
self._db = db
|
||||
#~ self._not_json = True
|
||||
|
||||
def on_get(self, req, resp, type_doc, id_doc):
|
||||
req.context['result'], file_name, content_type = \
|
||||
self._db.get_doc(type_doc, id_doc)
|
||||
resp.append_header('Content-Disposition',
|
||||
'attachment; filename={}'.format(file_name))
|
||||
resp.content_type = content_type
|
||||
resp.status = falcon.HTTP_200
|
|
@ -0,0 +1,609 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#~ import re
|
||||
#~ from xml.etree import ElementTree as ET
|
||||
#~ from requests import Request, Session, exceptions
|
||||
import datetime
|
||||
import hashlib
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
from lxml import etree
|
||||
from xml.dom.minidom import parseString
|
||||
from xml.sax.saxutils import escape, unescape
|
||||
from uuid import UUID
|
||||
|
||||
from logbook import Logger
|
||||
from zeep import Client
|
||||
from zeep.plugins import HistoryPlugin
|
||||
from zeep.cache import SqliteCache
|
||||
from zeep.transports import Transport
|
||||
from zeep.exceptions import Fault, TransportError
|
||||
|
||||
from .configpac import DEBUG, TIMEOUT, AUTH, URL
|
||||
|
||||
|
||||
log = Logger('PAC')
|
||||
#~ node = client.create_message(client.service, SERVICE, **args)
|
||||
#~ print(etree.tostring(node, pretty_print=True).decode())
|
||||
|
||||
|
||||
class Ecodex(object):
|
||||
|
||||
def __init__(self):
|
||||
self.codes = URL['codes']
|
||||
self.error = ''
|
||||
self.message = ''
|
||||
self._transport = Transport(cache=SqliteCache(), timeout=TIMEOUT)
|
||||
self._plugins = None
|
||||
self._history = None
|
||||
if DEBUG:
|
||||
self._history = HistoryPlugin()
|
||||
self._plugins = [self._history]
|
||||
|
||||
def _get_token(self, rfc):
|
||||
client = Client(URL['seguridad'],
|
||||
transport=self._transport, plugins=self._plugins)
|
||||
try:
|
||||
result = client.service.ObtenerToken(rfc, self._get_epoch())
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
log.error(self.error)
|
||||
return ''
|
||||
|
||||
s = '{}|{}'.format(AUTH['ID'], result.Token)
|
||||
return hashlib.sha1(s.encode()).hexdigest()
|
||||
|
||||
def _get_token_rest(self, rfc):
|
||||
data = {
|
||||
'rfc': rfc,
|
||||
'grant_type': 'authorization_token',
|
||||
}
|
||||
headers = {'Content-type': 'application/x-www-form-urlencoded'}
|
||||
result = requests.post(URL['token'], data=data, headers=headers)
|
||||
data = result.json()
|
||||
s = '{}|{}'.format(AUTH['ID'], data['service_token'])
|
||||
return hashlib.sha1(s.encode()).hexdigest(), data['access_token']
|
||||
|
||||
def _validate_xml(self, xml):
|
||||
NS_CFDI = {'cfdi': 'http://www.sat.gob.mx/cfd/3'}
|
||||
if os.path.isfile(xml):
|
||||
tree = etree.parse(xml).getroot()
|
||||
else:
|
||||
tree = etree.fromstring(xml.encode())
|
||||
|
||||
fecha = tree.get('Fecha')
|
||||
rfc = tree.xpath('string(//cfdi:Emisor/@Rfc)', namespaces=NS_CFDI)
|
||||
data = {
|
||||
'ComprobanteXML': etree.tostring(tree).decode(),
|
||||
'RFC': rfc,
|
||||
'Token': self._get_token(rfc),
|
||||
'TransaccionID': self._get_epoch(fecha),
|
||||
}
|
||||
return data
|
||||
|
||||
def _get_by_hash(self, sh, rfc):
|
||||
token, access_token = self._get_token_rest(rfc)
|
||||
url = URL['hash'].format(sh)
|
||||
headers = {
|
||||
'Authorization': 'Bearer {}'.format(access_token),
|
||||
'X-Auth-Token': token,
|
||||
}
|
||||
result = requests.get(url, headers=headers)
|
||||
if result.status_code == 200:
|
||||
print (result.json())
|
||||
return
|
||||
|
||||
def timbra_xml(self, xml):
|
||||
data = self._validate_xml(xml)
|
||||
client = Client(URL['timbra'],
|
||||
transport=self._transport, plugins=self._plugins)
|
||||
try:
|
||||
result = client.service.TimbraXML(**data)
|
||||
except Fault as e:
|
||||
error = str(e)
|
||||
if self.codes['HASH'] in error:
|
||||
sh = error.split(' ')[3]
|
||||
return self._get_by_hash(sh[:40], data['RFC'])
|
||||
self.error = error
|
||||
return ''
|
||||
|
||||
tree = parseString(result.ComprobanteXML.DatosXML)
|
||||
xml = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
||||
return xml
|
||||
|
||||
def _get_epoch(self, date=None):
|
||||
if isinstance(date, str):
|
||||
f = '%Y-%m-%dT%H:%M:%S'
|
||||
e = int(time.mktime(time.strptime(date, f)))
|
||||
else:
|
||||
date = datetime.datetime.now()
|
||||
e = int(time.mktime(date.timetuple()))
|
||||
return e
|
||||
|
||||
def estatus_cuenta(self, rfc):
|
||||
#~ Codigos:
|
||||
#~ 100 = Cuenta encontrada
|
||||
#~ 101 = RFC no dado de alta en el sistema ECODEX
|
||||
token = self._get_token(rfc)
|
||||
if not token:
|
||||
return {}
|
||||
|
||||
data = {
|
||||
'RFC': rfc,
|
||||
'Token': token,
|
||||
'TransaccionID': self._get_epoch()
|
||||
}
|
||||
client = Client(URL['clients'],
|
||||
transport=self._transport, plugins=self._plugins)
|
||||
try:
|
||||
result = client.service.EstatusCuenta(**data)
|
||||
except Fault as e:
|
||||
log.error(str(e))
|
||||
return
|
||||
#~ print (result)
|
||||
return result.Estatus
|
||||
|
||||
|
||||
class Finkok(object):
|
||||
|
||||
def __init__(self):
|
||||
self.codes = URL['codes']
|
||||
self.error = ''
|
||||
self.message = ''
|
||||
self._transport = Transport(cache=SqliteCache(), timeout=TIMEOUT)
|
||||
self._plugins = None
|
||||
self._history = None
|
||||
self.uuid = ''
|
||||
self.fecha = None
|
||||
if DEBUG:
|
||||
self._history = HistoryPlugin()
|
||||
self._plugins = [self._history]
|
||||
|
||||
def _debug(self):
|
||||
if not DEBUG:
|
||||
return
|
||||
print('SEND', self._history.last_sent)
|
||||
print('RESULT', self._history.last_received)
|
||||
return
|
||||
|
||||
def _check_result(self, method, result):
|
||||
#~ print ('CODE', result.CodEstatus)
|
||||
#~ print ('INCIDENCIAS', result.Incidencias)
|
||||
self.message = ''
|
||||
MSG = {
|
||||
'OK': 'Comprobante timbrado satisfactoriamente',
|
||||
'307': 'Comprobante timbrado previamente',
|
||||
}
|
||||
status = result.CodEstatus
|
||||
if status is None and result.Incidencias:
|
||||
for i in result.Incidencias['Incidencia']:
|
||||
self.error += 'Error: {}\n{}'.format(
|
||||
i['CodigoError'], i['MensajeIncidencia'])
|
||||
return ''
|
||||
|
||||
if method == 'timbra' and status in (MSG['OK'], MSG['307']):
|
||||
#~ print ('UUID', result.UUID)
|
||||
#~ print ('FECHA', result.Fecha)
|
||||
if status == MSG['307']:
|
||||
self.message = MSG['307']
|
||||
tree = parseString(result.xml)
|
||||
response = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
||||
self.uuid = result.UUID
|
||||
self.fecha = result.Fecha
|
||||
|
||||
return response
|
||||
|
||||
def _load_file(self, path):
|
||||
try:
|
||||
with open(path, 'rb') as f:
|
||||
data = f.read()
|
||||
except Exception as e:
|
||||
self.error = str(e)
|
||||
return
|
||||
return data
|
||||
|
||||
def _validate_xml(self, file_xml):
|
||||
if os.path.isfile(file_xml):
|
||||
try:
|
||||
with open(file_xml, 'rb') as f:
|
||||
xml = f.read()
|
||||
except Exception as e:
|
||||
self.error = str(e)
|
||||
return False, ''
|
||||
else:
|
||||
xml = file_xml.encode('utf-8')
|
||||
return True, xml
|
||||
|
||||
def _validate_uuid(self, uuid):
|
||||
try:
|
||||
UUID(uuid)
|
||||
return True
|
||||
except ValueError:
|
||||
self.error = 'UUID no válido: {}'.format(uuid)
|
||||
return False
|
||||
|
||||
def timbra_xml(self, file_xml):
|
||||
self.error = ''
|
||||
method = 'timbra'
|
||||
ok, xml = self._validate_xml(file_xml)
|
||||
if not ok:
|
||||
return ''
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'xml': xml,
|
||||
}
|
||||
if URL['quick_stamp']:
|
||||
try:
|
||||
result = client.service.quick_stamp(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return
|
||||
else:
|
||||
try:
|
||||
result = client.service.stamp(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return
|
||||
|
||||
return self._check_result(method, result)
|
||||
|
||||
def _get_xml(self, uuid):
|
||||
if not self._validate_uuid(uuid):
|
||||
return ''
|
||||
|
||||
method = 'util'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'uuid': uuid,
|
||||
'taxpayer_id': self.rfc,
|
||||
'invoice_type': 'I',
|
||||
}
|
||||
try:
|
||||
result = client.service.get_xml(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
except TransportError as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
if result.error:
|
||||
self.error = result.error
|
||||
return ''
|
||||
|
||||
tree = parseString(result.xml)
|
||||
xml = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
||||
return xml
|
||||
|
||||
def recupera_xml(self, file_xml='', uuid=''):
|
||||
self.error = ''
|
||||
if uuid:
|
||||
return self._get_xml(uuid)
|
||||
|
||||
method = 'timbra'
|
||||
ok, xml = self._validate_xml(file_xml)
|
||||
if not ok:
|
||||
return ''
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
try:
|
||||
result = client.service.stamped(xml, AUTH['USER'], AUTH['PASS'])
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return self._check_result(method, result)
|
||||
|
||||
def estatus_xml(self, uuid):
|
||||
method = 'timbra'
|
||||
if not self._validate_uuid(uuid):
|
||||
return ''
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
try:
|
||||
result = client.service.query_pending(AUTH['USER'], AUTH['PASS'], uuid)
|
||||
#~ print (result.date)
|
||||
#~ tree = parseString(unescape(result.xml))
|
||||
#~ response = tree.toprettyxml(encoding='utf-8').decode('utf-8')
|
||||
return result.status
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
def cancel_xml(self, rfc, uuids, path_cer, path_key):
|
||||
for u in uuids:
|
||||
if not self._validate_uuid(u):
|
||||
return ''
|
||||
|
||||
cer = self._load_file(path_cer)
|
||||
key = self._load_file(path_key)
|
||||
method = 'cancel'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
uuid_type = client.get_type('ns1:UUIDS')
|
||||
sa = client.get_type('ns0:stringArray')
|
||||
|
||||
args = {
|
||||
'UUIDS': uuid_type(uuids=sa(string=uuids)),
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'taxpayer_id': rfc,
|
||||
'cer': cer,
|
||||
'key': key,
|
||||
'store_pending': True,
|
||||
}
|
||||
try:
|
||||
result = client.service.cancel(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
if result.CodEstatus and self.codes['205'] in result.CodEstatus:
|
||||
self.error = result.CodEstatus
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
def cancel_signature(self, file_xml):
|
||||
method = 'cancel'
|
||||
if os.path.isfile(file_xml):
|
||||
root = etree.parse(file_xml).getroot()
|
||||
else:
|
||||
root = etree.fromstring(file_xml)
|
||||
|
||||
xml = etree.tostring(root)
|
||||
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'xml': xml,
|
||||
'store_pending': True,
|
||||
}
|
||||
|
||||
result = client.service.cancel_signature(**args)
|
||||
return result
|
||||
|
||||
def get_acuse(self, rfc, uuids, type_acuse='C'):
|
||||
for u in uuids:
|
||||
if not self._validate_uuid(u):
|
||||
return ''
|
||||
|
||||
method = 'cancel'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'taxpayer_id': rfc,
|
||||
'uuid': '',
|
||||
'type': type_acuse,
|
||||
}
|
||||
try:
|
||||
result = []
|
||||
for u in uuids:
|
||||
args['uuid'] = u
|
||||
r = client.service.get_receipt(**args)
|
||||
result.append(r)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
def estatus_cancel(self, uuids):
|
||||
for u in uuids:
|
||||
if not self._validate_uuid(u):
|
||||
return ''
|
||||
|
||||
method = 'cancel'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'uuid': '',
|
||||
}
|
||||
try:
|
||||
result = []
|
||||
for u in uuids:
|
||||
args['uuid'] = u
|
||||
r = client.service.query_pending_cancellation(**args)
|
||||
result.append(r)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
def add_token(self, rfc, email):
|
||||
"""
|
||||
Se requiere cuenta de reseller para usar este método
|
||||
"""
|
||||
method = 'util'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'name': rfc,
|
||||
'token_username': email,
|
||||
'taxpayer_id': rfc,
|
||||
'status': True,
|
||||
}
|
||||
result = client.service.add_token(**args)
|
||||
return result
|
||||
|
||||
def get_date(self):
|
||||
method = 'util'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
try:
|
||||
result = client.service.datetime(AUTH['USER'], AUTH['PASS'])
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
if result.error:
|
||||
self.error = result.error
|
||||
return
|
||||
|
||||
return result.datetime
|
||||
|
||||
def add_client(self, rfc, type_user=False):
|
||||
"""
|
||||
Se requiere cuenta de reseller para usar este método
|
||||
type_user: False == 'P' == Prepago or True == 'O' == On demand
|
||||
"""
|
||||
tu = {False: 'P', True: 'O'}
|
||||
method = 'client'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
args = {
|
||||
'reseller_username': AUTH['USER'],
|
||||
'reseller_password': AUTH['PASS'],
|
||||
'taxpayer_id': rfc,
|
||||
'type_user': tu[type_user],
|
||||
'added': datetime.datetime.now().isoformat()[:19],
|
||||
}
|
||||
try:
|
||||
result = client.service.add(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
def edit_client(self, rfc, status=True):
|
||||
"""
|
||||
Se requiere cuenta de reseller para usar este método
|
||||
status = 'A' or 'S'
|
||||
"""
|
||||
sv = {False: 'S', True: 'A'}
|
||||
method = 'client'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
args = {
|
||||
'reseller_username': AUTH['USER'],
|
||||
'reseller_password': AUTH['PASS'],
|
||||
'taxpayer_id': rfc,
|
||||
'status': sv[status],
|
||||
}
|
||||
try:
|
||||
result = client.service.edit(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
def get_client(self, rfc):
|
||||
"""
|
||||
Se requiere cuenta de reseller para usar este método
|
||||
"""
|
||||
method = 'client'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
args = {
|
||||
'reseller_username': AUTH['USER'],
|
||||
'reseller_password': AUTH['PASS'],
|
||||
'taxpayer_id': rfc,
|
||||
}
|
||||
|
||||
try:
|
||||
result = client.service.get(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
except TransportError as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
def assign_client(self, rfc, credit):
|
||||
"""
|
||||
Se requiere cuenta de reseller para usar este método
|
||||
"""
|
||||
method = 'client'
|
||||
client = Client(
|
||||
URL[method], transport=self._transport, plugins=self._plugins)
|
||||
args = {
|
||||
'username': AUTH['USER'],
|
||||
'password': AUTH['PASS'],
|
||||
'taxpayer_id': rfc,
|
||||
'credit': credit,
|
||||
}
|
||||
try:
|
||||
result = client.service.assign(**args)
|
||||
except Fault as e:
|
||||
self.error = str(e)
|
||||
return ''
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _get_data_sat(path):
|
||||
BF = 'string(//*[local-name()="{}"]/@{})'
|
||||
NS_CFDI = {'cfdi': 'http://www.sat.gob.mx/cfd/3'}
|
||||
|
||||
try:
|
||||
if os.path.isfile(path):
|
||||
tree = etree.parse(path).getroot()
|
||||
else:
|
||||
tree = etree.fromstring(path)
|
||||
|
||||
data = {}
|
||||
emisor = escape(
|
||||
tree.xpath('string(//cfdi:Emisor/@rfc)', namespaces=NS_CFDI) or
|
||||
tree.xpath('string(//cfdi:Emisor/@Rfc)', namespaces=NS_CFDI)
|
||||
)
|
||||
receptor = escape(
|
||||
tree.xpath('string(//cfdi:Receptor/@rfc)', namespaces=NS_CFDI) or
|
||||
tree.xpath('string(//cfdi:Receptor/@Rfc)', namespaces=NS_CFDI)
|
||||
)
|
||||
data['total'] = tree.get('total') or tree.get('Total')
|
||||
data['emisor'] = emisor
|
||||
data['receptor'] = receptor
|
||||
data['uuid'] = tree.xpath(BF.format('TimbreFiscalDigital', 'UUID'))
|
||||
except Exception as e:
|
||||
print (e)
|
||||
return {}
|
||||
|
||||
return '?re={emisor}&rr={receptor}&tt={total}&id={uuid}'.format(**data)
|
||||
|
||||
|
||||
def get_status_sat(xml):
|
||||
data = _get_data_sat(xml)
|
||||
if not data:
|
||||
return
|
||||
|
||||
URL = 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl'
|
||||
client = Client(URL, transport=Transport(cache=SqliteCache()))
|
||||
try:
|
||||
result = client.service.Consulta(expresionImpresa=data)
|
||||
except Exception as e:
|
||||
return 'Error: {}'.format(str(e))
|
||||
|
||||
return result.Estado
|
||||
|
||||
|
||||
def main():
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,401 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import datetime
|
||||
import getpass
|
||||
import hashlib
|
||||
import json
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unicodedata
|
||||
import uuid
|
||||
|
||||
from dateutil import parser
|
||||
|
||||
from settings import DEBUG, log, template_lookup, COMPANIES, DB_SAT, \
|
||||
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL
|
||||
|
||||
|
||||
#~ def _get_hash(password):
|
||||
#~ return bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
||||
|
||||
|
||||
#~ def validate_password(hashed, password):
|
||||
#~ return bcrypt.hashpw(password.encode(), hashed.encode()) == hashed.encode()
|
||||
|
||||
|
||||
def _call(args):
|
||||
return subprocess.check_output(args, shell=True).decode()
|
||||
|
||||
|
||||
def _get_md5(data):
|
||||
return hashlib.md5(data.encode()).hexdigest()
|
||||
|
||||
|
||||
def _save_temp(data, modo='wb'):
|
||||
path = tempfile.mkstemp()[1]
|
||||
with open(path, modo) as f:
|
||||
f.write(data)
|
||||
return path
|
||||
|
||||
|
||||
def _join(*paths):
|
||||
return os.path.join(*paths)
|
||||
|
||||
|
||||
def _kill(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except:
|
||||
pass
|
||||
return
|
||||
|
||||
|
||||
def get_pass():
|
||||
password = getpass.getpass('Introduce la contraseña: ')
|
||||
pass2 = getpass.getpass('Confirma la contraseña: ')
|
||||
|
||||
if password != pass2:
|
||||
msg = 'Las contraseñas son diferentes'
|
||||
return False, msg
|
||||
password = password.strip()
|
||||
if not password:
|
||||
msg = 'La contraseña es necesaria'
|
||||
return False, msg
|
||||
|
||||
return True, password
|
||||
|
||||
|
||||
def get_value(arg):
|
||||
value = input('Introduce el {}: '.format(arg)).strip()
|
||||
if not value:
|
||||
msg = 'El {} es requerido'.format(arg)
|
||||
log.error(msg)
|
||||
return ''
|
||||
return value
|
||||
|
||||
|
||||
def _get_args(rfc):
|
||||
con = sqlite3.connect(COMPANIES)
|
||||
cursor = con.cursor()
|
||||
sql = "SELECT con FROM names WHERE rfc=?"
|
||||
cursor.execute(sql, (rfc,))
|
||||
values = cursor.fetchone()
|
||||
if values is None:
|
||||
msg = 'No se encontró el RFC'
|
||||
log.error(msg)
|
||||
return ''
|
||||
|
||||
cursor.close()
|
||||
con.close()
|
||||
return values[0]
|
||||
|
||||
|
||||
def get_con(rfc=''):
|
||||
if not rfc:
|
||||
rfc = get_value('RFC').upper()
|
||||
if not rfc:
|
||||
return False
|
||||
|
||||
args = _get_args(rfc.upper())
|
||||
if not args:
|
||||
return False
|
||||
return loads(args)
|
||||
|
||||
|
||||
def get_rfcs():
|
||||
con = sqlite3.connect(COMPANIES)
|
||||
cursor = con.cursor()
|
||||
sql = "SELECT * FROM names"
|
||||
cursor.execute(sql)
|
||||
values = cursor.fetchall()
|
||||
cursor.close()
|
||||
con.close()
|
||||
return values
|
||||
|
||||
|
||||
def get_sat_key(table, key):
|
||||
con = sqlite3.connect(DB_SAT)
|
||||
cursor = con.cursor()
|
||||
sql = 'SELECT key, description FROM {} WHERE key=?'.format(table)
|
||||
cursor.execute(sql, (key,))
|
||||
data = cursor.fetchone()
|
||||
cursor.close()
|
||||
con.close()
|
||||
if data is None:
|
||||
return {'ok': False, 'text': 'No se encontró la clave'}
|
||||
return {'ok': True, 'text': data[1]}
|
||||
|
||||
|
||||
def now():
|
||||
return datetime.datetime.now().replace(microsecond=0)
|
||||
|
||||
|
||||
def get_token():
|
||||
return _get_hash(uuid.uuid4().hex)
|
||||
|
||||
|
||||
def get_mimetype(path):
|
||||
mt = mimetypes.guess_type(path)[0]
|
||||
return mt or 'application/octet-stream'
|
||||
|
||||
|
||||
def is_file(path):
|
||||
return os.path.isfile(path)
|
||||
|
||||
|
||||
def get_stream(path):
|
||||
return get_file(path), get_size(path)
|
||||
|
||||
|
||||
def get_file(path):
|
||||
return open(path, 'rb')
|
||||
|
||||
|
||||
def get_size(path):
|
||||
return os.path.getsize(path)
|
||||
|
||||
|
||||
def get_template(name, data={}):
|
||||
#~ print ('NAME', name, data)
|
||||
template = template_lookup.get_template(name)
|
||||
return template.render(**data)
|
||||
|
||||
|
||||
def dumps(data):
|
||||
return json.dumps(data, default=str)
|
||||
|
||||
|
||||
def loads(data):
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def clean(values):
|
||||
for k, v in values.items():
|
||||
if isinstance(v, str):
|
||||
values[k] = v.strip()
|
||||
return values
|
||||
|
||||
|
||||
def parse_con(values):
|
||||
data = values.split('|')
|
||||
try:
|
||||
con = {'type': data[0]}
|
||||
if con['type'] == 'sqlite':
|
||||
con['name'] = data[1]
|
||||
else:
|
||||
if data[1]:
|
||||
con['host'] = data[1]
|
||||
if data[2]:
|
||||
con['port'] = data[2]
|
||||
con['name'] = data[3]
|
||||
con['user'] = data[4]
|
||||
con['password'] = data[5]
|
||||
return con
|
||||
except IndexError:
|
||||
return {}
|
||||
|
||||
|
||||
def spaces(value):
|
||||
return ' '.join(value.split())
|
||||
|
||||
|
||||
def to_slug(string):
|
||||
value = (unicodedata.normalize('NFKD', string)
|
||||
.encode('ascii', 'ignore')
|
||||
.decode('ascii').lower())
|
||||
return value
|
||||
|
||||
|
||||
class Certificado(object):
|
||||
|
||||
def __init__(self, key, cer):
|
||||
self._key = key
|
||||
self._cer = cer
|
||||
self._modulus = ''
|
||||
self._save_files()
|
||||
self.error = ''
|
||||
|
||||
def _save_files(self):
|
||||
try:
|
||||
self._path_key = _save_temp(self._key)
|
||||
self._path_cer = _save_temp(self._cer)
|
||||
except:
|
||||
self._path_key = ''
|
||||
self._path_cer = ''
|
||||
return
|
||||
|
||||
def _kill(self, path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except:
|
||||
pass
|
||||
return
|
||||
|
||||
def _get_info_cer(self, session_rfc):
|
||||
data = {}
|
||||
args = 'openssl x509 -inform DER -in {}'
|
||||
try:
|
||||
cer_pem = _call(args.format(self._path_cer))
|
||||
except Exception as e:
|
||||
self.error = 'No se pudo convertir el CER en PEM'
|
||||
return data
|
||||
|
||||
args = 'openssl enc -base64 -in {}'
|
||||
try:
|
||||
cer_txt = _call(args.format(self._path_cer))
|
||||
except Exception as e:
|
||||
self.error = 'No se pudo convertir el CER en TXT'
|
||||
return data
|
||||
|
||||
args = 'openssl x509 -inform DER -in {} -noout -{}'
|
||||
try:
|
||||
result = _call(args.format(self._path_cer, 'purpose')).split('\n')[3]
|
||||
except Exception as e:
|
||||
self.error = 'No se puede saber si es FIEL'
|
||||
return data
|
||||
|
||||
if result == 'SSL server : No':
|
||||
self.error = 'El certificado es FIEL'
|
||||
return data
|
||||
|
||||
result = _call(args.format(self._path_cer, 'serial'))
|
||||
serie = result.split('=')[1].split('\n')[0][1::2]
|
||||
result = _call(args.format(self._path_cer, 'subject'))
|
||||
rfc = result.split('=')[5].split('/')[0].strip()
|
||||
|
||||
if not DEBUG:
|
||||
if not rfc == session_rfc:
|
||||
self.error = 'El RFC del certificado no corresponde.'
|
||||
return data
|
||||
|
||||
dates = _call(args.format(self._path_cer, 'dates')).split('\n')
|
||||
desde = parser.parse(dates[0].split('=')[1])
|
||||
hasta = parser.parse(dates[1].split('=')[1])
|
||||
self._modulus = _call(args.format(self._path_cer, 'modulus'))
|
||||
|
||||
data['cer'] = self._cer
|
||||
data['cer_tmp'] = None
|
||||
data['cer_pem'] = cer_pem
|
||||
data['cer_txt'] = cer_txt.replace('\n', '')
|
||||
data['serie'] = serie
|
||||
data['rfc'] = rfc
|
||||
data['desde'] = desde
|
||||
data['hasta'] = hasta
|
||||
return data
|
||||
|
||||
def _get_p12(self, password, rfc):
|
||||
tmp_cer = tempfile.mkstemp()[1]
|
||||
tmp_key = tempfile.mkstemp()[1]
|
||||
tmp_p12 = tempfile.mkstemp()[1]
|
||||
|
||||
args = 'openssl x509 -inform DER -in "{}" -out "{}"'
|
||||
_call(args.format(self._path_cer, tmp_cer))
|
||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:{} -out "{}"'
|
||||
_call(args.format(self._path_key, password, tmp_key))
|
||||
|
||||
args = 'openssl pkcs12 -export -in "{}" -inkey "{}" -name "{}" -passout ' \
|
||||
'pass:"{}" -out "{}"'
|
||||
_call(args.format(tmp_cer, tmp_key, rfc,
|
||||
hashlib.md5(rfc.encode()).hexdigest(), tmp_p12))
|
||||
data = open(tmp_p12, 'rb').read()
|
||||
|
||||
self._kill(tmp_cer)
|
||||
self._kill(tmp_key)
|
||||
self._kill(tmp_p12)
|
||||
|
||||
return data
|
||||
|
||||
def _get_info_key(self, password, rfc):
|
||||
data = {}
|
||||
|
||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:{}'
|
||||
try:
|
||||
result = _call(args.format(self._path_key, password))
|
||||
except Exception as e:
|
||||
self.error = 'Contraseña incorrecta'
|
||||
return data
|
||||
|
||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:{} | ' \
|
||||
'openssl rsa -noout -modulus'
|
||||
mod_key = _call(args.format(self._path_key, password))
|
||||
|
||||
if self._modulus != mod_key:
|
||||
self.error = 'Los archivos no son pareja'
|
||||
return data
|
||||
|
||||
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:{} | ' \
|
||||
'openssl rsa -des3 -passout pass:{}'.format(
|
||||
self._path_key, password, _get_md5(rfc))
|
||||
key_enc = _call(args)
|
||||
|
||||
data['key'] = self._key
|
||||
data['key_tmp'] = None
|
||||
data['key_enc'] = key_enc
|
||||
data['p12'] = self._get_p12(password, rfc)
|
||||
return data
|
||||
|
||||
def validate(self, password, rfc):
|
||||
if not self._path_key or not self._path_cer:
|
||||
self.error = 'Error al cargar el certificado'
|
||||
return {}
|
||||
|
||||
data = self._get_info_cer(rfc)
|
||||
llave = self._get_info_key(password, data['rfc'])
|
||||
if not llave:
|
||||
return {}
|
||||
|
||||
data.update(llave)
|
||||
|
||||
self._kill(self._path_key)
|
||||
self._kill(self._path_cer)
|
||||
return data
|
||||
|
||||
|
||||
def make_xml(data, certificado):
|
||||
from .cfdi_xml import CFDI
|
||||
|
||||
if DEBUG:
|
||||
data['emisor']['Rfc'] = certificado.rfc
|
||||
data['emisor']['RegimenFiscal'] = '603'
|
||||
|
||||
cfdi = CFDI()
|
||||
xml = cfdi.get_xml(data)
|
||||
|
||||
data = {
|
||||
'xsltproc': PATH_XSLTPROC,
|
||||
'xslt': _join(PATH_XSLT, 'cadena.xslt'),
|
||||
'xml': _save_temp(xml, 'w'),
|
||||
'openssl': PATH_OPENSSL,
|
||||
'key': _save_temp(certificado.key_enc, 'w'),
|
||||
'pass': _get_md5(certificado.rfc)
|
||||
}
|
||||
args = '"{xsltproc}" "{xslt}" "{xml}" | ' \
|
||||
'"{openssl}" dgst -sha256 -sign "{key}" -passin pass:{pass} | ' \
|
||||
'"{openssl}" enc -base64 -A'.format(**data)
|
||||
sello = _call(args)
|
||||
|
||||
_kill(data['xml'])
|
||||
_kill(data['key'])
|
||||
|
||||
return cfdi.add_sello(sello)
|
||||
|
||||
|
||||
def timbra_xml(xml):
|
||||
from .pac import Finkok as PAC
|
||||
|
||||
result = {'ok': True, 'error': ''}
|
||||
pac = PAC()
|
||||
xml = pac.timbra_xml(xml)
|
||||
if not xml:
|
||||
result['ok'] = False
|
||||
result['error'] = pac.error
|
||||
return result
|
||||
|
||||
result['xml'] = xml
|
||||
result['uuid'] = pac.uuid
|
||||
result['fecha'] = pac.fecha
|
||||
return result
|
|
@ -0,0 +1,13 @@
|
|||
[uwsgi]
|
||||
socket = 127.0.0.1:3032
|
||||
uid = nginx
|
||||
gid = nginx
|
||||
chdir = /srv/app/empresalibre/app
|
||||
wsgi-file = main.py
|
||||
callable = app
|
||||
master = true
|
||||
processes = 4
|
||||
threads = 4
|
||||
thunder-lock = true
|
||||
#~ stats = 127.0.0.1:9191
|
||||
logger = file:/srv/log/empresalibre-uwsgi.log
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import falcon
|
||||
from falcon_multipart.middleware import MultipartMiddleware
|
||||
from beaker.middleware import SessionMiddleware
|
||||
|
||||
from middleware import (
|
||||
AuthMiddleware,
|
||||
JSONTranslator,
|
||||
ConnectionMiddleware,
|
||||
static,
|
||||
handle_404
|
||||
)
|
||||
from models.db import StorageEngine
|
||||
from controllers.main import (
|
||||
AppLogin, AppLogout, AppAdmin, AppEmisor,
|
||||
AppMain, AppValues, AppPartners, AppProducts, AppInvoices, AppFolios,
|
||||
AppDocumentos
|
||||
)
|
||||
from settings import DEBUG
|
||||
|
||||
|
||||
db = StorageEngine()
|
||||
|
||||
api = falcon.API(middleware=[
|
||||
AuthMiddleware(),
|
||||
JSONTranslator(),
|
||||
ConnectionMiddleware(),
|
||||
MultipartMiddleware(),
|
||||
])
|
||||
api.req_options.auto_parse_form_urlencoded = True
|
||||
api.add_sink(handle_404, '')
|
||||
|
||||
api.add_route('/', AppLogin(db))
|
||||
api.add_route('/logout', AppLogout(db))
|
||||
api.add_route('/admin', AppAdmin(db))
|
||||
api.add_route('/emisor', AppEmisor(db))
|
||||
api.add_route('/folios', AppFolios(db))
|
||||
api.add_route('/main', AppMain(db))
|
||||
api.add_route('/values/{table}', AppValues(db))
|
||||
api.add_route('/doc/{type_doc}/{id_doc}', AppDocumentos(db))
|
||||
api.add_route('/partners', AppPartners(db))
|
||||
api.add_route('/products', AppProducts(db))
|
||||
api.add_route('/invoices', AppInvoices(db))
|
||||
|
||||
|
||||
|
||||
if DEBUG:
|
||||
api.add_sink(static, '/static')
|
||||
|
||||
|
||||
session_options = {
|
||||
'session.type': 'file',
|
||||
'session.cookie_expires': True,
|
||||
'session.data_dir': '/tmp/cache/data',
|
||||
'session.lock_dir': '/tmp/cache/lock',
|
||||
}
|
||||
app = SessionMiddleware(api, session_options)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
[uwsgi]
|
||||
http = 127.0.0.1:8000
|
||||
wsgi-file = main.py
|
||||
callable = app
|
||||
master = true
|
||||
processes = 4
|
||||
threads = 4
|
||||
py-autoreload = 1
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import falcon
|
||||
from controllers import util
|
||||
from models import main
|
||||
from settings import PATH_STATIC
|
||||
|
||||
|
||||
def handle_404(req, resp):
|
||||
id_session = req.cookies.get('beaker.session.id', '')
|
||||
if id_session:
|
||||
raise falcon.HTTPTemporaryRedirect('/main')
|
||||
raise falcon.HTTPTemporaryRedirect('/')
|
||||
|
||||
|
||||
def get_template(req, resp, resource):
|
||||
session = req.env['beaker.session']
|
||||
resp.content_type = 'text/html'
|
||||
data = {'username': session.get('user', '')}
|
||||
resp.body = util.get_template(resource.template, data)
|
||||
|
||||
|
||||
def static(req, res):
|
||||
path = PATH_STATIC + req.path
|
||||
if util.is_file(path):
|
||||
res.content_type = util.get_mimetype(path)
|
||||
res.stream, res.stream_len = util.get_stream(path)
|
||||
res.status = falcon.HTTP_200
|
||||
else:
|
||||
res.status = falcon.HTTP_404
|
||||
|
||||
|
||||
class AuthMiddleware(object):
|
||||
|
||||
def process_resource(self, req, resp, resource, params):
|
||||
id_session = req.cookies.get('beaker.session.id', '')
|
||||
if not id_session and req.path != '/':
|
||||
raise falcon.HTTPTemporaryRedirect('/')
|
||||
|
||||
|
||||
class JSONTranslator(object):
|
||||
|
||||
#~ def process_request(self, req, resp):
|
||||
#~ pass
|
||||
|
||||
def process_response(self, req, resp, resource):
|
||||
if 'result' not in req.context:
|
||||
return
|
||||
if '/doc/' in req.path:
|
||||
resp.body = req.context['result']
|
||||
return
|
||||
resp.body = util.dumps(req.context['result'])
|
||||
|
||||
|
||||
class ConnectionMiddleware(object):
|
||||
|
||||
#~ def process_request(self, req, resp):
|
||||
def process_resource(self, req, resp, resource, params):
|
||||
id_session = req.cookies.get('beaker.session.id', '')
|
||||
session = req.env['beaker.session']
|
||||
rfc = session.get('rfc', '')
|
||||
if id_session and rfc:
|
||||
opt = util.get_con(rfc)
|
||||
main.conectar(opt)
|
||||
|
||||
def process_response(self, req, resp, resource):
|
||||
main.desconectar()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env python
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from . import main
|
||||
|
||||
|
||||
class StorageEngine(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def authenticate(self, args):
|
||||
return main.authenticate(args)
|
||||
|
||||
def get_values(self, table, values=None):
|
||||
return getattr(self, '_get_{}'.format(table))(values)
|
||||
|
||||
def add_cert(self, file_object):
|
||||
return main.Certificado.add(file_object)
|
||||
|
||||
def validate_cert(self, values, session):
|
||||
return main.Certificado.validate(values, session)
|
||||
|
||||
def _get_cert(self, values):
|
||||
return main.Certificado.get_data()
|
||||
|
||||
def _get_cp(self, values):
|
||||
return main.get_cp(values['cp'])
|
||||
|
||||
def _get_formapago(self, values):
|
||||
return main.SATFormaPago.get_activos(values)
|
||||
|
||||
def _get_categorias(self, values):
|
||||
return main.Categorias.get_all()
|
||||
|
||||
def _get_newkey(self, values):
|
||||
return main.Productos.next_key()
|
||||
|
||||
def _get_unidades(self, values):
|
||||
return main.SATUnidades.get_activos()
|
||||
|
||||
def _get_taxes(self, values):
|
||||
return main.SATImpuestos.get_activos()
|
||||
|
||||
def _get_satkey(self, values):
|
||||
return main.get_sat_key(values['key'])
|
||||
|
||||
def _get_series(self, values):
|
||||
return main.Folios.get_all()
|
||||
|
||||
def _get_monedas(self, values):
|
||||
return main.SATMonedas.get_activos()
|
||||
|
||||
def _get_regimenes(self, values):
|
||||
return main.Emisor.get_regimenes()
|
||||
|
||||
def _get_usocfdi(self, values):
|
||||
return main.SATUsoCfdi.get_activos(values)
|
||||
|
||||
def delete(self, table, id):
|
||||
if table == 'partner':
|
||||
return main.Socios.remove(id)
|
||||
if table == 'product':
|
||||
return main.Productos.remove(id)
|
||||
if table == 'invoice':
|
||||
return main.Facturas.remove(id)
|
||||
if table == 'folios':
|
||||
return main.Folios.remove(id)
|
||||
return False
|
||||
|
||||
def _get_client(self, values):
|
||||
return main.Socios.get_by_client(values)
|
||||
|
||||
def _get_product(self, values):
|
||||
return main.Productos.get_by(values)
|
||||
|
||||
def get_partners(self, values):
|
||||
return main.Socios.get_(values)
|
||||
|
||||
def partner(self, values):
|
||||
id = int(values.pop('id', '0'))
|
||||
if id:
|
||||
return main.Socios.actualizar(values, id)
|
||||
return main.Socios.add(values)
|
||||
|
||||
def get_products(self, values):
|
||||
return main.Productos.get_(values)
|
||||
|
||||
def product(self, values):
|
||||
id = int(values.pop('id', '0'))
|
||||
if id:
|
||||
return main.Productos.actualizar(values, id)
|
||||
return main.Productos.add(values)
|
||||
|
||||
def invoice(self, values):
|
||||
id = int(values.pop('id', '0'))
|
||||
if id:
|
||||
return main.Facturas.actualizar(values, id)
|
||||
return main.Facturas.add(values)
|
||||
|
||||
def get_invoices(self, values):
|
||||
return main.Facturas.get_(values)
|
||||
|
||||
def _get_timbrar(self, values):
|
||||
return main.Facturas.timbrar(int(values['id']))
|
||||
|
||||
def get_emisor(self, rfc):
|
||||
return main.Emisor.get_(rfc)
|
||||
|
||||
def emisor(self, values):
|
||||
return main.Emisor.add(values)
|
||||
|
||||
def get_folios(self):
|
||||
return main.Folios.get_()
|
||||
|
||||
def add_folios(self, values):
|
||||
return main.Folios.add(values)
|
||||
|
||||
def get_doc(self, type_doc, id):
|
||||
if type_doc == 'xml':
|
||||
data, file_name = main.Facturas.get_xml(id)
|
||||
content_type = 'application.xml'
|
||||
return data, file_name, content_type
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import logbook
|
||||
import os
|
||||
import sys
|
||||
from mako.lookup import TemplateLookup
|
||||
from logbook import Logger, StreamHandler, RotatingFileHandler
|
||||
logbook.set_datetime_format('local')
|
||||
|
||||
|
||||
DEBUG = True
|
||||
VERSION = '0.1.0'
|
||||
EMAIL_SUPPORT = ('soporte@empresalibre.net',)
|
||||
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
PATH_STATIC = os.path.abspath(os.path.join(BASE_DIR, '..'))
|
||||
PATH_TEMPLATES = os.path.abspath(os.path.join(BASE_DIR, '..', 'templates'))
|
||||
|
||||
PATH_CP = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'cp.db'))
|
||||
COMPANIES = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'rfc.db'))
|
||||
DB_SAT = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', 'sat.db'))
|
||||
|
||||
PATH_XSLT = os.path.abspath(os.path.join(BASE_DIR, '..', 'xslt'))
|
||||
PATH_BIN = os.path.abspath(os.path.join(BASE_DIR, '..', 'bin'))
|
||||
|
||||
template_lookup = TemplateLookup(directories=[PATH_TEMPLATES],
|
||||
input_encoding='utf-8',
|
||||
output_encoding='utf-8')
|
||||
|
||||
LOG_PATH = 'empresalibre.log'
|
||||
LOG_NAME = 'API'
|
||||
LOG_LEVEL = 'INFO'
|
||||
|
||||
format_string = '[{record.time:%d-%b-%Y %H:%M:%S}] ' \
|
||||
'{record.level_name}: ' \
|
||||
'{record.channel}: ' \
|
||||
'{record.message}'
|
||||
|
||||
if DEBUG:
|
||||
LOG_LEVEL = 'DEBUG'
|
||||
StreamHandler(
|
||||
sys.stdout,
|
||||
level=LOG_LEVEL,
|
||||
format_string=format_string).push_application()
|
||||
else:
|
||||
LOG_PATH = '/srv/log/empresalibre.log'
|
||||
RotatingFileHandler(
|
||||
LOG_PATH,
|
||||
backup_count=10,
|
||||
max_size=1073741824,
|
||||
level=LOG_LEVEL,
|
||||
format_string=format_string).push_application()
|
||||
|
||||
log = Logger(LOG_NAME)
|
||||
|
||||
|
||||
PATH_XSLTPROC = 'xsltproc'
|
||||
PATH_OPENSSL = 'openssl'
|
||||
if 'win' in sys.platform:
|
||||
PATH_XSLTPROC = os.path.join(PATH_BIN, 'xsltproc.exe')
|
||||
PATH_OPENSSL = os.path.join(PATH_BIN, 'openssl.exe')
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,116 @@
|
|||
[
|
||||
{
|
||||
"tabla": "Categorias",
|
||||
"datos": [
|
||||
{"categoria": "Productos"},
|
||||
{"categoria": "Servicios"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tabla": "SATImpuestos",
|
||||
"datos": [
|
||||
{"key": "002", "name": "IVA", "tasa": 0.16, "activo": true, "default": true},
|
||||
{"key": "001", "name": "ISR", "tasa": 0.10, "tipo": "R", "activo": true},
|
||||
{"key": "002", "name": "IVA", "tasa": 0.0, "activo": true},
|
||||
{"key": "002", "name": "IVA", "tasa": 0.10, "tipo": "R", "activo": true},
|
||||
{"key": "002", "name": "IVA", "tasa": 0.666667, "tipo": "R", "activo": true},
|
||||
{"key": "000", "name": "Exento", "tipo": "E", "factor": "E", "activo": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tabla": "SATUnidades",
|
||||
"datos": [
|
||||
{"key": "HUR", "name": "Hora", "activo": true},
|
||||
{"key": "H87", "name": "Pieza", "activo": true},
|
||||
{"key": "E48", "name": "Servicio", "activo": true},
|
||||
{"key": "E51", "name": "Trabajo", "activo": false}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tabla": "SATMonedas",
|
||||
"datos": [
|
||||
{"key": "MXN", "name": "Peso Mexicano", "activo": true, "default": true},
|
||||
{"key": "USD", "name": "Dólar americano", "activo": false},
|
||||
{"key": "EUR", "name": "Euro", "activo": false}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tabla": "SATFormaPago",
|
||||
"datos": [
|
||||
{"key": "01", "name": "Efectivo", "activo": true},
|
||||
{"key": "02", "name": "Cheque nominativo", "activo": true},
|
||||
{"key": "03", "name": "Transferencia electrónica de fondos", "activo": true, "default": true},
|
||||
{"key": "04", "name": "Tarjeta de crédito", "activo": true},
|
||||
{"key": "05", "name": "Monedero electrónico", "activo": false},
|
||||
{"key": "06", "name": "Dinero electrónico", "activo": false},
|
||||
{"key": "08", "name": "Vales de despensa", "activo": false},
|
||||
{"key": "12", "name": "Dación en pago", "activo": false},
|
||||
{"key": "13", "name": "Pago por subrogación", "activo": false},
|
||||
{"key": "14", "name": "Pago por consignación", "activo": false},
|
||||
{"key": "15", "name": "Condonación", "activo": false},
|
||||
{"key": "17", "name": "Compensación", "activo": false},
|
||||
{"key": "23", "name": "Novación", "activo": false},
|
||||
{"key": "24", "name": "Confusión", "activo": false},
|
||||
{"key": "25", "name": "Remisión de deuda", "activo": false},
|
||||
{"key": "26", "name": "Prescripción o caducidad", "activo": false},
|
||||
{"key": "27", "name": "A satisfacción del acreedor", "activo": false},
|
||||
{"key": "28", "name": "Tarjeta de débito", "activo": true},
|
||||
{"key": "29", "name": "Tarjeta de servicios", "activo": false},
|
||||
{"key": "30", "name": "Aplicación de anticipos", "activo": false},
|
||||
{"key": "99", "name": "Por definir", "activo": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tabla": "SATRegimenes",
|
||||
"datos": [
|
||||
{"key": "601", "name": "General de Ley Personas Morales", "moral": true, "activo": true, "default": true},
|
||||
{"key": "603", "name": "Personas Morales con Fines no Lucrativos", "moral": true, "activo": true},
|
||||
{"key": "605", "name": "Sueldos y Salarios e Ingresos Asimilados a Salarios", "fisica": true, "activo": true},
|
||||
{"key": "606", "name": "Arrendamiento", "fisica": true, "activo": true},
|
||||
{"key": "608", "name": "Demás ingresos", "fisica": true, "activo": false},
|
||||
{"key": "609", "name": "Consolidación", "moral": true, "activo": false},
|
||||
{"key": "610", "name": "Residentes en el Extranjero sin Establecimiento Permanente en México", "fisica": true, "moral": true, "activo": false},
|
||||
{"key": "611", "name": "Ingresos por Dividendos (socios y accionistas)", "fisica": true, "activo": false},
|
||||
{"key": "612", "name": "Personas Físicas con Actividades Empresariales y Profesionales", "fisica": true, "activo": true, "default": true},
|
||||
{"key": "614", "name": "Ingresos por intereses", "fisica": true, "activo": false},
|
||||
{"key": "616", "name": "Sin obligaciones fiscales", "fisica": true, "activo": false},
|
||||
{"key": "620", "name": "Sociedades Cooperativas de Producción que optan por diferir sus ingresos", "moral": true, "activo": false},
|
||||
{"key": "621", "name": "Incorporación Fiscal", "fisica": true, "activo": true},
|
||||
{"key": "622", "name": "Actividades Agrícolas, Ganaderas, Silvícolas y Pesqueras", "fisica": true, "moral": true, "activo": false},
|
||||
{"key": "623", "name": "Opcional para Grupos de Sociedades", "moral": true, "activo": false},
|
||||
{"key": "624", "name": "Coordinados", "moral": true, "activo": false},
|
||||
{"key": "628", "name": "Hidrocarburos", "moral": true, "activo": false},
|
||||
{"key": "607", "name": "Régimen de Enajenación o Adquisición de Bienes", "moral": true, "activo": false},
|
||||
{"key": "629", "name": "De los Regímenes Fiscales Preferentes y de las Empresas Multinacionales", "fisica": true, "activo": false},
|
||||
{"key": "630", "name": "Enajenación de acciones en bolsa de valores", "fisica": true, "activo": false},
|
||||
{"key": "615", "name": "Régimen de los ingresos por obtención de premios", "fisica": true, "activo": false}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tabla": "SATUsoCfdi",
|
||||
"datos": [
|
||||
{"key": "G01", "name": "Adquisición de mercancias", "moral": true, "activo": true},
|
||||
{"key": "G02", "name": "Devoluciones, descuentos o bonificaciones", "moral": true, "activo": true},
|
||||
{"key": "G03", "name": "Gastos en general", "moral": true, "activo": true, "default": true},
|
||||
{"key": "I01", "name": "Construcciones", "moral": true, "activo": false},
|
||||
{"key": "I02", "name": "Mobilario y equipo de oficina por inversiones", "moral": true, "activo": false},
|
||||
{"key": "I03", "name": "Equipo de transporte", "moral": true, "activo": false},
|
||||
{"key": "I04", "name": "Equipo de computo y accesorios", "moral": true, "activo": false},
|
||||
{"key": "I05", "name": "Dados, troqueles, moldes, matrices y herramental", "moral": true, "activo": false},
|
||||
{"key": "I06", "name": "Comunicaciones telefónicas", "moral": true, "activo": false},
|
||||
{"key": "I07", "name": "Comunicaciones satelitales", "moral": true, "activo": false},
|
||||
{"key": "I08", "name": "Otra maquinaria y equipo", "moral": true, "activo": false},
|
||||
{"key": "D01", "name": "Honorarios médicos, dentales y gastos hospitalarios.", "activo": false},
|
||||
{"key": "D02", "name": "Gastos médicos por incapacidad o discapacidad", "activo": false},
|
||||
{"key": "D03", "name": "Gastos funerales.", "activo": false},
|
||||
{"key": "D04", "name": "Donativos.", "activo": true},
|
||||
{"key": "D05", "name": "Intereses reales efectivamente pagados por créditos hipotecarios (casa habitación).", "activo": false},
|
||||
{"key": "D06", "name": "Aportaciones voluntarias al SAR.", "activo": false},
|
||||
{"key": "D07", "name": "Primas por seguros de gastos médicos.", "activo": false},
|
||||
{"key": "D08", "name": "Gastos de transportación escolar obligatoria.", "activo": false},
|
||||
{"key": "D09", "name": "Depósitos en cuentas para el ahorro, primas que tengan como base planes de pensiones.", "activo": false},
|
||||
{"key": "D10", "name": "Pagos por servicios educativos (colegiaturas)", "activo": true},
|
||||
{"key": "P01", "name": "Por definir", "moral": true, "activo": true}
|
||||
]
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
|
||||
.login_header {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 150%;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.cmd_edit_parter {
|
||||
max-width: 32px,
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
.right_footer {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
font-size: 125%;
|
||||
color: DarkRed;
|
||||
}
|
||||
|
||||
.lbl_partner {
|
||||
font-weight: bold;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.delete {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 250%;
|
||||
color: red;
|
||||
}
|
||||
|
||||
|
||||
.cmd_close_partner div button {
|
||||
background-color: red !important;
|
||||
border-color: red !important;
|
||||
border-bottom: 1px solid red !important;
|
||||
}
|
||||
|
||||
/*
|
||||
.webix_message_area {
|
||||
position: absolute;
|
||||
margin-top: 25%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 40%;
|
||||
}
|
||||
*/
|
||||
|
||||
.webix_success div {
|
||||
background-color: #00a65a !important;
|
||||
font-size: 1vw;
|
||||
color: white;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
|
||||
/* SideBar*/
|
||||
.webix_sidebar{
|
||||
background: #ECEFF1;
|
||||
}
|
||||
.webix_sidebar .webix_tree_item {
|
||||
color: #454545;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
}
|
||||
.webix_sidebar .webix_scroll_cont > .webix_tree_leaves {
|
||||
padding: 0;
|
||||
}
|
||||
.webix_sidebar .webix_tree_leaves .webix_tree_leaves {
|
||||
margin-left: 0px;
|
||||
}
|
||||
.webix_sidebar_selected,
|
||||
.webix_sidebar_expanded .webix_tree_item:hover{
|
||||
background-color: rgba(0,0,0,0.02);
|
||||
}
|
||||
.webix_sidebar .webix_tree_item.webix_selected,
|
||||
.webix_sidebar .webix_tree_item.webix_selected span{
|
||||
background-color: #27ae60;
|
||||
padding-right:0;
|
||||
}
|
||||
.webix_sidebar .webix_tree_branch_1 .webix_tree_item{
|
||||
padding-left:40px;
|
||||
}
|
||||
.webix_sidebar .webix_tree_branch_1>.webix_tree_item{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding-left:0;
|
||||
}
|
||||
.webix_sidebar .webix_tree_branch_1{
|
||||
border-bottom:1px solid #e5e5e5;
|
||||
}
|
||||
.webix_sidebar .webix_tree_item.webix_selected span,
|
||||
.webix_sidebar .webix_tree_item span{
|
||||
margin:0;
|
||||
padding:0px;
|
||||
}
|
||||
.webix_sidebar_icon{
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.webix_sidebar_dir_icon{
|
||||
float: right;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/*SubMenu (Popup) */
|
||||
.webix_sidebar_popup{
|
||||
border:none !important;
|
||||
box-shadow: 2px 3px 3px #ddd;
|
||||
}
|
||||
.webix_sidebar_popup, .webix_sidebar_popup .webix_list_item{
|
||||
border-radius:0;
|
||||
}
|
||||
.webix_sidebar_popup_right{
|
||||
box-shadow: -1px 3px 3px #ddd;
|
||||
}
|
||||
/*SubMenu: title*/
|
||||
.webix_sidebar_popup_title{
|
||||
background: #ECEFF1;
|
||||
}
|
||||
.webix_sidebar_popup_title.webix_selected{
|
||||
border-left-color: #27ae60;
|
||||
background: #27ae60;
|
||||
}
|
||||
.webix_sidebar_popup_title .webix_template{
|
||||
line-height: 40px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #E5E5E5;
|
||||
border-left:none;
|
||||
}
|
||||
.webix_sidebar_selected.webix_sidebar_popup_title .webix_template{
|
||||
background: rgba(0,0,0,0.03);
|
||||
border-left: none;
|
||||
}
|
||||
.webix_sidebar_popup_list .webix_list_item{
|
||||
border-left: 1px solid #E5E5E5;
|
||||
border-right: 1px solid #E5E5E5;
|
||||
}
|
||||
/*SubMenu: list*/
|
||||
.webix_sidebar_popup_list .webix_list_item:first-child{
|
||||
border-top: 1px solid #E5E5E5;
|
||||
}
|
||||
.webix_sidebar_popup_list .webix_list_item:hover{
|
||||
background: #f6f9fb;
|
||||
}
|
||||
|
||||
.webix_sidebar_popup_list .webix_list_item.webix_selected:hover{
|
||||
background: #27ae60;
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/* SideBar*/
|
||||
.webix_sidebar{
|
||||
background: #ECEFF1;
|
||||
}
|
||||
.webix_sidebar .webix_tree_item {
|
||||
color: #454545;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
}
|
||||
.webix_sidebar .webix_scroll_cont > .webix_tree_leaves {
|
||||
padding: 0;
|
||||
}
|
||||
.webix_sidebar .webix_tree_leaves .webix_tree_leaves {
|
||||
margin-left: 0px;
|
||||
}
|
||||
.webix_sidebar_selected,
|
||||
.webix_sidebar_expanded .webix_tree_item:hover{
|
||||
background-color: rgba(0,0,0,0.02);
|
||||
}
|
||||
.webix_sidebar .webix_tree_item.webix_selected,
|
||||
.webix_sidebar .webix_tree_item.webix_selected span{
|
||||
background-color: #ffdb8f;
|
||||
padding-right:0;
|
||||
}
|
||||
.webix_sidebar .webix_tree_branch_1 .webix_tree_item{
|
||||
padding-left:40px;
|
||||
}
|
||||
.webix_sidebar .webix_tree_branch_1>.webix_tree_item{
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
padding-left:0;
|
||||
}
|
||||
.webix_sidebar .webix_tree_branch_1{
|
||||
border-bottom:1px solid #e5e5e5;
|
||||
}
|
||||
.webix_sidebar .webix_tree_item.webix_selected span,
|
||||
.webix_sidebar .webix_tree_item span{
|
||||
margin:0;
|
||||
padding:0px;
|
||||
}
|
||||
.webix_sidebar_icon{
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.webix_sidebar_dir_icon{
|
||||
float: right;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/*SubMenu (Popup) */
|
||||
.webix_sidebar_popup{
|
||||
border:none !important;
|
||||
box-shadow: 2px 3px 3px #ddd;
|
||||
}
|
||||
.webix_sidebar_popup, .webix_sidebar_popup .webix_list_item{
|
||||
border-radius:0;
|
||||
}
|
||||
.webix_sidebar_popup_right{
|
||||
box-shadow: -1px 3px 3px #ddd;
|
||||
}
|
||||
/*SubMenu: title*/
|
||||
.webix_sidebar_popup_title{
|
||||
background: #ECEFF1;
|
||||
}
|
||||
.webix_sidebar_popup_title.webix_selected{
|
||||
border-left-color: #ffdb8f;
|
||||
background: #ffdb8f;
|
||||
}
|
||||
.webix_sidebar_popup_title .webix_template{
|
||||
line-height: 40px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #E5E5E5;
|
||||
border-left:none;
|
||||
}
|
||||
.webix_sidebar_selected.webix_sidebar_popup_title .webix_template{
|
||||
background: rgba(0,0,0,0.03);
|
||||
border-left: none;
|
||||
}
|
||||
.webix_sidebar_popup_list .webix_list_item{
|
||||
border-left: 1px solid #E5E5E5;
|
||||
border-right: 1px solid #E5E5E5;
|
||||
}
|
||||
/*SubMenu: list*/
|
||||
.webix_sidebar_popup_list .webix_list_item:first-child{
|
||||
border-top: 1px solid #E5E5E5;
|
||||
}
|
||||
.webix_sidebar_popup_list .webix_list_item:hover{
|
||||
background: #f6f9fb;
|
||||
}
|
||||
|
||||
.webix_sidebar_popup_list .webix_list_item.webix_selected:hover{
|
||||
background: #ffdb8f;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,14 @@
|
|||
## Font Awesome
|
||||
|
||||
Copyright (C) 2012 by Dave Gandy
|
||||
|
||||
Author: Dave Gandy
|
||||
License: SIL (http://scripts.sil.org/OFL)
|
||||
Homepage: http://fortawesome.github.com/Font-Awesome/
|
||||
|
||||
|
||||
|
||||
## PT Sans Free
|
||||
|
||||
Copyright © 2009 ParaType Ltd.
|
||||
License: Free Font License v1.00
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 434 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 754 B |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,448 @@
|
|||
var msg = ''
|
||||
|
||||
|
||||
var controllers = {
|
||||
init: function(){
|
||||
//~ Admin
|
||||
$$('menu_user').attachEvent('onMenuItemClick', menu_user_click)
|
||||
$$('multi_admin').attachEvent('onViewChange', multi_admin_change)
|
||||
//~ Emisor
|
||||
$$('cmd_save_emisor').attachEvent('onItemClick', cmd_save_emisor_click)
|
||||
$$('emisor_cp').attachEvent('onKeyPress', emisor_postal_code_key_press)
|
||||
$$('emisor_cp').attachEvent('onTimedKeyPress', emisor_postal_code_key_up)
|
||||
$$('chk_escuela').attachEvent('onChange', chk_escuela_change)
|
||||
$$('chk_ong').attachEvent('onChange', chk_ong_change)
|
||||
$$('cmd_subir_certificado').attachEvent('onItemClick', cmd_subir_certificado_click)
|
||||
$$('up_cert').attachEvent('onUploadComplete', up_cert_upload_complete)
|
||||
$$('cmd_agregar_serie').attachEvent('onItemClick', cmd_agregar_serie_click)
|
||||
$$('grid_folios').attachEvent('onItemClick', grid_folios_click)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function menu_user_click(id, e, node){
|
||||
if (id == 1){
|
||||
window.location = '/logout'
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function cmd_home_click(){
|
||||
window.location = '/main'
|
||||
}
|
||||
|
||||
|
||||
function cmd_save_emisor_click(){
|
||||
var valid_cp = false
|
||||
var form = $$('form_emisor')
|
||||
|
||||
if (!form.validate()){
|
||||
msg = 'Valores inválidos'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues()
|
||||
|
||||
var ids = $$('lst_emisor_regimen').getSelectedId()
|
||||
if(!ids){
|
||||
msg = 'Selecciona al menos un Regimen Fiscal'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
if(values.emisor_cp && values.emisor_cp.length != 5){
|
||||
msg = 'Longitud inválida del C.P.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
if(values.emisor_cp2 && values.emisor_cp2.length != 5){
|
||||
msg = 'Longitud inválida del C.P. de Expedición'
|
||||
msg_error(msg)
|
||||
return
|
||||
}else if(values.emisor_cp2){
|
||||
webix.ajax().sync().get('/values/cp', {cp: values.emisor_cp2}, {
|
||||
error: function(text, data, xhr) {
|
||||
msg = 'Error al consultar el C.P. de Expedición'
|
||||
msg_error(msg)
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
if (values.estado == undefined){
|
||||
msg = 'No se encontró el C.P., asegurate de que sea correcto'
|
||||
msg_error(msg)
|
||||
}else{
|
||||
valid_cp = true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if(!valid_cp){
|
||||
return
|
||||
}
|
||||
|
||||
if(values.es_ong){
|
||||
if(!values.ong_autorizacion){
|
||||
msg = 'Si es ONG, el Número de Autorización del SAT es requerido'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
if(!values.ong_fecha){
|
||||
msg = 'Si es ONG, la Fecha de Autorización del SAT es requerida'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
if(!values.ong_fecha_dof){
|
||||
msg = 'Si es ONG, la Fecha de Publicación en DOF es requerida'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
values['regimenes'] = ids
|
||||
webix.ajax().post('/emisor', 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_sucess('Emisor guardado correctamente')
|
||||
}else{
|
||||
msg_error(values.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get_emisor(){
|
||||
var form = $$('form_emisor')
|
||||
|
||||
webix.ajax().get("/emisor", {}, {
|
||||
error: function(text, data, xhr) {
|
||||
msg = 'Error al consultar'
|
||||
msg_error(msg)
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json()
|
||||
if (values.ok){
|
||||
var emisor = values.row.emisor
|
||||
$$('lst_emisor_regimen').parse(values.row.regimenes)
|
||||
form.setValues(emisor, true)
|
||||
$$('lst_emisor_regimen').select(emisor.regimenes)
|
||||
}else{
|
||||
msg_error(values.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get_certificado(){
|
||||
var form = $$('form_cert')
|
||||
|
||||
webix.ajax().get("/values/cert", {}, {
|
||||
error: function(text, data, xhr) {
|
||||
msg = 'Error al consultar'
|
||||
msg_error(msg)
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json()
|
||||
form.setValues(values)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get_table_folios(){
|
||||
webix.ajax().get("/folios", {}, {
|
||||
error: function(text, data, xhr) {
|
||||
msg = 'Error al consultar'
|
||||
msg_error(msg)
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json()
|
||||
$$('grid_folios').parse(values)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function multi_admin_change(prevID, nextID){
|
||||
//~ webix.message(nextID)
|
||||
if(nextID == 'app_emisor'){
|
||||
$$('tab_emisor').setValue('Datos Fiscales')
|
||||
get_emisor()
|
||||
get_certificado()
|
||||
return
|
||||
}
|
||||
|
||||
if(nextID == 'app_folios'){
|
||||
get_table_folios()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function emisor_postal_code_key_up(){
|
||||
var value = this.getValue()
|
||||
|
||||
if( value.length == 5 ){
|
||||
webix.ajax().get('/values/cp', {cp: value}, {
|
||||
error: function(text, data, xhr) {
|
||||
msg = 'Error al consultar el C.P.'
|
||||
msg_error(msg)
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
if (values.estado == undefined){
|
||||
msg = 'No se encontró el C.P., asegurate de que sea correcto'
|
||||
msg_error(msg)
|
||||
} else {
|
||||
$$('form_emisor').setValues({
|
||||
emisor_cp2: value,
|
||||
emisor_estado: values.estado,
|
||||
emisor_municipio: values.municipio,
|
||||
emisor_colonia: ''}, true)
|
||||
$$('emisor_colonia').define('suggest', [])
|
||||
if (webix.isArray(values.colonia)){
|
||||
$$('emisor_colonia').define('suggest', values.colonia)
|
||||
}else{
|
||||
$$('form_emisor').setValues(
|
||||
{emisor_colonia: values.colonia}, true)
|
||||
}
|
||||
$$('emisor_colonia').refresh()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function emisor_postal_code_key_press(code, e){
|
||||
var data = [8, 9, 37, 39, 46]
|
||||
if ( data.indexOf(code) >= 0 ){
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( code < 48 || code > 57){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function chk_escuela_change(new_value, old_value){
|
||||
var value = Boolean(new_value)
|
||||
if (value){
|
||||
$$('cmd_niveles').enable()
|
||||
} else {
|
||||
$$('cmd_niveles').disable()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function chk_ong_change(new_value, old_value){
|
||||
var value = Boolean(new_value)
|
||||
if (value){
|
||||
$$('ong_autorizacion').enable()
|
||||
$$('ong_fecha').enable()
|
||||
$$('ong_fecha_dof').enable()
|
||||
} else {
|
||||
$$('ong_autorizacion').disable()
|
||||
$$('ong_fecha').disable()
|
||||
$$('ong_fecha_dof').disable()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function cmd_subir_certificado_click(){
|
||||
var form = $$('form_upload')
|
||||
|
||||
if (!form.validate()){
|
||||
msg = 'Valores inválidos'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues()
|
||||
|
||||
if(!values.contra.trim()){
|
||||
msg = 'La contraseña no puede estar vacía'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
if($$('lst_cert').count() < 2){
|
||||
msg = 'Selecciona al menos dos archivos: CER y KEY del certificado.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
if($$('lst_cert').count() > 2){
|
||||
msg = 'Selecciona solo dos archivos: CER y KEY del certificado.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
var fo1 = $$('up_cert').files.getItem($$('up_cert').files.getFirstId())
|
||||
var fo2 = $$('up_cert').files.getItem($$('up_cert').files.getLastId())
|
||||
|
||||
var ext = ['key', 'cer']
|
||||
if(ext.indexOf(fo1.type.toLowerCase()) == -1 || ext.indexOf(fo2.type.toLowerCase()) == -1){
|
||||
msg = 'Archivos inválidos, se requiere un archivo CER y un KEY.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
if(fo1.type == fo2.type && fo1.size == fo2.size){
|
||||
msg = 'Selecciona archivos diferentes: un archivo CER y un KEY.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
var rfc = $$('form_cert').getValues()['cert_rfc']
|
||||
if(rfc){
|
||||
msg = 'Ya existe un certificado guardado<BR><BR>¿Deseas reemplazarlo?'
|
||||
webix.confirm({
|
||||
title: 'Certificado Existente',
|
||||
ok: 'Si',
|
||||
cancel: 'No',
|
||||
type: 'confirm-error',
|
||||
text: msg,
|
||||
callback:function(result){
|
||||
if(result){
|
||||
$$('up_cert').send()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function up_cert_upload_complete(response){
|
||||
if(response.status != 'server'){
|
||||
msg = 'Ocurrio un error al subir los archivos'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
msg = 'Archivos subidos correctamente. Esperando validación'
|
||||
msg_sucess(msg)
|
||||
|
||||
var values = $$('form_upload').getValues()
|
||||
$$('form_upload').setValues({})
|
||||
$$('up_cert').files.data.clearAll()
|
||||
|
||||
webix.ajax().post('/values/cert', 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){
|
||||
$$('form_cert').setValues(values.data)
|
||||
msg_sucess(values.msg)
|
||||
}else{
|
||||
msg_error(values.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function cmd_agregar_serie_click(){
|
||||
var form = $$('form_folios')
|
||||
var grid = $$('grid_folios')
|
||||
|
||||
if (!form.validate()){
|
||||
msg = 'Valores inválidos'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues()
|
||||
|
||||
var reg = /^[a-z]+$/i
|
||||
if(!reg.test(values.folio_serie)){
|
||||
msg = 'Introduce una serie válida. Solo letras.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
var pre = '1'
|
||||
if(grid.count() > 0){
|
||||
pre = ''
|
||||
}
|
||||
|
||||
var usarcon = ''
|
||||
if(values.folio_usarcon != 'S'){
|
||||
usarcon = values.folio_usarcon
|
||||
}
|
||||
|
||||
var values = {
|
||||
serie: values.folio_serie.trim().toUpperCase(),
|
||||
inicio: values.folio_inicio,
|
||||
usarcon: usarcon,
|
||||
default: pre,
|
||||
}
|
||||
|
||||
webix.ajax().post('/folios', 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){
|
||||
form.setValues(
|
||||
{folio_serie: '', folio_inicio: 1, folio_usarcon: 'S'})
|
||||
grid.add(values.row)
|
||||
msg = 'Serie agregada correctamente'
|
||||
msg_sucess(msg)
|
||||
}else{
|
||||
msg_error(values.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function grid_folios_click(id, e, node){
|
||||
if(id.column != 'delete'){
|
||||
return
|
||||
}
|
||||
|
||||
msg = '¿Estás seguro de borrar esta serie?<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER'
|
||||
webix.confirm({
|
||||
title: 'Borrar Serie',
|
||||
ok: 'Si',
|
||||
cancel: 'No',
|
||||
type: 'confirm-error',
|
||||
text: msg,
|
||||
callback:function(result){
|
||||
if(result){
|
||||
webix.ajax().del('/folios', {id: id.row}, function(text, xml, xhr){
|
||||
msg = 'Serie eliminada correctamente'
|
||||
if(xhr.status == 200){
|
||||
$$('grid_folios').remove(id.row)
|
||||
msg_sucess(msg)
|
||||
}else{
|
||||
msg = 'No se pudo eliminar'
|
||||
msg_error(msg)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,651 @@
|
|||
var query = []
|
||||
var grid = null
|
||||
var msg = ''
|
||||
|
||||
|
||||
function get_series(){
|
||||
webix.ajax().get('/values/series', function(text, data){
|
||||
var values = data.json()
|
||||
table_series.clear()
|
||||
table_series.insert(values)
|
||||
pre = values[0]
|
||||
$$('lst_serie').getList().parse(values)
|
||||
$$('lst_serie').setValue(pre.id)
|
||||
if(pre.usar_con){
|
||||
$$('lst_tipo_comprobante').setValue(pre.usar_con)
|
||||
$$('lst_tipo_comprobante').config.readonly = true
|
||||
$$('lst_tipo_comprobante').refresh()
|
||||
}
|
||||
if(values.length == 1){
|
||||
$$('lst_serie').config.readonly = true
|
||||
$$('lst_serie').refresh()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function get_forma_pago(){
|
||||
webix.ajax().get('/values/formapago', {key: true}, function(text, data){
|
||||
var values = data.json()
|
||||
//~ pre = values[0]
|
||||
$$('lst_forma_pago').getList().parse(values)
|
||||
//~ $$('lst_forma_pago').setValue(pre.id)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function get_monedas(){
|
||||
webix.ajax().get('/values/monedas', function(text, data){
|
||||
var values = data.json()
|
||||
pre = values[0]
|
||||
$$('lst_moneda').getList().parse(values)
|
||||
$$('lst_moneda').setValue(pre.id)
|
||||
if(values.length == 1){
|
||||
$$('fs_moneda').hide()
|
||||
$$('fs_moneda').refresh()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function get_uso_cfdi(){
|
||||
get_uso_cfdi_to_table({key: true})
|
||||
query = table_usocfdi.chain().data()
|
||||
$$('lst_uso_cfdi').getList().parse(query)
|
||||
}
|
||||
|
||||
|
||||
function get_regimen_fiscal(){
|
||||
webix.ajax().get('/values/regimenes', function(text, data){
|
||||
var values = data.json()
|
||||
pre = values[0]
|
||||
$$('lst_regimen_fiscal').getList().parse(values)
|
||||
$$('lst_regimen_fiscal').setValue(pre.id)
|
||||
if(values.length == 1){
|
||||
$$('fs_regimen_fiscal').hide()
|
||||
$$('fs_regimen_fiscal').refresh()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function default_config(){
|
||||
webix.ajax().sync().get('/values/taxes', function(text, data){
|
||||
var values = data.json()
|
||||
table_taxes.clear()
|
||||
table_taxes.insert(values)
|
||||
})
|
||||
get_series()
|
||||
get_forma_pago()
|
||||
get_monedas()
|
||||
get_uso_cfdi()
|
||||
get_regimen_fiscal()
|
||||
table_pt.clear()
|
||||
table_totals.clear()
|
||||
}
|
||||
|
||||
|
||||
function cmd_new_invoice_click(id, e, node){
|
||||
var form = $$('form_invoice')
|
||||
var grid_totals = $$('grid_totals')
|
||||
grid = $$('grid_details')
|
||||
|
||||
default_config()
|
||||
form.adjust()
|
||||
form.setValues({id: 0, id_partner: 0, lbl_client: 'Ninguno'})
|
||||
grid.clearAll()
|
||||
grid_totals.clearAll()
|
||||
grid_totals.add({id: 1, concepto: 'SubTotal', importe: 0})
|
||||
$$('multi_invoices').setValue('invoices_new')
|
||||
form.focus('search_client_id')
|
||||
}
|
||||
|
||||
|
||||
function cmd_edit_invoice_click(id, e, node){
|
||||
|
||||
$$("multi_invoices").setValue("invoices_new")
|
||||
|
||||
}
|
||||
|
||||
|
||||
function delete_invoice(id){
|
||||
webix.ajax().del('/invoices', {id: id}, function(text, xml, xhr){
|
||||
if(xhr.status == 200){
|
||||
gi.remove(id)
|
||||
msg_sucess('Factura eliminada correctamente')
|
||||
}else{
|
||||
msg_error('No se pudo eliminar')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function cmd_delete_invoice_click(id, e, node){
|
||||
|
||||
var row = gi.getSelectedItem()
|
||||
if (row == undefined){
|
||||
msg_error('Selecciona una factura')
|
||||
return
|
||||
}
|
||||
|
||||
if(row.uuid){
|
||||
msg_error('Solo se pueden eliminar facturas sin timbrar')
|
||||
return
|
||||
}
|
||||
|
||||
var msg = '¿Estás seguro de eliminar la siguiente Factura?<BR><BR>'
|
||||
msg += '(' + row['folio'] + ') ' + row['cliente']
|
||||
msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER'
|
||||
webix.confirm({
|
||||
title:'Eliminar Factura',
|
||||
ok:'Si',
|
||||
cancel:'No',
|
||||
type:'confirm-error',
|
||||
text:msg,
|
||||
callback:function(result){
|
||||
if (result){
|
||||
delete_invoice(row['id'])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function validate_invoice(values){
|
||||
|
||||
if(values.id_partner == 0){
|
||||
webix.UIManager.setFocus('search_client_name')
|
||||
msg = 'Selecciona un cliente'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
if(!grid.count()){
|
||||
webix.UIManager.setFocus('search_product_id')
|
||||
msg = 'Agrega al menos un producto o servicio'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
var uso_cfdi = $$('lst_uso_cfdi').getValue()
|
||||
if(uso_cfdi.trim() == ""){
|
||||
webix.UIManager.setFocus('lst_uso_cfdi')
|
||||
msg = 'El Uso del CFDI es requerido'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
var forma_pago = $$('lst_forma_pago').getValue()
|
||||
if(forma_pago.trim() == ""){
|
||||
webix.UIManager.setFocus('lst_forma_pago')
|
||||
msg = 'La Forma de pago es requerida'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
var tipo_cambio = $$('txt_tipo_cambio').getValue()
|
||||
if(tipo_cambio.trim() == ""){
|
||||
webix.UIManager.setFocus('txt_tipo_cambio')
|
||||
msg = 'El Tipo de Cambio es requerido'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
if(isNaN(tipo_cambio * 1)){
|
||||
webix.UIManager.setFocus('txt_tipo_cambio')
|
||||
msg = 'El Tipo de Cambio debe ser un valor númerico'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
var moneda = $$('lst_moneda').getValue()
|
||||
if(moneda == 'MXN' && tipo_cambio != 1){
|
||||
webix.UIManager.setFocus('txt_tipo_cambio')
|
||||
msg = 'Si la moneda es MXN, el Tipo de Cambio debe ser 1.00'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
if(moneda != 'MXN' && tipo_cambio == 1){
|
||||
webix.UIManager.setFocus('txt_tipo_cambio')
|
||||
msg = 'Si la moneda no es MXN, el Tipo de Cambio debe ser diferente de 1.00'
|
||||
msg_error(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
function update_grid_invoices(values){
|
||||
if(values.new){
|
||||
gi.add(values.row)
|
||||
}else{
|
||||
gi.updateItem(values.row['id'], values.row)
|
||||
}
|
||||
}
|
||||
|
||||
function send_timbrar(id){
|
||||
webix.ajax().get('/values/timbrar', {id: id}, function(text, data){
|
||||
var values = data.json()
|
||||
if(values.ok){
|
||||
msg_sucess(values.msg)
|
||||
gi.updateItem(id, values.row)
|
||||
}else{
|
||||
webix.alert({
|
||||
title: 'Error al Timbrar',
|
||||
text: values.msg,
|
||||
type: 'alert-error'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function save_invoice(data){
|
||||
var result = false
|
||||
var values = NaN
|
||||
|
||||
webix.ajax().sync().post('invoices', data, {
|
||||
error:function(text, data, XmlHttpRequest){
|
||||
msg = 'Ocurrio un error, consulta a soporte técnico'
|
||||
msg_error(msg)
|
||||
},
|
||||
success:function(text, data, XmlHttpRequest){
|
||||
values = data.json();
|
||||
if(values.ok){
|
||||
msg_sucess('Factura guardada correctamente. Enviando a timbrar')
|
||||
update_grid_invoices(values)
|
||||
send_timbrar(values.row['id'])
|
||||
result = true
|
||||
}else{
|
||||
msg_error(values.msg)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if(result){
|
||||
table_pt.clear()
|
||||
table_totals.clear()
|
||||
grid.clearAll()
|
||||
$$('grid_totals').clearAll()
|
||||
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
function cmd_timbrar_click(id, e, node){
|
||||
var form = this.getFormView();
|
||||
|
||||
if(!form.validate()) {
|
||||
webix.message({type:'error', text:'Valores inválidos'})
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues();
|
||||
if(!validate_invoice(values)){
|
||||
return
|
||||
}
|
||||
|
||||
var rows = grid.data.getRange()
|
||||
for (i = 0; i < rows.length; i++) {
|
||||
delete rows[i]['delete']
|
||||
delete rows[i]['clave']
|
||||
delete rows[i]['descripcion']
|
||||
delete rows[i]['unidad']
|
||||
delete rows[i]['importe']
|
||||
rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
|
||||
}
|
||||
|
||||
var data = new Object()
|
||||
data['id'] = values.id
|
||||
data['cliente'] = values.id_partner
|
||||
data['productos'] = rows
|
||||
data['serie'] = $$('lst_serie').getText()
|
||||
data['forma_pago'] = $$('lst_forma_pago').getValue()
|
||||
data['condiciones_pago'] = $$('txt_condicion_pago').getValue().trim()
|
||||
data['moneda'] = $$('lst_moneda').getValue()
|
||||
data['tipo_cambio'] = $$('txt_tipo_cambio').getValue()
|
||||
data['tipo_comprobante'] = $$('lst_tipo_comprobante').getValue()
|
||||
data['metodo_pago'] = $$('lst_metodo_pago').getValue()
|
||||
data['uso_cfdi'] = $$('lst_uso_cfdi').getValue()
|
||||
data['regimen_fiscal'] = $$('lst_regimen_fiscal').getValue()
|
||||
|
||||
if(!save_invoice(data)){
|
||||
return
|
||||
}
|
||||
|
||||
form.setValues({id_partner: 0, lbl_partner: 'Ninguno'})
|
||||
$$('multi_invoices').setValue('invoices_home')
|
||||
}
|
||||
|
||||
|
||||
function cmd_close_invoice_click(id, e, node){
|
||||
$$('multi_invoices').setValue('invoices_home')
|
||||
}
|
||||
|
||||
|
||||
function search_client_by_id(id){
|
||||
var msg = ''
|
||||
webix.ajax().get('/values/client', {'id': id}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type: 'error', text: 'Error al consultar'})
|
||||
},
|
||||
success: function(text, data, xhr){
|
||||
var values = data.json()
|
||||
if (values.ok){
|
||||
set_client(values.row)
|
||||
}else{
|
||||
msg = 'No se encontró un cliente con la clave: ' + id
|
||||
webix.message({type:'error', text: msg})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function set_client(row){
|
||||
var form = $$('form_invoice')
|
||||
var html = '<span class="webix_icon fa-user"></span><span class="lbl_partner">'
|
||||
form.setValues({
|
||||
id_partner:row.id, search_client_id:'', search_client_name:'',
|
||||
forma_pago: row.forma_pago, uso_cfdi: row.uso_cfdi}, true)
|
||||
html += row.nombre + ' (' + row.rfc + ')</span>'
|
||||
$$('lbl_client').setValue(html)
|
||||
form.focus('search_product_id')
|
||||
}
|
||||
|
||||
|
||||
function grid_clients_found_click(obj){
|
||||
set_client(obj)
|
||||
}
|
||||
|
||||
|
||||
function search_client_id_key_press(code, e){
|
||||
var value = this.getValue()
|
||||
if(code == 13 && value.length > 0){
|
||||
var id = parseInt(value, 10)
|
||||
if (isNaN(id)){
|
||||
webix.message({type:'error', text:'Captura una clave válida'});
|
||||
}else{
|
||||
search_client_by_id(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function calculate_taxes(){
|
||||
var tmp = null
|
||||
table_totals.clear()
|
||||
var subtotal = 0
|
||||
var total_iva = 0
|
||||
var id = 2
|
||||
var grid_totals = $$('grid_totals')
|
||||
|
||||
grid_totals.clearAll()
|
||||
grid_totals.add({id: 1, concepto: 'SubTotal', importe: 0})
|
||||
|
||||
grid.eachRow(function(row){
|
||||
var product = grid.getItem(row)
|
||||
subtotal += parseFloat(product.importe)
|
||||
query = table_pt.chain().find({'product': product.id}).data()
|
||||
for(var tax of query){
|
||||
tmp = table_totals.findOne({'tax': tax.tax})
|
||||
if(tmp === null){
|
||||
table_totals.insert(
|
||||
{'tax': tax.tax, 'importe': parseFloat(product.importe)})
|
||||
tmp = table_totals.findOne({'tax': tax.tax})
|
||||
}else{
|
||||
tmp.importe += parseFloat(product.importe)
|
||||
table_totals.update(tmp)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var tax = null
|
||||
var tipo = 'Traslado '
|
||||
var concepto = ''
|
||||
var total_tax = 0
|
||||
query = table_totals.chain().data()
|
||||
for(var t of query){
|
||||
tax = table_taxes.findOne({'id': t.tax})
|
||||
if(tax.tipo == 'E' || tax.tipo == 'R'){
|
||||
continue
|
||||
}
|
||||
concepto = tipo + tax.name + ' (' + tax.tasa + ')'
|
||||
total_tax = (tax.tasa * t.importe).round(DECIMALES)
|
||||
grid_totals.add({id: id, concepto: concepto, importe: total_tax})
|
||||
id += 1
|
||||
if(tax.name == 'IVA'){
|
||||
total_iva += total_tax
|
||||
}
|
||||
}
|
||||
|
||||
tipo = 'Retención '
|
||||
for(var t of query){
|
||||
tax = table_taxes.findOne({'id': t.tax})
|
||||
if(tax.tipo == 'E' || tax.tipo == 'T'){
|
||||
continue
|
||||
}
|
||||
concepto = tipo + tax.name + ' (' + tax.tasa + ')'
|
||||
if(tax.tasa == (2/3).round(6)){
|
||||
total_tax = (tax.tasa * total_iva * -1).round(DECIMALES)
|
||||
concepto = tipo + tax.name + ' (2/3)'
|
||||
}else{
|
||||
total_tax = (tax.tasa * t.importe * -1).round(DECIMALES)
|
||||
}
|
||||
grid_totals.add({id: id, concepto: concepto, importe: total_tax})
|
||||
id += 1
|
||||
}
|
||||
|
||||
var row = {importe: subtotal}
|
||||
grid_totals.updateItem(1, row)
|
||||
}
|
||||
|
||||
|
||||
function set_product(values){
|
||||
var taxes = values.taxes
|
||||
var values = values.row
|
||||
var form = $$('form_invoice')
|
||||
var row = grid.getItem(values.id)
|
||||
|
||||
values['delete'] = '-'
|
||||
if (row == undefined){
|
||||
values['cantidad'] = 1
|
||||
values['importe'] = values['valor_unitario']
|
||||
grid.add(values)
|
||||
} else {
|
||||
values['cantidad'] = parseFloat(row.cantidad) + 1
|
||||
values['importe'] = values['valor_unitario'] * values['cantidad']
|
||||
grid.updateItem(row.id, values)
|
||||
}
|
||||
form.setValues({search_product_id:'', search_product_name:''}, true)
|
||||
|
||||
for(var v of taxes){
|
||||
var pt = table_pt.findOne(v)
|
||||
if(pt === null){
|
||||
table_pt.insert(v)
|
||||
}
|
||||
}
|
||||
calculate_taxes()
|
||||
}
|
||||
|
||||
|
||||
function grid_products_found_click(obj){
|
||||
search_product_by_id(obj.id)
|
||||
}
|
||||
|
||||
|
||||
function search_product_by_id(id){
|
||||
var msg = ''
|
||||
|
||||
webix.ajax().get('/values/product', {'id': id}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type: 'error', text: 'Error al consultar'})
|
||||
},
|
||||
success: function(text, data, xhr){
|
||||
var values = data.json()
|
||||
if (values.ok){
|
||||
set_product(values)
|
||||
} else {
|
||||
msg = 'No se encontró un producto con la clave: ' + id
|
||||
webix.message({type: 'error', text: msg})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function search_product_id_key_press(code, e){
|
||||
var value = this.getValue()
|
||||
if(code == 13 && value.length > 0){
|
||||
var id = parseInt(value, 10)
|
||||
if (isNaN(id)){
|
||||
webix.message({type: 'error', text: 'Captura una clave válida'});
|
||||
}else{
|
||||
search_product_by_id(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function grid_details_before_edit_start(id){
|
||||
var columns = ['', 'descripcion', 'cantidad', 'valor_unitario']
|
||||
if(!columns.indexOf(id.column)){
|
||||
return !this.getItem(id.row)[id.column]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function grid_details_before_edit_stop(state, editor){
|
||||
var row = grid.getItem(editor.row)
|
||||
|
||||
if(editor.column == 'descripcion'){
|
||||
if(!state.value.trim()){
|
||||
msg = 'La descripción no puede estar vacía'
|
||||
webix.message({type:'error', text: msg})
|
||||
grid.blockEvent()
|
||||
state.value = state.old
|
||||
grid.editCancel()
|
||||
grid.unblockEvent()
|
||||
return true
|
||||
}
|
||||
state.value = state.value.trim()
|
||||
return true
|
||||
}
|
||||
|
||||
if(editor.column == 'cantidad'){
|
||||
var cantidad = parseFloat(state.value)
|
||||
if(isNaN(cantidad)){
|
||||
msg = 'La cantidad debe ser un número'
|
||||
webix.message({type:'error', text: msg})
|
||||
grid.blockEvent()
|
||||
state.value = state.old
|
||||
grid.editCancel()
|
||||
grid.unblockEvent()
|
||||
return true
|
||||
}
|
||||
var valor_unitario = row['valor_unitario']
|
||||
}
|
||||
|
||||
if(editor.column == 'valor_unitario'){
|
||||
var valor_unitario = parseFloat(state.value)
|
||||
if(isNaN(valor_unitario)){
|
||||
msg = 'El valor unitario debe ser un número'
|
||||
webix.message({type:'error', text: msg})
|
||||
grid.blockEvent()
|
||||
state.value = state.old
|
||||
grid.editCancel()
|
||||
grid.unblockEvent()
|
||||
return true
|
||||
}
|
||||
var cantidad = row['cantidad']
|
||||
}
|
||||
|
||||
row['importe'] = (cantidad * valor_unitario).round(DECIMALES)
|
||||
grid.refresh()
|
||||
calculate_taxes()
|
||||
}
|
||||
|
||||
|
||||
function grid_details_click(id, e, node){
|
||||
if(id.column != 'delete'){
|
||||
return
|
||||
}
|
||||
grid.remove(id.row)
|
||||
calculate_taxes()
|
||||
}
|
||||
|
||||
|
||||
function grid_details_header_click(id){
|
||||
if(id.column != 'delete'){
|
||||
return
|
||||
}
|
||||
|
||||
var msg = '¿Estás seguro de quitar todos los productos?'
|
||||
webix.confirm({
|
||||
title: 'Quitar todos',
|
||||
ok: 'Si',
|
||||
cancel: 'No',
|
||||
type: 'confirm-error',
|
||||
text: msg,
|
||||
callback:function(result){
|
||||
if (result){
|
||||
grid.clearAll()
|
||||
calculate_taxes()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function cmd_refacturar_click(){
|
||||
show('Refacturar')
|
||||
}
|
||||
|
||||
|
||||
function cmd_invoice_timbrar_click(){
|
||||
if(gi.count() == 0){
|
||||
return
|
||||
}
|
||||
|
||||
var row = gi.getSelectedItem()
|
||||
if (row == undefined){
|
||||
msg_error('Selecciona una factura')
|
||||
return
|
||||
}
|
||||
|
||||
if(row.uuid){
|
||||
msg_error('La factura ya esta timbrada')
|
||||
return
|
||||
}
|
||||
|
||||
msg = '¿Estás seguro de enviar a timbrar esta factura?'
|
||||
webix.confirm({
|
||||
title: 'Timbrar Factura',
|
||||
ok: 'Si',
|
||||
cancel: 'No',
|
||||
type: 'confirm-error',
|
||||
text: msg,
|
||||
callback:function(result){
|
||||
if(result){
|
||||
send_timbrar(row.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function grid_invoices_click(id, e, node){
|
||||
var row = this.getItem(id)
|
||||
if(id.column == 'xml'){
|
||||
location = '/doc/xml/' + row.id
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
var gi = null
|
||||
|
||||
|
||||
var controllers = {
|
||||
init: function(){
|
||||
//~ Main
|
||||
$$('menu_user').attachEvent('onMenuItemClick', menu_user_click);
|
||||
//~ Partner
|
||||
$$('cmd_new_partner').attachEvent('onItemClick', cmd_new_partner_click);
|
||||
$$('cmd_new_contact').attachEvent('onItemClick', cmd_new_contact_click);
|
||||
$$('cmd_edit_partner').attachEvent('onItemClick', cmd_edit_partner_click);
|
||||
$$('cmd_delete_partner').attachEvent('onItemClick', cmd_delete_partner_click);
|
||||
$$('cmd_save_partner').attachEvent('onItemClick', cmd_save_partner_click);
|
||||
$$('cmd_cancel_partner').attachEvent('onItemClick', cmd_cancel_partner_click);
|
||||
$$('cmd_cancel_contact').attachEvent('onItemClick', cmd_cancel_contact_click);
|
||||
$$('codigo_postal').attachEvent('onKeyPress', postal_code_key_press);
|
||||
$$('codigo_postal').attachEvent('onTimedKeyPress', postal_code_key_up);
|
||||
$$('colonia').attachEvent('onFocus', colonia_on_focus)
|
||||
$$("tipo_persona").attachEvent( "onChange", opt_tipo_change)
|
||||
$$("es_cliente").attachEvent( "onChange", is_client_change)
|
||||
$$("es_proveedor").attachEvent( "onChange", is_supplier_change)
|
||||
$$("rfc").attachEvent( "onBlur", rfc_lost_focus)
|
||||
$$('multi').attachEvent('onViewChange', multi_change)
|
||||
//~ Products
|
||||
$$("cmd_new_product").attachEvent("onItemClick", cmd_new_product_click)
|
||||
$$("cmd_edit_product").attachEvent("onItemClick", cmd_edit_product_click)
|
||||
$$("cmd_delete_product").attachEvent("onItemClick", cmd_delete_product_click)
|
||||
$$("cmd_save_product").attachEvent("onItemClick", cmd_save_product_click)
|
||||
$$("cmd_cancel_product").attachEvent("onItemClick", cmd_cancel_product_click)
|
||||
$$("chk_automatica").attachEvent("onChange", chk_automatica_change)
|
||||
$$("valor_unitario").attachEvent("onChange", valor_unitario_change)
|
||||
//~ Invoices
|
||||
$$('cmd_new_invoice').attachEvent("onItemClick", cmd_new_invoice_click)
|
||||
$$('cmd_refacturar').attachEvent("onItemClick", cmd_refacturar_click)
|
||||
$$('cmd_delete_invoice').attachEvent("onItemClick", cmd_delete_invoice_click)
|
||||
$$('cmd_timbrar').attachEvent('onItemClick', cmd_timbrar_click)
|
||||
$$('cmd_close_invoice').attachEvent('onItemClick', cmd_close_invoice_click)
|
||||
$$('search_client_id').attachEvent('onKeyPress', search_client_id_key_press)
|
||||
$$('grid_clients_found').attachEvent('onValueSuggest', grid_clients_found_click)
|
||||
$$('search_product_id').attachEvent('onKeyPress', search_product_id_key_press)
|
||||
$$('grid_products_found').attachEvent('onValueSuggest', grid_products_found_click)
|
||||
$$('grid_details').attachEvent('onItemClick', grid_details_click)
|
||||
$$('grid_details').attachEvent('onHeaderClick', grid_details_header_click)
|
||||
$$('grid_details').attachEvent('onBeforeEditStart', grid_details_before_edit_start)
|
||||
$$('grid_details').attachEvent('onBeforeEditStop', grid_details_before_edit_stop)
|
||||
$$('cmd_invoice_timbrar').attachEvent('onItemClick', cmd_invoice_timbrar_click)
|
||||
$$('grid_invoices').attachEvent('onItemClick', grid_invoices_click)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function get_uso_cfdi_to_table(args){
|
||||
webix.ajax().sync().get('/values/usocfdi', args, function(text, data){
|
||||
var values = data.json()
|
||||
table_usocfdi.clear()
|
||||
table_usocfdi.insert(values)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function get_partners(){
|
||||
webix.ajax().get("/partners", {}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({ type:"error", text: "Error al consultar"});
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
$$("grid_partners").clearAll();
|
||||
if (values.ok){
|
||||
$$("grid_partners").parse(values.rows, 'json');
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function get_products(){
|
||||
var grid = $$('grid_products')
|
||||
webix.ajax().get('/products', {}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type: 'error', text: 'Error al consultar'})
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
grid.clearAll();
|
||||
if (values.ok){
|
||||
grid.parse(values.rows, 'json');
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function get_invoices(){
|
||||
var grid = $$('grid_invoices')
|
||||
webix.ajax().get('/invoices', {}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type: 'error', text: 'Error al consultar'})
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
grid.clearAll();
|
||||
if (values.ok){
|
||||
grid.parse(values.rows, 'json');
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function menu_user_click(id, e, node){
|
||||
if (id == 1){
|
||||
window.location = '/logout';
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function multi_change(prevID, nextID){
|
||||
//~ webix.message(nextID)
|
||||
if(nextID == 'app_partners'){
|
||||
active = $$('multi_partners').getActiveId()
|
||||
if(active == 'partners_home'){
|
||||
get_partners()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if(nextID == 'app_products'){
|
||||
active = $$('multi_products').getActiveId()
|
||||
if(active == 'products_home'){
|
||||
get_products()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if(nextID == 'app_invoices'){
|
||||
active = $$('multi_invoices').getActiveId()
|
||||
if(active == 'invoices_home'){
|
||||
get_invoices()
|
||||
}
|
||||
gi = $$('grid_invoices')
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function get_taxes(){
|
||||
webix.ajax().sync().get('/values/taxes', function(text, data){
|
||||
var values = data.json()
|
||||
table_taxes.clear()
|
||||
table_taxes.insert(values)
|
||||
$$("grid_product_taxes").clearAll()
|
||||
$$("grid_product_taxes").parse(values, 'json')
|
||||
})
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
|
||||
|
||||
function cmd_new_partner_click(id, e, node){
|
||||
$$('form_partner').setValues({
|
||||
id: 0, pais: 'México', tipo_persona: 1, es_activo: true})
|
||||
$$('forma_pago').getList().load('/values/formapago')
|
||||
$$('grid_partners').clearSelection()
|
||||
$$('multi_partners').setValue('partners_new')
|
||||
$$('tab_partner').setValue('Datos Fiscales')
|
||||
|
||||
get_uso_cfdi_to_table({})
|
||||
query = table_usocfdi.chain().find({fisica: true}).data()
|
||||
$$('lst_uso_cfdi_socio').getList().parse(query)
|
||||
}
|
||||
|
||||
|
||||
function cmd_new_contact_click(id, e, node){
|
||||
$$('grid_contacts').clearSelection()
|
||||
$$('multi_contacts').setValue('contacts_new')
|
||||
}
|
||||
|
||||
|
||||
function cmd_edit_partner_click(id, e, node){
|
||||
var msg = ''
|
||||
var row = $$('grid_partners').getSelectedItem()
|
||||
|
||||
if (row == undefined){
|
||||
msg = 'Selecciona un Socio de Negocio'
|
||||
webix.message({type:'error', text: msg})
|
||||
return
|
||||
}
|
||||
|
||||
webix.ajax().get("/partners", {id: row['id']}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type:"error", text: "Error al consultar"})
|
||||
},
|
||||
success: function(text, data, xhr){
|
||||
var values = data.json()
|
||||
$$('form_partner').setValues(values)
|
||||
$$('forma_pago').getList().load('/values/formapago')
|
||||
|
||||
get_uso_cfdi_to_table({})
|
||||
if(values.tipo_persona == 1){
|
||||
query = table_usocfdi.chain().find({fisica: true}).data()
|
||||
}else if(values.tipo_persona == 2){
|
||||
query = table_usocfdi.chain().find({moral: true}).data()
|
||||
}else{
|
||||
query = [{id: 'P01', value: 'Por definir'}]
|
||||
}
|
||||
$$('lst_uso_cfdi_socio').getList().parse(query)
|
||||
if(values.es_cliente){
|
||||
$$('cuenta_cliente').enable()
|
||||
}
|
||||
if(values.es_proveedor){
|
||||
$$('cuenta_proveedor').enable()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$$('multi_partners').setValue('partners_new')
|
||||
$$('tab_partner').setValue('Datos Fiscales')
|
||||
};
|
||||
|
||||
|
||||
function cmd_delete_partner_click(id, e, node){
|
||||
var msg = ''
|
||||
var row = $$('grid_partners').getSelectedItem()
|
||||
|
||||
if (row == undefined){
|
||||
msg = 'Selecciona un Cliente o Proveedor'
|
||||
webix.message({type:'error', text: msg})
|
||||
return
|
||||
}
|
||||
|
||||
msg = '¿Estás seguro de eliminar al cliente?<BR><BR>'
|
||||
msg += row['nombre'] + ' (' + row['rfc'] + ')'
|
||||
msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER<BR><BR>'
|
||||
msg += 'Solo se pueden eliminar clientes o proveedores sin documentos '
|
||||
msg += 'relacionados. Se recomienda solo desactivar en vez de eliminar'
|
||||
webix.confirm({
|
||||
title:'Eliminar Cliente',
|
||||
ok:'Si',
|
||||
cancel:'No',
|
||||
type:'confirm-error',
|
||||
text:msg,
|
||||
callback:function(result){
|
||||
if (result){
|
||||
delete_partner(row['id'])
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
function delete_partner(id){
|
||||
webix.ajax().del('/partners', {id: id}, function(text, xml, xhr){
|
||||
var msg = 'Socio eliminado correctamente'
|
||||
if (xhr.status == 200){
|
||||
$$('grid_partners').remove(id);
|
||||
webix.message({type: 'success', text: msg})
|
||||
} else {
|
||||
msg = 'No se pudo eliminar. Asegurate de que no tenga documentos relacionados'
|
||||
webix.message({type: 'error', text: msg})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function cmd_save_partner_click(id, e, node){
|
||||
var msg = 'Valores inválidos'
|
||||
var form = this.getFormView();
|
||||
|
||||
if (!form.validate()) {
|
||||
webix.message({type: 'error', text: msg})
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues();
|
||||
|
||||
if(values.codigo_postal && values.codigo_postal.length != 5){
|
||||
msg = 'Longitud inválida del C.P.'
|
||||
msg_error(msg)
|
||||
return
|
||||
}
|
||||
|
||||
if (!values.es_cliente && !values.es_proveedor){
|
||||
msg = 'Selecciona si es cliente, proveedor o ambos'
|
||||
msg_error(msg)
|
||||
$$('tab_partner').setValue('Otros Datos')
|
||||
return
|
||||
}
|
||||
|
||||
webix.ajax().post('/partners', values, {
|
||||
error:function(text, data, XmlHttpRequest){
|
||||
msg = 'Ocurrio un error, consulta a soporte técnico';
|
||||
webix.message({type:'error', text:msg});
|
||||
},
|
||||
success:function(text, data, XmlHttpRequest){
|
||||
var values = data.json();
|
||||
if (values.ok) {
|
||||
update_grid_partner(values)
|
||||
} else {
|
||||
webix.message({type:'error', text:values.msg});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function update_grid_partner(values){
|
||||
var msg = 'Socio de negocio agregado correctamente'
|
||||
if (values.new){
|
||||
$$('form_partner').clear()
|
||||
$$('grid_partners').add(values.row)
|
||||
}else{
|
||||
msg = 'Socio de negocio actualizado correctamente'
|
||||
$$("grid_partners").updateItem(values.row['id'], values.row)
|
||||
}
|
||||
$$('multi_partners').setValue('partners_home')
|
||||
webix.message({type:'success', text: msg})
|
||||
}
|
||||
|
||||
|
||||
function cmd_cancel_partner_click(id, e, node){
|
||||
$$('multi_partners').setValue('partners_home')
|
||||
}
|
||||
|
||||
|
||||
function cmd_cancel_contact_click(id, e, node){
|
||||
$$('multi_contacts').setValue('contacts_home')
|
||||
}
|
||||
|
||||
|
||||
function postal_code_key_up(){
|
||||
var value = this.getValue()
|
||||
var msg = ''
|
||||
if( value.length == 5 ){
|
||||
webix.ajax().get('/values/cp', {cp: value}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type:'error', text:'Error al consultar el C.P.'})
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
if (values.estado == undefined){
|
||||
msg = 'No se encontró el C.P., asegurate de que sea correcto'
|
||||
webix.message({type:'error', text:msg})
|
||||
} else {
|
||||
$$('form_partner').setValues({
|
||||
estado: values.estado,
|
||||
municipio: values.municipio,
|
||||
colonia: ''}, true)
|
||||
$$('colonia').define('suggest', [])
|
||||
if (webix.isArray(values.colonia)){
|
||||
$$('colonia').define('suggest', values.colonia)
|
||||
}else{
|
||||
$$('form_partner').setValues({colonia: values.colonia}, true)
|
||||
}
|
||||
$$('colonia').refresh()
|
||||
$$('form_partner').focus('colonia')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function postal_code_key_press(code, e){
|
||||
var data = [8, 9, 37, 39, 46]
|
||||
if ( data.indexOf(code) >= 0 ){
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( code < 48 || code > 57){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function colonia_on_focus(){
|
||||
if ($$(this.config.suggest).getList().config.height > 2){
|
||||
$$(this.config.suggest).show(this.getInputNode())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function opt_tipo_change(new_value, old_value){
|
||||
|
||||
$$("nombre").define("value", "")
|
||||
$$("pais").define("readonly", true)
|
||||
$$("pais").define("value", PAIS)
|
||||
|
||||
|
||||
if (new_value == 1 || new_value == 2){
|
||||
$$("rfc").define("value", "");
|
||||
$$("rfc").define("readonly", false);
|
||||
} else if (new_value == 3) {
|
||||
$$("rfc").define("value", RFC_PUBLICO);
|
||||
$$("nombre").define("value", PUBLICO);
|
||||
$$("rfc").define("readonly", true);
|
||||
} else if (new_value == 4) {
|
||||
$$("rfc").define("value", RFC_EXTRANJERO);
|
||||
$$("rfc").define("readonly", true);
|
||||
$$("pais").define("readonly", false);
|
||||
$$("pais").define("value", "");
|
||||
}
|
||||
|
||||
$$("nombre").refresh();
|
||||
$$("rfc").refresh();
|
||||
$$("pais").refresh();
|
||||
if (new_value == 3) {
|
||||
$$("calle").focus();
|
||||
} else {
|
||||
$$("rfc").focus();
|
||||
}
|
||||
|
||||
$$('lst_uso_cfdi_socio').define('suggest', [])
|
||||
if (new_value == 1){
|
||||
query = table_usocfdi.chain().find({fisica: true}).data()
|
||||
}else if (new_value == 2){
|
||||
query = table_usocfdi.chain().find({moral: true}).data()
|
||||
}else{
|
||||
query = [{id: 'P01', value: 'Por definir'}]
|
||||
}
|
||||
$$('lst_uso_cfdi_socio').getList().parse(query)
|
||||
$$('lst_uso_cfdi_socio').refresh()
|
||||
}
|
||||
|
||||
|
||||
function is_client_change(new_value, old_value){
|
||||
var value = Boolean(new_value)
|
||||
if (value){
|
||||
$$("cuenta_cliente").enable();
|
||||
} else {
|
||||
$$("cuenta_cliente").disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function is_supplier_change(new_value, old_value){
|
||||
var value = Boolean(new_value)
|
||||
if (value){
|
||||
$$("cuenta_proveedor").enable();
|
||||
} else {
|
||||
$$("cuenta_proveedor").disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function rfc_lost_focus(prev_view){
|
||||
//~ var form = this.getFormView()
|
||||
//~ var values = form.getValues()
|
||||
|
||||
//~ if (values.rfc.trim() == ""){
|
||||
//~ return
|
||||
//~ }
|
||||
|
||||
//~ if (values.id == undefined){
|
||||
//~ exclude = ''
|
||||
//~ } else {
|
||||
//~ exclude = {'id': values.id}
|
||||
//~ }
|
||||
|
||||
//~ values = {
|
||||
//~ 'table': 'partner',
|
||||
//~ 'filter': {'rfc': values.rfc.trim().toUpperCase()},
|
||||
//~ 'exclude': exclude,
|
||||
//~ }
|
||||
//~ webix.message(values)
|
||||
//~ webix.ajax().get("/values/validate", values, {
|
||||
//~ error:function(text, data, XmlHttpRequest){
|
||||
//~ msg = "No se pudo validar el RFC"
|
||||
//~ webix.message({ type:"error", text: msg });
|
||||
//~ },
|
||||
//~ success:function(text, data, XmlHttpRequest){
|
||||
//~ var values = data.json();
|
||||
//~ if (values.exists) {
|
||||
//~ msg = "El RFC ya existe"
|
||||
//~ webix.message({ type:"error", text: msg });
|
||||
//~ }
|
||||
//~ }
|
||||
//~ })
|
||||
}
|
||||
|
||||
|
||||
function multi_partners_change(prevID, nextID){
|
||||
webix.message(prevID)
|
||||
webix.message(nextID)
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
|
||||
function cmd_new_product_click(id, e, node){
|
||||
$$('form_product').setValues({
|
||||
id: 0, es_activo_producto: true})
|
||||
add_config({'key': 'id_product', 'value': ''})
|
||||
get_new_key()
|
||||
get_taxes()
|
||||
$$('grid_products').clearSelection()
|
||||
$$('categoria').getList().load('/values/categorias')
|
||||
$$('unidad').getList().load('/values/unidades')
|
||||
$$("multi_products").setValue("product_new")
|
||||
}
|
||||
|
||||
|
||||
function cmd_edit_product_click(id, e, node){
|
||||
var grid = $$('grid_products')
|
||||
var row = grid.getSelectedItem()
|
||||
if(row == undefined){
|
||||
webix.message({type: 'error', text: 'Selecciona un Producto'})
|
||||
return
|
||||
}
|
||||
|
||||
get_taxes()
|
||||
$$('categoria').getList().load('/values/categorias')
|
||||
$$('unidad').getList().load('/values/unidades')
|
||||
|
||||
webix.ajax().get('/products', {id:row['id']}, {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type: 'error', text: 'Error al consultar'})
|
||||
},
|
||||
success: function(text, data, xhr){
|
||||
var values = data.json()
|
||||
$$('form_product').setValues(values.row)
|
||||
add_config({'key': 'id_product', 'value': values.row.id})
|
||||
for(i = 0; i < values.taxes.length; i++){
|
||||
$$('grid_product_taxes').select(values.taxes[i], true)
|
||||
}
|
||||
}
|
||||
})
|
||||
$$('multi_products').setValue('product_new')
|
||||
|
||||
};
|
||||
|
||||
|
||||
function delete_product(id){
|
||||
webix.ajax().del('/products', {id:id}, function(text, xml, xhr){
|
||||
var msg = 'Producto eliminado correctamente'
|
||||
if(xhr.status == 200){
|
||||
$$('grid_products').remove(id)
|
||||
webix.message({type:'success', text:msg})
|
||||
}else{
|
||||
msg = 'No se pudo eliminar'
|
||||
webix.message({type:'error', text:msg})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function cmd_delete_product_click(id, e, node){
|
||||
var row = $$('grid_products').getSelectedItem()
|
||||
if (row == undefined){
|
||||
webix.message({type:'error', text: 'Selecciona un Producto'})
|
||||
return
|
||||
}
|
||||
|
||||
var msg = '¿Estás seguro de eliminar el Producto?<BR><BR>'
|
||||
msg += '(' + row['clave'] + ') ' + row['descripcion']
|
||||
msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER<BR><BR>Se recomienda '
|
||||
msg += 'solo desactivar el producto en vez de eliminar'
|
||||
webix.confirm({
|
||||
title: 'Eliminar Producto',
|
||||
ok: 'Si',
|
||||
cancel: 'No',
|
||||
type: 'confirm-error',
|
||||
text: msg,
|
||||
callback:function(result){
|
||||
if (result){
|
||||
delete_product(row['id'])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function validate_sat_key_product(key, text){
|
||||
var result = false
|
||||
webix.ajax().sync().get('/values/satkey', {key:key}, function(text, data){
|
||||
result = data.json()
|
||||
})
|
||||
if(text){
|
||||
if(result.ok){
|
||||
return '<b>' + result.text + '</b>'
|
||||
}else{
|
||||
return '<b><font color="red">' + result.text + '</font></b>'
|
||||
}
|
||||
}
|
||||
return result.ok
|
||||
}
|
||||
|
||||
|
||||
function update_grid_products(values){
|
||||
var msg = 'Producto agregado correctamente'
|
||||
if(values.new){
|
||||
$$('form_product').clear()
|
||||
$$('grid_products').add(values.row)
|
||||
}else{
|
||||
msg = 'Producto actualizado correctamente'
|
||||
$$("grid_products").updateItem(values.row['id'], values.row)
|
||||
}
|
||||
$$('multi_products').setValue('products_home')
|
||||
webix.message({type: 'success', text: msg})
|
||||
}
|
||||
|
||||
|
||||
function cmd_save_product_click(id, e, node){
|
||||
var msg = ''
|
||||
var form = this.getFormView()
|
||||
|
||||
if(!form.validate()){
|
||||
webix.message({type: 'error', text: 'Valores inválidos'})
|
||||
return
|
||||
}
|
||||
|
||||
var rows = $$('grid_product_taxes').getSelectedId(true, true)
|
||||
if (rows.length == 0){
|
||||
webix.message({type: 'error', text: 'Selecciona un impuesto'})
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues();
|
||||
|
||||
if (!validate_sat_key_product(values.clave_sat, false)){
|
||||
webix.message({ type:'error', text:'La clave SAT no existe' })
|
||||
return
|
||||
}
|
||||
|
||||
values['taxes'] = JSON.stringify(rows)
|
||||
webix.ajax().sync().post('products', values, {
|
||||
error:function(text, data, XmlHttpRequest){
|
||||
msg = 'Ocurrio un error, consulta a soporte técnico'
|
||||
webix.message({type: 'error', text: msg})
|
||||
},
|
||||
success:function(text, data, XmlHttpRequest){
|
||||
var values = data.json();
|
||||
if (values.ok) {
|
||||
update_grid_products(values)
|
||||
}else{
|
||||
webix.message({type:'error', text:values.msg})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function cmd_cancel_product_click(id, e, node){
|
||||
|
||||
$$("multi_products").setValue("products_home")
|
||||
|
||||
};
|
||||
|
||||
|
||||
function chk_automatica_change(new_value, old_value){
|
||||
var value = Boolean(new_value)
|
||||
if (value){
|
||||
var value = get_config('id_product')
|
||||
if(value){
|
||||
$$("clave").setValue(value)
|
||||
$$("clave").refresh()
|
||||
}else{
|
||||
get_new_key()
|
||||
}
|
||||
$$("clave").config.readonly = true
|
||||
$$('form_product').focus('clave_sat')
|
||||
} else {
|
||||
$$("clave").setValue('')
|
||||
$$("clave").config.readonly = false
|
||||
$$('form_product').focus('clave')
|
||||
}
|
||||
$$("clave").refresh()
|
||||
}
|
||||
|
||||
|
||||
function get_new_key(){
|
||||
webix.ajax().get('/values/newkey', {
|
||||
error: function(text, data, xhr) {
|
||||
webix.message({type:'error', text: text})
|
||||
},
|
||||
success: function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
$$("clave").setValue(values.value)
|
||||
$$("clave").refresh()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function valor_unitario_change(new_value, old_value){
|
||||
if(!isFinite(new_value)){
|
||||
this.config.value = old_value
|
||||
this.refresh()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
var PUBLICO = "Público en general";
|
||||
var RFC_PUBLICO = "XAXX010101000";
|
||||
var RFC_EXTRANJERO = "XEXX010101000";
|
||||
var PAIS = "México";
|
||||
var DECIMALES = 2;
|
||||
|
||||
|
||||
var db = new loki('data.db');
|
||||
var table_config = db.addCollection('config')
|
||||
var table_taxes = db.addCollection('taxes')
|
||||
var table_pt = db.addCollection('productstaxes')
|
||||
var table_totals = db.addCollection('totals', {unique: ['tax']})
|
||||
var table_series = db.addCollection('series')
|
||||
var table_usocfdi = db.addCollection('usocfdi')
|
||||
|
||||
|
||||
function show(values){
|
||||
webix.message(JSON.stringify(values, null, 2))
|
||||
}
|
||||
|
||||
|
||||
function msg_error(msg){
|
||||
webix.message({type: 'error', text: msg})
|
||||
}
|
||||
|
||||
|
||||
function msg_sucess(msg){
|
||||
webix.message({type: 'sucess', text: msg})
|
||||
}
|
||||
|
||||
|
||||
Number.prototype.round = function(decimals){
|
||||
return Number((Math.round(this + "e" + decimals) + "e-" + decimals))
|
||||
}
|
||||
|
||||
|
||||
webix.protoUI({
|
||||
$cssName: "text",
|
||||
name: "currency",
|
||||
$init:function(){
|
||||
this.attachEvent("onItemClick", function(){
|
||||
this.$setValue(this.config.raw, true)
|
||||
})
|
||||
this.attachEvent("onBlur", function(){
|
||||
this.$setValue(this.config.value)
|
||||
})
|
||||
},
|
||||
$render:function(){
|
||||
this.$setValue(this.config.value)
|
||||
},
|
||||
$setValue:function(value, raw){
|
||||
this.config.raw = value
|
||||
if(!raw){
|
||||
value = webix.i18n.priceFormat(value)
|
||||
}
|
||||
this.getInputNode().value = value
|
||||
}
|
||||
}, webix.ui.text)
|
||||
|
||||
|
||||
webix.ui.datafilter.rowCount = webix.extend({
|
||||
refresh:function(master, node, value){
|
||||
node.firstChild.innerHTML = master.count();
|
||||
}
|
||||
}, webix.ui.datafilter.summColumn)
|
||||
|
||||
|
||||
function validate_rfc(value){
|
||||
rfc = value.trim().toUpperCase();
|
||||
if ( rfc == ""){
|
||||
webix.message({ type:"error", text:"El RFC no puede estar vacío" });
|
||||
return false
|
||||
}
|
||||
|
||||
var tipo_persona = $$('tipo_persona').getValue()
|
||||
var length = 13
|
||||
var start = 4
|
||||
if(tipo_persona==2){
|
||||
length = 12
|
||||
start = 2
|
||||
}
|
||||
if (rfc.length != length){
|
||||
webix.message({ type:"error", text:"Longitud incorrecta del RFC" });
|
||||
return false
|
||||
}
|
||||
if (tipo_persona < 3 && (rfc == RFC_PUBLICO || rfc == RFC_EXTRANJERO)){
|
||||
webix.message({ type:"error", text:"RFC incorrecto" });
|
||||
return false
|
||||
}
|
||||
|
||||
var part = rfc.slice(0, start);
|
||||
var re = new RegExp('[a-z&Ñ]{' + start + '}', 'i');
|
||||
if (!part.match(re)){
|
||||
webix.message({ type:"error", text: "El RFC tiene caractéres inválidos al inicio" });
|
||||
return false
|
||||
}
|
||||
part = rfc.slice(-3);
|
||||
re = new RegExp('[a-z0-9]{3}', 'i');
|
||||
if (!part.match(re)){
|
||||
webix.message({ type:"error", text: "El RFC tiene caractéres inválidos al final" });
|
||||
return false
|
||||
}
|
||||
|
||||
part = rfc.slice(-9, -3);
|
||||
re = new RegExp('[0-9]{6}', 'i');
|
||||
if (!part.match(re)){
|
||||
webix.message({ type:"error", text: "Fecha inválida" });
|
||||
return false
|
||||
}
|
||||
var month = parseInt(part.slice(-4, -2))
|
||||
if (month == 0 || month > 12 ){
|
||||
webix.message({ type:"error", text: "Fecha inválida" });
|
||||
return false
|
||||
}
|
||||
var day = parseInt(part.slice(-2))
|
||||
if (day == 0 || day > 31 ){
|
||||
webix.message({ type:"error", text: "Fecha inválida" });
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
function validate_email(email){
|
||||
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
return re.test(email)
|
||||
}
|
||||
|
||||
|
||||
function add_config(args){
|
||||
var key = table_config.findOne({key: args.key})
|
||||
if(key===null){
|
||||
table_config.insert(args)
|
||||
}else{
|
||||
key.value = args.value
|
||||
table_config.update(key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function get_config(value){
|
||||
var key = table_config.findOne({key: value})
|
||||
if(key===null){
|
||||
return ''
|
||||
}else{
|
||||
return key.value
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*Spanish (Mexico) locale*/
|
||||
webix.i18n.locales["es-MX"] = {
|
||||
groupDelimiter:",",
|
||||
groupSize:3,
|
||||
decimalDelimiter:".",
|
||||
decimalSize:2,
|
||||
dateFormat:"%d/%n/%Y",
|
||||
timeFormat:"%h:%i %a",
|
||||
longDateFormat:"%l, %d' %je '%F' %je '%Y",
|
||||
fullDateFormat:"%l, %d' %je '%F' %je '%Y %h:%i %a",
|
||||
am:["a.m.","A.M."],
|
||||
pm:["p.m.","P.M."],
|
||||
price:"${obj}",
|
||||
priceSettings:{
|
||||
groupDelimiter:",",
|
||||
groupSize:3,
|
||||
decimalDelimiter:".",
|
||||
decimalSize:2
|
||||
},
|
||||
calendar:{
|
||||
monthFull:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],
|
||||
monthShort:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],
|
||||
dayFull:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],
|
||||
dayShort:["dom","lun","mar","mié","jue","vie","sáb"]
|
||||
}
|
||||
};
|
|
@ -0,0 +1,26 @@
|
|||
/*Spanish locale*/
|
||||
webix.i18n.locales["es"] = {
|
||||
groupDelimiter:".",
|
||||
groupSize:3,
|
||||
decimalDelimiter:",",
|
||||
decimalSize:2,
|
||||
dateFormat:"%d/%n/%Y",
|
||||
timeFormat:"%G:%i",
|
||||
longDateFormat:"%l, %d' %je '%F' %je '%Y",
|
||||
fullDateFormat:"%l, %d' %je '%F' %je '%Y %G:%i",
|
||||
am:null,
|
||||
pm:null,
|
||||
price:"{obj} €",
|
||||
priceSettings:{
|
||||
groupDelimiter:".",
|
||||
groupSize:3,
|
||||
decimalDelimiter:",",
|
||||
decimalSize:2
|
||||
},
|
||||
calendar:{
|
||||
monthFull:["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre"],
|
||||
monthShort:["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic"],
|
||||
dayFull:["domingo","lunes","martes","miércoles","jueves","viernes","sábado"],
|
||||
dayShort:["dom","lun","mar","mié","jue","vie","sáb"]
|
||||
}
|
||||
};
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,275 @@
|
|||
webix.protoUI({
|
||||
name: "sidebar",
|
||||
defaults:{
|
||||
titleHeight: 40,
|
||||
type: "sideBar",
|
||||
activeTitle: true,
|
||||
select: true,
|
||||
scroll: false,
|
||||
collapsed: false,
|
||||
collapsedWidth: 41,
|
||||
position: "left",
|
||||
width: 250,
|
||||
mouseEventDelay: 10
|
||||
},
|
||||
$init: function(config){
|
||||
this.$ready.push(this._initSidebar);
|
||||
this.$ready.push(this._initContextMenu);
|
||||
},
|
||||
|
||||
on_context:{},
|
||||
on_mouse_move:{},
|
||||
_initSidebar: function(){
|
||||
this._fullWidth = this.config.width;
|
||||
this.attachEvent("onBeforeOpen", function(id){
|
||||
if(!this.config.multipleOpen)
|
||||
this.closeAll();
|
||||
return !this.config.collapsed;
|
||||
});
|
||||
this.attachEvent("onItemClick", function(id, ev, node){
|
||||
if(this.getPopup() && !this.getPopup().config.hidden)
|
||||
ev.showpopup = true;
|
||||
if(webix.env.touch)
|
||||
this._showPopup(id, node);
|
||||
});
|
||||
this.attachEvent("onBeforeSelect", function(id){
|
||||
if(!this.getItem(id).$count){
|
||||
var selected = this.getSelectedId();
|
||||
if(selected && id!= selected){
|
||||
var parentId = this.getParentId(selected);
|
||||
|
||||
this.removeCss(parentId, "webix_sidebar_selected");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.attachEvent("onAfterSelect", function(id){
|
||||
var parentId = this.getParentId(id);
|
||||
this.addCss(parentId, "webix_sidebar_selected");
|
||||
var title = this.getPopupTitle();
|
||||
|
||||
title.callEvent("onMasterSelect",[id]);
|
||||
});
|
||||
this.attachEvent("onMouseMove", function(id, ev, node){
|
||||
this._showPopup(id, node);
|
||||
});
|
||||
|
||||
if(this.config.collapsed)
|
||||
this.collapse();
|
||||
},
|
||||
_showPopup: function(id, node){
|
||||
if(this.config.collapsed){
|
||||
var popup = this.getPopup();
|
||||
|
||||
if(popup){
|
||||
var title = this.getPopupTitle();
|
||||
if(title){
|
||||
this._updateTitle(id);
|
||||
}
|
||||
var list = this.getPopupList();
|
||||
if(list){
|
||||
this._updateList(id);
|
||||
}
|
||||
var x = (this.config.position == "left"?this.config.collapsedWidth:-popup.config.width);
|
||||
popup.show(node, {x: x , y:-1});
|
||||
}
|
||||
}
|
||||
},
|
||||
_updateTitle: function(id){
|
||||
var title = this.getPopupTitle();
|
||||
title.masterId = id;
|
||||
title.parse(this.getItem(id));
|
||||
var selectedId = this.getSelectedId();
|
||||
if(selectedId && this.getParentId(selectedId) == id){
|
||||
webix.html.addCss(title.$view, "webix_sidebar_selected", true);
|
||||
}
|
||||
else{
|
||||
webix.html.removeCss(title.$view, "webix_sidebar_selected");
|
||||
}
|
||||
|
||||
if(selectedId == id){
|
||||
webix.html.addCss(title.$view, "webix_selected", true);
|
||||
}
|
||||
else{
|
||||
webix.html.removeCss(title.$view, "webix_selected");
|
||||
}
|
||||
},
|
||||
_updateList: function(id){
|
||||
var list = this.getPopupList();
|
||||
list.masterId = id;
|
||||
var selectedId = this.getSelectedId();
|
||||
var data = [].concat(webix.copy(this.data.getBranch(id)));
|
||||
list.unselect();
|
||||
if(data.length){
|
||||
list.show();
|
||||
list.data.importData(data);
|
||||
if(list.exists(selectedId))
|
||||
list.select(selectedId);
|
||||
}
|
||||
else
|
||||
list.hide();
|
||||
|
||||
},
|
||||
_initContextMenu: function(){
|
||||
var config = this.config,
|
||||
popup;
|
||||
|
||||
if(config.popup){
|
||||
popup = webix.$$(config.popup);
|
||||
}
|
||||
if(!popup){
|
||||
var dirClassName = (config.position=="left"?"webix_sidebar_popup_left":"webix_sidebar_popup_right");
|
||||
var popupConfig = {
|
||||
view:"popup",
|
||||
css: "webix_sidebar_popup "+dirClassName,
|
||||
autofit: false,
|
||||
width: this._fullWidth - this.config.collapsedWidth,
|
||||
borderless: true,
|
||||
padding:0,
|
||||
body:{
|
||||
rows:[
|
||||
{
|
||||
view: "template", borderless: true, css: "webix_sidebar_popup_title",
|
||||
template: "#value#", height: this.config.titleHeight+2,
|
||||
on:{
|
||||
onMasterSelect: function(id){
|
||||
var master = this.getTopParentView().master;
|
||||
if( master && master.getParentId(id) == this.masterId){
|
||||
webix.html.addCss(this.$view, "webix_sidebar_selected", true);
|
||||
}
|
||||
if(master.config.collapsed && master.getItem(id).$level ==1){
|
||||
webix.html.addCss(this.$view, "webix_selected", true);
|
||||
}
|
||||
}
|
||||
},
|
||||
onClick:{
|
||||
webix_template: function(){
|
||||
var id = this.masterId;
|
||||
var master = this.getTopParentView().master;
|
||||
if(!master.getItem(id).$count)
|
||||
master.select(id);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ view: "list", select: true, borderless: true, css: "webix_sidebar_popup_list", autoheight: true,
|
||||
on:{
|
||||
onAfterSelect: function(id){
|
||||
this.getTopParentView().master.select(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
webix.extend(popupConfig, config.popup||{}, true);
|
||||
popup = webix.ui(popupConfig);
|
||||
popup.master = this;
|
||||
}
|
||||
popup.attachEvent("onBeforeShow",function(){
|
||||
return config.collapsed;
|
||||
});
|
||||
var master = this;
|
||||
var h = webix.event(document.body,"mousemove", function(e){
|
||||
var trg = e.target || e.srcElement;
|
||||
if(!popup.config.hidden && !popup.$view.contains(trg) && !master.$view.firstChild.contains(trg)){
|
||||
popup.hide();
|
||||
}
|
||||
});
|
||||
this.attachEvent("onDestruct", function(){
|
||||
if(webix.removeEvent)
|
||||
webix.removeEvent(h);
|
||||
if(popup)
|
||||
popup.destructor();
|
||||
});
|
||||
config.popupId = popup.config.id;
|
||||
},
|
||||
getPopup: function(){
|
||||
return webix.$$(this.config.popupId);
|
||||
},
|
||||
getPopupTitle: function(){
|
||||
var popup = this.getPopup();
|
||||
return popup.getBody().getChildViews()[0];
|
||||
},
|
||||
getPopupList: function(){
|
||||
var popup = this.getPopup();
|
||||
return popup.getBody().getChildViews()[1];
|
||||
},
|
||||
position_setter:function(value){
|
||||
var newPos = value;
|
||||
var oldPos = value=="left"?"right":"left";
|
||||
|
||||
webix.html.removeCss(this.$view, "webix_sidebar_"+oldPos);
|
||||
webix.html.addCss(this.$view, "webix_sidebar_"+newPos, true);
|
||||
|
||||
var popup = this.getPopup();
|
||||
if(popup){
|
||||
var popupEl = popup.$view;
|
||||
webix.html.removeCss(popupEl, "webix_sidebar_popup_"+oldPos);
|
||||
webix.html.addCss(popupEl, "webix_sidebar_popup_"+newPos, true);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
collapse: function(){
|
||||
this.define("collapsed", true);
|
||||
},
|
||||
expand: function(){
|
||||
this.define("collapsed", false);
|
||||
},
|
||||
toggle: function(){
|
||||
var collapsed = !this.config.collapsed;
|
||||
this.define("collapsed", collapsed);
|
||||
},
|
||||
collapsed_setter: function(value){
|
||||
var width;
|
||||
|
||||
if(!value){
|
||||
width = this._fullWidth;
|
||||
}
|
||||
else{
|
||||
width = this.config.collapsedWidth;
|
||||
this.closeAll();
|
||||
}
|
||||
|
||||
if(!value){
|
||||
this.type.collapsed = false;
|
||||
webix.html.addCss(this.$view, "webix_sidebar_expanded", true);
|
||||
}
|
||||
else{
|
||||
this.type.collapsed = true;
|
||||
webix.html.removeCss(this.$view, "webix_sidebar_expanded");
|
||||
}
|
||||
|
||||
this.define("width",width);
|
||||
this.resize();
|
||||
|
||||
return value;
|
||||
}
|
||||
}, webix.ui.tree);
|
||||
|
||||
webix.type(webix.ui.tree, {
|
||||
name:"sideBar",
|
||||
height: "auto",
|
||||
css: "webix_sidebar",
|
||||
template: function(obj, common){
|
||||
if(common.collapsed)
|
||||
return common.icon(obj, common);
|
||||
return common.arrow(obj, common)+common.icon(obj, common) +"<span>"+obj.value+"</span>";
|
||||
},
|
||||
arrow: function(obj, common){
|
||||
var html = "";
|
||||
var open = "";
|
||||
for (var i=1; i<=obj.$level; i++){
|
||||
if (i==obj.$level && obj.$count){
|
||||
var className = "webix_sidebar_dir_icon webix_icon fa-angle-"+(obj.open?"down":"left");
|
||||
html+="<span class='"+className+"'></span>";
|
||||
}
|
||||
}
|
||||
return html;
|
||||
},
|
||||
icon:function(obj, common){
|
||||
if(obj.icon)
|
||||
return "<span class='webix_icon webix_sidebar_icon fa-"+obj.icon+"'></span>";
|
||||
return "";
|
||||
}
|
||||
});
|
|
@ -0,0 +1,319 @@
|
|||
|
||||
var menu_data = [
|
||||
{id: 'app_home', icon: 'dashboard', value: 'Inicio'},
|
||||
{id: 'app_emisor', icon: 'user-circle', value: 'Emisor'},
|
||||
{id: 'app_folios', icon: 'sort-numeric-asc', value: 'Folios'},
|
||||
]
|
||||
|
||||
|
||||
var sidebar = {
|
||||
view: 'sidebar',
|
||||
data: menu_data,
|
||||
ready: function(){
|
||||
this.select('app_home');
|
||||
this.open(this.getParentId('app_home'));
|
||||
},
|
||||
on:{
|
||||
onAfterSelect: function(id){
|
||||
$$('multi_admin').setValue(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var emisor_datos_fiscales = [
|
||||
{template: 'Datos SAT', type: 'section'},
|
||||
{cols: [{view: 'text', id: 'emisor_rfc', name: 'emisor_rfc', label: 'RFC: ',
|
||||
width: 300, required: true, invalidMessage: 'RFC inválido',
|
||||
readonly: true, attributes: {maxlength: 13}}, {}]},
|
||||
{view: 'text', id: 'emisor_nombre', name: 'emisor_nombre',
|
||||
label: 'Razón Social: ', required: true,
|
||||
invalidMessage: 'La Razón Social es requerida'},
|
||||
{cols: [
|
||||
{view: 'search', id: 'emisor_cp', name: 'emisor_cp', width: 300,
|
||||
label: 'C.P.: ', required: true, attributes: {maxlength: 5},
|
||||
invalidMessage: 'El C.P. es requerido'},
|
||||
{view: 'text', id: 'emisor_cp2', name: 'emisor_cp2', width: 300,
|
||||
label: 'C.P. de Expedición: ', attributes: {maxlength: 5}},
|
||||
{}]},
|
||||
{cols: [
|
||||
{view: 'label', label: 'Regimenes Fiscales *', required: true}, {}]},
|
||||
{cols: [{view: 'list', id: 'lst_emisor_regimen', select: 'multiselect',
|
||||
name: 'lst_emisor_regimen', width: 600, height: 125, required: true,
|
||||
data: []}, {}]},
|
||||
{template: 'Dirección Fiscal', type: 'section'},
|
||||
{view: 'text', id: 'emisor_calle', name: 'emisor_calle', label: 'Calle: '},
|
||||
{cols: [{view: 'text', id: 'emisor_no_exterior', name: 'emisor_no_exterior',
|
||||
width: 300, label: 'No Exterior: '},{}]},
|
||||
{cols: [{view: 'text', id: 'emisor_no_interior', name: 'emisor_no_interior',
|
||||
width: 300, label: 'No Interior: '},{}]},
|
||||
{view: 'text', id: 'emisor_colonia', name: 'emisor_colonia',
|
||||
label: 'Colonia: '},
|
||||
{view: 'text', id: 'emisor_municipio', name: 'emisor_municipio',
|
||||
label: 'Municipio: '},
|
||||
{view: 'text', id: 'emisor_estado', name: 'emisor_estado',
|
||||
label: 'Estado: '},
|
||||
{view: 'text', id: 'emisor_pais', name: 'emisor_pais', label: 'País: ',
|
||||
value: 'México', readonly: true},
|
||||
{template: '', type: 'section', minHeight: 25},
|
||||
]
|
||||
|
||||
|
||||
var emisor_otros_datos= [
|
||||
{template: 'Generales', type: 'section'},
|
||||
{view: 'text', id: 'emisor_nombre_comercial',
|
||||
name: 'emisor_nombre_comercial', label: 'Nombre comercial: '},
|
||||
{view: 'text', id: 'emisor_telefono', name: 'emisor_telefono',
|
||||
label: 'Teléfonos: '},
|
||||
{view: 'text', id: 'emisor_correo', name: 'emisor_correo',
|
||||
label: 'Correos: '},
|
||||
{view: 'text', id: 'emisor_web', name: 'emisor_web',
|
||||
label: 'Página Web: '},
|
||||
{template: 'Escuela', type: 'section'},
|
||||
{cols: [{view: 'checkbox', id: 'chk_escuela', name: 'es_escuela',
|
||||
label: 'Es Escuela'},
|
||||
{view: 'button', id: 'cmd_niveles', label: 'Niveles Escolares',
|
||||
type: 'form', align: 'center', autowidth: true, disabled: true},
|
||||
{}, {}]},
|
||||
{template: 'ONG', type: 'section'},
|
||||
{view: 'checkbox', id: 'chk_ong', name: 'es_ong', label: 'Es ONG'},
|
||||
{cols: [{view: 'text', id: 'ong_autorizacion', name: 'ong_autorizacion',
|
||||
label: 'Autorización: ', disabled: true,
|
||||
placeholder: 'Número de autorización del SAT'}, {}]},
|
||||
{cols: [{view: 'datepicker', id: 'ong_fecha', name: 'ong_fecha',
|
||||
label: 'Fecha de Autorización: ', disabled: true, format: '%d-%M-%Y',
|
||||
placeholder: 'Fecha de autorización en el SAT'}, {}]},
|
||||
{cols: [{view: 'datepicker', id: 'ong_fecha_dof', name: 'ong_fecha_dof',
|
||||
label: 'Fecha de DOF: ', disabled: true, format: '%d-%M-%Y',
|
||||
placeholder: 'Fecha de publicación en el DOF'}, {}]},
|
||||
]
|
||||
|
||||
|
||||
var emisor_certificado = [
|
||||
{template: 'Certificado actual', type: 'section'},
|
||||
{view: 'form', id: 'form_cert', rows: [
|
||||
{cols: [{view: 'text', id: 'cert_rfc', name: 'cert_rfc',
|
||||
label: 'RFC: ', readonly: true, placeholder: 'Ninguno'}, {}]},
|
||||
{cols: [{view: 'text', id: 'cert_serie', name: 'cert_serie',
|
||||
label: 'Serie: ', readonly: true, placeholder: 'Ninguno'}, {}]},
|
||||
{cols: [{view: 'text', id: 'cert_desde', name: 'cert_desde',
|
||||
label: 'Vigente desde: ', readonly: true}, {}]},
|
||||
{cols: [{view: 'text', id: 'cert_hasta', name: 'cert_hasta',
|
||||
label: 'Vigente hasta: ', readonly: true}, {}]},
|
||||
]},
|
||||
{template: 'Cargar Certificado', type: 'section'},
|
||||
{view: 'form', id: 'form_upload', rows: [
|
||||
{cols: [{},
|
||||
{view: 'uploader', id: 'up_cert', autosend: false, link: 'lst_cert',
|
||||
value: 'Seleccionar certificado', upload: '/values/files'}, {}]},
|
||||
{cols: [{},
|
||||
{view: 'list', id: 'lst_cert', name: 'certificado',
|
||||
type: 'uploader', autoheight:true, borderless: true}, {}]},
|
||||
{cols: [{},
|
||||
{view: 'text', id: 'txt_contra', name: 'contra',
|
||||
label: 'Contraseña KEY', labelPosition: 'top',
|
||||
labelAlign: 'center', type: 'password', required: true}, {}]},
|
||||
{cols: [{}, {view: 'button', id: 'cmd_subir_certificado',
|
||||
label: 'Subir certificado'}, {}]},
|
||||
]},
|
||||
]
|
||||
|
||||
|
||||
var controls_emisor = [
|
||||
{
|
||||
view: 'tabview',
|
||||
id: 'tab_emisor',
|
||||
tabbar: {options: [
|
||||
'Datos Fiscales',
|
||||
'Otros Datos',
|
||||
'Certificado']},
|
||||
animate: true,
|
||||
cells: [
|
||||
{id: 'Datos Fiscales', rows: emisor_datos_fiscales},
|
||||
{id: 'Otros Datos', rows: emisor_otros_datos},
|
||||
{id: 'Certificado', rows: emisor_certificado},
|
||||
{},
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
var form_emisor = {
|
||||
type: 'space',
|
||||
cols: [{
|
||||
view: 'form',
|
||||
id: 'form_emisor',
|
||||
complexData: true,
|
||||
elements: controls_emisor,
|
||||
elementsConfig: {
|
||||
labelWidth: 150,
|
||||
labelAlign: 'right'
|
||||
},
|
||||
autoheight: true,
|
||||
rules: {
|
||||
emisor_nombre: function(value){return value.trim() != ''},
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
var options_usarcon = [
|
||||
{id: 'S', value: 'Todos'},
|
||||
{id: 'I', value: 'Ingreso'},
|
||||
{id: 'E', value: 'Egreso'},
|
||||
{id: 'T', value: 'Traslado'},
|
||||
]
|
||||
|
||||
|
||||
var grid_folios_cols = [
|
||||
{id: 'delete', header: '', width: 30, css: 'delete'},
|
||||
{id: 'serie', header: 'Serie', fillspace: 1},
|
||||
{id: 'inicio', header: 'Inicio', fillspace: 1},
|
||||
{id: 'usarcon', header: 'Usar Con', fillspace: 1},
|
||||
{id: 'pre', header: 'Predeterminado', fillspace: 1}
|
||||
]
|
||||
|
||||
|
||||
var grid_folios = {
|
||||
view: 'datatable',
|
||||
id: 'grid_folios',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
headermenu: true,
|
||||
columns: grid_folios_cols
|
||||
}
|
||||
|
||||
|
||||
var emisor_folios = [
|
||||
{template: 'Nueva serie', type: 'section'},
|
||||
{cols: [
|
||||
{view: 'text', id: 'folio_serie', name: 'folio_serie', label: 'Serie: ',
|
||||
required: true, attributes: {maxlength: 15}},
|
||||
{view: 'counter', id: 'folio_inicio', name: 'folio_inicio', value: 1,
|
||||
required: true, label: 'Inicio: ', step: 1, min: 1},
|
||||
{view: 'richselect', id: 'folio_usarcon', name: 'folio_usarcon',
|
||||
label: 'Usar Con: ', value: 'S', required: true,
|
||||
options: options_usarcon},
|
||||
]},
|
||||
{maxHeight: 20},
|
||||
{cols: [{},
|
||||
{view: 'button', id: 'cmd_agregar_serie', label: 'Agregar Serie',
|
||||
autowidth: true, type: 'form'},
|
||||
{}]},
|
||||
{template: 'Series guardadas', type: 'section'},
|
||||
grid_folios
|
||||
]
|
||||
|
||||
|
||||
var controls_folios = [
|
||||
{
|
||||
view: 'tabview',
|
||||
id: 'tab_folios',
|
||||
tabbar: {options: ['Folios']},
|
||||
animate: true,
|
||||
cells: [
|
||||
{id: 'Folios', rows: emisor_folios},
|
||||
{},
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
var form_folios = {
|
||||
type: 'space',
|
||||
cols: [{
|
||||
view: 'form',
|
||||
id: 'form_folios',
|
||||
complexData: true,
|
||||
elements: controls_folios,
|
||||
elementsConfig: {
|
||||
labelWidth: 100,
|
||||
labelAlign: 'right'
|
||||
},
|
||||
autoheight: true,
|
||||
rules: {
|
||||
folio_serie: function(value){return value.trim() != ''},
|
||||
folio_inicio: function(value){return value > 0},
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
var app_emisor = {
|
||||
id: 'app_emisor',
|
||||
rows:[
|
||||
{view: 'template', id: 'th_emisor', type: 'header',
|
||||
template: 'Emisor'},
|
||||
form_emisor,
|
||||
{maxHeight: 20},
|
||||
{margin: 10, cols: [{},
|
||||
{view: 'button', id: 'cmd_save_emisor', label: 'Guardar' ,
|
||||
type: 'form', autowidth: true, align: 'center'},
|
||||
{}]
|
||||
},
|
||||
{},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
var app_folios = {
|
||||
id: 'app_folios',
|
||||
rows:[
|
||||
{view: 'template', id: 'th_folios', type: 'header',
|
||||
template: 'Folios'},
|
||||
form_folios,
|
||||
{},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
var multi_admin = {
|
||||
id: 'multi_admin',
|
||||
animate: true,
|
||||
cells:[
|
||||
{
|
||||
id: 'app_admin_home',
|
||||
view: 'template',
|
||||
template: 'HOME'
|
||||
},
|
||||
app_emisor,
|
||||
app_folios,
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
var menu_user = {
|
||||
view: 'menu',
|
||||
id: 'menu_user',
|
||||
width: 150,
|
||||
autowidth: true,
|
||||
data: [
|
||||
{id: '0', value: 'User...', submenu:[{id:1, value:'Cerrar Sesión'}]},
|
||||
],
|
||||
type: {
|
||||
subsign: true,
|
||||
},
|
||||
};
|
||||
|
||||
var ui_admin = {
|
||||
rows: [
|
||||
{view: 'toolbar', padding: 3, elements: [
|
||||
{view: 'button', type: 'icon', icon: 'bars',
|
||||
width: 37, align: 'left', css: 'app_button', click: function(){
|
||||
$$('$sidebar1').toggle()
|
||||
}
|
||||
},
|
||||
{view: 'label', label: 'Empresa Libre - Configuración'},
|
||||
{},
|
||||
{view: 'button', type: 'icon', width: 40, css: 'app_button',
|
||||
icon: 'home', click: 'cmd_home_click'},
|
||||
menu_user
|
||||
]},
|
||||
{
|
||||
cols:[
|
||||
sidebar,
|
||||
multi_admin,
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
|
@ -0,0 +1,331 @@
|
|||
|
||||
|
||||
var toolbar_invoices = [
|
||||
{view: "button", id: "cmd_new_invoice", label: "Nueva", type: "iconButton",
|
||||
autowidth: true, icon: "plus"},
|
||||
{view: "button", id: "cmd_refacturar", label: "Refacturar", type: "iconButton",
|
||||
autowidth: true, icon: "pencil"},
|
||||
{},
|
||||
{view: "button", id: "cmd_delete_invoice", label: "Eliminar", type: "iconButton",
|
||||
autowidth: true, icon: "minus"},
|
||||
]
|
||||
|
||||
|
||||
var toolbar_invoices_util = [
|
||||
{view: 'button', id: 'cmd_invoice_timbrar', label: 'Timbrar',
|
||||
type: 'iconButton', autowidth: true, icon: 'ticket'},
|
||||
]
|
||||
|
||||
|
||||
function get_icon(tipo){
|
||||
var node = "<img src='/static/img/file-" + tipo + ".png' height='20' width='17' style='margin: 5px 0px'/>"
|
||||
return node
|
||||
}
|
||||
|
||||
|
||||
var grid_invoices_cols = [
|
||||
{id: "id", header:"ID", hidden:true},
|
||||
{id: "serie", header: ["Serie", {content: "selectFilter"}], adjust: "data",
|
||||
sort:"string"},
|
||||
{id: "folio", header: ["Folio", {content: "numberFilter"}], adjust: "data",
|
||||
sort:"int", css: "cell_right"},
|
||||
{id: "uuid", header: ["UUID", {content: "textFilter"}], adjust: "data",
|
||||
sort:"string", hidden:true},
|
||||
{id: "fecha", header: ["Fecha y Hora"], adjust: "data", sort:"string"},
|
||||
{id: "tipo_comprobante", header: ["Tipo", {content: "selectFilter"}],
|
||||
adjust: 'header', sort: 'string'},
|
||||
{id: "estatus", header: ["Estatus", {content: "selectFilter"}],
|
||||
adjust: "data", sort:"string"},
|
||||
{id: 'total_mn', header: ['Total M.N.', {content: 'numberFilter'}], width: 150,
|
||||
sort: 'int', format: webix.i18n.priceFormat, css: 'right'},
|
||||
{id: "cliente", header: ["Razón Social", {content: "selectFilter"}],
|
||||
fillspace:true, sort:"string"},
|
||||
{id: 'xml', header: 'XML', adjust: 'data', template: get_icon('xml')},
|
||||
{id: 'pdf', header: 'PDF', adjust: 'data', template: get_icon('pdf')},
|
||||
{id: 'zip', header: 'ZIP', adjust: 'data', template: get_icon('zip')},
|
||||
{id: 'email', header: '', adjust: 'data', template: get_icon('email')}
|
||||
]
|
||||
|
||||
|
||||
var grid_invoices = {
|
||||
view: 'datatable',
|
||||
id: 'grid_invoices',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
footer: true,
|
||||
resizeColumn: true,
|
||||
headermenu: true,
|
||||
columns: grid_invoices_cols,
|
||||
};
|
||||
|
||||
|
||||
var grid_details_cols = [
|
||||
{id: "id", header:"ID", hidden: true},
|
||||
{id: 'delete', header: '', width: 30, css: 'delete'},
|
||||
{id: "clave", header:{text: 'Clave', css: 'center'}, width: 100},
|
||||
{id: "descripcion", header:{text: 'Descripción', css: 'center'},
|
||||
fillspace: true, editor: 'text'},
|
||||
{id: "unidad", header:{text: 'Unidad', css: 'center'}, width: 100},
|
||||
{id: 'cantidad', header: {text: 'Cantidad', css: 'center'}, width: 100,
|
||||
format: webix.i18n.numberFormat, css:'right', editor: 'text'},
|
||||
{id: "valor_unitario", header:{text: 'Valor Unitario', css: 'center'}, width: 100,
|
||||
format: webix.i18n.priceFormat, css:'right', editor: 'text'},
|
||||
{id: "importe", header:{text: 'Importe', css: 'center'}, width: 150, format: webix.i18n.priceFormat, css:'right'},
|
||||
]
|
||||
|
||||
|
||||
var grid_details = {
|
||||
view: 'datatable',
|
||||
id: 'grid_details',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
autoheight: true,
|
||||
editable: true,
|
||||
columns: grid_details_cols,
|
||||
data: []
|
||||
}
|
||||
|
||||
|
||||
var grid_totals_cols = [
|
||||
{id: 'id', header: 'ID', hidden: true},
|
||||
{id: 'concepto', header: 'Concepto', width: 200,
|
||||
footer: {text: 'TOTAL', css:'right_footer'}, css:'right'},
|
||||
{id: 'importe', header: 'Importe', width: 150,
|
||||
footer: {content: 'summColumn', css:'right_footer'},
|
||||
format: webix.i18n.priceFormat, css:'right'},
|
||||
]
|
||||
|
||||
|
||||
var grid_totals = {
|
||||
view: 'datatable',
|
||||
id: 'grid_totals',
|
||||
select: false,
|
||||
width: 350,
|
||||
header: false,
|
||||
footer: true,
|
||||
autoheight: true,
|
||||
columns: grid_totals_cols,
|
||||
data: [{id: 1, concepto: 'SubTotal', importe: 0}]
|
||||
}
|
||||
|
||||
|
||||
var suggest_partners = {
|
||||
view: 'gridsuggest',
|
||||
id: 'grid_clients_found',
|
||||
name: 'grid_clients_found',
|
||||
body: {
|
||||
autoConfig: false,
|
||||
header: false,
|
||||
columns: [
|
||||
{id: 'id', hidden: true},
|
||||
{id: 'nombre', adjust: 'data'},
|
||||
{id: 'rfc', adjust: 'data'},
|
||||
{id: 'forma_pago', hidden: true},
|
||||
{id: 'uso_cfdi', hidden: true},
|
||||
],
|
||||
dataFeed:function(text){
|
||||
if (text.length > 2){
|
||||
this.load('/values/client?name=' + text)
|
||||
}else{
|
||||
this.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var suggest_products = {
|
||||
view: 'gridsuggest',
|
||||
id: 'grid_products_found',
|
||||
name: 'grid_products_found',
|
||||
body: {
|
||||
autoConfig: false,
|
||||
header: true,
|
||||
columns: [
|
||||
{id: 'id', hidden: true},
|
||||
{id: 'clave', adjust: 'data'},
|
||||
{id: 'descripcion', adjust: 'data'},
|
||||
{id: 'unidad', adjust: 'data'},
|
||||
{id: 'valor_unitario', adjust: 'data',
|
||||
format: webix.i18n.priceFormat}
|
||||
],
|
||||
dataFeed:function(text){
|
||||
if (text.length > 2){
|
||||
this.load('/values/product?name=' + text)
|
||||
}else{
|
||||
this.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var body_comprobante = {rows: [{
|
||||
cols: [
|
||||
{
|
||||
view: 'richselect',
|
||||
id: 'lst_tipo_comprobante',
|
||||
label: 'Tipo',
|
||||
labelPosition: 'top',
|
||||
required: true,
|
||||
value: 'I',
|
||||
options: [
|
||||
{id: 'I', value: 'Ingreso'},
|
||||
{id: 'E', value: 'Egreso'},
|
||||
{id: 'T', value: 'Traslado'}
|
||||
]
|
||||
},
|
||||
{
|
||||
view: 'richselect',
|
||||
id: 'lst_serie',
|
||||
label: 'Serie',
|
||||
labelPosition: 'top',
|
||||
options: [],
|
||||
},
|
||||
]},
|
||||
{view: 'richselect', id: 'lst_uso_cfdi', name: 'uso_cfdi', required: true,
|
||||
labelPosition: 'top', label: 'Uso del CFDI', options: []},
|
||||
]}
|
||||
|
||||
|
||||
var opt_metodo_pago = [
|
||||
{id: 'PUE', value: 'Pago en una sola exhibición'},
|
||||
{id: 'PPD', value: 'Pago en parcialidades o diferido'}
|
||||
]
|
||||
|
||||
|
||||
var body_opciones = {rows: [
|
||||
{view: 'richselect', id: 'lst_forma_pago', name: 'forma_pago',
|
||||
label: 'Forma de Pago', labelPosition: 'top', required: true,
|
||||
options: []},
|
||||
{view: 'richselect', id: 'lst_metodo_pago', label: 'Método de Pago',
|
||||
labelPosition: 'top', options: opt_metodo_pago, readonly: true,
|
||||
value: 'PUE',
|
||||
required: true},
|
||||
{view: 'text', id: 'txt_condicion_pago', label: 'Condiciones de Pago',
|
||||
labelPosition: 'top'},
|
||||
]}
|
||||
|
||||
|
||||
var body_moneda = {cols: [
|
||||
{view: 'richselect', id: 'lst_moneda', label: 'Nombre',
|
||||
labelPosition: 'top', required: true, options: []},
|
||||
{view: 'text', type: 'text', id: 'txt_tipo_cambio', value: '1.00',
|
||||
label: 'Tipo de Cambio', labelPosition: 'top', required: true,
|
||||
invalidMessage: 'Captura un valor númerico', inputAlign: 'right',
|
||||
readonly: true}
|
||||
]}
|
||||
|
||||
|
||||
var body_regimen_fiscal = {
|
||||
view: 'richselect',
|
||||
id: 'lst_regimen_fiscal',
|
||||
required: true,
|
||||
options: []
|
||||
}
|
||||
|
||||
|
||||
var controls_generate = [
|
||||
{cols: [ {rows:[
|
||||
{view: 'fieldset', label: 'Buscar Cliente', body: {rows: [
|
||||
{cols: [
|
||||
{view:"search", id:"search_client_id", name:"search_client_id",
|
||||
label:"por Clave", labelPosition:'top', maxWidth:200,
|
||||
placeholder:'Captura la clave'},
|
||||
{view: 'search', id: 'search_client_name',
|
||||
name: 'search_client_name', label: 'por Nombre o RFC',
|
||||
labelPosition: 'top', suggest: suggest_partners,
|
||||
placeholder: 'Captura al menos tres letras'},
|
||||
]},
|
||||
{cols: [{
|
||||
view: 'label', id: 'lbl_client_title',
|
||||
name: "lbl_client_title", label: 'Seleccionado: ',
|
||||
autowidth:true},
|
||||
{view: 'label', id: 'lbl_client', name: 'lbl_client',
|
||||
label: 'Ninguno'},
|
||||
]}
|
||||
]}},
|
||||
{view: 'fieldset', label: 'Buscar Producto', body: {rows: [
|
||||
{cols: [
|
||||
{view: "search", id: "search_product_id",
|
||||
name: "search_product_id", label: "por Clave",
|
||||
labelPosition:'top', maxWidth:200,
|
||||
placeholder:'Captura la clave'},
|
||||
{view: "search", id: "search_product_name",
|
||||
name: "search_product_name", label: "por Descripción",
|
||||
labelPosition:'top', suggest: suggest_products,
|
||||
placeholder:'Captura al menos tres letras'},
|
||||
]},
|
||||
]}}
|
||||
]},
|
||||
{maxWidth: 10},
|
||||
{maxWidth: 300, rows: [
|
||||
{view: 'fieldset', label: 'Comprobante', body: body_comprobante},
|
||||
{view: 'fieldset', label: 'Opciones de Pago', body: body_opciones},
|
||||
{view: 'fieldset', id: 'fs_moneda', label: 'Moneda', body: body_moneda},
|
||||
{view: 'fieldset', id: 'fs_regimen_fiscal', label: 'Regimen Fiscal',
|
||||
body: body_regimen_fiscal},
|
||||
]}
|
||||
]},
|
||||
{view: 'label', label: 'Detalle', height: 30, align: 'left'},
|
||||
grid_details,
|
||||
{minHeight: 15, maxHeight: 15},
|
||||
{cols: [{}, grid_totals]}
|
||||
]
|
||||
|
||||
|
||||
var controls_invoices = [
|
||||
{
|
||||
view: "tabview",
|
||||
tabbar: {options: ["Generar"]}, animate: true,
|
||||
cells: [
|
||||
{id: "Generar", rows: controls_generate},
|
||||
]
|
||||
},
|
||||
{rows: [
|
||||
{template:"", type: "section" },
|
||||
{margin: 10, cols: [{},
|
||||
{view: "button", id: "cmd_timbrar", label: "Timbrar",
|
||||
type: "form", autowidth: true, align:"center"},
|
||||
{view: 'button', id: 'cmd_close_invoice', label: 'Cancelar',
|
||||
type: 'danger', autowidth: true, align: 'center'},
|
||||
{}]
|
||||
},
|
||||
]}
|
||||
]
|
||||
|
||||
|
||||
var form_invoice = {
|
||||
type: 'space',
|
||||
cols: [{
|
||||
view: 'form',
|
||||
id: 'form_invoice',
|
||||
complexData: true,
|
||||
elements: controls_invoices,
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
var multi_invoices = {
|
||||
id: 'multi_invoices',
|
||||
view: 'multiview',
|
||||
animate: true,
|
||||
cells:[
|
||||
{id: 'invoices_home', rows:[
|
||||
{view: 'toolbar', elements: toolbar_invoices},
|
||||
{view: 'toolbar', elements: toolbar_invoices_util},
|
||||
grid_invoices,
|
||||
]},
|
||||
{id: 'invoices_new', rows:[form_invoice, {}]}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
var app_invoices = {
|
||||
id: "app_invoices",
|
||||
rows:[
|
||||
{view: "template", id: "th_invoices", type: "header", template:"Administración de Facturas" },
|
||||
multi_invoices
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
var msg_rfc = 'El RFC es requerido'
|
||||
var msg_user = 'El usuario es requerido'
|
||||
var msg_pass = 'La contraseña es requerida'
|
||||
|
||||
var form_controls = [
|
||||
{view: 'text', label: 'RFC', id: 'txt_rfc', name: 'rfc',
|
||||
labelPosition: 'top', required: true, invalidMessage: msg_rfc},
|
||||
{view: 'text', label: 'Usuario', id: 'txt_usuario', name: 'usuario',
|
||||
labelPosition: 'top', required: true, invalidMessage: msg_user},
|
||||
{view: 'text', label: 'Contraseña', id: 'txt_contra', name: 'contra',
|
||||
type: 'password', required: true, labelPosition: 'top',
|
||||
invalidMessage: msg_pass},
|
||||
{margin: 10, cols:[{}, {view: 'button', value: 'Iniciar Sesión',
|
||||
click: 'validate_login', hotkey: 'enter'}, {}]}
|
||||
]
|
||||
|
||||
|
||||
var msg_header = 'Bienvenido a Empresa Libre'
|
||||
|
||||
var ui_login = {
|
||||
rows: [
|
||||
{maxHeight: 50},
|
||||
{view: 'template', template: msg_header, maxHeight: 50, css: 'login_header'},
|
||||
{maxHeight: 50},
|
||||
{cols: [{}, {type: 'space', padding: 5,
|
||||
rows: [
|
||||
{view: 'template', template: 'Acceso al sistema', type: 'header'},
|
||||
{
|
||||
container: 'form_login',
|
||||
view: 'form',
|
||||
id: 'form_login',
|
||||
width: 400,
|
||||
elements: form_controls,
|
||||
rules:{
|
||||
rfc:function(value){ return value.trim() != '';},
|
||||
usuario:function(value){ return value.trim() != '';},
|
||||
contra:function(value){ return value.trim() != '';},
|
||||
}
|
||||
},
|
||||
]}, {}, ]
|
||||
},
|
||||
]
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
var menu_data = [
|
||||
{id: 'app_home', icon: 'dashboard', value: 'Inicio'},
|
||||
{id: 'app_partners', icon: 'users', value: 'Clientes y Proveedores'},
|
||||
{id: 'app_products', icon: 'server', value: 'Productos y Servicios'},
|
||||
{id: 'app_invoices', icon: 'cart-plus', value: 'Facturas'},
|
||||
];
|
||||
|
||||
|
||||
var sidebar = {
|
||||
view: 'sidebar',
|
||||
data: menu_data,
|
||||
ready: function(){
|
||||
this.select('app_home');
|
||||
this.open(this.getParentId('app_home'));
|
||||
},
|
||||
on:{
|
||||
onAfterSelect: function(id){
|
||||
$$('multi').setValue(id)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var multi_main = {
|
||||
id: 'multi',
|
||||
animate: true,
|
||||
cells:[
|
||||
{
|
||||
id: 'app_home',
|
||||
view: 'template',
|
||||
template: 'HOME'
|
||||
},
|
||||
app_partners,
|
||||
app_products,
|
||||
app_invoices,
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
var menu_user = {
|
||||
view: 'menu',
|
||||
id: 'menu_user',
|
||||
width: 150,
|
||||
autowidth: true,
|
||||
data: [
|
||||
{id: '0', value: 'User...', submenu:[{id:1, value:'Cerrar Sesión'}]},
|
||||
],
|
||||
type: {
|
||||
subsign: true,
|
||||
},
|
||||
};
|
||||
|
||||
var ui_main = {
|
||||
rows: [
|
||||
{view: 'toolbar', padding: 3, elements: [
|
||||
{view: 'button', type: 'icon', icon: 'bars',
|
||||
width: 37, align: 'left', css: 'app_button', click: function(){
|
||||
$$('$sidebar1').toggle()
|
||||
}
|
||||
},
|
||||
{view: 'label', label: 'Empresa Libre'},
|
||||
{},
|
||||
menu_user,
|
||||
{view: 'button', type: 'icon', width: 45, css: 'app_button', icon: 'bell-o', badge: 1}
|
||||
]
|
||||
},
|
||||
{
|
||||
cols:[
|
||||
sidebar,
|
||||
multi_main,
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
|
@ -0,0 +1,323 @@
|
|||
|
||||
|
||||
var toolbar_partners = [
|
||||
{view: 'button', id: 'cmd_new_partner', label: 'Nuevo', type: 'iconButton',
|
||||
autowidth: true, icon: 'user-plus'},
|
||||
{view: 'button', id: 'cmd_edit_partner', label: 'Editar', type: 'iconButton',
|
||||
autowidth: true, icon: 'user'},
|
||||
{view: 'button', id: 'cmd_delete_partner', label: 'Eliminar', type: 'iconButton',
|
||||
autowidth: true, icon: 'user-times'},
|
||||
]
|
||||
|
||||
|
||||
var grid_partners_cols = [
|
||||
{id: 'index', header:'#', adjust:'data', css: 'right',
|
||||
footer: {content: 'rowCount', colspan: 2, css: 'right'}},
|
||||
{id: 'id', header: 'Clave', adjust:'data', sort: 'int', css: 'right'},
|
||||
{id: 'rfc', header: ['RFC', {content: 'textFilter'}], adjust:'data',
|
||||
sort: 'string', footer: {text: 'Clientes y Proveedores', colspan: 2}},
|
||||
{id: 'nombre', header: ['Razón Social', {content: 'textFilter'}],
|
||||
fillspace:true, sort: 'string'},
|
||||
]
|
||||
|
||||
|
||||
var grid_partners = {
|
||||
view: 'datatable',
|
||||
id: 'grid_partners',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
footer: true,
|
||||
resizeColumn: true,
|
||||
headermenu: true,
|
||||
columns: grid_partners_cols,
|
||||
on:{
|
||||
'data->onStoreUpdated':function(){
|
||||
this.data.each(function(obj, i){
|
||||
obj.index = i+1;
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
var persons_type = [
|
||||
{id: 1, value: 'Física'},
|
||||
{id: 2, value: 'Moral'},
|
||||
{id: 3, value: 'Público'},
|
||||
{id: 4, value: 'Extranjero'},
|
||||
]
|
||||
|
||||
|
||||
var controls_fiscales = [
|
||||
{template: 'Tipo de Persona', type: 'section'},
|
||||
{view: 'radio', id: 'tipo_persona', name: 'tipo_persona', label: 'Tipos: ',
|
||||
labelWidth: 150, value: 1, options: persons_type, required: true,
|
||||
invalidMessage: 'El Tipo de Persona es requerido'},
|
||||
{template: 'Dirección Fiscal', type: 'section'},
|
||||
{cols: [{view: 'text', id: 'rfc', name: 'rfc', label: 'RFC: ', width: 300,
|
||||
required: true, invalidMessage: 'RFC inválido', attributes: {maxlength: 13}},{}]},
|
||||
{view: 'text', id: 'nombre', name: 'nombre', label: 'Razón Social: ', required: true,
|
||||
invalidMessage: 'La Razón Social es requerida'},
|
||||
{view: 'text', id: 'calle', name: 'calle', label: 'Calle: '},
|
||||
{cols: [{view: 'text', id: 'no_exterior', name: 'no_exterior', width: 300,
|
||||
label: 'No Exterior: '},{}]},
|
||||
{cols: [{view: 'text', id: 'no_interior', name: 'no_interior', width: 300,
|
||||
label: 'No Interior: '},{}]},
|
||||
{cols: [{view: 'search', id: 'codigo_postal', name: 'codigo_postal',
|
||||
width: 300, label: 'C.P.: ', attributes: {maxlength: 5}},{}]},
|
||||
{view: 'text', id: 'colonia', name: 'colonia', label: 'Colonia: '},
|
||||
{view: 'text', id: 'municipio', name: 'municipio', label: 'Municipio: '},
|
||||
{view: 'text', id: 'estado', name: 'estado', label: 'Estado: '},
|
||||
{view: 'text', id: 'pais', name: 'pais', label: 'País: ',
|
||||
value: 'México', readonly: true},
|
||||
{template: 'Condiciones Comerciales', type: 'section'},
|
||||
{cols: [
|
||||
{view: 'richselect', id: 'forma_pago', name: 'forma_pago',
|
||||
label: 'Forma de Pago: ', required: true, options: [],
|
||||
invalidMessage: 'La Forma de pago es requerida'},
|
||||
{view: 'text', id: 'condicion_pago', name: 'condicion_pago',
|
||||
label: 'Condiciones de Pago: '},
|
||||
]},
|
||||
{cols: [
|
||||
{view: 'counter', id: 'dias_pago', name: 'dias_pago',
|
||||
label: 'Días de pago', step: 5, value: 0, min: 0, max: 365,
|
||||
tooltip: 'Permite calcular las fechas de pago', width: 250},
|
||||
{view: 'checkbox', id: 'dias_habiles', name: 'dias_habiles',
|
||||
label: 'Hábiles: ', value: false, width: 180},
|
||||
{},
|
||||
]},
|
||||
{cols: [
|
||||
{view: 'richselect', id: 'lst_uso_cfdi_socio', name: 'uso_cfdi_socio',
|
||||
label: 'Uso del CFDI', options: []},
|
||||
{},
|
||||
]}
|
||||
]
|
||||
|
||||
|
||||
var controls_others = [
|
||||
{view: 'checkbox', id: 'es_activo', name: 'es_activo', label: 'Activo: ',
|
||||
value: true, bottomLabel: ' Se recomienda solo desactivar y no eliminar'},
|
||||
{view: 'text', id: 'commercial_name', name: 'nombre_comercial',
|
||||
label: 'Nombre Comercial: '},
|
||||
{view: 'text', id: 'telefonos', name: 'telefonos', label: 'Teléfonos: '},
|
||||
{view: 'text', id: 'web', name: 'web', label: 'Página Web: '},
|
||||
{view: 'text', id: 'correo_facturas', name: 'correo_facturas',
|
||||
label: 'Correos para Facturas: ', tooltip: 'Separados por comas',
|
||||
bottomLabel: 'Uno o más correos electrónicos separados por comas'},
|
||||
{cols: [
|
||||
{view: 'checkbox', id: 'es_cliente', name: 'es_cliente',
|
||||
label: 'Es Cliente: ', value: true, width: 180},
|
||||
{view: 'text', id: 'cuenta_cliente', name: 'cuenta_cliente',
|
||||
label: 'Cuenta Cliente: ', disabled: true}, {}]
|
||||
},
|
||||
{cols: [
|
||||
{view: 'checkbox', id: 'es_proveedor', name: 'es_proveedor',
|
||||
label: 'Es Proveedor: ', value: false, width: 180},
|
||||
{view: 'text', id: 'cuenta_proveedor', name: 'cuenta_proveedor',
|
||||
label: 'Cuenta Proveedor: ', disabled: true}, {}]
|
||||
},
|
||||
{view: 'checkbox', name: 'es_ong', label: 'Es ONG: ', value: false},
|
||||
{view: 'text', name: 'tags', label: 'Etiquetas',
|
||||
tooltip: 'Utiles para filtrados rápidos. Separa por comas.'},
|
||||
{view: 'textarea' , height: 200, name: 'notas', label: 'Notas'},
|
||||
]
|
||||
|
||||
|
||||
|
||||
var toolbar_contacts = [
|
||||
{view: 'button', id: 'cmd_new_contact', label: 'Nuevo', type: 'iconButton',
|
||||
autowidth: true, icon: 'user-plus'},
|
||||
]
|
||||
|
||||
|
||||
var grid_contacts_cols = [
|
||||
{id: 'index', header:'#', adjust:'data', css:'right',
|
||||
footer: {content: 'rowCount'}},
|
||||
{id: 'id', header: '', hidden: true},
|
||||
{id: 'title', header: 'Título', adjust:'data', sort: 'string',
|
||||
footer: 'Contactos'},
|
||||
{id: 'first_name', header: ['Nombre', {content: 'textFilter'}], adjust:'data',
|
||||
sort: 'string'},
|
||||
{id: 'paterno', header: ['Apellido Paterno', {content: 'textFilter'}],
|
||||
fillspace:true, sort: 'string'},
|
||||
{id: 'materno', header: ['Apellido Materno', {content: 'textFilter'}],
|
||||
fillspace:true, sort: 'string'},
|
||||
{id: 'date_born', header: ['Fecha de Nacimiento'],
|
||||
adjust: 'data'},
|
||||
]
|
||||
|
||||
|
||||
var grid_contacts = {
|
||||
view: 'datatable',
|
||||
id: 'grid_contacts',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
height: 400,
|
||||
footer: true,
|
||||
resizeColumn: true,
|
||||
headermenu: true,
|
||||
columns: grid_contacts_cols,
|
||||
on:{
|
||||
'data->onStoreUpdated':function(){
|
||||
this.data.each(function(obj, i){
|
||||
obj.index = i+1;
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
var grid_email = {
|
||||
view: 'datatable',
|
||||
id: 'grid_email',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
height: 200,
|
||||
resizeColumn: true,
|
||||
columns: [
|
||||
{id: 'id', header: '', hidden: true},
|
||||
{id: 'type', header: 'Tipo', adjust:'data', sort: 'string'},
|
||||
{id: 'email', header: ['Correo Electrónico'], fillspace:true, sort: 'string'},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
var grid_phone = {
|
||||
view: 'datatable',
|
||||
id: 'grid_phone',
|
||||
select: 'row',
|
||||
adjust: true,
|
||||
height: 200,
|
||||
resizeColumn: true,
|
||||
columns: [
|
||||
{id: 'id', header: '', hidden: true},
|
||||
{id: 'type', header: 'Tipo', adjust:'data', sort: 'string'},
|
||||
{id: 'phone', header: ['Teléfono'], fillspace:true, sort: 'string'},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
var controls_contact = [
|
||||
{template: 'Datos Generales', type: 'section' },
|
||||
{cols: [
|
||||
{view: 'combo', id: 'cbo_title_contact', name: 'cbo_title_contact',
|
||||
label: 'Título: ', width: 150},
|
||||
{view: 'text', id: 'name_contact', name: 'name_contact',
|
||||
label: 'Nombre: '},
|
||||
{view: 'text', id: 'paterno_contact', name: 'paterno_contact',
|
||||
label: 'A. Paterno: '},
|
||||
{view: 'text', id: 'materno_contact', name: 'materno_contact',
|
||||
label: 'A. Materno: '},
|
||||
{view: 'datepicker', id: 'date_contact', name: 'date_contact',
|
||||
label: 'Fecha de Nacimiento: ', format: '%d-%M-%Y'},
|
||||
]},
|
||||
{template: 'Correos y Teléfonos', type: 'section' },
|
||||
{cols: [
|
||||
grid_email,
|
||||
{maxWidth: 10},
|
||||
grid_phone,
|
||||
]},
|
||||
{},
|
||||
{ template:"", type: "section" },
|
||||
{ margin: 10, cols: [{},
|
||||
{view: "button", id: "cmd_save_conctact", label: "Guardar Contacto" , type: "form", autowidth: true, align:"center"},
|
||||
{view: "button", id: "cmd_cancel_contact", label: "Regresar" , type: "danger", autowidth: true, align:"center"},
|
||||
{}]
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
|
||||
var form_contact = {
|
||||
type: 'space',
|
||||
cols: [{
|
||||
view: 'form',
|
||||
id: 'form_contact',
|
||||
complexData: true,
|
||||
elements: controls_contact,
|
||||
elementsConfig: {
|
||||
labelPosition: 'top',
|
||||
},
|
||||
autoheight: true,
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
var multi_contacts = {
|
||||
id: 'multi_contacts',
|
||||
animate: true,
|
||||
cells:[
|
||||
{id: 'contacts_home', rows:[
|
||||
{view: 'toolbar', elements: toolbar_contacts},
|
||||
grid_contacts,
|
||||
]},
|
||||
{id: 'contacts_new', rows:[form_contact, {}]}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
var controls_partner = [
|
||||
{
|
||||
view: 'tabview',
|
||||
id: 'tab_partner',
|
||||
tabbar: {options: ['Datos Fiscales', 'Otros Datos', 'Contactos']}, animate: true,
|
||||
cells: [
|
||||
{id: 'Datos Fiscales', rows: controls_fiscales},
|
||||
{id: 'Otros Datos', rows: controls_others},
|
||||
{id: 'Contactos', rows: [multi_contacts]},
|
||||
]
|
||||
},
|
||||
{rows: [
|
||||
{ template:"", type: "section" },
|
||||
{ margin: 10, cols: [{},
|
||||
{view: "button", id: "cmd_save_partner", label: "Guardar" , type: "form", autowidth: true, align:"center"},
|
||||
{view: "button", id: "cmd_cancel_partner", label: "Cancelar" , type: "danger", autowidth: true, align:"center"},
|
||||
{}]
|
||||
},
|
||||
]}
|
||||
]
|
||||
|
||||
|
||||
var form_partner = {
|
||||
type: 'space',
|
||||
cols: [{
|
||||
view: 'form',
|
||||
id: 'form_partner',
|
||||
complexData: true,
|
||||
elements: controls_partner,
|
||||
elementsConfig: {
|
||||
labelWidth: 150,
|
||||
labelAlign: 'right'
|
||||
},
|
||||
autoheight: true,
|
||||
rules: {
|
||||
nombre: function(value){ return value.trim() != '';},
|
||||
rfc: validate_rfc,
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
var multi_partners = {
|
||||
id: 'multi_partners',
|
||||
animate: true,
|
||||
cells:[
|
||||
{id: 'partners_home', rows:[
|
||||
{view: 'toolbar', elements: toolbar_partners},
|
||||
grid_partners,
|
||||
]},
|
||||
{id: 'partners_new', rows:[form_partner, {}]}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
var title_partners = 'Administración de Clientes y Proveedores'
|
||||
var app_partners = {
|
||||
id: 'app_partners',
|
||||
rows:[
|
||||
{view: 'template', id: 'th_partner', type: 'header', template: title_partners},
|
||||
multi_partners
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
|
||||
|
||||
var toolbar_products = [
|
||||
{view: "button", id: "cmd_new_product", label: "Nuevo", type: "iconButton",
|
||||
autowidth: true, icon: "plus"},
|
||||
{view: "button", id: "cmd_edit_product", label: "Editar", type: "iconButton",
|
||||
autowidth: true, icon: "pencil"},
|
||||
{view: "button", id: "cmd_delete_product", label: "Eliminar",
|
||||
type: "iconButton", autowidth: true, icon: "minus"},
|
||||
]
|
||||
|
||||
|
||||
var grid_products_cols = [
|
||||
{ id: "id", header: "ID", width: 75},
|
||||
{ id: "clave", header: ["Clave", {content: "textFilter"}], width: 100,
|
||||
sort:"string" },
|
||||
{ id: "descripcion", header: ["Descripción", {content: "textFilter"}],
|
||||
fillspace:true, sort:"string" },
|
||||
{ id: "unidad", header: ["Unidad", {content: "selectFilter"}], width: 150,
|
||||
sort:"string" },
|
||||
{ id: "valor_unitario", header: ["Precio", {content: "numberFilter"}], width: 150,
|
||||
sort:"int", format: webix.i18n.priceFormat, css: "right" },
|
||||
]
|
||||
|
||||
|
||||
var grid_products = {
|
||||
view: "datatable",
|
||||
id: "grid_products",
|
||||
select: "row",
|
||||
adjust: true,
|
||||
footer: true,
|
||||
resizeColumn: true,
|
||||
headermenu: true,
|
||||
columns: grid_products_cols,
|
||||
}
|
||||
|
||||
var suggest_categories = {
|
||||
view: "datasuggest",
|
||||
type: "tree",
|
||||
width: 400,
|
||||
body: { data: [] },
|
||||
}
|
||||
|
||||
|
||||
var grid_product_taxes_cols = [
|
||||
{id:"id", header:"ID", hidden: true},
|
||||
{id:"name", header:'Nombre'},
|
||||
{id:"tipo", header:'Tipo'},
|
||||
{id:"tasa", header:'Tasa'},
|
||||
]
|
||||
|
||||
|
||||
var grid_product_taxes = {
|
||||
view: 'datatable',
|
||||
id: 'grid_product_taxes',
|
||||
select: 'row',
|
||||
multiselect: true,
|
||||
adjust: true,
|
||||
autoheight: true,
|
||||
autowidth: true,
|
||||
headermenu: true,
|
||||
columns: grid_product_taxes_cols,
|
||||
}
|
||||
|
||||
|
||||
var controls_generals = [
|
||||
{view: 'checkbox', id: 'es_activo_producto', name: 'es_activo_producto',
|
||||
label: 'Activo: ', value: true,
|
||||
bottomLabel: 'Se recomienda solo desactivar y no eliminar'},
|
||||
{cols: [
|
||||
{view: 'combo', id: 'categoria', name: 'categoria', label: 'Categoría',
|
||||
labelPosition: 'top', options: suggest_categories},
|
||||
{view: 'text', id: 'clave', name: 'clave', label: 'Clave',
|
||||
labelPosition: 'top', readonly: true, required: true},
|
||||
{view: 'checkbox', id: 'chk_automatica', label: 'Automática',
|
||||
labelPosition: 'top', value: true, maxWidth: 80},
|
||||
{view: 'search', id: 'clave_sat', name: 'clave_sat', label: 'Clave SAT',
|
||||
labelPosition: 'top', required: true, placeholder: 'Buscar clave...'},
|
||||
]},
|
||||
{cols: [
|
||||
{view: 'text', id: 'codigo_barras', name: 'codigo_barras',
|
||||
label: 'Código de Barras', labelPosition: 'top', hidden: true},
|
||||
{view: 'text', id: 'cuenta_predial', name: 'cuenta_predial',
|
||||
label: 'Cuenta Predial', labelPosition: 'top', hidden: true},
|
||||
{id: 'txt_col1'}]},
|
||||
{view: "textarea", id: "descripcion", name: "descripcion", height: 200,
|
||||
label: "Descripción", required: true, labelPosition: "top",
|
||||
invalidMessage: "La Descripción es requerida" },
|
||||
{minHeight: 5},
|
||||
{cols: [
|
||||
{view: "richselect", id: "unidad", name: "unidad", label: "Unidad",
|
||||
width: 300, labelWidth: 130, labelAlign: "right", required: true,
|
||||
invalidMessage: "La Unidad es requerida", options: []},
|
||||
{view: 'text', id: 'tags_producto', name: 'tags_producto',
|
||||
labelAlign: 'right', label: 'Etiquetas',
|
||||
placeholder: 'Separadas por comas'}
|
||||
]},
|
||||
{cols: [{view: "currency", type: "text", id: "valor_unitario",
|
||||
name: "valor_unitario", label: "Valor Unitario", width: 300,
|
||||
labelWidth: 130, labelAlign: "right", required: true,
|
||||
invalidMessage: "Captura un valor númerico", inputAlign: "right" },{}]},
|
||||
{cols: [
|
||||
{view: 'checkbox', id: 'inventario', name: 'inventario', hidden: true,
|
||||
label: 'Inventario', labelAlign: 'right', labelWidth: 130},
|
||||
{view: 'counter', id: 'existencia', name: 'existencia', hidden: true,
|
||||
label: 'Existencia', step: 5, value: 0, min: 0, disabled: true},
|
||||
{view: 'counter', id: 'minimo', name: 'minimo', hidden: true,
|
||||
label: 'Mínimo', step: 5, value: 0, min: 0, disabled: true},
|
||||
{id: 'txt_col2'}]},
|
||||
{cols:[{view:'label', label:'Impuestos', width: 300, align:'center'}, {}]},
|
||||
{cols:[grid_product_taxes, {}]}
|
||||
]
|
||||
|
||||
|
||||
var controls_products = [
|
||||
{
|
||||
view: "tabview",
|
||||
tabbar: { options: ["Datos"]}, animate: true,
|
||||
cells: [
|
||||
{id: "Datos", rows: controls_generals},
|
||||
],
|
||||
},
|
||||
{rows: [
|
||||
{ template:"", type: "section" },
|
||||
{ margin: 10, cols: [{},
|
||||
{view: "button", id: "cmd_save_product", label: "Guardar" , type: "form", autowidth: true, align:"center"},
|
||||
{view: "button", id: "cmd_cancel_product", label: "Cancelar" , type: "danger", autowidth: true, align:"center"},
|
||||
{}]
|
||||
},
|
||||
]}
|
||||
]
|
||||
|
||||
|
||||
var form_product = {
|
||||
type: "space",
|
||||
cols: [{
|
||||
view: "form",
|
||||
id: "form_product",
|
||||
//~ width: 600,
|
||||
complexData: true,
|
||||
elements: controls_products,
|
||||
rules: {
|
||||
descripcion: function(value){ return value.trim() != ""; },
|
||||
valor_unitario: function(value){ return value.trim() != "$"; },
|
||||
}
|
||||
}],
|
||||
}
|
||||
|
||||
|
||||
var multi_products = {
|
||||
id: "multi_products",
|
||||
animate: true,
|
||||
cells:[
|
||||
{id: "products_home", rows:[
|
||||
{view:"toolbar", elements: toolbar_products},
|
||||
grid_products,
|
||||
]},
|
||||
{id: "product_new", rows:[form_product, {}]}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
var app_products = {
|
||||
id: "app_products",
|
||||
rows:[
|
||||
{view: "template", id: "th_products", type: "header", template:"Administración de Productos" },
|
||||
multi_products
|
||||
],
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,30 @@
|
|||
<%inherit file="base.html"/>
|
||||
|
||||
<%block name="media">
|
||||
<link rel="stylesheet" href="/static/css/sidebar_air.css" type="text/css">
|
||||
<link rel="stylesheet" href="/static/css/app.css" type="text/css">
|
||||
<script src="/static/js/sidebar.js" type="text/javascript" ></script>
|
||||
|
||||
<script src="/static/js/controller/util.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/ui/admin.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/controller/admin.js" type="text/javascript" ></script>
|
||||
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
|
||||
<input type=hidden id="username" value="${username}"/>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
webix.ready(function(){
|
||||
webix.CustomScroll.init()
|
||||
webix.ui(ui_admin)
|
||||
controllers.init()
|
||||
var user = document.getElementById("username").value
|
||||
$$('menu_user').getMenu(0).updateItem(0, {value:user})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</%block>
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Empresa Libre</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="/static/img/favicon.png">
|
||||
<link rel="stylesheet" href="/static/css/air.css" type="text/css">
|
||||
<link rel="stylesheet" href="/static/css/app.css" type="text/css">
|
||||
<script src="/static/js/webix_debug.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/es-MX.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/lokijs.min.js" type="text/javascript" ></script>
|
||||
<%block name="media"/>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
webix.debug = true;
|
||||
webix.i18n.setLocale("es-MX");
|
||||
</script>
|
||||
|
||||
<%block name="content"/>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,43 @@
|
|||
<%inherit file="base.html"/>
|
||||
|
||||
<%block name="media">
|
||||
<script src="/static/js/ui/login.js" type="text/javascript" ></script>
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
|
||||
<div id="form_login"></div>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
function validate_login(){
|
||||
var form = this.getFormView();
|
||||
|
||||
if (!form.validate()) {
|
||||
webix.message({ type:"error", text:"Valores inválidos" });
|
||||
return
|
||||
}
|
||||
|
||||
var values = form.getValues()
|
||||
|
||||
webix.ajax().post("/", values, function(text, data, xhr) {
|
||||
var values = data.json();
|
||||
if (values.login) {
|
||||
if (values.super) {
|
||||
window.location = "/admin"
|
||||
}else{
|
||||
window.location = "/main"
|
||||
}
|
||||
} else {
|
||||
webix.message({ type:"error", text: values.msg })
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
webix.ready(function(){
|
||||
webix.ui(ui_login);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</%block>
|
|
@ -0,0 +1,16 @@
|
|||
<%inherit file="base.html"/>
|
||||
|
||||
<%block name="media">
|
||||
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
window.location = "/";
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
</%block>
|
|
@ -0,0 +1,36 @@
|
|||
<%inherit file="base.html"/>
|
||||
|
||||
<%block name="media">
|
||||
<link rel="stylesheet" href="/static/css/sidebar_air.css" type="text/css">
|
||||
<script src="/static/js/sidebar.js" type="text/javascript" ></script>
|
||||
|
||||
<script src="/static/js/controller/util.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/ui/partners.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/ui/products.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/ui/invoices.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/ui/main.js" type="text/javascript" ></script>
|
||||
|
||||
<script src="/static/js/controller/partners.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/controller/products.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/controller/invoices.js" type="text/javascript" ></script>
|
||||
<script src="/static/js/controller/main.js" type="text/javascript" ></script>
|
||||
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
|
||||
<input type=hidden id="username" value="${username}"/>
|
||||
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
|
||||
webix.ready(function(){
|
||||
webix.CustomScroll.init()
|
||||
webix.ui(ui_main)
|
||||
controllers.init()
|
||||
var user = document.getElementById("username").value
|
||||
$$('menu_user').getMenu(0).updateItem(0, {value:user})
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
</%block>
|
|
@ -0,0 +1,345 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:cce11="http://www.sat.gob.mx/ComercioExterior11" xmlns:donat="http://www.sat.gob.mx/donat" xmlns:divisas="http://www.sat.gob.mx/divisas" xmlns:implocal="http://www.sat.gob.mx/implocal" xmlns:leyendasFisc="http://www.sat.gob.mx/leyendasFiscales" xmlns:pfic="http://www.sat.gob.mx/pfic" xmlns:tpe="http://www.sat.gob.mx/TuristaPasajeroExtranjero" xmlns:nomina12="http://www.sat.gob.mx/nomina12" xmlns:registrofiscal="http://www.sat.gob.mx/registrofiscal" xmlns:pagoenespecie="http://www.sat.gob.mx/pagoenespecie" xmlns:aerolineas="http://www.sat.gob.mx/aerolineas" xmlns:valesdedespensa="http://www.sat.gob.mx/valesdedespensa" xmlns:consumodecombustibles="http://www.sat.gob.mx/consumodecombustibles" xmlns:notariospublicos="http://www.sat.gob.mx/notariospublicos" xmlns:vehiculousado="http://www.sat.gob.mx/vehiculousado" xmlns:servicioparcial="http://www.sat.gob.mx/servicioparcialconstruccion" xmlns:decreto="http://www.sat.gob.mx/renovacionysustitucionvehiculos" xmlns:destruccion="http://www.sat.gob.mx/certificadodestruccion" xmlns:obrasarte="http://www.sat.gob.mx/arteantiguedades" xmlns:ine="http://www.sat.gob.mx/ine" xmlns:iedu="http://www.sat.gob.mx/iedu" xmlns:ventavehiculos="http://www.sat.gob.mx/ventavehiculos" xmlns:terceros="http://www.sat.gob.mx/terceros" xmlns:pago10="http://www.sat.gob.mx/Pagos">
|
||||
|
||||
<!-- Con el siguiente método se establece que la salida deberá ser en texto -->
|
||||
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/>
|
||||
|
||||
<xsl:include href="utilerias.xslt"/>
|
||||
<xsl:include href="comercioexterior11.xslt"/>
|
||||
<xsl:include href="leyendasFisc.xslt"/>
|
||||
<xsl:include href="nomina12.xslt"/>
|
||||
|
||||
<!--
|
||||
<xsl:include href="ecc11.xslt"/>
|
||||
<xsl:include href="donat11.xslt"/>
|
||||
<xsl:include href="Divisas.xslt"/>
|
||||
<xsl:include href="implocal.xslt"/>
|
||||
<xsl:include href="pfic.xslt"/>
|
||||
<xsl:include href="TuristaPasajeroExtranjero.xslt"/>
|
||||
<xsl:include href="cfdiregistrofiscal.xslt"/>
|
||||
<xsl:include href="pagoenespecie.xslt"/>
|
||||
<xsl:include href="aerolineas.xslt"/>
|
||||
<xsl:include href="valesdedespensa.xslt"/>
|
||||
<xsl:include href="consumodecombustibles.xslt"/>
|
||||
<xsl:include href="notariospublicos.xslt"/>
|
||||
<xsl:include href="vehiculousado.xslt"/>
|
||||
<xsl:include href="servicioparcialconstruccion.xslt"/>
|
||||
<xsl:include href="renovacionysustitucionvehiculos.xslt"/>
|
||||
<xsl:include href="certificadodedestruccion.xslt"/>
|
||||
<xsl:include href="obrasarteantiguedades.xslt"/>
|
||||
<xsl:include href="ine11.xslt"/>
|
||||
<xsl:include href="iedu.xslt"/>
|
||||
<xsl:include href="ventavehiculos11.xslt"/>
|
||||
<xsl:include href="terceros11.xslt"/>
|
||||
<xsl:include href="Pagos10.xslt"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- Aquí iniciamos el procesamiento de la cadena original con su | inicial y el terminador || -->
|
||||
<xsl:template match="/">|<xsl:apply-templates select="/cfdi:Comprobante"/>||</xsl:template>
|
||||
<!-- Aquí iniciamos el procesamiento de los datos incluidos en el comprobante -->
|
||||
<xsl:template match="cfdi:Comprobante">
|
||||
<!-- Iniciamos el tratamiento de los atributos de comprobante -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Version"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Serie"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Folio"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Fecha"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@FormaPago"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NoCertificado"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@CondicionesDePago"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@SubTotal"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Descuento"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Moneda"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TipoCambio"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Total"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoDeComprobante"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@MetodoPago"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@LugarExpedicion"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Confirmacion"/>
|
||||
</xsl:call-template>
|
||||
<!--
|
||||
Llamadas para procesar al los sub nodos del comprobante
|
||||
-->
|
||||
<xsl:apply-templates select="./cfdi:CfdiRelacionados"/>
|
||||
<xsl:apply-templates select="./cfdi:Emisor"/>
|
||||
<xsl:apply-templates select="./cfdi:Receptor"/>
|
||||
<xsl:apply-templates select="./cfdi:Conceptos"/>
|
||||
<xsl:apply-templates select="./cfdi:Impuestos"/>
|
||||
<xsl:for-each select="./cfdi:Complemento">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo CFDIRelacionados -->
|
||||
<xsl:template match="cfdi:CfdiRelacionados">
|
||||
<!-- Iniciamos el tratamiento de los atributos del CFDIRelacionados -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoRelacion"/>
|
||||
</xsl:call-template>
|
||||
<xsl:for-each select="./cfdi:CfdiRelacionado">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@UUID"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Emisor -->
|
||||
<xsl:template match="cfdi:Emisor">
|
||||
<!-- Iniciamos el tratamiento de los atributos del Emisor -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Rfc"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Nombre"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@RegimenFiscal"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Receptor -->
|
||||
<xsl:template match="cfdi:Receptor">
|
||||
<!-- Iniciamos el tratamiento de los atributos del Receptor -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Rfc"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Nombre"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@ResidenciaFiscal"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumRegIdTrib"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@UsoCFDI"/>
|
||||
</xsl:call-template>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Conceptos -->
|
||||
<xsl:template match="cfdi:Conceptos">
|
||||
<!-- Llamada para procesar los distintos nodos tipo Concepto -->
|
||||
<xsl:for-each select="./cfdi:Concepto">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!--Manejador de nodos tipo Concepto-->
|
||||
<xsl:template match="cfdi:Concepto">
|
||||
<!-- Iniciamos el tratamiento de los atributos del Concepto -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ClaveProdServ"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NoIdentificacion"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Cantidad"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ClaveUnidad"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Unidad"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Descripcion"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ValorUnitario"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Importe"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Descuento"/>
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Manejo de sub nodos de información Traslado de Conceptos:Concepto:Impuestos:Traslados-->
|
||||
<xsl:for-each select="./cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Base"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Impuesto"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoFactor"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TasaOCuota"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Importe"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- Manejo de sub nodos de Retencion por cada una de los Conceptos:Concepto:Impuestos:Retenciones-->
|
||||
<xsl:for-each select="./cfdi:Impuestos/cfdi:Retenciones/cfdi:Retencion">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Base"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Impuesto"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoFactor"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TasaOCuota"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Importe"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- Manejo de los distintos sub nodos de información aduanera de forma indistinta a su grado de dependencia -->
|
||||
<xsl:for-each select="./cfdi:InformacionAduanera">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- Llamada al manejador de nodos de CuentaPredial en caso de existir -->
|
||||
<xsl:if test="./cfdi:CuentaPredial">
|
||||
<xsl:apply-templates select="./cfdi:CuentaPredial"/>
|
||||
</xsl:if>
|
||||
|
||||
<!-- Llamada al manejador de nodos de ComplementoConcepto en caso de existir -->
|
||||
<xsl:if test="./cfdi:ComplementoConcepto">
|
||||
<xsl:apply-templates select="./cfdi:ComplementoConcepto"/>
|
||||
</xsl:if>
|
||||
|
||||
<!-- Llamada al manejador de nodos de Parte en caso de existir -->
|
||||
<xsl:for-each select=".//cfdi:Parte">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Información Aduanera -->
|
||||
<xsl:template match="cfdi:InformacionAduanera">
|
||||
<!-- Manejo de los atributos de la información aduanera -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NumeroPedimento"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Información CuentaPredial -->
|
||||
<xsl:template match="cfdi:CuentaPredial">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Numero"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo ComplementoConcepto -->
|
||||
<xsl:template match="cfdi:ComplementoConcepto">
|
||||
<xsl:for-each select="./*">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Parte -->
|
||||
<xsl:template match="cfdi:Parte">
|
||||
<!-- Iniciamos el tratamiento de los atributos de Parte-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ClaveProdServ"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NoIdentificacion"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Cantidad"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Unidad"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Descripcion"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@ValorUnitario"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Importe"/>
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Manejador de nodos tipo InformacionAduanera-->
|
||||
<xsl:for-each select=".//cfdi:InformacionAduanera">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Complemento -->
|
||||
<xsl:template match="cfdi:Complemento">
|
||||
<xsl:for-each select="./*">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de nodos tipo Domicilio fiscal -->
|
||||
<xsl:template match="cfdi:Impuestos">
|
||||
<!-- Manejo de sub nodos de Retencion por cada una de los Impuestos:Retenciones-->
|
||||
<xsl:for-each select="./cfdi:Retenciones/cfdi:Retencion">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Impuesto"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Importe"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
<!-- Iniciamos el tratamiento de los atributos de TotalImpuestosRetenidos-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalImpuestosRetenidos"/>
|
||||
</xsl:call-template>
|
||||
<!-- Manejo de sub nodos de información Traslado de Impuestos:Traslados-->
|
||||
<xsl:for-each select="./cfdi:Traslados/cfdi:Traslado">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Impuesto"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoFactor"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TasaOCuota"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Importe"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
<!-- Iniciamos el tratamiento de los atributos de TotalImpuestosTrasladados-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalImpuestosTrasladados"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,181 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:cce11="http://www.sat.gob.mx/ComercioExterior11">
|
||||
|
||||
<xsl:template match="cce11:ComercioExterior">
|
||||
<!--Manejador de nodos tipo ComercioExterior-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Version" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@MotivoTraslado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoOperacion" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@ClaveDePedimento" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@CertificadoOrigen" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumCertificadoOrigen" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumeroExportadorConfiable" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Incoterm" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Subdivision" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Observaciones" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TipoCambioUSD" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalUSD" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia -->
|
||||
<xsl:apply-templates select="./cce11:Emisor" />
|
||||
<xsl:for-each select="./cce11:Propietario">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
<xsl:apply-templates select="./cce11:Receptor" />
|
||||
<xsl:for-each select="./cce11:Destinatario">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
<xsl:apply-templates select="./cce11:Mercancias" />
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Emisor">
|
||||
<!-- Iniciamos el tratamiento de los atributos de cce11:Emisor-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Curp" />
|
||||
</xsl:call-template>
|
||||
|
||||
<xsl:apply-templates select="./cce11:Domicilio" />
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Propietario">
|
||||
<!-- Tratamiento de los atributos de cce11:Propietario-->
|
||||
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NumRegIdTrib" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ResidenciaFiscal" />
|
||||
</xsl:call-template>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Receptor">
|
||||
<!-- Tratamiento de los atributos de cce11:Receptor-->
|
||||
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumRegIdTrib" />
|
||||
</xsl:call-template>
|
||||
<xsl:apply-templates select="./cce11:Domicilio" />
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Destinatario">
|
||||
<!-- Tratamiento de los atributos de cce11:Destinatario-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumRegIdTrib" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Nombre" />
|
||||
</xsl:call-template>
|
||||
<!-- Manejo de los nodos dependientes -->
|
||||
<xsl:for-each select="./cce11:Domicilio">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Mercancias">
|
||||
<!-- Iniciamos el manejo de los nodos dependientes -->
|
||||
<xsl:for-each select="./cce11:Mercancia">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Domicilio">
|
||||
<!-- Iniciamos el tratamiento de los atributos de cce11:Domicilio-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Calle" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumeroExterior" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumeroInterior" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Colonia" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Localidad" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Referencia" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Municipio" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Estado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Pais" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@CodigoPostal" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:Mercancia">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NoIdentificacion" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@FraccionArancelaria" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@CantidadAduana" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@UnidadAduana" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@ValorUnitarioAduana" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ValorDolares" />
|
||||
</xsl:call-template>
|
||||
<xsl:for-each select="./cce11:DescripcionesEspecificas">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="cce11:DescripcionesEspecificas">
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Marca" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Modelo" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@SubModelo" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumeroSerie" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:leyendasFisc="http://www.sat.gob.mx/leyendasFiscales">
|
||||
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/>
|
||||
<!-- Manejador de nodos tipo leyendasFiscales -->
|
||||
<xsl:template match="leyendasFisc:LeyendasFiscales">
|
||||
<!--Iniciamos el tratamiento de los atributos del complemento LeyendasFiscales -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@version"/>
|
||||
</xsl:call-template>
|
||||
<!-- Manejo de los atributos de las leyendas Fiscales-->
|
||||
<xsl:for-each select="./leyendasFisc:Leyenda">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
<!-- Manejador de nodos tipo Información de las leyendas -->
|
||||
<xsl:template match="leyendasFisc:Leyenda">
|
||||
<!-- Manejo de los atributos de la leyenda -->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@disposicionFiscal"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@norma"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@textoLeyenda"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,412 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:nomina12="http://www.sat.gob.mx/nomina12">
|
||||
|
||||
<xsl:template match="nomina12:Nomina">
|
||||
<!--Manejador de nodos tipo Nomina-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Version" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoNomina" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@FechaPago" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@FechaInicialPago" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@FechaFinalPago" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NumDiasPagados" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalPercepciones" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalDeducciones" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalOtrosPagos" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia -->
|
||||
<xsl:for-each select="./nomina12:Emisor">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="./nomina12:Receptor">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="./nomina12:Percepciones">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="./nomina12:Deducciones">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="./nomina12:OtrosPagos">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<xsl:for-each select="./nomina12:Incapacidades">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="nomina12:Emisor">
|
||||
<!--Manejador de nodos tipo nomina12:Emisor-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Curp" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@RegistroPatronal" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@RfcPatronOrigen" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:EntidadSNCF-->
|
||||
<xsl:for-each select="./nomina12:EntidadSNCF">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia EntidadSNCF-->
|
||||
<xsl:template match="nomina12:EntidadSNCF">
|
||||
<!-- Iniciamos el manejo de los nodos dependientes -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@OrigenRecurso" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@MontoRecursoPropio" />
|
||||
</xsl:call-template>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="nomina12:Receptor">
|
||||
<!--Manejador de nodos tipo nomina12:Receptor-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Curp" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@NumSeguridadSocial" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@FechaInicioRelLaboral" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Antigüedad" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoContrato" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Sindicalizado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TipoJornada" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoRegimen" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NumEmpleado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Departamento" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Puesto" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@RiesgoPuesto" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@PeriodicidadPago" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@Banco" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@CuentaBancaria" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@SalarioBaseCotApor" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@SalarioDiarioIntegrado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ClaveEntFed" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:SubContratacion-->
|
||||
<xsl:for-each select="./nomina12:SubContratacion">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia SubContratacion-->
|
||||
<xsl:template match="nomina12:SubContratacion">
|
||||
<!-- Iniciamos el manejo de los nodos dependientes -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@RfcLabora" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@PorcentajeTiempo" />
|
||||
</xsl:call-template>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="nomina12:Percepciones">
|
||||
<!--Manejador de nodos tipo nomina12:Percepciones-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalSueldos" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalSeparacionIndemnizacion" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalJubilacionPensionRetiro" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TotalGravado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TotalExento" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:Percepcion-->
|
||||
<xsl:for-each select="./nomina12:Percepcion">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:JubilacionPensionRetiro-->
|
||||
<xsl:for-each select="./nomina12:JubilacionPensionRetiro">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:SeparacionIndemnizacion-->
|
||||
<xsl:for-each select="./nomina12:SeparacionIndemnizacion">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia Percepcion-->
|
||||
<xsl:template match="nomina12:Percepcion">
|
||||
<!--Manejador de nodos tipo nomina12:Percepcion-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoPercepcion" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Clave" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Concepto" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ImporteGravado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ImporteExento" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:AccionesOTitulos-->
|
||||
<xsl:for-each select="./nomina12:AccionesOTitulos">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:HorasExtra-->
|
||||
<xsl:for-each select="./nomina12:HorasExtra">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia AccionesOTitulos-->
|
||||
<xsl:template match="nomina12:AccionesOTitulos">
|
||||
<!-- Iniciamos el manejo de los nodos dependientes -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ValorMercado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@PrecioAlOtorgarse" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia HorasExtra-->
|
||||
<xsl:template match="nomina12:HorasExtra">
|
||||
<!-- Iniciamos el manejo de los nodos dependientes -->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Dias" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoHoras" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@HorasExtra" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@ImportePagado" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia JubilacionPensionRetiro-->
|
||||
<xsl:template match="nomina12:JubilacionPensionRetiro">
|
||||
<!--Manejador de nodos tipo nomina12:JubilacionPensionRetiro-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalUnaExhibicion" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalParcialidad" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@MontoDiario" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@IngresoAcumulable" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@IngresoNoAcumulable" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia SeparacionIndemnizacion-->
|
||||
<xsl:template match="nomina12:SeparacionIndemnizacion">
|
||||
<!--Manejador de nodos tipo nomina12:JubilacionPensionRetiro-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TotalPagado" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@NumAñosServicio" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@UltimoSueldoMensOrd" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@IngresoAcumulable" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@IngresoNoAcumulable" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="nomina12:Deducciones">
|
||||
<!--Manejador de nodos tipo nomina12:Deducciones-->
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalOtrasDeducciones" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@TotalImpuestosRetenidos" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:Deduccion-->
|
||||
<xsl:for-each select="./nomina12:Deduccion">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia Deduccion-->
|
||||
<xsl:template match="nomina12:Deduccion">
|
||||
<!--Manejador de nodos tipo nomina12:Deduccion-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoDeduccion" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Clave" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Concepto" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Importe" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="nomina12:OtrosPagos">
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:OtroPago-->
|
||||
<xsl:for-each select="./nomina12:OtroPago">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia OtroPago-->
|
||||
<xsl:template match="nomina12:OtroPago">
|
||||
<!--Manejador de nodos tipo nomina12:OtroPago-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoOtroPago" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Clave" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Concepto" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Importe" />
|
||||
</xsl:call-template>
|
||||
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:SubsidioAlEmpleo-->
|
||||
<xsl:for-each select="./nomina12:SubsidioAlEmpleo">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:CompensacionSaldosAFavor-->
|
||||
<xsl:for-each select="./nomina12:CompensacionSaldosAFavor">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia SubsidioAlEmpleo-->
|
||||
<xsl:template match="nomina12:SubsidioAlEmpleo">
|
||||
<!--Manejador de nodos tipo nomina12:SubsidioAlEmpleo-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@SubsidioCausado" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia CompensacionSaldosAFavor-->
|
||||
<xsl:template match="nomina12:CompensacionSaldosAFavor">
|
||||
<!--Manejador de nodos tipo nomina12:CompensacionSaldosAFavor-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@SaldoAFavor" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@Año" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@RemanenteSalFav" />
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="nomina12:Incapacidades">
|
||||
<!-- Iniciamos el tratamiento de los atributos de nomina12:Incapacidades-->
|
||||
<xsl:for-each select="./nomina12:Incapacidad">
|
||||
<xsl:apply-templates select="."/>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Iniciamos el manejo de los elementos hijo en la secuencia Incapacidad-->
|
||||
<xsl:template match="nomina12:Incapacidad">
|
||||
<!--Manejador de nodos tipo nomina12:Incapacidad-->
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@DiasIncapacidad" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Requerido">
|
||||
<xsl:with-param name="valor" select="./@TipoIncapacidad" />
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="Opcional">
|
||||
<xsl:with-param name="valor" select="./@ImporteMonetario" />
|
||||
</xsl:call-template>
|
||||
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
|
||||
|
||||
<!-- Manejador de datos requeridos -->
|
||||
<xsl:template name="Requerido">
|
||||
<xsl:param name="valor"/>|<xsl:call-template name="ManejaEspacios">
|
||||
<xsl:with-param name="s" select="$valor"/>
|
||||
</xsl:call-template>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Manejador de datos opcionales -->
|
||||
<xsl:template name="Opcional">
|
||||
<xsl:param name="valor"/>
|
||||
<xsl:if test="$valor">|<xsl:call-template name="ManejaEspacios"><xsl:with-param name="s" select="$valor"/></xsl:call-template></xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Normalizador de espacios en blanco -->
|
||||
<xsl:template name="ManejaEspacios">
|
||||
<xsl:param name="s"/>
|
||||
<xsl:value-of select="normalize-space(string($s))"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
Loading…
Reference in New Issue