@qcobro/common 1.24.1 → 1.28.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.
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -2
- package/dist/config.js.map +1 -1
- package/dist/schemas/agentEvaluations.d.ts +619 -0
- package/dist/schemas/agentEvaluations.d.ts.map +1 -0
- package/dist/schemas/agentEvaluations.js +124 -0
- package/dist/schemas/agentEvaluations.js.map +1 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/workspaceSettings.d.ts +31 -1
- package/dist/schemas/workspaceSettings.d.ts.map +1 -1
- package/dist/schemas/workspaceSettings.js +30 -2
- package/dist/schemas/workspaceSettings.js.map +1 -1
- package/dist/types/agentEvaluations.d.ts +93 -0
- package/dist/types/agentEvaluations.d.ts.map +1 -0
- package/dist/types/agentEvaluations.js +2 -0
- package/dist/types/agentEvaluations.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/voiceApplication.d.ts +65 -0
- package/dist/types/voiceApplication.d.ts.map +1 -1
- package/dist/types/workspaceSettings.d.ts +3 -1
- package/dist/types/workspaceSettings.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/money.d.ts +23 -0
- package/dist/utils/money.d.ts.map +1 -0
- package/dist/utils/money.js +68 -0
- package/dist/utils/money.js.map +1 -0
- package/dist/utils/outreach.d.ts +2 -0
- package/dist/utils/outreach.d.ts.map +1 -1
- package/dist/utils/outreach.js +105 -28
- package/dist/utils/outreach.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats an amount for a workspace's locale, with grouping separators.
|
|
3
|
+
*
|
|
4
|
+
* This exists for how amounts are *heard*, not how they look: text-to-speech reads a bare
|
|
5
|
+
* `9500` wrong and `9,500` right, and the provider (ElevenLabs) offers no SSML `<say-as>`
|
|
6
|
+
* control, so the only lever is the text QCobro produces. Rendered outreach bodies are the
|
|
7
|
+
* caller.
|
|
8
|
+
*
|
|
9
|
+
* Fraction digits are two when the amount has a fractional part and none when it does not,
|
|
10
|
+
* so a round balance reads "nueve mil quinientos" rather than "…coma cero cero", and a
|
|
11
|
+
* fractional one reads "…con cincuenta" rather than "…coma cinco".
|
|
12
|
+
*/
|
|
13
|
+
export function formatMoney(value, locale) {
|
|
14
|
+
if (!Number.isFinite(value))
|
|
15
|
+
return "";
|
|
16
|
+
const hasFraction = !Number.isInteger(value);
|
|
17
|
+
return new Intl.NumberFormat(locale, {
|
|
18
|
+
minimumFractionDigits: hasFraction ? 2 : 0,
|
|
19
|
+
maximumFractionDigits: hasFraction ? 2 : 0,
|
|
20
|
+
useGrouping: true
|
|
21
|
+
}).format(value);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The separators a locale uses, discovered from `Intl` rather than assumed — `9.500` is nine
|
|
25
|
+
* thousand five hundred in es-ES and nine-and-a-half in es-DO, so stripping a hardcoded comma
|
|
26
|
+
* would silently corrupt amounts the moment a second market is added.
|
|
27
|
+
*/
|
|
28
|
+
function separatorsFor(locale) {
|
|
29
|
+
const parts = new Intl.NumberFormat(locale, {
|
|
30
|
+
minimumFractionDigits: 1,
|
|
31
|
+
useGrouping: true
|
|
32
|
+
}).formatToParts(12345.6);
|
|
33
|
+
return {
|
|
34
|
+
group: parts.find((p) => p.type === "group")?.value ?? ",",
|
|
35
|
+
decimal: parts.find((p) => p.type === "decimal")?.value ?? "."
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Collapses every space-like separator shape to a plain ASCII space. */
|
|
39
|
+
function normalizeSpaces(value) {
|
|
40
|
+
return value.replace(/[\u00a0\u202f\u2007\u2009\u3000]/g, " ");
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parses a value that may be a number or a locale-formatted amount back to a number, so the
|
|
44
|
+
* template helpers keep working now that money-typed context fields render formatted. Returns
|
|
45
|
+
* `NaN` for anything unparseable — callers preserve their existing malformed-context
|
|
46
|
+
* behavior (`multiply` yields 0, comparisons yield false) rather than leaking `NaN` into
|
|
47
|
+
* customer-facing copy.
|
|
48
|
+
*/
|
|
49
|
+
export function toNumber(value, locale) {
|
|
50
|
+
if (typeof value === "number")
|
|
51
|
+
return value;
|
|
52
|
+
if (typeof value !== "string")
|
|
53
|
+
return Number(value);
|
|
54
|
+
const trimmed = value.trim();
|
|
55
|
+
if (trimmed === "")
|
|
56
|
+
return NaN;
|
|
57
|
+
const { group, decimal } = separatorsFor(locale);
|
|
58
|
+
// Some locales group with a non-breaking or narrow no-break space. Normalize every space
|
|
59
|
+
// shape to a plain one — in the value *and* in the separator — or the strip silently
|
|
60
|
+
// misses and `9 500` parses as NaN.
|
|
61
|
+
const normalized = normalizeSpaces(trimmed)
|
|
62
|
+
.split(normalizeSpaces(group))
|
|
63
|
+
.join("")
|
|
64
|
+
.split(decimal)
|
|
65
|
+
.join(".");
|
|
66
|
+
return Number(normalized);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=money.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"money.js","sourceRoot":"","sources":["../../src/utils/money.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,MAAc;IACvD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;QACnC,qBAAqB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,qBAAqB,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;QAC1C,qBAAqB,EAAE,CAAC;QACxB,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,KAAK,IAAI,GAAG;QAC1D,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,KAAK,IAAI,GAAG;KAC/D,CAAC;AACJ,CAAC;AAED,yEAAyE;AACzE,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAc,EAAE,MAAc;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,GAAG,CAAC;IAE/B,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACjD,yFAAyF;IACzF,qFAAqF;IACrF,oCAAoC;IACpC,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC;SACxC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;SAC7B,IAAI,CAAC,EAAE,CAAC;SACR,KAAK,CAAC,OAAO,CAAC;SACd,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC"}
|
package/dist/utils/outreach.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PortfolioAccountRecord } from "../types/portfolios.js";
|
|
2
2
|
import type { NumberSelector, WhatsAppTemplateParam } from "../types/dispatch.js";
|
|
3
|
+
import { type Locale } from "../schemas/workspaceSettings.js";
|
|
3
4
|
/**
|
|
4
5
|
* Renders a Handlebars template against a context. Bodies are plain text (voice
|
|
5
6
|
* script / SMS), never HTML, so escaping is disabled. A missing `{{field}}`
|
|
@@ -36,6 +37,7 @@ export declare function extractTemplateTokens(template: string): string[];
|
|
|
36
37
|
*/
|
|
37
38
|
export declare function buildOutreachContext(account: PortfolioAccountRecord, opts: {
|
|
38
39
|
currency: string;
|
|
40
|
+
locale: Locale;
|
|
39
41
|
}): Record<string, unknown>;
|
|
40
42
|
/**
|
|
41
43
|
* Builds the "Contexto — ..." bullet lines an autopilot prompt (WhatsApp/Email) shows the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outreach.d.ts","sourceRoot":"","sources":["../../src/utils/outreach.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"outreach.d.ts","sourceRoot":"","sources":["../../src/utils/outreach.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAyH9E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAQzF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAQhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,sBAAsB,EAC/B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAqBzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CA0DjG;AAED,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,EAAE,cACsB,CAAC;AAEtD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAa3D"}
|
package/dist/utils/outreach.js
CHANGED
|
@@ -1,32 +1,84 @@
|
|
|
1
1
|
import Handlebars from "handlebars";
|
|
2
|
+
import { DEFAULT_LOCALE } from "../schemas/workspaceSettings.js";
|
|
3
|
+
import { formatMoney, toNumber } from "./money.js";
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* The workspace locale for the render in progress, read off the root context that
|
|
6
|
+
* {@link buildOutreachContext} builds. Helpers are registered once, globally, so the locale
|
|
7
|
+
* cannot be closed over at registration — it has to come from the context being rendered.
|
|
8
|
+
* A context assembled some other way (a bare object in a test, a legacy caller) falls back to
|
|
9
|
+
* the default rather than throwing mid-dispatch.
|
|
6
10
|
*/
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
+
function localeOf(options) {
|
|
12
|
+
const root = options?.data?.root;
|
|
13
|
+
const value = root?.locale;
|
|
14
|
+
if (typeof value !== "string" || value === "")
|
|
15
|
+
return DEFAULT_LOCALE;
|
|
16
|
+
try {
|
|
17
|
+
// The supported-locale check belongs at the settings boundary, not here — re-checking it
|
|
18
|
+
// would make a helper silently ignore the workspace's own locale. All this guards is a
|
|
19
|
+
// malformed tag, which `Intl` throws a RangeError for; that must not surface as a
|
|
20
|
+
// template error in the middle of a customer-facing body.
|
|
21
|
+
new Intl.NumberFormat(value);
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return DEFAULT_LOCALE;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `{{multiply a b}}` — multiplies two amounts. Operands may be raw numbers or the
|
|
30
|
+
* locale-formatted amounts that money-typed context fields now render as (`"9,500"`), and the
|
|
31
|
+
* result is formatted the same way, so `{{multiply outstandingBalance 0.5}}` reads aloud like
|
|
32
|
+
* a stored balance. Either operand being non-numeric (missing field, bad data) yields 0
|
|
33
|
+
* rather than NaN, so a malformed context never produces `NaN` in a customer-facing message.
|
|
34
|
+
*/
|
|
35
|
+
Handlebars.registerHelper("multiply", (a, b, options) => {
|
|
36
|
+
const locale = localeOf(options);
|
|
37
|
+
const x = toNumber(a, locale);
|
|
38
|
+
const y = toNumber(b, locale);
|
|
39
|
+
return Number.isFinite(x) && Number.isFinite(y) ? formatMoney(x * y, locale) : 0;
|
|
11
40
|
});
|
|
12
41
|
/**
|
|
13
42
|
* `{{eq a b}}` — strict equality, for branching on exact values (e.g.
|
|
14
|
-
* `{{#if (eq customerSegment "variant_A")}}`).
|
|
43
|
+
* `{{#if (eq customerSegment "variant_A")}}`). Numeric operands are compared by value, so
|
|
44
|
+
* comparing a money-typed field against a number still works now that it renders formatted.
|
|
15
45
|
*/
|
|
16
|
-
Handlebars.registerHelper("eq", (a, b) =>
|
|
46
|
+
Handlebars.registerHelper("eq", (a, b, options) => {
|
|
47
|
+
if (a === b)
|
|
48
|
+
return true;
|
|
49
|
+
const locale = localeOf(options);
|
|
50
|
+
const x = toNumber(a, locale);
|
|
51
|
+
const y = toNumber(b, locale);
|
|
52
|
+
return Number.isFinite(x) && Number.isFinite(y) && x === y;
|
|
53
|
+
});
|
|
17
54
|
/**
|
|
18
55
|
* `{{gt a b}}` / `{{gte a b}}` / `{{lt a b}}` / `{{lte a b}}` — numeric
|
|
19
56
|
* comparisons for use inside `{{#if}}`, e.g. `{{#if (gte daysPastDue 30)}}`.
|
|
20
|
-
* Operands are
|
|
21
|
-
*
|
|
22
|
-
* makes the condition not match rather than
|
|
23
|
-
* an alias of `gte` (both names are in common use).
|
|
57
|
+
* Operands are parsed with the workspace locale so a formatted amount compares by its
|
|
58
|
+
* underlying value; anything unparseable becomes `NaN`, and every JS comparison against
|
|
59
|
+
* `NaN` is `false` — so a malformed context makes the condition not match rather than
|
|
60
|
+
* throwing. `ge` is registered as an alias of `gte` (both names are in common use).
|
|
61
|
+
*/
|
|
62
|
+
Handlebars.registerHelper("gt", (a, b, o) => toNumber(a, localeOf(o)) > toNumber(b, localeOf(o)));
|
|
63
|
+
Handlebars.registerHelper("gte", (a, b, o) => toNumber(a, localeOf(o)) >= toNumber(b, localeOf(o)));
|
|
64
|
+
Handlebars.registerHelper("ge", (a, b, o) => toNumber(a, localeOf(o)) >= toNumber(b, localeOf(o)));
|
|
65
|
+
Handlebars.registerHelper("lt", (a, b, o) => toNumber(a, localeOf(o)) < toNumber(b, localeOf(o)));
|
|
66
|
+
Handlebars.registerHelper("lte", (a, b, o) => toNumber(a, localeOf(o)) <= toNumber(b, localeOf(o)));
|
|
67
|
+
/**
|
|
68
|
+
* `{{digits value}}` — renders a value's digits separated by single spaces
|
|
69
|
+
* (`"8092323333"` → `"8 0 9 2 3 2 3 3 3 3"`) so text-to-speech reads them one at a time
|
|
70
|
+
* instead of as a single quantity. Non-digit characters are dropped, so a stored
|
|
71
|
+
* `"+1 (809) 232-3333"` works as-is; an empty or missing value renders empty rather than
|
|
72
|
+
* aborting the dispatch.
|
|
73
|
+
*
|
|
74
|
+
* This one stays opt-in — only the template author knows a value should be spelled out.
|
|
75
|
+
* `{{digits phone}}` is right, `{{digits outstandingBalance}}` is not.
|
|
24
76
|
*/
|
|
25
|
-
Handlebars.registerHelper("
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
77
|
+
Handlebars.registerHelper("digits", (value) => {
|
|
78
|
+
if (value === null || value === undefined)
|
|
79
|
+
return "";
|
|
80
|
+
return String(value).replace(/\D/g, "").split("").join(" ");
|
|
81
|
+
});
|
|
30
82
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
31
83
|
function toDate(value) {
|
|
32
84
|
if (value instanceof Date)
|
|
@@ -104,10 +156,21 @@ export function extractTemplateTokens(template) {
|
|
|
104
156
|
*/
|
|
105
157
|
export function buildOutreachContext(account, opts) {
|
|
106
158
|
const firstName = account.fullName.trim().split(/\s+/)[0] ?? "";
|
|
159
|
+
const money = (value) => value === null ? null : formatMoney(value, opts.locale);
|
|
107
160
|
return {
|
|
108
161
|
...account,
|
|
162
|
+
// Money-typed fields are formatted here rather than at each call site so every channel —
|
|
163
|
+
// and the console's live preview — renders the same text. Counts (daysPastDue,
|
|
164
|
+
// missedInstallments, termsLength) stay numeric: a count with a thousands separator is
|
|
165
|
+
// wrong, and `{{daysPastDue}}` reads correctly as-is.
|
|
166
|
+
outstandingBalance: money(account.outstandingBalance),
|
|
167
|
+
principalAmount: money(account.principalAmount),
|
|
168
|
+
termsAmount: money(account.termsAmount),
|
|
169
|
+
lastPaymentAmount: money(account.lastPaymentAmount),
|
|
109
170
|
firstName,
|
|
110
171
|
currency: opts.currency,
|
|
172
|
+
// Read by the numeric helpers to parse formatted operands back to numbers.
|
|
173
|
+
locale: opts.locale,
|
|
111
174
|
isDue: account.daysPastDue > 0
|
|
112
175
|
};
|
|
113
176
|
}
|
|
@@ -128,20 +191,35 @@ export function buildAutopilotContextLines(context) {
|
|
|
128
191
|
return [];
|
|
129
192
|
const lines = [];
|
|
130
193
|
const currency = typeof context.currency === "string" ? ` ${context.currency}` : "";
|
|
194
|
+
const locale = typeof context.locale === "string" ? context.locale : DEFAULT_LOCALE;
|
|
195
|
+
/**
|
|
196
|
+
* Money-typed context fields are locale-formatted strings, not numbers, so these lines read
|
|
197
|
+
* the amount back through the locale rather than testing `typeof === "number"` — that guard
|
|
198
|
+
* would now silently drop every amount from the model's context.
|
|
199
|
+
*/
|
|
200
|
+
const amount = (value) => {
|
|
201
|
+
if (value === null || value === undefined)
|
|
202
|
+
return null;
|
|
203
|
+
const parsed = toNumber(value, locale);
|
|
204
|
+
return Number.isFinite(parsed) ? { text: String(value), value: parsed } : null;
|
|
205
|
+
};
|
|
131
206
|
if (typeof context.firstName === "string" && context.firstName) {
|
|
132
207
|
lines.push(`Cliente: ${context.firstName}`);
|
|
133
208
|
}
|
|
134
|
-
|
|
135
|
-
|
|
209
|
+
const balance = amount(context.outstandingBalance);
|
|
210
|
+
if (balance) {
|
|
211
|
+
lines.push(`Saldo pendiente: ${balance.text}${currency}`);
|
|
136
212
|
}
|
|
137
|
-
|
|
138
|
-
|
|
213
|
+
const principal = amount(context.principalAmount);
|
|
214
|
+
if (principal && principal.value > 0) {
|
|
215
|
+
lines.push(`Monto original del préstamo: ${principal.text}${currency}`);
|
|
139
216
|
}
|
|
140
|
-
|
|
217
|
+
const installment = amount(context.termsAmount);
|
|
218
|
+
if (installment && installment.value > 0) {
|
|
141
219
|
const freq = typeof context.termsFrequency === "string" && context.termsFrequency
|
|
142
220
|
? ` (${context.termsFrequency})`
|
|
143
221
|
: "";
|
|
144
|
-
lines.push(`Cuota: ${
|
|
222
|
+
lines.push(`Cuota: ${installment.text}${currency}${freq}`);
|
|
145
223
|
}
|
|
146
224
|
if (typeof context.termsLength === "number" && context.termsLength > 0) {
|
|
147
225
|
lines.push(`Plazo: ${context.termsLength} cuotas`);
|
|
@@ -157,10 +235,9 @@ export function buildAutopilotContextLines(context) {
|
|
|
157
235
|
? context.lastPaymentDate
|
|
158
236
|
: new Date(context.lastPaymentDate);
|
|
159
237
|
if (!Number.isNaN(date.getTime())) {
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
lines.push(`Último pago${amount}: ${date.toISOString().slice(0, 10)}`);
|
|
238
|
+
const lastPayment = amount(context.lastPaymentAmount);
|
|
239
|
+
const paid = lastPayment ? ` de ${lastPayment.text}${currency}` : "";
|
|
240
|
+
lines.push(`Último pago${paid}: ${date.toISOString().slice(0, 10)}`);
|
|
164
241
|
}
|
|
165
242
|
}
|
|
166
243
|
return lines;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outreach.js","sourceRoot":"","sources":["../../src/utils/outreach.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"outreach.js","sourceRoot":"","sources":["../../src/utils/outreach.ts"],"names":[],"mappings":"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"}
|