hvp-shared 13.8.0 → 13.9.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.
@@ -58,6 +58,15 @@ export declare const BRANCH_COLOR_IDS: Readonly<Record<AppointmentBranch, string
58
58
  export declare const COLOR_ID_TO_BRANCH: Readonly<Record<string, AppointmentBranch>>;
59
59
  /** colorId 8 (Graphite) = cancelled. Tracked as a separate metric. */
60
60
  export declare const CANCELLED_COLOR_ID = "8";
61
+ /**
62
+ * colorId 7 (Peacock cyan) = cliente no llegó (no-show).
63
+ *
64
+ * Convention: when a client doesn't show up to their appointment, recepción
65
+ * repinta el evento con este color para señalar pendiente-de-seguimiento.
66
+ * Tracked separately from cancellations (which are client-initiated) and
67
+ * excluded from compliance scoring.
68
+ */
69
+ export declare const NO_SHOW_COLOR_ID = "7";
61
70
  /**
62
71
  * colorIds reserved for special events (NOT patient appointments).
63
72
  *
@@ -13,7 +13,7 @@
13
13
  * runs remain reproducible.
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.HVP_EVENT_PROP_KEYS = exports.KNOWN_BREEDS = exports.PET_AGE_REGEX = exports.SCHEDULER_DATE_FALLBACK_REGEX = exports.SCHEDULER_WITH_DATE_REGEX = exports.SCHEDULER_REGEX = exports.PHONE_REGEX = exports.QVET_ID_REGEX = exports.CANCELLED_TITLE_REGEX = exports.REMINDER_TITLE_REGEX = exports.PREFERRED_VET_REGEX = exports.EXCLUDED_TITLE_PREFIXES = exports.SERVICE_CODE_SYNONYMS = exports.CANONICAL_SERVICE_CODES = exports.EXCLUDED_COLOR_IDS = exports.CANCELLED_COLOR_ID = exports.COLOR_ID_TO_BRANCH = exports.BRANCH_COLOR_IDS = exports.STANDARD_V1 = exports.STANDARD_V3 = exports.STANDARD_V2 = void 0;
16
+ exports.HVP_EVENT_PROP_KEYS = exports.KNOWN_BREEDS = exports.PET_AGE_REGEX = exports.SCHEDULER_DATE_FALLBACK_REGEX = exports.SCHEDULER_WITH_DATE_REGEX = exports.SCHEDULER_REGEX = exports.PHONE_REGEX = exports.QVET_ID_REGEX = exports.CANCELLED_TITLE_REGEX = exports.REMINDER_TITLE_REGEX = exports.PREFERRED_VET_REGEX = exports.EXCLUDED_TITLE_PREFIXES = exports.SERVICE_CODE_SYNONYMS = exports.CANONICAL_SERVICE_CODES = exports.EXCLUDED_COLOR_IDS = exports.NO_SHOW_COLOR_ID = exports.CANCELLED_COLOR_ID = exports.COLOR_ID_TO_BRANCH = exports.BRANCH_COLOR_IDS = exports.STANDARD_V1 = exports.STANDARD_V3 = exports.STANDARD_V2 = void 0;
17
17
  // ─── Standard v1 ─────────────────────────────────────────────────────────────
18
18
  /**
19
19
  * Multi-factor appointment standard v2.
@@ -213,6 +213,15 @@ exports.COLOR_ID_TO_BRANCH = {
213
213
  // ─── Excluded colorIds ───────────────────────────────────────────────────────
214
214
  /** colorId 8 (Graphite) = cancelled. Tracked as a separate metric. */
215
215
  exports.CANCELLED_COLOR_ID = "8";
216
+ /**
217
+ * colorId 7 (Peacock cyan) = cliente no llegó (no-show).
218
+ *
219
+ * Convention: when a client doesn't show up to their appointment, recepción
220
+ * repinta el evento con este color para señalar pendiente-de-seguimiento.
221
+ * Tracked separately from cancellations (which are client-initiated) and
222
+ * excluded from compliance scoring.
223
+ */
224
+ exports.NO_SHOW_COLOR_ID = "7";
216
225
  /**
217
226
  * colorIds reserved for special events (NOT patient appointments).
218
227
  *
@@ -407,7 +416,7 @@ exports.SCHEDULER_REGEX = /\b(?:AG[.:]?|AGE[.:]|AGEND[OÓ][.:]?|AGENG[OÓ]|AGED[
407
416
  * "AGENDADA POR SLR 02/12/25" → groups: SLR, "02/12/25"
408
417
  * "AGENDADO POR SLR" → groups: SLR, undefined
409
418
  */
410
- exports.SCHEDULER_WITH_DATE_REGEX = /\b(?:AG[.:]?|AGE[.:]|AGEND[OÓ][.:]?|AGENG[OÓ]|AGED[OÓ]|AGENDAD[OA](?:\s+POR)?)\s+([A-Z]{2,4})(?:\s+(\d{1,2}[./\-]\d{1,2}(?:[./\-]\d{2,4})?|\d{1,2}\s+(?:ENE|FEB|MAR|ABR|MAY|JUN|JUL|AGO|SEP|OCT|NOV|DIC|ENERO|FEBRERO|MARZO|ABRIL|MAYO|JUNIO|JULIO|AGOSTO|SEPTIEMBRE|OCTUBRE|NOVIEMBRE|DICIEMBRE)))?\b/i;
419
+ exports.SCHEDULER_WITH_DATE_REGEX = /\b(?:AG[.:]?|AGE[.:]|AGEND[OÓ][.:]?|AGENG[OÓ]|AGED[OÓ]|AGENDAD[OA](?:\s+POR)?)\s+([A-Z]{2,4})(?:\s+(?:el\s+|del\s+)?(\d{1,2}[./\-]\d{1,2}(?:[./\-]\d{2,4})?|\d{1,2}[./\-](?:ENE|FEB|MAR|ABR|MAY|JUN|JUL|AGO|SEP|OCT|NOV|DIC|ENERO|FEBRERO|MARZO|ABRIL|MAYO|JUNIO|JULIO|AGOSTO|SEPTIEMBRE|OCTUBRE|NOVIEMBRE|DICIEMBRE)(?:[./\-]\d{2,4})?|\d{1,2}\s+(?:ENE|FEB|MAR|ABR|MAY|JUN|JUL|AGO|SEP|OCT|NOV|DIC|ENERO|FEBRERO|MARZO|ABRIL|MAYO|JUNIO|JULIO|AGOSTO|SEPTIEMBRE|OCTUBRE|NOVIEMBRE|DICIEMBRE)))?\b/i;
411
420
  /**
412
421
  * Fallback pattern for when recepción writes just a date followed by a
413
422
  * col_code, no `AGENDO/AG` prefix. Examples observed in production:
@@ -423,7 +432,7 @@ exports.SCHEDULER_WITH_DATE_REGEX = /\b(?:AG[.:]?|AGE[.:]|AGEND[OÓ][.:]?|AGENG[
423
432
  * annotation. Prevents false positives by requiring an immediately-adjacent
424
433
  * date.
425
434
  */
426
- exports.SCHEDULER_DATE_FALLBACK_REGEX = /\b(\d{1,2}[./\-]\d{1,2}(?:[./\-]\d{2,4})?)\s+([A-Z]{2,4})\b/i;
435
+ exports.SCHEDULER_DATE_FALLBACK_REGEX = /\b(\d{1,2}[./\-]\d{1,2}(?:[./\-]\d{2,4})?|\d{1,2}[./\-](?:ENE|FEB|MAR|ABR|MAY|JUN|JUL|AGO|SEP|OCT|NOV|DIC|ENERO|FEBRERO|MARZO|ABRIL|MAYO|JUNIO|JULIO|AGOSTO|SEPTIEMBRE|OCTUBRE|NOVIEMBRE|DICIEMBRE)(?:[./\-]\d{2,4})?)\s+([A-Z]{2,4})\b/i;
427
436
  // ─── Pet age detection ───────────────────────────────────────────────────────
428
437
  /**
429
438
  * Captures pet age expressions in Spanish from descriptions.
@@ -150,6 +150,8 @@ describe("Description regexes", () => {
150
150
  ["18.11.25 MGC", "18.11.25", "MGC"],
151
151
  ["04/05/2026 FJV", "04/05/2026", "FJV"],
152
152
  ["27-11-25 RGL", "27-11-25", "RGL"],
153
+ // 13.8.1 — slash-separated date with month abbreviation
154
+ ["07/may/2026 FJV", "07/may/2026", "FJV"],
153
155
  ];
154
156
  for (const [text, dateExp, codeExp] of cases) {
155
157
  const match = text.match(google_calendar_constants_1.SCHEDULER_DATE_FALLBACK_REGEX);
@@ -157,6 +159,22 @@ describe("Description regexes", () => {
157
159
  expect(match?.[2]?.toUpperCase()).toBe(codeExp);
158
160
  }
159
161
  });
162
+ it("SCHEDULER_WITH_DATE_REGEX captures dates with intervening preposition and slash-month formats", () => {
163
+ const cases = [
164
+ ["AGENDÓ JGG el 05/05/2026", "JGG", "05/05/2026"],
165
+ ["AGENDADO POR JGG el 07/may/2026", "JGG", "07/may/2026"],
166
+ ["agendo jgg el 14 mayo", "JGG", "14 MAYO"],
167
+ ["AGENDO YMP del 16/05/2026", "YMP", "16/05/2026"],
168
+ ["Agendó JGG el 05/05/2026 igual bueno", "JGG", "05/05/2026"],
169
+ ];
170
+ for (const [text, codeExp, dateExp] of cases) {
171
+ const match = text.match(google_calendar_constants_1.SCHEDULER_WITH_DATE_REGEX);
172
+ expect(match?.[1]?.toUpperCase()).toBe(codeExp);
173
+ if (dateExp) {
174
+ expect(match?.[2]?.toUpperCase()).toBe(dateExp.toUpperCase());
175
+ }
176
+ }
177
+ });
160
178
  it("SCHEDULER_WITH_DATE_REGEX captures both col_code and date annotation", () => {
161
179
  const cases = [
162
180
  ["AGENDO XZA 16 MAYO", "XZA", "16 MAYO"],
@@ -53,7 +53,7 @@ export interface DiagnosticDimensionResult {
53
53
  /**
54
54
  * Reason an event was excluded from scoring.
55
55
  */
56
- export type DiagnosticExclusionReason = 'cancelled' | 'blocker' | 'special' | 'operational' | 'interview' | 'reminder';
56
+ export type DiagnosticExclusionReason = 'cancelled' | 'blocker' | 'special' | 'operational' | 'interview' | 'reminder' | 'no_show';
57
57
  /**
58
58
  * Full diagnostic result for one event.
59
59
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hvp-shared",
3
- "version": "13.8.0",
3
+ "version": "13.9.0",
4
4
  "description": "Shared types and utilities for HVP backend and frontend",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",