private bool FondoDeCaja() { // Se verifica si ya se hizo el fondo CajaFondo oFondo = this.ctlCajaGeneral.ctlFondeDeCaja; if (oFondo.FondoRealizado) { UtilLocal.MensajeInformacion("El Fondo de Caja del día de hoy ya se realizó."); return false; } // Se confirma la operación string sMensaje = string.Format("¿Estás seguro que deseas guardar el Fondo de Caja con un importe de {0}?", oFondo.Conteo.ToString(GlobalClass.FormatoMoneda)); if (oFondo.Diferencia != 0) sMensaje += string.Format("\n\nToma en cuenta que hay una diferencia de {0} y por tanto se requerirá una autorización para continuar.", oFondo.Diferencia.ToString(GlobalClass.FormatoMoneda)); if (UtilLocal.MensajePregunta(sMensaje) != DialogResult.Yes) return false; // Se solicita la validación del usuario var Res = UtilLocal.ValidarObtenerUsuario("Ventas.FondoDeCaja.Agregar"); if (Res.Error) return false; var oUsuario = Res.Respuesta; // Se solicita la validación de autorización, si aplica Usuario oAutorizo = null; if (oFondo.Diferencia != 0) { Res = UtilLocal.ValidarObtenerUsuario("Autorizaciones.Ventas.FondoDeCaja.Diferencia", "Autorización"); //if (Res.Exito) oAutorizo = Res.Respuesta; } // Se procede a guardar los datos DateTime dAhora = DateTime.Now; // Se guarda el dato de inicio var oEfectivo = new CajaEfectivoPorDia() { SucursalID = GlobalClass.SucursalID, Dia = dAhora, Inicio = oFondo.Conteo, InicioUsuarioID = oUsuario.UsuarioID }; Datos.Guardar<CajaEfectivoPorDia>(oEfectivo); // Se registra la póliza de la diferencia, si hubo if (oFondo.Diferencia != 0) { if (oFondo.Diferencia > 0) ContaProc.CrearPoliza(Cat.ContaTiposDePoliza.Diario, "DIFERENCIA EN FONDO DE CAJA", Cat.ContaCuentasAuxiliares.Caja, Cat.ContaCuentasAuxiliares.FondoDeCaja , oFondo.Diferencia, DateTime.Now.ToShortDateString(), Cat.Tablas.CajaEfectivoPorDia, oEfectivo.CajaEfectivoPorDiaID); else ContaProc.CrearPoliza(Cat.ContaTiposDePoliza.Diario, "DIFERENCIA EN FONDO DE CAJA", Cat.ContaCuentasAuxiliares.FondoDeCaja, Cat.ContaCuentasAuxiliares.Caja , (oFondo.Diferencia * -1), DateTime.Now.ToShortDateString(), Cat.Tablas.CajaEfectivoPorDia, oEfectivo.CajaEfectivoPorDiaID); } // Se genera y guarda la autorización, si aplica if (oFondo.Diferencia != 0) { VentasProc.GenerarAutorizacion(Cat.AutorizacionesProcesos.FondoDeCajaDiferencia, Cat.Tablas.CajaEfectivoPorDia, oEfectivo.CajaEfectivoPorDiaID , (oAutorizo == null ? 0 : oAutorizo.UsuarioID)); } // Se muestra una notifiación con el resultado UtilLocal.MostrarNotificacion("Procedimiento completado correctamente."); return true; }
private bool FacturaGlobal(CajaEfectivoPorDia oDia) { // Se obtiene el importe a restar, excepto si es domingo decimal mRestar = 0; if (DateTime.Now.DayOfWeek != DayOfWeek.Sunday) mRestar = Util.Decimal(Config.Valor("Ventas.FacturaGlobal.Restar")); // Se obtienen el total de los tickets del día DateTime dHoy = DateTime.Today; var oPagosDet = Datos.GetListOf<VentasPagosDetalleAvanzadoView>(c => c.SucursalID == GlobalClass.SucursalID && EntityFunctions.TruncateTime(c.Fecha) == dHoy && !c.Facturada); var oDevsV = Datos.GetListOf<VentasDevolucionesView>(c => c.SucursalID == GlobalClass.SucursalID && EntityFunctions.TruncateTime(c.Fecha) == dHoy); decimal mTickets = 0, mNegativos = 0, mCancelaciones = 0, mDevoluciones = 0; decimal mDevolucionesDia = 0, mDevolucionesDiasAnt = 0, mGarantiasDia = 0, mGarantiasDiasAnt = 0, mCobranza = 0; decimal mFacturarVales = 0, mCostoVales = 0; string sCancelaciones = "", sDevoluciones = ""; decimal mCostoTotal = 0; var oVentasProc = new List<int>(); var oPagosProc = new List<int>(); var oFormasDePago = new List<VentasPagosDetalleView>(); foreach (var oReg in oPagosDet) { // Si es nota de crédito negativa, se ignora // Se determinó que las devoluciones y las garantías con vale (las cuales generan un pago negativo) sí deben restar en la // factura global porque en otro momento, cuando se use el vale, ese importe sí va a sumar en la factura de ese día. // Se llegó a esta conclusión entre Isidro y Santa Haidé. 17/04/2015 // if (oReg.FormaDePagoID == Cat.FormasDePago.Vale && oReg.Importe < 0) // continue; // Se suma el importe a la variable correspondiente if (oReg.Importe >= 0) { mTickets += oReg.Importe; // Para diferenciar vales if (oReg.FormaDePagoID == Cat.FormasDePago.Vale) mFacturarVales += oReg.Importe; // Para diferencia la cobranza if (oReg.ACredito.Valor()) mCobranza += oReg.Importe; // Se suma el costo, si es venta a crédito, se calcula un proporcional if (!oPagosProc.Contains(oReg.VentaPagoID.Valor())) { if (!oVentasProc.Contains(oReg.VentaID.Valor())) { var oVentaDet = Datos.GetListOf<VentaDetalle>(c => c.VentaID == oReg.VentaID && c.Estatus); decimal mCosto = oVentaDet.Sum(c => c.Costo * c.Cantidad); decimal mPrecio = oVentaDet.Sum(c => (c.PrecioUnitario + c.Iva) * c.Cantidad); // Si la venta no está pagada, se calcula un proporcional if (oReg.VentaEstatusID != Cat.VentasEstatus.Completada && mPrecio > 0) mCosto = ((oReg.ImportePago.Valor() / mPrecio) * mCosto); mCostoTotal += mCosto; oVentasProc.Add(oReg.VentaID.Valor()); } // Para diferenciar vales var oPagoVales = Datos.GetListOf<VentaPagoDetalle>(c => c.VentaPagoID == oReg.VentaPagoID && c.Importe > 0 && c.TipoFormaPagoID == Cat.FormasDePago.Vale && c.Estatus); if (oPagoVales.Count > 0) mCostoVales += oPagoVales.Sum(c => c.Importe); oPagosProc.Add(oReg.VentaPagoID.Valor()); } // Para tener el dato de las diferentes formas de pago var oFormaDePago = oFormasDePago.FirstOrDefault(c => c.FormaDePagoID == oReg.FormaDePagoID); if (oFormaDePago == null) { oFormaDePago = new VentasPagosDetalleView() { FormaDePagoID = oReg.FormaDePagoID, FormaDePago = oReg.FormaDePago }; oFormasDePago.Add(oFormaDePago); } oFormaDePago.Importe += oReg.Importe; } else { // Se verifica a qué tipo de movimiento corresponde el pago negativo, Devolución / Garantía / 9500 decimal mImporteNeg = (oReg.Importe * -1); // Se verifica si es una Devolución/Cancelación var oDev = Datos.GetEntity<VentaDevolucion>(c => c.VentaPagoDetalleID == oReg.VentaPagoDetalleID && c.Estatus); if (oDev == null) { // Se verifica si es de un 9500 var o9500 = Datos.GetEntity<Cotizacion9500>(c => c.AnticipoVentaID == oReg.VentaID && c.Estatus); if (o9500 == null) { // Se verifica si es de una garantía var oGar = Datos.GetEntity<VentaGarantia>(c => c.VentaPagoDetalleID == oReg.VentaPagoDetalleID && c.Estatus); if (oGar == null) { // Si se llega aquí quiere decir que hay un pago negativo que no es ni de devolución/cancelación ni de 9500 ni de garantía. Es importante // revisar de qué es para hacer los ajustes necesarios - Moi 16/06/2015 UtilLocal.MensajeAdvertencia("Se encontró un pago negativo sin origen aparente. Número: " + oReg.VentaPagoDetalleID.ToString() + ". Por favor toma nota de este número y avísale al administrador del sistema."); } else { // Se suma el importe correspondiente de venta y de costo if (oReg.FechaVenta < dHoy) { mGarantiasDiasAnt += mImporteNeg; mCostoTotal -= oGar.Costo; // Para diferenciar vales if (oReg.FormaDePagoID == Cat.FormasDePago.Vale) mCostoVales -= oGar.Costo; } else { mGarantiasDia += mImporteNeg; // No se resta el costo, por lo mismo que los pagos negativos de devoluciones (abajo mencionado). } } } else { // Se suma el importe correspondiente mNegativos += mImporteNeg; // Se suma el costo, se toma el importe proporcional según el pago var o9500Det = Datos.GetListOf<Cotizacion9500Detalle>(c => c.Cotizacion9500ID == o9500.Cotizacion9500ID && c.Estatus); decimal mCosto = o9500Det.Sum(c => c.Costo * c.Cantidad); decimal mPrecio = o9500Det.Sum(c => c.PrecioAlCliente * c.Cantidad); mCosto = ((oReg.Importe / mPrecio) * mCosto); mCostoTotal += mCosto; // Para diferenciar vales if (oReg.FormaDePagoID == Cat.FormasDePago.Vale) mCostoVales += mCosto; } } else { // Se suma el importe correspondiente de venta y de costo if (oReg.FechaVenta < dHoy) { mDevolucionesDiasAnt += mImporteNeg; // Para la factura impresa string sFolioVenta = ("|" + oReg.FolioVenta + "|"); if (oDev.EsCancelacion) { mCancelaciones += (oReg.Importe * -1); sCancelaciones += (sCancelaciones.Contains(sFolioVenta) ? "" : (", " + sFolioVenta)); } else { mDevoluciones += (oReg.Importe * -1); sDevoluciones += (sCancelaciones.Contains(sFolioVenta) ? "" : (", " + sFolioVenta)); } // Para diferenciar vales (como es negativo, se resta) // Siempre no, si es un pago negativo no se debe considerar para la suma del importe de vales (Haid{e e Isidro detectamos que los vales // creados son negativos y estaban apareciendo en la FGD en negativo y esto no es correcto. Cuando se crea un vale ya existe una póliza // que hace la operación de afectar Caja y Anticipo Clientes. La FGD sólo debe afectarse cuando los vales se usan)- Moi 08/08/2015 // if (oReg.FormaDePagoID == Cat.FormasDePago.Vale) // mFacturarVales += oReg.Importe; // Se resta el costo, (cada pago negativo corresponde sólo a una devolución) var oDevDet = Datos.GetListOf<VentaDevolucionDetalle>(c => c.VentaDevolucionID == oDev.VentaDevolucionID && c.Estatus); mCostoTotal -= (oDevDet.Count > 0 ? oDevDet.Sum(c => c.Costo * c.Cantidad) : 0); // Para diferenciar vales if (oReg.FormaDePagoID == Cat.FormasDePago.Vale) mCostoVales -= oDevDet.Sum(c => c.Costo * c.Cantidad); } else { mDevolucionesDia += mImporteNeg; // No se resta el costo en pagos negativos del día, pues tampoco se suma el costo de su pago positivo equivalente ya que si la venta está devuelta // ya no tiene detalle - Moi 16/06/2015 // var oDevDet = General.GetListOf<VentaDevolucionDetalle>(c => c.VentaDevolucionID == oDev.VentaDevolucionID && c.Estatus); // mCostoTotal -= (oDevDet.Count > 0 ? oDevDet.Sum(c => c.Costo * c.Cantidad) : 0); } } } } // Se obtiene lo pendiente por restar de facturado días anteriores de otras sucursales cuando no se abrió alguna tienda o no se hizo, si hubiera decimal mFacturadoDiasAnt = 0; var oPendientePorFacturar = Datos.GetListOf<FacturaGlobalPendientePorDescontar>(c => c.SucursalID == GlobalClass.SucursalID && c.Fecha < dHoy); foreach (var oReg in oPendientePorFacturar) { mFacturadoDiasAnt += oReg.Importe; // Se resta el costo, proporcional a lo abonado en días anteriores var oVentaDet = Datos.GetListOf<VentaDetalle>(c => c.VentaID == oReg.VentaID && c.Estatus); decimal mCosto = oVentaDet.Sum(c => c.Costo * c.Cantidad); decimal mPrecio = oVentaDet.Sum(c => (c.PrecioUnitario + c.Iva) * c.Cantidad); if (mPrecio == 0) continue; // No estoy seguro por qué el precio podría ser cero, sería bueno analizar con más calma :D mCosto = ((oReg.Importe / mPrecio) * mCosto); mCostoTotal -= mCosto; } // Se obtiene el total de los tickets de días anteriores facturados el día de hoy var oDatos = Datos.GetListOf<VentasFacturasDetalleAvanzadoView>(c => EntityFunctions.TruncateTime(c.Fecha) == dHoy && c.FechaVenta < dHoy && c.EstatusGenericoID == Cat.EstatusGenericos.Completada) .Select(c => new { c.VentaID }).Distinct(); foreach (var oReg in oDatos) { // Se verifica si el pago es de la sucursal actual, si no, no se cuenta // No se pude dar que se abone en múltiples sucursales pues hay un candado que donde se hace el primer abono de la venta, sólo ahí se puede abonar. if (Datos.Exists<VentasPagosView>(c => c.VentaID == oReg.VentaID && c.Importe > 0 && c.SucursalID != GlobalClass.SucursalID)) continue; // Se obtiene el importe de lo abonado sólo los días anteriores a hoy var oAbonosAnt = Datos.GetListOf<VentasPagosView>(c => c.VentaID == oReg.VentaID && c.Fecha < dHoy); decimal mAbonosAnt = oAbonosAnt.Sum(c => c.Importe); mFacturadoDiasAnt += mAbonosAnt; // Para diferenciar vales /* Ya no se consideran los vales de lo facturado de tickets de días anteriores porque ya fueron contemplados en la factura global del día de la venta - Moi 2015-08-26 var oAbonosAntVale = General.GetListOf<VentasPagosDetalleAvanzadoView>(c => c.VentaID == oReg.VentaID && c.Fecha < dHoy && c.FormaDePagoID == Cat.FormasDePago.Vale); decimal mAbonosAntVale = oAbonosAntVale.Sum(c => c.Importe); mFacturarVales += mAbonosAntVale; */ // Se resta el costo, proporcional a lo abonado en días anteriores var oVentaDet = Datos.GetListOf<VentaDetalle>(c => c.VentaID == oReg.VentaID && c.Estatus); decimal mCosto = oVentaDet.Sum(c => c.Costo * c.Cantidad); decimal mPrecio = oVentaDet.Sum(c => (c.PrecioUnitario + c.Iva) * c.Cantidad); if (mPrecio == 0) continue; // No estoy seguro por qué el precio podría ser cero, sería bueno analizar con más calma :D mCosto = ((mAbonosAnt / mPrecio) * mCosto); mCostoTotal -= mCosto; // Para diferenciar vales // mCostoVales -= ((mAbonosAntVale / mPrecio) * mCosto); } // Se hace el cálculo final decimal mCostoMinimo = (UtilTheos.ObtenerImporteMasIva(mCostoTotal) * 1.1M); // decimal mOficial = (mTickets - mNegativos - mDevoluciones - mCancelaciones - mFacturadoDiasAnt); decimal mOficial = (mTickets - mNegativos - mDevolucionesDia - mDevolucionesDiasAnt - mGarantiasDia - mGarantiasDiasAnt - mFacturadoDiasAnt); decimal mFacturar = (mOficial - mRestar); decimal mRestante = 0; var oFacturaGlobalAnt = Datos.GetListOf<CajaFacturaGlobal>(c => c.SucursalID == GlobalClass.SucursalID).OrderBy(c => c.Dia).LastOrDefault(); if (mFacturar > mCostoMinimo) { // Se verifica si hay saldo restante, para abonar la diferencia if (oFacturaGlobalAnt.SaldoRestante > 0) { mRestante = (mFacturar - mCostoMinimo); mRestante = (mRestante > oFacturaGlobalAnt.SaldoRestante ? oFacturaGlobalAnt.SaldoRestante : mRestante); mFacturar -= mRestante; mRestante *= -1; } } else { mRestante = (mCostoMinimo - mFacturar); mFacturar = mCostoMinimo; } // Se genera cuadro informativo de los cálculos realizados /* var oTexto = new StringBuilder(); oTexto.AppendLine("Tickets:\t\t(+)\t" + mTickets.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Negativos:\t\t(-)\t" + mNegativos.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Devoluciones:\t\t(-)\t" + mDevoluciones.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Cancelaciones:\t(-)\t" + mCancelaciones.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Facturado días ant.:\t(-)\t" + mFacturadoDiasAnt.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Restar:\t\t(-)\t" + mRestar.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Costo Min.:\t\t(i)\t" + mCostoMinimo.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("Restante ant.:\t(-)\t" + mRestante.ToString(GlobalClass.FormatoMoneda)); oTexto.AppendLine("------------------------------------------------------"); oTexto.AppendLine("Facturar:\t\t(=)\t" + mFacturar.ToString(GlobalClass.FormatoMoneda)); new MensajeTexto("Factura Global del Día", oTexto.ToString()).ShowDialog(Principal.Instance); */ // Se calcula el importe de la reserva, con múltiplos de 50 decimal mReserva = 0; decimal mPreFacturar = mFacturar; if (mOficial != mFacturar) { mReserva = (mOficial - mFacturar); if (mReserva > 0) { int iMultipo = (int)Math.Floor(mReserva / 50); decimal mDiferencia = (mReserva - (50 * iMultipo)); mFacturar += mDiferencia; mReserva -= mDiferencia; } else { mReserva = 0; } } // Se manda hacer la factura int iFacturaID = 0; if (mFacturar > 0) { string sVentas = ("VENTAS PÚBLICO GENERAL: " + dHoy.ToString("d")); sCancelaciones = ("CANCELACIONES: " + (sCancelaciones.Length > 0 ? sCancelaciones.Substring(2).Replace("|", "") : "")); sDevoluciones = ("DEVOLUCIONES: " + (sDevoluciones.Length > 0 ? sDevoluciones.Substring(2).Replace("|", "") : "")); var oResFactura = VentasLoc.GenerarFacturaGlobal(sVentas, mCostoTotal, (mFacturar + mCancelaciones + mDevoluciones) , sCancelaciones, mCancelaciones, sDevoluciones, mDevoluciones, oFormasDePago); if (oResFactura.Error) { UtilLocal.MensajeAdvertencia("Hubo un error al generar la factura.\n\n" + oResFactura.Mensaje); return false; } iFacturaID = oResFactura.Respuesta; } else { mFacturar = 0; mRestante = (mOficial - mRestar); if (mRestante < 0) mRestante *= -1; } // Se guardan los datos de la factura global var oFacturaGlobal = new CajaFacturaGlobal() { Dia = oDia.Dia, SucursalID = GlobalClass.SucursalID, Tickets = mTickets, FacturadoDeDiasAnt = mFacturadoDiasAnt, Negativos = mNegativos, DevolucionesDia = mDevolucionesDia, DevolucionesDiasAnt = mDevolucionesDiasAnt, GarantiasDia = mGarantiasDia, GarantiasDiasAnt = mGarantiasDiasAnt, Cobranza = mCobranza, Restar = mRestar, CostoMinimo = mCostoMinimo, Restante = mRestante, SaldoRestante = (oFacturaGlobalAnt.SaldoRestante + mRestante), PreFacturar = mPreFacturar, Facturado = mFacturar, FacturadoVales = mFacturarVales, VentaFacturaID = (iFacturaID > 0 ? (int?)iFacturaID : null) }; Datos.Guardar<CajaFacturaGlobal>(oFacturaGlobal); // Se borran los datos de importes pendientes por descontar, por tickets convertidos a factura de otras sucursales oPendientePorFacturar = Datos.GetListOf<FacturaGlobalPendientePorDescontar>(c => c.SucursalID == GlobalClass.SucursalID); foreach (var oReg in oPendientePorFacturar) Datos.Eliminar<FacturaGlobalPendientePorDescontar>(oReg); // Se crea la Poliza correspondiente (AfeConta) if (iFacturaID > 0) { var oFactura = Datos.GetEntity<VentaFactura>(c => c.VentaFacturaID == iFacturaID && c.Estatus); ContaProc.CrearPolizaAfectacion(Cat.ContaAfectaciones.VentaContadoPagoFacturaGlobal, oFactura.VentaFacturaID, (oFactura.Serie + oFactura.Folio) , "FACTURA GLOBAL DEL DÍA"); // Se hace una póliza sencilla por la diferencia de, si hay if (mOficial != mFacturar) { var oSucursal = Datos.GetEntity<Sucursal>(c => c.SucursalID == GlobalClass.SucursalID && c.Estatus); ContaProc.CrearPoliza(Cat.ContaTiposDePoliza.Diario, "RESERVA NÓMINA", Cat.ContaCuentasAuxiliares.ReservaNomina, Cat.ContaCuentasAuxiliares.Resguardo , mReserva, oSucursal.NombreSucursal, Cat.Tablas.CajaFacturaGlobal, oFacturaGlobal.CajaFacturaGlobalID); // Se crea una póliza nueva cargando a Caja y la otra cuenta en cero, para equilibrar caja (caso raro), sólo si la reserva fue mayor a cero if (mReserva > 0) { var oPoliza = ContaProc.CrearPoliza(Cat.ContaTiposDePoliza.Diario, "RESERVA NÓMINA AJUSTE", Cat.ContaCuentasAuxiliares.Caja , Cat.ContaCuentasAuxiliares.CapitalFijo, mReserva, "RN AJUSTE", null, null); var oPolizaDet = Datos.GetEntity<ContaPolizaDetalle>(c => c.ContaPolizaID == oPoliza.ContaPolizaID && c.ContaCuentaAuxiliarID == Cat.ContaCuentasAuxiliares.CapitalFijo); oPolizaDet.Abono = 0; Datos.Guardar<ContaPolizaDetalle>(oPolizaDet); } } } return true; }