|
21 | 21 | class BudgetUsageManager(BaseManager):
|
22 | 22 | def __init__(self, *args, **kwargs):
|
23 | 23 | super().__init__(*args, **kwargs)
|
| 24 | + |
24 | 25 | self.budget_mgr = BudgetManager()
|
25 |
| - self.notification_mgr: NotificationManager = self.locator.get_manager( |
26 |
| - "NotificationManager" |
27 |
| - ) |
| 26 | + self.notification_mgr = NotificationManager() |
28 | 27 | self.email_mgr = None
|
| 28 | + |
29 | 29 | self.budget_usage_model = BudgetUsage
|
30 | 30 |
|
31 | 31 | def create_budget_usages(self, budget_vo: Budget) -> None:
|
@@ -113,95 +113,98 @@ def notify_budget_usage(self, budget_vo: Budget) -> None:
|
113 | 113 | plans = notification.plans or []
|
114 | 114 |
|
115 | 115 | for plan in plans:
|
116 |
| - if current_month not in budget_vo.notified_months: |
117 |
| - unit = plan.unit |
118 |
| - threshold = plan.threshold |
119 |
| - is_notify = False |
120 |
| - |
121 |
| - if budget_vo.time_unit == "TOTAL": |
122 |
| - budget_usage_vos = self.filter_budget_usages( |
123 |
| - budget_id=budget_id, |
124 |
| - workspace_id=workspace_id, |
125 |
| - domain_id=domain_id, |
126 |
| - ) |
127 |
| - total_budget_usage = sum( |
128 |
| - [budget_usage_vo.cost for budget_usage_vo in budget_usage_vos] |
129 |
| - ) |
130 |
| - budget_limit = budget_vo.limit |
131 |
| - else: |
132 |
| - budget_usage_vos = self.filter_budget_usages( |
133 |
| - budget_id=budget_id, |
134 |
| - workspace_id=workspace_id, |
135 |
| - domain_id=domain_id, |
136 |
| - date=current_month, |
137 |
| - ) |
138 | 116 |
|
139 |
| - if budget_usage_vos.count() == 0: |
140 |
| - _LOGGER.debug( |
141 |
| - f"[notify_budget_usage] budget_usage_vos is empty: {budget_id}" |
142 |
| - ) |
143 |
| - continue |
| 117 | + if plan.notified: |
| 118 | + _LOGGER.debug( |
| 119 | + f"[notify_budget_usage] skip notification: already notified {budget_id} (usage percent: {plan.threshold}%, threshold: {plan.threshold}%)" |
| 120 | + ) |
| 121 | + continue |
| 122 | + |
| 123 | + unit = plan.unit |
| 124 | + threshold = plan.threshold |
| 125 | + is_notify = False |
144 | 126 |
|
145 |
| - total_budget_usage = budget_usage_vos[0].cost |
146 |
| - budget_limit = budget_usage_vos[0].limit |
| 127 | + if budget_vo.time_unit == "TOTAL": |
| 128 | + |
| 129 | + budget_usage_vos = self.filter_budget_usages( |
| 130 | + budget_id=budget_id, |
| 131 | + workspace_id=workspace_id, |
| 132 | + domain_id=domain_id, |
| 133 | + ) |
| 134 | + total_budget_usage = sum( |
| 135 | + [budget_usage_vo.cost for budget_usage_vo in budget_usage_vos] |
| 136 | + ) |
| 137 | + budget_limit = budget_vo.limit |
| 138 | + else: |
| 139 | + budget_usage_vos = self.filter_budget_usages( |
| 140 | + budget_id=budget_id, |
| 141 | + workspace_id=workspace_id, |
| 142 | + domain_id=domain_id, |
| 143 | + date=current_month, |
| 144 | + ) |
147 | 145 |
|
148 |
| - if budget_limit == 0: |
| 146 | + if budget_usage_vos.count() == 0: |
149 | 147 | _LOGGER.debug(
|
150 |
| - f"[notify_budget_usage] budget_limit is 0: {budget_id}" |
| 148 | + f"[notify_budget_usage] budget_usage_vos is empty: {budget_id}" |
151 | 149 | )
|
152 | 150 | continue
|
153 | 151 |
|
154 |
| - budget_percentage = round(total_budget_usage / budget_limit * 100, 2) |
| 152 | + total_budget_usage = budget_usage_vos[0].cost |
| 153 | + budget_limit = budget_usage_vos[0].limit |
155 | 154 |
|
| 155 | + if budget_limit == 0: |
| 156 | + _LOGGER.debug(f"[notify_budget_usage] budget_limit is 0: {budget_id}") |
| 157 | + continue |
| 158 | + |
| 159 | + budget_percentage = budget_vo.utilization_rate |
| 160 | + |
| 161 | + if unit == "PERCENT": |
| 162 | + if budget_percentage > threshold: |
| 163 | + is_notify = True |
| 164 | + is_changed = True |
| 165 | + if is_notify: |
| 166 | + _LOGGER.debug( |
| 167 | + f"[notify_budget_usage] notify event: {budget_id}, current month: {current_month} (plan: {plan.to_dict()})" |
| 168 | + ) |
| 169 | + |
| 170 | + try: |
| 171 | + self._notify_message( |
| 172 | + budget_vo, |
| 173 | + total_budget_usage, |
| 174 | + budget_percentage, |
| 175 | + threshold, |
| 176 | + ) |
| 177 | + |
| 178 | + updated_plans.append( |
| 179 | + { |
| 180 | + "threshold": threshold, |
| 181 | + "unit": unit, |
| 182 | + "notified": True, |
| 183 | + } |
| 184 | + ) |
| 185 | + |
| 186 | + except Exception as e: |
| 187 | + _LOGGER.error( |
| 188 | + f"[notify_budget_usage] Failed to notify message ({budget_id}): {e}", |
| 189 | + exc_info=True, |
| 190 | + ) |
| 191 | + else: |
156 | 192 | if unit == "PERCENT":
|
157 |
| - if budget_percentage > threshold: |
158 |
| - is_notify = True |
159 |
| - is_changed = True |
160 |
| - if is_notify: |
161 | 193 | _LOGGER.debug(
|
162 |
| - f"[notify_budget_usage] notify event: {budget_id}, current month: {current_month} (plan: {plan.to_dict()})" |
| 194 | + f"[notify_budget_usage] skip notification: {budget_id} " |
| 195 | + f"(usage percent: {budget_percentage}%, threshold: {threshold}%)" |
163 | 196 | )
|
164 |
| - try: |
165 |
| - self._notify_message( |
166 |
| - budget_vo, |
167 |
| - total_budget_usage, |
168 |
| - budget_percentage, |
169 |
| - threshold, |
170 |
| - ) |
171 |
| - |
172 |
| - updated_plans.append( |
173 |
| - { |
174 |
| - "threshold": threshold, |
175 |
| - "unit": unit, |
176 |
| - "notified_months": plan.notified_months |
177 |
| - + [current_month], |
178 |
| - } |
179 |
| - ) |
180 |
| - except Exception as e: |
181 |
| - _LOGGER.error( |
182 |
| - f"[notify_budget_usage] Failed to notify message ({budget_id}): {e}", |
183 |
| - exc_info=True, |
184 |
| - ) |
185 | 197 | else:
|
186 |
| - if unit == "PERCENT": |
187 |
| - _LOGGER.debug( |
188 |
| - f"[notify_budget_usage] skip notification: {budget_id} " |
189 |
| - f"(usage percent: {budget_percentage}%, threshold: {threshold}%)" |
190 |
| - ) |
191 |
| - else: |
192 |
| - _LOGGER.debug( |
193 |
| - f"[notify_budget_usage] skip notification: {budget_id} " |
194 |
| - f"(usage cost: {total_budget_usage}, threshold: {threshold})" |
195 |
| - ) |
196 |
| - |
197 |
| - updated_plans.append(plan.to_dict()) |
| 198 | + _LOGGER.debug( |
| 199 | + f"[notify_budget_usage] skip notification: {budget_id} " |
| 200 | + f"(usage cost: {total_budget_usage}, threshold: {threshold})" |
| 201 | + ) |
198 | 202 |
|
199 |
| - else: |
200 | 203 | updated_plans.append(plan.to_dict())
|
201 | 204 |
|
202 | 205 | if is_changed:
|
203 | 206 | notification.plans = updated_plans
|
204 |
| - budget_vo.update({"notifications": notification.to_dict()}) |
| 207 | + budget_vo.update({"notification": notification.to_dict()}) |
205 | 208 |
|
206 | 209 | def delete_budget_usage_by_budget_vo(self, budget_vo: Budget) -> None:
|
207 | 210 | budget_usage_vos = self.filter_budget_usages(
|
@@ -324,15 +327,15 @@ def _update_monthly_budget_usage(
|
324 | 327 | budget_usage_vo.update({"cost": 0})
|
325 | 328 |
|
326 | 329 | if budget_vo.time_unit == "TOTAL":
|
327 |
| - budget_utilization_rate = total_usage_cost / budget_vo.limit * 100 |
| 330 | + budget_utilization_rate = round(total_usage_cost / budget_vo.limit * 100, 2) |
328 | 331 | self.budget_mgr.update_budget_by_vo(
|
329 | 332 | {"utilization_rate": budget_utilization_rate}, budget_vo
|
330 | 333 | )
|
331 | 334 | else:
|
332 | 335 | for budget_usage_vo in budget_usage_vos:
|
333 | 336 | if budget_usage_vo.date == current_month:
|
334 |
| - budget_utilization_rate = ( |
335 |
| - budget_usage_vo.cost / budget_usage_vo.limit * 100 |
| 337 | + budget_utilization_rate = round( |
| 338 | + budget_usage_vo.cost / budget_usage_vo.limit * 100, 2 |
336 | 339 | )
|
337 | 340 | self.budget_mgr.update_budget_by_vo(
|
338 | 341 | {"utilization_rate": budget_utilization_rate}, budget_vo
|
|
0 commit comments