Coverage for src/usaspending/models/recipient_spending.py: 96%

23 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-03 17:15 -0700

1"""Recipient spending model for USASpending spending by recipient data.""" 

2 

3from __future__ import annotations 

4 

5from typing import Optional, TYPE_CHECKING 

6from ..utils.formatter import to_float, round_to_millions 

7from .recipient import Recipient 

8 

9if TYPE_CHECKING: 

10 from ..client import USASpending 

11 

12 

13class RecipientSpending(Recipient): 

14 """Model for spending by recipient data. 

15 

16 Represents spending data grouped by recipient with recipient-specific 

17 fields like recipient_id and UEI. 

18 """ 

19 

20 def __init__(self, data: dict, client: Optional["USASpending"] = None): 

21 """Initialize RecipientSpending model. 

22 

23 Args: 

24 data: Raw recipient spending data from API 

25 client: USASpending client instance 

26 """ 

27 super().__init__(data, client) 

28 

29 @property 

30 def duns(self) -> Optional[str]: 

31 """DUNS number from spending data (stored in 'code' field).""" 

32 return self.get_value(["code"], default=None) 

33 

34 @property 

35 def amount(self) -> Optional[float]: 

36 """Total spending amount for this record.""" 

37 return to_float(self.get_value(["amount"])) 

38 

39 @property 

40 def total_outlays(self) -> Optional[float]: 

41 """Total outlays for this spending record.""" 

42 return to_float(self.get_value(["total_outlays"])) 

43 

44 @property 

45 def spending_level(self) -> Optional[str]: 

46 """The spending level used for this data (transactions, awards, subawards).""" 

47 return self.get_value(["spending_level"]) 

48 

49 def __repr__(self) -> str: 

50 """String representation of RecipientSpending.""" 

51 name = self.name or "Unknown Recipient" 

52 formatted_amount = round_to_millions(self.amount) or 0 

53 return f"<RecipientSpending {name}: {formatted_amount}>"