Protheus - Fazendo update na tabela SPC0X0 - Fluig e ADVPL

Prezado/Prezada,

eu tenho um dataset e tenho um código ADVPL. É um serviço REST. O serviço, pelo teste, funciona 100%.

Quando vou fazer uma alteração de um registro na tabela SPC010, funciona tudo 100%.
Mas, eu preciso alterar outro registro na tabela SPC020, coisa que não estou sabendo fazer.

Seria no Dastaset ou no ADVPL do Protheus a montagem da SQL passar a ser SPC020?

Pensei até que eu deveria trocar a Company no dataset de ‘companyId: 1 + ‘’,’ para ’ companyId: 2 + ‘’,', mas não deu certo.

Abaixo, o Dataset está assim (ignore o parâmetro ‘sufixo’, foi só um teste, não está sendo usado para nada):

function createDataset(fields, constraints, sortFields) {
//========================================================================================HOMOLOGAÇÃO
//ds_ucrg_rest_horaextra
let operacao ='-1';
let rejeitar ='-1';
let escritorio = '-1';
if(constraints !== null){
for (var i = 0; i < constraints.length; i++) {
if (constraints[i].fieldName == "OPERACAO") {
operacao = constraints[i].initialValue;
}//if constraints ==
if (constraints[i].fieldName == "REJEITAR") {
rejeitar= constraints[i].initialValue;
}//if constraints ==
if (constraints[i].fieldName == "ESCRITORIO") {
escritorio = constraints[i].initialValue;
}//if constraints ==
}//for
}//if constraints !==
var dataset = DatasetBuilder.newDataset();
dataset.addColumn('Retorno_get');
let matricula = fields[0];
let dataHE = fields[1];//YYYYMMDD
let qtd = fields[2];
let codigo = fields[3];

var clientService = fluigAPI.getAuthorizeClientService();
let data = "";
let varEndpoint = "";
if(operacao=="1"){
    //Seleciona um funcionário faz um PUT para rejeitar (ou, eventualmente, aprovar) HE
     //Rejeita = 1, põe 200 no campo PC_PDI; Rejeita = 0, põe '   ' no campo PC_PDI lá no código da API REST
     //matricula = '999999';
     let sufixo = '010';
     if (escritorio=='2') sufixo ='020';
          varEndpoint = '/api/crm/v1/HoraExtraTratamento/AlteraRegistro?Matricula='+matricula+'&DataHE='+dataHE+'&Quantidade='+qtd+'&Codigo='+codigo+'&Rejeita='+rejeitar+'&Sufixo='+sufixo;
     data = {
        companyId: 1 + '',
        serviceCode: 'REST_PROTHEUS_HOMO',
        endpoint: varEndpoint,
        method: 'PUT',
        timeoutService: '100',
        }
}//operacao 1
if(operacao=="2"){
    //pega um funcionário
    varEndpoint = '/api/crm/v1/HoraExtraTratamento/UmRegistro?Matricula='+matricula+'&DataHE='+dataHE+'&Quantidade='+qtd+'&Codigo='+codigo;
     data = {
        companyId: 1 + '',
        serviceCode: 'REST_PROTHEUS_HOMO',
        endpoint: varEndpoint,
        method: 'get',
        timeoutService: '100'
        }
}//operacao 2
log.info("ds_ucrg_dataset_lixao "+varEndpoint);
//A API que fiz,...
//...todos os parâmetros são passados no PATH, não usando a seção 'params'

/*
data = {
companyId: 1 + '',
serviceCode: 'REST_PROTHEUS_HOMO',
endpoint: '/api/crm/v1/HoraExtraTratamento/UmRegistro?Matricula=113457&DataHE=20260518&Quantidade=1&Codigo=101',
method: 'get',
timeoutService: '100'
}
/
/
data = {
companyId: 1 + '',
serviceCode: 'REST_PROTHEUS_HOMO',
endpoint: '/api/crm/v1/HoraExtraTratamento/Todos',
method: 'get',
timeoutService: '100'
}
*/
var vo = clientService.invoke(JSON.stringify(data));

if (vo.getResult() == null || vo.getResult().isEmpty()) {
    dataset.addRow(new Array("Retorno esta vazio"))
} else {
    dataset.addRow(new Array(vo.getResult()))
}
return dataset; 

}//createDataset

e o código ADVPL está assim:

WSMETHOD PUT AlteraRegistro WSRECEIVE Matricula,DataHE,Quantidade,Codigo,Rejeita,Sufixo WSSERVICE HoraExtraTratamento

//Parâmetro Rejeita = 1, põe 200 no campo PC_PDI; Rejeita = 0, põe '   ' no mesmo campo

Local lRet       := .T.

Local jResponse  := JsonObject():New()

Local aRegistros := {}

Local jLinha

Local cAliasFor

Local cSql := ""

Local nRec := 0

Local lRejeita := .T.

if ::Rejeita == '0'

    lRejeita := .F.

endif

cAliasFor := GetNextAlias() //CRIA ALIAS TEMPORARIO

//TEXTO QUERY

cSql :=" Select \* "+ENTER

cSql +=" FROM " + RetSQLName("SPC")+" "+ENTER

//cSql +=" FROM SPC" +::Sufixo+" "+ENTER

cSql +=" Where PC_FILIAL = '" + xFilial("SPC") + "'"+ENTER

cSql +=" AND D_E_L_E_T\_ = ' ' "+ENTER

cSql +=" AND PC_MAT = '"+::Matricula+"' "+ENTER

cSql +=" AND PC_DATA = '"+::DataHE+"' "+ENTER

cSql +=" AND PC_QUANTC = '"+::Quantidade+"' "+ENTER

cSql +=" AND PC_PD = '"+::Codigo+"' "

MemoWrite("sqlUpdate.txt",cSql)

//TRATAMENTO ADEQUACAO QUERY

cSql := ChangeQuery(cSql)

//CRIA TABELA TEMPORARIA

dbUseArea( .T.,"TOPCONN", TCGENQRY(,,cSql),(cAliasFor), .F., .T.)

//CONTA QUANTIDADE REGISTROS

Count To nRec

MemoWrite("contador.txt",cValToChar(nRec))

If nRec == 0

    jLinha := JsonObject():New()

    jLinha\['erro'\] := "Não encontrou o registro"

    DbSelectArea(cAliasFor)

    dbCloseArea()

    ::SetContentType("application/json")

    ::SetResponse(EncodeUTF8(jLinha:toJSON()))

    Return

EndIf



//ABRE TABELA TEMPORARIA

DbSelectArea(cAliasFor)

DbGoTop()



DbSelectArea("SPC")

DbGoto((cAliasFor)->R_E_C_N_O\_)



RecLock("SPC",.F.)

if lRejeita

    //está rejeitando a HE da pessoa

    SPC->PC_PDI := '200'

else

    //está modificando a rejeitação para aprovada

    SPC->PC_PDI := '   '

endif

msUnlock()

jLinha := JsonObject():New()



jLinha\['matricula'\] := (cAliasFor)->PC_MAT

jLinha\['codigo'\]    := (cAliasFor)->PC_PD

jLinha\['recno'\]    := (cAliasFor)->R_E_C_N_O\_



AAdd(aRegistros, jLinha)



//FECHA A TABELA TEMPORARIA

DbSelectArea(cAliasFor)

dbCloseArea()

    DbSelectArea("SPC")

dbCloseArea()

jResponse\['dados'\] := aRegistros

::SetContentType("application/json")

::SetResponse(EncodeUTF8(jResponse:toJSON()))

return lRet

Prezada/Prezado,

depois de muita luta, descobri (com ajuda de vários chatBots, é claro) que eu precisava pôr (sem muita segurança ainda, mas funcionou) no server.ini do servidor Protheus REST, estas duas seções:

[HTTPREST] 

Port=8032 

URIs=HTTPENV1 

SECURITY=1 

ACTIVE= 1

;o active=1 acima ativa a autenticação básica (Basic Auth) ou via Token (JW T)

[HTTPEN V1]

URL=/ rest

Instance s=1,1

CORSEn able=1

AllowO rigin=*

AllowHeaders=Authorization, Content-Type, Accept, Origin, X-Requested-With,  tenantId

AllowMethods=GET, POST, PUT, DELETE , OPTIONS

Pre pareIn=all

Public=fwjwt/refresh_t oken,auth  

TenantIdHea der=tenantId 

No código ADVPL, no método PUT em que se faz update de tabelas, está assim (agora a minha variável/parâmetro ::Sufixo recebe do Fluig ‘010’ ou ‘020’ para indicar que tabela eu quero, mas também indicando que ‘grupo/empresa’ estou trabalhando no momento:

#INCLUDE “TOTVS.CH”

#INCLUDE “RESTFUL.CH”

#DEFINE ENTER Chr(13)+Chr(10)

WSRESTFUL HoraExtraTratamento DESCRIPTION “Tratamento de horas extras”

WSDATA Matricula        AS STRING   OPTIONAL

WSDATA DataHE           AS STRING   OPTIONAL

WSDATA Quantidade       AS NUMERIC  OPTIONAL

WSDATA Codigo           AS STRING   OPTIONAL

WSDATA Rejeita          AS STRING   OPTIONAL

WSDATA Sufixo           AS STRING   OPTIONAL




WSMETHOD GET Todos ;

    DESCRIPTION "Retorna todas as HE aprovadas de todos os funcionários" ;

    WSSYNTAX "/api/crm/v1/HoraExtraTratamento/Todos" ;

    PATH "/api/crm/v1/HoraExtraTratamento/Todos"



WSMETHOD GET ListaFuncionario ;

    DESCRIPTION "Retorna todas as HE aprovadas de uma determinada matrícula" ;

    WSSYNTAX "/api/crm/v1/HoraExtraTratamento/ListaFuncionario?Matricula={Matricula}" ;

    PATH "/api/crm/v1/HoraExtraTratamento/ListaFuncionario"



WSMETHOD GET UmRegistro ;

    DESCRIPTION "Retorna um lançamento específico" ;

    WSSYNTAX "/api/crm/v1/HoraExtraTratamento/UmRegistro?Matricula={Matricula}&DataHE={DataHE}&Quantidade={Quantidade}&Codigo={Codigo}" ;

    PATH "/api/crm/v1/HoraExtraTratamento/UmRegistro"



WSMETHOD PUT AlteraRegistro ;

    DESCRIPTION "Altera um registro específico para 200" ;

    WSSYNTAX "/api/crm/v1/HoraExtraTratamento/AlteraRegistro?Matricula={Matricula}&DataHE={DataHE}&Quantidade={Quantidade}&Codigo={Codigo}&Rejeita={Rejeita}&Sufixo={Sufixo}" ;

    PATH "/api/crm/v1/HoraExtraTratamento/AlteraRegistro"

ENDWSRESTFUL

WSMETHOD GET Todos WSSERVICE HoraExtraTratamento

Local lRet       := .T.

Local jResponse  := JsonObject():New()

Local aRegistros := {}

Local jLinha

Local cAliasFor

Local cSql := ""

Local nRec := 0

cAliasFor := GetNextAlias() //CRIA ALIAS TEMPORARIO

//TEXTO QUERY

cSql :=" Select \* "+ENTER

cSql +=" FROM " + RetSQLName("SPC")+" "+ENTER

cSql +=" Where PC_FILIAL = '" + xFilial("SPC") + "'"+ENTER

cSql +=" AND D_E_L_E_T\_ = ' ' "+ENTER

cSql +=" AND PC_MAT = '113457'"

//TRATAMENTO ADEQUACAO QUERY

cSql := ChangeQuery(cSql)

//CRIA TABELA TEMPORARIA

dbUseArea( .T.,"TOPCONN", TCGENQRY(,,cSql),(cAliasFor), .F., .T.)

//CONVERSAO TIPO DE DADO

//TCSetField(cAliasFor,"A2_ULTCOM","D" )

//CONTA QUANTIDADE REGISTROS

Count To nRec

If nRec == 0

    Alert("NAO FORAM ENCONTRADOS DADOS, REFACA OS PARAMETROS","ATENCAO")

    DbSelectArea(cAliasFor)

    dbCloseArea()

    Return

EndIf

//ABRE TABELA TEMPORARIA

DbSelectArea(cAliasFor)

dbGoTop()

While !Eof()

    jLinha := JsonObject():New()



    jLinha\['matricula'\] := (cAliasFor)->PC_MAT

    jLinha\['codigo'\]    := (cAliasFor)->PC_PD



    AAdd(aRegistros, jLinha)



    (cAliasFor)->(DbSkip())

End

//FECHA A TABELA TEMPORARIA

DbSelectArea(cAliasFor)

dbCloseArea()

jResponse\['dados'\] := aRegistros

::SetContentType("application/json")

::SetResponse(EncodeUTF8(jResponse:toJSON()))

Return lRet

WSMETHOD GET ListaFuncionario WSRECEIVE Matricula WSSERVICE HoraExtraTratamento

Local lRet := .T.

//PARA PEGAR OS VALORES LÁ PASSADOS NO WSRECEIVE...

//… USE ::Matricula NO ADVPL, tal como cMatricula := ::Matricula

Return lRet

WSMETHOD GET UmRegistro WSRECEIVE Matricula,DataHE,Quantidade,Codigo WSSERVICE HoraExtraTratamento

Local lRet       := .T.

Local jResponse  := JsonObject():New()

Local cAliasWS   := 'SPC'

//–

//PARA PEGAR OS VALORES LÁ PASSADOS NO WSRECEIVE…

//… USE ::Matricula NO ADVPL, tal como cMatricula := ::Matricula

//–

DbSelectArea(cAliasWS)

(cAliasWS)->(DbSetOrder(2))

If (cAliasWS)->(MsSeek(FWxFilial(cAliasWS) +'113457'))

    jResponse\['matricula'\] := (cAliasWS)->PC_MAT

    jResponse\['data'\] := DtoC((cAliasWS)->PC_DATA)

    jResponse\['codigo'\] := (cAliasWS)->PC_PD

else

    Self:setStatus(500)

    jResponse\['error'\]    := 'Não achou a matrícula'

endif




Self:SetContentType("application/json")

Self:SetResponse(EncodeUTF8(jResponse:toJSON()))

Return lRet

WSMETHOD PUT AlteraRegistro WSRECEIVE Matricula,DataHE,Quantidade,Codigo,Rejeita,Sufixo WSSERVICE HoraExtraTratamento

Local lRet         := .T.

Local jResponse    := JsonObject():New()

Local aRegistros   := {}

Local jLinha

Local cAliasFor    := ""

Local cSql         := ""

Local cSqlUpdate   := ""

Local nRec         := 0

Local cTabelaFis   := ""

Local cValorPDI    := "200"



MemoWrite("0_antesValidacaoSufixo.txt", ::Sufixo)



// 1. MONTA O NOME DA TABELA FÍSICA DINAMICAMENTE (Ex: SPC010, SPC020)

If !Empty(::Sufixo)

    cTabelaFis := "SPC" + AllTrim(::Sufixo)

Else

    cTabelaFis := RetSQLName("SPC") // Fallback caso não venha o sufixo

EndIf



MemoWrite("1_tabelaAlvo.txt", cTabelaFis)



If ::Rejeita == '0'

    cValorPDI := '   '

EndIf



cAliasFor := GetNextAlias()



// 2. QUERY APONTANDO DIRETO PARA A TABELA DINÂMICA

cSql := " SELECT R_E_C_N_O\_ AS REC_NUM, PC_MAT, PC_PD " + ENTER

cSql += " FROM " + cTabelaFis + " " + ENTER

cSql += " WHERE PC_FILIAL = '" + xFilial("SPC") + "' " + ENTER

cSql += " AND D_E_L_E_T\_ = ' ' " + ENTER

cSql += " AND PC_MAT = '" + ::Matricula + "' " + ENTER

cSql += " AND PC_DATA = '" + ::DataHE + "' " + ENTER

cSql += " AND PC_QUANTC = '" + ::Quantidade + "' " + ENTER

cSql += " AND PC_PD = '" + ::Codigo + "' "



MemoWrite("2_cSqlBusca.txt", cSql)



cSql := ChangeQuery(cSql)

dbUseArea(.T., "TOPCONN", TCGENQRY(,, cSql), (cAliasFor), .F., .T.)



Count To nRec

MemoWrite("3_contador.txt", cValToChar(nRec))



If nRec == 0

    jLinha := JsonObject():New()

    jLinha\['erro'\] := "Não encontrou o registro"

    

    (cAliasFor)->(dbCloseArea())

    

    ::SetContentType("application/json")

    ::SetResponse(EncodeUTF8(jLinha:toJSON()))

    Return .T.

EndIf



(cAliasFor)->(DbGoTop())



// 3. EXECUTA O UPDATE DIRETO NA TABELA DINÂMICA (SPC010, SPC020)

cSqlUpdate := " UPDATE " + cTabelaFis + " " + ENTER

cSqlUpdate += " SET PC_PDI = '" + cValorPDI + "' " + ENTER

cSqlUpdate += " WHERE R_E_C_N_O\_ = " + cValToChar((cAliasFor)->REC_NUM) + " "



MemoWrite("4_cSqlUpdate.txt", cSqlUpdate)



If TCSQLExec(cSqlUpdate) < 0

    jLinha := JsonObject():New()

    jLinha\['erro'\] := "Falha ao atualizar no banco: " + TCSQLError()

    

    (cAliasFor)->(dbCloseArea())

    

    ::SetContentType("application/json")

    ::SetResponse(EncodeUTF8(jLinha:toJSON()))

    Return .T.

EndIf



// 4. PREPARA A RESPOSTA JSON

jLinha := JsonObject():New()

jLinha\['matricula'\] := (cAliasFor)->PC_MAT

jLinha\['codigo'\]    := (cAliasFor)->PC_PD

jLinha\['recno'\]     := (cAliasFor)->REC_NUM



AAdd(aRegistros, jLinha)



(cAliasFor)->(dbCloseArea())



jResponse\['dados'\] := aRegistros

::SetContentType("application/json")

::SetResponse(EncodeUTF8(jResponse:toJSON()))

Return lRet

O protheus não aceita mais basic auth por padrão nos servicos rest. Não sei ao certo apartir de qual versão isso ocorreu mas ja tive esse bo faz mais de um ano. Logo você esta forçando algo que não deveria o correto e usar oauth. Vale essa resalva.

Obrigado, Daniel, vale a ressalva.