Criando facilmente o Modelo3
O Modulo3, é uma função pronta que tem o mesmo efeito de uma rotina onde teremos uma janela com um cabeçalho usando a função EnChoice uma grade usando a fução MsGetDados para os itens.
O retorno da função é True quando clicamos no botão Confirmar ou False, quando clicamos no botão Fechar. É possível incluir também novos botões dentro do botão Ações Relacionadas.
Um exemplo de um Modelo3 é a rotina OMSA010 – Manutenção da Tabela de Preço
Uma grande vantagem de se usar o Modelo3 é a sua simplicidade, sem contar que iremos programar o mínimo possível.
Sintaxe:
Modelo3(cTitulo,cAlias1,cAlias2,aMyEncho,cLinOk,cTudoOk,nOpcE,nOpcG,cFieldOk,lVirtual,nLinhas,aAltEnchoice,nFreeze, aButtons, aCordW, nSizeHeader)
Onde:
Nome |
Tipo |
Descrição |
cTitulo |
Caracter |
Titulo da janela |
cAlias |
Caracter |
Alias da Enchoice |
cAlias2 |
Caracter |
Alias da Getdados |
aMyEncho |
Vetor |
Array com campos da enchoice |
cLinhaOk |
Caracter |
Função para validação da linha |
cTudoOk |
Caracter |
Função para validação na confirmação |
nOpcE |
Numérico |
nOpc da Enchoice 3 = Incluir , 4 = Alterar, 5 = Excluir |
nOpcG |
Numérico |
nOpc da Getdados 3 = Incluir , 4 = Alterar, 5 = Excluir |
cFieldOk |
Caracter |
Validação para todos os campos da GetDados |
lVirtual |
Lógico |
Permite visualizar campos virtuais na enchoice |
nLinhas |
Numérico |
Número máximo de linhas na getdados |
aAltEnchoice |
Vetor |
Array com campos alteráveis da Enchoice |
nFreeze |
Numérico |
Congelamento das colunas. |
aButtons |
Vetor |
Array com botões de usuário na enchoicebar |
aCordW |
Vetor |
Coordenadas da janela |
nSizeHeader |
Numérico |
Altura da enchoice |
No exemplo abaixo, irei mostrar como montar um modelo3 onde deixarei alguns campos habilitados para que somente estes campos sejam modificados e salvos na hora que confirmar.
Na grade, irei apresentar alguns campos, assim como a enchoice, irei definir quais campos serão salvos na hora em que confirmar a tela.
Irei trabalhar com as tabelas SC5 (Cabeçalho do Pedidos de Venda) e SC6 (Itens dos Pedidos de Venda)
Este fonte é chamado a partir do menu mBrowser do Pedido de Venda
1 2 3 |
User Function MA410MNU AADD(aRotina, {"Exemplo Modelo 3", "U_AFAT009()", 0, 4}) Return |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
#Include 'Protheus.ch' User Function ExemploM3() Local cLinok := "Allwaystrue" Local cTudook := "Allwaystrue" Local nOpce := 4 //define modo de alteração para a enchoice Local nOpcg := 4 //define modo de alteração para o grid Local cFieldok := "Allwaystrue" Local lRet := .T. Local cMensagem := "" Local lVirtual := .T. //Mostra campos virtuais se houver Local nFreeze := 0 Local nAlturaEnc:= 400 //Altura da Enchoice Private cCadastro := "Pedido de Venda" Private aCols := {} Private aHeader := {} Private aCpoEnchoice:= {} Private aAltEnchoice:= {"C5_CONDPAG","C5_TPFRETE","C5_MENNOTA","C5_ZZPVCL","C5_ZZBOX","C5_ZZEQUIP","C5_ZZMOD1","C5_ZZMOD2","C5_ZZCAIXA"} Private cTitulo Private cAlias1 := "SC5" Private cAlias2 := "SC6" // Verifica se o pedido já está liberado If !Empty(SC5->C5_NOTA).Or.SC5->C5_LIBEROK=='E' .And. Empty(SC5->C5_BLQ) MsgStop("Este pedido está encerrado!") Else RegToMemory("SC5",.F.) RegToMemory("SC6",.F.) DefineCabec() DefineaCols(nOpcg) lRet:=Modelo3(cCadastro,cAlias1,cAlias2,aCpoEnchoice,cLinok,cTudook,nOpce,nOpcg,cFieldok,lVirtual,,aAltenchoice,nFreeze,,,nAlturaEnc) //retornará como true se clicar no botao confirmar if lRet cMensagem += "Esta rotina tem a finalidade de salvar alguns campos no PEDIDO DE VENDA LIBERADO"+CRLF+CRLF cMensagem += "APENAS os campos abaixo SERÃO SALVOS:"+CRLF+CRLF cMensagem += "Cabeçalho: "+CRLF cMensagem += "Cond.Pag,Tipo Frete,Mens.p/Nota,P.V.Cliente,Box Number,Equip/Line,Module,cont.Module,No.Caixa "+CRLF+CRLF cMensagem += "Itens:"+CRLF cMensagem += "Item P.C.,Num.Ped.Comp,Descrição,Data Fatura"+CRLF+CRLF if MsgYesNo(cMensagem+"CONFIRMA ALTERAÇÃO DOS DADOS ?", cCadastro) Processa({||Gravar()},cCadastro,"Alterando os dados, aguarde...") endif else RollbackSx8() endif Endif Return Static Function DefineCabec() Local aSC6 := {"C6_ITEM","C6_ITEMPC","C6_NUMPCOM","C6_PRODUTO","C6_DESCRI","C6_ENTREG","C6_ZZENTFA","C6_QTDVEN","C6_UNSVEN","C6_QTDLIB","C6_PRCVEN","C6_PRUNIT","C6_VALOR","C6_VALDESC","C6_DESCONT","C6_TES","C6_CF","C6_IDENTB6","C6_CONTRAT","C6_ITEMCON","C6_LOTECTL","C6_NUMLOTE","C6_ENTREG","C6_ITEMED","C6_BLQ"} Local nUsado aHeader := {} aCpoEnchoice:= {} nUsado:=0 //Monta a enchoice DbSelectArea("SX3") SX3->(DbSetOrder(1)) dbseek(cAlias1) while SX3->(!eof()) .AND. X3_ARQUIVO == cAlias1 IF X3USO(X3_USADO) .AND. CNIVEL >= X3_NIVEL AADD(ACPOENCHOICE,X3_CAMPO) endif dbskip() enddo //Monta o aHeader do grid conforme os campos definidos no array aSC6 (apenas os campos que deseja) //Caso contrário, se quiser todos os campos é necessário trocar o "For" por While, para que este faça a leitura de toda a tabela DbSelectArea("SX3") SX3->(DbSetOrder(2)) aHeader:={} For nX := 1 to Len(aSC6) If SX3->(DbSeek(aSC6[nX])) If X3USO(X3_USADO).And.cNivel>=X3_NIVEL nUsado:=nUsado+1 Aadd(aHeader, {TRIM(X3_TITULO), X3_CAMPO , X3_PICTURE, X3_TAMANHO, X3_DECIMAL,X3_VALID, X3_USADO , X3_TIPO , X3_ARQUIVO, X3_CONTEXT}) Endif Endif Next nX Return //Insere o conteudo no aCols do grid Static function DefineaCols(nOpc) Local nQtdcpo := 0 Local i := 0 Local nCols := 0 nQtdcpo := len(aHeader) aCols := {} dbselectarea(cAlias2) dbsetorder(1) dbseek(xfilial(cAlias2)+(cAlias1)->C5_NUM) while .not. eof() .and. (cAlias2)->C6_FILIAL == xfilial(cAlias2) .and. (cAlias2)->C6_NUM==(cAlias1)->C5_NUM aAdd(aCols,array(nQtdcpo+1)) nCols++ for i:= 1 to nQtdcpo if aHeader[i,10] <> "V" aCols[nCols,i] := Fieldget(Fieldpos(aHeader[i,2])) else aCols[nCols,i] := Criavar(aHeader[i,2],.T.) endif next i aCols[nCols,nQtdcpo+1] := .F. dbselectarea(cAlias2) dbskip() enddo Return //Gravar o conteudo dos campos Static Function Gravar() Local bcampo := { |nfield| field(nfield) } Local i:= 0 Local y:= 0 Local nitem := 0 Local nItem := aScan(aHeader,{|x| AllTrim(Upper(x[2]))=="C6_ITEM"}) Local nProduto := aScan(aHeader,{|x| AllTrim(Upper(x[2]))=="C6_PRODUTO"}) Local nPosCpo Local nCpo Local nI Local cCamposSC5 := "C5_CONDPAG|C5_TPFRETE|C5_MENNOTA|C5_ZZPVCL|C5_ZZBOX|C5_ZZEQUIP|C5_ZZMOD1|C5_ZZMOD2|C5_ZZCAIXA" Local cCamposSC6 := "C6_ITEMPC|C6_NUMPCOM|C6_DESCRI|C6_ZZENTFA" Begin Transaction //Gravando dados da enchoice dbselectarea(cAlias1) Reclock(cAlias1,.F.) for i:= 1 to fcount() incproc() if "FILIAL" $ FIELDNAME(i) Fieldput(i,xfilial(cAlias1)) else //Grava apenas os campos contidos na variavel cCamposSC5 If ( FieldName(i) $ cCamposSC5 ) Fieldput(i,M->&(EVAL(bcampo,i))) Endif endif next i Msunlock() //Gravando dados do grid dbSelectArea("SC6") SC6->(dbSetOrder(1)) For nI := 1 To Len(aCols) If !(aCols[nI, Len(aHeader)+1]) If SC6->(dbSeek( xFilial("SC6")+M->C5_NUM+aCols[nI,nItem]+aCols[nI,nProduto] )) RecLock("SC6",.F.) For nCpo := 1 to fCount() //Grava apenas os campos contidos na variavel $cCamposSC6 If (FieldName(nCpo)$cCamposSC6) nPosCpo := aScan(aHeader,{|x| AllTrim(x[2]) == AllTrim(FieldName(nCpo))}) If nPosCpo > 0 FieldPut(nCpo,aCols[nI,nPosCpo]) EndIf Endif Next nCpo SC6->(MsUnLock()) Endif Endif Next nI End Transaction Return |
Recomendo também a função do colega Marinado de Jesus, vide URL http://totvs-advpl-naldodj.googlecode.com/svn-history/r2/trunk/templates/P10/ndj_01/Projeto/NDJLib/NDJLib005.prg , a sua função está bem mais completa que a padrão Totvs.
Espero que o exemplo tenha sido útil!
4 comentários
Legal o artigo… realmente se formos fazer ‘na mão’ um modelo3 nós perderíamos um tempinho mesmo…
E, melhor do que isso seria irmos para o MVC mesmo né?
Parabéns pelo post!
Leonardo
http://www.userfunction.com.br
Tanto o modelo2, quanto o modelo3 é uma boa alternativa para quem ainda não conheceu o MVC do Protheus.
Em breve postarei o modelo2 e mais exemplos de MVC
Eu sempre acompanho o blog, acho que seria interessante e mais didatico, separar cada trecho e descrever o que cada trecho faz, pois ai quem acompanha e vai fazer os exemplos tem uma explicação do que o trecho de codigo faz, pois quem esta começando muitas vezes não consegue acompanha por não entender algo.
Mas o artigo esta exelente!
Olá João. Agradecemos pela dica, iremos reformular nosso site deixando-o mais didático possível.
abraços
Equipe BlogAdvpl