diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py
index f739874..82d7ebc 100644
--- a/source/app/controllers/main.py
+++ b/source/app/controllers/main.py
@@ -78,13 +78,11 @@ class AppPartners(object):
def on_get(self, req, resp):
values = req.params
- print ('GET VALUES', values)
req.context['result'] = self._db.get_partners(values)
resp.status = falcon.HTTP_200
def on_post(self, req, resp):
values = req.params
- print ('POST VALUES', values)
req.context['result'] = self._db.partner(values)
resp.status = falcon.HTTP_200
@@ -108,7 +106,6 @@ class AppProducts(object):
def on_post(self, req, resp):
values = req.params
- #~ print ('VALUES', values)
req.context['result'] = self._db.product(values)
resp.status = falcon.HTTP_200
@@ -118,3 +115,26 @@ class AppProducts(object):
resp.status = falcon.HTTP_200
else:
resp.status = falcon.HTTP_204
+
+
+class AppInvoices(object):
+
+ def __init__(self, db):
+ self._db = db
+
+ def on_get(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.get_invoices(values)
+ resp.status = falcon.HTTP_200
+
+ def on_post(self, req, resp):
+ values = req.params
+ req.context['result'] = self._db.invoice(values)
+ resp.status = falcon.HTTP_200
+
+ def on_delete(self, req, resp):
+ values = req.params
+ if self._db.delete('invoice', values['id']):
+ resp.status = falcon.HTTP_200
+ else:
+ resp.status = falcon.HTTP_204
diff --git a/source/app/main.py b/source/app/main.py
index 3d795e2..921faf6 100644
--- a/source/app/main.py
+++ b/source/app/main.py
@@ -12,7 +12,8 @@ from middleware import (
)
from models.db import StorageEngine
from controllers.main import (
- AppLogin, AppLogout, AppAdmin, AppMain, AppValues, AppPartners, AppProducts
+ AppLogin, AppLogout, AppAdmin, AppMain, AppValues, AppPartners, AppProducts,
+ AppInvoices
)
from settings import DEBUG
@@ -31,6 +32,7 @@ api.add_route('/main', AppMain(db))
api.add_route('/values/{table}', AppValues(db))
api.add_route('/partners', AppPartners(db))
api.add_route('/products', AppProducts(db))
+api.add_route('/invoices', AppInvoices(db))
if DEBUG:
diff --git a/source/app/models/db.py b/source/app/models/db.py
index 59a2a45..80fac0d 100644
--- a/source/app/models/db.py
+++ b/source/app/models/db.py
@@ -41,6 +41,9 @@ class StorageEngine(object):
def _get_monedas(self, values):
return main.SATMonedas.get_activos()
+ def _get_regimenes(self, values):
+ return main.Emisor.get_regimenes()
+
def _get_usocfdi(self, values):
return main.SATUsoCfdi.get_activos()
@@ -49,6 +52,8 @@ class StorageEngine(object):
return main.Socios.remove(id)
if table == 'product':
return main.Productos.remove(id)
+ if table == 'invoice':
+ return main.Facturas.remove(id)
return False
def _get_client(self, values):
@@ -61,8 +66,7 @@ class StorageEngine(object):
return main.Socios.get_(values)
def partner(self, values):
- id = int(values['id'])
- del values['id']
+ id = int(values.pop('id', '0'))
if id:
return main.Socios.actualizar(values, id)
return main.Socios.add(values)
@@ -71,12 +75,20 @@ class StorageEngine(object):
return main.Productos.get_(values)
def product(self, values):
- id = int(values['id'])
- del values['id']
+ id = int(values.pop('id', '0'))
if id:
return main.Productos.actualizar(values, id)
return main.Productos.add(values)
+ def invoice(self, values):
+ id = int(values.pop('id', '0'))
+ if id:
+ return main.Facturas.actualizar(values, id)
+ return main.Facturas.add(values)
+
+ def get_invoices(self, values):
+ return main.Facturas.get_(values)
+
diff --git a/source/app/models/main.py b/source/app/models/main.py
index 0dfa407..aaf4ac3 100644
--- a/source/app/models/main.py
+++ b/source/app/models/main.py
@@ -102,11 +102,22 @@ class SATRegimenes(BaseModel):
moral = BooleanField(default=False)
class Meta:
- order_by = ('name',)
+ order_by = ('-default', 'name',)
indexes = (
(('key', 'name'), True),
)
+ @classmethod
+ def get_activos(cls):
+ rows = (SATRegimenes
+ .select(
+ SATRegimenes.key.alias('id'),
+ SATRegimenes.name.alias('value'))
+ .where(SATRegimenes.activo==True)
+ .dicts()
+ )
+ return tuple(rows)
+
class Emisor(BaseModel):
rfc = TextField(index=True)
@@ -139,6 +150,12 @@ class Emisor(BaseModel):
class Meta:
order_by = ('nombre',)
+ @classmethod
+ def get_regimenes(cls):
+ obj = Emisor.select()[0]
+ rows = [{'id': row.key, 'value': row.name} for row in obj.regimenes]
+ return tuple(rows)
+
class Certificado(BaseModel):
key = BlobField()
@@ -248,7 +265,7 @@ class SATFormaPago(BaseModel):
def get_activos(cls):
rows = (SATFormaPago
.select(
- SATFormaPago.id,
+ SATFormaPago.key.alias('id'),
SATFormaPago.name.alias('value'))
.where(SATFormaPago.activo==True)
.dicts()
@@ -671,7 +688,7 @@ class Facturas(BaseModel):
cliente = ForeignKeyField(Socios)
serie = TextField(default='')
folio = IntegerField(default=0)
- fecha = DateTimeField(default=util.now)
+ fecha = DateTimeField(default=util.now, formats=['%Y-%m-%d %H:%M:%S'])
fecha_timbrado = DateTimeField(null=True)
forma_pago = TextField(default='')
condiciones_pago = TextField(default='')
@@ -701,6 +718,167 @@ class Facturas(BaseModel):
class Meta:
order_by = ('fecha',)
+ @classmethod
+ def get_(cls, values):
+ rows = tuple(Facturas
+ .select(Facturas.id, Facturas.serie, Facturas.folio, Facturas.uuid,
+ Facturas.fecha, Facturas.tipo_comprobante, Facturas.estatus,
+ Facturas.total_mn, Socios.nombre.alias('cliente'))
+ .join(Socios)
+ .switch(Facturas).dicts()
+ )
+ return {'ok': True, 'rows': rows}
+
+ @classmethod
+ def remove(cls, id):
+ 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)
+ q.execute()
+ return bool(obj.delete_instance())
+
+ def _get_folio(self, serie):
+ inicio_serie = Folios.select(
+ Folios.inicio).where(Folios.serie==serie).scalar()
+ inicio = (Facturas
+ .select(fn.Max(Facturas.folio))
+ .where(Facturas.serie==serie)
+ .scalar())
+ if inicio is None:
+ inicio = inicio_serie
+ else:
+ inicio += 1
+ return inicio
+
+ def _calculate_totals(self, invoice, products):
+ subtotal = 0
+ totals_tax = {}
+ total_trasladados = None
+ total_retenciones = None
+ total_iva = 0
+
+ for product in products:
+ id_product = product.pop('id')
+ p = Productos.get(Productos.id==id_product)
+ product['descripcion'] = p.descripcion
+ product['unidad'] = p.unidad.key
+ product['clave'] = p.clave
+ product['clave_sat'] = p.clave_sat
+
+ product['factura'] = invoice.id
+ product['producto'] = id_product
+ product['importe'] = round(
+ float(product['cantidad']) * float(product['valor_unitario']), 2)
+ subtotal += product['importe']
+
+ FacturasDetalle.create(**product)
+ for tax in p.impuestos:
+ if tax.id in totals_tax:
+ totals_tax[tax.id]['importe'] += product['importe']
+ else:
+ tax.importe = product['importe']
+ totals_tax[tax.id] = tax
+
+ for tax in totals_tax.values():
+ if tax.tipo == 'E' or tax.tipo == 'R':
+ continue
+ import_tax = round(float(tax.tasa) * tax.importe, 2)
+ total_trasladados = (total_trasladados or 0) + import_tax
+ if tax.name == 'IVA':
+ total_iva += import_tax
+
+ invoice_tax = {
+ 'factura': invoice.id,
+ 'impuesto': tax.id,
+ 'base': tax.importe,
+ 'importe': import_tax,
+ }
+ FacturasImpuestos.create(**invoice_tax)
+
+ for tax in totals_tax.values():
+ if tax.tipo == 'E' or tax.tipo == 'T':
+ continue
+ if tax.tasa == round(Decimal(2/3), 6):
+ import_tax = round(float(tax.tasa) * total_iva, 2)
+ else:
+ import_tax = round(float(tax.tasa) * tax.importe, 2)
+ total_retenciones = (total_retenciones or 0) + import_tax
+
+ invoice_tax = {
+ 'factura': invoice.id,
+ 'impuesto': tax['id'],
+ 'base': tax['importe'],
+ 'importe': import_tax,
+ }
+ FacturasImpuestos.create(**invoice_tax)
+
+ total = subtotal + (total_trasladados or 0) - (total_retenciones or 0)
+ total_mn = round(total * invoice.tipo_cambio, 2)
+ data = {
+ 'subtotal': subtotal,
+ 'total': total,
+ 'total_mn': total_mn,
+ 'total_trasladados': total_trasladados,
+ 'total_retenciones': total_retenciones,
+ }
+ return data
+
+ @classmethod
+ def add(cls, values):
+ #~ print ('VALUES', values)
+ productos = util.loads(values.pop('productos'))
+
+ emisor = Emisor.select()[0]
+ values['folio'] = cls._get_folio(cls, values['serie'])
+ values['tipo_cambio'] = float(values['tipo_cambio'])
+ values['lugar_expedicion'] = emisor.codigo_postal
+
+ with database_proxy.atomic() as txn:
+ obj = Facturas.create(**values)
+ totals = cls._calculate_totals(cls, obj, productos)
+ obj.subtotal = totals['subtotal']
+ obj.total_trasladados = totals['total_trasladados']
+ obj.total_retenciones = totals['total_retenciones']
+ obj.total = totals['total']
+ obj.total_mn = totals['total_mn']
+ obj.save()
+
+ #~ obj.xml = self._make_xml(obj, emisor)
+ #~ obj.save()
+
+ msg = 'Factura guardada correctamente. Enviando a timbrar'
+ #~ 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()
+
+ row = {
+ 'id': obj.id,
+ 'serie': obj.serie,
+ 'folio': obj.folio,
+ 'uuid': obj.uuid,
+ 'fecha': obj.fecha,
+ 'tipo_comprobante': obj.tipo_comprobante,
+ 'estatus': obj.estatus,
+ 'total_mn': obj.total_mn,
+ 'cliente': obj.cliente.nombre,
+ }
+ data = {'ok': True, 'row': row, 'new': True, 'error': False, 'msg': msg}
+ return data
+
class FacturasDetalle(BaseModel):
factura = ForeignKeyField(Facturas)
diff --git a/source/static/img/file-xml.png b/source/static/img/file-xml.png
new file mode 100644
index 0000000..74dae07
Binary files /dev/null and b/source/static/img/file-xml.png differ
diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js
index 02e3892..1a243ad 100644
--- a/source/static/js/controller/invoices.js
+++ b/source/static/js/controller/invoices.js
@@ -1,5 +1,6 @@
var query = []
var grid = null
+var msg = ''
function get_series(){
@@ -15,6 +16,10 @@ function get_series(){
$$('lst_tipo_comprobante').config.readonly = true
$$('lst_tipo_comprobante').refresh()
}
+ if(values.length == 1){
+ $$('lst_serie').config.readonly = true
+ $$('lst_serie').refresh()
+ }
})
}
@@ -35,18 +40,31 @@ function get_monedas(){
pre = values[0]
$$('lst_moneda').getList().parse(values)
$$('lst_moneda').setValue(pre.id)
+ if(values.length == 1){
+ $$('fs_moneda').hide()
+ $$('fs_moneda').refresh()
+ }
})
}
function get_uso_cfdi(){
- webix.ajax().get('/values/usocfdi', function(text, data){
+ query = table_usocfdi.chain().find({fisica: true}).data()
+ $$('lst_uso_cfdi').getList().parse(query)
+ $$('lst_uso_cfdi').setValue(query[0].id)
+}
+
+
+function get_regimen_fiscal(){
+ webix.ajax().get('/values/regimenes', function(text, data){
var values = data.json()
pre = values[0]
- table_usocfdi.clear()
- table_usocfdi.insert(values)
- $$('lst_uso_cfdi').getList().parse(values)
- $$('lst_uso_cfdi').setValue(pre.id)
+ $$('lst_regimen_fiscal').getList().parse(values)
+ $$('lst_regimen_fiscal').setValue(pre.id)
+ if(values.length == 1){
+ $$('fs_regimen_fiscal').hide()
+ $$('fs_regimen_fiscal').refresh()
+ }
})
}
@@ -61,6 +79,7 @@ function default_config(){
get_forma_pago()
get_monedas()
get_uso_cfdi()
+ get_regimen_fiscal()
table_pt.clear()
table_totals.clear()
}
@@ -86,27 +105,197 @@ function cmd_edit_invoice_click(id, e, node){
$$("multi_invoices").setValue("invoices_new")
-};
+}
+
+
+function delete_invoice(id){
+ webix.ajax().del('/invoices', {id: id}, function(text, xml, xhr){
+ if(xhr.status == 200){
+ $$('grid_invoices').remove(id)
+ msg_sucess('Factura eliminada correctamente')
+ }else{
+ msg_error('No se pudo eliminar')
+ }
+ })
+}
+
function cmd_delete_invoice_click(id, e, node){
- webix.message({type:"success", text: "OK Delete"});
-
-};
-
-
-function cmd_timbrar_click(id, e, node){
- var form = this.getFormView()
-
- if (!form.validate()) {
- webix.message({type: 'error', text: 'Valores inválidos'})
+ var row = $$('grid_invoices').getSelectedItem()
+ if (row == undefined){
+ msg_error('Selecciona una factura')
return
}
- $$('form_invoice').clear();
+ if(!row['uuid']==null){
+ msg_error('Solo se pueden eliminar facturas sin timbrar')
+ return
+ }
+
+ var msg = '¿Estás seguro de eliminar la siguiente Factura?
'
+ msg += '(' + row['folio'] + ') ' + row['cliente']
+ msg += '
ESTA ACCIÓN NO SE PUEDE DESHACER'
+ webix.confirm({
+ title:'Eliminar Factura',
+ ok:'Si',
+ cancel:'No',
+ type:'confirm-error',
+ text:msg,
+ callback:function(result){
+ if (result){
+ delete_invoice(row['id'])
+ }
+ }
+ })
+}
+
+
+function validate_invoice(values){
+
+ if(values.id_partner == 0){
+ webix.UIManager.setFocus('search_client_name')
+ msg = 'Selecciona un cliente'
+ msg_error(msg)
+ return false
+ }
+
+ if(!grid.count()){
+ webix.UIManager.setFocus('search_product_id')
+ msg = 'Agrega al menos un producto o servicio'
+ msg_error(msg)
+ return false
+ }
+
+ var tipo_cambio = $$('txt_tipo_cambio').getValue()
+ if(tipo_cambio.trim() == ""){
+ webix.UIManager.setFocus('txt_tipo_cambio')
+ msg = 'El Tipo de Cambio es requerido'
+ msg_error(msg)
+ return false
+ }
+
+ if(isNaN(tipo_cambio * 1)){
+ webix.UIManager.setFocus('txt_tipo_cambio')
+ msg = 'El Tipo de Cambio debe ser un valor númerico'
+ msg_error(msg)
+ return false
+ }
+
+ var moneda = $$('lst_moneda').getValue()
+ if(moneda == 'MXN' && tipo_cambio != 1){
+ webix.UIManager.setFocus('txt_tipo_cambio')
+ msg = 'Si la moneda es MXN, el Tipo de Cambio debe ser 1.00'
+ msg_error(msg)
+ return false
+ }
+
+ if(moneda != 'MXN' && tipo_cambio == 1){
+ webix.UIManager.setFocus('txt_tipo_cambio')
+ msg = 'Si la moneda no es MXN, el Tipo de Cambio debe ser diferente de 1.00'
+ msg_error(msg)
+ return false
+ }
+
+ return true
+}
+
+
+function update_grid_invoices(values){
+ if(values.new){
+ $$('grid_invoices').add(values.row)
+ }else{
+ $$("grid_invoices").updateItem(values.row['id'], values.row)
+ }
+}
+
+
+function save_invoice(data){
+ var result = false
+ var values = NaN
+
+ webix.ajax().sync().post('invoices', data, {
+ error:function(text, data, XmlHttpRequest){
+ msg = 'Ocurrio un error, consulta a soporte técnico'
+ msg_error(msg)
+ },
+ success:function(text, data, XmlHttpRequest){
+ values = data.json();
+ if(values.ok){
+ update_grid_invoices(values)
+ result = true
+ }else{
+ webix.message({type:'error', text:values.msg})
+ }
+ }
+ })
+
+ if(result){
+ table_pt.clear()
+ table_totals.clear()
+ grid.clearAll()
+ $$('grid_totals').clearAll()
+
+ }
+
+ if(values.error){
+ webix.alert({
+ title: 'Error al Timbrar',
+ text: values.msg,
+ type: 'alert-error'
+ })
+ }else{
+ msg_sucess(values.msg)
+ }
+
+ return result
+}
+
+
+function cmd_timbrar_click(id, e, node){
+ var form = this.getFormView();
+
+ if(!form.validate()) {
+ webix.message({type:'error', text:'Valores inválidos'})
+ return
+ }
+
+ var values = form.getValues();
+ if(!validate_invoice(values)){
+ return
+ }
+
+ var rows = grid.data.getRange()
+ for (i = 0; i < rows.length; i++) {
+ delete rows[i]['delete']
+ delete rows[i]['clave']
+ delete rows[i]['descripcion']
+ delete rows[i]['unidad']
+ delete rows[i]['importe']
+ rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario'])
+ }
+
+ var data = new Object()
+ data['id'] = values.id
+ data['cliente'] = values.id_partner
+ data['productos'] = rows
+ data['serie'] = $$('lst_serie').getText()
+ data['forma_pago'] = $$('lst_forma_pago').getValue()
+ data['condiciones_pago'] = $$('txt_condicion_pago').getValue().trim()
+ data['moneda'] = $$('lst_moneda').getValue()
+ data['tipo_cambio'] = $$('txt_tipo_cambio').getValue()
+ data['tipo_comprobante'] = $$('lst_tipo_comprobante').getValue()
+ data['metodo_pago'] = $$('lst_metodo_pago').getValue()
+ data['uso_cfdi'] = $$('lst_uso_cfdi').getValue()
+ data['regimen_fiscal'] = $$('lst_regimen_fiscal').getValue()
+
+ if(!save_invoice(data)){
+ return
+ }
+
+ form.setValues({id_partner: 0, lbl_partner: 'Ninguno'})
$$('multi_invoices').setValue('invoices_home')
- webix.message({type:"success", text: "Factura guardada correctamente"})
}
@@ -204,7 +393,7 @@ function calculate_taxes(){
continue
}
concepto = tipo + tax.name + ' (' + tax.tasa + ')'
- total_tax = (tax.tasa * t.importe).round(2)
+ total_tax = (tax.tasa * t.importe).round(DECIMALES)
grid_totals.add({id: id, concepto: concepto, importe: total_tax})
id += 1
if(tax.name == 'IVA'){
@@ -220,16 +409,16 @@ function calculate_taxes(){
}
concepto = tipo + tax.name + ' (' + tax.tasa + ')'
if(tax.tasa == (2/3).round(6)){
- total_tax = (tax.tasa * total_iva * -1).round(2)
+ total_tax = (tax.tasa * total_iva * -1).round(DECIMALES)
concepto = tipo + tax.name + ' (2/3)'
}else{
- total_tax = (tax.tasa * t.importe * -1).round(2)
+ total_tax = (tax.tasa * t.importe * -1).round(DECIMALES)
}
grid_totals.add({id: id, concepto: concepto, importe: total_tax})
id += 1
}
- row = {importe: subtotal}
+ var row = {importe: subtotal}
grid_totals.updateItem(1, row)
}
@@ -301,6 +490,65 @@ function search_product_id_key_press(code, e){
}
+function grid_details_before_edit_start(id){
+ var columns = ['', 'descripcion', 'cantidad', 'valor_unitario']
+ if(!columns.indexOf(id.column)){
+ return !this.getItem(id.row)[id.column]
+ }
+}
+
+
+function grid_details_before_edit_stop(state, editor){
+ var row = grid.getItem(editor.row)
+
+ if(editor.column == 'descripcion'){
+ if(!state.value.trim()){
+ msg = 'La descripción no puede estar vacía'
+ webix.message({type:'error', text: msg})
+ grid.blockEvent()
+ state.value = state.old
+ grid.editCancel()
+ grid.unblockEvent()
+ return true
+ }
+ state.value = state.value.trim()
+ return true
+ }
+
+ if(editor.column == 'cantidad'){
+ var cantidad = parseFloat(state.value)
+ if(isNaN(cantidad)){
+ msg = 'La cantidad debe ser un número'
+ webix.message({type:'error', text: msg})
+ grid.blockEvent()
+ state.value = state.old
+ grid.editCancel()
+ grid.unblockEvent()
+ return true
+ }
+ var valor_unitario = row['valor_unitario']
+ }
+
+ if(editor.column == 'valor_unitario'){
+ var valor_unitario = parseFloat(state.value)
+ if(isNaN(valor_unitario)){
+ msg = 'El valor unitario debe ser un número'
+ webix.message({type:'error', text: msg})
+ grid.blockEvent()
+ state.value = state.old
+ grid.editCancel()
+ grid.unblockEvent()
+ return true
+ }
+ var cantidad = row['cantidad']
+ }
+
+ row['importe'] = (cantidad * valor_unitario).round(DECIMALES)
+ grid.refresh()
+ calculate_taxes()
+}
+
+
function grid_details_click(id, e, node){
if(id.column != 'delete'){
return
@@ -308,3 +556,25 @@ function grid_details_click(id, e, node){
grid.remove(id.row)
calculate_taxes()
}
+
+
+function grid_details_header_click(id){
+ if(id.column != 'delete'){
+ return
+ }
+
+ var msg = '¿Estás seguro de quitar todos los productos?'
+ webix.confirm({
+ title: 'Quitar todos',
+ ok: 'Si',
+ cancel: 'No',
+ type: 'confirm-error',
+ text: msg,
+ callback:function(result){
+ if (result){
+ grid.clearAll()
+ calculate_taxes()
+ }
+ }
+ })
+}
diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js
index 396a881..c6b083d 100644
--- a/source/static/js/controller/main.js
+++ b/source/static/js/controller/main.js
@@ -39,10 +39,25 @@ var controllers = {
$$('search_product_id').attachEvent('onKeyPress', search_product_id_key_press)
$$('grid_products_found').attachEvent('onValueSuggest', grid_products_found_click)
$$('grid_details').attachEvent('onItemClick', grid_details_click)
+ $$('grid_details').attachEvent('onHeaderClick', grid_details_header_click)
+ $$('grid_details').attachEvent('onBeforeEditStart', grid_details_before_edit_start)
+ $$('grid_details').attachEvent('onBeforeEditStop', grid_details_before_edit_stop)
+
+ get_uso_cfdi_to_table()
}
}
+function get_uso_cfdi_to_table(){
+ webix.ajax().get('/values/usocfdi', function(text, data){
+ var values = data.json()
+ pre = values[0]
+ table_usocfdi.clear()
+ table_usocfdi.insert(values)
+ })
+}
+
+
function get_partners(){
webix.ajax().get("/partners", {}, {
error: function(text, data, xhr) {
@@ -76,6 +91,23 @@ function get_products(){
}
+function get_invoices(){
+ var grid = $$('grid_invoices')
+ webix.ajax().get('/invoices', {}, {
+ error: function(text, data, xhr) {
+ webix.message({type: 'error', text: 'Error al consultar'})
+ },
+ success: function(text, data, xhr) {
+ var values = data.json();
+ grid.clearAll();
+ if (values.ok){
+ grid.parse(values.rows, 'json');
+ };
+ }
+ });
+}
+
+
function menu_user_click(id, e, node){
if (id == 1){
window.location = '/logout';
@@ -85,7 +117,7 @@ function menu_user_click(id, e, node){
function multi_change(prevID, nextID){
- //~ webix.message(prevID)
+ //~ webix.message(nextID)
if(nextID == 'app_partners'){
active = $$('multi_partners').getActiveId()
if(active == 'partners_home'){
@@ -102,6 +134,14 @@ function multi_change(prevID, nextID){
return
}
+ if(nextID == 'app_invoices'){
+ active = $$('multi_invoices').getActiveId()
+ if(active == 'invoices_home'){
+ get_invoices()
+ }
+ return
+ }
+
}
diff --git a/source/static/js/controller/partners.js b/source/static/js/controller/partners.js
index 6d55add..d9ba384 100644
--- a/source/static/js/controller/partners.js
+++ b/source/static/js/controller/partners.js
@@ -7,13 +7,17 @@ function cmd_new_partner_click(id, e, node){
$$('grid_partners').clearSelection()
$$('multi_partners').setValue('partners_new')
$$('tab_partner').setValue('Datos Fiscales')
-};
+
+ query = table_usocfdi.chain().find({fisica: true}).data()
+ $$('lst_uso_cfdi_socio').getList().parse(query)
+
+}
function cmd_new_contact_click(id, e, node){
$$('grid_contacts').clearSelection()
$$('multi_contacts').setValue('contacts_new')
-};
+}
function cmd_edit_partner_click(id, e, node){
@@ -204,6 +208,7 @@ function opt_tipo_change(new_value, old_value){
$$("pais").define("readonly", true)
$$("pais").define("value", PAIS)
+
if (new_value == 1 || new_value == 2){
$$("rfc").define("value", "");
$$("rfc").define("readonly", false);
@@ -226,6 +231,17 @@ function opt_tipo_change(new_value, old_value){
} else {
$$("rfc").focus();
}
+
+ $$('lst_uso_cfdi_socio').define('suggest', [])
+ if (new_value == 1){
+ query = table_usocfdi.chain().find({fisica: true}).data()
+ }else if (new_value == 2){
+ query = table_usocfdi.chain().find({moral: true}).data()
+ }else{
+ query = [{id: 'P01', value: 'Por definir'}]
+ }
+ $$('lst_uso_cfdi_socio').getList().parse(query)
+ $$('lst_uso_cfdi_socio').refresh()
}
diff --git a/source/static/js/controller/util.js b/source/static/js/controller/util.js
index 6ae639f..568d557 100644
--- a/source/static/js/controller/util.js
+++ b/source/static/js/controller/util.js
@@ -2,6 +2,7 @@ var PUBLICO = "Público en general";
var RFC_PUBLICO = "XAXX010101000";
var RFC_EXTRANJERO = "XEXX010101000";
var PAIS = "México";
+var DECIMALES = 2;
var db = new loki('data.db');
@@ -18,6 +19,16 @@ function show(values){
}
+function msg_error(msg){
+ webix.message({type: 'error', text: msg})
+}
+
+
+function msg_sucess(msg){
+ webix.message({type: 'sucess', text: msg})
+}
+
+
Number.prototype.round = function(decimals){
return Number((Math.round(this + "e" + decimals) + "e-" + decimals))
}
diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js
index 8da3482..10ffb09 100644
--- a/source/static/js/ui/invoices.js
+++ b/source/static/js/ui/invoices.js
@@ -54,7 +54,7 @@ var grid_details_cols = [
{id: 'delete', header: '', width: 30, css: 'delete'},
{id: "clave", header:{text: 'Clave', css: 'center'}, width: 100},
{id: "descripcion", header:{text: 'Descripción', css: 'center'},
- fillspace: true},
+ fillspace: true, editor: 'text'},
{id: "unidad", header:{text: 'Unidad', css: 'center'}, width: 100},
{id: 'cantidad', header: {text: 'Cantidad', css: 'center'}, width: 100,
format: webix.i18n.numberFormat, css:'right', editor: 'text'},
@@ -70,6 +70,7 @@ var grid_details = {
select: 'row',
adjust: true,
autoheight: true,
+ editable: true,
columns: grid_details_cols,
data: []
}
@@ -186,7 +187,8 @@ var body_opciones = {rows: [
{view: 'richselect', id: 'lst_forma_pago', label: 'Forma de Pago',
labelPosition: 'top', required: true, options: []},
{view: 'richselect', id: 'lst_metodo_pago', label: 'Método de Pago',
- labelPosition: 'top', options: opt_metodo_pago, value: 'PUE',
+ labelPosition: 'top', options: opt_metodo_pago, readonly: true,
+ value: 'PUE',
required: true},
{view: 'text', id: 'txt_condicion_pago', label: 'Condiciones de Pago',
labelPosition: 'top'},
@@ -211,6 +213,14 @@ var body_uso_cfdi = {
}
+var body_regimen_fiscal = {
+ view: 'richselect',
+ id: 'lst_regimen_fiscal',
+ required: true,
+ options: []
+}
+
+
var controls_generate = [
{cols: [ {rows:[
{view: 'fieldset', label: 'Buscar Cliente', body: {rows: [
@@ -248,8 +258,10 @@ var controls_generate = [
{maxWidth: 300, rows: [
{view: 'fieldset', label: 'Comprobante', body: body_comprobante},
{view: 'fieldset', label: 'Opciones de Pago', body: body_opciones},
- {view: 'fieldset', label: 'Moneda', body: body_moneda},
+ {view: 'fieldset', id: 'fs_moneda', label: 'Moneda', body: body_moneda},
{view: 'fieldset', label: 'Uso del CFDI', body: body_uso_cfdi},
+ {view: 'fieldset', id: 'fs_regimen_fiscal', label: 'Regimen Fiscal',
+ body: body_regimen_fiscal},
]}
]},
{view: 'label', label: 'Detalle', height: 30, align: 'left'},
@@ -268,11 +280,11 @@ var controls_invoices = [
]
},
{rows: [
- { template:"", type: "section" },
- { margin: 10, cols: [{},
+ {template:"", type: "section" },
+ {margin: 10, cols: [{},
{view: "button", id: "cmd_timbrar", label: "Timbrar",
type: "form", autowidth: true, align:"center"},
- {view: 'button', id: 'cmd_close_invoice', label: 'Salir',
+ {view: 'button', id: 'cmd_close_invoice', label: 'Cancelar',
type: 'danger', autowidth: true, align: 'center'},
{}]
},
@@ -281,14 +293,14 @@ var controls_invoices = [
var form_invoice = {
- type: "space",
+ type: 'space',
cols: [{
- view: "form",
- id: "form_invoice",
+ view: 'form',
+ id: 'form_invoice',
complexData: true,
elements: controls_invoices,
}]
-};
+}
var multi_invoices = {
@@ -302,7 +314,7 @@ var multi_invoices = {
]},
{id: "invoices_new", rows:[form_invoice, {}]}
]
-};
+}
var app_invoices = {
diff --git a/source/static/js/ui/partners.js b/source/static/js/ui/partners.js
index 358f7d1..472826d 100644
--- a/source/static/js/ui/partners.js
+++ b/source/static/js/ui/partners.js
@@ -85,6 +85,11 @@ var controls_fiscales = [
{view: 'checkbox', id: 'dias_habiles', name: 'dias_habiles',
label: 'Hábiles: ', value: false, width: 180},
{},
+ ]},
+ {cols: [
+ {view: 'richselect', id: 'lst_uso_cfdi_socio', name: 'uso_cfdi_socio',
+ label: 'Uso del CFDI', options: []},
+ {},
]}
]