Child pages
  • Interceptação do Commit e Validação MVC - FWModelEvent

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Conceito

 

 

Utilizando o formulário contínuo

Com esse método você pode incluir novos componentes (Grids e Fields) incluindo abaixo dos componentes originais num formulário contínuo como uma página web.

Para isso é preciso configurar o FwFormView com o método SetContinuousForm (FWFormView). 

Importante salientar que a definição dessa propriedade deve ser feita somente no novo formulário. Não é preciso configurar o formulário contínuo no fonte original.

Nesse artigo é apresentado o novo recurso para interceptação do commit e validação do modelo MVC, permitindo uma melhor separação das operações pós gravação de modelo ( integrações com o ERP por exemplo) e validação de modelo, além de permitir o reuso dessas operações em localizações de formulários MVC.

Sobrescrevendo o bloco de Commit.

Atualmente quando é preciso realizar outras operações além da gravação do modelo no Commit do MVC (contabilização, integração fiscal, financeira e etc.) são utilizados os seguintes passos:

  • Criação do bloco de commit.
  • Dentro da função do bloco é executada a função FWFormCommit, para persistir o modelo.
  • Abre as tabelas do modelo e executa a leitura (novamente) do modelo, executando as operações de integração


Code Block
Code Block
languagecpp
themeEclipse
firstline1
titleExemplo de herança de interface (formulário continuo)bloco de commit
linenumberstrue
collapsetrue
//-------------------------------------------------------------------
/*/{Protheus.doc} ViewDefModelDef
Definição do interfacemodelo de Dados
Data Model definition
@author alvaro.camillo
@since 05/09/2016
@version 1.0
/*/
//-------------------------------------------------------------------
Static Function ViewDefModelDef()
Local oViewoModel
Local oStr1		:= FWLoadView("MLOC001"FWFormStruct(1,'ZC3')
Local oStr2		:= FWFormStruct(21, 'ZL0ZC4')
oStr2:RemoveField( 'ZL0_LOJA' )
oStr2:RemoveField( 'ZL0_COD' )
//Formulário Continuo 
oView:SetContinuousForm(.T.)
oView:AddGrid('FORM3' , oStr2,'ZL0DETAIL') 
//Criação da box com tamanho 00 pois o formulario continuo irá calcular o tamanho da tela. 
oView:CreateHorizontalBox( 'BOXFORM3', 00)
oView:SetOwnerView('FORM3','BOXFORM3')
oView:AddIncrementField('FORM3' , 'ZL0_ITEM' ) 
oView:EnableTitleView('FORM3' , 'Endereço Russo' ) 
Return oView

 

Criando uma nova box (horizontal ou vertical).

Esse método pode ser utilizado quando existe a necessidade de personalizar ainda mais a tela, podendo alterar inclusive a disposição dos componentes da tela.

Porém esse método possui as seguintes desvantagens:

  • O analista precisa conhecer os detalhes da implementação do fonte de origem, pois é preciso saber o nome do painel(box) do fonte original.
  • Caso o mantenedor do fonte de origem resolva mudar a disposição ou refatorar os nomes do elementos, o fonte derivado deverá ser alterado para continuar funcionando.
    Local bCommit	:= {|oModel| MLOC003Com(oModel) }
    oModel := MPFormModel():New('MLOC003Old', /*bPre*/, /*bPost*/, bCommit, /*bCancel*/)
    oModel:SetDescription('Pedidos')
    oModel:addFields('ZC3MASTER',,oStr1)
    oModel:addGrid('ZC4DETAIL','ZC3MASTER',oStr2)
    oModel:SetRelation('ZC4DETAIL', { { 'ZC4_FILIAL', 'xFilial("ZC4")' }, { 'ZC4_COD', 'ZC3_COD' } }, ZC4->(IndexKey(1)) )
    oModel:getModel('ZC3MASTER'):SetDescription('Pedido')
    oModel:getModel('ZC4DETAIL'):SetDescription('Item do pedido')
    oModel:AddCalc( 'Totalizador', 'ZC3MASTER', 'ZC4DETAIL', 'ZC4_TOTAL', 'ZC__TOTALPED', 'SUM', /*bCondition*/, /*bInitValue*/,'Total do Pedido' /*cTitle*/, /*bFormula*/)
    Return oModel
     
    //-------------------------------------------------------------------
    /*/{Protheus.doc} MLOC003Com
    Função de Commit
    Commit Function
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Static Function MLOC003Com(oModel)
    Local cPadrao 		:= "005" 						// Lançamento padrão a ser configurado no CT5 //Standard entries to be configured on CT5
    Local nTotal 		:= 0 							//  Variável totalizadora da contabilizacao //Variable with accounting total
    Local aFlagCTB		:= {} 							// Array com as informações para a gravação do flag de contabilização do registro//Array with informations for accounting flag record
    Local nHdlPrv		:= 0 							// Handle (numero do arquivo de trabalho) utilizado na contabilizacao//Handler (working file number) used on accounting
    Local cLote	  		:= LoteCont("FIN")				// Lote Contábil do lançamento, cada módulo tem o seu e está configurado na tabela 09 do SX5//Temporary file used on accounting
    Local cArquivo		:= "" 							// Arquivo temporario usado para contabilizacao
    Local lMostra		:= .T. 							
    Local lAglutina 	:= .F. 						
    Begin Transaction
    FWFormCommit( oModel )
    // Função que verifica se o lançamento padrão foi configurado pelo cliente 
    // Function which verify if the accounting entry was configured by customer
    If VerPadrao(cPadrao)
    	// Rotina que abre o capa do lote contábil ( Inicio da Contabilização)
    	// Accounting beginning
    	nHdlPrv := HeadProva(cLote,FunName(),Substr(cUsername,1,6),@cArquivo)
    EndIf
    ZC4->(dbSetOrder(1))//ZC4_FILIAL+ZC4_COD+ZC4_ITEM
    ZC0->(dbSetOrder(1))//ZC0_FILIAL+ZC0_COD+ZC0_LOJA
    ZC1->(dbSetOrder(1))//ZC1_FILIAL+ZC1_COD
    ZC0->(MsSeek(xFilial("ZC0") + ZC3->(ZC3_CLIENT + ZC3_LOJA) ))
    If ZC4->(dbSeek( xFilial("ZC4") + ZC3->ZC3_COD ))
    	While ZC4->(!EOF()) .And. ZC4->(ZC4_FILIAL+ZC4_COD) == xFilial("ZC4") + ZC3->ZC3_COD 
    		ZC1->(MsSeek(xFilial("ZC4") + ZC4->ZC4_PROD ))
    		
    		If nHdlPrv > 0  
    			aAdd(aFlagCTB,{"ZC4_LA","S","ZC4",ZC4->(Recno()),0,0,0})	
    			// Função que interpreta todas as sequencias de lançamento configurada pelo usuário e cria as linhas de lançamento contábil
    			// Executada uma vez para cada registro que quer ser contabilizado
    			// Function which interpret all sequences of the standard entries and creates the accounting entries.
    			// Executed once for each record which will be accounted for.
    			
    			nTotal += DetProva(nHdlPrv,cPadrao,FunName(),cLote,,,,,,,,@aFlagCTB)
    		Endif
    				
    		ZC4->(dbSkip())
    	EndDo
    	If nHdlPrv > 0 .And. ( nTotal > 0 )
    		// Função que fecha o lote contábil
    		// Function that closes the accounting lot
    		RodaProva(nHdlPrv, nTotal)         
    		// Função que apresenta a tela de contabilização, realiza aglutinação caso necessária e grava o documento contábil ( CT2 )
    		// Function that shows the account dialog, performs the grouping if needed and records the accounting document ( CT2 )	
    		cA100Incl(cArquivo,nHdlPrv,3,cLote,lMostra,lAglutina)
    	Endif	
    EndIf
    End Transaction
    
    Return .T.
    
    
    
    
    
    
     

    Porém essa implementação tem limitações como:

    • Uso excessivo de bloco de código com gasto de memória e baixa performance. 
    • É preciso realizar a leitura novamente dos registros para as operações de integração.
    • O controle de transação fica por conta do desenvolvedor.
    • Em um fonte localizado não é possível estender o comportamento do commit, incluindo novas operações. 

    O padrão Observer

    O Observer é um padrão de projeto de software que define uma dependência um-para-muitos entre objetos de modo que quando um objeto muda o estado, todos seus dependentes são notificados e atualizados automaticamente. Permite que objetos interessados sejam avisados da mudança de estado ou outros eventos ocorrendo num outro objeto.(https://pt.wikipedia.org/wiki/Observer)


    Image Added

    O padrão Observer no MVC Protheus - Utilizando a classe FWModelEvent

    Em um fomulário MVC esse padrão é aplicado utilizando os seguintes passos:

    • Desenvolver uma classe que herde da classe FWModelEvent.
    • Inscrever um objeto dessa classe no modelo.


    Desenvolvendo uma classe FWModelEvent

    Essa classe será responsável pela a operação que complementa a persistência do modelo e a validação e será chamada toda vez que o formulário onde ele foi inscrito realize o commit ou realize alguma validação

    Warning
    titleImportante
    • É possível inscrever mais de um Evento ao formulário, permitindo a separação de comportamentos em classe diferentes ( classe para a contabilização, classe para a integração fiscal e etc)
    • Não é possível executar o bloco de commit e o padrão FwModelEvent ao mesmo tempo, caso aconteça o sistema irá gerar um erro de execução.
    • A função de entrada de um fonte MVC (chamada de menu) da rotina padrão deve ter no máximo 7 caracteres, pois a rotina localizada tem o seu nome somado a sigla do país.
    • Para o filtro de campos funcionar corretamente, na definição da view deve ser utilizada a função FwLoadModel para carregar o modelo. Não utilize ModelDef()

    Essa classe deve herdar da classe FWModelEvent e implementar os seguintes métodos:


    Panel
    titleNew

    Sintaxe

    FWModelEvent ():New()-> Objeto FWModelEvent 


    Descrição

    Construtor da classe. Método Obrigatório para ser implementado


    Panel
    titleDestroy

    Sintaxe

    FWModelEvent ():Destroy()


    Descrição

    Destrutor da classe
    Caso o evento utilize atributos como array,objetos é boa prática o desenvolvedor
    limpar esses atributos da memória.

    Utilize para limpar atributos que são array ou objetos.

    Exemplo

    Limpeza de array:

    aSize(aArray, 0)

    aArray := Nil

    Limpeza de objeto

    oObject := Nil



    Panel
    titleAfter

    Sintaxe

    FWModelEvent ():After(oSubModel, cModelId, cAlias, lNewRecord)


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações do commit
    depois da gravação de cada submodelo (field ou cada linha de uma grid)


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Sub modelo




    cModelId

    Caracter

    Id do submodelo




    cAliasCaracter

    Alias do submodelo




    lNewRecordLógicoIndica se é um registro novo.


    Panel
    titleBefore

    Sintaxe

    FWModelEvent ():Before(oSubModel, cModelId, cAlias, lNewRecord)


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações do commit
    antes da gravação de cada submodelo (field ou cada linha de uma grid)


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Sub modelo




    cModelId

    Caracter

    Id do submodelo




    cAliasCaracter

    Alias do submodelo




    lNewRecordLógicoIndica se é um registro novo.


    Panel
    titleAfterTTS

    Sintaxe

    FWModelEvent ():AfterTTS(oModel, cModelId)


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações do  após a transação.

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleBeforeTTS

    Sintaxe

    FWModelEvent ():BeforeTTS(oModel, cModelId)


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações do commit antes da transação.

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleInTTS

    Sintaxe

    FWModelEvent ():InTTS(oModel, cModelId)


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações do commit Após as gravações porém
    antes do final da transação.

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleActivate

    Sintaxe

    FWModelEvent ():Activate(oModel, lCopy)


    Descrição

    Método que é chamado pelo MVC quando ocorrer a ativação do Model.

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    lCopy

    Lógico

    Informa se o model deve carregar os dados do registro posicionado em operações de inclusão.
    Essa opção é usada quando é necessário fazer uma operação de cópia.




    Panel
    titleDeActivate

    Sintaxe

    FWModelEvent (): DeActivate(oModel)


    Descrição

    Método que é chamado pelo MVC quando ocorrer a desativação do Model.

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    Panel
    titleVldActivate

    Sintaxe

    FWModelEvent (): VldActivate(oModel, cModelId) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações de validação do Model.

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    cModelIdCaracterId do submodelo


    Panel
    titleModelPreVld

    Sintaxe

    FWModelEvent ():ModelPreVld(oModel, cModelId) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações de pre validação do Model

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleModelPosVld

    Sintaxe

    FWModelEvent ():ModelPosVld(oModel, cModelId) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações de pos validação do Model

    Esse evento ocorre uma vez no contexto do modelo principal.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleGridPosVld

    Sintaxe

    FWModelEvent ():GridPosVld(oSubModel, cModelID) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações de pós validação do Grid


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleGridLinePreVld

    Sintaxe

    FWModelEvent ():GridLinePreVld(oSubModel, cModelID, nLine, cAction, cId, xValue, xCurrentValue) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações de pre validação da linha do Grid


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    nLineNuméricoLinha do grid


    cActionCaracterAção executada no grid, podendo ser: ADDLINE, UNDELETE, DELETE, SETVALUE, CANSETVALUE, ISENABLE


    cIdCaracternome do campo


    xValueVariávelNovo valor do campo


    xCurrentValueVariávelValor atual do campo


    Panel
    titleGridLinePosVld

    Sintaxe

    FWModelEvent ():GridLinePosVld(oSubModel, cModelID, nLine) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer as ações de pos validação da linha do Grid


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    nLineNuméricoLinha do grid


    Panel
    titleFieldPreVld

    Sintaxe

    FWModelEvent ():FieldPreVld(oSubModel, cModelID, cAction, cId, xValue) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer a ação de pré validação do Field


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    cActionCaracterAção executada no grid, podendo ser: SETVALUE, CANSETVALUE


    cIdCaracternome do campo


    xValueCaracterNovo valor do campo


    Panel
    titleFieldPosVld

    Sintaxe

    FWModelEvent ():FieldPosVld(oSubModel, cModelID) -> lOK


    Descrição

    Método que é chamado pelo MVC quando ocorrer a ação de pós validação do Field


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    oSubModel

    Objeto

    Modelo principal




    cModelId

    Caracter

    Id do submodelo




    Panel
    titleGetEvent

    Sintaxe

    FWModelEvent ():GetEvent(cIdEvent) -> oEvent


    Descrição

    Método que retorna um evento superior da cadeia de eventos.
    Através do método InstallEvent, é possível encadear dois eventos que estão relacionados, como por exemplo um
    evento de negócio padrão e um evento localizado que complementa essa regra de negócio.
    Caso o evento localizado, necessite de atributos da classe superior, ele irá utilizar esse método para recuperá-lo.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    cIdEvent

    Caracter

    Id do Evento Superior.




    Code Block
    languagecpp
    themeEclipse
    firstline1
    titleExemplo de classe FwModelEvent (Simples)
    linenumberstrue
    collapsetrue
    #Include 'Protheus.ch'
    #Include 'FWMVCDef.ch'
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ML003PRORUS
    Classe interna implementando o FWModelEvent
    Intern class inherited from FWModelEvent.
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Class ML003PRORUS FROM FWModelEvent
    	Method After()
    	Method New()
    End Class
    Method New() Class ML003PRORUS
    Return
    Method After(oModel, cModelId, cAlias, lNewRecord) Class ML003PRORUS
    If cAlias == "ZC4" .And. lNewRecord
    	ZL1->(dbSetOrder(1))//ZL1_FILIAL+ZL1_COD
    	If ZL1->(MsSeek(xFilial("ZL1") + ZC4->ZC4_PROD ))
    		RecLock("ZL1",.F.)
    			ZL1->ZL1_QTVEND += ZC4->ZC4_QUANT  
    		MsUnLock()
    	EndIf
    EndIf		
    Return
    
    
    
     
    Code Block
    languagecpp
    themeEclipse
    firstline1
    titleExemplo de classe FwModelEvent (Contabilização)
    linenumberstrue
    collapsetrue
     #Include 'Protheus.ch'
    #Include 'FWMVCDef.ch'
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ML003CTB
    Classe interna implementando o FWModelEvent
    Intern class inherited from FWModelEvent.
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Class ML003CTB FROM FWModelEvent
    	//Lançamento padrão a ser configurado no CT5
    	//Standard entries to be configured on CT5
    	DATA cPadrao
    	//Variável totalizadora da contabilizacao 
    	//Variable with accounting total
    	DATA nTotal
    	//Array com as informações para a gravação do flag de contabilização do registro 
    	//Array with informations for accounting flag record
    	DATA aFlagCTB
    	//Handle (numero do arquivo de trabalho) utilizado na contabilizacao 
    	//Handler (working file number) used on accounting
    	DATA nHdlPrv
    	//Arquivo temporario usado para contabilizacao  
    	//Temporary file used on accounting
    	DATA cArquivo
    	DATA cLote
    	
    	Method new()
    	Method After()
    	Method AfterTTS()
    	Method BeforeTTS()
    	
    	Method ModelPosVld()
    	Method GridLinePreVld()
    	Method openCTB()
    	Method closeCTB()
    	Method writeLineCTB()
    	
    	Method Destroy()
    End Class
    Method new ()  Class ML003CTB
    	self:cPadrao 		:= "005" 						
    	self:nTotal 		:= 0 							
    	self:aFlagCTB		:= {} 							
    	self:nHdlPrv		:= 0 							
    	self:cLote			:= ""
    	self:cArquivo		:= ""
    Return
     
    Method Destroy()  Class ML003CTB		
    	self:aFlagCTB := aSize(self:aFlagCTB,0)
    	self:aFlagCTB := Nil					
    Return
    //-------------------------------------------------------------------
    /*/{Protheus.doc} BeforeTTS
    Inicio da transação com a abertura do lote contabil
    Transaction beginning and the oppening of lot accounting
    @author Rodrigo Antonio
    @version P12
    /*/
    //-------------------------------------------------------------------
    Method BeforeTTS(oModel, cModelId) Class ML003CTB
    	self:openCTB(oModel)	
    Return
    //-------------------------------------------------------------------
    /*/{Protheus.doc} After
    Executado após a gravaçao de cada linha para realizar lançamento contábil
    Runs after every line recording to execute the accounting entries
    @author Rodrigo Antonio
    @version P12
    /*/
    //-------------------------------------------------------------------
    Method After(oModel, cModelId, cAlias, lNewRecord)  Class ML003CTB
    	self:writeLineCTB(oModel,cModelId,cAlias,lNewRecord) 
    Return
    //-------------------------------------------------------------------
    /*/{Protheus.doc} AfterTTS
    Fechamento da contabilização.
    Accounting closing.
    @author Rodrigo Antonio
    @version P12
    /*/
    //-------------------------------------------------------------------
    Method AfterTTS(oModel, cModelId)  Class ML003CTB
    	self:closeCTB(oModel)
    Return
    
    //-------------------------------------------------------------------
    /*/{Protheus.doc} openCTB
    Metodo para ser executado antes da transação para abrir o header de contabilização
    Method to be executed before the accounting header openning transaction
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method openCTB(oModel) Class ML003CTB
    //Lançamento padrão a ser configurado no CT5
    //Standard entries to be configured on CT5
    self:cPadrao 		:= "005"
    //Variável totalizadora da contabilizacao 
    //Variable with accounting total
    self:nTotal 		:= 0
    //Array com as informações para a gravação do flag de contabilização do registro 
    //Array with informations for accounting flag record
    self:aFlagCTB		:= {}
    //Handle (numero do arquivo de trabalho) utilizado na contabilizacao 
    //Handler (working file number) used on accounting
    self:nHdlPrv		:= 0
    // Lote Contábil do lançamento, cada módulo tem o seu e está configurado na tabela 09 do SX5
    //accounting lot. Each model has a corresponding lot configured on the table 09 of SX5 
    self:cLote	  		:= LoteCont("FIN")
    //Arquivo temporario usado para contabilizacao  
    //Temporary file used on accounting
    self:cArquivo		:= ""
    // Função que verifica se o lançamento padrão foi configurado pelo cliente 
    // Function which verify if the accounting entry was configured by customer
    If VerPadrao(self:cPadrao)
    	// Rotina que abre o lote contábil ( Inicio da Contabilização)
    	// Accounting beginning
    	self:nHdlPrv := HeadProva(self:cLote,FunName(),Substr(cUsername,1,6),@self:cArquivo)
    EndIf
    Return 
    //-------------------------------------------------------------------
    /*/{Protheus.doc} writeLineCTB
    Metodo para ser executado depois da gravação.
    Method to be executed after the data recording
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method writeLineCTB(oModel,cModelId,cAlias,lNewRecord) Class ML003CTB
    	Local aArea:= GetArea()
    	If cAlias == "ZC4"
    		ZC0->(dbSetOrder(1))//ZC0_FILIAL+ZC0_COD+ZC0_LOJA
    		ZC1->(dbSetOrder(1))//ZC1_FILIAL+ZC1_COD
    		
    		ZC0->(MsSeek(xFilial("ZC0") + ZC3->(ZC3_CLIENT + ZC3_LOJA) ))
    		ZC1->(MsSeek(xFilial("ZC4") + ZC4->ZC4_PROD ))
    		
    		If self:nHdlPrv > 0  
    			aAdd(self:aFlagCTB,{"ZC4_LA","S","ZC4",ZC4->(Recno()),0,0,0})	
    			// Função que interpreta todas as sequencias de lançamento configurada pelo usuário e cria as linhas de lançamento contábil
    			// Executada uma vez para cada registro que quer ser contabilizado
    			// Function which interpret all sequences of the standard entries and creates the accounting entries.
    			// Executed once for each record which will be accounted for.
    			self:nTotal += DetProva(self:nHdlPrv,self:cPadrao,FunName(),self:cLote,,,,,,,,@self:aFlagCTB)
    		Endif
    	Endif
    	RestArea(aArea)
    Return
    //-------------------------------------------------------------------
    /*/{Protheus.doc} closeCTB
    Metodo para ser executado depois da transação.
    Method to be executed after the transaction.
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method closeCTB(oModel) Class ML003CTB
    // Verifica se mostra ou nao tela de contabilização
    // Verify if accounting dialog will to be shown
    Local lMostra	:= .T.
    // Verifica se aglutina lançamentos com as mesmas entidades contábeis
    // Verify if it's needed to group entries with the same accounting entities'
    Local lAglutina := .F.
    If self:nHdlPrv > 0 .And. ( self:nTotal > 0 )
    	// Função que fecha o lote contábil
    	// Function that closes the accounting lot
    	RodaProva(self:nHdlPrv, self:nTotal)
    	// Função que apresenta a tela de contabilização, realiza aglutinação caso necessária e grava o documento contábil ( CT2 )
    	// Function that shows the account dialog, performs the grouping if needed and records the accounting document ( CT2 )
    	cA100Incl(self:cArquivo,self:nHdlPrv,3,self:cLote,lMostra,lAglutina)
    Endif
    Return
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ModelPos
    Metodo de pos validação do modelo.
    Model post validation method.
    @author Guilherme Spadaccia
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method ModelPosVld(oModel, cModelId) Class ML003CTB
    Local lRet := .T.
    //Defino o model que irei validar
    //Define which model will be validated
    If cModelId == 'MLOC003'
    	If oModel:GetValue('ZC3MASTER','ZC3_COD') == "000000"
    		lRet := .F.
    		Help("",1,"VALID",,"Code 000000 is reserved",1,0)
    	EndIf
    EndIf
    Return lRet
    
    //-------------------------------------------------------------------
    /*/{Protheus.doc} GridLinePre
    Metodo de pré validação da linha da Grid.
    Grid line pre validation method.
    @author Guilherme Spadaccia
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method GridLinePreVld(oSubModel, cModelID, nLine, cAction, cId, xValue, xCurrentValue) Class ML003CTB
    Local lRet := .T.
    If cModelID == "ZC4DETAIL"
    	If cAction == "SETVALUE" .And. cId == "ZC4_QUANT"
    		If xValue%2 > 0
    			lRet := .F.
    			Help("",1,"VALID",,"Only pair quantities are accepted",1,0)
    		EndIf
    	EndIf
    EndIf
    Return lRet
    Code Block
    languagecpp
    themeEclipse
    firstline1
    titleExemplo de classe FwModelEvent derivada de outro evento já implementado (Localização)
    linenumberstrue
    collapsetrue
    #Include 'Protheus.ch'
    #Include 'FWMVCDef.ch'
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ML003CTBRUS
    Classe interna implementando o FWModelEvent localizando para  padrão Russo
    Intern class inherited from FWModelEvent for russian Standard.
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Class ML003CTBRUS FROM FWModelEvent
    	
    	Method New()
    	Method After()
    	Method ModelPosVld()
    	Method GridLinePreVld()
    End Class
    
    Method New() Class ML003CTBRUS
    Return
    //-------------------------------------------------------------------
    /*/{Protheus.doc} After
    Método para ser executado depois da gravação.
    Method to be executed after the data recording
    @author alvaro.camillo
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method After(oModel,cModelId,cAlias,lNewRecord) Class ML003CTBRUS
    Local aArea:= GetArea()
    Local oEventCtb := self:GetEvent("ML003CTB")
    If cAlias == "ZL4"
    	If oEventCtb:nHdlPrv > 0  
    		aAdd(oEventCtb:aFlagCTB,{"ZL4_LA","S","ZL4",ZL4->(Recno()),0,0,0})	
    		// Função que interpreta todas as sequencias de lançamento configurada pelo usuário e cria as linhas de lançamento contábil
    		// Executada uma vez para cada registro que quer ser contabilizado
    		// Function which interpret all sequences of the standard entries and creates the accounting entries.
    		// Executed once for each record which will be accounted for.
    		oEventCtb:nTotal += DetProva(oEventCtb:nHdlPrv,"006",FunName(),oEventCtb:cLote,,,,,,,,@oEventCtb:aFlagCTB)
    	Endif
    Endif
    RestArea(aArea)
    Return 
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ModelPos
    Metodo de pos validação do modelo.
    Model post validation method.
    @author Guilherme Spadaccia
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method ModelPosVld(oModel, cModelId) Class ML003CTBRUS
    Local lRet := .T.
    //Defino o model que irei validar
    If cModelId == 'MLOC003'
    	If oModel:GetValue('ZC3MASTER','ZC3_COD') == "000001"
    		lRet := .F.
    		Help("",1,"VALID",,"Code 000001 is reserved in Russia.",1,0)
    	EndIf
    EndIf
    Return lRet
    //-------------------------------------------------------------------
    /*/{Protheus.doc} GridLinePre
    Metodo de pré validação da linha da Grid.
    Grid line pre validation method.
    @author Guilherme Spadaccia
    @since 06/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Method GridLinePreVld(oSubModel, cModelID, nLine, cAction, cId, xValue, xCurrentValue) Class ML003CTBRUS
    Local lRet := .T.
    If cModelID == "ZC4DETAIL"
    	If cAction == "SETVALUE" .And. cId == "ZC4_QUANT"
    		If xValue > 10
    			lRet := .F.
    			Help("",1,"VALID",,"Only quantities under 10 are accepted",1,0)
    		EndIf
    	EndIf
    EndIf
    Return lRet

    Inscrever um objeto no modelo.

    Nessa etapa, no formulário MVC é preciso inscrever o objeto pelo método InstallEvent:

    Panel
    titleInstallEvent

    Sintaxe

    MPFormModel():InstallEvent(cIdEvent, cOwner, oEvent)


    Descrição

    Método de inscrição de objeto FwModelEvent

    Através do método InstallEvent, é possível encadear dois eventos que estão relacionados, como por exemplo um
    evento de negócio padrão e um evento localizado que complementa essa regra de negócio.


    Parâmetros


    Nome

    Tipo

    Descrição

    Default

    Obrigatório

    Referência

    cIdEvent

    Carácter

    Id do Evento


    Sim 


    cOwner Carácter Id do Evento Superior
     Não
    oEventObjetoEvento do Modelo
    Sim



    Code Block
    languagecpp
    themeEclipse
    firstline1
    titleExemplo de inscrição de evento
    linenumberstrue
    collapsetrue
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ModelDef
    Definição do modelo de Dados
    Data Model definition
    @author alvaro.camillo
    @since 05/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Static Function ModelDef()
    Local oModel
    Local oStr1		:= FWFormStruct(1,'ZC3')
    Local oStr2		:= FWFormStruct(1,'ZC4')
    Local oEvent  := ML003CTB():New()
    oModel := MPFormModel():New('MLOC003', /*bPre*/, /*bPost*/, /*bCommit*/, /*bCancel*/)
    oModel:SetDescription('Pedidos')
    oModel:addFields('ZC3MASTER',,oStr1)
    oModel:addGrid('ZC4DETAIL','ZC3MASTER',oStr2)
    oModel:SetRelation('ZC4DETAIL', { { 'ZC4_FILIAL', 'xFilial("ZC4")' }, { 'ZC4_COD', 'ZC3_COD' } }, ZC4->(IndexKey(1)) )
    oModel:getModel('ZC3MASTER'):SetDescription('Pedido')
    oModel:getModel('ZC4DETAIL'):SetDescription('Item do pedido')
    oModel:getModel('ZC4DETAIL'):SetUseOldGrid( .T. )
    oModel:AddCalc( 'Totalizador', 'ZC3MASTER', 'ZC4DETAIL', 'ZC4_TOTAL', 'ZC__TOTALPED', 'SUM', /*bCondition*/, /*bInitValue*/,'Total do Pedido' /*cTitle*/, /*bFormula*/)
    oModel:InstallEvent("ML003CTB", /*cOwner*/, oEvent)
    Return oModel
    
     

    Para realizar essa operação, é preciso criar um novo box para o novo componente.É preciso criar sempre um box vertical dentro de um horizontal e vice-versa.

    Nesse ponto é preciso verificar no fonte de origem qual é o ID do box e qual é a sua orientação.
    Code Block
    languagecpp
    themeEclipse
    firstline1
    titleExemplo de herança de interface (criando um novo box)inscrição de evento em um fonte localizado
    linenumberstrue
    collapselinenumberstrue
    //-------------------------------------------------------------------
    /*/{Protheus.doc} ViewDef
    Definição do interface} ModelDef
    Definição do modelo de Dados
    Data Model definition
    @author alvaro.camillo
    @since 05/09/2016
    @version 1.0
    /*/
    //-------------------------------------------------------------------
    Static Function ViewDef()
    // Cria um objeto de Modelo de Dados baseado no ModelDef do fonte informado
    Local oModel := FWLoadModel( 'MLOC001View' )
    // Cria a estrutura a ser acrescentada na View
    Local oStr2	:= FWFormStruct(2, 'ZL0')
    // Inicia a View com uma View ja existente
    Local oView	:= FWLoadView("MLOC001")
    oStr2:RemoveField( 'ZL0_LOJA' )
    oStr2:RemoveField( 'ZL0_COD' )
    // Altera o Modelo de dados quer será utilizado
    oView:SetModel( oModel )
    // Adiciona no nosso View um controle do tipo grid
    oView:AddGrid('VIEW_ZL0' , oStr2,'ZL0DETAIL')
    // É preciso criar sempre um box vertical dentro de um horizontal e vice-versa
    // como na MLOC001 o box é horizontal, cria-se um vertical primeiro
    // Box existente na interface original
    oView:CreateVerticallBox( 'TELANOVA' , 100, 'BOXFORM1' )
    // Novos Boxes
    oView:CreateHorizontalBox( 'SUPERIOR' , 50, 'TELANOVA' )
    oView:CreateHorizontalBox( 'INFERIOR' , 50, 'TELANOVA' )
    // Relaciona o identificador (ID) da View com o "box" para exibicao
    oView:SetOwnerView( 'FORM1', 'SUPERIOR' )
    oView:SetOwnerView( 'VIEW_ZL0', 'INFERIOR' )
     
    Return oView--------------
    Static Function ModelDef()
    Local oModel		:= FWLoadModel('MLOC003')
    Local oStr2		:= FWFormStruct(1,'ZL4')
    Local oObsCTB		:= ML003CTBRUS():New()
    Local oObsProduto	:= ML003PRORUS():New()
    oModel:addGrid('ZL4DETAIL','ZC4DETAIL',oStr2)
    oModel:SetRelation('ZL4DETAIL', { { 'ZL4_FILIAL', 'xFilial("ZL4")' }, { 'ZL4_COD', 'ZC3_COD' }, { 'ZL4_ITEM', 'ZC4_ITEM' } }, ZL4->(IndexKey(1)) )
    oModel:getModel('ZL4DETAIL'):SetDescription('Rateio do Item Russo')
    oModel:getModel('ZL4DETAIL'):SetOptional(.T.)
    //Instala o evento de atualização de saldo
    //Install Balance update Event
    oModel:InstallEvent("ML00PRORUS", , oObsProduto)
    //Instala o evento de contabilizao Russa
    //Install Russian Accounting Event
    oModel:InstallEvent("ML003CTBRUS", "ML003CTB", oObsCTB)
    
    Return oModel
    
    
    
    
    
     



    Status do documentoDesenvolvimento
    Data
     
    Versão1.0
    Autores

    Alvaro Camillo Neto

     
    Índice
    Table of Contents
    outlinetrue
    indent10px