Páginas filhas
  • Guia de boas práticas - Estrutura de programas

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.
Composition Setup
import.css=/download/attachments/327912/newLayout.css
Portuguese

Pagetitle
Guia de boas práticas - Estrutura de programas
Guia de boas práticas - Estrutura de programas

Documento: Guia de boas práticas - Estrutura de programas

Define as regras de nomeação de programas e as estruturas dos principais programas da Linha Microsiga Protheus


 

A Linha Microsiga Protheus possui um padrão de construção de programa. O padrão inicia-se pelo nome do programa.
Os programas da Linha Microsiga Protheus devem possuir 7 (sete) dígitos e duas extensões possíveis, conforme demonstrado abaixo:

 
XXX Y NNN.PR?

XXX
É o prefixo do módulo da linha Microsiga Protheus, exemplo: GPE para o módulo de Gestão de Pessoal, PON para o módulo de Ponto Eletrônico, FAT para o módulo de Faturamento, etc.
Y
É o código que identifica a operação do programa. Utilize A para programas de formulários ou processamento, C para programas de consulta e R para programas de relatório, X para programas de biblioteca e M para miscelâneas.
NNN
Código seqüencial do programa. Mantenha o padrão de numeração de 10 em 10 e relacione as operações de programa similares. Exemplo: GPEA010 – Cadastros de funcionários, GPEA020 – Cadastro de pessoas, GPEA030 – Cadastro de formulas, GPER010 – Relatório de funcionários, GPER020 – Relatório de pessoas, GPER030 – Relatório de formulas.
III
As três últimas letras identificam a localização de origem do programa. Deve ser utilizado com base na tabela abaixo com as siglas dos países, conforme norma da ISO 3166.
Atenção: A sigla torna-se obrigatória apenas para programas de produtos localizados. Caso contrário a sigla deixa de ser obrigatória.
PR?
Utilizamos dois tipos de extensões para programas, PRG ou PRX. Utilize PRG para programas de interface não gráfica e PRX para programas de interface gráfica.

 Não altere o padrão de nomes ou crie um próprio, várias características do Framework da Linha Microsiga Protheus são ativadas pelo padrão de nomes.





ISO 3166
Pais
3 Letras
Pais
3 Letras
Afeganistão
AFG
Grã-Bretanha (Reino Unido, UK)
GBR
África do Sul
ZAF
Granada
GRD
Albânia
ALB
Grécia
GRC
Alemanha
DEU
Groelândia
GRL
Angola
AGO
Guatemala
GTM
Arábia Saudita
SAU
Haiti
HTI
Argélia
DZA
Holanda
NLD
Argentina
ARG
Honduras
HND
Armênia
ARM
Índia
IND
Austrália
AUS
Indonésia
IDN
Áustria
AUT
Irã
IRN
Bélgica
BEL
Iraque
IRQ
Belize
BLZ
Irlanda
IRL
Bolívia
BOL
Islândia
ISL
Brasil
BRA
Israel
ISR
Canadá
CAN
Itália
ITA
Chile
CHL
Jamaica
JAM
China
CHN
Japão
JPN
Cingapura
SGP
Marrocos
MAR
Colômbia
COL
México
MEX
Congo
COG
Moçambique
MOZ
Coréia do Norte
PRK
Nicarágua
NIC
Coréia do Sul
KOR
Nigéria
NGA
Costa do Marfim
CIV
Noruega
NOR
Costa Rica
CRI
Nova Zelândia
NZL
Cuba
CUB
Panamá
PAN
Dinamarca
DNK
Paraguai
PRY
Egito
EGY
Peru
PER
El Salvador
SLV
Polinésia Francesa
PYF
Emirados Árabes Unidos
ARE
Polônia
POL
Equador
ECU
Porto Rico
PRI
Eslováquia
SVK
Portugal
PRT
Eslovênia
SVN
Rep Dominicana
DOM
Espanha
ESP
República Tcheca
CZE
Estados Unidos
USA
Romênia
ROM
Estônia
EST
Suécia
SWE
Etiópia
ETH
Suíça
CHE
Filipinas
PHL
Trinidad and Tobago
TTO
Finlândia
FIN
Uganda
UGA
França
FRA
Uruguai
URY
                                             

Padrão de construção para programas de formulário
Os programas de formulário são divididos em seis seções, a saber:
·         Seção do Browse
·         Seção do Menu de operações da rotina
·         Seção da Regra de negócio
·         Seção da Interface
·         Seção de Validação
·         Seção Opcional de gravação
·         Seção Opcional das demais funcionalidades do formulário
Na Seção do Browse definimos o Alias principal do formulário, a descrição da rotina e outras opções relativas ao modo de visualização dos registros da tabela, tais como: Filtros, Perguntas, Legenda e Opções do padrão de operação disponíveis.
User Function COMP023_MVC()
Local oBrowse
 
oBrowse := FWmBrowse():New()
oBrowse:SetAlias( 'ZA3' )
oBrowse:SetDescription( 'Albuns' )
oBrowse:Activate()
 
Return NIL
 
Tenha por hábito utilizar legendas no Browse caso haja sinalizadores no Browse. Por padrão devem-se utilizar  cores disponíveis por framework (BR_AMARELO, BR_AZUL, BR_BRANCO, BR_CINZA, BR_LARANJA, BR_MARRON, BR_PINK, BR_PRETO, BR_VERDE, BR_VERMELHO, entre outros). Cores adicionais podem causar problemas para daltônicos.
Na Seção do Menu de operações da rotina definimos quais operações estarão disponível para o usuário final. As opções mais comuns são: Pesquisa, Inclusão, Alteração, Visualização e Exclusão.
Static Function MenuDef()
Local aRotina := {}
 
ADD OPTION aRotina Title 'Pesquisar' Action 'PesqBrw'             OPERATION 1 ACCESS 0
ADD OPTION aRotina Title 'Visualizar' Action 'VIEWDEF.COMP023_MVC' OPERATION 2 ACCESS 0
ADD OPTION aRotina Title 'Incluir'    Action 'VIEWDEF.COMP023_MVC' OPERATION 3 ACCESS 0
ADD OPTION aRotina Title 'Alterar'    Action 'VIEWDEF.COMP023_MVC' OPERATION 4 ACCESS 0
ADD OPTION aRotina Title 'Excluir'    Action 'VIEWDEF.COMP023_MVC' OPERATION 5 ACCESS 0
ADD OPTION aRotina Title 'Imprimir'   Action 'VIEWDEF.COMP023_MVC' OPERATION 8 ACCESS 0
ADD OPTION aRotina Title 'Copiar'     Action 'VIEWDEF.COMP023_MVC' OPERATION 9 ACCESS 0
 
Return aRotina
 
Na Seção da Regra de negócio definimos a estrutura do formulário, como as tabelas dele se relacionam e quais são as funções de validação para cada estrutura e para todo o formulário. Tenha como háito inserir  a validação correta em cada uma das estruturas.
Na validação de campo, valide apenas o campo e evite validar mais de um campo no mesmo bloco. Na validação da estrutura de campos, valide as dependências dos campos da estrutura. Na validação do formulário, valide a dependência das estruturas do formulário. Não há necessidade de repetição de validação.
Esta seção é utilizada para muitos fins e evolui constantemente, por conta disto ela não deve ter chamadas de interface e os campos podem ser informados em qualquer ordem e não necessariamente na ordem esperada, por isto a regra de validação citada acima é tão importante. Proteja o seu código dos eventos que um usuário possa realizar.
Static Function ModelDef()
// Cria a estrutura a ser usada no Modelo de Dados
Local oStruZA3 := FWFormStruct( 1, 'ZA3', /*bAvalCampo*/, /*lViewUsado*/ )
Local oStruZA4 := FWFormStruct( 1, 'ZA4', /*bAvalCampo*/, /*lViewUsado*/ )
Local oStruZA5 := FWFormStruct( 1, 'ZA5', /*bAvalCampo*/, /*lViewUsado*/ )
Local oModel
 
// Cria o objeto do Modelo de Dados
oModel := MPFormModel():New( 'COMP023M', /*bPreValidacao*/, /*bPosValidacao*/, /*bCommit*/, /*bCancel*/ )
 
// Adiciona ao modelo uma estrutura de formulário de edição por campo
oModel:AddFields( 'ZA3MASTER', /*cOwner*/, oStruZA3 )
 
// Adiciona ao modelo uma estrutura de formulário de edição por grid
oModel:AddGrid( 'ZA4DETAIL', 'ZA3MASTER', oStruZA4, /*bLinePre*/, /*bLinePost*/, /*bPreVal*/, /*bPosVal*/, /*BLoad*/ )
//oModel:AddGrid( 'ZA5DETAIL', 'ZA4DETAIL', oStruZA5, /*bLinePre*/, /*bLinePost*/, /*bPreVal*/, /*bPosVal*/, /*BLoad*/ )
oModel:AddGrid( 'ZA5DETAIL', 'ZA4DETAIL', oStruZA5, { |oMdlG,nLine,cAcao,cCampo| COMP023LPRE( oMdlG, nLine, cAcao, cCampo ) }, /*bLinePost*/, /*bPreVal*/, /*bPosVal*/, /*BLoad*/ )
 
// Faz relaciomaneto entre os compomentes do model
oModel:SetRelation( 'ZA4DETAIL', { { 'ZA4_FILIAL', 'xFilial( "ZA4" )' }, { 'ZA4_ALBUM' , 'ZA3_ALBUM' } } , ZA4->( IndexKey( 1 ) ) )
oModel:SetRelation( 'ZA5DETAIL', { { 'ZA5_FILIAL', 'xFilial( "ZA5" )' }, { 'ZA5_ALBUM' , 'ZA3_ALBUM' }, { 'ZA5_MUSICA', 'ZA4_MUSICA' } } , ZA5->( IndexKey( 1 ) ) )
 
// Liga o controle de não repetição de linha
oModel:GetModel( 'ZA4DETAIL' ):SetUniqueLine( { 'ZA4_MUSICA' } )
oModel:GetModel( 'ZA5DETAIL' ):SetUniqueLine( { 'ZA5_INTER' } )
 
// Adiciona a descrição do Modelo de Dados
oModel:SetDescription( 'Modelo de Albuns' )
 
// Adiciona a descrição do Componente do Modelo de Dados
oModel:GetModel( 'ZA3MASTER' ):SetDescription( 'Dados do Album' )
oModel:GetModel( 'ZA4DETAIL' ):SetDescription( 'Dados das Musicas do Album' )
oModel:GetModel( 'ZA5DETAIL' ):SetDescription( 'Interpretes das Musicas do Album' )
 
Return oModel
 
Na seção de interface definimos os elementos gráficos que serão utilizados no formulário e a relação que estes elementos têm, como a seção de regra de negócio. Os elementos gráficos mais comuns são a FormField e a FormGrid. Apesar desta seção permitir outros elementos gráficos, evite utilizá-los, durante as constantes mudanças de versão e release da linha Microsiga Protheus pode haver necessidade de retrabalho, o que não ocorre para os elementos do Framework citados. Outra razão para não usar outros elementos gráficos está na dificuldade de customização lembre-se que o maior argumento de venda da Linha Microsiga Protheus é a flexibilidade, sendo assim uma interface não flexível irá causar retrabalho por solicitação do cliente.
//-------------------------------------------------------------------
Static Function ViewDef()
// Cria a estrutura a ser usada na View
Local oStruZA3 := FWFormStruct( 2, 'ZA3' )
Local oStruZA4 := FWFormStruct( 2, 'ZA4' )
Local oStruZA5 := FWFormStruct( 2, 'ZA5' )
// Cria um objeto de Modelo de Dados baseado no ModelDef do fonte informado
Local oModel   := FWLoadModel( 'COMP023_MVC' )
Local oView
 
 
// Remove campos da estrutura
oStruZA4:RemoveField( 'ZA4_ALBUM' )
oStruZA5:RemoveField( 'ZA5_ALBUM' )
oStruZA5:RemoveField( 'ZA5_MUSICA' )
 
// Cria o objeto de View
oView := FWFormView():New()
 
// Define qual o Modelo de dados a ser utilizado
oView:SetModel( oModel )
 
//Adiciona no nosso View um controle do tipo FormFields(antiga enchoice)
oView:AddField( 'VIEW_ZA3', oStruZA3, 'ZA3MASTER' )
 
//Adiciona no nosso View um controle do tipo FormGrid(antiga newgetdados)
oView:AddGrid( 'VIEW_ZA4', oStruZA4, 'ZA4DETAIL' )
oView:AddGrid( 'VIEW_ZA5', oStruZA5, 'ZA5DETAIL' )
 
// Criar "box" horizontal para receber algum elemento da view
oView:CreateHorizontalBox( 'EMCIMA' , 20 )
oView:CreateHorizontalBox( 'MEIO'   , 40 )
oView:CreateHorizontalBox( 'EMBAIXO', 40 )
 
// Criar "box" vertical para receber algum elemento da view
//oView:CreateVerticalBox( 'EMBAIXODIR', 80, 'EMBAIXO' )
//oView:CreateVerticalBox( 'EMBAIXOESQ', 20, 'EMBAIXO' )
 
// Relaciona o ID da View com o "box" para exibição
oView:SetOwnerView( 'VIEW_ZA3', 'EMCIMA'   )
oView:SetOwnerView( 'VIEW_ZA4', 'MEIO'     )
oView:SetOwnerView( 'VIEW_ZA5', 'EMBAIXO' )
//oView:SetOwnerView( 'VIEW_ZA5', 'EMBAIXODIR' )
 
// Liga a identificação do componente
oView:EnableTitleView( 'VIEW_ZA3' )
oView:EnableTitleView( 'VIEW_ZA4', "MÚSICAS DO ÁLBUM", RGB( 224, 30, 43 ) )
oView:EnableTitleView( 'VIEW_ZA5', "INTERPRETES DAS MÚSICAS", 0 )
 
// Liga a Edição de Campos na FormGrid
//oView:SetViewProperty( 'VIEW_ZA4', "ENABLEDGRIDDETAIL", { 60 } )
//oView:SetViewProperty( 'VIEW_ZA5', "ENABLEDGRIDDETAIL", { 60 } )
 
// Acrescenta um objeto externo ao View do MVC
// AddOtherObject(cFormModelID,bBloco)
// cIDObject - Id
// bBloco    - Bloco chamado evera ser usado para se criaros objetos de tela externos ao MVC.
 
//oView:AddOtherObject("OTHER_PANEL", {|oPanel| COMP23BUT(oPanel)})
//oView:SetOwnerView("OTHER_PANEL",'EMBAIXOESQ')
Return oView
 
Na seção de validação,  você deve inserir todas as funções utilizadas para validação dos formulários. Tenha por padrão, incluir uma validação para cada campo das tabelas e privilegie as funções de framework existentes, tais como: ExistCPO(), ExistChav(), Vazio(), NaoVazio(), Texto(), CGC(), Pertence(), Positivo()¸etc. Evite usar estas funções encapsuladas em uma função, é importante que elas estejam  explícitas no dicionário de dados, para que o Framework consiga traduzir o seu significado e apresentar um texto coerente para o usuário quando a função help for acionada.
A validação do campo deve ter como escopo somente a sua validação e nenhuma dependência de outro campo. Caso necessário utilize os atributos de Gatilho e AddRules do dicionário de dados e evite simulá-los através de linhas de código própria. Para tratar as validações com dependência de campos, exemplo: banco, agência e conta, utilize a validação da estrutura do formulário que ela é necessária, além de um volume menor de código, reduz-se a possibilidade de bug. O usuário pode freqüentemente digitar os três campos na seqüência e alterar algum aleatoriamente, prever isto é uma tarefa tediosa e sem ganho em usabilidade.
Tenha por costume nomear as estruturas de validação do formulário seguindo o padrão abaixo:
·         Validação da estrutura FormField: *TudOk(), *TdOk() ou *tOk()
·         Validação da estrutura FormGrid: *LinOk(), *LnOk() ou LOk() para validação das linhas do grid e *TudOk(), *TdOk() ou *tOk() para validação de todas as linhas.
·         Validação do Formulário: *TudOk(), *TdOk() ou *tOk()
Separe muito bem aquilo que deve ser validado em uma linha da estrutura do FormGrid e aquilo que deve ser validado considerando-se todas as linhas. Apesar de parecer trivial, não considerar isto, tem sido um grande fator de retrabalho nos formulários que apresentam a estrutura FormGrid por conta da lentidão que acarreta quando há um número grande de linhas no formulário.
Por fim, considere aquilo que deve ser validado somando-se as estruturas existentes no formulário.
Na seção opcional de Gravação, crie funções do tipo Trigger. Gatilho ou Trigger é um recurso de programação executado sempre que o evento associado ocorrer. Trigger é um tipo especial de procedimento armazenado, que é executado sempre que há uma tentativa de modificar os dados de uma tabela que é protegida por ele.
É muito utilizada para ajudar a manter a consistência dos dados ou para propagar alterações em um determinado dado de uma tabela para outras. Um bom exemplo é um gatilho criado para controle de quem alterou a tabela, nesse caso, quando a alteração for efetuada, o gatilho é "disparado" e grava em uma tabela de histórico de alteração, o usuário e data/hora da alteração.
No padrão MVC os Triggers são chamados sempre que um registro do formulário do Model for atualizado, neste caso o Trigger é executado antes e depois do evento.
Não confunda os Triggers disparados pelo Model com os disparados pela interface View  e contidos no dicionário de dados. Um tem a função de preencher um campo segundo uma regra e ou outro de atualizar os dados dentro de uma transação.
O padrão MVC de formulário adotado pela Linha Microsiga Protheus realiza a gravação de todos os dados apresentados no Model do formulário, cabe o desenvolvedor realizar a gravação dos acumulados ou fazer as tarefas de regra de negócio. Como exemplo, podemos citar o Pedido de Venda ( MATA410 ). O framework do padrão MVC consegue gravar as tabelas SC5 – Cabeçalho do Pedido de Venda e SC6 – Itens do Pedido de Venda, porém falta realizar a gravação do SB2 – Saldos em estoque, SA1 – Cadastro de Cliente e SC9 – Itens liberados do Pedido de Venda. SB2 e SA1 são atualizados por conta de dados estatísticos, já o SC9 possui toda uma regra para liberar o pedido, sendo disparado pela gravação de um campo no item do pedido de venda – C6_QTDLIB.
Para realizar esta operação, recomenda-se a criação de uma função do tipo Trigger, conforme citado acima. Esta função tem disponível o registro da tabela que acabou de ser gravado, a operação que foi realizada ( Inclusão, Alteração ou Exclusão ) e o momento da chamada ( Antes ou Depois ). Isto possibilita ao desenvolvedor fazer as tratativas corretas em diversas situações. Continuando em nosso exemplo, para realizar as atualizações complementares do pedido de venda, o desenvolvedor poderia criar a função MaAvalSC6(nOperation, lEstorna). Esta função seria chamada antes e depois de gravar a tabela SC6. Quando for chamada antes e não for uma inclusão, ela poderia estornar os dados estatísticos e as regras de negócio realizadas com o registro da tabela, haja vista que nenhuma operação de gravação foi feita. Chamada após a gravação da tabela SC6, ela poderia atualizar os dados estatísticos e as regras de negócio dos novos dados.
Por fim, as funções do tipo Trigger contam apenas com os dados dos registros do formulário, não utilize variáveis de memória e/ou evite utilizar variáveis de ambiente.
Na Seção Opcional das demais funcionalidades do formulário crie as funções complementares da interface VIEW, tais como novos botões na barra de ferramenta ou outros componentes específicos da interface.

 

Padrão de construção para programas de Consulta
Não há um padrão para a estrutura dos programas de consulta, dando ao desenvolvedor liberdade para utilizar a sua criatividade. Porém algumas regras devem ser seguidas:
·         Consultas de formulário devem seguir o paarão dos programas de formulário, exemplo para aquelas aplicadas na gravação e validação.
·         As interfaces de consulta devem ser rápidas, portanto se há procedimentos que demandam tempo, mas são opcionais, elas devem ser acionadas sob demanda, através de um botão na interface e ter uma régua de processamento para indicar ao usuário uma expectativa de tempo, bem como a opção para cancelar a operação.
·         O uso do objeto TreeView deve ser evitado e somente poderá ser utilizado se o número de elementos definidos em todos os seus níveis for pequeno e não tende a crescer conforme a base de dados.
·         Consultas que exportem dados devem seguir as regras de privilégio do cadastro de usuários.
Padrão de construção para programas de Relatórios
Os programas de relatório são divididos em três seções e dois tipos, a saber:
·         Personalizáveis
o   Seção de inicialização
o   Seção de definição do relatório
o   Seção de impressão
·         Não personalizáveis ou customizados
o   Seção de definição do relatório
o   Seção de impressão
Um relatório da linha Microsiga Protheus pode ser de dois tipos (Personalizáveis e Não personalizáveis), conforme a necessidade de impressão. Porém, os não personalizáveis devem ser utilizados apenas para manutenção do legado e em desenvolvimentos específicos, em que o cliente não pode alterar o layout do relatório, como os relatórios legais ( DANFe, P1/P2/P8/P9, Diário Geral, Razão Contábil, etc.).
Relatórios Personalizáveis
Na seção de inicialização dos relatórios personalizáveis, deve-se  verificar se o relatório possui o tipo Não personalizável disponível e fazemos as chamadas apropriadas conforme o caso.
Function ()
 
Local oReport
If FindFunction("TRepInUse") .And. TRepInUse()
                //---------------------------------------
                // Interface de impressao
                //---------------------------------------
                oReport := ReportDef()
                oReport:PrintDialog()
Else
                R3()
EndIf
Return
 
Na seção de definição do relatório, devem ser criados  os componentes de impressão, as seções e as células, os totalizadores e demais componentes que o usuário poderá personalizar no relatório.
Os dados fornecidos nesta seção são utilizados para montagem da interface padrão do relatório.
Static Function ReportDef()
 
Local oReport
 
//---------------------------------------
//Criacao do componente de impressao                                      
//---------------------------------------
// TReport():New                                                            
// ExpC1 : Nome do relatorio                                                
// ExpC2 : Titulo                                                           
// ExpC3 : Pergunte                                                         
// ExpB4 : Bloco de codigo que sera executado na confirmacao da impressao  
// ExpC5 : Descricao                                                        
//                                                                          
//---------------------------------------
oReport := TReport():New(/*Nome do Relatório*/,/*Titulo do Relatório*/,/*Pergunte*/, {|oReport| ReportPrint(oReport)},/*Descricao do relatório*/)
//oReport:SetLandscape()
oReport:SetTotalInLine(.F.)
Pergunte(oReport:uParam,.F.)
//---------------------------------------
// Criacao da secao utilizada pelo relatorio                                
//                                                                          
// TRSection():New                                                          
// ExpO1 : Objeto TReport que a secao pertence                              
// ExpC2 : Descricao da seçao                                               
// ExpA3 : Array com as tabelas utilizadas pela secao. A primeira tabela    
//         sera considerada como principal para a seção.                    
// ExpA4 : Array com as Ordens do relatório                                 
// ExpL5 : Carrega campos do SX3 como celulas                               
//         Default : False                                                  
// ExpL6 : Carrega ordens do Sindex                                         
//         Default : False                                                  
//                                                                          
//---------------------------------------
//---------------------------------------
// Criacao da celulas da secao do relatorio                                 
//                                                                          
// TRCell():New                                                             
// ExpO1 : Objeto TSection que a secao pertence                             
// ExpC2 : Nome da celula do relatório. O SX3 será consultado               
// ExpC3 : Nome da tabela de referencia da celula                           
// ExpC4 : Titulo da celula                                                 
//         Default : X3Titulo()                                             
// ExpC5 : Picture                                                          
//         Default : X3_PICTURE                                             
// ExpC6 : Tamanho                                                          
//         Default : X3_TAMANHO                                             
// ExpL7 : Informe se o tamanho esta em pixel                               
//         Default : False                                                  
// ExpB8 : Bloco de código para impressao.                                  
//         Default : ExpC2                                                  
//                                                                          
//---------------------------------------
oSection := TRSection():New(/*oReport*/,/*Nome da secao*/,/*{Tabelas da secao}*/,/*{Array com as ordens do relatório}*/,/*Campos do SX3*/,/*Campos do SIX*/)
oSection:SetTotalInLine(.F.)
TRCell():New(/*oSection*/,/*X3_CAMPO*/,/*Tabela*/,/*Titulo*/,/*Picture*/,/*Tamanho*/,/*lPixel*/,/*{|| code-block de impressao }*/)
TRFunction():New(oSection:Cell(/*X3_CAMPO*/),/* cID */,"SUM",/*oBreak*/,/*cTitle*/,/*cPicture*/,/*uFormula*/,/*lEndSection*/,.F./*lEndReport*/,/*lEndPage*/)
 
oSection2 := TRSection():New(oSection,/*Nome da secao*/,/*{Tabelas da secao}*/,/*{Array com as ordens do relatório}*/,/*Campos do SX3*/,/*Campos do SIX*/)
oSection2:SetTotalInLine(.F.)
TRCell():New(/*oSection2*/,/*X3_CAMPO*/,/*Tabela*/,/*Titulo*/,/*Picture*/,/*Tamanho*/,/*lPixel*/,/*{|| code-block de impressao }*/)
TRFunction():New(oSection2:Cell(/*X3_CAMPO*/),/* cID */,"SUM",/*oBreak*/,/*cTitle*/,/*cPicture*/,/*uFormula*/,/*lEndSection*/,.F./*lEndReport*/,/*lEndPage*/)
 
Return(oReport)
 
Na seção de impressão, deve-se  controlar  o fluxo do relatório, executar as query´s, filtros e  a ordenação definido pelos parâmetros do relatório.
Os parâmetros do relatório devem ser criados utilizando-se o Cadastro de Perguntas do dicionário de dados da Linha Microsiga Protheus (SX1). O não uso do dicionário pode criar problemas em agendamentos do relatório, bem como outras características do produto.
Static Function ReportPrint(oReport)
Local cAliasQry := ""
Local lQuery    := .F.
#IFNDEF TOP
                Local cCondicao := ""
#ENDIF
//---------------------------------------
// Transforma parametros Range em expressao SQL                             
//---------------------------------------
MakeSqlExpr(oReport:uParam)
//---------------------------------------
// Filtragem do relatório                                                   
//---------------------------------------
#IFDEF TOP
                //---------------------------------------
                // Query do relatório da secao 1                                            
                //---------------------------------------
                lQuery := .T.
                oReport:Section(1):BeginQuery()        
                BeginSql Alias cAliasQry
                SELECT *
                FROM %table:% XXX,%table:% YYY
                WHERE XXX_FILIAL = %xFilial:XXX% AND
                               XXX.%NotDel% AND
                               YYY_FILIAL = %xFilial:XXX% AND
                               YYY.%NotDel%
                ORDER BY DAK_COD,DAK_SEQCAR,DAI_SEQUEN,DAI_PEDIDO
                EndSql
                //---------------------------------------
                // Metodo EndQuery ( Classe TRSection )                                     
                // Prepara o relatório para executar o Embedded SQL.                        
                // ExpA1 : Array com os parametros do tipo Range                            
                //---------------------------------------
                oReport:Section(1):EndQuery(/*Array com os parametros do tipo Range*/)                  
#ELSE
                dbSelectArea(cAliasQry)
                dbSetOrder(1)
                cCondicao := 'XXX_FILIAL == "'+xFilial("XXX")+'" '
                oReport:Section(1):SetFilter(cCondicao,IndexKey())          
                oReport:Section(1):Section(1):SetRelation(/*{|| cExpSeek }*/,/*cAlias*/,/*Order*/,/*lSeek*/)
                oReport:Section(1):Section(1):SetParentFilter(/*{|| lQuery}*/)
#ENDIF                  
//---------------------------------------
// Metodo TrPosition()                                                      
// Posiciona em um registro de uma outra tabela. O posicionamento será      
// realizado antes da impressao de cada linha do relatório.                 
// ExpO1 : Objeto Report da Secao                                           
// ExpC2 : Alias da Tabela                                                  
// ExpX3 : Ordem ou NickName de pesquisa                                    
// ExpX4 : String ou Bloco de código para pesquisa. A string será macroexe-
//         cutada.                                                          
//---------------------------------------
TRPosition():New(oReport:Section(1),/*cAlias*/,/*nOrder*/,/*{|| cSeek }*/)
//---------------------------------------
// Inicio da impressao do fluxo do relatório                                
//---------------------------------------
oReport:SetMeter(cAliasQry->(LastRec()))
If Mod1
                oReport:Section(1):Print()
Else
                dbSelectArea(cAliasQry)
                While !oReport:Cancel() .And. !(cAliasQry)->(Eof())
                               oReport:Section(1):Section(1):Init()
                               oReport:Section(1):Section(1):PrintLine()
                               oReport:Section(1):Section(1):Finish()
                               dbSelectArea(cAliasDAI)
                               dbSkip()
                               oReport:IncMeter()
                EndDo
                oReport:Section(1):Finish()  
                oReport:Section(1):SetPageBreak(.T.)
EndIf
Return
 
Relatórios Não Personalizáveis
Os relatórios não personalizáveis podem ser criados utilizando-se a TMsPrinter para os relatórios gráficos e o par de funções SetPrint/SetDefault para os não-graficos.
Independente do método utilizado, os relatórios deste tipo devem utilizar o Cadastro de Perguntas do dicionário de dados da Linha Microsiga Protheus (SX1).
Segue exemplo de uma estrutura de relatório não-gráfico:
#INCLUDE "PROTHEUS.CH"
#DEFINE CHRCOMP If(aReturn[4]==1,15,18)
 
Function ()
 
//----------------------------------------------------------------------------------------------------
// Define Variaveis                                                         
//----------------------------------------------------------------------------------------------------
Local Titulo := STR0001 //"" // Titulo do Relatorio
Local cDesc1 := STR0002 //"" // Descricao 1
Local cDesc2 := STR0003 //"" // Descricao 2
Local cDesc3 := STR0004 //"" // Descricao 3
Local cString := "" // Alias utilizado na Filtragem
Local lDic    := .F. // Habilita/Desabilita Dicionario
Local lComp   := .T. // Habilita/Desabilita o Formato Comprimido/Expandido
Local lFiltro := .T. // Habilita/Desabilita o Filtro
Local wnrel   := ""  // Nome do Arquivo utilizado no Spool
Local nomeprog:= "" // nome do programa
 
Private Tamanho := "G" // P/M/G
Private Limite := 220 // 80/132/220
Private aOrdem := {} // Ordem do Relatorio
Private cPerg   := "" // Pergunta do Relatorio
Private aReturn := { STR0005, 1,STR0006, 1, 2, 1, "",1 } //"Zebrado"###"Administracao"
                                                                                              //[1] Reservado para Formulario
                                                                                              //[2] Reservado para N§ de Vias
                                                                                              //[3] Destinatario
                                                                                              //[4] Formato => 1-Comprimido 2-Normal
                                                                                              //[5] Midia   => 1-Disco 2-Impressora
                                                                                              //[6] Porta ou Arquivo 1-LPT1... 4-COM1...
                                                                                              //[7] Expressao do Filtro
                                                                                              //[8] Ordem a ser selecionada
                                                                                              //[9]..[10]..[n] Campos a Processar (se houver)
 
Private lEnd    := .F.// Controle de cancelamento do relatorio
Private m_pag   := 1 // Contador de Paginas
Private nLastKey:= 0 // Controla o cancelamento da SetPrint e SetDefault
 
//----------------------------------------------------------------------------------------------------
// Verifica as Perguntas Seleciondas                                        
//----------------------------------------------------------------------------------------------------
Pergunte(cPerg,.F.)
//----------------------------------------------------------------------------------------------------
// Envia para a SetPrinter                                                  
//----------------------------------------------------------------------------------------------------
wnrel:=SetPrint(cString,wnrel,cPerg,@titulo,cDesc1,cDesc2,cDesc3,lDic,aOrdem,lComp,Tamanho,,lFiltro)
If ( nLastKey==27 )
                dbSelectArea(cString)
                dbSetOrder(1)
                Set Filter to
                Return
Endif
SetDefault(aReturn,cString)
If ( nLastKey==27 )
                dbSelectArea(cString)
                dbSetOrder(1)
                Set Filter to
                Return
Endif
RptStatus({|lEnd| ImpDet(@lEnd,wnRel,cString,nomeprog,Titulo)},Titulo)
Return(.T.)
 
Static Function ImpDet(lEnd,wnrel,cString,nomeprog,Titulo)
 
Local li      := 100 // Contador de Linhas
Local lImp    := .F. // Indica se algo foi impresso
Local cbCont := 0   // Numero de Registros Processados
Local cbText := "" // Mensagem do Rodape
//
//                          1         2         3         4         5         6         7         8         9        10        11        12        13        14        15        16        17        18        19        20        21        22
//                01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
Local cCabec1
Local cCabec2
dbSelectArea(cString)
SetRegua(LastRec())
dbSetOrder(1)
dbSeek(xFilial())
 
While ( !Eof() .And. xFilial()== )
                lImp := .T.
                If lEnd
                               @ Prow()+1,001 PSAY STR0007 //"CANCELADO PELO OPERADOR"
                               Exit
                EndIf
                If ( li > 58 )
                               li := cabec(Titulo,cCabec1,cCabec2,nomeprog,Tamanho,CHRCOMP)
                               li++
                Endif
 
                dbSelectArea(cString)
                dbSkip()
                cbCont++
                IncRegua()
EndDo
 
If ( lImp )
                Roda(cbCont,cbText,Tamanho)
EndIf
 
Set Device To Screen
Set Printer To
If ( aReturn[5] = 1 )
                dbCommitAll()
                OurSpool(wnrel)
Endif
MS_FLUSH()
Return(.T.)
Padrão de construção para programas de Processamento
Durante os anos esta foi à estrutura que mais evolui na Linha Microsiga Protheus, no momento focaremos apenas no ultimo padrão.
Os programas de processamento tem uma estrutura simples, formada por três elementos a saber:
·         Setup
·         Processamento
·         Agendamento
No Setup demonstra-se a interface padrão fornecida pela função FWGridProcess. Cabe ao desenvolvedor preencher corretamente os parâmetros da rotina.
A montagem desta interface é feita com base no dicionário de dados e pode variar conforme o caso. A apresentação dos parâmetros do dicionário de dados – SX6 e tabelas padrões – SX5 estão vinculados ao cadastramento da rotina no TOTVSPARAM, responsável pela sincronização das rotinas e parâmetros envolvidos.
É possível definir até cinco réguas de processamento, porém recomenda-se não usar mais do que duas réguas.
Function testeba()
oGrid:=FWGridProcess():New("MATA330","teste","teste do processamento",{|lEnd| u_testeba1(oGrid,@lEnd)},"MTA330","u_testeba2")
oGrid:SetMeters(2)
oGrid:SetThreadGrid(5)
oGrid:Activate()
If oGrid:IsFinished()
                alert("fim")
Else
                alert("fim com erro")
EndIf
Return
 
Na seção processamento, apresenta-se o fluxo de controle da rotina, a atualização das réguas e o controle de cancelamento do processamento.
 
Function Testeba1(oGrid,lEnd)
Local nX,nY
 
oGrid:SetMaxMeter(4,1,"teste1")
For nX := 1 To 4
                oGrid:SetMaxMeter(10,2,"teste2")
                For nY := 1 To 10
                               If !oGrid:CallExecute("callexecute is load",Iif(nX==5.And.nY==10,0,1))
                                               lEnd := .T.
                               EndIf
                               oGrid:SetIncMeter(2)
                               If lEnd
                                               Exit
                               EndIf
                Next nY
                If lEnd
                               Exit
                EndIf
                oGrid:SetIncMeter(1)
Next nX
Return    
 
A seção de agendamento contém os dados que são informados ao Schedule da Linha Microsiga Protheus para o correto agendamento da rotina de processamento.
Static Function SchedDef()
                // aReturn[1] – Tipo
                // aReturn[2] – Pergunte
                // aReturn[3] – Alias
                // aReturn[4] – Array de ordem
                // aReturn[5] – Titulo
Return { “R”, “PARAMDEF”, “SA1”, {“Codigo”, “Nome”}, “Título” }