Hi Otto.
I paid for the webinar but couldn't watch it online that day. I watched it later and I'll tell you that it did work.
I contacted Carles to discuss the ADS issue and he recommended UThttp. Based on the webinar and some tips from Carles, I managed to create an example.
I managed to add my tAds class and other functions.
Then I watched some of Carles' videos at https://carles9000.github.io/index_doc_en.html and I believe there's still a lot to learn.
I'm using VS Code with Copilot and the Claude Opus 4.5 AI agent.
On Claude's ASK, talk to him and tell him to read the documentation on the page and the source code that you need to include in a GitHub project. Then ask him to memorize the subject and register it on GitHub.
I'll show you some screenshots and source files here.
In the Copilot settings panel, enable Memory.

Some screens


Some sources from the program.
IniCobrnca.html
<?prg
#include "lib/tweb/tweb.ch"
LOCAL o, oWeb
DEFINE WEB oWeb TITLE 'CartWeb - Identificação html'
oWeb:cLang := 'pt-br'
oWeb:AddJs( 'https://code.jquery.com/jquery-3.6.0.min.js' )
oWeb:AddJs( 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js' )
oWeb:AddCss( 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css' )
oWeb:AddCss( 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css' )
DEFINE FORM o ID 'myform' API 'api_cobranca' OF oWeb
o:lDessign := .f.
o:lFluid := .t.
INIT FORM o
HTML o
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
margin: 0;
}
.card-cpf {
margin: auto;
margin-top: 12vh;
width: 90%;
max-width: 460px;
border: none;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
background-color: #fff;
padding: 40px 30px;
}
@media only screen and (max-width: 576px) {
.card-cpf {
width: 95% !important;
max-width: 100% !important;
margin-top: 4vh;
padding: 20px 15px;
}
}
.card-cpf h4 {
color: #333;
font-weight: 600;
}
.card-cpf .subtitle {
color: #777;
font-size: 0.9rem;
margin-bottom: 25px;
}
.toggle-doc {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
}
.toggle-doc .btn {
min-width: 100px;
}
.toggle-doc .btn.active {
background-color: #667eea;
border-color: #667eea;
color: #fff;
}
.toggle-doc .btn:not(.active) {
background-color: #f0f0f0;
border-color: #ddd;
color: #555;
}
</style>
ENDTEXT
HTML o
<div class="card-cpf">
<div class="text-center">
<h4><i class="fa fa-id-card"></i> Identificação</h4>
<p class="subtitle">Informe seu CPF ou CNPJ para continuar</p>
</div>
<div class="toggle-doc">
<button type="button" class="btn btn-sm active" id="btnCpf" onclick="toggleDoc('cpf')">CPF</button>
<button type="button" class="btn btn-sm" id="btnCnpj" onclick="toggleDoc('cnpj')">CNPJ</button>
</div>
<div class="form-group">
<label for="documento"><i class="fa fa-file-text-o"></i> Documento</label>
<input type="text" class="form-control form-control-lg" id="documento"
placeholder="000.000.000-00" maxlength="18" autocomplete="off"
inputmode="numeric" style="text-align:center; font-size:1.2rem; letter-spacing:1px;">
<input type="hidden" id="tipo_doc" value="cpf">
</div>
<div class="text-center mt-4" style="display:flex; justify-content:center; gap:10px;">
<button type="button" class="btn btn-lg"
style="background-color:#667eea; color:#fff; min-width:150px; border-radius:8px;"
onclick="validarDocumento()">
<i class="fa fa-arrow-right"></i> Continuar
</button>
<button type="button" class="btn btn-lg btn-outline-secondary"
style="min-width:150px; border-radius:8px;"
onclick="fecharPagina();">
<i class="fa fa-times"></i> Cancelar
</button>
</div>
</div>
ENDTEXT
HTML o
<script>
var tipoDoc = 'cpf';
function fecharPagina() {
window.close();
// Navegadores mĂłveis bloqueiam window.close() em abas nĂŁo abertas via JS
setTimeout(function() {
// Se nĂŁo fechou, navega para about:blank
window.location.href = 'about:blank';
}, 300);
}
function toggleDoc(tipo) {
tipoDoc = tipo;
$('#tipo_doc').val(tipo);
var inp = $('#documento');
inp.val('');
inp.focus();
if (tipo === 'cpf') {
inp.attr('placeholder', '000.000.000-00');
inp.attr('maxlength', '14');
$('#btnCpf').addClass('active');
$('#btnCnpj').removeClass('active');
} else {
inp.attr('placeholder', '00.000.000/0000-00');
inp.attr('maxlength', '18');
$('#btnCnpj').addClass('active');
$('#btnCpf').removeClass('active');
}
}
// Máscara CPF: 000.000.000-00
// Máscara CNPJ: 00.000.000/0000-00
$('#documento').on('input', function() {
var v = $(this).val().replace(/\D/g, '');
if (tipoDoc === 'cpf') {
if (v.length > 11) v = v.substring(0, 11);
if (v.length > 9) v = v.replace(/(\d{3})(\d{3})(\d{3})(\d{1,2})/, '$1.$2.$3-$4');
else if (v.length > 6) v = v.replace(/(\d{3})(\d{3})(\d{1,3})/, '$1.$2.$3');
else if (v.length > 3) v = v.replace(/(\d{3})(\d{1,3})/, '$1.$2');
} else {
if (v.length > 14) v = v.substring(0, 14);
if (v.length > 12) v = v.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{1,2})/, '$1.$2.$3/$4-$5');
else if (v.length > 8) v = v.replace(/(\d{2})(\d{3})(\d{3})(\d{1,4})/, '$1.$2.$3/$4');
else if (v.length > 5) v = v.replace(/(\d{2})(\d{3})(\d{1,3})/, '$1.$2.$3');
else if (v.length > 2) v = v.replace(/(\d{2})(\d{1,3})/, '$1.$2');
}
$(this).val(v);
});
$('#documento').on('keypress', function(e) {
if (e.which === 13) {
validarDocumento();
}
});
function validarCPF(cpf) {
cpf = cpf.replace(/\D/g, '');
if (cpf.length !== 11) return false;
if (/^(\d)\1{10}$/.test(cpf)) return false;
var soma = 0, resto;
for (var i = 1; i <= 9; i++) soma += parseInt(cpf.substring(i-1, i)) * (11 - i);
resto = (soma * 10) % 11;
if (resto === 10 || resto === 11) resto = 0;
if (resto !== parseInt(cpf.substring(9, 10))) return false;
soma = 0;
for (var i = 1; i <= 10; i++) soma += parseInt(cpf.substring(i-1, i)) * (12 - i);
resto = (soma * 10) % 11;
if (resto === 10 || resto === 11) resto = 0;
if (resto !== parseInt(cpf.substring(10, 11))) return false;
return true;
}
function validarCNPJ(cnpj) {
cnpj = cnpj.replace(/\D/g, '');
if (cnpj.length !== 14) return false;
if (/^(\d)\1{13}$/.test(cnpj)) return false;
var tamanho = cnpj.length - 2;
var numeros = cnpj.substring(0, tamanho);
var digitos = cnpj.substring(tamanho);
var soma = 0, pos = tamanho - 7;
for (var i = tamanho; i >= 1; i--) {
soma += numeros.charAt(tamanho - i) * pos--;
if (pos < 2) pos = 9;
}
var resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
if (resultado != digitos.charAt(0)) return false;
tamanho = tamanho + 1;
numeros = cnpj.substring(0, tamanho);
soma = 0; pos = tamanho - 7;
for (var i = tamanho; i >= 1; i--) {
soma += numeros.charAt(tamanho - i) * pos--;
if (pos < 2) pos = 9;
}
resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
if (resultado != digitos.charAt(1)) return false;
return true;
}
function validarDocumento() {
var doc = $('#documento').val().replace(/\D/g, '');
var tipo = tipoDoc;
if (doc.length === 0) {
alert('Por favor, informe o ' + tipo.toUpperCase());
$('#documento').focus();
return;
}
if (tipo === 'cpf' && !validarCPF(doc)) {
alert('CPF inválido. Verifique e tente novamente.');
$('#documento').focus();
return;
}
if (tipo === 'cnpj' && !validarCNPJ(doc)) {
alert('CNPJ inválido. Verifique e tente novamente.');
$('#documento').focus();
return;
}
MsgApi('api_cobranca', 'consultar2', { tipo: tipo, documento: doc });
}
function exibirResultado(f_hDsCursorResultado) {
var aStruct = f_hDsCursorResultado.struct;
var aData = f_hDsCursorResultado.data;
if (!aData || aData.length === 0) {
alert('Nenhum registro encontrado.');
return;
}
var labelMap = {
'P_DEVPRO_C_DEVEDOR_NOME': 'Nome ',
'DEVEDOR_DOC_VALIDO': 'Documento CPF/CNPJ ',
'PROTESTO_APONTA': 'NĂşmero do Apontamento',
'PROTESTO_SEQ_DATA': 'Data da Apresentação',
'PROTESTO_VALOR': 'Valor do TĂtulo',
'PROTESTO_NUMERO': 'NĂşmero do TĂtulo',
'PROTESTO_DT_EMISSAO': 'Data de EmissĂŁo',
'PROTESTO_DT_VENCE': 'Data de Vencimento',
'PROTESTO_CREDOR': 'Credor ',
'PROTESTO_DAT_APONTA': 'Data de Apontamento',
'PROTESTO_DAT_VENCE': 'Data Limite para Pagamento',
'PROTESTO_VAL_APONTA': 'Valor dos Emolumentos',
'PROTESTO_VAL_DILIGE': 'Valor das DiligĂŞncias'
};
var camposData = ['PROTESTO_SEQ_DATA', 'PROTESTO_DT_EMISSAO', 'PROTESTO_DT_VENCE',
'PROTESTO_DAT_APONTA', 'PROTESTO_DAT_VENCE'];
var camposValor = ['PROTESTO_VALOR', 'PROTESTO_VAL_APONTA', 'PROTESTO_VAL_DILIGE'];
function formatarData(v) {
if (!v) return '';
var s = String(v).replace(/\D/g, '');
if (s.length === 8) return s.substring(6,8) + '/' + s.substring(4,6) + '/' + s.substring(0,4);
var d = new Date(v);
if (isNaN(d.getTime())) return v;
var dd = ('0' + d.getDate()).slice(-2);
var mm = ('0' + (d.getMonth()+1)).slice(-2);
return dd + '/' + mm + '/' + d.getFullYear();
}
function formatarValor(v) {
if (v === null || v === undefined || v === '') return 'R$ 0,00';
var n = parseFloat(v);
if (isNaN(n)) return v;
return 'R$ ' + n.toFixed(2).replace('.', ',').replace(/\B(?=(\d{3})+(?!\d))/g, '.');
}
function formatarCampo(fieldName, val) {
if (camposData.indexOf(fieldName) !== -1) return formatarData(val);
if (camposValor.indexOf(fieldName) !== -1) return formatarValor(val);
return (val !== null && val !== undefined ? val : '');
}
var html = '';
for (var i = 0; i < aData.length; i++) {
html += '<div class="card mb-3" style="border-radius:10px; box-shadow:0 2px 8px rgba(0,0,0,0.1);">';
html += '<div class="card-body">';
html += '<h6 class="card-title" style="color:#667eea; font-weight:600;">TĂtulo ' + (i + 1) + '</h6>';
html += '<hr style="margin:8px 0;">';
for (var c = 0; c < aStruct.length; c++) {
var fieldName = aStruct[c][0];
var label = labelMap[fieldName] || fieldName;
var val = formatarCampo(fieldName, aData[i][fieldName]);
var negrito = (fieldName === 'PROTESTO_VALOR' || fieldName === 'PROTESTO_DAT_VENCE');
html += '<div class="d-flex justify-content-between" style="padding:3px 0; border-bottom:1px solid #f0f0f0;">';
html += '<strong style="color:#555; font-size:0.76rem;">' + label + '</strong>';
html += negrito
? '<strong style="font-size:0.76rem;">' + val + '</strong>'
: '<span style="font-size:0.76rem;">' + val + '</span>';
html += '</div>';
}
var totalPag = (parseFloat(aData[i]['PROTESTO_VALOR']) || 0)
+ (parseFloat(aData[i]['PROTESTO_VAL_APONTA']) || 0)
+ (parseFloat(aData[i]['PROTESTO_VAL_DILIGE']) || 0);
html += '<div class="d-flex justify-content-between" style="padding:8px 0; margin-top:6px; background-color:#f0f4ff; border-radius:6px; padding-left:8px; padding-right:8px;">';
html += '<strong style="color:#667eea; font-size:0.85rem;">Valor Total para Pagamento</strong>';
html += '<strong style="color:#667eea; font-size:0.85rem;">' + formatarValor(totalPag) + '</strong>';
html += '</div>';
html += '<div class="text-center" style="margin-top:10px;">';
html += '<button type="button" class="btn btn-sm" style="background-color:#28a745; color:#fff; border-radius:6px; width:100%;" onclick="baixarBoleto(' + i + ')">';
html += '<i class="fa fa-download"></i> Baixe o Boleto para Pagamento</button>';
html += '</div>';
html += '</div></div>';
}
$('.card-cpf').css({'width': '90%', 'max-width': '870px'}).html(
'<div class="text-center"><h4><i class="fa fa-list"></i> TĂtulos para pagamentos</h4>' +
'<p class="subtitle">' + aData.length + ' tĂtulo(s) encontrado(s)</p></div>' +
'<div style="max-height:60vh; overflow-y:auto;">' + html + '</div>' +
'<div class="text-center mt-3">' +
'<button type="button" class="btn btn-lg" style="background-color:#667eea; color:#fff; border-radius:8px;" onclick="location.reload();">' +
'<i class="fa fa-arrow-left"></i> Voltar</button></div>'
);
}
var _dadosResultado = null;
var _exibirResultadoOriginal = exibirResultado;
exibirResultado = function(f_hDsCursorResultado) {
_dadosResultado = f_hDsCursorResultado;
_exibirResultadoOriginal(f_hDsCursorResultado);
};
function baixarBoleto(idx) {
if (!_dadosResultado || !_dadosResultado.data || !_dadosResultado.data[idx]) return;
var reg = _dadosResultado.data[idx];
// TODO: chamar API para gerar boleto
// MsgApi('api_cobranca', 'boleto', { aponta: reg['PROTESTO_APONTA'] });
alert('Função de boleto será implementada em breve.');
}
$(document).ready(function() {
toggleDoc('cpf');
$('#documento').focus();
});
</script>
ENDTEXT
ENDFORM o
INIT WEB oWeb RETURN
?>
CartWeb.prg = App.prg
#include 'lib/uhttpd2/uhttpd2.ch'
request DBFCDX
request TWEB
request ORDKEYNO
request DBSKIP, __DbREINDEX
// Default codepage ------
//REQUEST HB_CODEPAGE_ES850
//REQUEST HB_LANG_ES
//REQUEST HB_CODEPAGE_ESWIN
// -----------------------
//REQUEST HB_CODEPAGE_ESMWIN
//REQUEST HB_CODEPAGE_ES850C
//REQUEST HB_CODEPAGE_FR850
//REQUEST HB_CODEPAGE_FR850M
//REQUEST HB_CODEPAGE_FRISO
//REQUEST HB_CODEPAGE_PL852
//REQUEST HB_CODEPAGE_PLISO
//REQUEST HB_CODEPAGE_PLMAZ
//REQUEST HB_CODEPAGE_PLWIN
//REQUEST HB_CODEPAGE_PT850
//REQUEST HB_CODEPAGE_PT860
REQUEST HB_CODEPAGE_PTISO
// -----------------------
REQUEST hb_cdpList
#define VK_ESCAPE 27
#define APP_VERSION 'CartWeb v1.0.0'
// -------------------------------------------------- //
function main()
hb_threadStart( @WebServer() )
while inkey(0) != VK_ESCAPE
end
retu nil
// -------------------------------------------------- //
function WebServer( hConfig )
local oServer := Httpd2()
local hCfg := Config()
HB_HCaseMatch( hCfg, .F. )
oServer:SetPort( HB_HGetDef( hCfg, 'port', 81 ) )
oServer:bInit := {|hInfo| ServerInfo(), OpenUrl( hInfo ) }
// Routing...
//oServer:Route( '/' , 'main.html' )
//oServer:Route( 'splash' , 'splash.html' )
//oServer:Route( '/' , 'security/login.html' )
oServer:Route( 'meuprotesto' , 'InitCobranca.html' )
//oServer:Route( 'login' , 'security/login.html' )
//oServer:Route( 'logout' , 'logout' )
//oServer:Route( 'dashboard' , 'dashboard' ) // Ull! direct to dashboard function :-)
//oServer:Route( 'browse' , 'dbu/browse.html' )
//oServer:Route( 'structure' , 'dbu/structure.html' )
//oServer:Route( 'indexes' , 'dbu/indexes.html' )
//oServer:Route( 'pack' , 'dbu/pack.html' )
//oServer:Route( 'server_info', 'dbu/server_info.html' )
//oServer:Route( 'users' , 'dbu/tables/users.html' )
//oServer:Route( 'repository' , 'dbu/tables/repository.html' )
//oServer:Route( 'about' , 'dbu/about.html' )
// -----------------------------------------------------------------------//
IF ! oServer:Run()
? "=> Server error:", oServer:cError
RETU 1
ENDIF
RETURN 0
// -------------------------------------------------- //
function ServerInfo()
Local lc_hCfgsIni
local hCfg := UGetServerInfo()
lc_hCfgsIni := INI_CFGS()
hCfg[ 'path' ] := HB_DIRBASE()
hCfg[ 'os' ] := os()
hCfg[ 'harbour' ] := version()
hCfg[ 'builddate' ] := HB_BUILDDATE()
hCfg[ 'compiler' ] := HB_compiler()
hCfg[ 'codepage' ] := hb_SetCodePage() + '/' + hb_cdpUniID( hb_SetCodePage() )
hCfg[ 'version_tweb' ] := TWebVersion()
Console '---------------------------------'
Console 'DominiumCart WebServer Info'
Console '---------------------------------'
Console 'Path.............: ' + hCfg[ 'path' ]
Console 'Version UT.......: ' + hCfg[ 'version' ]
Console 'Start............: ' + hCfg[ 'start' ]
Console 'Port.............: ' + ltrim(str(hCfg[ 'port' ]))
Console 'OS...............: ' + hCfg[ 'os' ]
Console 'Harbour..........: ' + hCfg[ 'harbour' ]
Console 'Build date.......: ' + hCfg[ 'builddate' ]
Console 'Compiler.........: ' + hCfg[ 'compiler' ]
Console 'SSL..............: ' + if( hCfg[ 'ssl' ], 'Yes', 'No' )
Console 'Trace............: ' + if( hCfg[ 'debug' ], 'Yes', 'No' )
Console 'Codepage.........: ' + hCfg[ 'codepage' ]
Console 'UTF8 (actived)...: ' + if( hCfg[ 'utf8' ], 'Yes', 'No' )
Console 'Base de dados....: ' + lc_hCfgsIni[ 'ServerDados' ]
Console '---------------------------------'
Console 'Escape for exit...'
retu nil
// -------------------------------------------------- //
function Config()
local hCfg
//RddSetDefault( 'DBFCDX' )
//HB_LANGSELECT('ES')
//HB_SetCodePage ( "ESWIN" )
//SET( _SET_DBCODEPAGE, 'ESWIN' )
//SET( _SET_DELETED, 'ON' )
//HB_LANGSELECT('ES')
//HB_SetCodePage ( "ESWIN" )
//SET( _SET_DBCODEPAGE, 'ESWIN' )
//SET( _SET_DELETED, 'ON' )
REQUEST HB_CODEPAGE_PTISO
HB_SETCODEPAGE( "PTISO" )
REQUEST HB_LANG_PT_BR
HB_LANGSELECT( 'PT_BR' )
SET AUTOPEN OFF
SET DATE FORMAT TO 'DD/MM/YYYY'
CheckDbfs()
hCfg := CheckIni()
retu hCfg
// -------------------------------------------------- //
function AppVersion() ; retu APP_VERSION
function AppPathData() ; retu HB_DIRBASE() + 'data.sys' + hb_ps()
// -------------------------------------------------- //
function AppGetRepo()
local oRepo := TDbf():New( 'repository.dbf', 'repository.cdx', 'name' )
local aRows := {}
Aadd( aRows, '' )
while (oRepo:cAlias)->( !eof() )
if (oRepo:cAlias)->active
Aadd( aRows, alltrim((oRepo:cAlias)->name ))
endif
(oRepo:cAlias)->(dbskip())
end
(oRepo:cAlias)->( DbCloseArea() )
retu aRows
// -------------------------------------------------- //
function AppRepo2Path( cRepo )
local cPath := ''
local oRepo := TDbf():New( 'repository.dbf', 'repository.cdx', 'name' )
if oRepo:Seek( cRepo )
cPath := oRepo:Row()[ 'PATH' ]
endif
retu cPath
//----------------------------------------------------------------------------//
#define SW_SHOW 5
static function OpenUrl( hInfo )
local cUrl := ''
cUrl := if( hInfo[ 'ssl' ], 'https://localhost', 'http://localhost' )
if hInfo[ 'port' ] != 80
cUrl += ':' + ltrim(str( hInfo[ 'port' ] ))
endif
#ifdef __PLATFORM__WINDOWS
WAPI_ShellExecute( nil, "open", cUrl, nil, nil, SW_SHOW )
#else
hb_run( 'xdg-open ' + cUrl )
#endif
retu nil
Api_cobranca.prg
#include '.\uhttpd2.ch'
#include ".\tweb.ch"
function Api_Cobranca( oDom )
do case
case oDom:GetProc() == 'consultar2' ; Cobranca_Consultar( oDom )
otherwise
oDom:SetError( "Proc don't defined => " + oDom:GetProc())
endcase
retu oDom:Send()
// -------------------------------------------------- //
static function Cobranca_Consultar( oDom )
local cTipo := oDom:Get( 'tipo' )
local cDocumento := oDom:Get( 'documento' )
local nConn := -1
local cQuery := ""
local aVars := {}
local aResultado := {}
local nI
Local lc_oDs_TitulosPendentes := Nil
Local lc_hCursorResultado := Nil // Hash para armazenar o cursor de resultado da consulta de tads em hDsCursorsHash
// Remove formatação do documento (pontos, traços, barras)
//cDocumento := StrTran( cDocumento, ".", "" )
//cDocumento := StrTran( cDocumento, "-", "" )
//cDocumento := StrTran( cDocumento, "/", "" )
cDocumento := AllTrim( cDocumento )
cDocumento := DOC_CPF_CNPJ_FORMAT( cDocumento )
if empty( cDocumento )
oDom:SetError( "Documento nĂŁo informado." )
return nil
endif
// Conecta ao dicionário de dados
nConn := DictionaryConnectionNew(oDom)
//nConn := -1 // Forçando erro de conexão para teste
//oDom:SetMsg( "nConn = " + AllTrim(Str(nConn)) )
//Return nil
if nConn < 0
oDom:SetError( "NĂŁo foi possĂvel conectar ao banco de dados." )
return nil
endif
// Cria objeto tAds para executar a query SELECT
// DB_PROTESTO DB_P_DEVPRO DB_DEVEDOR
lc_oDs_TitulosPendentes := tAds():DsNew(1/*1-Select*/, nConn)
/*
Text Into lc_oDs_TitulosPendentes:cQrySql
Select
Tb01.SEQ_PROT AS P_DEVPRO_SEQ_PROT,
Tb01.SEQ_DATA AS P_DEVPRO_SEQ_DATA,
Tb01.N_DEVEDOR AS P_DEVPRO_N_DEVEDOR,
Tb01.cDevedorNome AS P_DEVPRO_C_DEVEDOR_NOME,
Tb02.SEQ_PROT AS PROTESTO_SEQ_PROT,
Tb02.SEQ_DATA AS PROTESTO_SEQ_DATA,
Tb02.nCodigoPortador AS PROTESTO_N_CODIGO_PORTADOR,
Tb02.cCodigoPortador AS PROTESTO_C_CODIGO_PORTADOR,
Tb02.NTIPO_TIT AS PROTESTO_N_TIPO_TIT,
Tb02.VALOR AS PROTESTO_VALOR,
Tb02.NUMERO AS PROTESTO_NUMERO,
Tb02.DT_EMISSAO AS PROTESTO_DT_EMISSAO,
Tb02.DT_VENCE AS PROTESTO_DT_VENCE,
Tb02.CREDOR AS PROTESTO_CREDOR,
Tb02.APONTA AS PROTESTO_APONTA,
Tb02.N_SQBOLETO AS PROTESTO_N_SQBOLETO,
Tb02.DAT_APONTA AS PROTESTO_DAT_APONTA,
Tb02.DAT_VENCE AS PROTESTO_DAT_VENCE,
Tb02.VAL_APONTA AS PROTESTO_VAL_APONTA,
Tb02.VAL_DILIGE AS PROTESTO_VAL_DILIGE,
Tb03.NCODIGO AS DEVEDOR_NCODIGO,
Tb03.NOME AS DEVEDOR_NOME,
Tb03.CPF AS DEVEDOR_CPF,
Tb03.CGC AS DEVEDOR_CGC,
Tb03.cCelular AS DEVEDOR_CELULAR
*/
Text Into lc_oDs_TitulosPendentes:cQrySql
Select
Tb01.cDevedorNome AS P_DEVPRO_C_DEVEDOR_NOME,
IIF(Tb03.NPESSOA = 1, Tb03.CPF, Tb03.CGC) AS DEVEDOR_DOC_VALIDO,
Tb02.APONTA AS PROTESTO_APONTA,
Tb02.SEQ_DATA AS PROTESTO_SEQ_DATA,
Tb02.VALOR AS PROTESTO_VALOR,
Tb02.NUMERO AS PROTESTO_NUMERO,
Tb02.DT_EMISSAO AS PROTESTO_DT_EMISSAO,
Tb02.DT_VENCE AS PROTESTO_DT_VENCE,
Tb02.CREDOR AS PROTESTO_CREDOR,
Tb02.DAT_APONTA AS PROTESTO_DAT_APONTA,
Tb02.DAT_VENCE AS PROTESTO_DAT_VENCE,
Tb02.VAL_APONTA AS PROTESTO_VAL_APONTA,
Tb02.VAL_DILIGE AS PROTESTO_VAL_DILIGE
From P_DEVPRO AS Tb01
Inner join PROTESTO AS Tb02 On Tb01.SEQ_PROT = Tb02.SEQ_PROT
left join DEVEDOR AS Tb03 On Tb01.N_DEVEDOR = Tb03.NCODIGO
__WHERE__ __GROUP_BY__ __ORDER_BY__ ;
EndText
lc_oDs_TitulosPendentes:nCacheDefault := 100 //Page
lc_oDs_TitulosPendentes:lDataLoadOnSkip := .T.
lc_oDs_TitulosPendentes:lDataLoadBinaryField := .F.
lc_oDs_TitulosPendentes:lDsCursorsToTemp := .F.
lc_oDs_TitulosPendentes:lDsCursorsToJson := .T.
//lc_oDs_TitulosPendentes:aFieldsTempIndex := {"Field1","Field2"}
If cTipo == "cpf"
Text Into lc_oDs_TitulosPendentes:cDsWhere
Where Tb03.CPF = _cDocumento_
and Tb02.APONTA > 0
and Tb02.TIP_SOLUCA = 0
EndText
Elseif cTipo == "cnpj"
Text Into lc_oDs_TitulosPendentes:cDsWhere
Where Tb03.CGC = _cDocumento_
and Tb02.APONTA > 0
and Tb02.TIP_SOLUCA = 0
EndText
Else
oDom:SetError( "Tipo de documento inválido. Use 'cpf' ou 'cnpj'." )
lc_oDs_TitulosPendentes:End()
DictionaryConnectionClose( nConn )
return nil
EndIf
//Text Into lc_oDs_TitulosPendentes:cDsGroupBy
// Group By
//EndText
//Text Into lc_oDs_TitulosPendentes:cDsOrderBy
// Order By
//EndText
lc_oDs_TitulosPendentes:DsAddVar("_cDocumento_",cDocumento)
//lc_oDs_TitulosPendentes:DsExecute()
// Executa a query
if ! lc_oDs_TitulosPendentes:DsExecute()
oDom:SetError( "Erro ao consultar documento: " + AllTrim(Str(lc_oDs_TitulosPendentes:nErrorSql)) )
lc_oDs_TitulosPendentes:End()
DictionaryConnectionClose( nConn )
return nil
endif
hb_MemoWrit( "Last_Qry.txt", lc_oDs_TitulosPendentes:cQrySqlLast)
//oDom:SetMsg( "Documento encontrado. " + AllTrim(Str(Len(lc_hCursorResultado['data']))) + " registro(s)." )
//Return Nil
// Verifica se encontrou registros
if lc_oDs_TitulosPendentes:KeyCount() == 0
lc_oDs_TitulosPendentes:End()
DictionaryConnectionClose( nConn )
oDom:SetError( "Nenhum registro encontrado para o documento informado." )
return nil
endif
// Armazena o cursor de resultado em hDsCursorsHash usando nConn como chave
lc_hCursorResultado := lc_oDs_TitulosPendentes:hDsCursorsHash
// Fecha cursor e conexĂŁo
lc_oDs_TitulosPendentes:End()
DictionaryConnectionClose( nConn )
// Envia os dados para o frontend
oDom:SetJS( "exibirResultado", lc_hCursorResultado ) // Envia o hash com estrutura e dados para a função JavaScript exibirResultado(data)
return nil
// -------------------------------------------------- //