next-finance-mcp 0.9.39 → 0.9.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +19 -8
- package/dist/client.js +85 -52
- package/dist/index.js +21 -10
- package/package.json +2 -1
package/dist/client.d.ts
CHANGED
|
@@ -123,6 +123,7 @@ export interface CriteriosLancamento {
|
|
|
123
123
|
data: string;
|
|
124
124
|
valor?: number;
|
|
125
125
|
descricao?: string;
|
|
126
|
+
moeda?: string;
|
|
126
127
|
}
|
|
127
128
|
/** Edita um lançamento existente. Localiza por critérios e aplica as alterações. */
|
|
128
129
|
export interface EditarLancamentoOpts extends CriteriosLancamento {
|
|
@@ -364,6 +365,7 @@ export declare function buscarLancamentos(opts: FiltroLancamentos): Promise<Resu
|
|
|
364
365
|
export interface TituloSlim {
|
|
365
366
|
vencimento: string;
|
|
366
367
|
valor: number;
|
|
368
|
+
moeda: string;
|
|
367
369
|
contraparte: string;
|
|
368
370
|
conta: string;
|
|
369
371
|
em_cobranca: boolean;
|
|
@@ -378,12 +380,21 @@ export interface FiltroTitulos {
|
|
|
378
380
|
dataInicio?: string;
|
|
379
381
|
dataFim?: string;
|
|
380
382
|
busca?: string;
|
|
383
|
+
moeda?: string;
|
|
381
384
|
apenasVencidos?: boolean;
|
|
382
385
|
incluirCobranca?: boolean;
|
|
383
386
|
apenasCobranca?: boolean;
|
|
384
387
|
pagina?: number;
|
|
385
388
|
limite?: number;
|
|
386
389
|
}
|
|
390
|
+
export interface TotaisTitulosMoeda {
|
|
391
|
+
moeda: string;
|
|
392
|
+
quantidade: number;
|
|
393
|
+
valor_total: number;
|
|
394
|
+
valor_vencido: number;
|
|
395
|
+
valor_a_vencer: number;
|
|
396
|
+
em_cobranca: number;
|
|
397
|
+
}
|
|
387
398
|
export interface ResultadoTitulos {
|
|
388
399
|
titulos: TituloSlim[];
|
|
389
400
|
paginacao: PaginaMeta;
|
|
@@ -391,15 +402,10 @@ export interface ResultadoTitulos {
|
|
|
391
402
|
inicio: string;
|
|
392
403
|
fim: string;
|
|
393
404
|
};
|
|
394
|
-
|
|
395
|
-
quantidade: number;
|
|
396
|
-
valor_total: number;
|
|
397
|
-
valor_vencido: number;
|
|
398
|
-
valor_a_vencer: number;
|
|
399
|
-
em_cobranca: number;
|
|
400
|
-
};
|
|
405
|
+
totais_por_moeda: TotaisTitulosMoeda[];
|
|
401
406
|
por_contraparte?: {
|
|
402
407
|
contraparte: string;
|
|
408
|
+
moeda: string;
|
|
403
409
|
valor: number;
|
|
404
410
|
quantidade: number;
|
|
405
411
|
vencido: number;
|
|
@@ -410,12 +416,14 @@ export declare const buscarContasAReceber: (o?: FiltroTitulos) => Promise<Result
|
|
|
410
416
|
export interface ClienteSlim {
|
|
411
417
|
nome: string;
|
|
412
418
|
tipo: "PF" | "PJ";
|
|
419
|
+
moeda: string;
|
|
413
420
|
titulos_a_receber: number;
|
|
414
421
|
valor_a_receber: number;
|
|
415
422
|
valor_vencido: number;
|
|
416
423
|
}
|
|
417
424
|
export interface FiltroClientes {
|
|
418
425
|
busca?: string;
|
|
426
|
+
moeda?: string;
|
|
419
427
|
pagina?: number;
|
|
420
428
|
limite?: number;
|
|
421
429
|
}
|
|
@@ -423,7 +431,10 @@ export interface FiltroClientes {
|
|
|
423
431
|
export declare function listarClientes(opts?: FiltroClientes): Promise<{
|
|
424
432
|
clientes: ClienteSlim[];
|
|
425
433
|
paginacao: PaginaMeta;
|
|
426
|
-
|
|
434
|
+
total_a_receber_por_moeda: {
|
|
435
|
+
moeda: string;
|
|
436
|
+
valor: number;
|
|
437
|
+
}[];
|
|
427
438
|
}>;
|
|
428
439
|
export interface UltimoPrecoProdutoOpts {
|
|
429
440
|
busca: string;
|
package/dist/client.js
CHANGED
|
@@ -1004,38 +1004,58 @@ export async function criarTransferencia(o) {
|
|
|
1004
1004
|
};
|
|
1005
1005
|
}
|
|
1006
1006
|
/** Localiza UM lançamento por critérios. Retorna ID interno (não exposto).
|
|
1007
|
-
* Usado por editar/excluir → exige permissão Editar na conta.
|
|
1007
|
+
* Usado por editar/excluir → exige permissão Editar na conta.
|
|
1008
|
+
* IMPORTANTE: há contas HOMÔNIMAS (ex.: 5 contas "Conta a Pagar", uma por moeda).
|
|
1009
|
+
* Por isso varremos TODAS as contas cujo nome casa e desambiguamos por
|
|
1010
|
+
* valor/descrição/moeda — assim a edição funciona mesmo com nomes repetidos. */
|
|
1008
1011
|
async function localizarLancamento(crit) {
|
|
1009
|
-
const {
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1012
|
+
const { contas } = await fetchContas();
|
|
1013
|
+
const me = await obterUsuarioLogado();
|
|
1014
|
+
const termo = crit.nomeConta.trim().toLowerCase();
|
|
1015
|
+
const candContas = contas
|
|
1016
|
+
.filter(isContaAtiva)
|
|
1017
|
+
.filter(c => permissaoDaConta(c, me) === "Editar")
|
|
1018
|
+
.filter(c => String(c["Nome"] ?? c["NomeConta"] ?? "").toLowerCase().includes(termo));
|
|
1019
|
+
if (candContas.length === 0) {
|
|
1020
|
+
throw new Error(`Conta "${crit.nomeConta}" não encontrada (ou sem permissão de edição).`);
|
|
1021
|
+
}
|
|
1022
|
+
// Resolve moeda de cada conta candidata (para desambiguar e filtrar)
|
|
1023
|
+
const mapaMoedas = await obterMapaMoedas();
|
|
1024
|
+
const moedaDaConta = (c) => {
|
|
1025
|
+
const m = mapaMoedas.get(String(c["IdMoeda"] ?? ""));
|
|
1026
|
+
return (m?.sigla || m?.nome || String(c["NomeMoeda"] ?? "")).trim();
|
|
1015
1027
|
};
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1028
|
+
// Filtra por moeda, se informada (ex.: "BRL", "Real")
|
|
1029
|
+
let contasBusca = candContas;
|
|
1030
|
+
if (crit.moeda?.trim()) {
|
|
1031
|
+
const tm = normalizar(crit.moeda);
|
|
1032
|
+
contasBusca = candContas.filter(c => normalizar(moedaDaConta(c)).includes(tm));
|
|
1033
|
+
if (contasBusca.length === 0) {
|
|
1034
|
+
const disp = [...new Set(candContas.map(moedaDaConta))].join(", ");
|
|
1035
|
+
throw new Error(`Nenhuma conta "${crit.nomeConta}" na moeda "${crit.moeda}". Moedas disponíveis: ${disp}`);
|
|
1036
|
+
}
|
|
1020
1037
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1038
|
+
// Busca lançamentos na data em cada conta candidata
|
|
1039
|
+
const all = [];
|
|
1040
|
+
for (const c of contasBusca) {
|
|
1041
|
+
const idConta = String(c["Id"] ?? "");
|
|
1042
|
+
if (!idConta)
|
|
1043
|
+
continue;
|
|
1044
|
+
try {
|
|
1045
|
+
const lancs = await fetchLancamentosWebDeUmaConta(idConta, crit.data, crit.data);
|
|
1046
|
+
for (const l of lancs) {
|
|
1047
|
+
if (!l["NomeConta"])
|
|
1048
|
+
l["NomeConta"] = c["Nome"];
|
|
1049
|
+
l["__moeda"] = moedaDaConta(c);
|
|
1050
|
+
}
|
|
1051
|
+
all.push(...lancs);
|
|
1052
|
+
}
|
|
1053
|
+
catch { /* ignora conta que falhou; segue nas demais */ }
|
|
1033
1054
|
}
|
|
1034
1055
|
// Filtra por valor e descrição
|
|
1035
|
-
let cand =
|
|
1036
|
-
if (crit.valor !== undefined)
|
|
1056
|
+
let cand = all;
|
|
1057
|
+
if (crit.valor !== undefined)
|
|
1037
1058
|
cand = cand.filter(l => Math.abs(Number(l["Valor"]) - crit.valor) < 0.001);
|
|
1038
|
-
}
|
|
1039
1059
|
if (crit.descricao?.trim()) {
|
|
1040
1060
|
const t = crit.descricao.trim().toLowerCase();
|
|
1041
1061
|
cand = cand.filter(l => String(l["Descricao"] ?? "").toLowerCase().includes(t));
|
|
@@ -1044,11 +1064,11 @@ async function localizarLancamento(crit) {
|
|
|
1044
1064
|
throw new Error(`Nenhum lançamento encontrado em ${crit.data} para "${crit.nomeConta}" com os critérios informados.`);
|
|
1045
1065
|
}
|
|
1046
1066
|
if (cand.length > 1) {
|
|
1047
|
-
const lista = cand.slice(0,
|
|
1048
|
-
throw new Error(`${cand.length} lançamentos batem com os critérios. Refine valor/descrição. Encontrados: ${lista}`);
|
|
1067
|
+
const lista = cand.slice(0, 6).map(l => `${Number(l["Valor"]).toFixed(2)} ${String(l["__moeda"] ?? "")} — ${String(l["Descricao"] ?? "")} [${String(l["NomeConta"] ?? "")}]`).join("; ");
|
|
1068
|
+
throw new Error(`${cand.length} lançamentos batem com os critérios. Refine valor/descrição/moeda. Encontrados: ${lista}`);
|
|
1049
1069
|
}
|
|
1050
1070
|
const m = cand[0];
|
|
1051
|
-
return { id: String(m["Id"]), descricao: String(m["Descricao"] ?? ""), valor: Number(m["Valor"]) };
|
|
1071
|
+
return { id: String(m["Id"]), descricao: String(m["Descricao"] ?? ""), valor: Number(m["Valor"]), conta: String(m["NomeConta"] ?? ""), moeda: m["__moeda"] ? String(m["__moeda"]) : undefined };
|
|
1052
1072
|
}
|
|
1053
1073
|
export async function editarLancamento(opts) {
|
|
1054
1074
|
const alvo = await localizarLancamento(opts);
|
|
@@ -1896,6 +1916,11 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1896
1916
|
const cobrancaTipos = new Set(TIPOS_TITULO.cobranca);
|
|
1897
1917
|
const { contas } = await fetchContas();
|
|
1898
1918
|
const me = await obterUsuarioLogado();
|
|
1919
|
+
const mapaMoedas = await obterMapaMoedas();
|
|
1920
|
+
const moedaDaConta = (c) => {
|
|
1921
|
+
const m = mapaMoedas.get(String(c["IdMoeda"] ?? ""));
|
|
1922
|
+
return (m?.sigla || m?.nome || String(c["NomeMoeda"] ?? "") || "?").trim();
|
|
1923
|
+
};
|
|
1899
1924
|
const alvo = contas
|
|
1900
1925
|
.filter(isContaAtiva)
|
|
1901
1926
|
.filter(c => permissaoDaConta(c, me) !== "Negar")
|
|
@@ -1903,12 +1928,13 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1903
1928
|
const todas = await mapWithConcurrency(alvo, 8, async (c) => {
|
|
1904
1929
|
const id = String(c["Id"] ?? c["IdConta"] ?? "");
|
|
1905
1930
|
const nome = String(c["Nome"] ?? c["NomeConta"] ?? "");
|
|
1931
|
+
const moeda = moedaDaConta(c);
|
|
1906
1932
|
const emCob = cobrancaTipos.has(String(c["NomeTipoConta"] ?? "").toLowerCase().trim());
|
|
1907
1933
|
if (!id)
|
|
1908
1934
|
return [];
|
|
1909
1935
|
try {
|
|
1910
1936
|
const lancs = await fetchLancamentosWebDeUmaConta(id, dataInicio, dataFim);
|
|
1911
|
-
return lancs.map(l => ({ l, nome, emCob }));
|
|
1937
|
+
return lancs.map(l => ({ l, nome, moeda, emCob }));
|
|
1912
1938
|
}
|
|
1913
1939
|
catch {
|
|
1914
1940
|
return [];
|
|
@@ -1917,7 +1943,7 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1917
1943
|
const hojeStr = isoDate(new Date());
|
|
1918
1944
|
let titulos = todas.flat()
|
|
1919
1945
|
.filter(({ l }) => !(l["IdLancamentoTransferencia"] ?? l["Transferencia"]))
|
|
1920
|
-
.map(({ l, nome, emCob }) => {
|
|
1946
|
+
.map(({ l, nome, moeda, emCob }) => {
|
|
1921
1947
|
const s = slimLancamento(l);
|
|
1922
1948
|
if (!s.conta)
|
|
1923
1949
|
s.conta = nome;
|
|
@@ -1927,6 +1953,7 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1927
1953
|
return {
|
|
1928
1954
|
vencimento: venc,
|
|
1929
1955
|
valor: s.valor,
|
|
1956
|
+
moeda,
|
|
1930
1957
|
contraparte: s.descricao,
|
|
1931
1958
|
conta: s.conta,
|
|
1932
1959
|
em_cobranca: emCob,
|
|
@@ -1938,6 +1965,10 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1938
1965
|
observacoes: s.observacoes,
|
|
1939
1966
|
};
|
|
1940
1967
|
});
|
|
1968
|
+
if (opts.moeda?.trim()) {
|
|
1969
|
+
const tm = normalizar(opts.moeda);
|
|
1970
|
+
titulos = titulos.filter(t => normalizar(t.moeda).includes(tm));
|
|
1971
|
+
}
|
|
1941
1972
|
if (opts.apenasCobranca)
|
|
1942
1973
|
titulos = titulos.filter(t => t.em_cobranca);
|
|
1943
1974
|
if (opts.busca) {
|
|
@@ -1947,19 +1978,23 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1947
1978
|
if (opts.apenasVencidos)
|
|
1948
1979
|
titulos = titulos.filter(x => x.vencido);
|
|
1949
1980
|
titulos.sort((a, b) => (a.vencimento < b.vencimento ? -1 : a.vencimento > b.vencimento ? 1 : 0));
|
|
1950
|
-
|
|
1981
|
+
// Totais SEMPRE separados por moeda (nunca somar moedas diferentes)
|
|
1982
|
+
const mapMoeda = new Map();
|
|
1951
1983
|
const mapCp = new Map();
|
|
1952
1984
|
for (const t of titulos) {
|
|
1953
1985
|
const v = Math.abs(t.valor);
|
|
1954
|
-
|
|
1986
|
+
const tm = mapMoeda.get(t.moeda) ?? { moeda: t.moeda, quantidade: 0, valor_total: 0, valor_vencido: 0, valor_a_vencer: 0, em_cobranca: 0 };
|
|
1987
|
+
tm.quantidade += 1;
|
|
1988
|
+
tm.valor_total += v;
|
|
1955
1989
|
if (t.vencido)
|
|
1956
|
-
|
|
1990
|
+
tm.valor_vencido += v;
|
|
1957
1991
|
else
|
|
1958
|
-
|
|
1992
|
+
tm.valor_a_vencer += v;
|
|
1959
1993
|
if (t.em_cobranca)
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
const
|
|
1994
|
+
tm.em_cobranca += v;
|
|
1995
|
+
mapMoeda.set(t.moeda, tm);
|
|
1996
|
+
const key = `${t.contraparte || "(sem descrição)"}|${t.moeda}`;
|
|
1997
|
+
const g = mapCp.get(key) ?? { contraparte: t.contraparte || "(sem descrição)", moeda: t.moeda, valor: 0, quantidade: 0, vencido: 0 };
|
|
1963
1998
|
g.valor += v;
|
|
1964
1999
|
g.quantidade += 1;
|
|
1965
2000
|
if (t.vencido)
|
|
@@ -1968,20 +2003,17 @@ async function buscarTitulos(grupo, opts) {
|
|
|
1968
2003
|
}
|
|
1969
2004
|
const inicio = (pagina - 1) * limite;
|
|
1970
2005
|
const pageItems = titulos.slice(inicio, inicio + limite);
|
|
2006
|
+
const totais_por_moeda = [...mapMoeda.values()]
|
|
2007
|
+
.sort((a, b) => b.valor_total - a.valor_total)
|
|
2008
|
+
.map(t => ({ moeda: t.moeda, quantidade: t.quantidade, valor_total: round2(t.valor_total), valor_vencido: round2(t.valor_vencido), valor_a_vencer: round2(t.valor_a_vencer), em_cobranca: round2(t.em_cobranca) }));
|
|
1971
2009
|
const por_contraparte = [...mapCp.values()]
|
|
1972
2010
|
.sort((a, b) => b.valor - a.valor).slice(0, 50)
|
|
1973
|
-
.map(g => ({ contraparte: g.contraparte, valor: round2(g.valor), quantidade: g.quantidade, vencido: round2(g.vencido) }));
|
|
2011
|
+
.map(g => ({ contraparte: g.contraparte, moeda: g.moeda, valor: round2(g.valor), quantidade: g.quantidade, vencido: round2(g.vencido) }));
|
|
1974
2012
|
return {
|
|
1975
2013
|
titulos: pageItems,
|
|
1976
2014
|
paginacao: { pagina, limite, total: titulos.length, paginas: Math.ceil(titulos.length / limite) || 1, tem_mais: inicio + limite < titulos.length },
|
|
1977
2015
|
periodo: { inicio: dataInicio, fim: dataFim },
|
|
1978
|
-
|
|
1979
|
-
quantidade: titulos.length,
|
|
1980
|
-
valor_total: round2(valorTotal),
|
|
1981
|
-
valor_vencido: round2(valorVencido),
|
|
1982
|
-
valor_a_vencer: round2(valorAVencer),
|
|
1983
|
-
em_cobranca: round2(valorCobranca),
|
|
1984
|
-
},
|
|
2016
|
+
totais_por_moeda,
|
|
1985
2017
|
por_contraparte,
|
|
1986
2018
|
};
|
|
1987
2019
|
}
|
|
@@ -1993,13 +2025,11 @@ export async function listarClientes(opts = {}) {
|
|
|
1993
2025
|
const pagina = Math.max(1, opts.pagina ?? 1);
|
|
1994
2026
|
const limite = Math.min(200, Math.max(1, opts.limite ?? 50));
|
|
1995
2027
|
// Base: títulos a receber (inclui em cobrança) — a contraparte é o cliente.
|
|
1996
|
-
const recebiveis = await buscarTitulos("receber", { incluirCobranca: true, limite: 200, pagina: 1 });
|
|
1997
|
-
// Reagrupa por contraparte
|
|
2028
|
+
const recebiveis = await buscarTitulos("receber", { incluirCobranca: true, moeda: opts.moeda, limite: 200, pagina: 1 });
|
|
2029
|
+
// Reagrupa por contraparte+moeda (nunca somar moedas diferentes).
|
|
1998
2030
|
const mapa = new Map();
|
|
1999
2031
|
for (const g of recebiveis.por_contraparte ?? []) {
|
|
2000
|
-
|
|
2001
|
-
// tipo: tenta achar a pessoa no cadastro para classificar PF/PJ
|
|
2002
|
-
mapa.set(nome, { nome, tipo: "PJ", titulos_a_receber: g.quantidade, valor_a_receber: g.valor, valor_vencido: g.vencido });
|
|
2032
|
+
mapa.set(`${g.contraparte}|${g.moeda}`, { nome: g.contraparte, tipo: "PJ", moeda: g.moeda, titulos_a_receber: g.quantidade, valor_a_receber: g.valor, valor_vencido: g.vencido });
|
|
2003
2033
|
}
|
|
2004
2034
|
// Classifica PF/PJ consultando o cadastro de pessoas (lista completa cacheada).
|
|
2005
2035
|
try {
|
|
@@ -2018,11 +2048,14 @@ export async function listarClientes(opts = {}) {
|
|
|
2018
2048
|
clientes = clientes.filter(c => normalizar(c.nome).includes(t));
|
|
2019
2049
|
}
|
|
2020
2050
|
clientes.sort((a, b) => b.valor_a_receber - a.valor_a_receber);
|
|
2051
|
+
const totMoeda = new Map();
|
|
2052
|
+
for (const c of clientes)
|
|
2053
|
+
totMoeda.set(c.moeda, (totMoeda.get(c.moeda) ?? 0) + c.valor_a_receber);
|
|
2021
2054
|
const inicio = (pagina - 1) * limite;
|
|
2022
2055
|
return {
|
|
2023
2056
|
clientes: clientes.slice(inicio, inicio + limite),
|
|
2024
2057
|
paginacao: { pagina, limite, total: clientes.length, paginas: Math.ceil(clientes.length / limite) || 1, tem_mais: inicio + limite < clientes.length },
|
|
2025
|
-
|
|
2058
|
+
total_a_receber_por_moeda: [...totMoeda.entries()].map(([moeda, valor]) => ({ moeda, valor: round2(valor) })),
|
|
2026
2059
|
};
|
|
2027
2060
|
}
|
|
2028
2061
|
/**
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { enterDefaultCtx } from "./context.js";
|
|
|
11
11
|
import { openLoginUI } from "./login-server.js";
|
|
12
12
|
// Modo stdio: ativa um contexto único global no startup. Multi-tenancy só no modo HTTP.
|
|
13
13
|
enterDefaultCtx();
|
|
14
|
-
const server = new Server({ name: "next-finance-mcp", version: "0.9.
|
|
14
|
+
const server = new Server({ name: "next-finance-mcp", version: "0.9.40" }, { capabilities: { tools: {} } });
|
|
15
15
|
// ── Ferramentas ─────────────────────────────────────────────────────────────
|
|
16
16
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
17
17
|
tools: [
|
|
@@ -136,15 +136,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
136
136
|
{
|
|
137
137
|
name: "buscar_contas_a_pagar",
|
|
138
138
|
description: "Lista os TÍTULOS A PAGAR (contas a pagar) da carteira — agrega TODAS as contas do tipo 'Conta a Pagar'. " +
|
|
139
|
-
"Cada título traz: vencimento, valor, fornecedor (campo 'contraparte'), conta, se está vencido e os dias " +
|
|
140
|
-
"de atraso/para vencer. Retorna
|
|
141
|
-
"Use apenas_vencidos=true para
|
|
139
|
+
"Cada título traz: vencimento, valor, moeda, fornecedor (campo 'contraparte'), conta, se está vencido e os dias " +
|
|
140
|
+
"de atraso/para vencer. Retorna totais_por_moeda (nunca soma moedas diferentes) e agregação por fornecedor. " +
|
|
141
|
+
"Use moeda='BRL' para focar no real; apenas_vencidos=true para só o que está em atraso. Janela padrão: 1 ano atrás a 1 ano à frente.",
|
|
142
142
|
inputSchema: {
|
|
143
143
|
type: "object",
|
|
144
144
|
properties: {
|
|
145
145
|
data_inicio: { type: "string", description: "Data início do vencimento YYYY-MM-DD (padrão: 1 ano atrás)" },
|
|
146
146
|
data_fim: { type: "string", description: "Data fim do vencimento YYYY-MM-DD (padrão: 1 ano à frente)" },
|
|
147
147
|
busca: { type: "string", description: "Filtra pelo nome do fornecedor (contraparte)" },
|
|
148
|
+
moeda: { type: "string", description: "Filtra por moeda (ex: 'BRL'). Sem isso, retorna todas — e os totais vêm separados por moeda (nunca somados)." },
|
|
148
149
|
apenas_vencidos: { type: "boolean", description: "Se true, retorna só títulos vencidos (em atraso)" },
|
|
149
150
|
pagina: { type: "number", description: "Página (começa em 1, padrão: 1)" },
|
|
150
151
|
limite: { type: "number", description: "Títulos por página (padrão: 50, máximo: 200)" },
|
|
@@ -155,15 +156,16 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
155
156
|
name: "buscar_contas_a_receber",
|
|
156
157
|
description: "Lista os TÍTULOS A RECEBER da carteira — agrega TODAS as contas do tipo 'Conta a Receber' e, por padrão, " +
|
|
157
158
|
"também as do tipo 'Contas em Cobrança' (cada título tem o flag em_cobranca). Cada título traz: vencimento, " +
|
|
158
|
-
"valor, cliente (campo 'contraparte'), conta, se está vencido e os dias de atraso/para vencer. Retorna
|
|
159
|
-
"(
|
|
160
|
-
"para
|
|
159
|
+
"valor, moeda, cliente (campo 'contraparte'), conta, se está vencido e os dias de atraso/para vencer. Retorna " +
|
|
160
|
+
"totais_por_moeda (nunca soma moedas diferentes) e agregação por cliente. Use moeda='BRL' para focar no real; " +
|
|
161
|
+
"apenas_cobranca=true para SÓ os recebíveis em cobrança; apenas_vencidos=true para só os vencidos. Janela padrão: 1 ano atrás a 1 ano à frente.",
|
|
161
162
|
inputSchema: {
|
|
162
163
|
type: "object",
|
|
163
164
|
properties: {
|
|
164
165
|
data_inicio: { type: "string", description: "Data início do vencimento YYYY-MM-DD (padrão: 1 ano atrás)" },
|
|
165
166
|
data_fim: { type: "string", description: "Data fim do vencimento YYYY-MM-DD (padrão: 1 ano à frente)" },
|
|
166
167
|
busca: { type: "string", description: "Filtra pelo nome do cliente (contraparte)" },
|
|
168
|
+
moeda: { type: "string", description: "Filtra por moeda (ex: 'BRL'). Sem isso, retorna todas — e os totais vêm separados por moeda (nunca somados)." },
|
|
167
169
|
apenas_vencidos: { type: "boolean", description: "Se true, retorna só títulos vencidos (em atraso)" },
|
|
168
170
|
apenas_cobranca: { type: "boolean", description: "Se true, retorna SÓ os títulos em cobrança" },
|
|
169
171
|
incluir_cobranca: { type: "boolean", description: "Inclui as contas 'em Cobrança' na agregação (padrão: true)" },
|
|
@@ -183,6 +185,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
183
185
|
type: "object",
|
|
184
186
|
properties: {
|
|
185
187
|
busca: { type: "string", description: "Filtra pelo nome do cliente" },
|
|
188
|
+
moeda: { type: "string", description: "Filtra por moeda dos recebíveis (ex: 'BRL'). O total a receber vem separado por moeda." },
|
|
186
189
|
pagina: { type: "number", description: "Página (começa em 1, padrão: 1)" },
|
|
187
190
|
limite: { type: "number", description: "Clientes por página (padrão: 50, máximo: 200)" },
|
|
188
191
|
},
|
|
@@ -234,8 +237,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
234
237
|
},
|
|
235
238
|
{
|
|
236
239
|
name: "editar_lancamento",
|
|
237
|
-
description: "Edita um lançamento existente. Localiza pelo
|
|
238
|
-
"
|
|
240
|
+
description: "Edita um lançamento existente. Localiza pelo nome_conta + data + valor/descrição (varre TODAS as contas " +
|
|
241
|
+
"homônimas, inclusive em moedas diferentes — ex: as várias 'Conta a Pagar') e aplica as alterações. " +
|
|
242
|
+
"Se mais de um lançamento bater, a tool lista as opções para você refinar (use 'moeda' para desambiguar).",
|
|
239
243
|
inputSchema: {
|
|
240
244
|
type: "object",
|
|
241
245
|
properties: {
|
|
@@ -244,6 +248,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
244
248
|
data: { type: "string", description: "Data do lançamento YYYY-MM-DD (para localizar)" },
|
|
245
249
|
valor: { type: "number", description: "Valor original (para localizar, opcional)" },
|
|
246
250
|
descricao: { type: "string", description: "Descrição original (substring, para localizar, opcional)" },
|
|
251
|
+
moeda: { type: "string", description: "Moeda da conta (ex: 'BRL') — desambigua contas homônimas em moedas diferentes" },
|
|
247
252
|
// Campos a alterar (qualquer um, todos opcionais)
|
|
248
253
|
nova_descricao: { type: "string", description: "Nova descrição" },
|
|
249
254
|
novo_valor: { type: "number", description: "Novo valor (negativo = despesa, positivo = receita)" },
|
|
@@ -271,6 +276,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
271
276
|
data: { type: "string", description: "Data do lançamento YYYY-MM-DD" },
|
|
272
277
|
valor: { type: "number", description: "Valor (opcional, ajuda a desambiguar)" },
|
|
273
278
|
descricao: { type: "string", description: "Descrição (substring, opcional)" },
|
|
279
|
+
moeda: { type: "string", description: "Moeda da conta (ex: 'BRL') — desambigua contas homônimas em moedas diferentes" },
|
|
274
280
|
},
|
|
275
281
|
required: ["nome_conta", "data"],
|
|
276
282
|
},
|
|
@@ -787,6 +793,7 @@ async function handleTool(name, args) {
|
|
|
787
793
|
dataInicio: args["data_inicio"],
|
|
788
794
|
dataFim: args["data_fim"],
|
|
789
795
|
busca: args["busca"],
|
|
796
|
+
moeda: args["moeda"],
|
|
790
797
|
apenasVencidos: args["apenas_vencidos"],
|
|
791
798
|
pagina: args["pagina"],
|
|
792
799
|
limite: args["limite"],
|
|
@@ -803,6 +810,7 @@ async function handleTool(name, args) {
|
|
|
803
810
|
dataInicio: args["data_inicio"],
|
|
804
811
|
dataFim: args["data_fim"],
|
|
805
812
|
busca: args["busca"],
|
|
813
|
+
moeda: args["moeda"],
|
|
806
814
|
apenasVencidos: args["apenas_vencidos"],
|
|
807
815
|
apenasCobranca: args["apenas_cobranca"],
|
|
808
816
|
incluirCobranca: args["incluir_cobranca"],
|
|
@@ -819,6 +827,7 @@ async function handleTool(name, args) {
|
|
|
819
827
|
return walErr;
|
|
820
828
|
return ok(await client.listarClientes({
|
|
821
829
|
busca: args["busca"],
|
|
830
|
+
moeda: args["moeda"],
|
|
822
831
|
pagina: args["pagina"],
|
|
823
832
|
limite: args["limite"],
|
|
824
833
|
}));
|
|
@@ -879,6 +888,7 @@ async function handleTool(name, args) {
|
|
|
879
888
|
data: args["data"],
|
|
880
889
|
valor: args["valor"],
|
|
881
890
|
descricao: args["descricao"],
|
|
891
|
+
moeda: args["moeda"],
|
|
882
892
|
nova_descricao: args["nova_descricao"],
|
|
883
893
|
novo_valor: args["novo_valor"],
|
|
884
894
|
nova_data: args["nova_data"],
|
|
@@ -904,6 +914,7 @@ async function handleTool(name, args) {
|
|
|
904
914
|
data: args["data"],
|
|
905
915
|
valor: args["valor"],
|
|
906
916
|
descricao: args["descricao"],
|
|
917
|
+
moeda: args["moeda"],
|
|
907
918
|
}));
|
|
908
919
|
}
|
|
909
920
|
case "permissao_conta": {
|
|
@@ -1182,6 +1193,6 @@ async function handleTool(name, args) {
|
|
|
1182
1193
|
async function main() {
|
|
1183
1194
|
const transport = new StdioServerTransport();
|
|
1184
1195
|
await server.connect(transport);
|
|
1185
|
-
client.log(`NEXT Finance MCP server v0.9.
|
|
1196
|
+
client.log(`NEXT Finance MCP server v0.9.40 iniciado. Timeout upstream: ${process.env.NEXT_FINANCE_TIMEOUT_MS ?? "15000"}ms`);
|
|
1186
1197
|
}
|
|
1187
1198
|
main().catch((err) => { console.error("Erro fatal:", err); process.exit(1); });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-finance-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.40",
|
|
4
4
|
"mcpName": "io.github.paivapiovesan/next-finance",
|
|
5
5
|
"description": "MCP Server para o NEXT Finance (finance.net.br) — login via browser, listagem de carteiras, contas e lançamentos",
|
|
6
6
|
"type": "module",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
42
|
+
"docx": "^9.7.1",
|
|
42
43
|
"express": "^5.2.1",
|
|
43
44
|
"undici": "^7.25.0"
|
|
44
45
|
},
|