diff --git a/App_Code/ClsOP.vb b/App_Code/ClsOP.vb index 8688a3969..eb34c60ee 100644 --- a/App_Code/ClsOP.vb +++ b/App_Code/ClsOP.vb @@ -408,6 +408,33 @@ Public Class ClsOP #Region "O R D E N E S D E P R O D U C C I O N" + + Public Function OPAdd(Descripcion As String, CveCliente As Integer, CveEmpresa As Integer, CveUsuario As Integer, Fecha As Date, CveSubProyecto As Integer, xmlproductos As String, ByRef CveOP As Integer, ByRef Folio As Integer) As Boolean + Dim Retorno As Boolean = False + DataAdapter("PA_OP_OrdendeProduccionAdd") + With SqlAdapter.SelectCommand.Parameters + .Add("@Descripcion", SqlDbType.VarChar).Value = Descripcion + .Add("@CveCliente", SqlDbType.Int).Value = CveCliente + .Add("@CveEmpresa", SqlDbType.Int).Value = CveEmpresa + .Add("@CveUsuario", SqlDbType.Int).Value = CveUsuario + .Add("@Fecha", SqlDbType.Date).Value = Fecha + .Add("@CveSubProyecto", SqlDbType.Int).Value = CveSubProyecto + .Add("@xmlproductos", SqlDbType.Xml).Value = xmlproductos + .Add("@CveOP", SqlDbType.Int).Direction = ParameterDirection.Output + .Add("@Folio", SqlDbType.Int).Value = ParameterDirection.Output + End With + Try + SqlAdapter.Fill(Data) + CveOP = CInt(SqlAdapter.SelectCommand.Parameters("@CveOP").Value) + Folio = CInt(SqlAdapter.SelectCommand.Parameters("@Folio").Value) + Retorno = True + Catch ex As Exception + OnError("Ocurrió un error al agregar la Orden de Produccion.", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo()) + Retorno = False + End Try + Return Retorno + End Function + Public Function GetReportesOP(CveOP As Integer, CveCliente As Integer, CveSubProyecto As Integer, CvePS As Integer, CveEstatus As Integer, Asignado As Integer, FechaI As Date, FechaF As Date, CveEmpresa As Integer) As Boolean Dim Retorno As Boolean = False DataAdapter("PA_OP_OrdendeProduccionGet") @@ -474,6 +501,27 @@ Public Class ClsOP Return Retorno End Function + Public Function UpdateEstatusOP(CveOP As Integer, CveEstatusOP As Integer, CveEmpresa As Integer) As Boolean + Dim Retorno As Boolean = False + DataAdapter("PA_OP_OrdendeProduccionEstatusUp") + + With SqlAdapter.SelectCommand.Parameters + .Add("@CveOP", SqlDbType.Int).Value = CveOP + .Add("@CveEstatusOP", SqlDbType.Int).Value = CveEstatusOP + .Add("@CveEmpresa", SqlDbType.Int).Value = CveEmpresa + End With + + Try + SqlAdapter.Fill(Data) + Retorno = True ' Éxito si no hay excepciones + Catch ex As Exception + OnError("Error al actualizar estatus de la OP", ex, SqlAdapter.SelectCommand.Parameters.ParametrosInfo) + Retorno = False + End Try + + Return Retorno + End Function + Public Function UpdateOP(CveOP As Integer, Descripcion As String, CveCliente As Integer, CvePS As Integer, CveSubProyecto As Integer, Cantidad As Integer, Fecha As Date, CveEmpresa As Integer, CveUsuario As Integer) As Boolean Dim Retorno As Boolean = False DataAdapter("PA_OP_OrdendeProduccionUp") diff --git a/Inventarios/TrasladoSolicitud.aspx.vb b/Inventarios/TrasladoSolicitud.aspx.vb index 53d05aefa..7b5ff9426 100644 --- a/Inventarios/TrasladoSolicitud.aspx.vb +++ b/Inventarios/TrasladoSolicitud.aspx.vb @@ -335,7 +335,7 @@ Partial Class Inventarios_TrasladoSolicitud Dim CodigoPS As String = "" For Each row As GridViewRow In GvDatos.Rows - Existencia = ObjInventarios.GetExistenciasPS(row.DataKey("CvePS").ToEntero, row.DataKey("CveUM").ToEntero, UsuarioActual.CveEmpresa, DdlAlmacenOrigen.SelectedValue.ToEntero, FechaMovto:=NowADS.ToString("yyyy/MM/dd 23:59"), Lote:=row.DataKey("Lote").ToString, FechaCaducidad:=row.DataKey("FechaCaducidad").ToString.ToDate) + Existencia = ObjInventarios.GetExistenciasPS(row.DataKey("CvePS").ToEntero, row.DataKey("CveUM").ToEntero, UsuarioActual.CveEmpresa, DdlAlmacenOrigen.SelectedValue.ToEntero, FechaMovto:=NowADS.ToString("yyyy/MM/dd 23:59"), FechaCaducidad:=row.DataKey("FechaCaducidad").ToString.ToDate) If Existencia - TempDT.SUM("Cantidad", $"CvePS = {row.DataKey("CvePS").ToEntero} AND CveUM = {row.DataKey("CveUM").ToEntero}") < 0 Then CodigoPS = GlobalDTPSSimplificado(UsuarioActual.CveEmpresa, CvePS:=row.DataKey("CvePS").ToEntero).FiltroPrimeroValor("PSCodigo", "") MensajeExistencia.AppendFormat("
- {0}. Existencia: {1}", CodigoPS, Existencia) diff --git a/OP/OP.aspx b/OP/OP.aspx index f42a51846..7ca37ef2a 100644 --- a/OP/OP.aspx +++ b/OP/OP.aspx @@ -1,9 +1,227 @@ -<%@ Page Title="" Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="OP.aspx.vb" Inherits="OP_OP" %> +<%@ Import Namespace="Extensiones" %> + +<%@ Page Title="" Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="OP.aspx.vb" Inherits="OP_OP" %> + @@ -81,109 +293,177 @@ - + +
+ + +
+
+
+
+ Orden de producción # +
+
+
+
+
+
+
+ + +
+
+
+ + +
+
+
+
+
+ + + +
+ +
+ + + +
+ +
+
+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+
+ +
+
+
+ + + + +
+ + + + + + +
+
+
+
+
+
+
+
+ +
+
+
+
+ Estatus +
+ +
+
+ + +
+
+
+ +
+
+
+ + + -
- -
-

Orden de producción #

-
- - - -
-
-
-
- - -
-
- - -
- -
- - Proyecto: - -
- +
+
+
+
+
+ Productos +
- - Subproyecto: - -
- +
+
+ +
+ +
+
+ + + + + + + + + +
+
-
-
- - -
- - - -
- - -
-
- -
-
-
- - - - -
- - - - - - -
-
- - -
- -
- -
- - -
- - - -
-
+
Productos
@@ -191,60 +471,347 @@ + + + + +
-
-
-
Materia prima
- - - - - - - - +
+
+
+ + +
+
+
+
+
+ Materia Prima +
+
+ + Solicitar MP +
-
+
+ +
Materia prima
+ + + + + + + + +
+
+
+
+ + +
+
+
+
+
+ Mano de Obra +
+
+ + +
Mano de obra
- +
- -
-
-
Costo indirecto
- - - - - - +
+
+
+
+
+
+ Costo Indirecto
- - - - -
- +
+
Costo indirecto
+ + + + + + +
+
+ + + + + + + +
+ +
+ +
+
+ +
+
+ + + + diff --git a/OP/OP.aspx.vb b/OP/OP.aspx.vb index 912e1f845..4e48eecba 100644 --- a/OP/OP.aspx.vb +++ b/OP/OP.aspx.vb @@ -5,6 +5,9 @@ Imports System.IO Imports Extensiones Imports Microsoft.Reporting.WebForms Imports Org.BouncyCastle.Asn1.Utilities +Imports Profact.TimbraCFDI.Complementos.Ecc.Ecc11 +Imports System.Xml +Imports System.Data.SqlClient Partial Class OP_OP Inherits ClsPaginas @@ -54,6 +57,23 @@ Partial Class OP_OP End Set End Property + Private Property DtMPAgregados As DataTable + Get + If ViewState("DtMPAgregados") Is Nothing Then + DtMPAgregados = New DataTable() + DtMPAgregados.Columns.Add("Clave", GetType(Integer)) + DtMPAgregados.Columns.Add("PSCodigo", GetType(String)) + DtMPAgregados.Columns.Add("CveUM", GetType(Integer)) + DtMPAgregados.Columns.Add("UnidadMedida", GetType(String)) + DtMPAgregados.Columns.Add("Cantidad", GetType(Decimal)) + End If + Return CType(ViewState("DtMPAgregados"), DataTable) + End Get + Set(value As DataTable) + ViewState("DtMPAgregados") = value + End Set + End Property + #End Region @@ -72,27 +92,37 @@ Partial Class OP_OP DtPS.Columns.Add("PSCodigo", GetType(String)) DtPS.Columns.Add("UnidadMedida", GetType(String)) DtPS.Columns.Add("Cantidad", GetType(Decimal)) + DtPS.Columns.Add("CveUM", GetType(Integer)) DtPS.Columns.Add("Surtido", GetType(Decimal)) DtPS.Columns.Add("Costo", GetType(Decimal)) DtMP = New DataTable() DtMP.Columns.Add("Tipo", GetType(String)) ' Producto, MP, MO, CI DtMP.Columns.Add("Clave", GetType(Integer)) - DtMP.Columns.Add("Producto", GetType(String)) + DtMP.Columns.Add("CvePSMateriaPrima", GetType(Integer)) + DtMP.Columns.Add("CveUM", GetType(Integer)) + DtMP.Columns.Add("CveUMMateriaPrima", GetType(Integer)) + DtMP.Columns.Add("PSCodigo", GetType(String)) DtMP.Columns.Add("UnidadMedida", GetType(String)) DtMP.Columns.Add("Cantidad", GetType(Decimal)) DtMP.Columns.Add("Surtido", GetType(Decimal)) + 'DtMP.Columns.Add("CveAlmacenDestino", GetType(Integer)) DtMO = New DataTable() DtMO.Columns.Add("Tipo", GetType(String)) ' Producto, MP, MO, CI DtMO.Columns.Add("Clave", GetType(Integer)) + DtMO.Columns.Add("CveUM", GetType(Integer)) + DtMO.Columns.Add("CvePuesto", GetType(Integer)) DtMO.Columns.Add("Puesto", GetType(String)) DtMO.Columns.Add("Cantidad", GetType(Decimal)) DtCI = New DataTable() DtCI.Columns.Add("Tipo", GetType(String)) ' Producto, MP, MO, CI DtCI.Columns.Add("Clave", GetType(Integer)) - DtCI.Columns.Add("Producto", GetType(String)) + 'DtCI.Columns.Add("CveUM", GetType(Integer)) + 'DtCI.Columns.Add("CvePSMateriaPrima", GetType(Integer)) + 'DtCI.Columns.Add("CveUMMateriaPrima", GetType(Integer)) + DtCI.Columns.Add("productoMateriaPrima", GetType(String)) DtCI.Columns.Add("Cantidad", GetType(Decimal)) @@ -105,17 +135,20 @@ Partial Class OP_OP CargarProductos() If CveOP = -1 Then - ' Modo registro: mostrar dropdowns y ocultar los TextBox + DdlClientes.Enabled = True DdlProyecto.Enabled = True DdlSubProyecto.Enabled = True DdlPS.Enabled = True - + LnkSolicitarMP.Visible = False + BtnSimularMP.Visible = True + BtnFinalizarOP.Visible = False Else DdlClientes.Enabled = False - DdlProyecto.Enabled = False - DdlSubProyecto.Enabled = False DdlPS.Enabled = False + LnkSolicitarMP.Visible = False + BtnSimularMP.Visible = False + BtnFinalizarOP.Visible = True CargaDatos() End If End Sub @@ -127,18 +160,76 @@ Partial Class OP_OP Dim DTOP As DataTable = ObjOP.DtResultados If DTOP.Rows.Count > 0 Then Dim dr As DataRow = DTOP.Rows(0) - LblCveOP.Text = CveOP.ToString + LblFolio.Text = dr("Folio").ToString DdlClientes.txtText.Value = dr("Cliente").ToString DdlClientes.txtValue.Value = dr("CveCliente").ToString TxtEstatus.Text = dr("Estatus").ToString - DdlSubProyecto.SelectedValue = dr("CveSubProyecto").ToString + DdlSubProyecto.SelectedValueExist(dr("CveSubProyecto").ToString) DdlPS.txtText.Value = dr("Producto").ToString DdlPS.txtValue.Value = dr("CvePS").ToString Txtfecha.Text = dr("Fecha").ToString TxtDescripcion.Text = dr("Descripcion").ToString + + + If ObjOP.GetProductosOP(CveOP, UsuarioActual.CveEmpresa) Then + DtPS.Rows.Clear() + For Each rowProducto As DataRow In ObjOP.DtResultados.Rows + Dim newRow As DataRow = DtPS.NewRow() + newRow("Tipo") = "Producto" + newRow("Clave") = rowProducto("CvePS").ToString.ToEntero + newRow("PSCodigo") = rowProducto("Producto").ToString + + newRow("UnidadMedida") = rowProducto("UnidadMedida").ToString + newRow("Cantidad") = rowProducto("Cantidad").ToString.ToDecimal + newRow("CveUM") = rowProducto("CveUM").ToString.ToEntero + DtPS.Rows.Add(newRow) + Next + End If + + If ObjOP.GetProductosMP(CveOP, UsuarioActual.CveEmpresa) Then + DtMP.Rows.Clear() + For Each rowMP As DataRow In ObjOP.DtResultados.Rows + Dim newRow As DataRow = DtMP.NewRow() + newRow("Tipo") = "MP" + newRow("Clave") = rowMP("CvePS").ToString.ToEntero + newRow("PSCodigo") = rowMP("Producto").ToString + newRow("CvePSMateriaPrima") = rowMP("CvePS").ToString.ToEntero + newRow("CveUMMateriaPrima") = rowMP("CveUM").ToString.ToEntero + newRow("UnidadMedida") = rowMP("UnidadMedida").ToString + newRow("Cantidad") = rowMP("Cantidad").ToString.ToDecimal + newRow("Surtido") = rowMP("Surtido").ToString.ToDecimal() + DtMP.Rows.Add(newRow) + Next + End If + + '----- Cargar Mano de Obra ----- + If ObjOP.GetProductosMO(CveOP, UsuarioActual.CveEmpresa) Then + DtMO.Rows.Clear() + For Each rowMO As DataRow In ObjOP.DtResultados.Rows + Dim newRow As DataRow = DtMO.NewRow() + newRow("Tipo") = "MO" + newRow("Puesto") = rowMO("Puesto").ToString + newRow("Cantidad") = rowMO("Cantidad").ToString.ToDecimal + DtMO.Rows.Add(newRow) + Next + End If + + '----- Cargar Costos Indirectos ----- + If ObjOP.GetProductosCI(CveOP, UsuarioActual.CveEmpresa) Then + DtCI.Rows.Clear() + For Each rowCI As DataRow In ObjOP.DtResultados.Rows + Dim newRow As DataRow = DtCI.NewRow() + newRow("Tipo") = "CI" + newRow("productoMateriaPrima") = rowCI("producto").ToString + newRow("Cantidad") = rowCI("Cantidad").ToString.ToDecimal + DtCI.Rows.Add(newRow) + + Next + End If End If End If ObjOP.Dispose() + ActualizarGrids() End If End Sub @@ -180,10 +271,11 @@ Partial Class OP_OP newRow("PSCodigo") = DrPS("PSCodigo") newRow("UnidadMedida") = DrPS("UnidadMedida") newRow("Cantidad") = 1 + newRow("CveUM") = DrPS("CveUnidadMedida").ToString.ToEntero newRow("Surtido") = 0 newRow("Costo") = 0 DtPS.Rows.Add(newRow) - 'consultas GetMPReceta, GetMOReceta, GetCIReceta + Dim CveUM As Integer = DrPS("CveUnidadMedida").ToString.ToEntero @@ -194,7 +286,10 @@ Partial Class OP_OP Dim rowMP As DataRow = DtMP.NewRow() rowMP("Tipo") = "MP" rowMP("Clave") = CvePS - rowMP("Producto") = drMP("productoMateriaPrima").ToString() + rowMP("CvePSMateriaPrima") = CvePS + rowMP("CveUM") = CveUM + rowMP("CveUMMateriaPrima") = CveUM 'drMP("CveUMMateriaPrima").ToString().ToEntero() + rowMP("PSCodigo") = drMP("productoMateriaPrima").ToString() rowMP("UnidadMedida") = drMP("UnidadMedidaMateriaPrima").ToString() rowMP("Cantidad") = drMP("Cantidad").ToString().ToDecimal() rowMP("Surtido") = 0 @@ -218,11 +313,13 @@ Partial Class OP_OP Dim ObjCI As New ClsOP() If ObjCI.GetCIReceta(CvePS, CveUM, UsuarioActual.CveEmpresa) Then + For Each drCI As DataRow In ObjCI.DtResultados.Rows Dim rowCI As DataRow = DtCI.NewRow() rowCI("Tipo") = "CI" rowCI("Clave") = CvePS - rowCI("Producto") = drCI("productoMateriaPrima").ToString() + 'rowCI("CvePSMateriaPrima") = drCI("CvePSMateriaPrima").ToString().ToEntero() + rowCI("productoMateriaPrima") = drCI("productoMateriaPrima").ToString() rowCI("Cantidad") = drCI("Cantidad").ToString().ToDecimal() DtCI.Rows.Add(rowCI) Next @@ -232,42 +329,332 @@ Partial Class OP_OP End Sub Protected Sub BtnEliminarProducto_Click(sender As Object, e As EventArgs) - If DdlPS.SelectedValue = "-1" Then - Alert("Seleccione un producto del listado.", TipoMensaje.MsgAdvertencia) - Return - End If - - Dim CveProducto As Integer = DdlPS.SelectedValue.ToEntero() + Dim btnEliminar As LinkButton = DirectCast(sender, LinkButton) + Dim CveProducto As Integer = btnEliminar.CommandArgument.ToEntero() Dim filasProducto As DataRow() = DtPS.Select($"Clave = {CveProducto}") If filasProducto.Length > 0 Then DtPS.Rows.Remove(filasProducto(0)) + EliminarDatosRelacionados(CveProducto) + ActualizarGrids() End If - - EliminarDatosRelacionados(CveProducto) - - ActualizarGrids() End Sub Private Sub EliminarDatosRelacionados(CveProducto As Integer) + + ' Materia Prima Dim filasMP As DataRow() = DtMP.Select($"Clave = {CveProducto}") For Each fila As DataRow In filasMP DtMP.Rows.Remove(fila) Next + ' Mano de Obra Dim filasMO As DataRow() = DtMO.Select($"Clave = {CveProducto}") For Each fila As DataRow In filasMO DtMO.Rows.Remove(fila) Next + ' Costos Indirectos Dim filasCI As DataRow() = DtCI.Select($"Clave = {CveProducto}") For Each fila As DataRow In filasCI DtCI.Rows.Remove(fila) Next End Sub + Protected Sub LnkSolicitarMP_Click(sender As Object, e As EventArgs) + ' Cargar almacenes + DdlAlmacenOrigenMP.DataSource = GlobalDTAlmacen(UsuarioActual.CveEmpresa).FiltraParametros("CveTipoAlmacen = 1") + DdlAlmacenOrigenMP.DataBind() + DdlAlmacenDestinoMP.DataSource = GlobalDTAlmacen(UsuarioActual.CveEmpresa).FiltraParametros("CveTipoAlmacen = 28") + DdlAlmacenDestinoMP.DataBind() + + GvMPAgregados.DataKeyNames = New String() {"CvePSMateriaPrima", "CveUMMateriaPrima"} + + ' Filtrar MP no surtida + Dim DtMPFaltante As DataTable = DtMP.FiltraParametros("Surtido = 0").Copy() + GvMPAgregados.DataSource = DtMPFaltante + GvMPAgregados.DataBind() + + + ' Mostrar modal + RegistraScript("$('#DVModalSolicitarMP').modal('show');") + UpModalMP.Update() + End Sub + + Protected Sub BtnSimularMP_Click(sender As Object, e As EventArgs) + If CveOP <> -1 Then Exit Sub + If DdlPS.SelectedValue = "-1" Then Exit Sub + + Dim nombreProducto As String = DdlPS.txtText.Value ' Ajusta según tu control + Dim spanNombre As HtmlGenericControl = DirectCast(UpModalSimular.FindControl("SpanNombreProducto"), HtmlGenericControl) + spanNombre.InnerText = nombreProducto + + GvSimulacionMP.DataSource = Nothing + GvSimulacionMP.DataBind() + LblCantidadPosibleGlobal.Visible = False + + ' Cargar almacenes (sin borrar el ítem inicial) + DdlAlmacenSimular.DataSource = GlobalDTAlmacen(UsuarioActual.CveEmpresa).FiltraParametros("CveTipoAlmacen = 1") + DdlAlmacenSimular.DataTextField = "Almacen" ' Nombre de la columna para mostrar + DdlAlmacenSimular.DataValueField = "CveAlmacen" ' Columna para el valor + DdlAlmacenSimular.DataBind() + + CalcularSimulacion() + + RegistraScript("$('#DVModalSimularMP').modal('show');") + UpModalSimular.Update() + End Sub + + Protected Sub RblModoSimulacion_SelectedIndexChanged(sender As Object, e As EventArgs) + ' Controlar visibilidad del TextBox + PnlCantidad.Visible = (RblModoSimulacion.SelectedValue = "1") + + ' Resetear valor si cambian de modo + If RblModoSimulacion.SelectedValue = "2" Then + TxtCantidadSimular.Text = "1" + End If + + UpModalSimular.Update() + CalcularSimulacion() + End Sub + + Protected Sub DdlAlmacenSimular_SelectedIndexChanged(sender As Object, e As EventArgs) + If DdlAlmacenSimular.SelectedValue = "-1" Then + Alert("Por favor selecciona un almacén.", TipoMensaje.MsgAdvertencia) + Exit Sub + End If + CalcularSimulacion() + End Sub + + Protected Sub TxtCantidadSimular_TextChanged(sender As Object, e As EventArgs) + CalcularSimulacion() + UpModalSimular.Update() + End Sub + + Private Sub CalcularSimulacion() + If DdlAlmacenSimular.SelectedValue = "-1" Then Exit Sub + If DdlPS.SelectedValue = "-1" Then Exit Sub + + Dim CvePS As Integer = DdlPS.SelectedValue.ToEntero() + Dim DtMP As DataTable = ObtenerMPRequerida(CvePS) + AgregarColumnasSimulacion(DtMP) + Dim listaCantidadesPosibles As New List(Of Decimal) + Dim MinCantidadPosible As Decimal = 0D + + For Each rowMP As DataRow In DtMP.Rows + Dim CveMP As Integer = rowMP("CvePSMateriaPrima").ToString.ToEntero() + Dim CveUMMP As Integer = rowMP("CveUMMateriaPrima").ToString.ToEntero() + Dim CveAlmacen As Integer = DdlAlmacenSimular.SelectedValue.ToEntero() + + Dim Existencia As Decimal = 0 + Using ObjInventario As New ClsInventarios() + Existencia = ObjInventario. + GetExistenciasPS( + CvePS:=CveMP, + CveUnidadMedida:=CveUMMP, + CveEmpresa:=UsuarioActual.CveEmpresa, + CveAlmacen:=CveAlmacen + ) + End Using + + rowMP("Disponible") = Existencia + Dim CantidadUnitaria As Decimal = rowMP("Cantidad").ToString.ToDecimal() + rowMP("CantidadUnitaria") = CantidadUnitaria ' Fija (no se modifica) + + If RblModoSimulacion.SelectedValue = "1" Then + Dim CantidadProducto As Decimal = TxtCantidadSimular.Text.ToDecimal() + If RblModoSimulacion.SelectedValue = "1" AndAlso TxtCantidadSimular.Text.Trim() = "" Then + Alert("Ingresa la cantidad a simular", TipoMensaje.MsgAdvertencia) + Return + End If + Dim TotalRequerido As Decimal = CantidadUnitaria * CantidadProducto + rowMP("TotalRequerido") = TotalRequerido + rowMP("Faltante") = Math.Max(TotalRequerido - Existencia, 0D) + + Else + If CantidadUnitaria > 0 Then + Dim CantidadProducible As Decimal = Math.Floor(Existencia / CantidadUnitaria) + rowMP("CantidadPosible") = CantidadProducible ' ✔️ Valor individual por material + listaCantidadesPosibles.Add(CantidadProducible) + Else + rowMP("CantidadPosible") = 0D + End If + End If + Next + + If RblModoSimulacion.SelectedValue = "2" AndAlso listaCantidadesPosibles.Count > 0 Then + MinCantidadPosible = listaCantidadesPosibles.Min() + Else + MinCantidadPosible = 0D + End If + + GvSimulacionMP.Columns(3).Visible = (RblModoSimulacion.SelectedValue = "1") ' Total Requerido (Índice 3) + GvSimulacionMP.Columns(4).Visible = (RblModoSimulacion.SelectedValue = "1") ' Faltante (Índice 4) + GvSimulacionMP.Columns(5).Visible = (RblModoSimulacion.SelectedValue = "2") ' CantidadPosible (Índice 5) + + ' Asegurar visibilidad de columnas fijas + GvSimulacionMP.Columns(0).Visible = True + GvSimulacionMP.Columns(1).Visible = True + GvSimulacionMP.Columns(2).Visible = True + + GvSimulacionMP.DataSource = DtMP + GvSimulacionMP.DataBind() + LblCantidadPosibleGlobal.Text = $"Cantidad: {MinCantidadPosible:N0}" + LblCantidadPosibleGlobal.Visible = (RblModoSimulacion.SelectedValue = "2") + End Sub + + Private Sub AgregarColumnasSimulacion(ByRef dt As DataTable) + If Not dt.Columns.Contains("CantidadUnitaria") Then + dt.Columns.Add("CantidadUnitaria", GetType(Decimal)).DefaultValue = 0D + End If + + If Not dt.Columns.Contains("TotalRequerido") Then + dt.Columns.Add("TotalRequerido", GetType(Decimal)).DefaultValue = 0D + End If + + If Not dt.Columns.Contains("Disponible") Then + dt.Columns.Add("Disponible", GetType(Decimal)).DefaultValue = 0D + End If + If Not dt.Columns.Contains("Faltante") Then + dt.Columns.Add("Faltante", GetType(Decimal)).DefaultValue = 0D + End If + If Not dt.Columns.Contains("CantidadPosible") Then + dt.Columns.Add("CantidadPosible", GetType(Decimal)).DefaultValue = 0D + End If + End Sub + + Private Function ObtenerMPRequerida(CvePS As Integer) As DataTable + Dim ObjOP As New ClsOP() + ObjOP.GetMPReceta(CvePS, -1, UsuarioActual.CveEmpresa) + + ' Verificar y convertir CvePSMateriaPrima a Integer + For Each row As DataRow In ObjOP.DtResultados.Rows + If Not IsDBNull(row("CvePSMateriaPrima")) Then + row("CvePSMateriaPrima") = Convert.ToInt32(row("CvePSMateriaPrima")) + Else + row("CvePSMateriaPrima") = 0 ' Valor por defecto si es nulo + End If + Next + + Return ObjOP.DtResultados.Copy() + End Function + + Protected Sub BtnGuardarSolicitudMP_Click(sender As Object, e As EventArgs) + + Dim CveTraspasoSolicitud As Integer = -1 + + If DdlAlmacenOrigenMP.SelectedValue = DdlAlmacenDestinoMP.SelectedValue Then + Alert("Los almacenes de origen y destino no pueden ser el mismo. Por favor rectifique y vuelva a intentar.", TipoMensaje.MsgAdvertencia) + Exit Sub + End If + + If Not GvMPAgregados.Rows.Count > 0 Then + Alert("No se ha seleccionado ningún producto para trasladar.", TipoMensaje.MsgAdvertencia) + Exit Sub + End If + + Dim EstatusAlmacen As Integer = 2 + Dim Estatus As Integer = If(UsuarioActual.Empresa.Funcionalidad(105) <> "", 1, 3) + Dim ObjInventario As New ClsInventarios() + Dim TieneErrorExistencia As Boolean = False + Dim MensajeExistencia As New StringBuilder + MensajeExistencia.Append("No hay la existencia suficiente de los siguientes productos:
") + + '✅ 1. Validar existencias de MP + For Each row As GridViewRow In GvMPAgregados.Rows + '✅ Obtener claves CORRECTAS de la materia prima + Dim CveMP As Integer = GvMPAgregados.DataKeys(row.RowIndex)("CvePSMateriaPrima").ToString().ToEntero() + Dim CveUMMP As Integer = GvMPAgregados.DataKeys(row.RowIndex)("CveUMMateriaPrima").ToString().ToEntero() + Dim CantidadSolicitada As Decimal = DtMP.Rows(row.RowIndex)("Cantidad").ToString().ToDecimal() + + 'DtMP.Rows(row.RowIndex)("CveAlmacenDestino") = DdlAlmacenDestinoMP.SelectedValue.ToEntero() + + '✅ Verificar existencias + Dim Existencia As Decimal = ObjInventario.GetExistenciasPS( + CvePS:=CveMP, + CveUnidadMedida:=CveUMMP, + CveEmpresa:=UsuarioActual.CveEmpresa, + CveAlmacen:=DdlAlmacenOrigenMP.SelectedValue.ToEntero() + ) + + If Existencia < CantidadSolicitada Then + Dim NombreProducto As String = GlobalDTPSSimplificado(UsuarioActual.CveEmpresa, CveMP).FiltroPrimeroValor("Producto", "") + Dim Faltante As Decimal = CantidadSolicitada - Existencia + MensajeExistencia.AppendFormat( + "
- {0} ({1}) Existencia: {2}, Faltante: {3}", + NombreProducto, + row.Cells(0).Text, ' Código del producto + Existencia.ToString("N2"), + Faltante.ToString("N2") + ) + TieneErrorExistencia = True + End If + Next + + If TieneErrorExistencia Then + Alert(MensajeExistencia.ToString, TipoMensaje.MsgAdvertencia) + Exit Sub + End If + + '✅ 2. Crear traspaso si todo está correcto + ObjInventario.IniciaTransacSQL() + Dim TieneError As Boolean = False + + Dim FolioSolicitud As Integer = ObjInventario.AddTrasladoSolicitud( + TxtObservacionesMP.Text.Trim(), + DdlAlmacenOrigenMP.SelectedValue.ToEntero(), + DdlAlmacenDestinoMP.SelectedValue.ToEntero(), + Estatus, + -1, + NowADS, + CveUsuario:=UsuarioActual.CveUsuario, + CveEmpresa:=UsuarioActual.CveEmpresa, + EstatusAlmacen:=EstatusAlmacen + ) + + If FolioSolicitud > 0 Then + CveTraspasoSolicitud = ObjInventario.CveTraspasoSolicitud + Else + TieneError = True + End If + + '✅ 3. Agregar detalles del traspaso + If Not TieneError Then + For Each row As GridViewRow In GvMPAgregados.Rows + '✅ Usar claves de MATERIA PRIMA (CvePSMateriaPrima y CveUMMateriaPrima) + Dim CveMP As Integer = GvMPAgregados.DataKeys(row.RowIndex)("CvePSMateriaPrima").ToString().ToEntero() + Dim CveUMMP As Integer = GvMPAgregados.DataKeys(row.RowIndex)("CveUMMateriaPrima").ToString().ToEntero() + Dim Cantidad As Decimal = DtMP.Rows(row.RowIndex)("Cantidad").ToString().ToDecimal() + + If Not ObjInventario.AddTrasladoSolicitudDetalle( + CveTraspasoSolicitud, + Cantidad, + CveUMMP, '✅ Unidad de medida de la MP + CveMP, '✅ Clave de la MP + 0, "", -1, "-1", "-1", MinFecha + ) Then + TieneError = True + Exit For + End If + Next + End If + + '✅ 4. Confirmar o cancelar transacción + If Not TieneError Then + ObjInventario.Commit() + Alert($"Solicitud de Traspaso guardada. Folio: {FolioSolicitud}", TipoMensaje.MsgInformacion) + RegistraScript("$('#DVModalSolicitarMP').modal('hide');") + CargaDatos() + Else + ObjInventario.RollBack() + Alert("Error al guardar el traspaso.", TipoMensaje.MsgError) + End If + ObjInventario.Dispose() + + End Sub + Protected Sub BtnGuardarOP_Click(sender As Object, e As EventArgs) - ' Validar campos obligatorios + ' Validaciones básicas If DdlClientes.SelectedValue = "-1" Then Alert("Seleccione un cliente.", TipoMensaje.MsgAdvertencia) Return @@ -278,94 +665,86 @@ Partial Class OP_OP Return End If - ' Iniciar transacción Dim clsOP As New ClsOP() clsOP.IniciaTransacSQL() + Dim transactionActive As Boolean = False Try - ' Insertar/Actualizar cabecera de la OP usando UpdateOP - Dim CveOP As Integer = Me.CveOP ' Si es nuevo, CveOP = -1 - Dim Success As Boolean = clsOP.UpdateOP( - CveOP:=CveOP, - Descripcion:=TxtDescripcion.Text, - CveCliente:=DdlClientes.SelectedValue.ToEntero(), - CvePS:=DdlPS.SelectedValue.ToEntero(), - CveSubProyecto:=DdlSubProyecto.SelectedValue.ToEntero(), - Cantidad:=1, ' Ajustar según lógica de negocio - Fecha:=Convert.ToDateTime(Txtfecha.Text), - CveEmpresa:=UsuarioActual.CveEmpresa, - CveUsuario:=UsuarioActual.CveUsuario - ) - If Not Success Then - Throw New Exception("Error al guardar la cabecera de la OP.") - End If - ' Obtener el CveOP generado (asumiendo que se actualiza en la propiedad) - If Me.CveOP = -1 Then - ' Si es nuevo, recuperar el CveOP de la base de datos - ' (Requiere que el SP PA_OP_OrdendeProduccionUp devuelva el ID) - ' Esto depende de la implementación del SP. - ' Ejemplo hipotético: - clsOP.GetOP(-1, DdlClientes.SelectedValue.ToEntero(), DdlSubProyecto.SelectedValue.ToEntero(), -1, -1, -1, MinFecha, MaxFecha, UsuarioActual.CveEmpresa) - If clsOP.DtResultados.Rows.Count > 0 Then - Me.CveOP = clsOP.DtResultados.Rows(0)("CveOP").ToString.ToEntero() + + If Me.CveOP = -1 Then ' Modo CREACIÓN + + Dim xmlProductos As String = DataTableToXML(DtPS) + Dim CveOPGenerado As Integer = -1 + Dim FolioGenerado As Integer = -1 + + If clsOP.OPAdd( + Descripcion:=TxtDescripcion.Text, + CveCliente:=DdlClientes.SelectedValue.ToEntero(), + CveEmpresa:=UsuarioActual.CveEmpresa, + CveUsuario:=UsuarioActual.CveUsuario, + Fecha:=Convert.ToDateTime(Txtfecha.Text), + CveSubProyecto:=DdlSubProyecto.SelectedValue.ToEntero(), + xmlproductos:=xmlProductos, + CveOP:=CveOPGenerado, + Folio:=FolioGenerado + ) Then + Me.CveOP = CveOPGenerado + LblFolio.Text = FolioGenerado.ToString + Alert("Orden creada con Folio: " & FolioGenerado, TipoMensaje.MsgInformacion) + End If + Else ' Modo EDICIÓN + Dim CvePS As Integer = DtPS.Rows(0)("Clave").ToString.ToEntero() + Dim Cantidad As Integer = DtPS.Rows(0)("Cantidad").ToString.ToEntero() + BtnFinalizarOP.Visible = True + If Not clsOP.UpdateOP( + CveOP:=Me.CveOP, + Descripcion:=TxtDescripcion.Text, + CveCliente:=DdlClientes.SelectedValue.ToEntero(), + CvePS:=CvePS, + CveSubProyecto:=DdlSubProyecto.SelectedValue.ToEntero(), + Cantidad:=Cantidad, + Fecha:=Convert.ToDateTime(Txtfecha.Text), + CveEmpresa:=UsuarioActual.CveEmpresa, + CveUsuario:=UsuarioActual.CveUsuario + ) Then + Throw New Exception("Error al actualizar la OP") End If End If - ' Insertar detalles de Productos, MP, MO, CI - For Each drProducto As DataRow In DtPS.Rows - Dim CvePS As Integer = drProducto("Clave").ToString().ToEntero() - - ' Insertar Materia Prima relacionada - For Each drMP As DataRow In DtMP.Select($"Clave = {CvePS}") - clsOP.AddMP( - Cantidad:=drMP("Cantidad").ToString().ToDecimal(), - CvePS:=CvePS, - CvePSMateriaPrima:=drMP("CvePSMateriaPrima").ToString().ToEntero(), - CveUM:=drMP("CveUM").ToString().ToEntero(), - CveUMMateriaPrima:=drMP("CveUMMateriaPrima").ToString().ToEntero() - ) - Next - - ' Insertar Mano de Obra relacionada - For Each drMO As DataRow In DtMO.Select($"Clave = {CvePS}") - clsOP.AddMO( - Cantidad:=drMO("Cantidad").ToString().ToDecimal(), - CvePS:=CvePS, - CvePuesto:=drMO("CvePuesto").ToString().ToEntero(), - CveUM:=drMO("CveUM").ToString().ToEntero() - ) - Next - - ' Insertar Costos Indirectos relacionados - For Each drCI As DataRow In DtCI.Select($"Clave = {CvePS}") - clsOP.AddCI( - Cantidad:=drCI("Cantidad").ToString().ToDecimal(), - CvePS:=CvePS, - CvePSMateriaPrima:=drCI("CvePSMateriaPrima").ToString().ToEntero(), - CveUM:=drCI("CveUM").ToString().ToEntero(), - CveUMMateriaPrima:=drCI("CveUMMateriaPrima").ToString().ToEntero() - ) - Next - Next - - ' Commit si todo es exitoso clsOP.Commit() - Alert("Orden de Producción guardada correctamente.", TipoMensaje.MsgInformacion) - Response.Redirect($"OP.aspx?CveOP={Me.CveOP}") ' Redirigir a la OP guardada + transactionActive = False + + + Response.Redirect($"OP.aspx?CveOP={Me.CveOP}", False) + Context.ApplicationInstance.CompleteRequest() Catch ex As Exception - ' Rollback en caso de error - clsOP.RollBack() - Alert($"Error al guardar: {ex.Message}", TipoMensaje.MsgError) + If transactionActive Then + clsOP.RollBack() + End If + Alert($"Error: {ex.Message}", TipoMensaje.MsgError) Finally clsOP.Dispose() End Try End Sub + Private Function DataTableToXML(dt As DataTable) As String + Dim xmlDoc As New XmlDocument() + xmlDoc.LoadXml("") + + For Each row As DataRow In dt.Rows + Dim producto As XmlElement = xmlDoc.CreateElement("Producto") + producto.InnerXml = $"{row("Clave")}{row("Cantidad")}{row("CveUM")}" + xmlDoc.DocumentElement.AppendChild(producto) + Next + + Return xmlDoc.OuterXml + End Function + Private Sub ActualizarGrids() - Dim dtProductosFiltrados As DataTable = DtPS.Clone() ' Clona la estructura + Dim dtProductosFiltrados As DataTable = DtPS.Clone() Dim rowsProductos As DataRow() = DtPS.Select("Tipo = 'Producto'") If rowsProductos.Length > 0 Then dtProductosFiltrados = rowsProductos.CopyToDataTable() @@ -397,11 +776,227 @@ Partial Class OP_OP GvCostosIndirectos.DataSource = dtCIFiltrados GvCostosIndirectos.DataBind() + ' Calcular suma de "Surtido" + Dim sumSurtido As Decimal = DtMP.AsEnumerable().Sum(Function(row) row.Field(Of Decimal)("Surtido")) + + + LnkSolicitarMP.Visible = (CveOP > -1 AndAlso sumSurtido = 0) + UpGvDatosOP.Update() End Sub + Protected Sub DdlAlmacenOrigenMP_SelectedIndexChanged(sender As Object, e As EventArgs) + ' ✅ Mantener siempre el almacén de producción (tipo 28) en destino + DdlAlmacenDestinoMP.DataSource = GlobalDTAlmacen(UsuarioActual.CveEmpresa).FiltraParametros("CveTipoAlmacen = 28") + DdlAlmacenDestinoMP.DataBind() + + ' ✅ Opcional: Seleccionar el primer almacén de producción por defecto + If DdlAlmacenDestinoMP.Items.Count > 0 Then + DdlAlmacenDestinoMP.SelectedIndex = 0 + End If + End Sub + +#Region "Eventos de Botones" + + Protected Sub BtnFinalizarOP_Click(sender As Object, e As EventArgs) + If CveOP = -1 Then Exit Sub + + ' 1. Cargar almacén de salida (Tipo 28) + DdlAlmacenOrigenSalidaMP.DataSource = GlobalDTAlmacen(UsuarioActual.CveEmpresa).FiltraParametros("CveTipoAlmacen = 28") + DdlAlmacenOrigenSalidaMP.DataBind() + ' 2. Cargar almacén de producto terminado + DdlAlmacenTerminado.DataSource = GlobalDTAlmacen(UsuarioActual.CveEmpresa).FiltraParametros("CveTipoAlmacen = 1") + DdlAlmacenTerminado.DataBind() + DdlAlmacenTerminado.Items.Insert(0, New ListItem("Seleccionar almacén", "-1")) + + ' 3. Cargar GridViews + GvProductoTerminado.DataSource = DtPS.FiltraParametros("Tipo = 'Producto'") + GvProductoTerminado.DataBind() + + GvMPUtilizada.DataSource = DtMP.FiltraParametros("Tipo = 'MP'").Copy() + GvMPUtilizada.DataBind() + + RegistraScript("$('#DVModalFinalizarOP').modal('show');") + UpModalFinalizar.Update() + End Sub + + Protected Sub BtnGuardarFinalizarOP_Click(sender As Object, e As EventArgs) Handles BtnGuardarFinalizarOP.Click + If DdlAlmacenOrigenSalidaMP.SelectedValue = "-1" OrElse DdlAlmacenTerminado.SelectedValue = "-1" Then + Alert("Selecciona ambos almacenes.", TipoMensaje.MsgAdvertencia) + Exit Sub + End If + + ' Dim TotalCantidad As Decimal = DtMovimientos.SUMD("Cantidad") + 'Inicia la transacción + + Dim CveMovimientoSalida As Integer = 0 + Dim CveMovimientoEntrada As Integer = 0 + Dim IDPoliza As Integer = 0 + Dim FolioSalida As Integer = 0 + 'Dim CveMovimientoVirtualEntrada As Integer = 0 + 'Dim CveMovimientoVirtualSalida As Integer = 0 + 'Dim FolioVirtualEntrada As Integer = 0 + 'Dim FolioVirtualSalida As Integer = 0 + Dim FolioEntrada As Integer = 0 + Dim Fecha As DateTime = Txtfecha.Text.ToDate + Dim ErrorMovInv As Boolean = False + Dim ErrorAC As Boolean = False + Dim TextoError As String = "" + Dim TipoMovimientoSalida As Integer = 8 + Dim CveConceptoEntrada As Integer = 9 + Dim TotalCostoMP As Decimal = 0 + + Dim ObjInventario As New ClsInventarios() + + ObjInventario.IniciaTransacSQL() + Dim ObjConta As New ClsContabilidad(ObjInventario.IniciaTransacSQL()) + Try + + CveMovimientoSalida = ObjInventario.AddMovimiento( + CveAlmacen:=DdlAlmacenOrigenSalidaMP.SelectedValue.ToEntero(), + CveConcepto:=TipoMovimientoSalida, + CveMoneda:=1, + FechaMovto:=Fecha, + tFolio:=-1, + CveUsuario:=UsuarioActual.CveUsuario, + CveEmpresa:=UsuarioActual.CveEmpresa, + CveCompra:=-1, + CveVenta:=-1, + CveSubProyecto:=-1, + CveActivoFijo:=-1, + Observaciones:="Finalización OP #" & LblFolio.Text, + CveAlmacenDestino:=DdlAlmacenTerminado.SelectedValue.ToEntero(), + Modulo:="OP/FinalizarOPSalida" + ) + + + For Each rowMP As DataRow In DtMP.Select("Tipo = 'MP'") + If Not ObjInventario.AddMovimientoDetalle( + CveMovimientoSalida, + rowMP("Cantidad").ToString.ToDecimal(), + rowMP("CveUMMateriaPrima").ToString.ToEntero(), + rowMP("CvePSMateriaPrima").ToString.ToEntero(), + 1 + ) Then + Throw New Exception("Error al agregar detalle de MP") + End If + TotalCostoMP += rowMP("Cantidad").ToString.ToDecimal() + Next + + + CveMovimientoEntrada = ObjInventario.AddMovimiento( + CveAlmacen:=DdlAlmacenTerminado.SelectedValue.ToEntero(), + CveConcepto:=CveConceptoEntrada, + CveMoneda:=1, + FechaMovto:=Fecha, + tFolio:=-1, + CveUsuario:=UsuarioActual.CveUsuario, + CveEmpresa:=UsuarioActual.CveEmpresa, + CveCompra:=-1, CveVenta:=-1, CveSubProyecto:=-1, CveActivoFijo:=-1, + Observaciones:="Finalización OP #" & LblFolio.Text, + Modulo:="OP/FinalizarOPEntrada", + CveMovimientoRelacionado:=CveMovimientoSalida + ) + + + Dim CantidadPT As Decimal = DtPS.AsEnumerable().Sum(Function(row) Convert.ToDecimal(row("Cantidad"))) + Dim PU_PT As Decimal = If(CantidadPT > 0, TotalCostoMP / CantidadPT, 1) + + + For Each rowPT As DataRow In DtPS.Select("Tipo = 'Producto'") + If Not ObjInventario.AddMovimientoDetalle( + CveMovimientoEntrada, + rowPT("Cantidad").ToString.ToDecimal(), + rowPT("CveUM").ToString.ToEntero(), + rowPT("Clave").ToString.ToEntero(), + PU_PT + ) Then + Throw New Exception("Error al agregar detalle de PT") + End If + Next + + + Dim CvePrePoliza As Integer = ObjConta.AddPrePolizas( + Modulo:="Inventario/OPFinalizada", + CvePlantillaPoliza:=53, + Cargos:=0, + Abonos:=0, + CveMoneda:=1, + Fecha:=Fecha, + Concepto:="Producción OP #" & LblFolio.Text, + CveUsuario:=UsuarioActual.CveUsuario, + CveEmpresa:=UsuarioActual.CveEmpresa + ) + + + If Not ObjConta.AddPrePolizasDetalle( + CvePrePoliza, + False, + TotalCostoMP, + TotalCostoMP, + 68, + "Consumo MP OP #" & LblFolio.Text, + "Consumo MP OP #" & LblFolio.Text, + CveMovimientoAlmacen:=CveMovimientoSalida + ) Then ErrorMovInv = True + + + If Not ObjConta.AddPrePolizasDetalle( + CvePrePoliza, + True, + TotalCostoMP, + TotalCostoMP, + 68, + "Producción PT OP #" & LblFolio.Text, + "Producción PT OP #" & LblFolio.Text, + CveMovimientoAlmacen:=CveMovimientoEntrada + ) Then ErrorMovInv = True + + + If Not ErrorMovInv Then + Dim ObjOP As New ClsOP() + If Not ObjOP.UpdateEstatusOP(CveOP, 3, UsuarioActual.CveEmpresa) Then + ErrorMovInv = True + TextoError = "Error al actualizar estatus de la OP" + End If + End If + + + If Not ErrorMovInv Then + If Not ObjConta.ValidacionesPrePoliza(CvePrePoliza, UsuarioActual) Then + ErrorMovInv = True + TextoError = "Error en validación de póliza" + ElseIf ObjConta.ValorPolizaDescuadre > 0 Then + ErrorMovInv = True + TextoError = "Descuadre en póliza contable" + End If + End If + + + If Not ErrorMovInv Then + ObjInventario.Commit() + Alert($"OP finalizada. Folio Contable: {ObjConta.ContaFolio}", TipoMensaje.MsgInformacion) + Else + ObjInventario.RollBack() + Alert($"Error contable: {TextoError}", TipoMensaje.MsgError) + End If + + RegistraScript("$('#DVModalFinalizarOP').modal('hide');") + CargaDatos() + + Catch ex As Exception + ObjInventario.RollBack() + Alert($"Error crítico: {ex.Message}", TipoMensaje.MsgError) + Finally + ObjInventario.Dispose() + ObjConta.Dispose() + End Try + + + End Sub +#End Region End Class diff --git a/OP/RepOP.aspx b/OP/RepOP.aspx index 43dfa4ed2..07e4fce50 100644 --- a/OP/RepOP.aspx +++ b/OP/RepOP.aspx @@ -174,7 +174,7 @@ -