-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathservices.py
More file actions
235 lines (182 loc) · 8.08 KB
/
services.py
File metadata and controls
235 lines (182 loc) · 8.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
"""
Services for the Gatherings application.
This module provides high-level services for managing gatherings and their members.
"""
from typing import Dict, List, Tuple, Optional, Any
from models import DatabaseManager, Gathering, Member
class GatheringService:
"""Service for managing gatherings and their members."""
def __init__(self, db_manager: DatabaseManager):
"""Initialize the GatheringService with a DatabaseManager."""
self.db_manager = db_manager
def create_gathering(self, gathering_id: str, total_members: int) -> Gathering:
"""Creates a new gathering with the specified number of members."""
gathering = self.db_manager.create_gathering(gathering_id, total_members)
return gathering
def get_gathering(self, gathering_id: str) -> Optional[Gathering]:
"""
Get a gathering by ID.
Args:
gathering_id: The ID of the gathering
Returns:
The Gathering object, or None if not found
"""
return self.db_manager.get_gathering(gathering_id)
def add_expense(self, gathering_id: str, member_name: str, amount: float) -> Tuple[Gathering, Member]:
"""
Add an expense for a member in a gathering.
Args:
gathering_id: The ID of the gathering
member_name: The name of the member (can be auto-generated)
amount: The expense amount (positive number)
Returns:
Tuple of (updated Gathering, Member who paid)
Raises:
ValueError: If the gathering is closed, the member doesn't exist, or the amount is invalid
"""
return self.db_manager.add_expense(gathering_id, member_name, amount)
def calculate_reimbursements(self, gathering_id: str) -> Dict[str, float]:
"""
Calculate reimbursements for a gathering.
Args:
gathering_id: The ID of the gathering
Returns:
A dictionary mapping member names to reimbursement amounts
(negative values mean the member gets reimbursed, positive values mean they owe money)
Raises:
ValueError: If the gathering doesn't exist
"""
gathering = self.get_gathering(gathering_id)
if not gathering:
raise ValueError(f"Gathering '{gathering_id}' not found")
# Calculate how much each member has paid and should pay
expense_per_member = gathering.expense_per_member
# Calculate reimbursements
reimbursements = {}
for member in gathering.members:
# Amount to pay = total share - expenses + payments
# If negative, member gets reimbursed; if positive, member owes money
to_pay = expense_per_member - member.total_expenses + member.total_payments
reimbursements[member.name] = to_pay
return reimbursements
def record_payment(self, gathering_id: str, member_name: str, amount: float) -> Tuple[Gathering, Member]:
"""
Record a payment made by a member.
Args:
gathering_id: The ID of the gathering
member_name: The name of the member
amount: The payment amount (positive for payments, negative for reimbursements)
Returns:
Tuple of (updated Gathering, Member who paid/received)
Raises:
ValueError: If the gathering is closed, the member doesn't exist, or the payment is invalid
"""
return self.db_manager.record_payment(gathering_id, member_name, amount)
def rename_member(self, gathering_id: str, old_name: str, new_name: str) -> Member:
"""
Rename a member in a gathering.
Args:
gathering_id: The ID of the gathering
old_name: The current name of the member
new_name: The new name for the member
Returns:
The updated Member object
Raises:
ValueError: If the gathering is closed, the member doesn't exist, or the new name is already taken
"""
return self.db_manager.rename_member(gathering_id, old_name, new_name)
def close_gathering(self, gathering_id: str) -> Gathering:
"""
Close a gathering.
Args:
gathering_id: The ID of the gathering
Returns:
The updated Gathering object
Raises:
ValueError: If the gathering doesn't exist or is already closed
"""
return self.db_manager.close_gathering(gathering_id)
def delete_gathering(self, gathering_id: str, force: bool = False) -> None:
"""
Delete a gathering and all related data.
Args:
gathering_id: The ID of the gathering
force: If True, delete even if the gathering is closed
Raises:
ValueError: If the gathering doesn't exist or is closed and force is False
"""
return self.db_manager.delete_gathering(gathering_id, force)
def list_gatherings(self) -> List[Gathering]:
"""
List all gatherings.
Returns:
A list of all Gathering objects
"""
return self.db_manager.list_gatherings()
def get_payment_summary(self, gathering_id: str) -> Dict[str, Any]:
"""
Get a detailed payment summary for a gathering.
Args:
gathering_id: The ID of the gathering
Returns:
A dictionary with summary information:
{
'total_expenses': float,
'expense_per_member': float,
'members': {
'member1': {
'expenses': float,
'paid': float,
'balance': float,
'status': str
},
...
}
}
Raises:
ValueError: If the gathering doesn't exist
"""
gathering = self.get_gathering(gathering_id)
if not gathering:
raise ValueError(f"Gathering '{gathering_id}' not found")
summary = {
'total_expenses': gathering.total_expenses,
'expense_per_member': gathering.expense_per_member,
'members': {}
}
for member in gathering.members:
summary['members'][member.name] = {
'expenses': member.total_expenses,
'paid': member.total_payments,
'balance': member.balance,
'status': member.status
}
return summary
def add_member(self, gathering_id: str, member_name: str) -> Tuple[Gathering, Member]:
"""
Add a new member to an existing gathering.
Args:
gathering_id: The ID of the gathering
member_name: The name of the member to add
Returns:
Tuple of (updated Gathering, added Member)
Raises:
ValueError: If the gathering is closed, doesn't exist, or member already exists
"""
member = self.db_manager.add_member(gathering_id, member_name)
gathering = self.get_gathering(gathering_id)
return gathering, member
def remove_member(self, gathering_id: str, member_name: str) -> Gathering:
"""
Remove a member from a gathering.
Args:
gathering_id: The ID of the gathering
member_name: The name of the member to remove
Returns:
The updated Gathering object
Raises:
ValueError: If the gathering is closed, doesn't exist, the member doesn't exist,
or the member has expenses/payments
"""
self.db_manager.remove_member(gathering_id, member_name)
return self.get_gathering(gathering_id)