feat(go-crm): full auth, routing, middleware, and supporting infra
- Add auth handlers (signup, login, logout, account management) with bcrypt - Add client, customer, service, scheduling, payment, question, answer handlers - Add dashboard, monthly report, and lead pipeline pages - Add UTF-8 middleware to force charset on HTML responses - Add config package with env-based overrides for DB path, secrets, endpoints - Add parser package for WhatsApp message ingestion - Add clean-arch layers: pkg/domain, pkg/repo, pkg/usecase for leads - Add cmd/migrate utility for DB migrations - Add Makefile, README, run-tests.sh, and dev scripts - Update docker-compose.yml with memory limits - Update .air.toml to exclude DB files and stop on errors - Update whatsapp-sync dependencies and add src/index.js entrypoint - Add whatsme standalone WhatsApp reader app (source only) - Untrack .opencode-sandbox/data/go-crm.db from git history - Expand root .gitignore: ngrok, tmp dirs, sandbox DBs, compiled binaries
This commit is contained in:
117
apps/go-crm/internal/parser/parser_test.go
Normal file
117
apps/go-crm/internal/parser/parser_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package parser_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go-crm/internal/parser"
|
||||
)
|
||||
|
||||
func TestExtractService_KnownKeywords(t *testing.T) {
|
||||
keywords := map[string]string{
|
||||
"head spa": "Head Spa",
|
||||
"head-spa": "Head Spa",
|
||||
"headspa": "Head Spa",
|
||||
"massagem": "Massagem completa",
|
||||
"massagem completa": "Massagem completa",
|
||||
"drenagem": "Drenagem linfatica",
|
||||
"linfática": "Drenagem linfatica",
|
||||
"hydra": "Hydra Boost",
|
||||
"hydra boost": "Hydra Boost",
|
||||
"henna": "Design Henna",
|
||||
"design henna": "Design Henna",
|
||||
"masculino": "Masculino",
|
||||
"masc": "Masculino",
|
||||
}
|
||||
|
||||
mapping := map[string]string{
|
||||
"head spa": "Head Spa",
|
||||
"head-spa": "Head Spa",
|
||||
"headspa": "Head Spa",
|
||||
"massagem": "Massagem completa",
|
||||
"massagem completa": "Massagem completa",
|
||||
"drenagem": "Drenagem linfatica",
|
||||
"linfática": "Drenagem linfatica",
|
||||
"hydra": "Hydra Boost",
|
||||
"hydra boost": "Hydra Boost",
|
||||
"henna": "Design Henna",
|
||||
"design henna": "Design Henna",
|
||||
"masculino": "Masculino",
|
||||
"masc": "Masculino",
|
||||
}
|
||||
|
||||
for kw, expected := range keywords {
|
||||
// Build messages in Portuguese with the keyword embedded in natural phrasing.
|
||||
messages := []string{
|
||||
"Olá, gostaria de agendar um " + kw,
|
||||
"Boa tarde! Quero fazer " + kw + " por favor",
|
||||
"Quanto custa " + kw + "?",
|
||||
kw,
|
||||
}
|
||||
for _, msg := range messages {
|
||||
got := parser.ExtractService(msg, mapping)
|
||||
if got != expected {
|
||||
t.Errorf("message %q with keyword %q: got %q, want %q", msg, kw, got, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractService_UnknownMessage_ReturnsNaoEspecificou(t *testing.T) {
|
||||
mapping := map[string]string{
|
||||
"massagem": "Massagem completa",
|
||||
}
|
||||
|
||||
messages := []string{
|
||||
"Olá, tudo bem?",
|
||||
"Qual o horário de funcionamento?",
|
||||
"Vocês atendem no sábado?",
|
||||
"",
|
||||
}
|
||||
|
||||
for _, msg := range messages {
|
||||
got := parser.ExtractService(msg, mapping)
|
||||
if got != "Não especificou" {
|
||||
t.Errorf("message %q: got %q, want %q", msg, got, "Não especificou")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractService_CaseInsensitive(t *testing.T) {
|
||||
mapping := map[string]string{
|
||||
"head spa": "Head Spa",
|
||||
"henna": "Design Henna",
|
||||
}
|
||||
|
||||
cases := map[string]string{
|
||||
"Quero HEAD SPA": "Head Spa",
|
||||
"HENNA por favor": "Design Henna",
|
||||
"Head Spa agora": "Head Spa",
|
||||
}
|
||||
|
||||
for msg, expected := range cases {
|
||||
got := parser.ExtractService(msg, mapping)
|
||||
if got != expected {
|
||||
t.Errorf("message %q: got %q, want %q", msg, got, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePhone(t *testing.T) {
|
||||
cases := []struct {
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{"5511999999999@s.whatsapp.net", "+5511999999999"},
|
||||
{"5511999999999", "+5511999999999"},
|
||||
{"+5511999999999", "+5511999999999"},
|
||||
{"55 11 99999-9999", "+5511999999999"},
|
||||
{"11999999999", "+11999999999"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
got := parser.NormalizePhone(c.raw)
|
||||
if got != c.want {
|
||||
t.Errorf("NormalizePhone(%q) = %q, want %q", c.raw, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user