python-casahome 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ """Populated preferences and onboarding responses, plus calendar sync metadata."""
2
+
3
+ from pydantic import JsonValue
4
+
5
+ from casahome.models._base import CasaModel
6
+
7
+
8
+ class SchedulingDay(CasaModel):
9
+ day_of_week: int
10
+ label: str
11
+ enabled: bool
12
+
13
+
14
+ class SchedulingTimeOfDay(CasaModel):
15
+ id: str
16
+ window_title: str
17
+ window_time_range: str
18
+ enabled: bool
19
+
20
+
21
+ class SchedulePreferencesResponse(CasaModel):
22
+ days_of_week: list[SchedulingDay]
23
+ times_of_day: list[SchedulingTimeOfDay]
24
+
25
+
26
+ class NotificationChannel(CasaModel):
27
+ channel: str
28
+ enabled: bool
29
+ default_enabled: bool
30
+ required: bool
31
+
32
+
33
+ class NotificationType(CasaModel):
34
+ key: str
35
+ display_name: str
36
+ description: str
37
+ sort_order: int
38
+ channels: list[NotificationChannel]
39
+
40
+
41
+ class NotificationGroup(CasaModel):
42
+ key: str
43
+ display_name: str
44
+ sort_order: int
45
+ types: list[NotificationType]
46
+
47
+
48
+ class NotificationSettingsResponse(CasaModel):
49
+ groups: list[NotificationGroup]
50
+
51
+
52
+ class OnboardingSlot(CasaModel):
53
+ start_time: int
54
+ vendor_ids: list[str]
55
+
56
+
57
+ class OnboardingAvailabilityResponse(CasaModel):
58
+ message: str
59
+ number_of_required_vendors: int
60
+ estimated_visit_duration_seconds: int
61
+ timezone: str | None = None
62
+ available_slots: list[OnboardingSlot]
63
+
64
+
65
+ class OnboardingEvent(CasaModel):
66
+ id: str
67
+ start_at: int
68
+ end_at: int
69
+
70
+
71
+ class OnboardingDetailsResponse(CasaModel):
72
+ calendar_events: list[OnboardingEvent]
73
+
74
+
75
+ class AccessPreferencesResponse(CasaModel):
76
+ home_id: str
77
+ general_instructions: str | None = None
78
+ package_pickup_method: str | None = None
79
+ package_pickup_spot: str | None = None
80
+ package_pickup_call_home_member_id: str | None = None
81
+ package_pickup_general_instructions: str | None = None
82
+
83
+
84
+ class CalendarOption(CasaModel):
85
+ """UNVERIFIED item. Available/display calendars were empty."""
86
+
87
+ id: str | None = None
88
+ summary: str | None = None
89
+ color: str | None = None
90
+
91
+
92
+ class CalendarSyncResponse(CasaModel):
93
+ home_id: str
94
+ user_oauth_connected: bool
95
+ user_oauth_insufficient_scope: bool
96
+ calendar_sync_active: bool
97
+ has_active_syncs_in_other_homes: bool
98
+ available_calendars: list[CalendarOption]
99
+ display_calendars: list[CalendarOption]
100
+ user_oauth_email: str | None = None
101
+ google_calendar_id: str | None = None
102
+ google_calendar_summary: str | None = None
103
+ sync_status: str | None = None
104
+ sync_progress: JsonValue = None # Only null observed, no static structure.
@@ -0,0 +1,106 @@
1
+ """Read-only purchases. All item lists were empty, item fields are static.
2
+
3
+ Invoice payment structures, pricing summaries, and return info stay opaque JSON.
4
+ No payment or purchase mutation is exposed by these models.
5
+ """
6
+
7
+ from pydantic import JsonValue
8
+
9
+ from casahome.models._base import CasaModel
10
+
11
+
12
+ class PurchaseVendor(CasaModel):
13
+ id: str | None = None
14
+ name: str | None = None
15
+ image_url: str | None = None
16
+ image_url_cache_key: str | None = None
17
+
18
+
19
+ class PurchaseApproval(CasaModel):
20
+ id: str | None = None
21
+ home_id: str | None = None
22
+ title: str | None = None
23
+ image_url: str | None = None
24
+ image_cache_key: str | None = None
25
+ vendor: PurchaseVendor | None = None
26
+ unit_price_usd_cents: int | None = None
27
+ max_approved_unit_price_usd_cents: int | None = None
28
+ quantity: int | None = None
29
+ estimated_shipping_price_usd_cents: int | None = None
30
+ estimated_return_window_days: int | None = None
31
+ return_policy_notes: str | None = None
32
+ purchase_link: str | None = None
33
+ member_pricing_summary: JsonValue = None
34
+ updated_at: int | None = None
35
+
36
+
37
+ class ApprovedPurchase(PurchaseApproval):
38
+ item_id: str | None = None
39
+ approved_at: int | None = None
40
+ is_voided: bool | None = None
41
+
42
+
43
+ class PurchasedItem(CasaModel):
44
+ id: str | None = None
45
+ home_id: str | None = None
46
+ title: str | None = None
47
+ image_url: str | None = None
48
+ image_cache_key: str | None = None
49
+ vendor: PurchaseVendor | None = None
50
+ unit_price_usd_cents: int | None = None
51
+ return_policy_notes: str | None = None
52
+ purchase_link: str | None = None
53
+ updated_at: int | None = None
54
+ quantity: int | None = None
55
+ invoice_id: str | None = None
56
+ return_by_date: int | None = None
57
+ purchased_at: int | None = None
58
+ return_info: JsonValue = None
59
+
60
+
61
+ class PurchaseInvoice(CasaModel):
62
+ """Minimal static SimpleInvoice fields. Non-purchase wire items unobserved."""
63
+
64
+ id: str | None = None
65
+ date: str | None = None
66
+ date_display: str | None = None
67
+ date_epoch_seconds: int | None = None
68
+ amount: float | None = None
69
+ vendor_name: str | None = None
70
+ status: str | None = None
71
+ type: str | None = None
72
+ member_payment: JsonValue = None
73
+ vendor_payment: JsonValue = None
74
+
75
+
76
+ class PurchasesResponse(CasaModel):
77
+ context_title: str | None = None
78
+ pending_purchase_approvals: list[PurchaseApproval]
79
+ approved_purchases: list[ApprovedPurchase]
80
+ purchased_items: list[PurchasedItem]
81
+ non_purchase_invoices: list[PurchaseInvoice]
82
+ next_package_pickup_by: int | None = None
83
+
84
+
85
+ class ScopedPurchasesResponse(CasaModel):
86
+ """Provisional request/visit linkage to PurchasesResponse (static only).
87
+
88
+ Unlike the observed home response, the app model doesn't require
89
+ non_purchase_invoices. Unknown additions still survive as model_extra.
90
+ Scoped route envelopes and populated items remain UNVERIFIED.
91
+ """
92
+
93
+ context_title: str | None = None
94
+ pending_purchase_approvals: list[PurchaseApproval]
95
+ approved_purchases: list[ApprovedPurchase]
96
+ purchased_items: list[PurchasedItem]
97
+ next_package_pickup_by: int | None = None
98
+
99
+
100
+ class RequestPurchase(CasaModel):
101
+ """Static preview within visit detail."""
102
+
103
+ id: str
104
+ image_url: str | None = None
105
+ image_cache_key: str | None = None
106
+ status: str
@@ -0,0 +1,22 @@
1
+ """Typed read envelopes without changing the existing create_todo return model."""
2
+
3
+ from pydantic import Field
4
+
5
+ from casahome.models._base import CasaModel
6
+ from casahome.models.images import MediaAttachment
7
+ from casahome.models.todos import TodoDetail
8
+
9
+
10
+ class TodoReadDetail(TodoDetail):
11
+ """Populated core fields and attachments observed. Other nested fields static."""
12
+
13
+ flagged_for_support: bool = False
14
+ attachments: list[MediaAttachment] = Field(default_factory=list)
15
+
16
+
17
+ class TodoDetailsResponse(CasaModel):
18
+ todo: TodoReadDetail
19
+
20
+
21
+ class SuggestedTodosResponse(CasaModel):
22
+ suggested_todos: list[TodoReadDetail]
@@ -0,0 +1,21 @@
1
+ """Member referral code, ``/protected/member/referral_code/v2``.
2
+
3
+ The envelope and top-level ``referral_code`` keys were VERIFIED by a live
4
+ GET (2026-10). Display keys and referred-home item shapes aren't pinned, so
5
+ they stay ``JsonValue``. Unknown fields ride along in ``model_extra``.
6
+ """
7
+
8
+ from pydantic import JsonValue
9
+
10
+ from casahome.models._base import CasaModel
11
+
12
+
13
+ class ReferralCode(CasaModel):
14
+ code: str
15
+ referral_url: str
16
+ display: dict[str, JsonValue]
17
+ referred_homes: list[JsonValue]
18
+
19
+
20
+ class ReferralCodeResponse(CasaModel):
21
+ referral_code: ReferralCode
@@ -0,0 +1,149 @@
1
+ """Requests tab, request threads, and vendor visit models (UNVERIFIED endpoints)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime
6
+ from typing import Any
7
+
8
+ from pydantic import Field
9
+
10
+ from ._base import CasaModel, epoch_to_dt
11
+ from .enums import (
12
+ RequestStatusField,
13
+ RequestTypeField,
14
+ SenderRoleField,
15
+ VendorVisitStatusField,
16
+ VisitTypeField,
17
+ )
18
+ from .todos import TodoLaneCard
19
+
20
+
21
+ class Pagination(CasaModel):
22
+ page: int
23
+ page_size: int
24
+ total_count: int
25
+ total_pages: int
26
+
27
+
28
+ class RequestCard(CasaModel):
29
+ id: str
30
+ type: RequestTypeField
31
+ title: str
32
+ emoji: str
33
+ updated_at: int
34
+ latest_message_preview: str | None = None
35
+ has_unread_messages: bool = False
36
+ pending_invoice_count: int = 0
37
+ pending_purchase_count: int = 0
38
+ pending_schedule_prompt_count: int = 0
39
+ concierge_awaiting_reply: bool = False
40
+ vendor_visits: list[Any] = Field(default_factory=list)
41
+
42
+ @property
43
+ def updated_at_dt(self) -> datetime | None:
44
+ return epoch_to_dt(self.updated_at)
45
+
46
+
47
+ class RequestsSectionPresentation(CasaModel):
48
+ title: str
49
+ symbol: str | None = None
50
+
51
+
52
+ class RequestsLaneSection(CasaModel):
53
+ name: str
54
+ title: str
55
+ symbol: str | None = None
56
+ count: int | None = None
57
+ items: list[RequestCard] = Field(default_factory=list)
58
+
59
+
60
+ class RequestsLane(CasaModel):
61
+ needs_review: list[RequestCard] = Field(default_factory=list)
62
+ completed: RequestsSectionPresentation | None = None
63
+ completed_count: int = 0
64
+ sections: list[RequestsLaneSection] = Field(default_factory=list)
65
+
66
+
67
+ class TasksLaneSection(CasaModel):
68
+ name: str
69
+ title: str
70
+ symbol: str | None = None
71
+ count: int | None = None
72
+ items: list[Any] = Field(default_factory=list) # TaskCard, not yet modeled
73
+
74
+
75
+ class TasksLane(CasaModel):
76
+ sections: list[TasksLaneSection] = Field(default_factory=list)
77
+
78
+
79
+ class TodosLaneSection(CasaModel):
80
+ name: str
81
+ title: str
82
+ items: list[TodoLaneCard] = Field(default_factory=list)
83
+ order_revision: int | None = None
84
+
85
+
86
+ class TodosLane(CasaModel):
87
+ sections: list[TodosLaneSection] = Field(default_factory=list)
88
+
89
+
90
+ class RequestsResponse(CasaModel):
91
+ requests: RequestsLane
92
+ tasks: TasksLane
93
+ todos: TodosLane | None = None
94
+
95
+
96
+ class RequestMessage(CasaModel):
97
+ id: str
98
+ created_at: int
99
+ sender_role: SenderRoleField
100
+ sender_name: str
101
+ content: str | None = None
102
+ attachments: list[Any] = Field(default_factory=list)
103
+ scheduling_prompt: Any | None = None
104
+ availability_request: Any | None = None
105
+ invoice: Any | None = None
106
+ purchase_approval_requests: list[Any] | None = None
107
+
108
+ @property
109
+ def created_at_dt(self) -> datetime | None:
110
+ return epoch_to_dt(self.created_at)
111
+
112
+
113
+ class RequestDetails(CasaModel):
114
+ id: str
115
+ type: RequestTypeField
116
+ status: RequestStatusField
117
+ title: str
118
+ emoji: str
119
+ created_at: int
120
+ updated_at: int
121
+ has_unread_messages: bool = False
122
+ summary: dict[str, Any] = Field(default_factory=dict)
123
+ messages: list[RequestMessage] = Field(default_factory=list)
124
+ visits: list[Any] = Field(default_factory=list)
125
+ invoices: list[Any] = Field(default_factory=list)
126
+ purchases: list[Any] = Field(default_factory=list)
127
+ feedback: Any | None = None
128
+
129
+
130
+ class VendorVisitCalendarEvent(CasaModel):
131
+ id: str
132
+ start_time: int
133
+ end_time: int
134
+
135
+
136
+ class VendorVisit(CasaModel):
137
+ id: str
138
+ type: VisitTypeField
139
+ status: VendorVisitStatusField
140
+ request: dict[str, Any] = Field(default_factory=dict)
141
+ calendar_event: VendorVisitCalendarEvent | None = None
142
+ vendors: list[Any] = Field(default_factory=list)
143
+ task_items: list[Any] = Field(default_factory=list)
144
+ invoices: list[Any] = Field(default_factory=list)
145
+ purchases: list[Any] = Field(default_factory=list)
146
+ can_add_remove_items: bool = False
147
+ can_cancel: bool = False
148
+ feedback: Any | None = None
149
+ conversation: Any | None = None
@@ -0,0 +1,77 @@
1
+ """Static task detail and grouped visit-plan fields remain UNVERIFIED.
2
+
3
+ Fields inferred from the app. GroupedTaskDetails.tasks uses GroupedTaskItem.
4
+ Bookable's envelope was observed live, but tagged items remain JsonValue.
5
+ Swift case names aren't wire tags.
6
+ """
7
+
8
+ from pydantic import JsonValue
9
+
10
+ from casahome.models._base import CasaModel
11
+ from casahome.models.images import MediaAttachment
12
+
13
+
14
+ class BookableHandymanTasksResponse(CasaModel):
15
+ items: list[JsonValue]
16
+ current_vendor_additional_availability_minutes: int | None = None
17
+ total_additional_availability_minutes: int | None = None
18
+
19
+
20
+ class TaskDetailsVisit(CasaModel):
21
+ id: str
22
+ start_time: int
23
+
24
+
25
+ class TaskUpdate(CasaModel):
26
+ id: str
27
+ message: str
28
+ sender_name: str
29
+ sender_avatar_url: str | None = None
30
+ sender_avatar_cache_key: str | None = None
31
+ sent_at: int
32
+ attachments: list[MediaAttachment] | None = None
33
+
34
+
35
+ class TaskDetails(CasaModel):
36
+ id: str
37
+ title: str
38
+ description: str
39
+ emoji: str
40
+ status: str
41
+ visit: TaskDetailsVisit | None = None
42
+ updates: list[TaskUpdate]
43
+ attachments: list[MediaAttachment] | None = None
44
+ can_schedule_handyman_vendor_visit: bool
45
+ can_chat_with_concierge: bool
46
+ can_edit: bool
47
+ can_delete: bool
48
+
49
+
50
+ class VendorVisitAutopilotPlan(CasaModel):
51
+ id: str
52
+ title: str
53
+ description: str
54
+ emoji: str
55
+
56
+
57
+ class VendorVisitAutopilotTaskTarget(CasaModel):
58
+ id: str
59
+ kind: str
60
+ primary_label: str
61
+ secondary_label: str
62
+ symbol_name: str
63
+ image_url: str | None = None
64
+ image_cache_key: str | None = None
65
+
66
+
67
+ class GroupedTaskItem(CasaModel):
68
+ id: str
69
+ status: str
70
+ target: VendorVisitAutopilotTaskTarget | None = None
71
+ updates: list[TaskUpdate]
72
+
73
+
74
+ class GroupedTaskDetails(CasaModel):
75
+ plan: VendorVisitAutopilotPlan
76
+ visit: TaskDetailsVisit | None = None
77
+ tasks: list[GroupedTaskItem]
@@ -0,0 +1,47 @@
1
+ """Property tax reads. Only refresh metadata and an empty reports list observed."""
2
+
3
+ from pydantic import Field
4
+
5
+ from casahome.models._base import CasaModel
6
+
7
+
8
+ class PropertyTaxRefresh(CasaModel):
9
+ status: str
10
+ next_fetch_at: int | None = None
11
+
12
+
13
+ class PropertyTaxSpecialAssessment(CasaModel):
14
+ id: str | None = None
15
+ name: str | None = None
16
+ amount: float | None = None
17
+
18
+
19
+ class PropertyTaxInstallment(CasaModel):
20
+ id: str | None = None
21
+ total: float | None = None
22
+ due_date: int | None = None
23
+ payment_amount: float | None = None
24
+ payment_date: int | None = None
25
+
26
+
27
+ class PropertyTaxReport(CasaModel):
28
+ id: str | None = None
29
+ report_id: str | None = None
30
+ issued_at: int | None = None
31
+ agency_name: str | None = None
32
+ tax_collector_url: str | None = None
33
+ tax_year_start: int | None = None
34
+ tax_year_end: int | None = None
35
+ land_value: float | None = None
36
+ improvement_value: float | None = None
37
+ total_assessed_value: float | None = None
38
+ total_taxable_value: float | None = None
39
+ total_tax_due: float | None = None
40
+ special_assessments: list[PropertyTaxSpecialAssessment] = Field(default_factory=list)
41
+ installments: list[PropertyTaxInstallment] = Field(default_factory=list)
42
+
43
+
44
+ class PropertyTaxesResponse(CasaModel):
45
+ next_tax_bill_release_at: int | None = None
46
+ refresh: PropertyTaxRefresh | None = None
47
+ reports: list[PropertyTaxReport]
@@ -0,0 +1,52 @@
1
+ """To-do models (UNVERIFIED endpoints)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from pydantic import Field
8
+
9
+ from ._base import CasaModel
10
+ from .enums import (
11
+ TodoCreatorRoleField,
12
+ TodoLaneCardKindField,
13
+ TodoLaneCardStateField,
14
+ TodoStatusField,
15
+ )
16
+
17
+
18
+ class AttachMediaPayload(CasaModel):
19
+ upload_ids: list[str] = Field(default_factory=list)
20
+
21
+
22
+ class CreateTodoBody(CasaModel):
23
+ content: str
24
+ attachments: AttachMediaPayload | None = None
25
+
26
+
27
+ class TodoLaneCard(CasaModel):
28
+ kind: TodoLaneCardKindField
29
+ id: str
30
+ title: str
31
+ emoji: str
32
+ updated_at: int
33
+ state: TodoLaneCardStateField
34
+ origin_todo_id: str | None = None
35
+ can_delete: bool = False
36
+
37
+
38
+ class TodoDetail(CasaModel):
39
+ id: str
40
+ title: str
41
+ emoji: str
42
+ original_text: str
43
+ prepared_brief: str
44
+ status: TodoStatusField
45
+ creator_role: TodoCreatorRoleField
46
+ created_at: int
47
+ updated_at: int
48
+ can_delete: bool = False
49
+ is_suggested: bool = False
50
+ attachments: list[Any] = Field(default_factory=list)
51
+ question_rounds: list[Any] = Field(default_factory=list)
52
+ destination: Any | None = None