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: []}, + {}, ]} ]