From 28fcb803ab064ddf319e408475a9c2f28f52934f Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Sun, 12 Nov 2017 23:27:40 -0600 Subject: [PATCH] Agregar descuentos --- source/app/models/main.py | 65 +++++++++++++++++++------ source/static/js/controller/invoices.js | 28 +++++++++-- source/static/js/ui/invoices.js | 11 +++-- 3 files changed, 83 insertions(+), 21 deletions(-) diff --git a/source/app/models/main.py b/source/app/models/main.py index 90f8429..2afdbc3 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -952,6 +952,15 @@ class SATUsoCfdi(BaseModel): return tuple(rows) +class TipoCambio(BaseModel): + dia = DateField(default=util.now) + moneda = ForeignKeyField(SATMonedas) + tipo_cambio = DecimalField(max_digits=15, decimal_places=6, auto_round=True) + + class Meta: + order_by = ('-dia',) + + class Addendas(BaseModel): nombre = TextField(unique=True) addenda = TextField() @@ -1173,8 +1182,13 @@ class Productos(BaseModel): id = int(values.get('id', 0)) if id: row = (Productos - .select(Productos.id, Productos.clave, Productos.descripcion, - SATUnidades.name.alias('unidad'), Productos.valor_unitario) + .select( + Productos.id, + Productos.clave, + Productos.descripcion, + SATUnidades.name.alias('unidad'), + Productos.valor_unitario, + Productos.descuento) .join(SATUnidades).switch(Productos) .where(Productos.id==id).dicts()) if len(row): @@ -1330,7 +1344,8 @@ class Facturas(BaseModel): descuento = DecimalField(default=0.0, max_digits=20, decimal_places=6, auto_round=True) moneda = TextField(default='MXN') - tipo_cambio = DecimalField(default=1.0, decimal_places=6, auto_round=True) + tipo_cambio = DecimalField(default=1.0, max_digits=15, decimal_places=6, + auto_round=True) total = DecimalField(default=0.0, max_digits=20, decimal_places=6, auto_round=True) total_mn = DecimalField(default=0.0, max_digits=20, decimal_places=6, @@ -1714,29 +1729,43 @@ class Facturas(BaseModel): 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'] + + cantidad = float(product['cantidad']) + valor_unitario = float(product['valor_unitario']) + descuento = float(product['descuento']) + precio_final = valor_unitario - descuento + importe = round(cantidad * precio_final, 2) + + product['cantidad'] = cantidad + product['valor_unitario'] = valor_unitario + product['descuento'] = descuento + product['precio_final'] = precio_final + product['importe'] = round(cantidad * valor_unitario, 2) + + subtotal += importe FacturasDetalle.create(**product) + for tax in p.impuestos: if tax.id in totals_tax: - totals_tax[tax.id].importe += product['importe'] + #~ totals_tax[tax.id].importe += product['importe'] + totals_tax[tax.id].importe += importe else: - tax.importe = product['importe'] + #~ tax.importe = product['importe'] + tax.importe = importe totals_tax[tax.id] = tax - #~ totals_tax[tax.id]['importe'] = product['importe'] 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': @@ -1770,7 +1799,7 @@ class Facturas(BaseModel): total = subtotal + (total_trasladados or 0) - (total_retenciones or 0) total_mn = round(total * invoice.tipo_cambio, 2) data = { - 'subtotal': subtotal, + 'subtotal': subtotal + descuento, 'total': total, 'total_mn': total_mn, 'total_trasladados': total_trasladados, @@ -1868,6 +1897,7 @@ class Facturas(BaseModel): 'UsoCFDI': invoice.uso_cfdi, } + descuento = 0 conceptos = [] rows = FacturasDetalle.select().where(FacturasDetalle.factura==invoice) for row in rows: @@ -1881,6 +1911,9 @@ class Facturas(BaseModel): 'ValorUnitario': FORMAT.format(row.valor_unitario), 'Importe': FORMAT.format(row.importe), } + if row.descuento: + concepto['Descuento'] = FORMAT.format(row.descuento) + descuento += row.descuento taxes = {} traslados = [] @@ -1889,12 +1922,13 @@ class Facturas(BaseModel): for impuesto in row.producto.impuestos: if impuesto.tipo == 'E': continue - import_tax = round(impuesto.tasa * row.importe, 2) + base = row.importe - row.descuento + import_tax = round(impuesto.tasa * base, 2) tipo_factor = 'Tasa' if impuesto.factor != 'T': tipo_factor = 'Cuota' tax = { - "Base": FORMAT.format(row.importe), + "Base": FORMAT.format(base), "Impuesto": impuesto.key, "TipoFactor": tipo_factor, "TasaOCuota": str(impuesto.tasa), @@ -1912,6 +1946,9 @@ class Facturas(BaseModel): concepto['impuestos'] = taxes conceptos.append(concepto) + if descuento: + comprobante['Descuento'] = FORMAT.format(descuento) + impuestos = {} traslados = [] retenciones = [] @@ -2684,7 +2721,7 @@ def _crear_tablas(rfc): PreFacturasRelacionadas, SATAduanas, SATFormaPago, SATImpuestos, SATMonedas, SATRegimenes, SATTipoRelacion, SATUnidades, SATUsoCfdi, SATBancos, - Socios, Tags, Usuarios, CuentasBanco, + Socios, Tags, Usuarios, CuentasBanco, TipoCambio, Emisor.regimenes.get_through_model(), Socios.tags.get_through_model(), Productos.impuestos.get_through_model(), diff --git a/source/static/js/controller/invoices.js b/source/static/js/controller/invoices.js index 05e37ac..862b221 100644 --- a/source/static/js/controller/invoices.js +++ b/source/static/js/controller/invoices.js @@ -422,6 +422,7 @@ function guardar_y_timbrar(values){ delete rows[i]['unidad'] delete rows[i]['importe'] rows[i]['valor_unitario'] = parseFloat(rows[i]['valor_unitario']) + rows[i]['descuento'] = parseFloat(rows[i]['descuento']) } var data = new Object() @@ -687,7 +688,7 @@ function search_product_id_key_press(code, e){ function grid_details_before_edit_start(id){ - var columns = ['', 'descripcion', 'cantidad', 'valor_unitario'] + var columns = ['', 'descripcion', 'cantidad', 'valor_unitario', 'descuento'] if(!columns.indexOf(id.column)){ return !this.getItem(id.row)[id.column] } @@ -722,7 +723,8 @@ function grid_details_before_edit_stop(state, editor){ grid.unblockEvent() return true } - var valor_unitario = row['valor_unitario'] + var valor_unitario = parseFloat(row['valor_unitario']) + var descuento = parseFloat(row['descuento']) } if(editor.column == 'valor_unitario'){ @@ -736,10 +738,28 @@ function grid_details_before_edit_stop(state, editor){ grid.unblockEvent() return true } - var cantidad = row['cantidad'] + var cantidad = parseFloat(row['cantidad']) + var descuento = parseFloat(row['descuento']) } - row['importe'] = (cantidad * valor_unitario).round(DECIMALES) + if(editor.column == 'descuento'){ + var descuento = parseFloat(state.value) + if(isNaN(descuento)){ + msg = 'El descuento 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 = parseFloat(row['cantidad']) + var valor_unitario = parseFloat(row['valor_unitario']) + } + + var precio_final = valor_unitario - descuento + row['importe'] = (cantidad * precio_final).round(DECIMALES) + grid.refresh() calculate_taxes() } diff --git a/source/static/js/ui/invoices.js b/source/static/js/ui/invoices.js index ac69e57..b99c319 100644 --- a/source/static/js/ui/invoices.js +++ b/source/static/js/ui/invoices.js @@ -254,9 +254,14 @@ var grid_details_cols = [ {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'}, - {id: "valor_unitario", header:{text: 'Valor Unitario', css: 'center'}, width: 100, - format: webix.i18n.priceFormat, css:'right', editor: 'text'}, - {id: "importe", header:{text: 'Importe', css: 'center'}, width: 150, format: webix.i18n.priceFormat, css:'right'}, + {id: "valor_unitario", header:{text: 'Valor Unitario', css: 'center'}, + width: 100, format: webix.i18n.priceFormat, css:'right', editor: 'text'}, + {id: 'descuento', header:{text: 'Descuento', css: 'center'}, + width: 80, format: webix.i18n.priceFormat, css:'right', editor: 'text'}, + {id: 'precio_final', hidden: true, header: 'precio_final', width: 80, + format: webix.i18n.priceFormat, css:'right'}, + {id: "importe", header:{text: 'Importe', css: 'center'}, width: 150, + format: webix.i18n.priceFormat, css:'right'}, ]