Impuestos locales

This commit is contained in:
Mauricio Baeza 2017-11-19 00:42:16 -06:00
parent ff21b3c8bc
commit 9b430b882b
7 changed files with 152 additions and 15 deletions

View File

@ -39,6 +39,12 @@ SAT = {
'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',
},
'locales': {
'version': '1.0',
'prefix': 'implocal',
'xmlns': 'http://www.sat.gob.mx/implocal',
'schema': ' http://www.sat.gob.mx/implocal http://www.sat.gob.mx/sitio_internet/cfd/implocal/implocal.xsd',
},
}
@ -49,6 +55,8 @@ class CFDI(object):
self._xsi = SAT['xsi']
self._pre = self._sat_cfdi['prefix']
self._cfdi = None
self._complemento = None
self._impuestos_locales = False
self.error = ''
def _now(self):
@ -68,6 +76,7 @@ class CFDI(object):
self._nomina(datos['nomina'])
if 'complementos' in datos:
self._complementos(datos['complementos'])
self._locales(datos['impuestos'])
return self._to_pretty_xml(ET.tostring(self._cfdi, encoding='utf-8'))
def add_sello(self, sello):
@ -80,6 +89,10 @@ class CFDI(object):
return xml
def _validate(self, datos):
if datos['impuestos']['total_locales_trasladados'] or \
datos['impuestos']['total_locales_retenciones']:
self._impuestos_locales = True
if 'nomina' in datos:
return self._validate_nomina(datos)
return True
@ -105,7 +118,15 @@ class CFDI(object):
attributes = {}
attributes['xmlns:{}'.format(self._pre)] = self._sat_cfdi['xmlns']
attributes['xmlns:xsi'] = self._xsi
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema']
shema_locales = ''
if self._impuestos_locales:
name = 'xmlns:{}'.format(SAT['locales']['prefix'])
attributes[name] = SAT['locales']['xmlns']
shema_locales = SAT['locales']['schema']
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema'] + \
shema_locales
attributes.update(datos)
if not 'Version' in attributes:
@ -257,8 +278,31 @@ class CFDI(object):
ET.SubElement(deducciones, '{}:Deduccion'.format(pre), row)
return
def _locales(self, datos):
if not self._impuestos_locales:
return
if self._complemento is None:
self._complemento = ET.SubElement(
self._cfdi, '{}:Complemento'.format(self._pre))
attributes = {}
attributes['version'] = SAT['locales']['version']
attributes['TotaldeTraslados'] = datos['total_locales_trasladados']
attributes['TotaldeRetenciones'] = datos['total_locales_retenciones']
node = ET.SubElement(
self._complemento, 'implocal:ImpuestosLocales', attributes)
for retencion in datos['locales_retenciones']:
ET.SubElement(node, 'implocal:RetencionesLocales', retencion)
for traslado in datos['locales_trasladados']:
ET.SubElement(node, 'implocal:TrasladosLocales', traslado)
return
def _complementos(self, datos):
complemento = ET.SubElement(self._cfdi, '{}:Complemento'.format(self._pre))
self._complemento = ET.SubElement(
self._cfdi, '{}:Complemento'.format(self._pre))
if 'ce' in datos:
pre = 'cce11'
datos = datos.pop('ce')

View File

@ -1443,6 +1443,7 @@ class Productos(BaseModel):
.select(
Productos.id,
Productos.clave,
Productos.clave_sat,
Productos.descripcion,
SATUnidades.name.alias('unidad'),
Productos.valor_unitario,
@ -1463,8 +1464,12 @@ class Productos(BaseModel):
if name:
rows = (Productos
.select(
Productos.id, Productos.clave, Productos.descripcion,
SATUnidades.name.alias('unidad'), Productos.valor_unitario)
Productos.id,
Productos.clave,
Productos.clave_sat,
Productos.descripcion,
SATUnidades.name.alias('unidad'),
Productos.valor_unitario)
.join(SATUnidades)
.switch(Productos)
.where(Productos.descripcion.contains(name))
@ -1984,6 +1989,8 @@ class Facturas(BaseModel):
total_trasladados = None
total_retenciones = None
total_iva = 0
locales_traslados = 0
locales_retenciones = 0
for product in products:
id_product = product.pop('id')
@ -2015,10 +2022,8 @@ class Facturas(BaseModel):
for tax in p.impuestos:
if tax.id in totals_tax:
#~ totals_tax[tax.id].importe += product['importe']
totals_tax[tax.id].importe += importe
else:
#~ tax.importe = product['importe']
tax.importe = importe
totals_tax[tax.id] = tax
@ -2027,7 +2032,10 @@ class Facturas(BaseModel):
continue
import_tax = round(float(tax.tasa) * tax.importe, DECIMALES)
total_trasladados = (total_trasladados or 0) + import_tax
if tax.key == '000':
locales_traslados += import_tax
else:
total_trasladados = (total_trasladados or 0) + import_tax
if tax.name == 'IVA':
total_iva += import_tax
@ -2046,7 +2054,10 @@ class Facturas(BaseModel):
import_tax = round(float(tax.tasa) * total_iva, DECIMALES)
else:
import_tax = round(float(tax.tasa) * tax.importe, DECIMALES)
total_retenciones = (total_retenciones or 0) + import_tax
if tax.key == '000':
locales_retenciones += import_tax
else:
total_retenciones = (total_retenciones or 0) + import_tax
invoice_tax = {
'factura': invoice.id,
@ -2056,7 +2067,9 @@ class Facturas(BaseModel):
}
FacturasImpuestos.create(**invoice_tax)
total = subtotal + (total_trasladados or 0) - (total_retenciones or 0)
total = subtotal + \
(total_trasladados or 0) - (total_retenciones or 0) \
+ locales_traslados - locales_retenciones
total_mn = round(total * invoice.tipo_cambio, DECIMALES)
data = {
'subtotal': subtotal + descuento,
@ -2163,6 +2176,7 @@ class Facturas(BaseModel):
}
#~ descuento = 0
#~ tax_locales = False
conceptos = []
rows = FacturasDetalle.select().where(FacturasDetalle.factura==invoice)
for row in rows:
@ -2187,6 +2201,11 @@ class Facturas(BaseModel):
for impuesto in row.producto.impuestos:
if impuesto.tipo == 'E':
continue
if impuesto.key == '000':
#~ tax_locales = True
continue
base = row.importe - row.descuento
import_tax = round(impuesto.tasa * base, DECIMALES)
tipo_factor = 'Tasa'
@ -2211,12 +2230,13 @@ class Facturas(BaseModel):
concepto['impuestos'] = taxes
conceptos.append(concepto)
#~ if descuento:
#~ comprobante['Descuento'] = FORMAT.format(descuento)
impuestos = {}
traslados = []
retenciones = []
total_locales_trasladados = 0
total_locales_retenciones = 0
locales_trasladados = []
locales_retenciones = []
if not invoice.total_trasladados is None:
impuestos['TotalImpuestosTrasladados'] = \
FORMAT.format(invoice.total_trasladados)
@ -2228,6 +2248,25 @@ class Facturas(BaseModel):
.select()
.where(FacturasImpuestos.factura==invoice))
for tax in taxes:
if tax.impuesto.key == '000':
if tax.impuesto.tipo == 'T':
traslado = {
'ImpLocTrasladado': tax.impuesto.name,
'TasadeTraslado': str(round(tax.impuesto.tasa, 2)),
'Importe': FORMAT.format(tax.importe),
}
locales_trasladados.append(traslado)
total_locales_trasladados += tax.importe
else:
retencion = {
'ImpLocRetenido': tax.impuesto.name,
'TasadeRetencion': str(round(tax.impuesto.tasa, 2)),
'Importe': FORMAT.format(tax.importe),
}
locales_retenciones.append(retencion)
total_locales_retenciones += tax.importe
continue
tipo_factor = 'Tasa'
if tax.impuesto.factor != 'T':
tipo_factor = 'Cuota'
@ -2248,6 +2287,12 @@ class Facturas(BaseModel):
impuestos['traslados'] = traslados
impuestos['retenciones'] = retenciones
impuestos['total_locales_trasladados'] = \
FORMAT.format(total_locales_trasladados)
impuestos['total_locales_retenciones'] = \
FORMAT.format(total_locales_retenciones)
impuestos['locales_trasladados'] = locales_trasladados
impuestos['locales_retenciones'] = locales_retenciones
data = {
'comprobante': comprobante,

View File

@ -260,6 +260,13 @@ function validate_invoice(values){
return false
}
var r = grid.data.getRange()
if(r[0].clave_sat != CLAVE_ANTICIPOS){
msg = 'La clave del SAT para anticipos debe ser: ' + CLAVE_ANTICIPOS
msg_error(msg)
return false
}
query = table_relaciones.chain().data()
if(query.length > 0){
msg = 'Los anticipos no deben llevar CFDI relacionados'
@ -419,6 +426,7 @@ function guardar_y_timbrar(values){
for (i = 0; i < rows.length; i++) {
delete rows[i]['delete']
delete rows[i]['clave']
delete rows[i]['clave_sat']
delete rows[i]['unidad']
delete rows[i]['importe']
rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
@ -639,7 +647,7 @@ function set_product(values){
values['importe'] = (precio_final * values['cantidad']).round(DECIMALES)
grid.updateItem(row.id, values)
}
form.setValues({search_product_id:'', search_product_name:''}, true)
form.setValues({search_product_id: '', search_product_name: ''}, true)
for(var v of taxes){
var pt = table_pt.findOne(v)

View File

@ -3,6 +3,7 @@ var RFC_PUBLICO = "XAXX010101000";
var RFC_EXTRANJERO = "XEXX010101000";
var PAIS = "México";
var DECIMALES = 2;
var CLAVE_ANTICIPOS = '84111506';
var db = new loki('data.db');

View File

@ -233,6 +233,7 @@ 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: "clave_sat", hidden: true},
{id: "descripcion", header:{text: 'Descripción', css: 'center'},
fillspace: true, editor: 'text'},
{id: "unidad", header:{text: 'Unidad', css: 'center'}, width: 100},

View File

@ -8,12 +8,11 @@
<xsl:include href="comercioexterior11.xslt"/>
<xsl:include href="leyendasFisc.xslt"/>
<xsl:include href="nomina12.xslt"/>
<xsl:include href="implocal.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"/>

39
source/xslt/implocal.xslt Normal file
View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.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:implocal="http://www.sat.gob.mx/implocal">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/>
<!-- Manejador de nodos tipo implocal -->
<xsl:template match="implocal:ImpuestosLocales">
<!--Iniciamos el tratamiento de los atributos de ImpuestosLocales -->
<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="./@TotaldeRetenciones"/>
</xsl:call-template>
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@TotaldeTraslados"/>
</xsl:call-template>
<xsl:for-each select="implocal:RetencionesLocales">
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@ImpLocRetenido"/>
</xsl:call-template>
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@TasadeRetencion"/>
</xsl:call-template>
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@Importe"/>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="implocal:TrasladosLocales">
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@ImpLocTrasladado"/>
</xsl:call-template>
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@TasadeTraslado"/>
</xsl:call-template>
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@Importe"/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>