Independent FastAPI backend for Maskan CRM. Owns contacts, organizations, leads, pipelines, activities, products, quotes, users, permissions, audit records and first-party integration credentials, with Alembic migrations against PostgreSQL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
2.2 KiB
Python
84 lines
2.2 KiB
Python
from fastapi.testclient import TestClient
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models import Contact, Tenant
|
|
|
|
|
|
def test_contact_create_search_and_update(
|
|
client: TestClient,
|
|
auth_headers: dict[str, str],
|
|
) -> None:
|
|
created = client.post(
|
|
"/api/v1/contacts",
|
|
headers=auth_headers,
|
|
json={
|
|
"first_name": "Asha",
|
|
"last_name": "Rao",
|
|
"primary_email": "asha@example.com",
|
|
"score": 74,
|
|
"phones": [
|
|
{"label": "work", "value": "+91 90000 12345", "primary": True},
|
|
],
|
|
},
|
|
)
|
|
assert created.status_code == 201, created.text
|
|
contact_id = created.json()["id"]
|
|
assert created.json()["name"] == "Asha Rao"
|
|
|
|
listed = client.get(
|
|
"/api/v1/contacts?search=asha",
|
|
headers=auth_headers,
|
|
)
|
|
assert listed.status_code == 200
|
|
assert listed.json()["total"] == 1
|
|
|
|
updated = client.patch(
|
|
f"/api/v1/contacts/{contact_id}",
|
|
headers=auth_headers,
|
|
json={"lifecycle_stage": "opportunity", "score": 88},
|
|
)
|
|
assert updated.status_code == 200
|
|
assert updated.json()["score"] == 88
|
|
|
|
|
|
def test_duplicate_primary_email_is_rejected(
|
|
client: TestClient,
|
|
auth_headers: dict[str, str],
|
|
) -> None:
|
|
payload = {
|
|
"first_name": "Asha",
|
|
"last_name": "Rao",
|
|
"primary_email": "duplicate@example.com",
|
|
}
|
|
assert client.post("/api/v1/contacts", headers=auth_headers, json=payload).status_code == 201
|
|
duplicate = client.post(
|
|
"/api/v1/contacts",
|
|
headers=auth_headers,
|
|
json={**payload, "first_name": "Another"},
|
|
)
|
|
assert duplicate.status_code == 409
|
|
|
|
|
|
def test_cross_tenant_contact_returns_not_found(
|
|
client: TestClient,
|
|
auth_headers: dict[str, str],
|
|
db: Session,
|
|
) -> None:
|
|
other_tenant = Tenant(slug="other", name="Other Workspace")
|
|
db.add(other_tenant)
|
|
db.flush()
|
|
private_contact = Contact(
|
|
tenant_id=other_tenant.id,
|
|
first_name="Private",
|
|
last_name="Contact",
|
|
)
|
|
db.add(private_contact)
|
|
db.commit()
|
|
|
|
response = client.get(
|
|
f"/api/v1/contacts/{private_contact.id}",
|
|
headers=auth_headers,
|
|
)
|
|
assert response.status_code == 404
|
|
|