Coverage for hledger_lots/fifo_info.py: 63%

70 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-05-05 00:05 -0300

1from datetime import datetime 

2from typing import Optional, Tuple 

3 

4from .checks import MultipleBaseCurrencies 

5from .fifo import get_lots 

6from .hl import hledger2txn 

7from .info import AllInfo, Info, LotsInfo 

8from .lib import dt_list2table, get_avg_fifo 

9 

10 

11class FifoInfo(Info): 

12 def __init__( 

13 self, 

14 journals: Tuple[str, ...], 

15 commodity: str, 

16 check: bool, 

17 no_desc: Optional[str] = None, 

18 ): 

19 super().__init__(journals, commodity,no_desc) 

20 self.check = check 

21 

22 self.lots = get_lots(self.txns, check) 

23 self.last_buy_date = self.lots[-1].date if len(self.lots) > 0 else None 

24 

25 self.buy_lots = get_lots(self.txns, check) 

26 self.table = dt_list2table(self.buy_lots) 

27 

28 def get_info(self): 

29 if len(self.txns) == 0: 

30 return None 

31 

32 commodity = self.commodity 

33 

34 cur = self.lots[0].base_cur 

35 qtty = sum(lot.qtty for lot in self.lots) 

36 amount = sum(lot.price * lot.qtty for lot in self.lots) 

37 avg_cost = get_avg_fifo(self.lots) if qtty > 0 else 0 

38 

39 if self.has_txn: 

40 last_buy_date_str = self.lots[-1].date 

41 last_buy_date = datetime.strptime(last_buy_date_str, "%Y-%m-%d").date() 

42 xirr = self.get_lots_xirr(last_buy_date) 

43 else: 

44 xirr = 0 

45 

46 if self.market_price and self.market_date and xirr: 

47 market_price_str = f"{self.market_price:,.4f}" 

48 market_amount = self.market_price * qtty 

49 market_amount_str = f"{market_amount:,.2f}" 

50 market_profit = market_amount - amount 

51 market_profit_str = f"{market_profit:,.2f}" 

52 market_date = self.market_date.strftime("%Y-%m-%d") 

53 

54 xirr_str = f"{xirr:,.4f}%" 

55 else: 

56 market_amount_str = "" 

57 market_profit_str = "" 

58 market_date = "" 

59 market_price_str = "" 

60 xirr_str = "" 

61 

62 return LotsInfo( 

63 comm=commodity, 

64 cur=cur, 

65 qtty=str(qtty), 

66 amount=f"{amount:,.2f}", 

67 avg_cost=f"{avg_cost:,.4f}", 

68 mkt_price=market_price_str, 

69 mkt_amount=market_amount_str, 

70 mkt_profit=market_profit_str, 

71 mkt_date=market_date, 

72 xirr=xirr_str, 

73 ) 

74 

75 @property 

76 def info_txt(self): 

77 info = self.get_info() 

78 if not info: 

79 return f"No transactions available for {self.commodity}" 

80 return self.get_info_txt(info) 

81 

82 

83class AllFifoInfo(AllInfo): 

84 def __init__(self, journals: Tuple[str, ...], no_desc: str, check: bool): 

85 super().__init__(journals, no_desc) 

86 self.check = check 

87 

88 def get_info(self, commodity: str): 

89 txns = hledger2txn(self.journals, commodity, self.no_desc) 

90 try: 

91 lots = get_lots(txns, self.check) 

92 except MultipleBaseCurrencies: 

93 return None 

94 

95 if len(lots) > 0: 

96 lot_info = FifoInfo(self.journals, commodity, self.check).get_info() 

97 return lot_info 

98 

99 @property 

100 def infos(self): 

101 infos = [self.get_info(com) for com in self.commodities] 

102 infos = [info for info in infos if info is not None] 

103 return infos 

104 

105 def infos_table(self, output_format: str): 

106 return self.get_infos_table(self.infos, output_format) 

107 

108 def infos_csv(self): 

109 return self.get_infos_csv(self.infos)