diff --git a/B4A/C_Cliente.bas b/B4A/C_Cliente.bas index cc499d3..5aadc1b 100644 --- a/B4A/C_Cliente.bas +++ b/B4A/C_Cliente.bas @@ -4481,8 +4481,8 @@ Private Sub b_notificacion_Click Log("-" & tag & "-") Private tag1() As String = Regex.Split("\|", tag) Log(tag1.Length & "-" & tag1(0) & "-" & tag1(1)) - Private CODIGO As String = tag1(0) - Private ID As String = tag1(1) + Private CODIGO As String = tag1(1) + Private ID As String = tag1(0) p_transparenciaNoti.Visible = False DateTime.DateFormat = "yyyy-MM-dd HH:mm:ss" Starter.skmt.ExecNonQuery($"insert into HIST_NOTIFICACIONES (HN_CODIGO, HN_ID, HN_FECHA) values ('${CODIGO}', '${ID}', '${DateTime.Date(DateTime.Now)}')"$) diff --git a/B4A/C_Principal.bas b/B4A/C_Principal.bas index 9d92a79..4e2f1ff 100644 --- a/B4A/C_Principal.bas +++ b/B4A/C_Principal.bas @@ -643,6 +643,7 @@ Sub Subir_Click Next End If Sleep(1000) + Starter.revisandoNotifiaciones = False CARGA = "SUBIR" ' P1.Visible = True @@ -2289,9 +2290,9 @@ Sub JobDone(Job As HttpJob) LogColor(reqManager.reqsList, Colors.blue) LogColor(reqManager.reqsList.Size, Colors.blue) If CARGA = "SUBIR" Then actualizaProgressBar - + 'Si ya se procesaron TODAS las peticiones, entonces realizamos validaciones. - If reqManager.reqsList.Size = 0 Then + If reqManager.reqsList.Size = 0 And Not(Starter.revisandoNotifiaciones) Then If CARGA = "SUBIR" Then revisaHistNotificaciones End If End If @@ -2314,14 +2315,15 @@ Sub JobDone(Job As HttpJob) End Sub 'Envia el historial de notificaciones despues de haberlas borrado para que no se dupliquen. -Sub enviaHistNotificaciones - Private hn As Cursor = Starter.skmt.ExecQuery($"select * from hist_notificaciones"$) +Sub enviaHistNotificaciones(id As String, codigo As String) + Private hn As Cursor = Starter.skmt.ExecQuery($"select * from hist_notificaciones where HN_CODIGO = '${codigo}' and HN_ID = '${id}'"$) If hn.RowCount > 0 Then For i = 0 To hn.RowCount - 1 hn.Position = i cmd.Initialize cmd.Name = "insertHistNotificaciones" - cmd.Parameters = Array As Object( hn.GetString("HN_CODIGO"), hn.GetString("HN_ID"), hn.GetString("HN_FECHA")) + cmd.Parameters = Array As Object(hn.GetString("HN_ID"), hn.GetString("HN_CODIGO"), hn.GetString("HN_FECHA")) + Log($"Enviamos notificacion: id: ${hn.GetString("HN_ID")}, codigo: ${hn.GetString("HN_CODIGO")}, fecha: ${hn.GetString("HN_FECHA")}"$) reqManager.ExecuteCommand(cmd , "insertHistNotificaciones") Next hn.Close @@ -2331,7 +2333,9 @@ End Sub ' Revisa que en web haya el numero correcto de notificaciones en el historial Sub revisaHistNotificaciones LogColor("####################### REVISA NOTIS ########", Colors.red) - Private cn As Cursor = Starter.skmt.ExecQuery("select count(HN_CODIGO) as cuantos, HN_CODIGO, HN_ID from HIST_NOTIFICACIONES") + Starter.revisandoNotifiaciones = True +' Private cn As Cursor = Starter.skmt.ExecQuery("select count(HN_CODIGO) as cuantos, HN_CODIGO, HN_ID from HIST_NOTIFICACIONES") + Private cn As Cursor = Starter.skmt.ExecQuery($"SELECT HN_ID, HN_CODIGO, HN_FECHA, COUNT(*) As cuantos FROM HIST_NOTIFICACIONES GROUP BY HN_ID"$) If cn.RowCount > 0 Then cn.Position = 0 Private CuantasN As Int = cn.GetInt("cuantos") @@ -2344,14 +2348,15 @@ Sub revisaHistNotificaciones Subs.logJobDoneResultados(r.resultado) For Each records() As Object In r.resultado.Rows Dim CuantasN As Int = records(r.resultado.Columns.Get("CUANTOS")) + LogColor($"####################### id: ${cn.GetString("HN_ID")}, codigo: ${cn.GetString("HN_CODIGO")}, Cuantas: ${CuantasN} ########"$, Colors.red) If cn.GetInt("cuantos") > CuantasN Then - enviaHistNotificaciones + enviaHistNotificaciones(cn.GetString("HN_ID"), cn.GetString("HN_CODIGO")) + Log($"enviaHistNotificaciones(${cn.GetString("HN_ID")}, ${cn.GetString("HN_CODIGO")})"$) End If Next Else Log(r.ErrorMessage) End If - End If End Sub @@ -2579,6 +2584,7 @@ Sub e_ruta_EnterPressed Starter.skmt.ExecNonQuery("delete from HIST_TREND_SPENDING_SEMANAL") Starter.skmt.ExecNonQuery("delete from VERSIONES") Starter.skmt.ExecNonQuery("delete from auditoria") + Starter.skmt.ExecNonQuery("delete from HIST_NOTIFICACIONES") Starter.skmt.ExecNonQuery2("INSERT INTO HIST_ENVIOS VALUES (?,0,?)", Array As Object(sTime, "PEDIDO")) Starter.skmt.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("NUMERO_PEDIDO")) @@ -3448,8 +3454,8 @@ Sub SUBIR_INFO_PEDIDO PB2.Progress = PB2.Progress + 1 contador_env = contador_env + 1 Next - c.Close End If + c.Close d.Position=0 cuantos_noventa = D.GetString("CUANTOS_NOVENTA") PB2.Progress = 100 @@ -3569,35 +3575,35 @@ Sub enviaPedidoBatch(filtro As String) ' BLOQUE DE VALIDACIÓN REMOTA: Revisar si el pedido ya está liquidado o el arqueo cerrado ' ========================================================================================= ' sql.revisaArqueoYLiquidacion_Kelloggs = select NVL(HVD_ESTATUS, 'NO') as liquidado, HVD_DTECIERRE, (select hist_ca_fecha from KELLOGGS.hist_cierre_arqueo where hist_ca_idalmacen = (?) and hist_ca_ruta = (?) and trunc(sysdate) = trunc(hist_ca_fecha)) as arqueo from KELLOGGS.HIST_VENTAS_DETALLE where HVD_ALMACEN = (?) and HVD_RUTA = (?) and trunc(sysdate) = trunc(HVD_FECHA) and HVD_TIPOVENTA = 'VENTA' and rownum <= 1 - + ' 1. Preparamos el comando para consultar el estatus directamente en la base de datos del servidor. cmd.Initialize cmd.Name = "revisaArqueoYLiquidacion_Kelloggs" Private ruta_ As String = Subs.traeRuta cmd.Parameters = Array As Object(ALMACEN, ruta_, ALMACEN, ruta_) - + ' 2. Disparamos la consulta al servidor de forma asíncrona usando reqManagerW. reqManagerW.ExecuteQuery(Starter.DBReqServer, cmd, Me, "revisaPedidoLiquidado") - + ' 3. Pausamos la ejecución de este bloque local hasta que el servidor nos responda. Wait For revisaPedidoLiquidado_Completed (rpd As TResultado) - + ' 4. Evaluamos la respuesta del servidor. If rpd.Success Then Log("SUCCESS - revisaPedidoLiquidado") - + ' Inicializamos variables asumiendo que el pedido NO está liquidado y NO hay arqueo. Dim liquidado As String = "NO" Dim arqueo As String = "null" - + ' Leemos los registros devueltos por el servidor para actualizar nuestras variables. For Each records() As Object In rpd.resultado.Rows liquidado = records(rpd.resultado.Columns.Get("LIQUIDADO")) arqueo = records(rpd.resultado.Columns.Get("ARQUEO")) Next - + Subs.logJobDoneResultados(rpd.resultado) - + ' 5. Regla de negocio: Si el estatus es "NO" liquidado y el arqueo es "null" (abierto), ' entonces es seguro proceder a modificar/enviar la información. If liquidado = "NO" And arqueo = "null" Then diff --git a/B4A/DBRequestManagerW.bas b/B4A/DBRequestManagerW.bas index d6589e2..3144808 100644 --- a/B4A/DBRequestManagerW.bas +++ b/B4A/DBRequestManagerW.bas @@ -4,167 +4,153 @@ ModulesStructureVersion=1 Type=Class Version=12.8 @EndOfDesignText@ -'Class module: jRDC1Wrapper -'Version 1.3 - Thread-Safe with ExecuteCommand support +'####################################################################################### +' Módulo de Clase: jRDC1Wrapper +' Versión: 1.9.2 - Thread-Safe, Async Support, B4A Memory Safe, State Persistent & Dynamic Link Support +' Autor: Cheve (José Alberto) +' +' DESCRIPCIÓN: +' Este módulo actúa como un "Wrapper" (envoltorio) especializado para DBRequestManager +' en entornos jRDC1. Su objetivo principal es modernizar el flujo de trabajo de +' versiones antiguas de B4X, permitiendo el uso de la sintaxis "Wait For" en lugar +' de depender exclusivamente del evento JobDone global. +' +' Ejemplo de uso: + +' Dim reqManagerW As DBRequestManagerW +' reqManagerW.Initialize +' cmd.Initialize +' cmd.Name = "selectAlgoDeAlgunLado" +' cmd.Parameters = Array As Object(user.Text, pass.Text) +' reqManagerW.ExecuteQuery(Starter.DBReqServer, cmd, Me, "loSeleccionado") +' Wait For loSeleccionado_Completed (res1 As TResultado) +' Log("tag: " & res1.tag & " Success: " & res1.Success) +' If res1.Success Then +' Subs.logJobDoneResultados(res1.resultado) +' Else +' Log(res1.ErrorMessage) +' End If +'####################################################################################### Public Sub Class_Globals - ' Public properties to be accessed after the wait for completes Type TResultado(Tag As String, Success As Boolean, resultado As DBResult, ErrorMessage As String) -' Type TCommandResult(Tag As String, Success As Boolean, RowsAffected As Int, ErrorMessage As String) - - 'C <<< Definimos un tipo para almacenar la información de cada job Type TJobInfo (Target As Object, EventName As String, IsQuery As Boolean) - 'C <<< Un mapa para mantener un registro de los jobs activos Private activeJobs As Map - - 'C <<< Un contador para generar tags únicos para cada job Private jobCounter As Int - - Public reqManager As DBRequestManager - Public cmd As DBCommand - Public resultado As TResultado -' Public commandResult As TCommandResult Private logger As Boolean = False + + ' Instancia centralizada. + Private reqManager As DBRequestManager + + ' Rastreo del EndPoint activo para evitar reinicializaciones redundantes + Private currentActiveLink As String = "" End Sub -'Initializes the object. Public Sub Initialize - 'C <<< Inicializamos el mapa y el contador - activeJobs.Initialize + If activeJobs.IsInitialized = False Then + activeJobs.Initialize + End If jobCounter = 0 + currentActiveLink = "" End Sub -'Executes the query using the old jRDC1 mechanism. -'Parameters: -' - rdcLink: The link for the reqManager initialization. -' - Command: The DBCommand to execute. -' - Target: The module (like 'Me') where the completed event should be raised. -' - Event: The name of the event to raise when the query completes (e.g., "WrapperEvent"). Public Sub ExecuteQuery(rdcLink As String, Command As DBCommand, Target As Object, Event As String) - '<<< Incrementamos el contador para obtener un ID único jobCounter = jobCounter + 1 - Dim currentJobTag As String = "reqManagerWJob_" & jobCounter - currentJobTag = Event + Dim currentJobTag As String = $"reqManagerWJob_${DateTime.Now}_${jobCounter}"$ If logger Then Log($"ExecuteQuery (Tag: ${currentJobTag}): Command=${Command.Name}, Event=${Event}"$) - '<<< Creamos una instancia de TJobInfo para guardar el target y el evento + ' Actualización dinámica de EndPoint solo si el Link cambió + If reqManager.IsInitialized = False Or currentActiveLink <> rdcLink Then + reqManager.Initialize(Me, rdcLink) + currentActiveLink = rdcLink + End If + Dim jobInfo As TJobInfo jobInfo.Initialize jobInfo.Target = Target jobInfo.EventName = Event - jobInfo.IsQuery = True ' Mark as query job + jobInfo.IsQuery = True - '<<< Guardamos la información del job en el mapa, usando el tag único como llave activeJobs.Put(currentJobTag, jobInfo) - - reqManager.Initialize(Me, rdcLink) - cmd = Command - - '<<< Ejecutamos la consulta pasando nuestro TAG ÚNICO - reqManager.ExecuteQuery(cmd, 0, currentJobTag) + reqManager.ExecuteQuery(Command, 0, currentJobTag) End Sub -'Executes a command (INSERT, UPDATE, DELETE) using the old jRDC1 mechanism. -'Parameters: -' - rdcLink: The link for the reqManager initialization. -' - Command: The DBCommand to execute. -' - Target: The module (like 'Me') where the completed event should be raised. -' - Event: The name of the event to raise when the command completes (e.g., "WrapperEvent"). Public Sub ExecuteCommand(rdcLink As String, Command As DBCommand, Target As Object, Event As String) - '<<< Incrementamos el contador para obtener un ID único jobCounter = jobCounter + 1 - Dim currentJobTag As String = "reqManagerWJob_" & jobCounter - currentJobTag = Event + Dim currentJobTag As String = $"reqManagerWJob_${DateTime.Now}_${jobCounter}"$ If logger Then Log($"ExecuteCommand (Tag: ${currentJobTag}): Command=${Command.Name}, Event=${Event}"$) - '<<< Creamos una instancia de TJobInfo para guardar el target y el evento + ' Actualización dinámica de EndPoint solo si el Link cambió + If reqManager.IsInitialized = False Or currentActiveLink <> rdcLink Then + reqManager.Initialize(Me, rdcLink) + currentActiveLink = rdcLink + End If + Dim jobInfo As TJobInfo jobInfo.Initialize jobInfo.Target = Target jobInfo.EventName = Event - jobInfo.IsQuery = False ' Mark as command job + jobInfo.IsQuery = False - '<<< Guardamos la información del job en el mapa, usando el tag único como llave activeJobs.Put(currentJobTag, jobInfo) - - reqManager.Initialize(Me, rdcLink) - cmd = Command - - '<<< Ejecutamos el comando pasando nuestro TAG ÚNICO - reqManager.ExecuteCommand(cmd, currentJobTag) + reqManager.ExecuteCommand(Command, currentJobTag) End Sub -'This sub will be called by the DBRequestManager when the job is done Public Sub JobDone(job As HttpJob) - Log("===== JDDBRW =====") - LogColor("JobDone: '" & reqManager.HandleJob(job).tag & "' - Registros: " & reqManager.HandleJob(job).Rows.Size, Colors.Green) 'Mod por CHV - 211110 - '<<< Obtenemos el Tag único que asignamos al job - Dim currentJobTag As String = job.Tag - - 'C <<< Verificamos si este job fue iniciado por nuestro wrapper - If activeJobs.ContainsKey(currentJobTag) = False Then - If logger Then Log($"JobDone: Se recibió un job con un tag desconocido: ${currentJobTag}"$) - job.Release - Return - End If - - '<<< Recuperamos la información específica de este job desde el mapa - Dim jobInfo As TJobInfo = activeJobs.Get(currentJobTag) + If logger Then Log("===== JDDBRW =====") + Dim currentJobTag As String = "" + Try - If jobInfo.IsQuery Then - ' Handle query result - resultado.Initialize - resultado.Tag = jobInfo.EventName ' Usamos el nombre del evento original como Tag del resultado - - If job.Success Then - Dim dbResult As DBResult = reqManager.HandleJob(job) - resultado.Success = True - resultado.Resultado = dbResult - resultado.ErrorMessage = "" - Else - resultado.Success = False - resultado.Resultado = Null - resultado.ErrorMessage = job.ErrorMessage - End If - job.Release - - '<<< Usamos la información recuperada del mapa para llamar al Sub correcto - If logger Then LogColor($"EVENTO: ${jobInfo.EventName}_Completed"$, Colors.Magenta) - CallSubDelayed2(jobInfo.Target, jobInfo.EventName & "_Completed", resultado) - Else - ' Handle command result - resultado.Initialize - resultado.Tag = jobInfo.EventName - - If job.Success Then - Dim dbResult As DBResult = reqManager.HandleJob(job) -' Dim rowsAffected As Int = reqManager.HandleCommandResult(job) -' For Each records() As Object In dbResult.Rows -' Dim rowsAffected As Int = records(dbResult.Columns.Get("AffectedRows")) -' Next - resultado.Success = True - resultado.resultado = dbResult - resultado.ErrorMessage = "" - Else - resultado.Success = False - resultado.resultado = Null - resultado.ErrorMessage = job.ErrorMessage - End If - job.Release - - '<<< Usamos la información recuperada del mapa para llamar al Sub correcto - If logger Then LogColor($"EVENTO: ${jobInfo.EventName}_Completed"$, Colors.Magenta) - CallSubDelayed2(jobInfo.Target, jobInfo.EventName & "_Completed", resultado) + If job <> Null And job.Tag <> Null And job.Tag Is String Then + currentJobTag = job.Tag + End If + + If activeJobs.ContainsKey(currentJobTag) Then + + Dim jobInfo As TJobInfo = activeJobs.Get(currentJobTag) + Dim res As TResultado + res.Initialize + res.Tag = jobInfo.EventName + + If job.Success Then + Dim dbResult As DBResult = reqManager.HandleJob(job) + If logger Then LogColor("JobDone: '" & dbResult.tag & "' - Registros: " & dbResult.Rows.Size, Colors.Green) + res.Success = True + res.resultado = dbResult + res.ErrorMessage = "" + Else + res.Success = False + res.resultado = Null + res.ErrorMessage = job.ErrorMessage + End If + + activeJobs.Remove(currentJobTag) + + If logger Then LogColor($"EVENTO: ${jobInfo.EventName}_Completed"$, Colors.Magenta) + CallSubDelayed2(jobInfo.Target, jobInfo.EventName & "_Completed", res) + + Else + If logger Then Log($"JobDone: Job descartado (Tag desconocido o nulo): ${currentJobTag}"$) End If - 'C <<< Se remueve el job del mapa en caso de ÉXITO - activeJobs.Remove(currentJobTag) Catch - If logger Then LogColor("Error en jRDC1Wrapper.JobDone: " & LastException, Colors.Red) - '<<< MUY IMPORTANTE: Remover el job del mapa para no tener fugas de memoria - activeJobs.Remove(currentJobTag) + If logger Then LogColor("Error Crítico en jRDC1Wrapper.JobDone: " & LastException, Colors.Red) + + If currentJobTag <> "" And activeJobs.ContainsKey(currentJobTag) Then + Dim jobInfo As TJobInfo = activeJobs.Get(currentJobTag) + Dim resErr As TResultado + resErr.Initialize + resErr.Tag = jobInfo.EventName + resErr.Success = False + resErr.ErrorMessage = "Error interno procesando la respuesta DB: " & LastException.Message + + activeJobs.Remove(currentJobTag) + CallSubDelayed2(jobInfo.Target, jobInfo.EventName & "_Completed", resErr) + End If End Try + + If job <> Null Then job.Release End Sub \ No newline at end of file diff --git a/B4A/KelloggsV4.b4a b/B4A/KelloggsV4.b4a index 3108947..cc1f045 100644 --- a/B4A/KelloggsV4.b4a +++ b/B4A/KelloggsV4.b4a @@ -918,7 +918,7 @@ Version=12.8 #Region Project Attributes #ApplicationLabel: Kelloggs Venta #VersionCode: 3000 - #VersionName: 6.03.28 + #VersionName: 6.03.30 #SupportedOrientations: portrait #CanInstallToExternalStorage: False #BridgeLogger:true diff --git a/B4A/KelloggsV4.b4a.meta b/B4A/KelloggsV4.b4a.meta index a05c93f..897b10b 100644 --- a/B4A/KelloggsV4.b4a.meta +++ b/B4A/KelloggsV4.b4a.meta @@ -94,7 +94,7 @@ ModuleClosedNodes29= ModuleClosedNodes3= ModuleClosedNodes30=3 ModuleClosedNodes31= -ModuleClosedNodes32=2 +ModuleClosedNodes32= ModuleClosedNodes33= ModuleClosedNodes34= ModuleClosedNodes4=1,3 @@ -103,6 +103,6 @@ ModuleClosedNodes6= ModuleClosedNodes7= ModuleClosedNodes8= ModuleClosedNodes9= -NavigationStack=C_Principal,JobDone,2239,0,C_Principal,Class_Globals,0,0,C_Cliente,B4XPage_Appear,793,0,C_Cliente,Guardar_Click,1084,0,C_Cliente,mandaPendientes,1100,0,DBRequestManagerW,ExecuteCommand,92,0,C_Principal,enviaPedidoBatch1,3697,0,C_Principal,SUBIR_INFO_PEDIDO,3517,0,C_Principal,enviaPedidoBatch,3565,6 +NavigationStack=Subs,parseHTTPError,2013,0,C_Principal,revisaHistNotificaciones,2355,6,C_Principal,enviaHistNotificaciones,2325,6,C_NuevoCliente,Class_Globals,2,0,B4XMainPage,i_engranes_LongClick,745,0,DBRequestManagerW,ExecuteQuery,50,0,DBRequestManagerW,Initialize,42,0,DBRequestManagerW,JobDone,135,6,DBRequestManagerW,Class_Globals,20,0,DBRequestManagerW,ExecuteCommand,105,0 SelectedBuild=0 VisibleModules=32,1,13,4,33,16,34,14,15,24,22 diff --git a/B4A/Starter.bas b/B4A/Starter.bas index 49ad8b8..502d8a8 100644 --- a/B4A/Starter.bas +++ b/B4A/Starter.bas @@ -58,6 +58,7 @@ Sub Process_Globals Dim GUID As String = "" Dim passSupervisor As String = "135###" ' Valor predeterminado DIFERENTE a "" Dim semana As Int = 0 + dim revisandoNotifiaciones as Boolean = false End Sub Sub Service_Create