Hoje trago para vocês um disparo de e-Mail em AdvPL com dados de funcionários e ponto eletrônico.
O grande Fabrício Amaro (LinkedIn), há um tempo vem adaptando um boletim de RH, tanto com dados gerais de funcionários, quanto um espelho de ponto (tanto analítico quanto sintético), o famoso MABOLRH.
Conversando com ele recentemente, tive a necessidade de implantar esse “workflow” para disparo de informações para o RH, e assim sendo, peguei o fonte original MABOLRH e coloquei alguns comentários no fonte e fiz adaptações nele (retirando campos customizados, trechos comentados, etc).
Abaixo um print do boletim geral:
Abaixo um print do boletim do ponto resumido:
Abaixo o código fonte inteiro, ressalto para verificarem a variável cEmails (que são os destinatários da mensagem). Além disso, o ideal é ter compilado uma função de disparo de e-Mail, nesse caso é usado a zEnvMail, disponível em https://terminaldeinformacao.com/2017/10/17/funcao-dispara-e-mail-varios-anexos-em-advpl/ .
//Bibliotecas #Include "RwMake.ch" #Include "TopConn.ch" #Include "Protheus.ch" Static dParam01 := FirstDate(Date()) //Periodo de - Static dParam02 := LastDate(Date()) //Periodo ate - Static cParam03 := "" //Copiar e-mail: - Static nParam04 := 1 //Tipo? - 1=Apontamentos, 2=Banco de Horas Banco de Horas Static nParam05 := 2 //Mostrar Salario? - 1=Nao, 2=Sim Static nParam06 := 1 //Somente Horas Normais? - 1=Sim, 2=Nao Static nParam07 := 1 //Banco de Horas? - 1=Sintetico, 2=Analitico Static nParam08 := 1 //Intervalo Menor Que - Static nParam09 := 1.42 //Intervalo Maior Que - Static nParam10 := 1 //Acumulado Horas Extras? - 1=Nao, 2=Sim Static nParam11 := 1 //Mostrar Justificativas? - 1=Nao, 2=Sim Static nParam12 := 1 //Mostrar evento abonado? - 1=Nao, 2=Sim Static nParam13 := 1 //Mostrar evento informado? - 1=Nao, 2=Sim Static nParam14 := 1 //Considera Horas Extras? - 1=Nao, 2=Sim /*/{Protheus.doc} zBolRH Workflow com Boletim informativo do RH baseado no MABOLRH @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ User Function zBolRH() Local aArea := GetArea() Local lContinua := .T. Local dDataBkp := sToD("") Private lAutom := .F. Private cEmails := "" //Se nao estiver preparado o ambiente, prepara no Ponto Eletronico If Select("SX2") == 0 lAutom := .T. RPCSetEnv("01", "01", "", "", "SIGAPON") Else lContinua := MsgYesNo("Essa funcao ira disparar os boletins dos funcionarios. Deseja continuar?", "Atencao") EndIf //Se o dia For menor que 10, o email sera referente ao mes passado If Day(Date()) <= 10 dParam01 := FirstDate( MonthSub(dParam01, 1) ) dParam02 := LastDate(dParam01) EndIf //Altera a dDataBase para a ultima data dDataBkp := dDataBase dDataBase := dParam02 //Pegando os emails cEmails := "email@empresa.com;email2@empresa.com" //Chama o boletim resumido Processa({|| fBoletResu() }, "Processando...") //Marcacoes do Ponto nParam04 := 1 Processa({|| fBoletPont() }, "Processando...") //Banco de Horas nParam04 := 2 Processa({|| fBoletPont() }, "Processando...") //Voltando backup da data dDataBase := dDataBkp RestArea(aArea) Return /*/{Protheus.doc} fHCorpoIni Inicializa o HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHCorpoIni(cHtm) cHtm := '<html><body>' Return /*/{Protheus.doc} fHCorpoFin Finaliza o HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHCorpoFin(cHtm) cHtm += '</body></html>' Return /*/{Protheus.doc} fHPulaLin Pula de linha no HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHPulaLin(cHtm, nQuant) cHtm += Repl('<br>', nQuant) Return /*/{Protheus.doc} fHTabIni Inicia a estrutura da tabela no HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHTabIni(cHtm, nEspCel, nMarCel, nBorda) cHtm += '<table Width=100% cellspacing="' + Alltrim(Str(nEspCel)) + '" cellpadding="' + Alltrim(Str(nMarCel)) + '" border="' + Alltrim(Str(nBorda)) + '">' Return /*/{Protheus.doc} fHTabFin Fecha a estrutura da tabela no HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHTabFin(cHtm) cHtm += '</table>' Return /*/{Protheus.doc} fHTabLin Adiciona uma linha na estrutura da tabela no HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHTabLin(cHtm, aCol, cCorFundo, cCorFonte, nTamFonte) Local nCol Local lFonte //Verifica se foi passado definicao de fonte usada lFonte := ! (nTamFonte == Nil .And. cCorFonte == Nil) //Cria a linha cHtm += '<TR' + Iif(cCorFundo == Nil, '', ' BGCOLOR="#' + cCorFundo + '"') + '>' //Percorrendo as colunas For nCol := 1 To Len(aCol) //Cria a celula cHtm += '<TD valign=top>' //Caso nao tenha sido passado as informacoes de tamanho e cor, define a fonte da celula If lFonte cHtm += '<FONT face = tahoma ' If !(nTamFonte == Nil) cHtm += ' SIZE="' + Alltrim(Str(nTamFonte)) + '"' EndIf If !(cCorFonte == Nil) cHtm += ' COLOR="#' + cCorFonte + '"' EndIf cHtm += '>' EndIf //Encerra a celula cHtm += aCol[nCol] + '</TD>' Next cHtm += '</TR>' Return /*/{Protheus.doc} fHTitLin Adiciona uma linha de titulo na estrutura da tabela no HTML @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fHTitLin(cHtm, aCol, cCorFundo, cCorFonte, nTamFonte) Local nCol Local lFonte //Verifica se foi passado definicao de fonte usada lFonte := !(nTamFonte == Nil .And. cCorFonte == Nil) //Cria a linha cHtm += '<TR' + Iif(cCorFundo == Nil, '', ' BGCOLOR="#' + cCorFundo + '"') + '>' //Percorrendo as colunas For nCol := 1 To Len(aCol) //Cria a celula, se for a primeira coluna tera conteudo alinhado a direita If nCol == 1 cHtm += '<TD valign=top>' Else cHtm += '<TD valign=top align="right">' EndIf //Caso nao tenha sido passado as informacoes de tamanho e cor, define a fonte da celula If lFonte cHtm += '<FONT face = tahoma ' If !(nTamFonte == Nil) cHtm += ' SIZE="' + Alltrim(Str(nTamFonte)) + '"' EndIf If !(cCorFonte == Nil) cHtm += ' COLOR="#' + cCorFonte + '"' EndIf cHtm += '>' EndIf //Encerra a celula cHtm += aCol[nCol] + '</TD>' Next cHtm += '</TR>' Return /*/{Protheus.doc} fDiaSemana Funcao que retorna a sigla do dia da semana @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fDiaSemana(dData) Local cSiglaDia := "" If Dow(dData) == 1 cSiglaDia := "DOM" ElseIf Dow(dData) == 2 cSiglaDia := "SEG" ElseIf Dow(dData) == 3 cSiglaDia := "TER" ElseIf Dow(dData) == 4 cSiglaDia := "QUA" ElseIf Dow(dData) == 5 cSiglaDia := "QUI" ElseIf Dow(dData) == 6 cSiglaDia := "SEX" ElseIf Dow(dData) == 7 cSiglaDia := "SAB" EndIf Return cSiglaDia /*/{Protheus.doc} fEnviarEm Funcao para disparo de e-Mail @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fEnviarEm(cEmails, cAssunto, cCorpo) //Se tiver e-mails para colocar em copia If ! Empty(cParam03) cEmails := Alltrim(cParam03) + ";" + cEmails EndIf //Dispara o e-Mail u_zEnvMail(cEmails, cAssunto, cCorpo) Return /*/{Protheus.doc} fBoletResu Boletim Resumido com dados dos funcionarios @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fBoletResu() Local nAtual Local nRegs Local cQuery Local nDias Local nTotal := 0 Local nNormal := 0 Local nFerias := 0 Local nAfast := 0 Private cHtm := "" //Inicializa a mensagem fHCorpoIni(@cHtm) //Cria o cabecalho fHTabIni(@cHtm, 0, 2, 0) fHTitLin(@cHtm, {'Informacoes referentes ao mes: ' + SubStr(dToS(dDataBase), 5, 2) + "/" + SubStr(dToS(dDataBase), 1, 4), 'TOTVS'}, '788EA7', 'FFFFFF', 4) fHTitLin(@cHtm, {'Boletim Informativo R.H.', 'by TOTVS Microsiga Protheus'}, 'CCCCCC', '000000', -5) fHTabFin(@cHtm) fHPulaLin(@cHtm, 2) //Seleciona os funcionarios admitidos no mes cQuery := " SELECT " + CRLF cQuery += " RA_FILIAL, RA_MAT, RA_NOME, RA_ADMISSA, RJ_DESC, CTT_DESC01 " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " SRA, " + RetSQLName("CTT") + " CTT, " + RetSQLName("SRJ") + " SRJ " + CRLF cQuery += " WHERE " + CRLF cQuery += " RA_ADMISSA >= '" + SubStr(dToS(dDataBase), 1, 6) + "01' AND RA_ADMISSA <= '" + SubStr(dToS(dDataBase), 1, 6) + "31' " + CRLF cQuery += " AND RA_SITFOLH <> 'D' " + CRLF cQuery += " AND RA_CATFUNC <> 'A' " + CRLF cQuery += " AND RA_CODFUNC = RJ_FUNCAO " + CRLF cQuery += " AND RA_CC = CTT_CUSTO " + CRLF cQuery += " AND SRA.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND SRJ.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND CTT.D_E_L_E_T_ = ' ' " + CRLF TCQuery cQuery New Alias "QRY" TCSetField("QRY", "RA_ADMISSA", "D") //Define o tamanho da regua DbSelectArea("QRY") Count To nRegs QRY->(DbGoTop()) nAtual := 0 ProcRegua(nRegs) //Se existir registros If nRegs > 0 //Cabecalho da secao se funcionarios admitidos no mes fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'Funcionarios Admitidos no mes: ' + Alltrim(Str(nRegs))}, '000000', 'FFFFFF', -1) fHTabFin(@cHtm) //Titulo das colunas lImpar := .T. fHTabIni(@cHtm, 1, 2, 0) fHTabLin(@cHtm, {'Filial', 'Empresa', 'Mat', 'Nome', 'Admissao', 'Funcao', 'C.Custo'}, '000000', 'FFFFFF', -1) //Enquanto houver registros While ! QRY->(EoF()) //Incrementa a regua nAtual++ IncProc("Processando Admissoes " + cValToChar(nAtual) + " de " + cValToChar(nRegs) + "...") //Adiciona a linha no html fHTabLin(@cHtm, {QRY->RA_FILIAL, FWFilialName(cEmpAnt, QRY->RA_FILIAL, 1), QRY->RA_MAT, QRY->RA_NOME, dToC(QRY->RA_ADMISSA), QRY->RJ_DESC, QRY->CTT_DESC01 }, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) lImpar := ! lImpar DbSkip() EndDo fHTabFin(@cHtm) fHPulaLin(@cHtm, 1) EndIf QRY->(DbCloseArea()) //Seleciona os funcionarios demitidos no mes cQuery := "SELECT " + CRLF cQuery += " RA_FILIAL, RA_MAT, RA_ADMISSA, RA_DEMISSA, RJ_DESC, CTT_DESC01, RA_NOME " + CRLF cQuery += "FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " SRA, " + RetSQLName("CTT") + " CTT, " + RetSQLName("SRJ") + " SRJ " + CRLF cQuery += "WHERE " + CRLF cQuery += " RA_DEMISSA >= '" + SubStr(dToS(dDataBase), 1, 6) + "01' AND RA_DEMISSA <= '" + SubStr(dToS(dDataBase), 1, 6) + "31' " + CRLF cQuery += " AND RA_CATFUNC <> 'A' " + CRLF cQuery += " AND RA_CODFUNC = RJ_FUNCAO " + CRLF cQuery += " AND RA_CC = CTT_CUSTO " + CRLF cQuery += " AND SRA.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND SRJ.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND CTT.D_E_L_E_T_ = ' ' " + CRLF cQuery += "ORDER BY " + CRLF cQuery += " RA_FILIAL, RA_DEMISSA " + CRLF TCQuery cQuery New Alias "QRY" TCSetField("QRY", "RA_ADMISSA", "D") TCSetField("QRY", "RA_DEMISSA", "D") //Define o tamanho da regua DbSelectArea("QRY") Count To nRegs QRY->(DbGoTop()) nAtual := 0 ProcRegua(nRegs) //Se existir registros If nRegs > 0 //Cabecalho da secao se funcionarios demitidos no mes fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'Funcionarios Demitidos no mes: ' + Alltrim(Str(nRegs))}, '000000', 'FFFFFF', -1) fHTabFin(@cHtm) //Titulo das colunas lImpar := .T. fHTabIni(@cHtm, 1, 2, 0) fHTabLin(@cHtm, {'Filial', 'Empresa', 'Mat', 'Nome', 'Admissao', 'Demissao', 'Funcao', 'C.Custo'}, '000000', 'FFFFFF', -1) //Enquanto houver registros While ! QRY->(EoF()) //Incrementa a regua nAtual++ IncProc("Processando Admissoes " + cValToChar(nAtual) + " de " + cValToChar(nRegs) + "...") //Adiciona a linha no html fHTabLin(@cHtm, {QRY->RA_FILIAL, FWFilialName(cEmpAnt, QRY->RA_FILIAL, 1), QRY->RA_MAT, QRY->RA_NOME, dToC(QRY->RA_ADMISSA), dToC(QRY->RA_DEMISSA), QRY->RJ_DESC, QRY->CTT_DESC01 }, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) lImpar := ! lImpar QRY->(DbSkip()) EndDo fHTabFin(@cHtm) fHPulaLin(@cHtm, 1) EndIf QRY->(DbCloseArea()) //Seleciona vencimentos de experiencia cQuery := " SELECT " + CRLF cQuery += " RA_FILIAL, RA_VCTEXP2, RA_VCTOEXP, RA_MAT, RA_NOME, RA_ADMISSA, RA_CC, CTT_DESC01 " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " SRA, " + RetSQLName("CTT") + " CTT " + CRLF cQuery += " WHERE " + CRLF cQuery += " SRA.RA_VCTOEXP <> ' '" + CRLF cQuery += " AND ( SRA.RA_VCTOEXP >= '" + dToS(DaySub(dDataBase, 7)) + "' OR SRA.RA_VCTEXP2 >= '" + dToS(DaySub(dDataBase, 7)) + "')" + CRLF cQuery += " AND SRA.RA_CC = CTT.CTT_CUSTO " + CRLF cQuery += " ORDER BY SRA.RA_FILIAL, SRA.RA_VCTOEXP, SRA.RA_NOME ASC " + CRLF TCQuery cQuery New Alias "QRY" TCSetField("QRY", "RA_ADMISSA", "D") TCSetField("QRY", "RA_VCTOEXP", "D") TCSetField("QRY", "RA_VCTEXP2", "D") //Define o tamanho da regua DbSelectArea("QRY") Count To nRegs QRY->(DbGoTop()) nAtual := 0 ProcRegua(nRegs) //Se existir registros If nRegs > 0 //Cabecalho da secao de vencimentos de experiencia fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'Vencimento de Contratos de Experiencia ' + Alltrim(Str(nRegs))}, '000000', 'FFFFFF', -1) fHTabFin(@cHtm) //Titulo das colunas lImpar := .T. fHTabIni(@cHtm, 1, 2, 0) fHTabLin(@cHtm, {'Filial', 'Matricula', 'Nome', 'Admissao', 'Vencto 1', 'Vencto 2', 'Centro de Custo'}, '000000', 'FFFFFF', -1) //Enquanto houver registros While ! QRY->(EoF()) //Incrementa a regua nAtual++ IncProc("Processando Experiencias " + cValToChar(nAtual) + " de " + cValToChar(nRegs) + "...") //Pegando a diferenca de dias If QRY->RA_VCTEXP2 >= dDataBase nDias := DateDiffDay(QRY->RA_VCTEXP2, dDataBase) ElseIf QRY->RA_VCTOEXP >= dDataBase nDias := DateDiffDay(QRY->RA_VCTOEXP, dDataBase) EndIf //Adiciona a linha no html fHTabLin(@cHtm, {QRY->RA_FILIAL + " - " + FWFilialName(cEmpAnt, QRY->RA_FILIAL, 1), QRY->RA_MAT, QRY->RA_NOME, dToC(QRY->RA_ADMISSA), dToC(QRY->RA_VCTOEXP), dToC(QRY->RA_VCTEXP2), QRY->RA_CC + " - " + QRY->CTT_DESC01}, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) lImpar := !lImpar QRY->(DbSkip()) EndDo fHTabFin(@cHtm) fHPulaLin(@cHtm, 1) EndIf QRY->(DbCloseArea()) //Seleciona quadro de funcionarios geral cQuery := "SELECT " + CRLF cQuery += " RA_FILIAL, " + CRLF cQuery += " COUNT(*) AS TOTAL, " + CRLF cQuery += " ( " + CRLF cQuery += " SELECT " + CRLF cQuery += " COUNT(*) " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " F " + CRLF cQuery += " WHERE " + CRLF cQuery += " F.RA_SITFOLH <> 'D' " + CRLF cQuery += " AND F.RA_SITFOLH = 'F' " + CRLF cQuery += " AND F.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND F.RA_FILIAL = SRA.RA_FILIAL " + CRLF cQuery += " ) AS FERIAS, " + CRLF cQuery += " ( " + CRLF cQuery += " SELECT " + CRLF cQuery += " COUNT(*) " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " A " + CRLF cQuery += " WHERE " + CRLF cQuery += " A.RA_SITFOLH <> 'D' " + CRLF cQuery += " AND A.RA_SITFOLH = 'A' " + CRLF cQuery += " AND A.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND A.RA_FILIAL = SRA.RA_FILIAL " + CRLF cQuery += " ) AS AFAST " + CRLF cQuery += "FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " SRA " + CRLF cQuery += "WHERE " + CRLF cQuery += " RA_SITFOLH <> 'D' " + CRLF cQuery += " AND D_E_L_E_T_ = ' ' " + CRLF cQuery += "GROUP BY " + CRLF cQuery += " RA_FILIAL " + CRLF cQuery += "ORDER BY " + CRLF cQuery += " RA_FILIAL " + CRLF TCQuery cQuery New Alias "QRY" //Define o tamanho da regua DbSelectArea("QRY") Count To nRegs QRY->(DbGoTop()) nAtual := 0 ProcRegua(nRegs) //Se existir registros If nRegs > 0 //Cabecalho da secao de funcionarios fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'Quadro de Funcionarios'}, '000000', 'FFFFFF', -1) fHTabFin(@cHtm) //Titulo das colunas lImpar := .T. fHTabIni(@cHtm, 1, 2, 0) fHTabLin(@cHtm, {'Filial', 'Empresa', 'Total', 'Normal', 'Ferias', 'Afastados'}, '000000', 'FFFFFF', -1) //Zera os totais nTotal := 0 nNormal := 0 nFerias := 0 nAfast := 0 //Enquanto houver registros While ! QRY->(EoF()) //Incrementa a regua nAtual++ IncProc("Processando Quadro de Funcionarios " + cValToChar(nAtual) + " de " + cValToChar(nRegs) + "...") //Adiciona a linha no html fHTabLin(@cHtm, {QRY->RA_FILIAL, FWFilialName(cEmpAnt, QRY->RA_FILIAL, 1), Alltrim(Str(QRY->TOTAL)), Alltrim(Str(QRY->TOTAL-QRY->FERIAS-QRY->AFAST)), Alltrim(Str(QRY->FERIAS)), Alltrim(Str(QRY->AFAST)) }, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) lImpar := !lImpar //Atualiza totais nTotal += QRY->TOTAL nNormal += QRY->TOTAL - QRY->FERIAS - QRY->AFAST nFerias += QRY->FERIAS nAfast += QRY->AFAST QRY->(DbSkip()) EndDo //Adiciona totais e encerra tabela fHTabLin(@cHtm, {"", "", Alltrim(Str(nTotal)), Alltrim(Str(nNormal)), Alltrim(Str(nFerias)), Alltrim(Str(nAfast)) }, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) fHTabFin(@cHtm) fHPulaLin(@cHtm, 1) EndIf QRY->(DbCloseArea()) //Quadro de Funcionarios por Centro de Custos cQuery := "SELECT " + CRLF cQuery += " RA_FILIAL, RA_CC, CTT_DESC01, COUNT(*) AS TOTAL, " + CRLF cQuery += " ( " + CRLF cQuery += " SELECT COUNT(*) " + CRLF cQuery += " FROM " + RetSQLName("SRA") + " F " + CRLF cQuery += " WHERE F.RA_SITFOLH <> 'D' " + CRLF cQuery += " AND F.RA_SITFOLH = 'F' " + CRLF cQuery += " AND F.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND F.RA_FILIAL = SRA.RA_FILIAL " + CRLF cQuery += " AND F.RA_CC = SRA.RA_CC " + CRLF cQuery += " ) AS FERIAS, " + CRLF cQuery += " ( " + CRLF cQuery += " SELECT COUNT(*) " + CRLF cQuery += " FROM " + RetSQLName("SRA") + " A " + CRLF cQuery += " WHERE A.RA_SITFOLH <> 'D' " + CRLF cQuery += " AND A.RA_SITFOLH = 'A' " + CRLF cQuery += " AND A.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND A.RA_FILIAL = SRA.RA_FILIAL " + CRLF cQuery += " AND A.RA_CC = SRA.RA_CC " + CRLF cQuery += " ) AS AFAST " + CRLF cQuery += "FROM " + CRLF cQuery += " " + RetSQLName("SRA") + " SRA, " + RetSQLName("CTT") + " CTT " + CRLF cQuery += "WHERE " + CRLF cQuery += " RA_SITFOLH <> 'D' " + CRLF cQuery += " AND RA_CC = CTT_CUSTO " + CRLF cQuery += " AND SRA.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND CTT.D_E_L_E_T_ = ' ' " + CRLF cQuery += "GROUP BY RA_FILIAL, RA_CC, CTT_DESC01 " + CRLF cQuery += "ORDER BY RA_FILIAL " + CRLF TCQuery cQuery New Alias "QRY" //Define o tamanho da regua DbSelectArea("QRY") Count To nRegs QRY->(DbGoTop()) nAtual := 0 ProcRegua(nRegs) //Se tiver registros If nRegs > 0 //Cabecalho da secao de funcionarios por centro de custo fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'Quadro de Funcionarios por Centros de Custos'}, '000000', 'FFFFFF', -1) fHTabFin(@cHtm) //Titulo das colunas lImpar := .T. fHTabIni(@cHtm, 1, 2, 0) fHTabLin(@cHtm, {'Filial', 'Empresa', 'Cod C.Custo', 'Centro de Custos', 'Total', 'Normal', 'Ferias', 'Afastados'}, '000000', 'FFFFFF', -1) //Zera os totais nTotal := 0 nNormal := 0 nFerias := 0 nAfast := 0 //Enquanto houver registros While ! QRY->(EoF()) //Incrementa a regua nAtual++ IncProc("Processando Quadro de Funcionarios " + cValToChar(nAtual) + " de " + cValToChar(nRegs) + "...") //Adiciona a linha no html fHTabLin(@cHtm, {QRY->RA_FILIAL, FWFilialName(cEmpAnt, QRY->RA_FILIAL, 1), QRY->RA_CC, QRY->CTT_DESC01 , Alltrim(Str(QRY->TOTAL)), Alltrim(Str(QRY->TOTAL - QRY->FERIAS - QRY->AFAST)), Alltrim(Str(QRY->FERIAS)), Alltrim(Str(QRY->AFAST)) }, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) lImpar := !lImpar //Atualiza totais nTotal += QRY->TOTAL nNormal += QRY->TOTAL - QRY->FERIAS - QRY->AFAST nFerias += QRY->FERIAS nAfast += QRY->AFAST QRY->(DbSkip()) EndDo //Adiciona os totais e encerra a tabela fHTabLin(@cHtm, {"", "", "", "", Alltrim(Str(nTotal)), Alltrim(Str(nNormal)), Alltrim(Str(nFerias)), Alltrim(Str(nAfast)) }, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) fHTabFin(@cHtm) fHPulaLin(@cHtm, 1) EndIf QRY->(DbCloseArea()) //Adiciona uma mensagem de rodape e encerro o boletim fHTabIni(@cHtm, 0, 2, 0) fHTitLin(@cHtm, {'TOTVS - Mensagem automatica, favor nao responder este e-mail.'}, 'CCCCCC', '000000', -5) fHTabFin(@cHtm) fHCorpoFin(@cHtm) //Envia o e-Mail fEnviarEm(cEmails, "Boletim Informativo do R.H.", cHTM) Return /*/{Protheus.doc} fBoletPont Boletim do Ponto Eletronico separado por centro de custo @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fBoletPont() Local cQuery := "" Local cHtmPC := "" Local cHtmP8 := "" Local cHtmResult := "" Local cHtmAC := "" Local lTemApon := .F. Local nAtual Local nTotal Private cHtm := "" //Totais Private nTotHorN := 0 Private nTotValN := 0 Private nTotDiaN := 0 //Totais valorizados Private nTotHorV := 0 Private nTotValV := 0 Private nTotDiaV := 0 Private lTemCab := .F. //Buscando os centros de custo cQuery := " SELECT " + CRLF cQuery += " CTT_CUSTO , CTT_DESC01 " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("CTT") + " CTT " + CRLF cQuery += " WHERE " + CRLF cQuery += " CTT.D_E_L_E_T_ = ' ' " + CRLF TCQuery cQuery New Alias "QRY_CTT" //Definindo o tamanho da regua nTotal := 0 nAtual := 0 Count To nTotal ProcRegua(nTotal) QRY_CTT->(DbGoTop()) //Enquanto houver dados While ! QRY_CTT->(EoF()) //Zera os totais nTotHorN := 0 nTotValN := 0 nTotDiaN := 0 nTotHorV := 0 nTotValV := 0 nTotDiaV := 0 //Incrementa a regua nAtual++ IncProc("Centro Custo: " + QRY_CTT->CTT_CUSTO + " - " + Alltrim(QRY_CTT->CTT_DESC01) + " (" + cValToChar(nAtual) + " de " + cValToChar(nTotal) + ")" ) //Monta o corpo do e-mail fHCorpoIni(@cHtm) fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'Boletim do Ponto Eletronico - ' + Iif(nParam04 == 1, 'Divergências nas Marcacoes', 'Banco de Horas'), 'TOTVS'}, '788EA7', 'FFFFFF', 4) fHTabLin(@cHtm, {'Boletim Informativo do Ponto Eletronico', 'by TOTVS Microsiga Protheus'}, 'CCCCCC', '000000', -5) fHTabFin(@cHtm) fHPulaLin(@cHtm, 2) //Busca funcionarios do centro de custo atual cQuery := "SELECT " + CRLF cQuery += " RA_FILIAL, " + CRLF cQuery += " RA_MAT, " + CRLF cQuery += " RA_SALARIO, " + CRLF cQuery += " RA_HRSMES, " + CRLF cQuery += " RA_HRSEMAN, " + CRLF cQuery += " RA_TNOTRAB, " + CRLF cQuery += " RA_SEQTURN, " + CRLF cQuery += " RA_CC, " + CRLF cQuery += " RA_NOME " + CRLF cQuery += "FROM " cQuery += " " + RetSQLName("SRA") + " SRA " + CRLF cQuery += "WHERE " + CRLF cQuery += " RA_CC = '" + QRY_CTT->CTT_CUSTO + "' " + CRLF cQuery += " AND SRA.RA_SITFOLH <> 'D' " + CRLF cQuery += " AND SRA.D_E_L_E_T_ = ' ' " + CRLF cQuery += "ORDER BY SRA.RA_FILIAL, SRA.RA_MAT " + CRLF TCQuery cQuery New Alias "QRY_SRA" //Se nao houver funcionarios para esse centro de custo, volta para o laco da CTT If QRY_SRA->(EoF()) QRY_SRA->(DbCloseArea()) QRY_CTT->(DbSkip()) Loop EndIf //Insere o centro de custo no html lTemApon := .F. fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'CENTRO DE CUSTO: ' + Alltrim(QRY_CTT->CTT_CUSTO) + ' - ' + Alltrim(QRY_CTT->CTT_DESC01) }, '000000', 'FFFFFF', -1) fHTabFin(@cHtm) //Insere titulo para dados do funcionario lImpar := .T. fHTabIni(@cHtm, 1, 2, 0) fHTabLin(@cHtm, { 'Dados do Funcionario', Iif(nParam04 == 1, 'Apontamentos com divergencia', 'Banco de Horas') }, '000000', 'FFFFFF', -1) //Enquanto houver funcionarios While ! QRY_SRA->(EoF()) lTemCab := .F. //Define a data de/ate dDataIni := dParam01 dDataFim := dParam02 //Zera os htmls cHtmResult := "" cHtmP8 := "" cHtmPC := "" //Se for banco de horas If nParam04 == 2 //Busca as informacoes do banco de horas cHtmP8 := fProcuBH(QRY_SRA->RA_FILIAL, QRY_SRA->RA_MAT, ROUND(QRY_SRA->RA_SALARIO / (QRY_SRA->RA_HRSMES + QRY_SRA->RA_HRSEMAN) , 2) , ROUND((QRY_SRA->RA_HRSMES + QRY_SRA->RA_HRSEMAN) / 30, 2) ) cHtmResult += cHtmP8 Else //Enquanto a data de for menor ou igual a data ate While dDataIni <= dDataFim //Busca as marcacoes e os apontamentos cHtmP8 := fProcuMarc(QRY_SRA->RA_FILIAL, QRY_SRA->RA_MAT, dDataIni, QRY_SRA->RA_HRSMES, QRY_SRA->RA_TNOTRAB, QRY_SRA->RA_SEQTURN, QRY_SRA->RA_CC) cHtmResult += cHtmP8 //Incrementa 1 dia dDataIni := DaySum(dDataIni, 1) EndDo EndIf //Se encontrou informacoes If cHtmResult <> "" //Monta os dados do Funcionario cHtmPC := '<table width=260>' cHtmPC += '<tr>' cHtmPC += '<td><FONT face=tahoma SIZE=1 COLOR=red><b>' cHtmPC += QRY_SRA->RA_MAT + " - " + Alltrim(QRY_SRA->RA_NOME) cHtmPC += '</td>' cHtmPC += '</tr>' //Se for banco de horas If nParam04 == 2 //Se for mostrar o valor do salario/hora If nParam05 == 2 cHtmPC += '<tr>' cHtmPC += '<td BGCOLOR=#F3F3F3 align=right><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Sal. Hora: ' cHtmPC += '</td>' cHtmPC += '<td><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += cValToChar(Round(QRY_SRA->RA_SALARIO / (QRY_SRA->RA_HRSMES + QRY_SRA->RA_HRSEMAN), 2)) cHtmPC += '</td>' cHtmPC += '</tr>' EndIf cHtmPC += '<tr>' cHtmPC += '<td BGCOLOR=#F3F3F3 align=right><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Horas Mes: ' cHtmPC += '</td>' cHtmPC += '<td><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += cValToChar((QRY_SRA->RA_HRSMES + QRY_SRA->RA_HRSEMAN)) cHtmPC += '</td>' cHtmPC += '</tr>' EndIf cHtmPC += '</table>' //Insere os dados no html fHTabLin(@cHtm, { cHtmPC , cHtmResult}, Iif(lImpar, 'DDDDDD', 'FFFFFF'), Nil, -2) lImpar := !lImpar lTemApon := .T. EndIf QRY_SRA->(DbSkip()) EndDo //Se for banco de horas, ira demonstrar um acumulador If nParam04 == 2 cHtmAC := '<table width="100%">' cHtmAC += '<tr BGCOLOR=#F3F3F3>' cHtmAC += '<td align=center height=24 ROWSPAN=2><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmAC += '<b>TOTAL ATE O DIA</b>' cHtmAC += '</td>' cHtmAC += '<td align=center height=24 COLSPAN=3><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'HORAS NORMAIS' cHtmAC += '</td>' If nParam06 == 2 cHtmAC += '<td align=center WIDTH=5 rowspan=99><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += ' ' cHtmAC += '</td>' cHtmAC += '<td align=center height=24 COLSPAN=3><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'HORAS VALORIZADAS' cHtmAC += '</td>' EndIf cHtmAC += '</tr>' cHtmAC += '<tr BGCOLOR=#F3F3F3>' cHtmAC += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'Saldo ' cHtmAC += '</td>' cHtmAC += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'R$ Saldo' cHtmAC += '</td>' cHtmAC += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'Dias Saldo ' cHtmAC += '</td>' If nParam06 == 2 cHtmAC += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'Saldo ' cHtmAC += '</td>' cHtmAC += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'R$ Saldo' cHtmAC += '</td>' cHtmAC += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmAC += 'Dias Saldo ' cHtmAC += '</td>' EndIf cHtmAC += '</tr>' cHtmAC += '<tr>' cHtmAC += '<td><FONT face=tahoma SIZE=1 COLOR=black>' cHtmAC += '<b><center>' + dToC(dDataBase) + '</center></b>' cHtmAC += '</td>' //Horas Normais cHtmAC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black><b>' nSaldoN := nTotHorN cHora := cValToChar(StrZero(Int(nSaldoN), 4)) cMin := cValToChar(StrZero( (Iif(nSaldoN >= 0, nSaldoN - Int(nSaldoN), Int(nSaldoN) - nSaldoN)) * 100, 2)) cHora := cHora + ":" + cMin cHtmAC += cHora cHtmAC += '</td>' cHtmAC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black><b>' If nParam05 == 2 cHtmAC += TRANSFORM(nTotValN, "@E 999, 999.99") EndIf cHtmAC += '</td>' cHtmAC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black><b>' cHtmAC += TRANSFORM(nTotDiaN, "@E 999, 999.9") cHtmAC += '</td>' //Horas valorizadas If nParam06 == 2 cHtmAC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black><b>' nSaldoV := nTotHorV cHora := cValToChar(StrZero(Int(nSaldoV), 4)) cMin := cValToChar(StrZero( (Iif(nSaldoV >= 0, nSaldoV - Int(nSaldoV), Int(nSaldoV) - nSaldoV)) * 100, 2)) cHora := cHora + ":" + cMin cHtmAC += cHora cHtmAC += '</td>' cHtmAC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black><b>' If nParam05 == 2 cHtmAC += TRANSFORM(nTotValV, "@E 999, 999.99") EndIf cHtmAC += '</td>' cHtmAC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black><b>' cHtmAC += TRANSFORM(nTotDiaV, "@E 999, 999.9") cHtmAC += '</td>' EndIf cHtmAC += '</tr>' cHtmAC += '</table>' //Adicionando total geral fHTabLin(@cHtm, { "<br><br><center><b>TOTAL GERAL</b></center> " , cHtmAC}, Iif(lImpar, 'DDDDDD', 'CCCCCC'), Nil, -2) EndIf QRY_SRA->(DbCloseArea()) //Encerrando o html fHTabFin(@cHtm) fHPulaLin(@cHtm, 1) fHTabIni(@cHtm, 0, 2, 0) fHTabLin(@cHtm, {'TOTVS - Mensagem automatica.'}, 'CCCCCC', '000000', -5) fHTabFin(@cHtm) fHCorpoFin(@cHtm) //Se tiver dados, envia o email If lTemApon fEnviarEm(Alltrim(cEmails), "Boletim do Ponto Eletronico - " + Iif(nParam04 == 1, "Marcacoes do Ponto", "Banco de Horas") + " (" + Alltrim(QRY_CTT->CTT_DESC01) + ")", cHTM) EndIf QRY_CTT->(DbSkip()) EndDo QRY_CTT->(DbCloseArea()) Return /*/{Protheus.doc} fProcuBH Funcao para procurar banco de horas @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fProcuBH(cFil, cMat, nSalHor, nHorDia) Local lAchou := .F. Local cHtmDT := "" Local nSaldoN := 0 Local nSaldoV := 0 //Criando os dados do banco de horas cHtmDT := '<table width="100%">' cHtmDT += '<tr BGCOLOR=#F3F3F3>' cHtmDT += '<td align=center height=24 ROWSPAN=2><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'DIA' cHtmDT += '</td>' cHtmDT += '<td align=center height=24 ROWSPAN=2><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'EVENTO' cHtmDT += '</td>' cHtmDT += '<td align=center height=24 COLSPAN=4><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'HORAS NORMAIS' cHtmDT += '</td>' If nParam06 == 2 cHtmDT += '<td align=center WIDTH=5 rowspan=99><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += ' ' cHtmDT += '</td>' cHtmDT += '<td align=center height=24 COLSPAN=4><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'HORAS VALORIZADAS' cHtmDT += '</td>' EndIf cHtmDT += '</tr>' cHtmDT += '<tr BGCOLOR=#F3F3F3>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Qtde. ' cHtmDT += '</td>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Saldo ' cHtmDT += '</td>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'R$ Saldo' cHtmDT += '</td>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Dias Saldo ' cHtmDT += '</td>' If nParam06 == 2 cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Qtde. ' cHtmDT += '</td>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Saldo ' cHtmDT += '</td>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'R$ Saldo' cHtmDT += '</td>' cHtmDT += '<td align=center height=24><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Dias Saldo ' cHtmDT += '</td>' EndIf cHtmDT += '</tr>' //Busca por dados do banco de horas cQuery := " SELECT " + CRLF cQuery += " P9_TIPOCOD, " + CRLF cQuery += " PI_QUANT, " + CRLF cQuery += " PI_QUANTV, " + CRLF cQuery += " P9_CODIGO, " + CRLF cQuery += " P9_DESC " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SPI") + " SPI " + CRLF cQuery += " INNER JOIN " + RetSQLName("SP9") + " SP9 ON SP9.P9_CODIGO = SPI.PI_PD " + CRLF cQuery += " WHERE " + CRLF cQuery += " SPI.PI_FILIAL = '" + cFil + "' " + CRLF cQuery += " AND SPI.PI_MAT = '" + cMat + "' " + CRLF cQuery += " AND SPI.PI_STATUS <> 'B' " + CRLF cQuery += " AND SPI.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND SP9.D_E_L_E_T_ = ' ' " + CRLF cQuery += " ORDER BY SPI.PI_DATA " + CRLF TCQuery cQuery New Alias "QRY_SPI" //Zera os totais nSaldoN := 0 nSaldoV := 0 //Enquanto houver dados DbSelectArea("QRY_SPI") While ! QRY_SPI->(EoF()) //Pegando o saldo normal e o valorizado nSaldoN := Iif(QRY_SPI->P9_TIPOCOD == "1", SomaHoras(QRY_SPI->PI_QUANT , nSaldoN ) , SubHoras( nSaldoN , QRY_SPI->PI_QUANT ) ) nSaldoV := Iif(QRY_SPI->P9_TIPOCOD == "1", SomaHoras(QRY_SPI->PI_QUANTV , nSaldoV ) , SubHoras( nSaldoV , QRY_SPI->PI_QUANTV) ) //Se for analitico If nParam07 == 2 cHtmDT += '<tr>' cHtmDT += '<td><FONT face=tahoma SIZE=1 COLOR=black>' cHtmDT += '<center>' + dToC(STOD(QRY_SPI->PI_DATA)) + '</center>' cHtmDT += '</td>' cHtmDT += '<td><FONT face=tahoma SIZE=1 COLOR=black>' cHtmDT += QRY_SPI->P9_CODIGO cHtmDT += " - " cHtmDT += QRY_SPI->P9_DESC cHtmDT += "<b>" cHtmDT += Iif(QRY_SPI->P9_TIPOCOD == "1", '<font COLOR=blue> + </font> ', '<font COLOR=red> -</font> ') cHtmDT += '</b></td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' //Horas Normais cHora := cValToChar(StrZero(Int(QRY_SPI->PI_QUANT), 4)) cMin := cValToChar(StrZero((QRY_SPI->PI_QUANT - Int(QRY_SPI->PI_QUANT)) * 100, 2)) cHora := cHora + ":" + cMin cHtmDT += cHora cHtmDT += '</td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHora := cValToChar(StrZero(Int(nSaldoN), 4)) cMin := cValToChar(StrZero( (Iif(nSaldoN >= 0, nSaldoN - Int(nSaldoN), Int(nSaldoN) - nSaldoN)) * 100, 2)) cHora := cHora + ":" + cMin cHtmDT += cHora cHtmDT += '</td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' If nParam05 == 2 cHtmDT += TRANSFORM(nSaldoN * nSalHor, "@E 9, 999.99") EndIf cHtmDT += '</td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmDT += TRANSFORM(nSaldoN / nHorDia, "@E 9, 999.9") cHtmDT += '</td>' //Horas Valorizadas If nParam06 == 2 cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHora := cValToChar(StrZero(Int(QRY_SPI->PI_QUANTV), 4)) cMin := cValToChar(StrZero((QRY_SPI->PI_QUANTV - Int(QRY_SPI->PI_QUANTV)) * 100, 2)) cHora := cHora + ":" + cMin cHtmDT += cHora cHtmDT += '</td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHora := cValToChar(StrZero(Int(nSaldoV), 4)) cMin := cValToChar(StrZero( (Iif(nSaldoV >= 0, nSaldoV - Int(nSaldoV), Int(nSaldoV) - nSaldoV)) * 100, 2)) cHora := cHora + ":" + cMin cHtmDT += cHora cHtmDT += '</td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' If nParam05 == 2 cHtmDT += TRANSFORM(nSaldoV * nSalHor, "@E 9, 999.99") EndIf cHtmDT += '</td>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmDT += TRANSFORM(nSaldoV / nHorDia, "@E 9, 999.9") cHtmDT += '</td>' EndIf cHtmDT += '</tr>' EndIf lAchou := .T. QRY_SPI->(DbSkip()) EndDo //Montando o total do funcionario cHtmDT += '<tr>' cHtmDT += '<td colspan=12><FONT face=tahoma SIZE=1 COLOR=black>' cHtmDT += '<hr>' cHtmDT += '</tr>' cHtmDT += '<tr>' cHtmDT += '<td colspan=2><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmDT += '<b>' cHtmDT += Iif(nSaldoN >= 0, '<font COLOR=blue>SALDO ATUAL POSITIVO </font> ', '<font COLOR=red>SALDO ATUAL NEGATIVO </font> ') cHtmDT += '</b></td>' cHtmDT += '<td><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmDT += ' ' cHtmDT += '</td>' cHtmDT += '<td align=center>' cHtmDT += Iif(nSaldoN >= 0, '<font face=tahoma SIZE=1 COLOR=blue><b>', '<font face=tahoma SIZE=1 COLOR=red><b>') cHora := cValToChar(StrZero(Int(nSaldoN), 4)) cMin := cValToChar(StrZero( (Iif(nSaldoN >= 0, nSaldoN - Int(nSaldoN), Int(nSaldoN) - nSaldoN)) * 100, 2)) cHora := cHora + ":" + cMin cHtmDT += cHora cHtmDT += '</td>' cHtmDT += '<td align=center>' If nParam05 == 2 cHtmDT += Iif(nSaldoN >= 0, '<font face=tahoma SIZE=1 COLOR=blue><b>', '<font face=tahoma SIZE=1 COLOR=red><b>') cHtmDT += TRANSFORM(nSaldoN * nSalHor, "@E 9, 999.99") EndIf cHtmDT += '</td>' cHtmDT += '<td align=center>' cHtmDT += Iif(nSaldoN >= 0, '<font face=tahoma SIZE=1 COLOR=blue><b>', '<font face=tahoma SIZE=1 COLOR=red><b>') cHtmDT += TRANSFORM(nSaldoN / nHorDia, "@E 9, 999.9") cHtmDT += '</td>' //Horas valorizadas If nParam06 == 2 cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=BLACK><b>' cHtmDT += ' ' cHtmDT += '</td>' cHtmDT += '<td align=center>' cHtmDT += Iif(nSaldoN >= 0, '<font face=tahoma SIZE=1 COLOR=blue><b>', '<font face=tahoma SIZE=1 COLOR=red><b>') cHora := cValToChar(StrZero(Int(nSaldoV), 4)) cMin := cValToChar(StrZero( (Iif(nSaldoV >= 0, nSaldoV - Int(nSaldoV), Int(nSaldoV) - nSaldoV)) * 100, 2)) cHora := cHora + ":" + cMin cHtmDT += cHora cHtmDT += '</td>' cHtmDT += '<td align=center>' If nParam05 == 2 cHtmDT += Iif(nSaldoN >= 0, '<font face=tahoma SIZE=1 COLOR=blue><b>', '<font face=tahoma SIZE=1 COLOR=red><b>') cHtmDT += TRANSFORM(nSaldoV * nSalHor, "@E 9, 999.99") EndIf cHtmDT += '</td>' cHtmDT += '<td align=center>' cHtmDT += Iif(nSaldoN >= 0, '<font face=tahoma SIZE=1 COLOR=blue><b>', '<font face=tahoma SIZE=1 COLOR=red><b>') cHtmDT += TRANSFORM(nSaldoV / nHorDia, "@E 9, 999.9") cHtmDT += '</td>' EndIf cHtmDT += '</tr>' cHtmDT += '</table>' //Atualizando os totais nTotHorN := SomaHoras(nTotHorN, nSaldoN) nTotValN += nSaldoN * nSalHor nTotDiaN += nSaldoN / nHorDia //Atualizando os totais (valorizados) nTotHorV := SomaHoras(nTotHorV, nSaldoV) nTotValV += nSaldoV * nSalHor nTotDiaV += nSaldoV / nHorDia QRY_SPI->(DbCloseArea()) Return (Iif(lAchou, cHtmDT, "")) /*/{Protheus.doc} fProcuMarc Funcao para procurar marcacoes @author Fabricio Amaro (adaptacao e documentacao por Daniel Atilio) @since 20/02/2020 @version 1.0 /*/ Static Function fProcuMarc(cFil, cMat, cData, cHorMes, cTur, cSeq, cCC, cRec) Local lAchou := .F. Local lAchouApon := .F. Local cHtmP8 := "" Local nCont := 0 Local cHtmDT := "" Local n1E := 0 Local n1S := 0 Local n2E := 0 Local n2S := 0 Local n1EP := 0 Local n1SP := 0 Local n2EP := 0 Local n2SP := 0 Local cHora := "" Local cMin := "" Local lSemMarc := .F. Local cApontInt := "" Local cHoraInt := "" Local cInt Local cTpDia //Inicializa a tabela cHtmDT := '<table width="80">' If !lTemCab cHtmDT += '<tr BGCOLOR=#F3F3F3>' cHtmDT += '<td align=center><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += 'Data' cHtmDT += '</td>' cHtmDT += '</tr>' EndIf cHtmDT += '<tr>' cHtmDT += '<td><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmDT += dToC(cData) + ' - ' + fDiaSemana(cData) cHtmDT += '</td>' cHtmDT += '</tr>' cHtmDT += '</table>' cHtmP8 := '<table width="200">' If !lTemCab cHtmP8 += '<tr BGCOLOR=#F3F3F3>' cHtmP8 += '<td align=center><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmP8 += 'Horario apontado' cHtmP8 += '</td>' cHtmP8 += '</tr>' EndIf cHtmP8 += '<tr>' cHtmP8 += '<td><FONT face=tahoma SIZE=1 COLOR=black>' //Procura as marcacoes cQuery := "SELECT P8_HORA " + CRLF cQuery += "FROM " + RetSQLName("SP8") + " SP8 " + CRLF cQuery += "WHERE SP8.P8_FILIAL = '" + cFil + "' " + CRLF cQuery += " AND SP8.P8_MAT = '" + cMat + "' " + CRLF cQuery += " AND SP8.P8_DATAAPO = '" + dToS(cData) + "' " + CRLF cQuery += " AND SP8.P8_TPMCREP <> 'D' " + CRLF cQuery += " AND SP8.D_E_L_E_T_ = ' ' " + CRLF cQuery += "ORDER BY SP8.P8_DATA, SP8.P8_HORA " + CRLF TCQuery cQuery New Alias "QRY_SP8" //Enquanto houver registros While ! QRY_SP8->(EoF()) cHtmP8 += Iif(nCont == 0, "", " - ") cHtmP8 += Iif(nCont == 0, "", " - ") //Montando a exibicao da hora cHora := cValToChar(StrZero(Int(QRY_SP8->P8_HORA), 2)) cMin := cValToChar(StrZero((QRY_SP8->P8_HORA - Int(QRY_SP8->P8_HORA)) * 100, 2)) cHora := cHora + ":" + cMin cHtmP8 += cHora //Armazenando as marcacoes If nCont == 0 n1E := QRY_SP8->P8_HORA ElseIf nCont == 1 n1S := QRY_SP8->P8_HORA ElseIf nCont == 2 n2E := QRY_SP8->P8_HORA ElseIf nCont == 3 n2S := QRY_SP8->P8_HORA EndIf nCont++ lAchou := .T. QRY_SP8->(DbSkip()) EndDo QRY_SP8->(DbCloseArea()) //Se nao teve marcacoes If nCont == 0 cApontInt += "" //"SEM MARCACAO" lSemMarc := .T. EndIf //Se a marcacao ficou impar, mostra no html If (Mod(nCont, 2)) <> 0 cApontInt += "IMPAR - " lAchouApon := .T. EndIf //Se houve marcacoes If ! lSemMarc //Pesquisa o calendario padrao cQuery := " SELECT " + CRLF cQuery += " PJ_TPDIA, " + CRLF cQuery += " PJ_ENTRA1, " + CRLF cQuery += " PJ_SAIDA1, " + CRLF cQuery += " PJ_ENTRA2, " + CRLF cQuery += " PJ_SAIDA1, " + CRLF cQuery += " PJ_SAIDA2, " + CRLF cQuery += " PJ_INTERV1, " + CRLF cQuery += " PJ_HRSINT1 " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SPJ") + " SPJ" + CRLF cQuery += " WHERE " + CRLF cQuery += " PJ_TURNO = '" + cTur + "' AND SPJ.D_E_L_E_T_ = ' ' " + CRLF cQuery += " AND PJ_SEMANA = '" + cSeq + "' AND PJ_DIA = '" + cValToChar(Dow(cData)) + "'" + CRLF TCQuery cQuery NEW ALIAS "QRY_SPJ" //Pegando o tipo de dia se e trabalhado cInt := "" cTpDia := QRY_SPJ->PJ_TPDIA If cTpDia == "S" n1EP := QRY_SPJ->PJ_ENTRA1 n1SP := QRY_SPJ->PJ_SAIDA1 n2EP := QRY_SPJ->PJ_ENTRA2 n2SP := QRY_SPJ->PJ_SAIDA2 cInt := QRY_SPJ->PJ_INTERV1 nHorIntP := QRY_SPJ->PJ_HRSINT1 EndIf QRY_SPJ->(DbCloseArea()) //Turno com 4 marcacoes If cInt == "S" If nCont < 4 cApontInt += "MARCACAO MENOR QUE O PROGRAMADO" lAchouApon := .T. ElseIf nCont > 4 cApontInt += "MARCACAO MAIOR QUE O PROGRAMADO" lAchouApon := .T. EndIf //Turno com 2 marcacoes Else If nCont < 2 cApontInt += "MARCACAO MENOR QUE O PROGRAMADO" lAchouApon := .T. ElseIf nCont > 2 cApontInt += "MARCACAO MAIOR QUE O PROGRAMADO" lAchouApon := .T. EndIf EndIf //Analisa se a marcacao foi menor ou maior que o programado (somente quando ha intervalo) If cInt == "S" .And. !lAchouApon //Se a segunda entrada passar para o outro dia If n2E < n1S nHorInt := 23.59 - n1S nHorInt := SomaHoras(nHorInt, n2E) nHorInt := SomaHoras(nHorInt, 0.01) Else nHorInt := SubHoras(n2E, n1S) EndIf cHora := cValToChar(StrZero(Int(nHorInt), 2)) cMin := cValToChar(StrZero((nHorInt - Int(nHorInt)) * 100, 2)) cHoraInt := cHora + ":" + cMin EndIf //Se nao for dia trabalhado If ! (cTpDia == "S") cApontInt := "" EndIf EndIf cHtmP8 += '</td>' cHtmP8 += '</tr>' cHtmP8 += '</TABLE>' //Buscando apontamentos no ponto que geraram divergencia do padrao e ainda nao foram abonadas nem informado outro evento cHtmPC := '<table>' If !lTemCab cHtmPC += '<tr BGCOLOR=#F3F3F3>' cHtmPC += '<td align=center width=200><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Descricao do Evento' cHtmPC += '</td>' cHtmPC += '<td align=center width=50><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Qtde.' cHtmPC += '</td>' If nParam10 == 2 cHtmPC += '<td align=center width=80><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Acum. H.E.' cHtmPC += '</td>' EndIf //Colunas de Justificativa If nParam11 == 2 cHtmPC += '<td align=center width=80><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += ' Abonar ' cHtmPC += '</td>' cHtmPC += '<td align=center width=80><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += ' Descontar <br>Folha' cHtmPC += '</td>' cHtmPC += '<td align=center width=100><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Descontar<br>Banco Hora' cHtmPC += '</td>' cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += 'Motivo (descrever) ' cHtmPC += '</td>' EndIf //Eventos ja abonados If nParam12 == 2 cHtmPC += '<td align=center width=200><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += ' EVENTO JA ABONADO ' cHtmPC += '</td>' EndIf //Eventos informados If nParam13 == 2 cHtmPC += '<td align=center width=200><FONT face=tahoma SIZE=1 COLOR=BLACK>' cHtmPC += ' OUTRO EVENTO JA INFORMADO ' cHtmPC += '</td>' EndIf cHtmPC += '</tr>' EndIf //Buscando eventos cQuery := " SELECT " + CRLF cQuery += " PC_QUANTC, " + CRLF cQuery += " PC_PD, " + CRLF cQuery += " P9_DESC " + CRLF cQuery += " FROM " + CRLF cQuery += " " + RetSQLName("SPC") + " SPC " + CRLF cQuery += " INNER JOIN " + RetSQLName("SP9") + " SP9 ON P9_CODIGO = PC_PD AND SP9.D_E_L_E_T_ = ' ' AND P9_DIVERGE = 'S' " + CRLF cQuery += " WHERE " + CRLF cQuery += " SPC.PC_FILIAL = '" + cFil + "' " + CRLF cQuery += " AND SPC.PC_MAT = '" + cMat + "' " + CRLF //Buscando eventos nao abonados If nParam12 == 1 cQuery += "AND SPC.PC_ABONO = ' ' " + CRLF EndIf //Buscando eventos nao informados If nParam13 == 1 cQuery += "AND SPC.PC_PDI = ' ' " + CRLF EndIf //Desconsiderar hora extra If nParam14 == 1 cQuery += "AND SP9.P9_CLASEV <> '01'" + CRLF EndIf cQuery += "AND SPC.PC_DATA = '" + dToS(cData) + "' " + CRLF cQuery += "AND SPC.D_E_L_E_T_ = ' ' " + CRLF TCQuery cQuery New Alias "QRY_SPC" //Se houver dados If ! QRY_SPC->(EoF()) //Enquanto houver dados While ! QRY_SPC->(EoF()) //Montando a exibicao da hora cHora := cValToChar(StrZero(Int(QRY_SPC->PC_QUANTC), 2)) cMin := cValToChar(StrZero((QRY_SPC->PC_QUANTC - Int(QRY_SPC->PC_QUANTC)) * 100, 2)) cHora := cHora + ":" + cMin nHoraExtra := 0 cHtmPC += '<tr>' cHtmPC += '<td width=200><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += QRY_SPC->PC_PD cHtmPC += " - " cHtmPC += QRY_SPC->P9_DESC If !(Empty(cApontInt)) cHtmPC += "<br><FONT color=red>" + cApontInt + "</font><br>" EndIf cHtmPC += '</td>' cHtmPC += '<td align=center width=50 valign=top><FONT face=tahoma SIZE=1 COLOR=black>' If !(Empty(cApontInt)) cHtmPC += "<br><FONT color=red>" + cHoraInt + "</font><br>" EndIf cHtmPC += '</td>' //Acumulado de horas extras If nParam10 == 2 nHoraExtra := 0 cQryHE := " SELECT " + CRLF cQryHE += " PC_QUANTC " + CRLF cQryHE += " FROM " + CRLF cQryHE += " " + RetSQLName("SPC") + " SPC " + CRLF cQryHE += " INNER JOIN " + RetSQLName("SP9") + " SP9 ON ( " + CRLF cQryHE += " SP9.P9_CODIGO = SPC.PC_PD " + CRLF cQryHE += " AND SP9.D_E_L_E_T_ = ' ' " + CRLF cQryHE += " AND SP9.P9_CLASEV = '01' " + CRLF cQryHE += " ) " + CRLF cQryHE += " WHERE " + CRLF cQryHE += " PC_FILIAL = '" + cFil + "' " + CRLF cQryHE += " AND PC_MAT = '" + cMat + "' " + CRLF cQryHE += " AND PC_DATA <= '" + dToS(cData) + "' " + CRLF cQryHE += " AND SPC.D_E_L_E_T_ = ' ' " + CRLF cQryHE += " AND SPC.PC_PDI = ' ' " + CRLF cQryHE += " AND SPC.PC_ABONO = ' ' " + CRLF TCQuery cQryHE New Alias "QRY_HE" //Enquanto houver horas extras While ! QRY_HE->(EoF()) nHoraExtra := SomaHoras(nHoraExtra, QRY_HE->PC_QUANTC) QRY_HE->(DbSkip()) EndDo QRY_HE->(DbCloseArea()) cHoraExtra := "" If nHoraExtra > 0 cHora := cValToChar(StrZero(Int(nHoraExtra), 2)) cMin := cValToChar(StrZero((nHoraExtra - Int(nHoraExtra)) * 100, 2)) cHoraExtra := cHora + ":" + cMin EndIf cHtmPC += '<td align=center width=80><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += cHoraExtra cHtmPC += '</td>' EndIf //Colunas de justificativa If nParam11 == 2 cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += '<font color=red><b>( ) ' cHtmPC += '</td>' cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += '<font color=red><b>( ) ' cHtmPC += '</td>' cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += '<font color=red><b>( ) ' cHtmPC += '</td>' cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += ' <font color=red><b>_ _ ' cHtmPC += '</td>' EndIf If nParam12 == 2 cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += QRY_SPC->PC_ABONO cHtmPC += " - " cHtmPC += POSICIONE("SP6", 1, XFILIAL("SP6") + QRY_SPC->PC_ABONO, "P6_DESC") cHtmPC += '</td>' EndIf If nParam13 == 2 cHtmPC += '<td align=center><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += QRY_SPC->PC_PDI cHtmPC += " - " cHtmPC += POSICIONE("SP9", 1, XFILIAL("SP9") + QRY_SPC->PC_PDI, "P9_DESC") cHtmPC += '</td>' EndIf cHtmPC += '</tr>' lAchouApon := .T. cApontInt := "" QRY_SPC->(DbSkip()) lTemCab := .T. EndDo //Se nao tiver apontamento, mas existir divergencia, sera mostrado ElseIf !(Empty(cApontInt)) cHtmPC += '<tr>' cHtmPC += '<td width=200><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += "<FONT color=red>" + cApontInt + "</font><br>" cHtmPC += '</td>' cHtmPC += '<td align=center width=50 valign=top><FONT face=tahoma SIZE=1 COLOR=black>' cHtmPC += "<FONT color=red>" + cHoraInt + "</font> - <br>" cHtmPC += '</td>' cHtmPC += '</tr>' EndIf QRY_SPC->(DbCloseArea()) //Encerrando o html cHtmPC += '</TABLE>' cHtmTEM := '<table border=0>' cHtmTEM += '<tr>' cHtmTEM += '<td valign=top>' cHtmTEM += cHtmDT cHtmTEM += '</td>' cHtmTEM += '<td valign=top>' cHtmTEM += cHtmP8 cHtmTEM += '</td>' cHtmTEM += '<td valign=top>' cHtmTEM += cHtmPC cHtmTEM += '</td>' cHtmTEM += '</tr>' cHtmTEM += '</TABLE>' Return (Iif(lAchouApon, cHtmTEM, ""))
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Dan,
Tem alguma customização para o envio de contracheques automaticamente para os e-mails cadastrados na SRA de cada funcionário?
Yuri!
Isso é padrão do sistema. No relatório do Recibo de Pagamento, tem a opção E-mail.
Segue TDN: https://tdn.totvs.com/display/public/PROT/MP+-+GPE0601+-+Envio+de+recibo+de+pagamento+por+email
Abs!
Yuri, conforme o Fabricio respondeu, já tem tratativas no padrão do Protheus.
Abraços jovem.