@credithub/harlan-components 1.128.0 → 1.130.0

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.
@@ -14,7 +14,8 @@ import { ConsultasComplementaresContext } from '../consultasComplementares';
14
14
  import { ButtonsSummary, SummaryButton } from '../dossie/summary/styles';
15
15
  import { getProductsPrices } from '../dossie/summary/utils';
16
16
  import StatusMessage from '../interface/statusMessage';
17
- import Section from '../section';
17
+ import Section, { pushExceptionDescription } from '../section';
18
+ import { isErrorWithPushFlag } from '../../utils/classifyRequestError';
18
19
  import { RequestStatus } from '../webservice';
19
20
  import ChartContent from './chartContent';
20
21
  import useChartData from './hooks/useChartData';
@@ -90,7 +91,7 @@ var ChartSystem = function (_a) {
90
91
  });
91
92
  }); };
92
93
  }, [loadingButtons, hasCredits, productsPrices, setConsultasComplementares]);
93
- var _p = useChartData(consultaSerasa, consultaBoaVista), chartData = _p.data, isLoadingChart = _p.isLoading, errorChart = _p.error, refetchChart = _p.refetch, chartDataProgress = _p.loadingProgress;
94
+ var _p = useChartData(consultaSerasa, consultaBoaVista), chartData = _p.data, isLoadingChart = _p.isLoading, errorChart = _p.error, chartUpstreamFailed = _p.upstreamRequestFailed, refetchChart = _p.refetch, chartDataProgress = _p.loadingProgress;
94
95
  var _q = useDividasPublicas(), quantidadeDividas = _q.quantidade, valorTotalDividas = _q.valorTotal, ultimaOcorrenciaDividas = _q.ultimaOcorrencia, dividasProgress = _q.loadingProgress;
95
96
  var lastComplementary = useRef({
96
97
  serasa: null,
@@ -99,7 +100,14 @@ var ChartSystem = function (_a) {
99
100
  // Evita escrever documentHistory repetidamente com o mesmo conteúdo
100
101
  var lastDocHistorySigRef = useRef('');
101
102
  // (refetch de histórico por mudança complementar centralizado no hook useChartData)
102
- var errorMessage = typeof errorChart === 'string' ? new Error(errorChart) : errorChart;
103
+ var chartHasError = chartUpstreamFailed || errorChart != null;
104
+ var errorMessage = errorChart instanceof Error
105
+ ? errorChart
106
+ : typeof errorChart === 'string'
107
+ ? new Error(errorChart)
108
+ : chartUpstreamFailed
109
+ ? new Error()
110
+ : null;
103
111
  var isOpen = useToggle(true)[0];
104
112
  // Usa valores já calculados de globalData.protestosData (calculados uma única vez em protestos.tsx)
105
113
  var quantidadeProtestos = (_g = (_f = globalData === null || globalData === void 0 ? void 0 : globalData.protestosData) === null || _f === void 0 ? void 0 : _f.totalProtestos) !== null && _g !== void 0 ? _g : 0;
@@ -231,10 +239,10 @@ var ChartSystem = function (_a) {
231
239
  response: undefined,
232
240
  type: isLoadingChart
233
241
  ? RequestStatus.Loading
234
- : errorChart
242
+ : chartHasError
235
243
  ? RequestStatus.Error
236
244
  : RequestStatus.Success,
237
- error: errorMessage || null,
245
+ error: errorMessage,
238
246
  refetch: refetchChart,
239
247
  document: chartData,
240
248
  progress: loadingProgress,
@@ -267,13 +275,21 @@ var ChartSystem = function (_a) {
267
275
  : undefined, ultimaOcorrenciaPefinSerasa: Array.isArray(chartData === null || chartData === void 0 ? void 0 : chartData.serasa) && chartData.serasa.length > 0
268
276
  ? (ultimaOcorrenciaSerasa !== null && ultimaOcorrenciaSerasa !== void 0 ? ultimaOcorrenciaSerasa : undefined)
269
277
  : undefined })));
270
- }, isError: function (err) { return ({
271
- children: React.createElement(React.Fragment, null),
272
- description: (React.createElement(StatusMessage, { type: "error" },
273
- "Erro ao realizar a an\u00E1lise: ",
274
- err.message)),
275
- variant: 'error'
276
- }); } }));
278
+ }, isError: function (err) {
279
+ return isErrorWithPushFlag(err)
280
+ ? {
281
+ children: React.createElement(React.Fragment, null),
282
+ description: pushExceptionDescription(err),
283
+ variant: 'default'
284
+ }
285
+ : {
286
+ children: React.createElement(React.Fragment, null),
287
+ description: (React.createElement(StatusMessage, { type: "error" },
288
+ "Erro ao realizar a an\u00E1lise: ",
289
+ err.message)),
290
+ variant: 'error'
291
+ };
292
+ } }));
277
293
  };
278
294
  export default ChartSystem;
279
295
  var templateObject_1;
@@ -2,7 +2,9 @@ import { DataInput } from '../../../components/chart/types/iChart';
2
2
  declare const useChartData: (consultaSerasa: any, consultaBoaVista: any) => {
3
3
  data: DataInput | null;
4
4
  isLoading: boolean;
5
- error: string | null;
5
+ error: Error | null;
6
+ /** True quando Histórico/Protestos/CCF estão em Error (mesmo sem mensagem no Error). */
7
+ upstreamRequestFailed: boolean;
6
8
  refetch: () => void;
7
9
  loadingProgress: number;
8
10
  };
@@ -37,7 +37,11 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
37
37
  var _g = useState(false), isProcessing = _g[0], setIsProcessing = _g[1];
38
38
  var _h = useState(false), dataReady = _h[0], setDataReady = _h[1];
39
39
  var lastProgress = useRef(0);
40
- /** Evita reprocessar o mesmo JSON + mesmos totais ao vivo; totais/PJ mudam → nova chave. */
40
+ /**
41
+ * Evita reprocessar em vão. Inclui totais do IEPTB (globalData) para atualizar o pie
42
+ * quando o JSON do DOCUMENTHISTORY for o mesmo; a série `protestos` do gráfico vem
43
+ * só do histórico em `processData` (sem override com IEPTB).
44
+ */
41
45
  var lastProcessSnapshotKey = useRef(null);
42
46
  var processingTimeout = useRef(null);
43
47
  var ctxHistory = useContext(Queries.GraficosAnaliticos);
@@ -155,6 +159,7 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
155
159
  boaVista: null
156
160
  });
157
161
  useEffect(function () {
162
+ var _a;
158
163
  var serasaChanged = consultaSerasa !== lastComplementary.current.serasa;
159
164
  var boaVistaChanged = consultaBoaVista !== lastComplementary.current.boaVista;
160
165
  if (serasaChanged || boaVistaChanged) {
@@ -162,7 +167,12 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
162
167
  serasa: consultaSerasa,
163
168
  boaVista: consultaBoaVista
164
169
  };
165
- ctxHistory.refetch();
170
+ if (ctxHistory.type !== RequestStatus.Error) {
171
+ ctxHistory.refetch();
172
+ }
173
+ else if ((_a = import.meta.env) === null || _a === void 0 ? void 0 : _a.DEV) {
174
+ console.debug('[useChartData] refetch de histórico ignorado: consulta anterior em erro');
175
+ }
166
176
  }
167
177
  // eslint-disable-next-line react-hooks/exhaustive-deps
168
178
  }, [consultaSerasa, consultaBoaVista]);
@@ -172,8 +182,12 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
172
182
  ctxProtestos.type === RequestStatus.Success &&
173
183
  ctxCCF.type === RequestStatus.Success;
174
184
  }, [ctxHistory.type, ctxProtestos.type, ctxCCF.type]);
185
+ var upstreamRequestFailed = useMemo(function () {
186
+ return ctxHistory.type === RequestStatus.Error ||
187
+ ctxProtestos.type === RequestStatus.Error ||
188
+ ctxCCF.type === RequestStatus.Error;
189
+ }, [ctxHistory.type, ctxProtestos.type, ctxCCF.type]);
175
190
  useEffect(function () {
176
- var _a;
177
191
  // Limpa timeout anterior se existir
178
192
  if (processingTimeout.current) {
179
193
  clearTimeout(processingTimeout.current);
@@ -189,8 +203,13 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
189
203
  setIsProcessing(false);
190
204
  return;
191
205
  }
192
- if (ctxHistory.type === RequestStatus.Error) {
193
- setErrorState(((_a = ctxHistory.error) === null || _a === void 0 ? void 0 : _a.message) || 'Erro ao consultar histórico');
206
+ if (upstreamRequestFailed) {
207
+ var err = ctxHistory.type === RequestStatus.Error
208
+ ? ctxHistory.error
209
+ : ctxProtestos.type === RequestStatus.Error
210
+ ? ctxProtestos.error
211
+ : ctxCCF.error;
212
+ setErrorState(err !== null && err !== void 0 ? err : null);
194
213
  setIsProcessing(false);
195
214
  setDataReady(false);
196
215
  lastProcessSnapshotKey.current = null;
@@ -232,7 +251,7 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
232
251
  }
233
252
  catch (error) {
234
253
  console.error('[useChartData] Erro ao processar dados:', error);
235
- setErrorState('Erro ao processar os dados');
254
+ setErrorState(error instanceof Error ? error : new Error(String(error)));
236
255
  setIsProcessing(false);
237
256
  setDataReady(false);
238
257
  lastProcessSnapshotKey.current = null;
@@ -264,11 +283,15 @@ var useChartData = function (consultaSerasa, consultaBoaVista) {
264
283
  // Verifica se está carregando - aguarda TODOS os contextos necessários terminarem
265
284
  // E aguarda o processamento E renderização dos dados estar completo
266
285
  // Só sai de loading quando dataReady === true (todos os contextos prontos + dados processados)
267
- var isLoading = !dataReady || isProcessing || !allContextsReady;
286
+ var isLoading = !upstreamRequestFailed &&
287
+ errorState == null &&
288
+ (!dataReady || isProcessing || !allContextsReady);
268
289
  return {
269
290
  data: data,
270
291
  isLoading: isLoading,
271
292
  error: errorState,
293
+ /** True quando Histórico/Protestos/CCF estão em Error (mesmo sem mensagem no Error). */
294
+ upstreamRequestFailed: upstreamRequestFailed,
272
295
  refetch: ctxHistory.refetch,
273
296
  loadingProgress: loadingProgress
274
297
  };
@@ -75,13 +75,6 @@ export var processData = function (data, quantidadeProcessosJuridicos, totalProt
75
75
  .filter(removeSameAsNext)
76
76
  .map(function (info) { return (__assign(__assign({}, info), { data: parseProtestStringToDate(info.data) })); })
77
77
  .filter(function (info) { return !Number.isNaN(info.data.getTime()); }), function (info) { return info.data; });
78
- /** Alinha o último ponto (data da consulta mais recente no histórico) com os totais ao vivo (mesma fonte que o pie). */
79
- if (totalProtestos !== undefined && data.protestos.length > 0) {
80
- var i = data.protestos.length - 1;
81
- data.protestos[i] = __assign(__assign(__assign({}, data.protestos[i]), { quantidade: totalProtestos }), (valorTotalProtestos !== undefined
82
- ? { valorTotal: valorTotalProtestos }
83
- : {}));
84
- }
85
78
  // ------------------------------------------------------------------
86
79
  // CCFs
87
80
  // ------------------------------------------------------------------
@@ -70,12 +70,16 @@ var GenerativeAI = function (_a) {
70
70
  var _o = useStreamQuery("SELECT FROM 'LlamaApi'.'Consulta'", summaryQueryData, streamMode === 'summary' && !!summaryQueryData), summaryIterator = _o.responseIterator, summaryError = _o.error, summaryLoading = _o.isLoading, refetchSummary = _o.refetch, abortSummary = _o.abort;
71
71
  // Configura a query chat
72
72
  var _p = useStreamQuery("SELECT FROM 'LlamaApi'.'Consulta'", chatQueryData, streamMode === 'chat' && !!chatQueryData), chatIterator = _p.responseIterator, chatError = _p.error, chatLoading = _p.isLoading, refetchChat = _p.refetch, abortChat = _p.abort;
73
- // Dispara o refetch inicial quando summaryQueryData estiver definido
73
+ // Dispara o refetch quando summaryQueryData mudar, exceto após erro real (evita loop de crédito)
74
74
  useEffect(function () {
75
- if (summaryQueryData) {
75
+ var _a;
76
+ if (summaryQueryData && !summaryError) {
76
77
  refetchSummary();
77
78
  }
78
- }, [summaryQueryData, refetchSummary]);
79
+ else if (summaryQueryData && summaryError && ((_a = import.meta.env) === null || _a === void 0 ? void 0 : _a.DEV)) {
80
+ console.debug('[GenerativeAI] refetch summary ignorado: erro na consulta anterior');
81
+ }
82
+ }, [summaryQueryData, refetchSummary, summaryError]);
79
83
  // Detecta a transição de refreshQuery de false para true para reiniciar a consulta
80
84
  var prevRefreshQueryRef = useRef(refreshQuery);
81
85
  useEffect(function () {
@@ -90,9 +94,11 @@ var GenerativeAI = function (_a) {
90
94
  }
91
95
  // Incrementa o refreshKey para forçar a atualização da query
92
96
  setRefreshKey(function (prev) { return prev + 1; });
97
+ // Retry explícito (refresh externo), mesmo se houve erro antes
98
+ refetchSummary();
93
99
  }
94
100
  prevRefreshQueryRef.current = refreshQuery;
95
- }, [refreshQuery, abortSummary, streamMode]);
101
+ }, [refreshQuery, abortSummary, streamMode, refetchSummary]);
96
102
  // Processa o stream da consulta summary (apenas uma vez)
97
103
  var processedSummaryRef = useRef(false);
98
104
  useEffect(function () {
@@ -246,21 +246,43 @@ var Liminar = function (_a) {
246
246
  return;
247
247
  var fetch = function () { return __awaiter(void 0, void 0, void 0, function () {
248
248
  var dossie, processosJuridicos, depsLoaded, newIds, hash, sourceApi, sourceProcessos, _a, possuiIndiciosDeLiminarProtestosDoPassado, protestosIds, sourceProtestos, combined, finalStatus;
249
- var _b;
250
- return __generator(this, function (_c) {
251
- switch (_c.label) {
249
+ var _b, _c, _d;
250
+ return __generator(this, function (_e) {
251
+ switch (_e.label) {
252
252
  case 0:
253
253
  dossie = globalData === null || globalData === void 0 ? void 0 : globalData.dossie;
254
254
  processosJuridicos = globalData === null || globalData === void 0 ? void 0 : globalData.processosJuridicosData;
255
255
  depsLoaded = !!(processosJuridicos === null || processosJuridicos === void 0 ? void 0 : processosJuridicos.isLoaded) && !!(dossie === null || dossie === void 0 ? void 0 : dossie.carousel);
256
256
  if (!depsLoaded || ctx.type === RequestStatus.Loading)
257
257
  return [2 /*return*/];
258
+ if (ctx.type === RequestStatus.Error ||
259
+ (processosJuridicos === null || processosJuridicos === void 0 ? void 0 : processosJuridicos.error) ||
260
+ ((_b = globalData === null || globalData === void 0 ? void 0 : globalData.protestosData) === null || _b === void 0 ? void 0 : _b.error)) {
261
+ if ((_c = import.meta.env) === null || _c === void 0 ? void 0 : _c.DEV) {
262
+ console.debug('[Liminar] consulta complementar ignorada: upstream em erro');
263
+ }
264
+ if (!processedRef.current) {
265
+ setData(function (prev) { return (__assign(__assign({}, prev), { liminar: {
266
+ indiciosDeLiminar: false,
267
+ message: 'Não encontrado',
268
+ isLoaded: true,
269
+ processosComLiminarIds: [],
270
+ indiciosDeLiminarProtestosDoPassado: false,
271
+ protestosDoPassadoIds: '',
272
+ invertedProcessos: [],
273
+ origensLiminar: [],
274
+ descricaoLiminar: 'Não encontrado'
275
+ } })); });
276
+ processedRef.current = true;
277
+ }
278
+ return [2 /*return*/];
279
+ }
258
280
  newIds = foundBusinessEntity
259
281
  ? processosComAssuntoValido.map(function (p) { return p.id; })
260
282
  : [];
261
283
  hash = JSON.stringify({
262
284
  t: ctx.type,
263
- indicios: (_b = ctx.document) === null || _b === void 0 ? void 0 : _b.indiciosDeLiminar,
285
+ indicios: (_d = ctx.document) === null || _d === void 0 ? void 0 : _d.indiciosDeLiminar,
264
286
  carousel: dossie.carousel,
265
287
  empresas: processosJuridicos.empresa
266
288
  });
@@ -273,7 +295,7 @@ var Liminar = function (_a) {
273
295
  setIsLoadingLiminarProtestosDoPassado(true);
274
296
  return [4 /*yield*/, fetchLiminarProtestosDoPassado()];
275
297
  case 1:
276
- _a = _c.sent(), possuiIndiciosDeLiminarProtestosDoPassado = _a.possuiIndiciosDeLiminarProtestosDoPassado, protestosIds = _a.protestosDoPassadoIds;
298
+ _a = _e.sent(), possuiIndiciosDeLiminarProtestosDoPassado = _a.possuiIndiciosDeLiminarProtestosDoPassado, protestosIds = _a.protestosDoPassadoIds;
277
299
  setIsLoadingLiminarProtestosDoPassado(false);
278
300
  sourceProtestos = detectLiminarFromProtestosDoPassado(possuiIndiciosDeLiminarProtestosDoPassado, protestosIds);
279
301
  combined = combineLiminarSources([
@@ -1,5 +1,4 @@
1
1
  import ProtestosIcon from '../../assets/icones/protestos';
2
- import { useGlobalData } from '../../contexts/globalDataContext';
3
2
  import { formatMoney } from '../../utils/number';
4
3
  import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
5
4
  import AddItemField from '../common/addItem';
@@ -9,7 +8,6 @@ import Section from '../section';
9
8
  import { Queries, RequestStatus } from '../webservice';
10
9
  var ProtestosSP = function () {
11
10
  var ctxLiminar = useContext(Queries.Liminar);
12
- var setData = useGlobalData().setData;
13
11
  var _a = useState(false), dataUpdated = _a[0], setDataUpdated = _a[1];
14
12
  var _b = useState(false), hideSection = _b[0], setHideSection = _b[1];
15
13
  var prevCtxTypeRef = useRef(null);
@@ -28,7 +26,7 @@ var ProtestosSP = function () {
28
26
  setHideSection(true);
29
27
  }
30
28
  prevCtxTypeRef.current = ctxLiminar.type;
31
- }, [ctxLiminar.type, ctxLiminar.document, dataUpdated, setData]);
29
+ }, [ctxLiminar.type, ctxLiminar.document, dataUpdated]);
32
30
  var possuiProtestosSp = useMemo(function () {
33
31
  var _a;
34
32
  if ((ctxLiminar === null || ctxLiminar === void 0 ? void 0 : ctxLiminar.type) === RequestStatus.Success)
@@ -11,6 +11,11 @@ export type ParsedResponse<T> = {
11
11
  response: Response;
12
12
  document: T;
13
13
  };
14
+ /** Aviso de exceção esperada (`push=true` no XML); só exibe UI se houver `message` ou `code`. */
15
+ export type PushNotice = {
16
+ message?: string;
17
+ code?: number;
18
+ };
14
19
  export type RequestContext<R> = {
15
20
  data?: Client.Form;
16
21
  urlData?: Client.Form;
@@ -24,6 +29,8 @@ export type RequestContext<R> = {
24
29
  activeRequests?: number;
25
30
  showLoadingBar?: boolean;
26
31
  warningMessage?: string | null;
32
+ /** Presente quando o backend sinalizou `push=true` (situação esperada, fluxo segue). */
33
+ pushNotice?: PushNotice | null;
27
34
  };
28
35
  export type HeaderReplaceResponse = {
29
36
  children: ReactNode;
@@ -5,14 +5,12 @@ import { useSafeQuery } from '../../hooks/useSafeQuery';
5
5
  import { isDocumentoPF } from '../../utils/string';
6
6
  import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import AddItemField from '../common/addItem';
8
+ import { formatInadPercentDisplay, inadCountPer100, resolveSerasaInadPercent } from './scoreSerasaProbUtils';
8
9
  import { ConsultasComplementaresContext } from '../consultasComplementares';
9
10
  import { Result, ResultContent } from '../interface/result';
10
11
  import StatusMessage from '../interface/statusMessage';
11
12
  import Section from '../section';
12
13
  import { RequestStatus } from '../webservice';
13
- var parseProb = function (raw) {
14
- return typeof raw === 'number' ? raw : Number(String(raw).replace(',', '.')) || 0;
15
- };
16
14
  var ConsultaScoreSerasa = function (_a) {
17
15
  var _b, _c, _d, _e, _f, _g;
18
16
  var documento = _a.documento;
@@ -21,7 +19,14 @@ var ConsultaScoreSerasa = function (_a) {
21
19
  var _h = useState(false), dataUpdated = _h[0], setDataUpdated = _h[1];
22
20
  var _j = useSafeQuery("SELECT FROM 'ScoreSerasa'.'Consulta'", { documento: documento }, (_c = (_b = consultasComplementaresContext === null || consultasComplementaresContext === void 0 ? void 0 : consultasComplementaresContext.consultasComplementares) === null || _b === void 0 ? void 0 : _b.scoreSerasa) === null || _c === void 0 ? void 0 : _c.consultaRealizada), response = _j.response, isLoading = _j.isLoading, error = _j.error, loadingProgress = _j.loadingProgress;
23
21
  var scoreData = (_e = (_d = response === null || response === void 0 ? void 0 : response.document) === null || _d === void 0 ? void 0 : _d.dados) === null || _e === void 0 ? void 0 : _e.score;
24
- var inadProb = parseProb(scoreData === null || scoreData === void 0 ? void 0 : scoreData.probabilidade_inadimplencia);
22
+ var inadResolvido = useMemo(function () {
23
+ return (scoreData === null || scoreData === void 0 ? void 0 : scoreData.score_calculado) === 'S'
24
+ ? resolveSerasaInadPercent({
25
+ pontuacao: scoreData.pontuacao,
26
+ probabilidade_inadimplencia: scoreData.probabilidade_inadimplencia
27
+ })
28
+ : null;
29
+ }, [scoreData]);
25
30
  var scoreRef = useRef(null);
26
31
  var consultaRealizada = useMemo(function () {
27
32
  var _a, _b;
@@ -61,8 +66,12 @@ var ConsultaScoreSerasa = function (_a) {
61
66
  progress: loadingProgress
62
67
  }, title: "Score Serasa", subtitle: "Consulta de Score", icon: ScoreBoaVistaIcon, description: !error && (React.createElement(StatusMessage, { type: scoreData ? 'success' : 'default' }, description)), onSuccess: function () { return (React.createElement(Result, null, scoreData && (React.createElement(ResultContent, { desktop: "repeat(4, 1fr)", tablet: "repeat(3, 1fr)", mobile: "1fr 1fr" },
63
68
  React.createElement(AddItemField, { name: "Score", value: String(scoreData.pontuacao) }),
64
- React.createElement(AddItemField, { name: "Probabilidade de Inadimpl\u00EAncia", value: "".concat(scoreData.probabilidade_inadimplencia, "%") }),
65
- React.createElement(AddItemField, { name: "An\u00E1lise", value: "DE CADA 100 ".concat(isDocumentoPF(documento) ? 'PESSOAS' : 'EMPRESAS', " CLASSIFICADAS NESTA CLASSE DE SCORE, \u00C9 PROV\u00C1VEL QUE ").concat(Math.floor(inadProb), " APRESENTEM D\u00C9BITOS NO MERCADO NOS PR\u00D3XIMOS 6 MESES.") }))))); }, isError: function (err) { return ({
69
+ React.createElement(AddItemField, { name: "Probabilidade de Inadimpl\u00EAncia", value: inadResolvido
70
+ ? formatInadPercentDisplay(inadResolvido.percent0to100)
71
+ : '—' }),
72
+ React.createElement(AddItemField, { name: "An\u00E1lise", value: inadResolvido
73
+ ? "DE CADA 100 ".concat(isDocumentoPF(documento) ? 'PESSOAS' : 'EMPRESAS', " CLASSIFICADAS NESTA CLASSE DE SCORE, \u00C9 PROV\u00C1VEL QUE ").concat(inadCountPer100(inadResolvido.percent0to100), " APRESENTEM D\u00C9BITOS NO MERCADO NOS PR\u00D3XIMOS 6 MESES.")
74
+ : '—' }))))); }, isError: function (err) { return ({
66
75
  children: React.createElement(React.Fragment, null),
67
76
  description: (React.createElement(StatusMessage, { type: "error" },
68
77
  "Erro ao realizar a consulta: ",
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Escala 0–1000 do Score Serasa; fora de faixa é ajustada (clamp).
3
+ */
4
+ export declare function parsePonto1000(pontuacao: unknown): number;
5
+ /**
6
+ * A API preenche probabilidade (0–100) ou vem vazia.
7
+ */
8
+ export declare function isProbFromApiValid(raw: unknown): boolean;
9
+ export declare function inadFromFallbackPontuacao(p: number): number;
10
+ /**
11
+ * Número inteiro 0–100 na frase "de cada 100" (arredondamento do % resolvido).
12
+ */
13
+ export declare function inadCountPer100(percent0to100: number): number;
14
+ /**
15
+ * "99,80%" com duas decimais (formato local).
16
+ */
17
+ export declare function formatInadPercentDisplay(percent0to100: number): string;
18
+ export declare function resolveSerasaInadPercent(rules: {
19
+ pontuacao: unknown;
20
+ probabilidade_inadimplencia: unknown;
21
+ }): {
22
+ percent0to100: number;
23
+ fromApi: boolean;
24
+ };
@@ -0,0 +1,66 @@
1
+ var SCORE_MAX = 1000;
2
+ var parseNumberFlexible = function (raw) {
3
+ if (raw === null || raw === undefined)
4
+ return null;
5
+ if (typeof raw === 'number') {
6
+ return Number.isFinite(raw) ? raw : null;
7
+ }
8
+ var s = String(raw).trim();
9
+ if (s === '')
10
+ return null;
11
+ var n = Number(s.replace(',', '.'));
12
+ return Number.isFinite(n) ? n : null;
13
+ };
14
+ /**
15
+ * Escala 0–1000 do Score Serasa; fora de faixa é ajustada (clamp).
16
+ */
17
+ export function parsePonto1000(pontuacao) {
18
+ var n = parseNumberFlexible(pontuacao);
19
+ if (n === null)
20
+ return 0;
21
+ return Math.min(SCORE_MAX, Math.max(0, n));
22
+ }
23
+ /**
24
+ * A API preenche probabilidade (0–100) ou vem vazia.
25
+ */
26
+ export function isProbFromApiValid(raw) {
27
+ if (raw === null || raw === undefined)
28
+ return false;
29
+ if (typeof raw === 'string' && raw.trim() === '')
30
+ return false;
31
+ var n = parseNumberFlexible(raw);
32
+ return n !== null;
33
+ }
34
+ var parseApiProbPercent = function (raw) {
35
+ var n = parseNumberFlexible(raw);
36
+ return n === null ? 0 : n;
37
+ };
38
+ export function inadFromFallbackPontuacao(p) {
39
+ return ((SCORE_MAX - p) / SCORE_MAX) * 100;
40
+ }
41
+ /**
42
+ * Número inteiro 0–100 na frase "de cada 100" (arredondamento do % resolvido).
43
+ */
44
+ export function inadCountPer100(percent0to100) {
45
+ return Math.min(100, Math.max(0, Math.round(percent0to100)));
46
+ }
47
+ var percentFormatter = new Intl.NumberFormat('pt-BR', {
48
+ minimumFractionDigits: 2,
49
+ maximumFractionDigits: 2
50
+ });
51
+ /**
52
+ * "99,80%" com duas decimais (formato local).
53
+ */
54
+ export function formatInadPercentDisplay(percent0to100) {
55
+ return "".concat(percentFormatter.format(percent0to100), "%");
56
+ }
57
+ export function resolveSerasaInadPercent(rules) {
58
+ var p = parsePonto1000(rules.pontuacao);
59
+ if (isProbFromApiValid(rules.probabilidade_inadimplencia)) {
60
+ return {
61
+ percent0to100: parseApiProbPercent(rules.probabilidade_inadimplencia),
62
+ fromApi: true
63
+ };
64
+ }
65
+ return { percent0to100: inadFromFallbackPontuacao(p), fromApi: false };
66
+ }
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
2
  import { ISectionProps, RequestStatus } from './requestContextTypes';
3
+ /** Aviso no header para exceção esperada (`push=true`): só a mensagem do backend. */
4
+ export declare function pushExceptionDescription(err: Error): React.ReactNode;
3
5
  declare const Section: React.ForwardRefExoticComponent<Omit<ISectionProps<unknown>, "ref"> & React.RefAttributes<HTMLDivElement>>;
4
6
  export declare const headerStatus: Record<RequestStatus, string>;
5
7
  export default Section;
@@ -14,6 +14,7 @@ import { PrintSectionWrapper } from './common/printSectionWrapper';
14
14
  import Header from './interface/header';
15
15
  import StatusMessage from './interface/statusMessage';
16
16
  import { RequestStatus } from './requestContextTypes';
17
+ import { isErrorWithPushFlag } from '../utils/classifyRequestError';
17
18
  var ButtonWrapper = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n justify-content: center;\n width: 100%;\n height: 40%;\n max-height: 52px;\n max-width: 300px;\n margin: 0 auto;\n"], ["\n justify-content: center;\n width: 100%;\n height: 40%;\n max-height: 52px;\n max-width: 300px;\n margin: 0 auto;\n"])));
18
19
  var sectionIdCounter = 0;
19
20
  var nextSectionId = function () {
@@ -49,12 +50,22 @@ var useSectionPrintBlocker = function (ctx, title, enabled, registerBlocker, res
49
50
  }
50
51
  }, [ctx, enabled, registerBlocker, resolveBlocker, title]);
51
52
  };
53
+ /** Aviso no header para exceção esperada (`push=true`): só a mensagem do backend. */
54
+ export function pushExceptionDescription(err) {
55
+ var _a;
56
+ var message = (_a = err.message) === null || _a === void 0 ? void 0 : _a.trim();
57
+ if (!message)
58
+ return undefined;
59
+ return React.createElement(StatusMessage, { type: "warning" }, message);
60
+ }
52
61
  var Section = forwardRef(function (_a, ref) {
53
62
  var onSuccess = _a.onSuccess, _b = _a.isError, isError = _b === void 0 ? function (err, ctx) {
54
- var shouldPush = (err === null || err === void 0 ? void 0 : err.push) === true;
55
- // Se push === true, não exibir erro (caso esperado, tratar como sucesso)
56
- if (shouldPush) {
57
- return null;
63
+ if (isErrorWithPushFlag(err)) {
64
+ return {
65
+ children: React.createElement(React.Fragment, null),
66
+ description: pushExceptionDescription(err),
67
+ variant: 'default'
68
+ };
58
69
  }
59
70
  var message = 'Problemas de comunicação, tente novamente.';
60
71
  return {
@@ -72,10 +83,18 @@ var Section = forwardRef(function (_a, ref) {
72
83
  useSectionPrintBlocker(ctx, headerProps === null || headerProps === void 0 ? void 0 : headerProps.title, readinessEnabled, printReadiness.registerBlocker, printReadiness.resolveBlocker);
73
84
  if (!ctx)
74
85
  return null;
75
- var type = ctx.type, progress = ctx.progress, warningMessage = ctx.warningMessage;
86
+ var type = ctx.type, progress = ctx.progress, warningMessage = ctx.warningMessage, pushNotice = ctx.pushNotice;
76
87
  var renderResponse = useCallback(function () {
77
88
  switch (type) {
78
89
  case RequestStatus.Success:
90
+ if (pushNotice &&
91
+ (ctx.document === undefined || ctx.document === null)) {
92
+ return {
93
+ children: React.createElement(React.Fragment, null),
94
+ description: undefined,
95
+ variant: 'default'
96
+ };
97
+ }
79
98
  return onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(ctx.document, ctx);
80
99
  case RequestStatus.Error: {
81
100
  var errorResult = isError(ctx.error, ctx);
@@ -92,21 +111,30 @@ var Section = forwardRef(function (_a, ref) {
92
111
  default:
93
112
  return null;
94
113
  }
95
- }, [type, onSuccess, isError, onLoading, ctx, printMode]);
114
+ }, [type, onSuccess, isError, onLoading, ctx, printMode, pushNotice]);
96
115
  var renderedResponse = renderResponse();
97
- var descriptionWithWarning = useCallback(function (description) {
98
- if (!warningMessage)
99
- return description;
100
- return (React.createElement(React.Fragment, null,
101
- React.createElement(StatusMessage, { type: "warning" }, warningMessage),
102
- description));
103
- }, [warningMessage]);
116
+ var descriptionWithAlerts = useCallback(function (description) {
117
+ var _a;
118
+ var out = description;
119
+ if (warningMessage) {
120
+ out = (React.createElement(React.Fragment, null,
121
+ React.createElement(StatusMessage, { type: "warning" }, warningMessage),
122
+ out));
123
+ }
124
+ var pushMessage = (_a = pushNotice === null || pushNotice === void 0 ? void 0 : pushNotice.message) === null || _a === void 0 ? void 0 : _a.trim();
125
+ if (pushMessage) {
126
+ out = (React.createElement(React.Fragment, null,
127
+ React.createElement(StatusMessage, { type: "warning" }, pushMessage),
128
+ out));
129
+ }
130
+ return out;
131
+ }, [warningMessage, pushNotice]);
104
132
  var defaultHeaderActions = useMemo(function () {
105
133
  return !printMode ? (React.createElement(BtnWrapper, { hidden: type === RequestStatus.Loading, onClick: toggleOpen }, isOpen ? React.createElement(ChevronUp, null) : React.createElement(ChevronDown, null))) : null;
106
134
  }, [type, isOpen, toggleOpen, printMode]);
107
135
  var renderHeader = function (props) {
108
136
  var description = props.description, actions = props.actions, rest = __rest(props, ["description", "actions"]);
109
- return (React.createElement(Header, __assign({ printBar: renderedResponse !== null && isOpen }, rest, { description: descriptionWithWarning(description), className: cn(className, type !== undefined && headerStatus[type]
137
+ return (React.createElement(Header, __assign({ printBar: renderedResponse !== null && isOpen }, rest, { description: descriptionWithAlerts(description), className: cn(className, type !== undefined && headerStatus[type]
110
138
  ? headerStatus[type]
111
139
  : '', props.className), variant: type === RequestStatus.Loading ? 'loading' : props.variant, loadingProps: {
112
140
  percentage: progress !== null && progress !== void 0 ? progress : 0,
@@ -214,16 +214,26 @@ export function useStreamQuery(query, data, enabled) {
214
214
  !abortControllerRef.current.signal.aborted) {
215
215
  abortControllerRef.current.abort();
216
216
  abortControllerRef.current = null;
217
- setIsLoading(false);
218
- hasStreamStartedRef.current = false;
219
- setResponseIterator(null);
220
217
  }
218
+ setIsLoading(false);
219
+ hasStreamStartedRef.current = false;
220
+ setResponseIterator(null);
221
221
  }, []);
222
+ /**
223
+ * Invariante anti-loop: após falha, mantemos `responseIterator` não-nulo até `abortStream`
224
+ * (o `useEffect` abaixo só dispara novo fetch quando `!responseIterator`). Limpar o iterator
225
+ * em todo erro sem esse contrato faria o efeito reabrir HTTP em ciclo.
226
+ */
222
227
  useEffect(function () {
223
- if (enabled && !responseIterator) {
224
- fetchStream();
228
+ if (!enabled) {
229
+ abortStream();
230
+ return;
225
231
  }
226
- }, [enabled, fetchStream, responseIterator]);
232
+ if (responseIterator)
233
+ return;
234
+ fetchStream();
235
+ }, [enabled, responseIterator, fetchStream, abortStream]);
236
+ useEffect(function () { return function () { return abortStream(); }; }, [abortStream]);
227
237
  return {
228
238
  responseIterator: responseIterator,
229
239
  error: error,
@@ -1,7 +1,7 @@
1
1
  import { EditalResponse, LiminarResponse, PDFProtestoDiscoverResponse, ProcessosJuridicosState } from '../@types/domain';
2
2
  import { Client } from '@credithub/webservice';
3
3
  import React, { Context, FC, PropsWithChildren } from 'react';
4
- import { type ParsedResponse, type RequestContext } from './requestContextTypes';
4
+ import { type ParsedResponse, type PushNotice, type RequestContext } from './requestContextTypes';
5
5
  export * from './requestContextTypes';
6
6
  export declare const WebService: React.Context<Client.WebService>;
7
7
  type RequestDefaults = {
@@ -25,6 +25,7 @@ export declare function CustomProvider<T extends Client.Form = Client.Form, R =
25
25
  export declare function useQuery<R = unknown, T extends Client.Form = Client.Form>(query: string, data?: T, enabled?: boolean): {
26
26
  response: ParsedResponse<R> | null;
27
27
  error: Error | null;
28
+ pushNotice: PushNotice | null;
28
29
  isLoading: boolean;
29
30
  loadingProgress: number;
30
31
  refetch: () => void;