|
2 | 2 |
|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | | -from collections.abc import Iterable |
| 5 | +from collections.abc import Callable, Iterable |
6 | 6 | from datetime import date, datetime |
7 | 7 | from pathlib import Path |
8 | 8 | from types import TracebackType |
@@ -82,6 +82,16 @@ def _summary_unavailable_section(section: str, error: AvitoError) -> SummaryUnav |
82 | 82 | ) |
83 | 83 |
|
84 | 84 |
|
| 85 | +def _safe_summary[SummaryT]( |
| 86 | + section: str, |
| 87 | + factory: Callable[[], SummaryT], |
| 88 | +) -> tuple[SummaryT | None, list[SummaryUnavailableSection]]: |
| 89 | + try: |
| 90 | + return factory(), [] |
| 91 | + except AvitoError as error: |
| 92 | + return None, [_summary_unavailable_section(section, error)] |
| 93 | + |
| 94 | + |
85 | 95 | class AvitoClient: |
86 | 96 | """Единственная публичная точка входа SDK с фабриками доменных объектов. |
87 | 97 |
|
@@ -189,18 +199,43 @@ def account_health( |
189 | 199 | date_from=date_from, |
190 | 200 | date_to=date_to, |
191 | 201 | ) |
| 202 | + item_ids = [item.item_id for item in listings.items if item.item_id is not None] |
| 203 | + chats, chats_unavailable = _safe_summary( |
| 204 | + "chats", |
| 205 | + lambda: self.chat_summary(user_id=resolved_user_id), |
| 206 | + ) |
| 207 | + orders, orders_unavailable = _safe_summary("orders", self.order_summary) |
| 208 | + reviews, reviews_unavailable = _safe_summary("reviews", self.review_summary) |
| 209 | + promotion, promotion_unavailable = _safe_summary( |
| 210 | + "promotion", |
| 211 | + lambda: self.promotion_summary(item_ids=item_ids), |
| 212 | + ) |
| 213 | + unavailable_sections = [ |
| 214 | + *listings.unavailable_sections, |
| 215 | + *chats_unavailable, |
| 216 | + *orders_unavailable, |
| 217 | + *reviews_unavailable, |
| 218 | + *promotion_unavailable, |
| 219 | + ] |
| 220 | + if chats is not None: |
| 221 | + unavailable_sections.extend(chats.unavailable_sections) |
| 222 | + if orders is not None: |
| 223 | + unavailable_sections.extend(orders.unavailable_sections) |
| 224 | + if reviews is not None: |
| 225 | + unavailable_sections.extend(reviews.unavailable_sections) |
| 226 | + if promotion is not None: |
| 227 | + unavailable_sections.extend(promotion.unavailable_sections) |
192 | 228 | return AccountHealthSummary( |
193 | 229 | user_id=resolved_user_id, |
194 | 230 | balance_total=balance.total, |
195 | 231 | balance_real=balance.real, |
196 | 232 | balance_bonus=balance.bonus, |
197 | 233 | listings=listings, |
198 | | - chats=self.chat_summary(user_id=resolved_user_id), |
199 | | - orders=self.order_summary(), |
200 | | - reviews=self.review_summary(), |
201 | | - promotion=self.promotion_summary( |
202 | | - item_ids=[item.item_id for item in listings.items if item.item_id is not None] |
203 | | - ), |
| 234 | + chats=chats, |
| 235 | + orders=orders, |
| 236 | + reviews=reviews, |
| 237 | + promotion=promotion, |
| 238 | + unavailable_sections=unavailable_sections, |
204 | 239 | ) |
205 | 240 |
|
206 | 241 | def listing_health( |
@@ -322,15 +357,36 @@ def order_summary(self) -> OrderSummary: |
322 | 357 | def review_summary(self) -> ReviewSummary: |
323 | 358 | """Возвращает итоговую read-only сводку по отзывам.""" |
324 | 359 |
|
325 | | - reviews = self.review().list() |
| 360 | + reviews_error: AvitoError | None = None |
| 361 | + try: |
| 362 | + reviews = self.review().list() |
| 363 | + except AvitoError as error: |
| 364 | + reviews = None |
| 365 | + reviews_error = error |
326 | 366 | rating = self.rating_profile().get() |
327 | | - scores = [item.score for item in reviews.items if item.score is not None] |
| 367 | + scores = [item.score for item in reviews.items if item.score is not None] if reviews else [] |
328 | 368 | average_score = sum(scores) / len(scores) if scores else None |
| 369 | + unavailable_sections = ( |
| 370 | + [_summary_unavailable_section("reviews", reviews_error)] |
| 371 | + if reviews_error is not None |
| 372 | + else [] |
| 373 | + ) |
329 | 374 | return ReviewSummary( |
330 | | - total_reviews=reviews.total if reviews.total is not None else len(reviews.items), |
331 | | - average_score=average_score, |
332 | | - unanswered_reviews=sum(1 for item in reviews.items if item.can_answer is True), |
| 375 | + total_reviews=( |
| 376 | + reviews.total |
| 377 | + if reviews is not None and reviews.total is not None |
| 378 | + else rating.reviews_count |
| 379 | + if reviews is None |
| 380 | + else len(reviews.items) |
| 381 | + ), |
| 382 | + average_score=average_score if reviews is not None else rating.score, |
| 383 | + unanswered_reviews=( |
| 384 | + sum(1 for item in reviews.items if item.can_answer is True) |
| 385 | + if reviews is not None |
| 386 | + else None |
| 387 | + ), |
333 | 388 | rating_score=rating.score, |
| 389 | + unavailable_sections=unavailable_sections, |
334 | 390 | ) |
335 | 391 |
|
336 | 392 | def promotion_summary(self, *, item_ids: list[int] | None = None) -> PromotionSummary: |
|
0 commit comments