Merge branch 'develop'

Agregar depósitos
This commit is contained in:
Mauricio Baeza 2017-11-23 23:58:14 -06:00
commit 096c90c26e
18 changed files with 1503 additions and 69 deletions

View File

@ -39,6 +39,25 @@ 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',
},
'donativo': {
'version': '1.1',
'prefix': 'donat',
'xmlns': 'http://www.sat.gob.mx/donat',
'schema': ' http://www.sat.gob.mx/donat http://www.sat.gob.mx/sitio_internet/cfd/donat/donat11.xsd',
'leyenda': 'Este comprobante ampara un donativo, el cual será destinado por la donataria a los fines propios de su objeto social. En el caso de que los bienes donados hayan sido deducidos previamente para los efectos del impuesto sobre la renta, este donativo no es deducible. La reproducción no autorizada de este comprobante constituye un delito en los términos de las disposiciones fiscales.',
},
'ine': {
'version': '1.1',
'prefix': 'ine',
'xmlns': 'http://www.sat.gob.mx/ine',
'schema': ' http://www.sat.gob.mx/ine http://www.sat.gob.mx/sitio_internet/cfd/ine/ine11.xsd',
},
}
@ -49,6 +68,10 @@ class CFDI(object):
self._xsi = SAT['xsi']
self._pre = self._sat_cfdi['prefix']
self._cfdi = None
self._complemento = None
self._impuestos_locales = False
self._donativo = False
self._ine = False
self.error = ''
def _now(self):
@ -64,10 +87,15 @@ class CFDI(object):
self._receptor(datos['receptor'])
self._conceptos(datos['conceptos'])
self._impuestos(datos['impuestos'])
self._locales(datos['impuestos'])
self._donatarias(datos['donativo'])
self._complementos(datos['complementos'])
if 'nomina' in datos:
self._nomina(datos['nomina'])
if 'complementos' in datos:
self._complementos(datos['complementos'])
#~ 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):
@ -80,6 +108,16 @@ 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 datos['donativo']:
self._donativo = True
if 'ine' in datos['complementos']:
self._ine = True
if 'nomina' in datos:
return self._validate_nomina(datos)
return True
@ -105,7 +143,27 @@ 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']
schema_locales = ''
if self._impuestos_locales:
name = 'xmlns:{}'.format(SAT['locales']['prefix'])
attributes[name] = SAT['locales']['xmlns']
schema_locales = SAT['locales']['schema']
schema_donativo = ''
if self._donativo:
name = 'xmlns:{}'.format(SAT['donativo']['prefix'])
attributes[name] = SAT['donativo']['xmlns']
schema_donativo = SAT['donativo']['schema']
schema_ine = ''
if self._ine:
name = 'xmlns:{}'.format(SAT['ine']['prefix'])
attributes[name] = SAT['ine']['xmlns']
schema_donativo = SAT['ine']['schema']
attributes['xsi:schemaLocation'] = self._sat_cfdi['schema'] + \
schema_locales + schema_donativo +schema_ine
attributes.update(datos)
if not 'Version' in attributes:
@ -257,8 +315,58 @@ 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 _donatarias(self, datos):
if not datos:
return
if self._complemento is None:
self._complemento = ET.SubElement(
self._cfdi, '{}:Complemento'.format(self._pre))
attributes = {}
attributes['version'] = SAT['donativo']['version']
attributes['leyenda'] = SAT['donativo']['leyenda']
attributes.update(datos)
node = ET.SubElement(self._complemento, 'donat:Donatarias', attributes)
return
def _complementos(self, datos):
complemento = ET.SubElement(self._cfdi, '{}:Complemento'.format(self._pre))
if not datos:
return
if self._complemento is None:
self._complemento = ET.SubElement(
self._cfdi, '{}:Complemento'.format(self._pre))
if 'ine' in datos:
atributos = {'Version': SAT['ine']['version']}
atributos.update(datos['ine'])
ET.SubElement(self._complemento, 'ine:INE', atributos)
if 'ce' in datos:
pre = 'cce11'
datos = datos.pop('ce')

View File

@ -18,9 +18,10 @@ class AppLogin(object):
session = req.env['beaker.session']
values = req.params
values['rfc'] = values['rfc'].upper()
result = self._db.authenticate(values)
result, user = self._db.authenticate(values)
if result['login']:
session.save()
session['userobj'] = user
session['user'] = result['user']
session['rfc'] = values['rfc']
req.context['result'] = result
@ -68,7 +69,11 @@ class AppValues(object):
def on_get(self, req, resp, table):
values = req.params
req.context['result'] = self._db.get_values(table, values)
if table == 'admin':
session = req.env['beaker.session']
req.context['result'] = session['userobj'].es_admin
else:
req.context['result'] = self._db.get_values(table, values)
resp.status = falcon.HTTP_200
def on_delete(self, req, resp, table):
@ -140,7 +145,6 @@ class AppPartners(object):
def on_get(self, req, resp):
values = req.params
#~ print ('VALUES', values)
req.context['result'] = self._db.get_partners(values)
resp.status = falcon.HTTP_200
@ -287,9 +291,16 @@ class AppMovimientosBanco(object):
def on_post(self, req, resp):
values = req.params
req.context['result'] = self._db.cuentasbanco(values)
req.context['result'] = self._db.add_movbanco(values)
resp.status = falcon.HTTP_200
def on_delete(self, req, resp):
values = req.params
if self._db.delete('movbanco', values['id']):
resp.status = falcon.HTTP_200
else:
resp.status = falcon.HTTP_204
class AppFolios(object):

View File

@ -36,7 +36,7 @@ from dateutil import parser
from .helper import CaseInsensitiveDict, NumLet, SendMail, TemplateInvoice
from settings import DEBUG, log, template_lookup, COMPANIES, DB_SAT, \
PATH_XSLT, PATH_XSLTPROC, PATH_OPENSSL, PATH_TEMPLATES, PATH_MEDIA, PRE, \
PATH_XMLSEC, TEMPLATE_CANCEL, DEFAULT_SAT_PRODUCTO
PATH_XMLSEC, TEMPLATE_CANCEL, DEFAULT_SAT_PRODUCTO, DECIMALES
#~ def _get_hash(password):
@ -816,7 +816,7 @@ class LIBO(object):
image.GraphicURL = data['path_cbb']
pd.add(image)
s = Size()
s.Width = 4250
s.Width = 4150
s.Height = 4500
image.setSize(s)
image.Anchor = self._set_cell('{timbre.cbb}')
@ -1270,6 +1270,10 @@ def get_bool(value):
return False
def get_float(value):
return round(float(value), DECIMALES)
class ImportFacturaLibre(object):
def __init__(self, path, rfc):

View File

@ -14,6 +14,12 @@ class StorageEngine(object):
def get_values(self, table, values=None):
return getattr(self, '_get_{}'.format(table))(values)
def _get_configtimbrar(self, values):
return main.config_timbrar()
def _get_saldocuenta(self, values):
return main.CuentasBanco.get_saldo(values['id'])
def _get_validartimbrar(self, values):
return main.validar_timbrar()
@ -166,6 +172,8 @@ class StorageEngine(object):
return main.SATImpuestos.remove(id)
if table == 'cuentasbanco':
return main.CuentasBanco.remove(id)
if table == 'movbanco':
return main.MovimientosBanco.remove(id)
return False
def _get_client(self, values):
@ -225,6 +233,9 @@ class StorageEngine(object):
def cuentasbanco(self, values):
return main.CuentasBanco.add(values)
def add_movbanco(self, values):
return main.MovimientosBanco.add(values)
def get_cuentasbanco(self, values):
return main.CuentasBanco.get_(values)

View File

@ -102,6 +102,21 @@ def validar_timbrar():
return {'ok': True, 'msg': msg}
def config_timbrar():
try:
obj = Emisor.select()[0]
except IndexError:
return {'cfdi_donativo': False}
conf = {
'cfdi_anticipo': Configuracion.get_('chk_config_anticipo'),
'cfdi_donativo': obj.es_ong,
'cfdi_ine': Configuracion.get_('chk_config_ine'),
}
return conf
class Configuracion(BaseModel):
clave = TextField(unique=True)
valor = TextField(default='')
@ -136,9 +151,19 @@ class Configuracion(BaseModel):
)
elif keys['fields'] == 'templates':
fields = (
'txt_plantilla_factura_32',
'txt_plantilla_factura_33',
'txt_plantilla_factura_33j')
'txt_plantilla_factura_32',
'txt_plantilla_factura_33',
'txt_plantilla_factura_33j'
)
data = (Configuracion
.select()
.where(Configuracion.clave.in_(fields))
)
elif keys['fields'] == 'configotros':
fields = (
'chk_config_anticipo',
'chk_config_ine',
)
data = (Configuracion
.select()
.where(Configuracion.clave.in_(fields))
@ -151,6 +176,7 @@ class Configuracion(BaseModel):
def add(cls, values):
try:
for k, v in values.items():
#~ print (k, v)
obj, created = Configuracion.get_or_create(clave=k)
obj.valor = v
obj.save()
@ -193,6 +219,28 @@ class Usuarios(BaseModel):
order_by = ('nombre', 'apellidos')
class Registro(BaseModel):
usuario = TextField()
accion = TextField(default='')
tabla = TextField(default='')
fecha = DateTimeField(default=util.now)
def __str__(self):
t = '{} {}-{} ({})'
return t.format(self.usuario, self.accion, self.tabla, self.fecha)
class Meta:
order_by = ('usuario', 'fecha')
@classmethod
def add(cls, values):
try:
Registro.create(**values)
return
except:
return
class SATRegimenes(BaseModel):
key = TextField(index=True, unique=True)
name = TextField(index=True)
@ -928,6 +976,20 @@ class CuentasBanco(BaseModel):
def __str__(self):
return '{} ({})'.format(self.banco.name, self.cuenta[-4:])
@classmethod
def actualizar_saldo(cls, id, saldo):
fields = {'saldo': saldo}
q = CuentasBanco.update(**fields).where(CuentasBanco.id==id)
return bool(q.execute())
@classmethod
def get_saldo(cls, id):
try:
obj = CuentasBanco.get(CuentasBanco.id==id)
return obj.saldo
except CuentasBanco.DoesNotExist:
return 0
@classmethod
def remove(cls, id):
try:
@ -1023,7 +1085,6 @@ class CuentasBanco(BaseModel):
nuevo_mov= {
'cuenta': obj.id,
'fecha': fecha_deposito,
'movimiento': 1,
'descripcion': 'Saldo inicial',
'forma_pago': SATFormaPago.get_by_key('99'),
'deposito': values['saldo'],
@ -1054,7 +1115,6 @@ class CuentasBanco(BaseModel):
class MovimientosBanco(BaseModel):
cuenta = ForeignKeyField(CuentasBanco)
fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
movimiento = IntegerField(default=0)
descripcion = TextField(default='')
forma_pago = ForeignKeyField(SATFormaPago)
retiro = DecimalField(default=0.0, max_digits=20, decimal_places=6,
@ -1063,6 +1123,8 @@ class MovimientosBanco(BaseModel):
auto_round=True)
saldo = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
cancelado = BooleanField(default=False)
conciliado = BooleanField(default=False)
moneda = TextField(default='MXN') # Complemento de pagos
tipo_cambio = DecimalField(default=1.0, max_digits=15, decimal_places=6,
auto_round=True)
@ -1079,12 +1141,62 @@ class MovimientosBanco(BaseModel):
class Meta:
order_by = ('fecha',)
indexes = (
(('cuenta', 'movimiento'), True),
def _ultimo_saldo(self, cuenta, fecha):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.fecha<fecha) &
(MovimientosBanco.cancelado==False))[-1]
)
return round(float(query.saldo), DECIMALES)
def _movimiento_anterior(self, cuenta, fecha):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.fecha<fecha) &
(MovimientosBanco.cancelado==False))[-1]
)
return query
def _actualizar_saldos(self, row):
query = (MovimientosBanco
.select()
.where(
(MovimientosBanco.cuenta==row.cuenta) &
(MovimientosBanco.fecha>row.fecha) &
(MovimientosBanco.cancelado==False))
)
saldo = round(Decimal(row.saldo), DECIMALES)
for mov in query:
mov.saldo = saldo + mov.deposito - mov.retiro
mov.save()
saldo = mov.saldo
CuentasBanco.actualizar_saldo(row.cuenta, saldo)
return saldo
@classmethod
def add(cls, values):
ids = values.pop('ids', '')
actualizar = False
if not 'saldo' in values:
actualizar = True
hora = values.pop('hora')
values['fecha'] = '{}T{}'.format(values['fecha'][:10], hora)
values['cuenta'] = int(values['cuenta'])
values['retiro'] = util.get_float(values['retiro'])
values['deposito'] = util.get_float(values['deposito'])
values['forma_pago'] = int(values['forma_pago'])
ultimo_saldo = cls._ultimo_saldo(
cls, values['cuenta'], values['fecha'])
values['saldo'] = \
ultimo_saldo - values['retiro'] + values['deposito']
with database_proxy.transaction():
try:
obj = MovimientosBanco.create(**values)
@ -1092,7 +1204,31 @@ class MovimientosBanco(BaseModel):
msg = 'Este movimiento ya existe'
return {'ok': False, 'msg': msg}
return {'ok': True}
if actualizar:
saldo = cls._actualizar_saldos(cls, obj)
if ids:
FacturasPagos.add(obj, util.loads(ids))
return {'ok': True, 'saldo': saldo}
@classmethod
def remove(cls, id):
try:
obj = MovimientosBanco.get(MovimientosBanco.id==id)
except MovimientosBanco.DoesNotExist:
return False
if obj.conciliado or obj.cancelado:
return False
with database_proxy.transaction():
obj.cancelado = True
obj.save()
obj = cls._movimiento_anterior(cls, obj.cuenta, obj.fecha)
cls._actualizar_saldos(cls, obj)
return True
@classmethod
def con(cls, id):
@ -1115,7 +1251,10 @@ class MovimientosBanco(BaseModel):
fd = (MovimientosBanco.fecha.between(
util.get_date(rango['start']),
util.get_date(rango['end'], True)))
filtros = (fd & (MovimientosBanco.cuenta==cuenta))
filtros = (fd &
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.cancelado==False)
)
else:
year = int(values['year'])
mes = int(values['mes'])
@ -1127,7 +1266,10 @@ class MovimientosBanco(BaseModel):
fm = (MovimientosBanco.fecha.month > 0)
else:
fm = (MovimientosBanco.fecha.month == mes)
filtros = (fy & fm & (MovimientosBanco.cuenta==cuenta))
filtros = (fy & fm &
(MovimientosBanco.cuenta==cuenta) &
(MovimientosBanco.cancelado==False)
)
rows = tuple(MovimientosBanco
.select(
@ -1147,6 +1289,8 @@ class MovimientosBanco(BaseModel):
class CfdiPagos(BaseModel):
movimiento = ForeignKeyField(MovimientosBanco)
fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
fecha_timbrado = DateTimeField(null=True)
xml = TextField(default='')
uuid = UUIDField(null=True)
estatus = TextField(default='Guardado')
@ -1181,6 +1325,12 @@ class SATUsoCfdi(BaseModel):
return
return SATUsoCfdi.get(SATUsoCfdi.key==key).id
@classmethod
def get_key(self, id):
if id is None:
return
return SATUsoCfdi.get(SATUsoCfdi.id==id).key
@classmethod
def get_activos(cls):
rows = (SATUsoCfdi
@ -1278,12 +1428,12 @@ class Socios(BaseModel):
@classmethod
def get_(cls, values):
print ('values', values)
#~ print ('values', values)
id = values.get('id', 0)
if id:
id = int(values['id'])
row = Socios.select().where(Socios.id==id).dicts()[0]
row['uso_cfdi_socio'] = row.pop('uso_cfdi')
row['uso_cfdi_socio'] = SATUsoCfdi.get_key(row.pop('uso_cfdi'))
if not row['condicion_pago'] is None:
row['condicion_pago'] = \
str(CondicionesPago.get(id=row['condicion_pago']))
@ -1397,7 +1547,16 @@ class Socios(BaseModel):
return bool(q.execute())
class Almacenes(BaseModel):
nombre = TextField(default='')
ubicacion = TextField(default='')
class Meta:
order_by = ('nombre',)
class Productos(BaseModel):
almacen = ForeignKeyField(Almacenes, null=True)
categoria = ForeignKeyField(Categorias, null=True)
clave = TextField(unique=True, index=True)
clave_sat = TextField(default='')
@ -1443,6 +1602,7 @@ class Productos(BaseModel):
.select(
Productos.id,
Productos.clave,
Productos.clave_sat,
Productos.descripcion,
SATUnidades.name.alias('unidad'),
Productos.valor_unitario,
@ -1463,8 +1623,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))
@ -1623,6 +1787,8 @@ class Facturas(BaseModel):
estatus_sat = TextField(default='Vigente')
regimen_fiscal = TextField(default='')
notas = TextField(default='')
saldo = DecimalField(default=0.0, max_digits=20, decimal_places=6,
auto_round=True)
pagada = BooleanField(default=False)
cancelada = BooleanField(default=False)
fecha_cancelacion = DateTimeField(null=True)
@ -1873,7 +2039,42 @@ class Facturas(BaseModel):
return (Facturas.folio.between(folio1, folio2))
def _get_por_pagar(self, ids):
filtros = (
(Facturas.cancelada==False) &
(Facturas.uuid.is_null(False)) &
(Facturas.tipo_comprobante=='I') &
(Facturas.saldo>0)
)
if ids:
filtros &= (Facturas.id.not_in(ids))
rows = tuple(Facturas
.select(
Facturas.id,
Facturas.serie,
Facturas.folio,
Facturas.uuid,
Facturas.fecha,
Facturas.tipo_comprobante,
Facturas.estatus,
Socios.nombre.alias('cliente'),
Facturas.total,
Facturas.saldo,
)
.where(filtros)
.join(Socios)
.switch(Facturas)
.dicts()
)
return {'ok': True, 'rows': rows}
return
def _get_opt(self, values):
if values['opt'] == 'porpagar':
return self._get_por_pagar(self, util.loads(values['ids']))
cfdis = util.loads(values['cfdis'])
if values['year'] == '-1':
@ -1984,6 +2185,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 +2218,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 +2228,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 +2250,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 +2263,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,
@ -2077,26 +2286,42 @@ class Facturas(BaseModel):
FacturasRelacionadas.create(**data)
return
def _guardar_ine(self, invoice, valores):
if not valores:
return
data = {
'factura': invoice,
'nombre': 'ine',
'valores': valores,
}
FacturasComplementos.create(**data)
return
@classmethod
def add(cls, values):
productos = util.loads(values.pop('productos'))
relacionados = util.loads(values.pop('relacionados'))
ine = values.pop('ine', {})
emisor = Emisor.select()[0]
values['folio'] = cls._get_folio(cls, values['serie'])
values['tipo_cambio'] = float(values['tipo_cambio'])
values['lugar_expedicion'] = emisor.cp_expedicion or emisor.codigo_postal
values['anticipo'] = util.get_bool(values['anticipo'])
values['donativo'] = util.get_bool(values['donativo'])
with database_proxy.atomic() as txn:
obj = Facturas.create(**values)
totals = cls._calculate_totals(cls, obj, productos)
cls._guardar_relacionados(cls, obj, relacionados)
cls._guardar_ine(cls, obj, ine)
obj.subtotal = totals['subtotal']
obj.descuento = totals['descuento']
obj.total_trasladados = totals['total_trasladados']
obj.total_retenciones = totals['total_retenciones']
obj.total = totals['total']
obj.saldo = totals['total']
obj.total_mn = totals['total_mn']
obj.save()
@ -2118,8 +2343,16 @@ class Facturas(BaseModel):
def _make_xml(self, invoice):
emisor = Emisor.select()[0]
certificado = Certificado.select()[0]
comprobante = {}
relacionados = {}
donativo = {}
complementos = FacturasComplementos.get_(invoice)
if invoice.donativo:
donativo['noAutorizacion'] = emisor.autorizacion
donativo['fechaAutorizacion'] = str(emisor.fecha_autorizacion)
if invoice.serie:
comprobante['Serie'] = invoice.serie
if invoice.condiciones_pago:
@ -2162,7 +2395,6 @@ class Facturas(BaseModel):
'UsoCFDI': invoice.uso_cfdi,
}
#~ descuento = 0
conceptos = []
rows = FacturasDetalle.select().where(FacturasDetalle.factura==invoice)
for row in rows:
@ -2178,7 +2410,6 @@ class Facturas(BaseModel):
}
if row.descuento:
concepto['Descuento'] = FORMAT.format(row.descuento)
#~ descuento += row.descuento
taxes = {}
traslados = []
@ -2187,6 +2418,10 @@ class Facturas(BaseModel):
for impuesto in row.producto.impuestos:
if impuesto.tipo == 'E':
continue
if impuesto.key == '000':
continue
base = row.importe - row.descuento
import_tax = round(impuesto.tasa * base, DECIMALES)
tipo_factor = 'Tasa'
@ -2211,12 +2446,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 +2464,27 @@ class Facturas(BaseModel):
.select()
.where(FacturasImpuestos.factura==invoice))
for tax in taxes:
if tax.impuesto.key == '000':
tasa = str(round(tax.impuesto.tasa * 100, 2))
simporte = FORMAT.format(tax.importe)
if tax.impuesto.tipo == 'T':
traslado = {
'ImpLocTrasladado': tax.impuesto.name,
'TasadeTraslado': tasa,
'Importe': simporte,
}
locales_trasladados.append(traslado)
total_locales_trasladados += tax.importe
else:
retencion = {
'ImpLocRetenido': tax.impuesto.name,
'TasadeRetencion': tasa,
'Importe': simporte,
}
locales_retenciones.append(retencion)
total_locales_retenciones += tax.importe
continue
tipo_factor = 'Tasa'
if tax.impuesto.factor != 'T':
tipo_factor = 'Cuota'
@ -2248,6 +2505,16 @@ class Facturas(BaseModel):
impuestos['traslados'] = traslados
impuestos['retenciones'] = retenciones
impuestos['total_locales_trasladados'] = ''
if total_locales_trasladados:
impuestos['total_locales_trasladados'] = \
FORMAT.format(total_locales_trasladados)
impuestos['total_locales_retenciones'] = ''
if total_locales_retenciones:
impuestos['total_locales_retenciones'] = \
FORMAT.format(total_locales_retenciones)
impuestos['locales_trasladados'] = locales_trasladados
impuestos['locales_retenciones'] = locales_retenciones
data = {
'comprobante': comprobante,
@ -2256,6 +2523,8 @@ class Facturas(BaseModel):
'receptor': receptor,
'conceptos': conceptos,
'impuestos': impuestos,
'donativo': donativo,
'complementos': complementos,
}
return util.make_xml(data, certificado)
@ -2713,15 +2982,39 @@ class FacturasRelacionadas(BaseModel):
return [str(r.factura_origen.uuid) for r in query]
class CfdiPagosFacturas(BaseModel):
pago = ForeignKeyField(CfdiPagos)
class FacturasComplementos(BaseModel):
factura = ForeignKeyField(Facturas)
nombre = TextField(default='')
valores = TextField(default='')
class Meta:
order_by = ('pago',)
indexes = (
(('pago', 'factura'), True),
order_by = ('factura',)
@classmethod
def get_(cls, factura):
query = (FacturasComplementos
.select()
.where(FacturasComplementos.factura==factura)
)
return {r.nombre: util.loads(r.valores) for r in query}
# ~ class CfdiPagosFacturas(BaseModel):
# ~ pago = ForeignKeyField(CfdiPagos)
# ~ factura = ForeignKeyField(Facturas)
# ~ numero = IntegerField(default=1)
# ~ saldo_anterior = DecimalField(default=0.0, max_digits=20, decimal_places=6,
# ~ auto_round=True)
# ~ importe = DecimalField(default=0.0, max_digits=18, decimal_places=6,
# ~ auto_round=True)
# ~ saldo = DecimalField(default=0.0, max_digits=18, decimal_places=6,
# ~ auto_round=True)
# ~ class Meta:
# ~ order_by = ('pago',)
# ~ indexes = (
# ~ (('pago', 'factura', 'numero'), True),
# ~ )
class PreFacturasRelacionadas(BaseModel):
@ -2867,6 +3160,7 @@ class FacturasImpuestos(BaseModel):
class FacturasPagos(BaseModel):
movimiento = ForeignKeyField(MovimientosBanco)
factura = ForeignKeyField(Facturas)
numero = IntegerField(default=1)
saldo_anterior = DecimalField(default=0.0, max_digits=20, decimal_places=6,
@ -2882,6 +3176,12 @@ class FacturasPagos(BaseModel):
(('factura', 'numero'), True),
)
@classmethod
def add(cls, mov, ids):
print (mov)
print (ids)
return
class PreFacturasImpuestos(BaseModel):
factura = ForeignKeyField(PreFacturas)
@ -2942,8 +3242,8 @@ def authenticate(args):
respuesta['login'] = True
respuesta['user'] = str(obj)
respuesta['super'] = obj.es_superusuario
#~ desconectar()
return respuesta
#~ respuesta['admin'] = obj.es_superusuario or obj.es_admin
return respuesta, obj
def get_cp(cp):
@ -3033,15 +3333,15 @@ def _init_values(rfc):
def _crear_tablas(rfc):
tablas = [Addendas, Categorias, Certificado, CondicionesPago, Configuracion,
Folios,
Folios, Registro,
Emisor, Facturas, FacturasDetalle, FacturasImpuestos, FacturasPagos,
FacturasRelacionadas, Productos,
FacturasRelacionadas, FacturasComplementos, Almacenes, Productos,
PreFacturas, PreFacturasDetalle, PreFacturasImpuestos,
PreFacturasRelacionadas,
SATAduanas, SATFormaPago, SATImpuestos, SATMonedas, SATRegimenes,
SATTipoRelacion, SATUnidades, SATUsoCfdi, SATBancos,
Socios, Tags, Usuarios, CuentasBanco, TipoCambio, MovimientosBanco,
CfdiPagos, CfdiPagosFacturas,
CfdiPagos,
Emisor.regimenes.get_through_model(),
Socios.tags.get_through_model(),
Productos.impuestos.get_through_model(),

View File

@ -39,6 +39,8 @@ var controllers = {
tb_options.attachEvent('onChange', tab_options_change)
$$('txt_plantilla_factura_32').attachEvent('onItemClick', txt_plantilla_factura_32_click)
$$('txt_plantilla_factura_33').attachEvent('onItemClick', txt_plantilla_factura_33_click)
$$('chk_config_anticipo').attachEvent('onItemClick', chk_config_item_click)
$$('chk_config_ine').attachEvent('onItemClick', chk_config_item_click)
}
}
@ -297,6 +299,7 @@ function get_config_values(opt){
},
success: function(text, data, xhr) {
var values = data.json()
//~ showvar(values)
Object.keys(values).forEach(function(key){
$$(key).setValue(values[key])
})
@ -808,6 +811,7 @@ function txt_plantilla_factura_32_click(e){
function tab_options_change(nv, ov){
var cv = {
Plantillas: 'templates',
Otros: 'configotros',
}
get_config_values(cv[nv])
}
@ -1185,3 +1189,23 @@ function cmd_emisor_eliminar_cuenta_click(){
}
})
}
function chk_config_item_click(id, e){
var values = {}
values[id] = $$(id).getValue()
webix.ajax().sync().post('/config', values, {
error: function(text, data, xhr) {
msg = 'Error al guardar la configuración'
msg_error(msg)
},
success: function(text, data, xhr) {
var values = data.json();
if (!values.ok){
msg_error(values.msg)
}
}
})
}

View File

@ -1,10 +1,21 @@
var msg = ''
var msg_importe = ''
var bancos_controllers = {
init: function(){
$$('lst_cuentas_banco').attachEvent('onChange', lst_cuentas_banco_change)
$$('cmd_agregar_retiro').attachEvent('onItemClick', cmd_agregar_retiro_click)
$$('cmd_agregar_deposito').attachEvent('onItemClick', cmd_agregar_deposito_click)
$$('cmd_guardar_retiro').attachEvent('onItemClick', cmd_guardar_retiro_click)
$$('cmd_guardar_deposito').attachEvent('onItemClick', cmd_guardar_deposito_click)
$$('cmd_cancelar_movimiento').attachEvent('onItemClick', cmd_cancelar_movimiento_click)
$$('txt_retiro_importe').attachEvent('onChange', txt_retiro_importe_change)
$$('txt_deposito_importe').attachEvent('onChange', txt_deposito_importe_change)
$$('grid_cfdi_este_deposito').attachEvent('onAfterDrop', grid_cfdi_este_deposito_after_drop)
$$('grid_cfdi_por_pagar').attachEvent('onAfterDrop', grid_cfdi_por_pagar_after_drop)
$$('grid_cfdi_este_deposito').attachEvent('onBeforeEditStop', grid_cfdi_este_deposito_before_edit_stop)
$$('grid_cfdi_este_deposito').attachEvent('onAfterEditStop', grid_cfdi_este_deposito_after_edit_stop)
set_year_month()
}
}
@ -31,7 +42,6 @@ function set_year_month(){
m.unblockEvent()
}
})
}
@ -91,16 +101,504 @@ function get_estado_cuenta(rango){
}
function get_saldo_cuenta(){
var id = $$('lst_cuentas_banco').getValue()
webix.ajax().get('/values/saldocuenta', {id: id}, function(text, data){
var value = data.json()
if(value){
$$('txt_cuenta_saldo').setValue(value)
}else{
msg = 'No se pudo consultar el saldo'
msg_error(msg)
}
})
}
function lst_cuentas_banco_change(nv, ov){
show('Cuenta change')
}
function get_bancos_forma_pago(retiro){
webix.ajax().get('/values/formapago', {}, function(text, data){
var values = data.json()
if(retiro){
$$('lst_retiro_forma_pago').getList().parse(values)
}else{
$$('lst_deposito_forma_pago').getList().parse(values)
}
})
}
function get_facturas_por_pagar(){
var grid1 = $$('grid_cfdi_este_deposito')
var grid2 = $$('grid_cfdi_por_pagar')
var ids = []
grid1.data.each(function(obj){
ids.push(obj.id)
})
webix.ajax().get('/invoices', {'opt': 'porpagar', 'ids': ids}, {
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()
grid2.clearAll()
if (values.ok){
grid2.parse(values.rows, 'json')
}
}
})
}
function cmd_agregar_retiro_click(){
show('Retiro')
get_bancos_forma_pago(true)
$$('multi_bancos').setValue('banco_retiro')
}
function cmd_agregar_deposito_click(){
show('Depósito')
msg_importe = ''
get_bancos_forma_pago(false)
get_facturas_por_pagar()
$$('multi_bancos').setValue('banco_deposito')
}
function validate_retiro(values){
var importe = values.retiro_importe.replace('$', '').replace(',', '').trim()
if(!importe){
msg = 'El importe es requerido'
msg_error(msg)
return false
}
importe = parseFloat(importe).round(2)
if(importe <= 0){
msg = 'El importe debe ser mayor a cero'
msg_error(msg)
return false
}
if(!values.retiro_descripcion.trim()){
msg = 'La descripción es requerida'
msg_error(msg)
return false
}
var today = new Date()
if(values.retiro_fecha > today){
msg = 'Fecha inválida, es una fecha futura'
msg_error(msg)
return
}
var horas = $$('time_retiro').getText().split(':')
var seg = parseInt(horas[2])
var min = parseInt(horas[1])
var horas = parseInt(horas[0])
if(horas > 23){
focus('time_retiro')
msg = 'Hora inválida'
msg_error(msg)
return false
}
if(min > 59){
focus('time_retiro')
msg = 'Hora inválida'
msg_error(msg)
return false
}
if(seg > 59){
focus('time_retiro')
msg = 'Hora inválida'
msg_error(msg)
return false
}
return true
}
function guardar_retiro(values){
var form = $$('form_banco_retiro')
var importe = get_float(values.retiro_importe)
var data = new Object()
data['cuenta'] = $$('lst_cuentas_banco').getValue()
data['fecha'] = values.retiro_fecha
data['hora'] = $$('time_retiro').getText()
data['numero_operacion'] = values.retiro_referencia.trim()
data['forma_pago'] = $$('lst_retiro_forma_pago').getValue()
data['retiro'] = importe
data['deposito'] = 0.0
data['descripcion'] = values.retiro_descripcion
webix.ajax().post('/movbanco', data, {
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){
$$('txt_cuenta_saldo').setValue(values.saldo)
get_estado_cuenta()
$$('multi_bancos').setValue('banco_home')
form.setValues({})
}else{
msg_error(values.msg)
}
}
})
}
function cmd_guardar_retiro_click(){
var form = $$('form_banco_retiro')
if(!form.validate()) {
msg_error('Valores inválidos')
return
}
var values = form.getValues()
if(!validate_retiro(values)){
return
}
msg = 'Todos los datos son correctos.<br><br>¿Deseas agregar este retiro?'
webix.confirm({
title: 'Guardar Retiro',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
guardar_retiro(values)
}
}
})
}
function txt_retiro_importe_change(new_value, old_value){
if(!isFinite(new_value)){
this.config.value = old_value
this.refresh()
}
}
function txt_deposito_importe_change(new_value, old_value){
if(!isFinite(new_value)){
this.config.value = old_value
this.refresh()
}
}
function actualizar_deposito(grid){
grid.sort("#fecha#", "desc", "date")
var suma = 0
var descripcion = ''
grid.data.each(function(obj){
descripcion += 'Pago de la factura: ' + obj.serie + obj.folio + ' del '
descripcion += 'cliente: ' + obj.cliente + '\n'
if(obj.importe == undefined){
obj.importe = obj.saldo
}
suma += obj.importe.to_float()
})
$$('txt_deposito_importe').setValue(suma)
$$('deposito_descripcion').setValue(descripcion.slice(0, -1))
grid.refresh()
}
function grid_cfdi_por_pagar_after_drop(context, native_event){
var grid = $$('grid_cfdi_este_deposito')
actualizar_deposito(grid)
}
function grid_cfdi_este_deposito_after_drop(context, native_event){
var grid = $$('grid_cfdi_este_deposito')
actualizar_deposito(grid)
}
function grid_cfdi_este_deposito_after_edit_stop(state, editor, ignoreUpdate){
var grid = $$('grid_cfdi_este_deposito')
var suma = 0
grid.data.each(function(obj){
suma += obj.importe.to_float()
})
$$('txt_deposito_importe').setValue(suma)
}
function grid_cfdi_este_deposito_before_edit_stop(state, editor){
var grid = $$('grid_cfdi_este_deposito')
var row = grid.getItem(editor.row)
if(editor.column == 'importe'){
var importe = parseFloat(state.value)
if(isNaN(importe)){
msg = 'El importe a pagar debe ser un número'
msg_error(msg)
grid.blockEvent()
state.value = state.old
grid.editCancel()
grid.unblockEvent()
return true
}
if(importe <= 0){
msg = 'El importe a pagar debe ser mayor a cero'
msg_error(msg)
grid.blockEvent()
state.value = state.old
grid.editCancel()
grid.unblockEvent()
return true
}
var saldo = row['saldo'].to_float()
if(importe > saldo){
msg = 'El importe a pagar no puede ser mayor al saldo de la factura'
msg_error(msg)
grid.blockEvent()
state.value = state.old
grid.editCancel()
grid.unblockEvent()
return true
}
}
}
function validate_deposito(values){
var grid = $$('grid_cfdi_este_deposito')
var importe = values.deposito_importe.to_float()
if(!importe){
msg = 'El importe es requerido'
msg_error(msg)
return false
}
if(importe <= 0){
msg = 'El importe debe ser mayor a cero'
msg_error(msg)
return false
}
if(!values.deposito_descripcion.trim()){
msg = 'La descripción es requerida'
msg_error(msg)
return false
}
var today = new Date()
if(values.deposito_fecha > today){
msg = 'Fecha inválida, es una fecha futura'
msg_error(msg)
return
}
var horas = $$('time_deposito').getText().split(':')
var seg = parseInt(horas[2])
var min = parseInt(horas[1])
var horas = parseInt(horas[0])
if(horas > 23){
focus('time_deposito')
msg = 'Hora inválida'
msg_error(msg)
return false
}
if(min > 59){
focus('time_deposito')
msg = 'Hora inválida'
msg_error(msg)
return false
}
if(seg > 59){
focus('time_deposito')
msg = 'Hora inválida'
msg_error(msg)
return false
}
if(grid.count()){
var suma = 0
grid.data.each(function(obj){
var tmp = obj.importe.to_float()
if(tmp <= 0){
msg = 'El importe de la factura: ' + obj.serie + obj.folio + ' no puede ser menor a cero'
msg_error(msg)
return false
}
suma += tmp
})
if(suma > importe){
msg = 'La suma del pago de facturas, no puede ser mayor al deposito'
msg_error(msg)
return false
}
if(suma < importe){
msg_importe = 'El importe del depósito en mayor a la suma de facturas. '
msg_importe += 'Asegurate de que esto sea correcto'
}
}
return true
}
function guardar_deposito(values){
var form = $$('form_banco_deposito')
var grid = $$('grid_cfdi_este_deposito')
var data = new Object()
data['cuenta'] = $$('lst_cuentas_banco').getValue()
data['fecha'] = values.deposito_fecha
data['hora'] = $$('time_deposito').getText()
data['numero_operacion'] = values.deposito_referencia.trim()
data['forma_pago'] = $$('lst_deposito_forma_pago').getValue()
data['deposito'] = values.deposito_importe.to_float()
data['retiro'] = 0.0
data['descripcion'] = values.deposito_descripcion
if(grid.count()){
var ids = new Object()
grid.data.each(function(obj){
ids[obj.id] = obj.importe.to_float()
})
data['ids'] = ids
}
webix.ajax().post('/movbanco', data, {
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){
$$('txt_cuenta_saldo').setValue(values.saldo)
get_estado_cuenta()
$$('multi_bancos').setValue('banco_home')
form.setValues({})
grid.clearAll()
}else{
msg_error(values.msg)
}
}
})
}
function cmd_guardar_deposito_click(){
var form = $$('form_banco_deposito')
var grid = $$('grid_cfdi_este_deposito')
if(!form.validate()) {
msg_error('Valores inválidos')
return
}
var values = form.getValues()
if(!validate_deposito(values)){
return
}
if(!grid.count()){
msg = 'Todos los datos son correctos<br>br>'
msg = 'El depósito no tiene facturas relacionadas<br><br>¿Estás '
msg += ' seguro de guardar del depósito sin facturas relacionadas?'
webix.confirm({
title: 'Guardar depósito',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
guardar_deposito(values)
}
}
})
}else{
if(!msg_importe){
msg_importe = 'Se van a relacionar ' + grid.count() + ' facturas.'
}
msg = 'Todos los datos son correctos.<br><br>' + msg_importe + '<br><br>'
msg += '¿Deseas agregar este depósito?'
webix.confirm({
title: 'Guardar depósito',
ok: 'Si',
cancel: 'No',
type: 'confirm-error',
text: msg,
callback:function(result){
if(result){
guardar_deposito(values)
}
}
})
}
}
function cancelar_movimiento(id){
var grid = $$('grid_cuentabanco')
webix.ajax().del('/movbanco', {id: id}, function(text, xml, xhr){
if(xhr.status == 200){
get_estado_cuenta()
get_saldo_cuenta()
msg_sucess('Movimiento cancelado correctamente')
}else{
msg_error('No se pudo eliminar')
}
})
}
function cmd_cancelar_movimiento_click(){
var grid = $$('grid_cuentabanco')
var row = grid.getSelectedItem()
if(row == undefined){
msg_error('Selecciona un movimiento')
return
}
if(row.descripcion == 'Saldo inicial'){
msg_error('No es posible eliminar el saldo inicial')
return
}
var msg = '¿Estás seguro de cancelar el movimiento seleccionado?'
msg += '<BR><BR>ESTA ACCIÓN NO SE PUEDE DESHACER<BR><BR>'
webix.confirm({
title:'Cancelar Movimiento',
ok:'Si',
cancel:'No',
type:'confirm-error',
text:msg,
callback:function(result){
if (result){
cancelar_movimiento(row['id'])
}
}
})
}

View File

@ -56,7 +56,6 @@ function get_monedas(){
$$('lst_moneda').setValue(pre.id)
if(values.length == 1){
$$('fs_moneda').hide()
//~ $$('fs_moneda').refresh()
}
})
}
@ -77,7 +76,6 @@ function get_regimen_fiscal(){
$$('lst_regimen_fiscal').setValue(pre.id)
if(values.length == 1){
$$('fs_regimen_fiscal').hide()
//~ $$('fs_regimen_fiscal').refresh()
}
})
}
@ -109,6 +107,17 @@ function default_config(){
$$('cmd_timbrar').enable()
}
})
webix.ajax().sync().get('/values/configtimbrar', function(text, data){
var values = data.json()
show('chk_cfdi_anticipo', values.cfdi_anticipo)
show('chk_cfdi_donativo', values.cfdi_donativo)
if(!values.cfdi_ine || values.cfdi_ine == '0'){
$$('tv_invoice').getTabbar().hideOption('INE')
}else{
$$('tv_invoice').getTabbar().showOption('INE')
}
})
}
@ -260,6 +269,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'
@ -268,6 +284,45 @@ function validate_invoice(values){
}
}
donativo = $$('chk_cfdi_donativo').getValue()
if(donativo){
query = table_totals.chain().data()
for(var t of query){
tax = table_taxes.findOne({'id': t.tax})
if(tax.tipo != 'E'){
msg = 'Los donativos deben de ser exentos'
msg_error(msg)
return false
}
}
}
usar_ine = $$('chk_cfdi_usar_ine').getValue()
if(usar_ine){
var id_contabilidad = $$('txt_ine_idcontabilidad').getValue().trim()
if(!id_contabilidad){
$$('tv_invoice').getTabbar().setValue('INE')
msg = 'El ID de contabilidad es requerido si se usa el complemento INE'
msg_error(msg)
return false
}
if(!id_contabilidad.is_number()){
$$('tv_invoice').getTabbar().setValue('INE')
msg = 'El ID de contabilidad deben ser solo digitos'
msg_error(msg)
return False
}
if(id_contabilidad.length != 6){
$$('tv_invoice').getTabbar().setValue('INE')
msg = 'El ID de contabilidad deben ser 6 digitos'
msg_error(msg)
return False
}
}
return true
}
@ -354,6 +409,7 @@ function save_invoice(data){
if(values.ok){
msg_sucess('Factura guardada correctamente. Enviando a timbrar')
update_grid_invoices(values)
gi.select(values.row['id'], false)
send_timbrar(values.row['id'])
result = true
}else{
@ -419,6 +475,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'])
@ -441,6 +498,17 @@ function guardar_y_timbrar(values){
data['relacionados'] = ids
data['tipo_relacion'] = tipo_relacion
data['anticipo'] = anticipo
data['donativo'] = $$('chk_cfdi_donativo').getValue()
var usar_ine = $$('chk_cfdi_usar_ine').getValue()
if(usar_ine){
var valores = {
TipoProceso: $$('lst_ine_tipo_proceso').getValue(),
TipoComite: $$('lst_ine_tipo_comite').getValue(),
IdContabilidad: $$('txt_ine_idcontabilidad').getValue(),
}
data['ine'] = valores
}
if(!save_invoice(data)){
return
@ -450,6 +518,7 @@ function guardar_y_timbrar(values){
tipo_relacion = ''
anticipo = false
$$('chk_cfdi_anticipo').setValue(0)
$$('chk_cfdi_usar_ine').getValue(0)
$$('form_invoice').setValues({id_partner: 0, lbl_partner: 'Ninguno'})
$$('multi_invoices').setValue('invoices_home')
@ -639,7 +708,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)
@ -800,7 +869,7 @@ function grid_details_header_click(id){
function cmd_refacturar_click(){
show('Refacturar')
showvar('Refacturar')
}
@ -1006,7 +1075,7 @@ function cmd_invoice_sat_click(){
webix.ajax().get('/values/statussat', {id: row.id}, function(text, data){
var values = data.json()
show(values)
showvar(values)
})
}

View File

@ -1,10 +1,25 @@
var gi = null
function configuracion_inicial(){
webix.ajax().get('/values/admin', function(text, data){
var values = data.json()
$$('cmd_ir_al_admin').show(values)
})
}
function cmd_ir_al_admin_click(){
window.location = '/admin'
}
var controllers = {
init: function(){
//~ Main
$$('menu_user').attachEvent('onMenuItemClick', menu_user_click);
configuracion_inicial()
//~ Partner
$$('cmd_new_partner').attachEvent('onItemClick', cmd_new_partner_click);
$$('cmd_new_contact').attachEvent('onItemClick', cmd_new_contact_click);
@ -170,7 +185,7 @@ function multi_change(prevID, nextID){
if(nextID == 'app_bancos'){
active = $$('multi_bancos').getActiveId()
if(active == 'bancos_home'){
if(active == 'banco_home'){
get_cuentas_banco()
}
return

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');
@ -32,11 +33,28 @@ var months = [
]
function show(values){
function focus(name){
webix.UIManager.setFocus(name)
}
function showvar(values){
webix.message(JSON.stringify(values, null, 2))
}
function show(nombre, value){
if(value == '0'){
value = false
}
if(value){
$$(nombre).show()
}else{
$$(nombre).hide()
}
}
function msg_error(msg){
webix.message({type: 'error', text: msg})
}
@ -57,6 +75,16 @@ String.prototype.is_number = function(){
}
String.prototype.to_float = function(){
return get_float(this)
}
function get_float(value){
return parseFloat(value.replace('$', '').replace(',', '').trim()).round(2)
}
webix.protoUI({
$cssName: "text",
name: "currency",

View File

@ -430,6 +430,20 @@ var options_templates = [
{}]
var options_admin_otros = [
{maxHeight: 15},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_anticipo', labelWidth: 0,
labelRight: 'Ayuda para generar anticipos'},
{}]},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_config_ine', labelWidth: 0,
labelRight: 'Mostrar el complemento INE al facturar'},
{}]},
{maxHeight: 20},
{}]
var tab_options = {
view: 'tabview',
id: 'tab_options',
@ -440,7 +454,7 @@ var tab_options = {
animate: true,
cells: [
{id: 'Plantillas', rows: options_templates},
{id: 'Otros', rows: [{}]},
{id: 'Otros', rows: options_admin_otros},
{},
],
}

View File

@ -17,10 +17,17 @@ var toolbar_filtro_cuenta = [
{view: 'daterangepicker', id: 'filtro_cuenta_fechas', label: 'Fechas',
labelAlign: 'right', width: 300},
{},
]
var toolbar_movimientos_banco = [
{view: 'button', id: 'cmd_agregar_retiro', label: 'Retiro',
type: 'iconButton', autowidth: true, icon: 'minus'},
{view: 'button', id: 'cmd_agregar_deposito', label: 'Depósito',
type: 'iconButton', autowidth: true, icon: 'plus'},
{},
{view: 'button', id: 'cmd_cancelar_movimiento', label: 'Cancelar',
type: 'iconButton', autowidth: true, icon: 'ban'},
]
@ -51,16 +58,210 @@ var grid_cuentabanco = {
}
var grid_cfdi_por_pagar_cols = [
{id: 'index', header: '#', adjust: 'data', css: 'right'},
{id: 'id', header: 'ID', hidden: true},
{id: 'serie', header: 'Serie', adjust: 'data'},
{id: 'folio', header: 'Folio', adjust: 'data', css: 'right'},
{id: 'uuid', header: 'UUID', width: 250, hidden: true},
{id: 'fecha', header: 'Fecha y Hora', width: 150, sort: 'date'},
{id: 'tipo_comprobante', header: 'Tipo', adjust: 'data'},
{id: 'estatus', header: 'Estatus', adjust: 'header'},
{id: 'cliente', header: ['Razón Social', {content: 'selectFilter'}],
fillspace:true, sort: 'string'},
{id: 'total', header: ['Total'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
]
var grid_cfdi_este_deposito_cols = [
{id: 'index', header: '#', adjust: 'data', css: 'right'},
{id: 'id', header: 'ID', hidden: true},
{id: 'serie', header: 'Serie', adjust: 'data'},
{id: 'folio', header: 'Folio', adjust: 'data', css: 'right'},
{id: 'uuid', header: 'UUID', width: 250, hidden: true},
{id: 'fecha', header: 'Fecha y Hora', width: 150, sort: 'date'},
{id: 'tipo_comprobante', header: 'Tipo', adjust: 'data'},
{id: 'estatus', header: 'Estatus', adjust: 'header'},
{id: 'cliente', header: ['Razón Social'], fillspace: true},
{id: 'total', header: ['Total'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'saldo', header: ['Saldo'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right'},
{id: 'importe', header: ['Este pago'], width: 125, sort: 'int',
format: webix.i18n.priceFormat, css: 'right', editor: 'text'},
]
var grid_cfdi_por_pagar = {
view: 'datatable',
id: 'grid_cfdi_por_pagar',
select: 'row',
autoConfig: false,
adjust: true,
height: 250,
resizeColumn: true,
headermenu: true,
drag: true,
columns: grid_cfdi_por_pagar_cols,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.index = i + 1
})
}
},
}
var grid_cfdi_este_deposito = {
view: 'datatable',
id: 'grid_cfdi_este_deposito',
select: 'row',
autoConfig: false,
adjust: true,
height: 200,
resizeColumn: true,
headermenu: true,
drag: true,
editable: true,
columns: grid_cfdi_este_deposito_cols,
on:{
'data->onStoreUpdated':function(){
this.data.each(function(obj, i){
obj.index = i + 1
})
}
},
}
var toolbar_banco_retiro = [
{view: 'label', label: 'Agregar retiro de banco'},
{},
{view: 'button', id: 'cmd_guardar_retiro', label: 'Guardar Retiro',
type: 'iconButton', autowidth: true, icon: 'minus'},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
icon: 'times-circle'}
]
var toolbar_banco_deposito = [
{view: 'label', label: 'Agregar depósito de banco'},
{},
{view: 'button', id: 'cmd_guardar_deposito', label: 'Guardar Depósito',
type: 'iconButton', autowidth: true, icon: 'plus'},
{view: 'icon', click: '$$("multi_bancos").setValue("banco_home")',
icon: 'times-circle'}
]
var controls_banco_retiro = [
{view: 'toolbar', elements: toolbar_banco_retiro},
{cols: [
{view: 'datepicker', id: 'date_retiro', name: 'retiro_fecha',
label: 'Fecha', format: '%d-%M-%Y', labelAlign: 'right',
required: true, invalidMessage: 'Selecciona una fecha',
labelWidth: 125},
{view: 'search', id: 'time_retiro', name: 'retiro_hora',
label: 'Hora', icon: 'clock-o', labelAlign: 'right',
pattern:{mask: '##:##:##', allow:/[0-9]/g}, required: true,
invalidMessage: 'Captura una hora'},
{view: 'text', id: 'retiro_referencia', name: 'retiro_referencia',
label: 'Referencia', labelAlign: 'right'},
]},
{cols: [
{view: 'richselect', id: 'lst_retiro_forma_pago',
name: 'retiro_forma_pago', label: 'Forma de Pago', required: true,
options: [], labelWidth: 125, labelAlign: 'right'},
{view: 'currency', type: 'text', id: 'txt_retiro_importe',
name: 'retiro_importe', label: 'Importe', labelAlign: 'right',
required: true, invalidMessage: 'Captura un valor númerico',
inputAlign: 'right', value: ''}
]},
{cols: [
{view: 'text', id: 'retiro_descripcion', name: 'retiro_descripcion',
label: 'Descripción', labelAlign: 'right', required: true,
labelWidth: 125},
]},
]
var controls_banco_deposito = [
{view: 'toolbar', elements: toolbar_banco_deposito},
{cols: [
{view: 'datepicker', id: 'date_deposito', name: 'deposito_fecha',
label: 'Fecha', format: '%d-%M-%Y', labelAlign: 'right',
required: true, invalidMessage: 'Selecciona una fecha',
labelWidth: 125},
{view: 'search', id: 'time_deposito', name: 'deposito_hora',
label: 'Hora', icon: 'clock-o', labelAlign: 'right',
pattern:{mask: '##:##:##', allow:/[0-9]/g}, required: true,
invalidMessage: 'Captura una hora'},
{view: 'text', id: 'deposito_referencia', name: 'deposito_referencia',
label: 'Referencia', labelAlign: 'right'},
]},
{cols: [
{view: 'richselect', id: 'lst_deposito_forma_pago',
name: 'deposito_forma_pago', label: 'Forma de Pago', required: true,
options: [], labelWidth: 125, labelAlign: 'right'},
{view: 'currency', type: 'text', id: 'txt_deposito_importe',
name: 'deposito_importe', label: 'Importe', labelAlign: 'right',
required: true, invalidMessage: 'Captura un valor númerico',
inputAlign: 'right', value: ''}
]},
{cols: [
{view: 'textarea', id: 'deposito_descripcion', label: 'Descripción',
name: 'deposito_descripcion', labelAlign: 'right', required: true,
labelWidth: 125, height: 70},
]},
{view: 'label', label: '<b>Facturas por pagar: </b>'},
grid_cfdi_por_pagar,
{view: 'label', label: '<b>Facturas a pagar en este depósito: </b>'},
grid_cfdi_este_deposito,
]
var form_banco_retiro = {
type: 'space',
responsive: true,
cols: [{
view: 'form',
id: 'form_banco_retiro',
complexData: true,
scroll: true,
elements: controls_banco_retiro,
}],
}
var form_banco_deposito = {
type: 'space',
responsive: true,
cols: [{
view: 'form',
id: 'form_banco_deposito',
complexData: true,
scroll: true,
elements: controls_banco_deposito,
}],
}
var multi_bancos = {
id: 'multi_bancos',
animate: true,
cells:[
{id: 'bancos_home', rows:[
{id: 'banco_home', rows:[
{view: 'toolbar', elements: toolbar_banco},
{view: 'toolbar', elements: toolbar_filtro_cuenta},
{view: 'toolbar', elements: toolbar_movimientos_banco},
grid_cuentabanco,
]}
//~ {id: 'partners_new', rows:[form_partner]}
]},
{id: 'banco_retiro', rows: [form_banco_retiro]},
{id: 'banco_deposito', rows: [form_banco_deposito]}
],
}

View File

@ -163,8 +163,11 @@ var toolbar_invoices_util = [
var toolbar_invoices_generate = {view: 'toolbar', elements: [{},
{view: 'button', id: 'cmd_cfdi_relacionados', label: 'CFDI Relacionados',
type: 'iconButton', autowidth: true, icon: 'file-o'},
{view: 'checkbox', id: 'chk_cfdi_anticipo', label: 'Es Anticipo', width: 100},
]}
{view: 'checkbox', id: 'chk_cfdi_anticipo', labelRight: 'Es Anticipo',
labelWidth: 0, width: 100, hidden: true},
{view: 'checkbox', id: 'chk_cfdi_donativo', labelRight: 'Es Donativo',
labelWidth: 0, width: 100, hidden: true},
{}]}
var toolbar_invoices_filter = [
@ -225,7 +228,7 @@ var grid_invoices = {
obj.index = i + 1
})
}
}
},
}
@ -233,6 +236,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},
@ -257,7 +261,7 @@ var grid_details = {
autoheight: true,
editable: true,
columns: grid_details_cols,
data: []
data: [],
}
@ -280,7 +284,7 @@ var grid_totals = {
footer: true,
autoheight: true,
columns: grid_totals_cols,
data: [{id: 1, concepto: 'SubTotal', importe: 0}]
data: [{id: 1, concepto: 'SubTotal', importe: 0}],
}
@ -520,14 +524,56 @@ var controls_prefactura = [
]
var opt_tipo_proceso = [
{id: 'Ordinario', value: 'Ordinario'},
{id: 'Precampaña', value: 'Precampaña'},
{id: 'Campaña', value: 'Campaña'},
]
var opt_tipo_comite = [
{id: 'Ejecutivo Nacional', value: 'Ejecutivo Nacional'},
{id: 'Ejecutivo Estatal', value: 'Ejecutivo Estatal'},
{id: 'Directivo Estatal', value: 'Directivo Estatal'},
]
var controles_ine = [
{maxHeight: 15},
{cols: [{maxWidth: 15},
{view: 'checkbox', id: 'chk_cfdi_usar_ine', labelWidth: 0,
labelRight: 'Usar el complemento INE'},
{}]},
{maxHeight: 10},
{cols: [{maxWidth: 15},
{view: 'richselect', id: 'lst_ine_tipo_proceso', labelWidth: 150,
label: 'Tipo de Proceso', options: opt_tipo_proceso,
value: 'Ordinario'},
{}]},
{maxHeight: 10},
{cols: [{maxWidth: 15},
{view: 'richselect', id: 'lst_ine_tipo_comite', labelWidth: 150,
label: 'Tipo de Comite', options: opt_tipo_comite,
value: 'Ejecutivo Nacional'},
{}]},
{maxHeight: 10},
{cols: [{maxWidth: 15},
{view: 'text', id: 'txt_ine_idcontabilidad', name: 'ine_idcontabilidad',
label: 'ID de Contabilidad: ', labelWidth: 150},
{}]},
]
var controls_invoices = [
{
view: 'tabview',
id: 'tv_invoice',
tabbar: {options: ['Generar', 'PreFacturas']}, animate: true,
//~ tabbar: {options: ['Generar', 'PreFacturas', 'INE']},
animate: true,
cells: [
{id: 'Generar', rows: controls_generate},
{id: 'PreFacturas', rows: controls_prefactura},
{id: 'INE', rows: controles_ine},
]
},
]

View File

@ -67,7 +67,10 @@ var ui_main = {
{},
menu_user,
{view: 'button', type: 'icon', width: 45, css: 'app_button',
icon: 'bell-o', badge: 0}
icon: 'bell-o', badge: 0},
{view: 'button', type: 'icon', width: 45, css: 'app_button',
icon: 'cogs', id: 'cmd_ir_al_admin', hidden: true,
click: 'cmd_ir_al_admin_click'}
]
},
{

View File

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

13
source/xslt/donat11.xslt Normal file
View File

@ -0,0 +1,13 @@
<?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:donat="http://www.sat.gob.mx/donat">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="no"/>
<!-- Manejador de nodos tipo donat:Donatarias -->
<xsl:template match="donat:Donatarias">
<!-- Iniciamos el tratamiento de los atributos de donat:Donatarias -->
<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="./@noAutorizacion"/></xsl:call-template>
<xsl:call-template name="Requerido"><xsl:with-param name="valor" select="./@fechaAutorizacion"/></xsl:call-template>
<xsl:call-template name="Requerido"><xsl:with-param name="valor" select="./@leyenda"/></xsl:call-template>
</xsl:template>
</xsl:stylesheet>

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>

51
source/xslt/ine11.xslt Normal file
View File

@ -0,0 +1,51 @@
<?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:ine="http://www.sat.gob.mx/ine">
<xsl:template match="ine:INE">
<!--Manejador de nodos tipo INE-->
<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="./@TipoProceso" />
</xsl:call-template>
<xsl:call-template name="Opcional">
<xsl:with-param name="valor" select="./@TipoComite" />
</xsl:call-template>
<xsl:call-template name="Opcional">
<xsl:with-param name="valor" select="./@IdContabilidad" />
</xsl:call-template>
<!-- Iniciamos el manejo de los elementos hijo en la secuencia -->
<xsl:for-each select="./ine:Entidad">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template match="ine:Entidad">
<!--Manejador de nodos tipo Entidad-->
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@ClaveEntidad" />
</xsl:call-template>
<xsl:call-template name="Opcional">
<xsl:with-param name="valor" select="./@Ambito" />
</xsl:call-template>
<!-- Iniciamos el tratamiento de los atributos de ine:Contabilidad-->
<xsl:for-each select="./ine:Contabilidad">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
<!-- Iniciamos el manejo de los elementos hijo en la secuencia Contabilidad-->
<xsl:template match="ine:Contabilidad">
<!-- Iniciamos el manejo de los nodos dependientes -->
<xsl:call-template name="Requerido">
<xsl:with-param name="valor" select="./@IdContabilidad" />
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>