feat: visible lead origin (Notes) + UI search trigger #2

Merged
forgejo-admin merged 3 commits from feature/lead-origin-note into main 2026-07-25 17:32:22 +00:00

Zusammenfassung

  • Herkunfts-Notiz: Jeder neu angelegte Lead bekommt jetzt eine FCRM Note „Herkunft: Google Places" mit Suchbegriff, Region, Stadt, Website-Scan-Status und Google-Bewertung. Hintergrund: Tags (Suchbegriff/Land/Region) werden zwar korrekt gespeichert, aber die CRM-Oberfläche hat keine UI-Komponente für generische Frappe-Tags — im gesamten Vue-Frontend nachgeprüft, keine Treffer. Für den Nutzer waren Tags damit faktisch unsichtbar. Die „Notes"-Ansicht existiert dagegen nachweislich im Lead-Frontend und wird bereits für die Duplikat-Notiz genutzt.
  • UI-Trigger nachgetragen: leadscraper/api.py (whitelisted enqueue_search) + Client-Script auf Lead Scraper Settings („Leads suchen"-Button mit Dialog für Suchbegriff/Regionen/Limit) — war bereits fertig und gegen den laufenden Stack getestet, aber nie committet (auf dieser Branch nachgeholt).

Verifikation

  • Herkunfts-Notiz: End-to-End gegen den laufenden Stack getestet (Skript, danach frappe.db.rollback()), Notiz-Inhalt korrekt.
  • UI-Trigger: Button + Dialog getestet, enqueue_search queued erfolgreich einen queue-long-Job, der einen echten Lead per Google-Places-Suche anlegt.

Test plan

  • Nach Merge: frappe-crm-erp neu bauen (apps.json zeigt auf main), damit die Änderungen im Image landen
  • Im CRM-Frontend einen Testlauf starten, „Notes"-Tab eines neuen Leads prüfen

Refs #1

## Zusammenfassung - **Herkunfts-Notiz:** Jeder neu angelegte Lead bekommt jetzt eine `FCRM Note` „Herkunft: Google Places" mit Suchbegriff, Region, Stadt, Website-Scan-Status und Google-Bewertung. Hintergrund: Tags (Suchbegriff/Land/Region) werden zwar korrekt gespeichert, aber die CRM-Oberfläche hat **keine** UI-Komponente für generische Frappe-Tags — im gesamten Vue-Frontend nachgeprüft, keine Treffer. Für den Nutzer waren Tags damit faktisch unsichtbar. Die „Notes"-Ansicht existiert dagegen nachweislich im Lead-Frontend und wird bereits für die Duplikat-Notiz genutzt. - **UI-Trigger nachgetragen:** `leadscraper/api.py` (whitelisted `enqueue_search`) + Client-Script auf `Lead Scraper Settings` („Leads suchen"-Button mit Dialog für Suchbegriff/Regionen/Limit) — war bereits fertig und gegen den laufenden Stack getestet, aber nie committet (auf dieser Branch nachgeholt). ## Verifikation - Herkunfts-Notiz: End-to-End gegen den laufenden Stack getestet (Skript, danach `frappe.db.rollback()`), Notiz-Inhalt korrekt. - UI-Trigger: Button + Dialog getestet, `enqueue_search` queued erfolgreich einen `queue-long`-Job, der einen echten Lead per Google-Places-Suche anlegt. ## Test plan - [ ] Nach Merge: `frappe-crm-erp` neu bauen (`apps.json` zeigt auf `main`), damit die Änderungen im Image landen - [ ] Im CRM-Frontend einen Testlauf starten, „Notes"-Tab eines neuen Leads prüfen Refs #1
Adds a "Leads suchen" button on the Lead Scraper Settings form (client
script) that opens a dialog for query/regions/limit-cities and calls a
new whitelisted leadscraper.api.enqueue_search, which queues tasks.run()
on the long-running job queue. This was the missing piece for a normal
CRM user to trigger a search without server/CLI access - previously only
bench commands existed.

Verified end-to-end against the running stack: button appears after
`bench build --app leadscraper`, enqueue_search correctly queues an RQ
job, the job completes and creates a real lead from a live Google Places
search triggered purely through the API (simulating the button click).

Note: this was implemented and tested in the same session as the CLI
commands (Refs #1) but was left uncommitted - catching up on this
feature branch.
Tags (query/country/region) were the only signal recorded for where a
lead came from, but the CRM frontend has no UI for generic Frappe tags
at all - checked the whole Vue frontend source, there's no tag component
anywhere. Tags were saved correctly in the DB but effectively invisible
to a normal CRM user.

add_origin_note() now records an "Herkunft: Google Places" FCRM Note
(search term, region, city, website-scan status, Google rating) on
every new lead, using the same reference_doctype/reference_docname
mechanism already used for the duplicate note - and the Notes tab is
confirmed present in the CRM's own Lead view. Tags are kept (still
useful for Desk list-view filtering), this just adds the visible
counterpart in the CRM app people actually use.

Verified against the running stack: note content renders with the
correct search context.
Real-world bug found while testing this branch: recaro-schnell.de's
mailto link (or a similarly encoded one) produced an unescaped HTML
entity in the extracted address, which then hit CRM Lead's
validate_email() as "info&...", raising InvalidEmailAddressError and
aborting the entire row's create_lead_from_row() - the Lead never got
created (validate() runs before the DB insert), no error was even
visible to the user beyond "fewer leads than expected", and worse: any
Lead created *after* the failing one in the same batch was, in one
observed run, missing its tags/origin note despite the code paths
otherwise working (isolated and reproduced with a controlled two-row
batch to confirm assign_tags/add_origin_note work correctly in
isolation - most likely explanation was a stale __pycache__/*.pyc from
an earlier `docker cp` whose mtime ordering fooled Python's bytecode
cache, not a logic bug; cleared now and documented as another instance
of the "container has code Python already imported" class of gotcha).

Two fixes:
- extract_email() now unescapes the mailto: candidate and validates it
  with EMAIL_RE.fullmatch before trusting it, falling back to the
  general regex scan of the (already-unescaped) page content otherwise.
- build_lead_fields() re-validates the final email regardless of source
  and silently drops it if malformed, instead of ever reaching
  frappe.get_doc(...).insert() with bad data - so no future extraction
  edge case can block lead creation again.

Verified against the real site that triggered this (recaro-schnell.de):
email now extracts cleanly as "info@r-schnell.de".
forgejo-admin deleted branch feature/lead-origin-note 2026-07-25 17:32:22 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Frappe-Projekte/LeadScraper-Google!2
No description provided.