Páginas filhas
  • Interceptação do Commit e Validação MVC - FWModelEvent

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

Conceito

Nesse artigo é apresentado o novo recurso para interceptação do commit do modelo MVC, permitindo uma melhor separação das operações pós gravação de modelo ( integrações com o ERP por exemplo), além de permitir o reuso dessa 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

 

Bloco de código
languagecpp
themeEclipse
firstline1
titleExemplo bloco de commit
linenumberstrue
collapsetrue
//-------------------------------------------------------------------
/*/{Protheus.doc} ModelDef
Definição do modelo de Dados
@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')
//Bloco a ser executado no Commit
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)) )
Return oModel
 
//-------------------------------------------------------------------
/*/{Protheus.doc} MLOC003Com
Função de Commit
@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
Local nTotal 		:= 0 							//  Variável totalizadora da contabilizacao
Local aFlagCTB		:= {} 							// Array com as informações para a gravação do flag de contabilização do registro
Local nHdlPrv		:= 0 							// Handle (numero do arquivo de trabalho) utilizado na contabilizacao
Local cLote	  		:= LoteCont("FIN")				// Lote Contábil do lançamento, cada módulo tem o seu e está configurado na tabela 09 do SX5
Local cArquivo		:= "" 							// Arquivo temporario usado para contabilizacao
Local lMostra		:= .T. 							// Verifica se mostra ou nao tela de contabilização
Local lAglutina 	:= .F. 							// Verifica se aglutina lançamentos com as mesmas entidades contábeis
Begin Transaction
FWFormCommit( oModel )
// Função que verifica se o lançamento padrão foi configurado pelo cliente 
If VerPadrao(cPadrao)
	// Rotina que abre o capa do lote contábil ( Inicio da Contabilização)
	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
			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
		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 )
		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)

 

 

 

O padrão Observer no MVC Protheus

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

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

 

Desenvolvendo uma classe Observer

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

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

 

Painel
titleDelete

Sintaxe

FWObserver():New()-> Objeto FWObserver

 

Descrição

Construtor da classe

 

Painel
titleNew

Sintaxe

FWObserver():update(oObserver,cAction,aParam)

 

Descrição

Método que é chamado pelo MVC quando ocorrer as ações do commit.

 

Parâmetros

 

Nome

Tipo

Descrição

Default

Obrigatório

Referência

cAliasoObserver

Caracter

Alias a ser utilizado pela tabela.

Objeto

Objeto do Observer

 GetNextAlias

 

 

aFieldscAction

Array

Array com estrutura de campos:
[1] Nome
[2] Tipo
[3] Tamanho
[4] Decimal

{}

 

 

 

Caracter

Tipo da ação que está sendo executada pelo commit:

BEFORE_TTS: Antes do início da transação

IN_TTS: Após as gravações porém antes do final da transação

AFTER_TTS: Após a transação

BEFORE: Antes da gravação de cada submodelo (field ou cada linha de uma grid)

AFTER: Depois da gravação de cada submodelo (field ou cada linha de uma grid)

 

 

 

aParamArray

Array com dados para ajudar a implementação da ação. Cada ação terá um conjunto de dados no array:

BEFORE_TTS,IN_TTS,AFTER_TTS: Apenas o submodelo ({oModel})

BEFORE e AFTER : Array com os seguintes elementos:

aParam[1] = Sub modelo

aParam[2] = Id do submodelo

aParam[3] = Alias do submodelo

aParam[4] = lNewRecord - Indica se é um registro novo.

   
Bloco de código
languagecpp
themeEclipse
firstline1
titleExemplo de classe observer (Simples)
linenumberstrue
collapsetrue
#Include 'Protheus.ch'
#Include 'FWMVCDef.ch'
//-------------------------------------------------------------------
/*/{Protheus.doc} ML003PRORUS
Classe interna implementando o Observer do Commit para atualização de saldo no produto
@author alvaro.camillo
@since 06/09/2016
@version 1.0
/*/
//-------------------------------------------------------------------
Class ML003PRORUS FROM FWObserver
	Method New()
	Method update()
End Class
Method update(oObserver,cAction,aParam) Class ML003PRORUS
Local oModel 	:= Nil
Local cModelId	:= ""
Local cAlias	:= ""
Local lNewRecord:= .F.

If cAction =="AFTER"
	oModel := aParam[1]
	cModelId:= aParam[2]
	cAlias:= aParam[3]
	lNewRecord:= aParam[4]
	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		
EndIf
return
Method new() Class ML003PRORUS
Return


 
Bloco de código
languagecpp
themeEclipse
firstline1
titleExemplo de classe observer (Contabilização)
linenumberstrue
collapsetrue
#Include 'Protheus.ch'
#Include 'FWMVCDef.ch'
//-------------------------------------------------------------------
/*/{Protheus.doc} ML003CTB
Classe interna implementando o Observer do Commit
@author alvaro.camillo
@since 06/09/2016
@version 1.0
/*/
//-------------------------------------------------------------------
Class ML003CTB FROM FWObserver
	DATA cPadrao 							// Lançamento padrão a ser configurado no CT5
	DATA nTotal 							//  Variável totalizadora da contabilizacao
	DATA aFlagCTB							// Array com as informações para a gravação do flag de contabilização do registro
	DATA nHdlPrv							// Handle (numero do arquivo de trabalho) utilizado na contabilizacao
	DATA cLote			
	DATA cArquivo							// Arquivo temporario usado para contabilizacao
	
	Method new()
	Method update()
	Method openCTB()
	Method closeCTB()
	Method writeLineCTB()
End Class
Method update(oObserver,cAction,aParam) Class ML003CTB
Local oModel 	:= Nil
Local cModelId	:= ""
Local cAlias	:= ""
Local lNewRecord:= .F.
If cAction =="BEFORE_TTS"
	oModel := aParam[1]
	self:openCTB(oModel)	
EndIf
If cAction =="AFTER"
	oModel := aParam[1]
	cModelId:= aParam[2]
	cAlias:= aParam[3]
	lNewRecord:= aParam[4]
	self:writeLineCTB(oModel,cModelId,cAlias,lNewRecord)	
EndIf
If cAction == "AFTER_TTS"
	oModel := aParam[1]
	self:closeCTB(oModel)	
EndIf
return
Method new ()  Class ML003CTB
	self:cPadrao 		:= "005" 						
	self:nTotal 		:= 0 							
	self:aFlagCTB		:= {} 							
	self:nHdlPrv		:= 0 							
	self:cLote			:= ""
	self:cArquivo		:= ""
Return
//-------------------------------------------------------------------
/*/{Protheus.doc} openCTB
Bloco para ser executado antes da transação para abrir o header de contabilização
@author alvaro.camillo
@since 06/09/2016
@version 1.0
/*/
//-------------------------------------------------------------------
Method openCTB(oModel) Class ML003CTB
Local lRet	:= .T. 							
self:cPadrao 		:= "005" 						// Lançamento padrão a ser configurado no CT5
self:nTotal 		:= 0 							//  Variável totalizadora da contabilizacao
self:aFlagCTB		:= {} 							// Array com as informações para a gravação do flag de contabilização do registro
self:nHdlPrv		:= 0 							// Handle (numero do arquivo de trabalho) utilizado na contabilizacao
self:cLote	  		:= LoteCont("FIN")				// Lote Contábil do lançamento, cada módulo tem o seu e está configurado na tabela 09 do SX5
self:cArquivo		:= "" 							// Arquivo temporario usado para contabilizacao
// Função que verifica se o lançamento padrão foi configurado pelo cliente 
If VerPadrao(self:cPadrao)
	// Rotina que abre o capa do lote contábil ( Inicio da Contabilização)
	self:nHdlPrv := HeadProva(self:cLote,FunName(),Substr(cUsername,1,6),@self:cArquivo)
EndIf
Return lRet
//-------------------------------------------------------------------
/*/{Protheus.doc} writeLineCTB
Bloco para ser executado depois da gravação.
@author alvaro.camillo
@since 06/09/2016
@version 1.0
/*/
//-------------------------------------------------------------------
Method writeLineCTB(oModel,cModelId,cAlias,lNewRecord) Class ML003CTB
Local lRet := .T.
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
		self:nTotal += DetProva(self:nHdlPrv,self:cPadrao,FunName(),self:cLote,,,,,,,,@self:aFlagCTB)
	Endif
Endif
RestArea(aArea)
Return lRet
//-------------------------------------------------------------------
/*/{Protheus.doc} closeCTB
Bloco para ser executado depois da transação.
@author alvaro.camillo
@since 06/09/2016
@version 1.0
/*/
//-------------------------------------------------------------------
Method closeCTB(oModel) Class ML003CTB
Local lRet := .T.
Local lMostra	:= .T. 							// Verifica se mostra ou nao tela de contabilização
Local lAglutina := .F. 							// Verifica se aglutina lançamentos com as mesmas entidades contábeis
If self:nHdlPrv > 0 .And. ( self:nTotal > 0 )
	// Função que fecha o lote contábil
	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 )
	cA100Incl(self:cArquivo,self:nHdlPrv,3,self:cLote,lMostra,lAglutina)
Endif

Return lRet

 

 



Status do documentoDesenvolvimento
Data 
Versão1.0
Autores

Alvaro Camillo Neto

Índice
Índice
outlinetrue
indent10px

...