none
Lógica misteriosa RRS feed

  • Pregunta

  • Hola

    Tengo unos meses padeciendo de unos problemas indetectables pero, con síntomas desagradables.

    Tengo un modulo de facturación que gestiono con linq, sql 2012 y vs2015.

    El problema radica en que, a veces, sin ningún patrón detectable, No registra en la tabla de inventario los movimientos del producto. 

    Lo primero que hago es preparar la cuadricula para ser recorrida lo mas depurada posible; es decir, que no hayan lineas sin cantidades ni datos necesarios para preservar la integridad de lo que se graba. Lo hago con este código..

     Private Sub BotonGuardar_Click(sender As Object, e As EventArgs) Handles BotonGuardar.Click
            Try
                Prepara()
                Salida()
    
     Catch ex As Exception
              
                MessageBox.Show(ex.Message, "Excepción!", MessageBoxButtons.OK, MessageBoxIcon.Error)
    
                  End Try
        End Sub

    Eso es en el Boton Guardar.

    Sub Prepara()
            'Or Convert.ToInt32(Row.Cells(0).Value) = 0)
            DataGriDetalles.AllowUserToAddRows = False
            For Index = DataGriDetalles.Rows.Count - 1 To 0 Step -1
                Dim Row = DataGriDetalles.Rows(Index)
                If Row.IsNewRow Then Continue For
                If (Row.Cells(0).Value Is Nothing) Or Row.Cells(1).Value Is Nothing Or Row.Cells(5).Value Is Nothing Or Row.Cells(6).Value Is Nothing Then 
                    DataGriDetalles.Rows.RemoveAt(Index) 
                End If
            Next
        End Sub

    Con este prepara la cuadricula para procesar y  grabar los datos reales.

    Private Sub Salida()
                   Try
                DataGriDetalles.AllowUserToAddRows = False
                Dim na As New PDVDatosDataContext()
                For Each row As DataGridViewRow In DataGriDetalles.Rows
    
                    Dim prod As Productos = na.Productos.FirstOrDefault(Function(a) a.codigo = Convert.ToString(row.Cells(0).Value))
    
                    If prod IsNot Nothing Then
                        prod.existencia = prod.existencia - Convert.ToString(row.Cells(5).Value)
                       
                        Dim det As New Invent()
                        det.codigo = Trim(row.Cells(0).Value)
                        det.fecha = Trim(TexFecha.Text)
                        det.tipo = "Factura"
                        det.numdoc = Trim(TexNumero.Text)
                        det.salida = Convert.ToString(row.Cells(5).Value)
                        det.costo = prod.costo
                        det.precio = Convert.ToString(row.Cells(3).Value)
    
                        na.Invent.InsertOnSubmit(det)
                        na.SubmitChanges()
                       
                    End If
    
                Next
              
    
            Catch ex As Exception
                            MessageBox.Show(ex.Message, "Excepción!", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub

    Y con este ultimo, rebajo la cantidad del inventario y registro el movimiento.

    Por favor si puden arrojarme luz en este caso, porque ya no se que hacer. Estoy preparando otro modulo de facturacion con codigo nativo de sql para el acceso a los datos. Con linq, ya he utilizado logger, ejecucion paso a paso, trazas de sql agent y no veo nada raro.

    domingo, 7 de enero de 2018 16:04

Respuestas

  • Tal como lo muestras aquí, efectivamente las llamadas son secuenciales, es decir, mientras no vuelva la llamada a "Prepara" no se ejecuta "Salida". El problema vendría en caso de que DENTRO de Prepara realizases alguna operación asíncrona y no esperases su terminación, en cuyo caso retornaría inmediatamente y por tanto se ejecutaría Salida incluso aunque los resultados generados por ese proceso asíncrono no estuviesen todavía disponibles.
    lunes, 8 de enero de 2018 21:00
  • Entonces allí no tengo problemas, pues cada uno tiene instrucciones que no dependen de ninguna respuesta entre sí.

    Las dependencias entre procedimientos no determinan el tiempo de invocación (de hecho las dependencias son síntoma de un diseño deficiente). El procedimiento Salida() -o cualquier otra instrucción- se ejecutará una vez haya finalizado la ejecución del procedimiento Prepara(), a menos que el procedimiento Prepara() sea un procedimiento asíncrono, de ser así evitará el bloqueo de la siguiente instrucción llamadora.

    lunes, 8 de enero de 2018 21:50

Todas las respuestas

  • Hola Formulaz, lo estoy viendo el código, Preparar() funciona perfecto a mi enteder, lo que noto es que disparas ambos eventos al mismo tiempo, si bien la pila de llamada debería respetarce, yo colocaría el disparo de Salida() dentro de Preparar() en el final del código. en cuanto a Salida() no lo entiendo bien (falencia mia), lo que noto es que prod as Productos debe ser una clase, se puede dar que esta clase esté vacía en determinado momento? Yo colocaría un Else en ese if para que me alerte di prod esta Null

    Sigo mirando

    Saludos


    ARA San Juan 44 HEROES     ‗‗‗‗­|||||‗‗‗‗‗

    • Propuesto como respuesta Pablo Rubio lunes, 8 de enero de 2018 15:12
    domingo, 7 de enero de 2018 20:03
  • Gracias Marcelo por contestar.

    Pues Prod nunca deberia estar vacio, pues consulta con codigos que ya existen, ya que estan en la cuadricula. Y en esta cuadricula se coloca el producto que esta en la bd. Y nadie mas tiene acceso a borrarlos, encima de que se debe cumplir un amplio protocolo para borrar alguno.

    Y en cuanto a que disparo ambos eventos al mismo tiempo, no te entiendo bien, pues considero que uno se cumple primero y despues el otro.

    Y Productos, es una tabla de la bd.

    Gracias.

    lunes, 8 de enero de 2018 2:06
  • Entonces, como debería yo llamar a los procedimientos?

    No entiendo, pensé que lo estoy haciendo muy bien, en orden y secuencia.

    Gracias.


    • Editado Formulaz5 lunes, 8 de enero de 2018 20:05
    lunes, 8 de enero de 2018 20:04
  • Hola.

    Tengo el siguiente código en el evento clic de un boton. Me comentaron que estoy llamando a los procedimientos al mismo tiempo. Que se debe respetar la pila de llamadas. A lo que no entiendo bien, pues yo pense que se ejecuta uno primero que otro y punto. Por tanto, no debería ocasionar ningun conflicto.

    Private Sub BotonGuardar_Click(sender As Object, e As EventArgs) Handles BotonGuardar.Click
            Try
                Prepara()
                Salida()
    
     Catch ex As Exception
              
                MessageBox.Show(ex.Message, "Excepción!", MessageBoxButtons.OK, MessageBoxIcon.Error)
    
                  End Try
        End Sub

    Gracias por sus aclaraciones.

    lunes, 8 de enero de 2018 20:18
  • Hola Formulaz, es una idea, como te dije en el primer respuesta la pila debería respetarse, pero a modo de prueba puedes optrar por colocarlo dentro de Preparar() ej:

    Sub Prepara()
            'Or Convert.ToInt32(Row.Cells(0).Value) = 0)
            DataGriDetalles.AllowUserToAddRows = False
            For Index = DataGriDetalles.Rows.Count - 1 To 0 Step -1
                Dim Row = DataGriDetalles.Rows(Index)
                If Row.IsNewRow Then Continue For
                If (Row.Cells(0).Value Is Nothing) Or Row.Cells(1).Value Is Nothing Or Row.Cells(5).Value Is Nothing Or Row.Cells(6).Value Is Nothing Then 
                    DataGriDetalles.Rows.RemoveAt(Index) 
                End If
            Next
         Salida()
        End Sub

    A menos que utlilices Praparar() en otros eventos que no tengan relación con Salida(). Igualmente luego de tu acalración me parece que el error puede estár en Salida() sostengo la idea de colocar un Else en caso que prod esté vacío, se que dices que no puede ser pero ... que los hay los hay je

             If prod IsNot Nothing Then
                        prod.existencia = prod.existencia - Convert.ToString(row.Cells(5).Value)
                       
                        Dim det As New Invent()
                        det.codigo = Trim(row.Cells(0).Value)
                        det.fecha = Trim(TexFecha.Text)
                        det.tipo = "Factura"
                        det.numdoc = Trim(TexNumero.Text)
                        det.salida = Convert.ToString(row.Cells(5).Value)
                        det.costo = prod.costo
                        det.precio = Convert.ToString(row.Cells(3).Value)
    
                        na.Invent.InsertOnSubmit(det)
                        na.SubmitChanges()
                   Else
    
                 MsgBox("prod no contiene valores!")
                       
                    End If
    Saludos


    ARA San Juan 44 HEROES     ‗‗‗‗­|||||‗‗‗‗‗

    • Propuesto como respuesta Pablo Rubio lunes, 8 de enero de 2018 22:51
    lunes, 8 de enero de 2018 20:41
  • Tal como lo muestras aquí, efectivamente las llamadas son secuenciales, es decir, mientras no vuelva la llamada a "Prepara" no se ejecuta "Salida". El problema vendría en caso de que DENTRO de Prepara realizases alguna operación asíncrona y no esperases su terminación, en cuyo caso retornaría inmediatamente y por tanto se ejecutaría Salida incluso aunque los resultados generados por ese proceso asíncrono no estuviesen todavía disponibles.
    lunes, 8 de enero de 2018 21:00
  • Gracias.

    Entonces allí no tengo problemas, pues cada uno tiene instrucciones que no dependen de ninguna respuesta entre sí.

    Se cumple uno y después el otro, sin mas.

    lunes, 8 de enero de 2018 21:11
  • Gracias Marcelo.

    A mi modo de ver la lógica ne este caso, pues seria lo mismo. Las instrucciones no esperan nada de ninguno de los módulos entre sí. 

    Pero sí que me has puesto la duda de la integridad de la cuadricula una vez se prepara, aunque sucedía igual antes de poner el bloque de Prepara(). 

    No entiendo, me parto el "caco" meditando por qué razón y posiblemente, a veces queda vacía la variable Prod y NO graba.

    Ya no sé que mas hacer. Lo único que estoy haciendo es utilizar instrucciones sql directas, nada de linq,  a ver como me va.

    Gracias.

    lunes, 8 de enero de 2018 21:18
  • Entonces allí no tengo problemas, pues cada uno tiene instrucciones que no dependen de ninguna respuesta entre sí.

    Las dependencias entre procedimientos no determinan el tiempo de invocación (de hecho las dependencias son síntoma de un diseño deficiente). El procedimiento Salida() -o cualquier otra instrucción- se ejecutará una vez haya finalizado la ejecución del procedimiento Prepara(), a menos que el procedimiento Prepara() sea un procedimiento asíncrono, de ser así evitará el bloqueo de la siguiente instrucción llamadora.

    lunes, 8 de enero de 2018 21:50
  • Correcto Williams.

    Las instrucciones de estos procedimientos no tienen nada que ver con otros procedimientos entre sí.

    Gracias.

    lunes, 8 de enero de 2018 21:53