Shurem commited on
Commit
fd2fe83
Β·
1 Parent(s): f05451c

fixed issue

Browse files
Files changed (2) hide show
  1. app/services/validation.py +14 -0
  2. docs.md +83 -0
app/services/validation.py CHANGED
@@ -328,10 +328,24 @@ def is_plausible_phone(raw: str) -> bool:
328
  phone number at all: a character that isn't a digit or common phone punctuation, or too few digits.
329
  Empty is plausible (a lead is allowed to have no phone at all) -- only a GIVEN garbage value should
330
  block a save; see CreateLeadInput/UpdateLeadInput's own field_validators.
 
 
 
 
 
 
 
331
  """
332
  value = (raw or "").strip()
333
  if not value:
334
  return True
 
 
 
 
 
 
 
335
  if any(ch not in "0123456789+()-. " for ch in value):
336
  return False
337
  return sum(ch.isdigit() for ch in value) >= 7
 
328
  phone number at all: a character that isn't a digit or common phone punctuation, or too few digits.
329
  Empty is plausible (a lead is allowed to have no phone at all) -- only a GIVEN garbage value should
330
  block a save; see CreateLeadInput/UpdateLeadInput's own field_validators.
331
+
332
+ BUGFIX (2026-10-29): contact_phone has ALWAYS been allowed to carry several comma-joined numbers for
333
+ one lead -- see call_timezone()'s own `.split(",")[0]`, crud/contacts.py, lead_engine.py's
334
+ _all_phones(), and the frontend's PhoneNumberList, all of which already expect this. This function
335
+ didn't account for that at all (no comma in its character whitelist), so any lead with more than one
336
+ number on file -- a legitimate, pre-existing, everyday case -- failed validation and blocked Save the
337
+ moment entry (6)'s blocking field_validator shipped. Now checks each comma-separated piece on its own.
338
  """
339
  value = (raw or "").strip()
340
  if not value:
341
  return True
342
+ pieces = [p.strip() for p in value.split(",") if p.strip()]
343
+ if not pieces:
344
+ return False
345
+ return all(_is_plausible_single_phone(p) for p in pieces)
346
+
347
+
348
+ def _is_plausible_single_phone(value: str) -> bool:
349
  if any(ch not in "0123456789+()-. " for ch in value):
350
  return False
351
  return sum(ch.isdigit() for ch in value) >= 7
docs.md CHANGED
@@ -3,6 +3,89 @@
3
  Running record of features shipped, bugs fixed, and how each was verified.
4
  Newest entry first. See `CLAUDE.md` for the logging rule.
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  ## 2026-10-28 (9)
7
 
8
  ### Lint cleanup: unused `MailtoButton` import
 
3
  Running record of features shipped, bugs fixed, and how each was verified.
4
  Newest entry first. See `CLAUDE.md` for the logging rule.
5
 
6
+ ## 2026-10-29 (2)
7
+
8
+ ### Bug fix: meeting booked from Callbacks/Pipeline/Meetings didn't count in Today's "Meetings" stat
9
+
10
+ User: "agar callbacks tab sy ya kahin sy meeting booked hoti hai woh meetings me count nhi hoti today me".
11
+ Root cause: Today/This-Week's "Meetings" stat (`app/crud/call_events.py`'s `_count_outcomes(... (
12
+ "meeting_booked",))`) only ever counts rows in the `call_events` table β€” written by
13
+ `apply_call_outcome()`/`book_followup_meeting()`. Cold Call Desk's battlecard correctly books a meeting
14
+ through `useCallOutcome()` (β†’ `apply_call_outcome`, which writes a call_events row), so those always
15
+ counted. But two OTHER "book a meeting" buttons β€” found by grepping every frontend call site that sets
16
+ `pipeline_stage: "meeting_booked"` β€” used a plain `useUpdateLead()` PATCH instead: a raw field write that
17
+ never touches `call_events` at all. The lead still correctly moved to the Meetings calendar (that only
18
+ needs `meeting_at`), so this was invisible unless you were specifically watching the Today counter.
19
+
20
+ **Files touched** (both frontend-only β€” the backend's `/leads/{id}/outcome` endpoint already existed and
21
+ already logs correctly, this was purely a wrong-hook wiring bug):
22
+ - `outreach-frontend/components/pipeline/pipeline-view.tsx` β€” `PipelineActions`'s "Meeting Booked" button
23
+ (shared by `/pipeline` AND `/callbacks`, since Callbacks reuses this same component scoped differently)
24
+ now uses `useCallOutcome()` instead of `useUpdateLead()` for a first-time booking (the
25
+ already-correct `useBookFollowupMeeting()` path for `proposal_sent`-stage leads is untouched).
26
+ - `outreach-frontend/components/meetings/needs-followup-list.tsx` β€” the Meetings page's "Mark as Meeting
27
+ Booked" button (on a lead sitting at Needs Follow-up), same swap.
28
+
29
+ Both now go through the exact same `apply_call_outcome(outcome="meeting_booked")` path Cold Call Desk
30
+ already used, which does everything the old raw PATCH did (same `pipeline_stage`/`meeting_at`) PLUS logs
31
+ to `call_events` (counts in Today), appends a note, and clears `sent_to_desk_at` if the lead was still on
32
+ a desk. Checked for other instances of the same bug pattern β€” two other `meeting_at:`-setting call sites
33
+ remain (`add-lead-popover.tsx`, and the general multi-field save in `lead-edit-form.tsx`) but both are
34
+ bulk/initial data entry, not a "disposition" action, so left as-is; only dedicated "book a meeting" action
35
+ buttons were in scope.
36
+
37
+ **How verified**: `npx tsc --noEmit` (0 errors) and `npx eslint` on both files (0 warnings/errors). Both
38
+ mirrored to `E:\outreach-agent-frontend`, confirmed zero drift via `diff -q`.
39
+
40
+ **Status**: ⚠️ Partial β€” code complete and statically verified, NOT yet live-tested. No backend restart
41
+ needed (frontend-only change, no backend file touched) β€” picked up on next page load. Live test: book a
42
+ meeting from the Callbacks tab (or Meetings page's "Mark as Meeting Booked"), then check Today's Meetings
43
+ count went up by one.
44
+
45
+ ## 2026-10-29 (1)
46
+
47
+ ### Bug fix: phone validation (entry 2026-10-28 (6)) broke the existing multi-number format
48
+
49
+ User screenshot: Contact Phone field with "+447786363281 ,+44 371 964 2113" (two numbers, the CRM's
50
+ existing comma-joined-multiple-numbers format β€” see `components/leads/phone-number-list.tsx`,
51
+ `lead_engine.py`'s `_all_phones()`, `call_timezone()`'s own `.split(",")[0]`) rejected as "Doesn't look
52
+ like a valid phone number", Save stuck disabled. Root cause: entry (6)'s `is_plausible_phone()` (both
53
+ backend and frontend) only ever validated a SINGLE number's characters β€” comma wasn't in the whitelist β€”
54
+ so any lead that legitimately carries more than one number broke the moment that blocking validator
55
+ shipped. This was a regression in a prior fix, not a pre-existing bug.
56
+
57
+ Fix: `is_plausible_phone()` now splits the input on comma and validates each piece independently (all
58
+ must pass), in both `outreach-backend/app/services/validation.py` and
59
+ `outreach-frontend/lib/validation/lead.ts`.
60
+
61
+ Also implemented the user's second ask in the same message: "agar koi add krna bhul jaye 2 3 numbers me
62
+ sy ek k bech me toh system wahan auto add kr dy" β€” if someone types/pastes two numbers back-to-back with
63
+ no separator at all, auto-insert one. New `autoSeparatePhoneNumbers()` in `lib/validation/lead.ts`,
64
+ scoped to the one unambiguous boundary this data actually has (every real number here starts with
65
+ "+<country code>"): a "+" immediately following another number's digits (no comma, only whitespace or
66
+ nothing between) gets a ", " inserted before it. Wired to `onBlur` on the Contact Phone field in both
67
+ `components/layout/add-lead-popover.tsx` and `components/leads/lead-edit-form.tsx` β€” reformats as soon as
68
+ the rep leaves the field, before `phoneInvalid` is ever computed against it. An already-comma-separated
69
+ input is left untouched (confirmed below).
70
+
71
+ **Files touched**: `outreach-backend/app/services/validation.py`,
72
+ `outreach-frontend/lib/validation/lead.ts`, `outreach-frontend/components/layout/add-lead-popover.tsx`,
73
+ `outreach-frontend/components/leads/lead-edit-form.tsx`.
74
+
75
+ **How verified**: `python3 -m py_compile` (backend, clean) plus a standalone interpreter check of the
76
+ split-validation logic against the exact reported value and several others (all correct, including
77
+ `""` β†’ true and `"qw"` β†’ false unchanged); `npx tsc --noEmit` (0 errors) and `npx eslint` (exit 0) on
78
+ all touched frontend files; a standalone Node check of both `isPlausiblePhone()` and
79
+ `autoSeparatePhoneNumbers()` together against 5 cases, including two numbers pasted with NO separator at
80
+ all and the user's own reported value verbatim β€” all passed. All 4 files mirrored to `E:\mz_chatbot` /
81
+ `E:\outreach-agent-frontend`, confirmed zero drift via `diff -q`.
82
+
83
+ **Status**: ⚠️ Partial β€” code complete and verified statically + via standalone logic tests, NOT yet
84
+ live-tested in the running app. Needs a backend restart (`validation.py` changed); frontend picked up on
85
+ next page load. Live test: paste the user's exact reported value into Contact Phone on both Add Lead and
86
+ Edit Lead, confirm Save is enabled; also type two numbers with no separator and tab out, confirm a comma
87
+ gets inserted automatically.
88
+
89
  ## 2026-10-28 (9)
90
 
91
  ### Lint cleanup: unused `MailtoButton` import