Facturar, generar y timbrar

This commit is contained in:
Mauricio Baeza 2017-10-10 18:49:05 -05:00
parent e9ffa41697
commit 55190c5faa
18 changed files with 2110 additions and 65 deletions

2
.gitignore vendored
View File

@ -19,4 +19,6 @@ credenciales.conf
*.sqlite
*.sql
rfc.db
configpac.py

View File

@ -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

View File

@ -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()

View File

@ -15,7 +15,8 @@ import uuid
from dateutil import parser
from settings import DEBUG, log, template_lookup, COMPANIES, DB_SAT
from settings import DEBUG, log, template_lookup, COMPANIES, DB_SAT, \
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL
#~ def _get_hash(password):
@ -30,6 +31,10 @@ 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:
@ -37,6 +42,18 @@ def _save_temp(data, modo='wb'):
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: ')
@ -312,7 +329,7 @@ class Certificado(object):
args = 'openssl pkcs8 -inform DER -in "{}" -passin pass:{} | ' \
'openssl rsa -des3 -passout pass:{}'.format(
self._path_key, password, hashlib.md5(rfc.encode()).hexdigest())
self._path_key, password, _get_md5(rfc))
key_enc = _call(args)
data['key'] = self._key
@ -327,7 +344,7 @@ class Certificado(object):
return {}
data = self._get_info_cer(rfc)
llave = self._get_info_key(password, rfc)
llave = self._get_info_key(password, data['rfc'])
if not llave:
return {}
@ -336,3 +353,49 @@ class Certificado(object):
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

View File

@ -16,6 +16,8 @@ if __name__ == '__main__':
from controllers import util
from settings import log, VERSION, PATH_CP
FORMAT = '{0:.2f}'
database_proxy = Proxy()
class BaseModel(Model):
@ -947,6 +949,7 @@ class Facturas(BaseModel):
obj = Facturas.get(Facturas.id==id)
if obj.uuid:
return False
q = FacturasDetalle.delete().where(FacturasDetalle.factura==obj)
q.execute()
q = FacturasImpuestos.delete().where(FacturasImpuestos.factura==obj)
@ -1108,21 +1111,21 @@ class Facturas(BaseModel):
receptor = {
'Rfc': invoice.cliente.rfc,
'Nombre': invoice.cliente.name,
'Nombre': invoice.cliente.nombre,
'UsoCFDI': invoice.uso_cfdi,
}
conceptos = []
rows = Details.select().where(Details.invoice==invoice)
rows = FacturasDetalle.select().where(FacturasDetalle.factura==invoice)
for row in rows:
concepto = {
'ClaveProdServ': row.product.key_sat,
'NoIdentificacion': row.product.key,
'Cantidad': FORMAT.format(row.cant),
'ClaveUnidad': row.product.unit.key,
'Unidad': row.product.unit.name,
'Descripcion': row.product.description,
'ValorUnitario': FORMAT.format(row.price),
'ClaveProdServ': row.producto.clave_sat,
'NoIdentificacion': row.producto.clave,
'Cantidad': FORMAT.format(row.cantidad),
'ClaveUnidad': row.producto.unidad.key,
'Unidad': row.producto.unidad.name,
'Descripcion': row.producto.descripcion,
'ValorUnitario': FORMAT.format(row.valor_unitario),
'Importe': FORMAT.format(row.importe),
}
@ -1130,25 +1133,21 @@ class Facturas(BaseModel):
traslados = []
retenciones = []
impuestos = (ProductsTaxes
.select()
.where(ProductsTaxes.product==row.product))
for impuesto in impuestos:
if impuesto.tax.tipo == 'E':
for impuesto in row.producto.impuestos:
if impuesto.tipo == 'E':
continue
import_tax = round(impuesto.tax.tasa * row.importe, 2)
import_tax = round(impuesto.tasa * row.importe, 2)
tipo_factor = 'Tasa'
if impuesto.tax.factor != 'T':
if impuesto.factor != 'T':
tipo_factor = 'Cuota'
tax = {
"Base": FORMAT.format(row.importe),
"Impuesto": impuesto.tax.key,
"Impuesto": impuesto.key,
"TipoFactor": tipo_factor,
"TasaOCuota": str(impuesto.tax.tasa),
"TasaOCuota": str(impuesto.tasa),
"Importe": FORMAT.format(import_tax),
}
if impuesto.tax.tipo == 'T':
if impuesto.tipo == 'T':
traslados.append(tax)
else:
retenciones.append(tax)
@ -1168,24 +1167,24 @@ class Facturas(BaseModel):
impuestos['TotalImpuestosRetenidos'] = \
FORMAT.format(invoice.total_retenciones)
taxes = (InvoicesTaxes
taxes = (FacturasImpuestos
.select()
.where(InvoicesTaxes.invoice==invoice))
.where(FacturasImpuestos.factura==invoice))
for tax in taxes:
tipo_factor = 'Tasa'
if tax.tax.factor != 'T':
if tax.impuesto.factor != 'T':
tipo_factor = 'Cuota'
if tax.tax.tipo == 'T':
if tax.impuesto.tipo == 'T':
traslado = {
"Impuesto": tax.tax.key,
"Impuesto": tax.impuesto.key,
"TipoFactor": tipo_factor,
"TasaOCuota": str(tax.tax.tasa),
"TasaOCuota": str(tax.impuesto.tasa),
"Importe": FORMAT.format(tax.importe),
}
traslados.append(traslado)
else:
retencion = {
"Impuesto": tax.tax.key,
"Impuesto": tax.impuesto.key,
"Importe": FORMAT.format(tax.importe),
}
retenciones.append(retencion)
@ -1209,21 +1208,24 @@ class Facturas(BaseModel):
obj.estatus = 'Generada'
obj.save()
#~ error = False
#~ result = util.timbra_xml(obj.xml)
#~ if result['ok']:
#~ obj.xml = result['xml']
#~ obj.uuid = result['uuid']
#~ obj.fecha_timbrado = result['fecha']
#~ obj.estatus = 'Timbrada'
#~ obj.save()
#~ else:
#~ error = True
#~ msg = result['error']
#~ obj.estatus = 'Error'
#~ obj.error = msg
#~ obj.save()
return
error = False
msg = 'Factura timbrada correctamente'
result = util.timbra_xml(obj.xml)
if result['ok']:
obj.xml = result['xml']
obj.uuid = result['uuid']
obj.fecha_timbrado = result['fecha']
obj.estatus = 'Timbrada'
obj.save()
row = {'uuid': obj.uuid, 'estatus': 'Timbrada'}
else:
error = True
msg = result['error']
obj.estatus = 'Error'
obj.error = msg
row = {'estatus': 'Error'}
obj.save()
return {'ok': result['ok'], 'msg': msg, 'row': row}
class FacturasDetalle(BaseModel):

View File

@ -20,6 +20,9 @@ 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')
@ -50,3 +53,9 @@ else:
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.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -111,7 +111,7 @@ function cmd_edit_invoice_click(id, e, node){
function delete_invoice(id){
webix.ajax().del('/invoices', {id: id}, function(text, xml, xhr){
if(xhr.status == 200){
$$('grid_invoices').remove(id)
gi.remove(id)
msg_sucess('Factura eliminada correctamente')
}else{
msg_error('No se pudo eliminar')
@ -120,16 +120,15 @@ function delete_invoice(id){
}
function cmd_delete_invoice_click(id, e, node){
var row = $$('grid_invoices').getSelectedItem()
var row = gi.getSelectedItem()
if (row == undefined){
msg_error('Selecciona una factura')
return
}
if(!row['uuid']==null){
if(row.uuid){
msg_error('Solo se pueden eliminar facturas sin timbrar')
return
}
@ -221,9 +220,9 @@ function validate_invoice(values){
function update_grid_invoices(values){
if(values.new){
$$('grid_invoices').add(values.row)
gi.add(values.row)
}else{
$$("grid_invoices").updateItem(values.row['id'], values.row)
gi.updateItem(values.row['id'], values.row)
}
}
@ -232,6 +231,7 @@ function send_timbrar(id){
var values = data.json()
if(values.ok){
msg_sucess(values.msg)
gi.updateItem(id, values.row)
}else{
webix.alert({
title: 'Error al Timbrar',
@ -256,11 +256,12 @@ function save_invoice(data){
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{
webix.message({type:'error', text:values.msg})
msg_error(values.msg)
}
}
})
@ -602,3 +603,40 @@ function grid_details_header_click(id){
}
})
}
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)
}
}
})
}

View File

@ -1,3 +1,4 @@
var gi = null
var controllers = {
@ -29,9 +30,9 @@ var controllers = {
$$("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_edit_invoice").attachEvent("onItemClick", cmd_edit_invoice_click)
$$("cmd_delete_invoice").attachEvent("onItemClick", cmd_delete_invoice_click)
$$('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)
@ -42,6 +43,7 @@ var controllers = {
$$('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)
}
}
@ -136,6 +138,7 @@ function multi_change(prevID, nextID){
if(active == 'invoices_home'){
get_invoices()
}
gi = $$('grid_invoices')
return
}

View File

@ -3,28 +3,46 @@
var toolbar_invoices = [
{view: "button", id: "cmd_new_invoice", label: "Nueva", type: "iconButton",
autowidth: true, icon: "plus"},
{view: "button", id: "cmd_edit_invoice", label: "Editar", type: "iconButton",
{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 doc_xml(obj){
var node = "<img src='/static/img/file-xml.png' height='20' width='20' style='margin: 5px 0px'/>"
return node
}
function doc_pdf(obj){
var node = "<img src='/static/img/file-pdf.png' height='20' width='20' style='margin: 5px 0px'/>"
return node
}
function get_icon(tipo){
var node = "<img src='/static/img/file-" + tipo + ".png' height='20' width='20' 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: 'xml', header: '', adjust: 'data', template: doc_xml},
{id: "uuid", header: ["UUID", {content: "textFilter"}], adjust: "data",
sort:"string"},
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'},
@ -34,13 +52,17 @@ var grid_invoices_cols = [
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",
view: 'datatable',
id: 'grid_invoices',
select: 'row',
adjust: true,
footer: true,
resizeColumn: true,
@ -296,15 +318,16 @@ var form_invoice = {
var multi_invoices = {
id: "multi_invoices",
id: 'multi_invoices',
view: 'multiview',
animate: true,
cells:[
{id: "invoices_home", rows:[
{view: "toolbar", elements: toolbar_invoices},
{id: 'invoices_home', rows:[
{view: 'toolbar', elements: toolbar_invoices},
{view: 'toolbar', elements: toolbar_invoices_util},
grid_invoices,
]},
{id: "invoices_new", rows:[form_invoice, {}]}
{id: 'invoices_new', rows:[form_invoice, {}]}
]
}

345
source/xslt/cadena.xslt Normal file
View File

@ -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>

View File

@ -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>

View File

@ -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>

412
source/xslt/nomina12.xslt Normal file
View File

@ -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>

View File

@ -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>