+
+
+
+
-
-
-
-
Costo indirecto
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Simulación
+
+
+
+
+
+
+
+
Materia prima
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Producto Terminado
+
+
+
+
+
+
+
+
+
+
+
+
+
Materia Prima
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
-