From ec0353f46930702e21b7a774f81967e989a520e2 Mon Sep 17 00:00:00 2001 From: Leopoldadmin Date: Sat, 4 Jul 2026 00:19:23 +0000 Subject: [PATCH] feat(core): add address fields to contact service serialization and CRUD --- app/services/contact_service.py | 42 +++++++++++++++------------------ 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/app/services/contact_service.py b/app/services/contact_service.py index edefd89..80aef59 100644 --- a/app/services/contact_service.py +++ b/app/services/contact_service.py @@ -14,6 +14,9 @@ from app.models.company import Company from app.models.contact import CompanyContact, Contact +ADDRESS_FIELDS = ("address_street", "address_city", "address_zip", "address_country", "address_state") + + def _contact_to_dict(c: Contact, include_companies: bool = False) -> dict[str, Any]: """Serialize a Contact ORM object to dict.""" data: dict[str, Any] = { @@ -27,6 +30,11 @@ def _contact_to_dict(c: Contact, include_companies: bool = False) -> dict[str, A "department": c.department, "linkedin_url": c.linkedin_url, "notes": c.notes, + "address_street": c.address_street, + "address_city": c.address_city, + "address_zip": c.address_zip, + "address_country": c.address_country, + "address_state": c.address_state, "created_at": c.created_at.isoformat() if c.created_at else None, "updated_at": c.updated_at.isoformat() if c.updated_at else None, } @@ -144,13 +152,17 @@ async def create_contact( department=data.get("department"), linkedin_url=data.get("linkedin_url"), notes=data.get("notes"), + address_street=data.get("address_street"), + address_city=data.get("address_city"), + address_zip=data.get("address_zip"), + address_country=data.get("address_country"), + address_state=data.get("address_state"), created_by=user_id, updated_by=user_id, ) db.add(contact) await db.flush() - # Link to companies if company_ids provided company_ids = data.get("company_ids") linked_companies = [] if company_ids: @@ -159,7 +171,6 @@ async def create_contact( cid = uuid.UUID(cid_str) if isinstance(cid_str, str) else cid_str except (ValueError, TypeError): continue - # Verify company exists in tenant comp_q = select(Company).where( Company.id == cid, Company.tenant_id == tenant_id, @@ -213,17 +224,11 @@ async def update_contact( return None changes: dict[str, Any] = {} - for field in ( - "first_name", - "last_name", - "email", - "phone", - "mobile", - "position", - "department", - "linkedin_url", - "notes", - ): + all_fields = ( + "first_name", "last_name", "email", "phone", "mobile", + "position", "department", "linkedin_url", "notes", + ) + ADDRESS_FIELDS + for field in all_fields: if field in data and data[field] is not None: old_val = getattr(contact, field) changes[field] = {"old": old_val, "new": data[field]} @@ -258,12 +263,7 @@ async def soft_delete_contact( await db.flush() await log_audit( - db, - tenant_id, - user_id, - "delete", - "contact", - contact_id, + db, tenant_id, user_id, "delete", "contact", contact_id, changes={"first_name": contact.first_name, "last_name": contact.last_name}, ) return True @@ -285,10 +285,8 @@ async def gdpr_hard_delete_contact( if contact is None: return False - # Capture snapshot before deletion snapshot = _contact_to_dict(contact) - # Delete N:M links first await db.execute( delete(CompanyContact).where( CompanyContact.contact_id == contact_id, @@ -296,11 +294,9 @@ async def gdpr_hard_delete_contact( ) ) - # Physical delete await db.delete(contact) await db.flush() - # Deletion log (immutable snapshot) await log_deletion( db, tenant_id,