Unified contacts model: Rentman-style type field (company/person), inline addresses, ContactPerson 1:N, all Rentman fields except rental-specific
This commit is contained in:
+270
-30
@@ -1,52 +1,291 @@
|
||||
"""Contact schemas — create, update, read, list."""
|
||||
"""Unified contact schemas — create, update, read, list, contactpersons."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ContactCreate(BaseModel):
|
||||
first_name: str = Field(..., min_length=1, max_length=100)
|
||||
last_name: str = Field(..., min_length=1, max_length=100)
|
||||
# ── ContactPerson ──
|
||||
|
||||
class ContactPersonCreate(BaseModel):
|
||||
firstname: str | None = Field(None, max_length=100)
|
||||
middle_name: str | None = Field(None, max_length=100)
|
||||
lastname: str | None = Field(None, max_length=100)
|
||||
function: str | None = Field(None, max_length=255)
|
||||
phone: str | None = Field(None, max_length=50)
|
||||
mobilephone: str | None = Field(None, max_length=50)
|
||||
email: str | None = Field(None, max_length=255)
|
||||
phone: str | None = Field(None, max_length=30)
|
||||
mobile: str | None = Field(None, max_length=30)
|
||||
position: str | None = Field(None, max_length=100)
|
||||
department: str | None = Field(None, max_length=100)
|
||||
linkedin_url: str | None = Field(None, max_length=500)
|
||||
notes: str | None = None
|
||||
company_ids: list[str] | None = None
|
||||
street: str | None = Field(None, max_length=255)
|
||||
number: str | None = Field(None, max_length=20)
|
||||
postalcode: str | None = Field(None, max_length=20)
|
||||
city: str | None = Field(None, max_length=100)
|
||||
state: str | None = Field(None, max_length=100)
|
||||
country: str | None = Field(None, max_length=2)
|
||||
tags: str | None = Field(None, max_length=500)
|
||||
custom: dict | None = None
|
||||
|
||||
|
||||
class ContactPersonUpdate(BaseModel):
|
||||
firstname: str | None = Field(None, max_length=100)
|
||||
middle_name: str | None = Field(None, max_length=100)
|
||||
lastname: str | None = Field(None, max_length=100)
|
||||
function: str | None = Field(None, max_length=255)
|
||||
phone: str | None = Field(None, max_length=50)
|
||||
mobilephone: str | None = Field(None, max_length=50)
|
||||
email: str | None = Field(None, max_length=255)
|
||||
street: str | None = Field(None, max_length=255)
|
||||
number: str | None = Field(None, max_length=20)
|
||||
postalcode: str | None = Field(None, max_length=20)
|
||||
city: str | None = Field(None, max_length=100)
|
||||
state: str | None = Field(None, max_length=100)
|
||||
country: str | None = Field(None, max_length=2)
|
||||
tags: str | None = Field(None, max_length=500)
|
||||
custom: dict | None = None
|
||||
|
||||
|
||||
class ContactPersonResponse(BaseModel):
|
||||
id: str
|
||||
contact_id: str
|
||||
displayname: str
|
||||
firstname: str | None = None
|
||||
middle_name: str | None = None
|
||||
lastname: str | None = None
|
||||
function: str | None = None
|
||||
phone: str | None = None
|
||||
mobilephone: str | None = None
|
||||
email: str | None = None
|
||||
street: str | None = None
|
||||
number: str | None = None
|
||||
postalcode: str | None = None
|
||||
city: str | None = None
|
||||
state: str | None = None
|
||||
country: str | None = None
|
||||
tags: str | None = None
|
||||
custom: dict | None = None
|
||||
created_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
# ── Contact ──
|
||||
|
||||
class ContactCreate(BaseModel):
|
||||
type: str = Field("company", pattern="^(company|person)$")
|
||||
name: str | None = Field(None, max_length=255)
|
||||
firstname: str | None = Field(None, max_length=100)
|
||||
surname: str | None = Field(None, max_length=100)
|
||||
surfix: str | None = Field(None, max_length=50)
|
||||
ext_name_line: str | None = Field(None, max_length=255)
|
||||
gender: str | None = Field(None, max_length=20)
|
||||
code: str | None = Field(None, max_length=100)
|
||||
accounting_code: str | None = Field(None, max_length=100)
|
||||
vendor_accounting_code: str | None = Field(None, max_length=100)
|
||||
# Mailing
|
||||
mailing_street: str | None = Field(None, max_length=255)
|
||||
mailing_number: str | None = Field(None, max_length=20)
|
||||
mailing_unit_number: str | None = Field(None, max_length=50)
|
||||
mailing_district: str | None = Field(None, max_length=100)
|
||||
mailing_extra_address_line: str | None = Field(None, max_length=255)
|
||||
mailing_postalcode: str | None = Field(None, max_length=20)
|
||||
mailing_city: str | None = Field(None, max_length=100)
|
||||
mailing_state: str | None = Field(None, max_length=100)
|
||||
mailing_country: str | None = Field(None, max_length=2)
|
||||
# Visit
|
||||
visit_street: str | None = Field(None, max_length=255)
|
||||
visit_number: str | None = Field(None, max_length=20)
|
||||
visit_unit_number: str | None = Field(None, max_length=50)
|
||||
visit_district: str | None = Field(None, max_length=100)
|
||||
visit_extra_address_line: str | None = Field(None, max_length=255)
|
||||
visit_postalcode: str | None = Field(None, max_length=20)
|
||||
visit_city: str | None = Field(None, max_length=100)
|
||||
visit_state: str | None = Field(None, max_length=100)
|
||||
# Invoice
|
||||
invoice_street: str | None = Field(None, max_length=255)
|
||||
invoice_number: str | None = Field(None, max_length=20)
|
||||
invoice_unit_number: str | None = Field(None, max_length=50)
|
||||
invoice_district: str | None = Field(None, max_length=100)
|
||||
invoice_extra_address_line: str | None = Field(None, max_length=255)
|
||||
invoice_postalcode: str | None = Field(None, max_length=20)
|
||||
invoice_city: str | None = Field(None, max_length=100)
|
||||
invoice_state: str | None = Field(None, max_length=100)
|
||||
invoice_country: str | None = Field(None, max_length=2)
|
||||
# General
|
||||
country: str | None = Field(None, max_length=2)
|
||||
# Communication
|
||||
phone_1: str | None = Field(None, max_length=50)
|
||||
phone_2: str | None = Field(None, max_length=50)
|
||||
email_1: str | None = Field(None, max_length=255)
|
||||
email_2: str | None = Field(None, max_length=255)
|
||||
website: str | None = Field(None, max_length=500)
|
||||
# Financial
|
||||
vat_code: str | None = Field(None, max_length=50)
|
||||
fiscal_code: str | None = Field(None, max_length=50)
|
||||
commerce_code: str | None = Field(None, max_length=100)
|
||||
purchase_number: str | None = Field(None, max_length=100)
|
||||
bic: str | None = Field(None, max_length=50)
|
||||
bank_account: str | None = Field(None, max_length=50)
|
||||
# Discounts
|
||||
discount_crew: float = 0
|
||||
discount_transport: float = 0
|
||||
discount_rental: float = 0
|
||||
discount_sale: float = 0
|
||||
discount_subrent: float = 0
|
||||
discount_total: float = 0
|
||||
# Geo
|
||||
latitude: float | None = None
|
||||
longitude: float | None = None
|
||||
# Notes
|
||||
projectnote: str | None = None
|
||||
projectnote_title: str | None = Field(None, max_length=255)
|
||||
contact_warning: str | None = None
|
||||
tags: str | None = Field(None, max_length=500)
|
||||
image: str | None = None
|
||||
# Custom
|
||||
custom: dict | None = None
|
||||
# Contact persons (optional inline create)
|
||||
contact_persons: list[ContactPersonCreate] | None = None
|
||||
|
||||
|
||||
class ContactUpdate(BaseModel):
|
||||
first_name: str | None = Field(None, min_length=1, max_length=100)
|
||||
last_name: str | None = Field(None, min_length=1, max_length=100)
|
||||
email: str | None = Field(None, max_length=255)
|
||||
phone: str | None = Field(None, max_length=30)
|
||||
mobile: str | None = Field(None, max_length=30)
|
||||
position: str | None = Field(None, max_length=100)
|
||||
department: str | None = Field(None, max_length=100)
|
||||
linkedin_url: str | None = Field(None, max_length=500)
|
||||
notes: str | None = None
|
||||
type: str | None = Field(None, pattern="^(company|person)$")
|
||||
name: str | None = Field(None, max_length=255)
|
||||
firstname: str | None = Field(None, max_length=100)
|
||||
surname: str | None = Field(None, max_length=100)
|
||||
surfix: str | None = Field(None, max_length=50)
|
||||
ext_name_line: str | None = Field(None, max_length=255)
|
||||
gender: str | None = Field(None, max_length=20)
|
||||
code: str | None = Field(None, max_length=100)
|
||||
accounting_code: str | None = Field(None, max_length=100)
|
||||
vendor_accounting_code: str | None = Field(None, max_length=100)
|
||||
mailing_street: str | None = Field(None, max_length=255)
|
||||
mailing_number: str | None = Field(None, max_length=20)
|
||||
mailing_unit_number: str | None = Field(None, max_length=50)
|
||||
mailing_district: str | None = Field(None, max_length=100)
|
||||
mailing_extra_address_line: str | None = Field(None, max_length=255)
|
||||
mailing_postalcode: str | None = Field(None, max_length=20)
|
||||
mailing_city: str | None = Field(None, max_length=100)
|
||||
mailing_state: str | None = Field(None, max_length=100)
|
||||
mailing_country: str | None = Field(None, max_length=2)
|
||||
visit_street: str | None = Field(None, max_length=255)
|
||||
visit_number: str | None = Field(None, max_length=20)
|
||||
visit_unit_number: str | None = Field(None, max_length=50)
|
||||
visit_district: str | None = Field(None, max_length=100)
|
||||
visit_extra_address_line: str | None = Field(None, max_length=255)
|
||||
visit_postalcode: str | None = Field(None, max_length=20)
|
||||
visit_city: str | None = Field(None, max_length=100)
|
||||
visit_state: str | None = Field(None, max_length=100)
|
||||
invoice_street: str | None = Field(None, max_length=255)
|
||||
invoice_number: str | None = Field(None, max_length=20)
|
||||
invoice_unit_number: str | None = Field(None, max_length=50)
|
||||
invoice_district: str | None = Field(None, max_length=100)
|
||||
invoice_extra_address_line: str | None = Field(None, max_length=255)
|
||||
invoice_postalcode: str | None = Field(None, max_length=20)
|
||||
invoice_city: str | None = Field(None, max_length=100)
|
||||
invoice_state: str | None = Field(None, max_length=100)
|
||||
invoice_country: str | None = Field(None, max_length=2)
|
||||
country: str | None = Field(None, max_length=2)
|
||||
phone_1: str | None = Field(None, max_length=50)
|
||||
phone_2: str | None = Field(None, max_length=50)
|
||||
email_1: str | None = Field(None, max_length=255)
|
||||
email_2: str | None = Field(None, max_length=255)
|
||||
website: str | None = Field(None, max_length=500)
|
||||
vat_code: str | None = Field(None, max_length=50)
|
||||
fiscal_code: str | None = Field(None, max_length=50)
|
||||
commerce_code: str | None = Field(None, max_length=100)
|
||||
purchase_number: str | None = Field(None, max_length=100)
|
||||
bic: str | None = Field(None, max_length=50)
|
||||
bank_account: str | None = Field(None, max_length=50)
|
||||
discount_crew: float | None = None
|
||||
discount_transport: float | None = None
|
||||
discount_rental: float | None = None
|
||||
discount_sale: float | None = None
|
||||
discount_subrent: float | None = None
|
||||
discount_total: float | None = None
|
||||
latitude: float | None = None
|
||||
longitude: float | None = None
|
||||
projectnote: str | None = None
|
||||
projectnote_title: str | None = Field(None, max_length=255)
|
||||
contact_warning: str | None = None
|
||||
tags: str | None = Field(None, max_length=500)
|
||||
image: str | None = None
|
||||
custom: dict | None = None
|
||||
default_person_id: str | None = None
|
||||
admin_contactperson_id: str | None = None
|
||||
|
||||
|
||||
class ContactResponse(BaseModel):
|
||||
id: str
|
||||
first_name: str
|
||||
last_name: str
|
||||
email: str | None = None
|
||||
phone: str | None = None
|
||||
mobile: str | None = None
|
||||
position: str | None = None
|
||||
department: str | None = None
|
||||
linkedin_url: str | None = None
|
||||
notes: str | None = None
|
||||
type: str
|
||||
displayname: str
|
||||
name: str | None = None
|
||||
firstname: str | None = None
|
||||
surname: str | None = None
|
||||
surfix: str | None = None
|
||||
ext_name_line: str | None = None
|
||||
gender: str | None = None
|
||||
code: str | None = None
|
||||
accounting_code: str | None = None
|
||||
vendor_accounting_code: str | None = None
|
||||
# Addresses (flat)
|
||||
mailing_street: str | None = None
|
||||
mailing_number: str | None = None
|
||||
mailing_unit_number: str | None = None
|
||||
mailing_district: str | None = None
|
||||
mailing_extra_address_line: str | None = None
|
||||
mailing_postalcode: str | None = None
|
||||
mailing_city: str | None = None
|
||||
mailing_state: str | None = None
|
||||
mailing_country: str | None = None
|
||||
visit_street: str | None = None
|
||||
visit_number: str | None = None
|
||||
visit_unit_number: str | None = None
|
||||
visit_district: str | None = None
|
||||
visit_extra_address_line: str | None = None
|
||||
visit_postalcode: str | None = None
|
||||
visit_city: str | None = None
|
||||
visit_state: str | None = None
|
||||
invoice_street: str | None = None
|
||||
invoice_number: str | None = None
|
||||
invoice_unit_number: str | None = None
|
||||
invoice_district: str | None = None
|
||||
invoice_extra_address_line: str | None = None
|
||||
invoice_postalcode: str | None = None
|
||||
invoice_city: str | None = None
|
||||
invoice_state: str | None = None
|
||||
invoice_country: str | None = None
|
||||
country: str | None = None
|
||||
phone_1: str | None = None
|
||||
phone_2: str | None = None
|
||||
email_1: str | None = None
|
||||
email_2: str | None = None
|
||||
website: str | None = None
|
||||
vat_code: str | None = None
|
||||
fiscal_code: str | None = None
|
||||
commerce_code: str | None = None
|
||||
purchase_number: str | None = None
|
||||
bic: str | None = None
|
||||
bank_account: str | None = None
|
||||
discount_crew: float = 0
|
||||
discount_transport: float = 0
|
||||
discount_rental: float = 0
|
||||
discount_sale: float = 0
|
||||
discount_subrent: float = 0
|
||||
discount_total: float = 0
|
||||
latitude: float | None = None
|
||||
longitude: float | None = None
|
||||
projectnote: str | None = None
|
||||
projectnote_title: str | None = None
|
||||
contact_warning: str | None = None
|
||||
tags: str | None = None
|
||||
image: str | None = None
|
||||
custom: dict | None = None
|
||||
default_person_id: str | None = None
|
||||
admin_contactperson_id: str | None = None
|
||||
created_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
class ContactDetailResponse(ContactResponse):
|
||||
companies: list[dict] = Field(default_factory=list)
|
||||
contact_persons: list[ContactPersonResponse] = Field(default_factory=list)
|
||||
|
||||
|
||||
class ContactListResponse(BaseModel):
|
||||
@@ -56,6 +295,7 @@ class ContactListResponse(BaseModel):
|
||||
page_size: int
|
||||
|
||||
|
||||
# Keep old names for compat
|
||||
class CompanyLinkRequest(BaseModel):
|
||||
role_at_company: str | None = Field(None, max_length=100)
|
||||
is_primary: bool = False
|
||||
|
||||
Reference in New Issue
Block a user