diff --git a/DFeMonitor.hbp b/DFeMonitor.hbp index 58d5f9e..fc0fbc8 100644 --- a/DFeMonitor.hbp +++ b/DFeMonitor.hbp @@ -52,5 +52,6 @@ src\utils\isTrue.prg src\utils\log.prg src\utils\msgDebugInfo.prg src\utils\msgNotify.prg +src\utils\SQL2JSON.prg src\utils\SysWait.prg src\utils\timersForms.prg diff --git a/DFeMonitor.rc b/DFeMonitor.rc index 283ec36..9f2c81e 100644 --- a/DFeMonitor.rc +++ b/DFeMonitor.rc @@ -1,5 +1,5 @@ 1 VERSIONINFO - FILEVERSION 4,1,17{ + FILEVERSION 4,1,18{ BLOCK "StringFileInfo" { BLOCK "040904E4" @@ -9,7 +9,7 @@ VALUE "LegalCopyright" , "Copyright (c) Sistrom Web" VALUE "OriginalFilename" , "DFeMonitor.exe" VALUE "ProductName" , "DFe Monitor" - VALUE "ProductVersion" , "4.1.17.Hb.MS" + VALUE "ProductVersion" , "4.1.18.Hb.MS" } } BLOCK "VarFileInfo" diff --git a/main.prg b/main.prg index 0dc98ef..e1ee7ac 100644 --- a/main.prg +++ b/main.prg @@ -23,7 +23,7 @@ REQUEST HB_CODEPAGE_UTF8 */ Function Main - public appData := TAppData():new("4.1.17") + public appData := TAppData():new("4.1.18") public appDataSource public appFTP public appEmpresas @@ -142,6 +142,7 @@ procedure main_form_oninit() SetProperty("main", "notifyIcon", "serverON") MessageBoxTimeout("O DFeMonitor ficará oculto na barra de tarefa", "DFeMonitor " + appData:version + ": Inicializado", MB_ICONEXCLAMATION, 3000) + recoverySQL() startTimer() return diff --git a/src/connections/mysql/db/ctes/CTes.prg b/src/connections/mysql/db/ctes/CTes.prg index 0e9fea7..f251207 100644 --- a/src/connections/mysql/db/ctes/CTes.prg +++ b/src/connections/mysql/db/ctes/CTes.prg @@ -521,6 +521,9 @@ method updateCTe(cId, aFields) class TDbCTes cte:Destroy() if !updated saveLog(sql:value, "Debug") + saveSQL(sql:value) + MsgStop("Banco de Dados sem conexão ou ocupado, esgotado todas as tentativas", "Erro de conexão: Tente mais tarde") + turnOFF() endif return updated @@ -552,8 +555,12 @@ method insertEventos(aEvents) class TDbCTes ctes_eventos := TQuery():new(sql:value) inserted := ctes_eventos:executed ctes_eventos:Destroy() + if !inserted saveLog(sql:value, "Debug") + saveSQL(sql:value) + MsgStop("Banco de Dados sem conexão ou ocupado, esgotado todas as tentativas", "Erro de conexão: Tente mais tarde") + turnOFF() endif return inserted \ No newline at end of file diff --git a/src/connections/mysql/db/mdfes/MDFes.prg b/src/connections/mysql/db/mdfes/MDFes.prg index cbe66a8..28f11c5 100644 --- a/src/connections/mysql/db/mdfes/MDFes.prg +++ b/src/connections/mysql/db/mdfes/MDFes.prg @@ -144,6 +144,9 @@ method updateMDFe(cId, aFields) class TDbMDFes if !updated saveLog(sql:value, "Debug") + saveSQL(sql:value) + MsgStop("Banco de Dados sem conexão ou ocupado, esgotado todas as tentativas", "Erro de conexão: Tente mais tarde") + turnOFF() endif return updated @@ -182,6 +185,9 @@ method insertEventos(aEvents) class TDbMDFes if !inserted saveLog(sql:value, "Debug") + saveSQL(sql:value) + MsgStop("Banco de Dados sem conexão ou ocupado, esgotado todas as tentativas", "Erro de conexão: Tente mais tarde") + turnOFF() endif return inserted diff --git a/src/connections/mysql/db/shared/Query.prg b/src/connections/mysql/db/shared/Query.prg index 1466ca6..f9c265b 100644 --- a/src/connections/mysql/db/shared/Query.prg +++ b/src/connections/mysql/db/shared/Query.prg @@ -9,7 +9,8 @@ class TQuery data count readonly method new(cSql) constructor - method runQuery(sql) + method tryRunQuery() + method runQuery() method serverBusy() method Skip() inline ::db:Skip() method GoTop() inline ::db:GoTop() @@ -30,7 +31,7 @@ method new(cSql) class TQuery if appDataSource:connected .or. appDataSource:connect() SetProperty("main", "NotifyIcon", "serverWAIT") msgNotify({'notifyTooltip' => "Executando query..."}) - if ::runQuery() + if ::tryRunQuery() ::count := ::db:LastRec() ::db:GoTop() msgNotify() @@ -39,7 +40,7 @@ method new(cSql) class TQuery AAdd(aLog, "Conexão perdida com banco de dados. Reconectando...") if appDataSource:connect() AAdd(aLog, "Conexão Restabelecida!") - if ::runQuery() + if ::tryRunQuery() ::count := ::db:LastRec() ::db:GoTop() msgNotify() @@ -63,27 +64,27 @@ method new(cSql) class TQuery return self -method runQuery() class TQuery - local tenta as numeric +method tryRunQuery() class TQuery + local tenta := 0 local command, table, mode - ::executed := false - ::db := appDataSource:mysql:Query(::sql) + if !::runQuery() + return false + endif - if (::db == nil) - if !appDataSource:connect() - msgNotify({"notifyTooltip" => "B.D. não conectado!"}) - saveLog("Banco de Dados não conectado!", "Warning") + do while ::serverBusy() + appDataSource:disconnect() + if (++tenta > 10) + saveLog("Servidor DB ocupado, esgotado as 10 tentativas", "Error") return false endif - ::db := appDataSource:mysql:Query(::sql) - if (::db == nil) - msgNotify({'notifyTooltip' => "Erro de SQL!"}) - saveLog("Erro ao executar Query! [Query is NIL]", "Error") - msgDebugInfo({'Erro ao executar ::db, avise ao suporte!', hb_eol() + hb_eol(), 'Ver Log do sistema', hb_eol(), 'Erro: Query is NIL'}) + saveLog("Servidor DB ocupado, aguardando 7 segundos e nova tentativa " + hb_ntos(tenta) + "/10", "Warning") + SysWait(7) + appDataSource:connect() + if !::runQuery() return false endif - endif + enddo command := hmg_upper(firstString(hb_utf8StrTran(::db:cQuery, ";"))) command := AllTrim(command) @@ -110,7 +111,7 @@ method runQuery() class TQuery table := Capitalize(table) endif - if ::db:NetErr() .and. !::serverBusy() + if ::db:NetErr() if ("DUPLICATE ENTRY" $ hmg_upper(::db:Error())) saveLog({"Erro de duplicidade ao " + mode + " " + table, ansi_to_unicode(::sql)}, "Error") elseif ("lost connection" $ hmg_lower(::db:Error())) @@ -141,13 +142,32 @@ method runQuery() class TQuery return ::executed +method runQuery class TQuery + ::executed := false + ::db := appDataSource:mysql:Query(::sql) + + if (::db == nil) + if !appDataSource:connect() + msgNotify({"notifyTooltip" => "B.D. não conectado!"}) + saveLog("Banco de Dados não conectado!", "Warning") + return false + endif + ::db := appDataSource:mysql:Query(::sql) + if (::db == nil) + msgNotify({'notifyTooltip' => "Erro de SQL!"}) + saveLog("Erro ao executar Query! [Query is NIL]", "Error") + msgDebugInfo({'Erro ao executar ::db, avise ao suporte!', hb_eol() + hb_eol(), 'Ver Log do sistema', hb_eol(), 'Erro: Query is NIL'}) + return false + endif + endif + +return true + method serverBusy() class TQuery local ocupado := (::db:NetErr() .and. 'server has gone away' $ ::db:Error()) if ocupado // Força a reconexão caso o servidor tenha "desaparecido" (ocupado) saveLog({"Servidor ocupado! Reconectando...", "Erro: " + ::db:Error()}, "Warning") - appDataSource:disconnect() - appDataSource:connect() endif return ocupado diff --git a/src/core/cte/cteSubmit.prg b/src/core/cte/cteSubmit.prg index 8de2f38..66e499a 100644 --- a/src/core/cte/cteSubmit.prg +++ b/src/core/cte/cteSubmit.prg @@ -7,30 +7,36 @@ procedure cteSubmit(cte) if appData:cte_sefaz_offline + saveLog("SEFAZ OFFLINE! Verificando se Sefaz está disponível...") // Verifica se a Sefaz SP voltou a ficar disponível (online) apiCTe:contingencia := false sefaz := apiCTe:ConsultarSefaz() if (sefaz["codigo_status"] == 107) + saveLog("SEFAZ ONLINE! Sefaz voltou a ficar disponível...") // Sefaz SP voltou a fica disponível, sai do módo contingência appData:cte_sefaz_offline := false elseif (sefaz["codigo_status"] == -1) + saveLog({"Sefaz status: -1", "Protocolo: " + apiCTe:numero_protocolo, "CTe Status: " + apiCTe:status, "Mensagem: " + apiCTe:mensagem}) cte:setUpdateEventos(apiCTe:numero_protocolo, apiCTe:data_evento, apiCTe:status, apiCTe:mensagem) errEmissao(apiCTe, cte) return else + saveLog("Verificando Sefaz Virtual de Contingência (SVC-RS) do RS está disponível...") // Verifica se a Sefaz Virtual de Contingência (SVC-RS) do RS está disponível (online) apiCTe:contingencia := true sefaz := apiCTe:ConsultarSefaz() if (sefaz["codigo_status"] == -1) + saveLog({"Sefaz SVC-RS status: -1", "Protocolo: " + apiCTe:numero_protocolo, "CTe Status: " + apiCTe:status, "Mensagem: " + apiCTe:mensagem}) cte:setUpdateEventos(apiCTe:numero_protocolo, apiCTe:data_evento, apiCTe:status, apiCTe:mensagem) errEmissao(apiCTe, cte) apiCTe:contingencia := false return elseif !(sefaz["codigo_status"] == 107) // Sefaz SP OFFLINE e SVC-RS ainda não está disponível! + saveLog("SEFAZ SVC-RS OFFLINE! Ainda não está disponível.") apiCTe:contingencia := false cte:setUpdateEventos(apiCTe:numero_protocolo, apiCTe:data_evento, apiCTe:codigo_status, apiCTe:motivo_status) cte:setUpdateEventos(apiCTe:numero_protocolo, apiCTe:data_evento, apiCTe:codigo_status, "SEFAZ SP E SEFAZ RS VIRUTAL DE CONTINGENCIA INDISPONIVEIS!") @@ -39,6 +45,7 @@ procedure cteSubmit(cte) else // Sefaz Virtual RS em Operação // tpEmis: 1 - Normal; 5 - Contingência FSDA; 7 - Autorização pela SVC-RS; 8 - Autorização pela SVC-SP + saveLog("SEFAZ SVC-RS ONLINE! Emissão de CTEs em CONTINGÊNCIA.") cte:tpEmis := 7 // SVC-RS cte:dhCont := apiCTe:data_emissao cte:xJust := apiCTe:motivo_status diff --git a/src/utils/SQL2JSON.prg b/src/utils/SQL2JSON.prg new file mode 100644 index 0000000..470489a --- /dev/null +++ b/src/utils/SQL2JSON.prg @@ -0,0 +1,22 @@ +procedure saveSQL(sql) + local fileJson := appData:systemPath + 'log\recovery_sql.json' + hb_MemoWrit(fileJson, hb_jsonEncode({"sql" => sql}, 4)) +return + +procedure recoverySQL() + local fileJson := appData:systemPath + 'log\recovery_sql.json' + local hSQL, q + + if hb_FileExists(fileJson) + hSQL := hb_jsonDecode(hb_MemoRead(fileJson)) + hb_FileDelete(fileJson) + if hb_HGetRef(hSQL, "sql") + q := TQuery():new(hSQL["sql"]) + if !q:executed + saveLog({"DB: Erro ao executar o SQL recuperado", hSQL["sql"]}, "Debug") + endif + q:Destroy() + endif + endif + +return \ No newline at end of file