sexta-feira, 23 de outubro de 2015

Protheus e o GRANT de DBA

Protheus e o GRANT de DBA no Oracle

Obs: Faça por conta e risco e em base de testes

Uma das grandes reclamações de empresas é sobre a segurança com o banco de dados. Tenho visto que muitos DBAs, não aceitam que o Protheus precise ter o grant de DBA para poder funcionar corretamente. Sinceramente concordo com isso.
Pessoalmente não gosto de dar todo esse poder, não que ache o Protheus não é confiável, mas, como muitas consultorias e pessoas acabam tendo acesso ao Protheus, é prudente limitar.
Estou em fase de transição de carreira de Analista de Sistemas para DBA Oracle/Sql Server, como trabalho com os dois mundos Protheus e Oracle, procurei uma forma de dar esse acesso sem parar o Protheus.
O teste será feito da seguinte forma :
Versão do DbAcess 4.2 Build 20141119 64 bits
Versão do Oracle 11.2.0.3

Vou deixar o serviço do DBACCESS no modo console para podermos visualizar tudo o que esta ocorrendo.

Subindo o serviço do Dbaccess




Concedendo as permissões

OBS: Recomendo executar este procedimento por um DBA

Caso já tenha concedido o acesso de DBA, faça o revoke

SQL> REVOKE DBA FROM NOME_SCHEMA;


Conceda as permissões, pode ser que o Protheus reclame de outras, se ocorrer, verifique no log do Dbaccess.


Testando a conexão

Note que ocorreu o erro Ambiente, Usuário ou Senha inválido.



O usuário, senha e ambientes não estão inválidos, a resposta do Protheus esta incorreta. Esta é uma mensagem genérica.

Vamos analisar o log do DBACCESS com mais detalhe :



Observando o log de erro acima, o Protheus tentou fazer um select na schema SYS na tabela OBJ$, mas o usuário não tem esse acesso.

O que o Protheus realmente precisa, é acessar as views de dicionário de dados.

Com isso, se der o grant de DBA, o usuário do Protheus consegue ler o conteúdo desta tabela.

Mas é justamente o que não queremos, então vamos dar acesso de leitura com o comando abaixo :



Ok, feito isso, vamos testar novamente


Pronto, revogamos o grant de DBA e o Protheus consegue se conectar.

Mas ainda não acabou..... O grant acima, foi somente para conexão com a base.

Ao tentar acessar o Protheus, os erros continuam....

Vamos dar mais permissões :

GRANT SELECT ON SYS.COLS$ TO NOME_SCHEMA;
GRANT SELECT ON SYS.OBJ$ TO NOME_SCHEMA;
GRANT SELECT ON SYS.ICOL$ TO NOME_SCHEMA;
GRANT SELECT ON V_$SESSION TO NOME_SCHEMA;
GRANT SELECT ON SYS.IND$ TO NOME_SCHEMA;


A permissão V_$SESSION é feita devido ao Protheus tentar dar select na V$SESSION que na verdade é um sinônimo.

Após tudo isso, fiz os seguintes testes no Protheus :
  • Atualizei o TSS -> Sem erros
  • Rodei os compatibilizadores do Protheus -> Sem erros
  • Criei tabela, indices, campos através do SIGACFG -> Sem erros


Se você gostou, clique nos links patrocinados. Obrigado !!!

quinta-feira, 12 de março de 2015

Exemplo pronto do uso da classe FWMSEXCEL

Sobre a classe FWMSEXCEL

A classe FWMSEXCEL tem como finalidade gerar um arquivo XML que posteriormente pode ser utilizado para ser aberto com o Excel.

Nesta classe,  o arquivo Excel fica mais elaborado e pode ser formatado com cores, tipos de dados, abas, etc. Diferentemente do CSV que não possuem nenhum tipo de formatação.

A desvantagem deste formato é que precisa de um Excel 2003 ou acima, além do arquivo ser bem maior do que um simples CSV.

Abaixo estou colando um exemplo completo que utilizei para exportar a planilha.
No site da Totvs (TDN) existe um exemplo bem completo explicando com detalhes o seu funcionamento.

Segue exemplo :

#INCLUDE "PROTHEUS.CH"
#include "TBICONN.CH"
#include "RWMAKE.CH"
#include 'topconn.ch'
#include "TbiCode.ch"

#DEFINE ENTER CHR(13)+CHR(10)
#DEFINE DIVISOR  ";"

USER FUNCTION Ckpt01
Local cQuery    := ""
Local cCaminho  := "\COCKPIT_OFFLINE
Local nConta    := 0
Local nContador := 0
Local cMensagem := ""
Local aEmail    
Local aTables   := { "SM0" }
Local oExcel := FWMSEXCEL():New()

// Montagem das colunas
oExcel:AddworkSheet("Contas a pagar")
oExcel:AddTable ("Contas a pagar","Relação de títulos em aberto",)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Filial",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Prefixo",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Titulo",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Parcela",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Tipo",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Natureza",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Cod.Forn",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Nome do fornecedor",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Emissão",1,4)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Vencimento real",1,4)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Valor do título",1,2)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Valor em reais",1,3)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Data da baixa",1,4)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Histórico do título",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Saldo do título",1,2,.F.)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Moeda",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Número da DI",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Número da PO",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Número da Invoice",1,1)
oExcel:AddColumn("Contas a pagar","Relação de títulos em aberto","Data da Invoice",1,4)

////////////////////

cQuery := "SELECT SE2010.E2_FILIAL, " + ENTER
cQuery += "       SE2010.E2_PREFIXO, " + ENTER
cQuery += "       SE2010.E2_NUM, " + ENTER
cQuery += "       SE2010.E2_PARCELA, " + ENTER
cQuery += "       SE2010.E2_TIPO, " + ENTER
cQuery += "       SE2010.E2_NATUREZ, " + ENTER
cQuery += "       SE2010.E2_FORNECE, " + ENTER
cQuery += "       SE2010.E2_NOMFOR, " + ENTER
cQuery += "       SE2010.E2_EMISSAO, " + ENTER
cQuery += "       SE2010.E2_VENCREA, " + ENTER
cquery += "       SE2010.E2_VALOR, " + ENTER
cQuery += "       SE2010.E2_VLCRUZ," + ENTER
cquery += "       SE2010.E2_BAIXA, " + ENTER
cquery += "       SE2010.E2_HIST, " + ENTER
cquery += "       SE2010.E2_SALDO, " + ENTER
cquery += "       DECODE(SE2010.E2_MOEDA,1,'REAL',2,'DOLAR') E2_MOEDA, " + ENTER
cquery += "       SE2010.E2_NUMDI, " + ENTER
cquery += "       SE2010.E2_NUMPO, " + ENTER
cQuery += "   SE2010.E2_INVOICE, " + ENTER
cQuery += "   SE2010.E2_DTENTRA " + ENTER
cQuery += "  FROM SE2010 SE2010 " + ENTER
cQuery += " WHERE SE2010.E2_SALDO > 0 " + ENTER
cQuery += "   AND SE2010.D_E_L_E_T_ = ' ' "+ ENTER
cQuery += " ORDER BY SE2010.E2_FILIAL, " + ENTER
cQuery += "          SE2010.E2_EMISSAO, " + ENTER
cQuery += "          SE2010.E2_PREFIXO, " + ENTER
cQuery += "          SE2010.E2_NUM, " + ENTER
cQuery += "          SE2010.E2_PARCELA, " + ENTER
cQuery += "          SE2010.E2_TIPO " + ENTER

If Select("QRY") > 0
QRY->( dbCloseArea() )
EndIf
    
//cArquivo := AllTrim(cCaminho) + "\" + "Contas_Pagar_01_" + DTOS(DATE()) + "_.csv"
cArquivo := AllTrim(cCaminho) + "\" + "Contas_Pagar_01_" + DTOS(DATE()) + "_.XML"
    
If !File(ALLTRIM(cArquivo))
    //nHandle :=MSFCreate(ALLTRIM(cArquivo))
Else
    fErase(ALLTRIM(cArquivo))
    Conout("..... Limpando arquivo temporário .....")
    //nHandle:= MSFCreate(ALLTRIM(cArquivo))
Endif
 
ConOut("..... Abrindo tabela temporária ....." )
//RPCSetType( 3 )
//RpcSetEnv ( "01", "01", Nil, Nil, "FAT", Nil, aTables )
    
dbUseArea( .T., "TopConn", TCGenQry(,,cQuery), "QRY", .F., .F. )
    
QRY->(dbEval({|| nConta++})) // Contador de linhas da tabela acima.
QRY->( dbGoTop() )   
    
ConOut("..... Gerando arquivo CSV ....." )
    
// Montagem do cabeçalho do relatório
//cLinha  := "Filial;Prefixo;Titulo;Parcela;Tipo;Natureza;Cod.Forn.;Nome Fornecedor;Data Emissao;Vencimento Real" + ENTER
    
While QRY->( !Eof() )
oExcel:AddRow("Contas a pagar","Relação de títulos em aberto",{AllTrim(QRY->E2_FILIAL),;
AllTrim(QRY->E2_PREFIXO),;
AllTrim(QRY->E2_NUM),;
AllTrim(QRY->E2_PARCELA),;
AllTrim(QRY->E2_TIPO),;
AllTrim(QRY->E2_NATUREZ),;
AllTrim(QRY->E2_FORNECE),;
AllTrim(QRY->E2_NOMFOR),;
AllTrim(u_xSTtoSF(QRY->E2_EMISSAO)),;
AllTrim(u_xSTtoSF(QRY->E2_VENCREA)),;
QRY->E2_VALOR,;
QRY->E2_VLCRUZ,;
AllTrim(u_xSTtoSF(QRY->E2_BAIXA)),;
AllTrim(QRY->E2_HIST),;
QRY->E2_SALDO,;
AllTrim(QRY->E2_MOEDA),;
AllTrim(QRY->E2_NUMDI),;
AllTrim(QRY->E2_NUMPO),;
AllTrim(QRY->E2_INVOICE),;
AllTrim(u_xSTtoSF(QRY->E2_DTENTRA));
})
    nContador ++
    QRY->( dbSkip() )
    ConOut("..... Andamento : " + AllTrim(Str(ROUND(100 / nConta * nContador,2))) + " %")
Enddo

ConOut("..... Salvando arquivo XML  ....." )
oExcel:Activate()
oExcel:GetXMLFile(cArquivo)
   
If Select("QRY") > 0
QRY->( dbCloseArea() )
EndIf
    
//fclose(nHandle)

ConOut("..... Gerando e-mail  ....." )    
// Envia o e-mail para o usuário
cMensagem   := "Email enviado automaticamento pelo Protheus " + ENTER + ENTER
cMensagem   += "Relatório de títulos do contas a pagar emitido dia " + dToc(DATE()) + ENTER + ENTER
cMensagem   += "OBS : ABRIR COM O EXCEL 2003 EM DIANTE OU SIMILAR " + ENTER + ENTER

cMensagem   += "Relatório disponível no caminho \\BONETE\PROTHEUS11\PROTHEUS_DATA" + cArquivo 
    
aEmail := StrTokArr(AllTrim(GetMv("MV_COCKT01")), ";")

for i:=1 to Len(aEmail)
U_xEEmail(cMensagem,"Relatório Cockpit Pagar gerado ",AllTrim(aEmail[i]))
    ConOut("..... Email enviado para " + aEmail[i])
next i
    
RETURN