22"""Calculates Coin charges for an AS Product.
33"""
44import argparse
5- from decimal import Decimal
65from collections import namedtuple
6+ from decimal import Decimal
7+ import sys
78from typing import Any , Dict , Optional
89import urllib3
910
1011from rich .pretty import pprint
12+ from rich .console import Console
1113from squonk2 .auth import Auth
1214from squonk2 .as_api import AsApi , AsApiRv
1315
1618urllib3 .disable_warnings (urllib3 .exceptions .InsecureRequestWarning )
1719
1820AdjustedCoins : namedtuple = namedtuple ("AdjustedCoins" ,
19- ["coins" , "fc" , "ac" , "aac" , "lc" , "alc" ])
21+ ["coins" , "fc" , "ac" , "aac" ])
2022
2123
2224def main (c_args : argparse .Namespace ) -> None :
2325 """Main function."""
26+
27+ console = Console ()
28+
2429 env : Optional [Env ] = get_env ()
2530 if not env :
2631 return
@@ -36,7 +41,10 @@ def main(c_args: argparse.Namespace) -> None:
3641 # Get the product details.
3742 # This gives us the product's allowance, limit and overspend multipliers
3843 p_rv : AsApiRv = AsApi .get_product (token , product_id = args .product )
39- assert p_rv .success
44+ if not p_rv .success :
45+ console .log (p_rv .msg )
46+ console .log (f"[bold red]ERROR[/bold red] Failed to get [blue]{ args .product } [/blue]" )
47+ sys .exit (1 )
4048 if args .verbose :
4149 pprint (p_rv .msg )
4250
@@ -45,13 +53,15 @@ def main(c_args: argparse.Namespace) -> None:
4553 allowance : Decimal = Decimal (p_rv .msg ["product" ]["coins" ]["allowance" ])
4654 allowance_multiplier : Decimal = Decimal (p_rv .msg ["product" ]["coins" ]["allowance_multiplier" ])
4755 limit : Decimal = Decimal (p_rv .msg ["product" ]["coins" ]["limit" ])
48- overspend_multiplier : Decimal = Decimal (p_rv .msg ["product" ]["coins" ]["overspend_multiplier" ])
4956
5057 remaining_days : int = p_rv .msg ["product" ]["coins" ]["remaining_days" ]
5158
5259 # Get the product's charges...
5360 pc_rv : AsApiRv = AsApi .get_product_charges (token , product_id = args .product )
54- assert pc_rv .success
61+ if not pc_rv .success :
62+ console .log (pc_rv .msg )
63+ console .log (f"[bold red]ERROR[/bold red] Failed to get [blue]{ args .product } [/blue]" )
64+ sys .exit (1 )
5565 if args .verbose :
5666 pprint (pc_rv .msg )
5767
@@ -70,12 +80,16 @@ def main(c_args: argparse.Namespace) -> None:
7080
7181 # Accumulate all the processing costs
7282 num_processing_charges : int = 0
73- total_processing_coins : Decimal = Decimal ()
83+ total_uncommitted_processing_coins : Decimal = Decimal ()
84+ total_committed_processing_coins : Decimal = Decimal ()
7485 if pc_rv .msg ["processing_charges" ]:
75- for merchant in pc_rv .msg ["processing_charges" ]:
76- for item in merchant ["items" ]:
77- total_processing_coins += Decimal (item ["coins" ])
78- num_processing_charges += 1
86+ for mp_charge in pc_rv .msg ["processing_charges" ]:
87+ charge_coins : Decimal = Decimal (mp_charge ["charge" ]["coins" ])
88+ if "closed" in mp_charge :
89+ total_committed_processing_coins += charge_coins
90+ else :
91+ total_uncommitted_processing_coins += charge_coins
92+ num_processing_charges += 1
7993
8094 invoice : Dict [str , Any ] = {
8195 "Product" : product_id ,
@@ -85,38 +99,34 @@ def main(c_args: argparse.Namespace) -> None:
8599 "Allowance" : str (allowance ),
86100 "Allowance Multiplier" : str (allowance_multiplier ),
87101 "Limit" : str (limit ),
88- "Overspend Multiplier" : str (overspend_multiplier ),
89102 "From" : pc_rv .msg ["from" ], "Until" : pc_rv .msg ["until" ],
90103 "Billing Day" : p_rv .msg ["product" ]["coins" ]["billing_day" ],
91104 "Remaining Days" : remaining_days ,
92105 "Current Burn Rate" : str (burn_rate ),
93106 "Number of Storage Charges" : num_storage_charges ,
94- "Accrued Storage Coins" : str (total_storage_coins ),
95107 "Number of Processing Charges" : num_processing_charges ,
96- "Accrued Processing Coins" : str (total_processing_coins ),
108+ "Committed Storage Coins" : str (total_storage_coins ),
109+ "Committed Processing Coins" : str (total_committed_processing_coins ),
110+ "Uncommitted Processing Coins" : str (total_uncommitted_processing_coins ),
97111 }
98112
99- total_coins : Decimal = total_storage_coins + total_processing_coins
113+ total_coins : Decimal = total_storage_coins + total_committed_processing_coins
100114
101115 ac : AdjustedCoins = _calculate_adjusted_coins (
102116 total_coins ,
103117 allowance ,
104118 allowance_multiplier ,
105- limit ,
106- overspend_multiplier
107119 )
108120
109- invoice ["Overspend Adjustment" ] = {
110- "Coins (Total Raw)" : f"{ total_storage_coins } + { total_processing_coins } = { total_coins } " ,
121+ invoice ["Allowance Adjustment" ] = {
122+ "Coins (Total Raw)" : f"{ total_storage_coins } + { total_committed_processing_coins } = { total_coins } " ,
111123 "Coins (Penalty Free)" : str (ac .fc ),
112124 "Coins (In Allowance Band)" : str (ac .ac ),
113125 "Coins (Allowance Charge)" : f"{ ac .ac } x { allowance_multiplier } = { ac .aac } " ,
114- "Coins (Above Limit)" : str (ac .lc ),
115- "Coins (Overspend Charge)" : f"{ ac .lc } x { overspend_multiplier } = { ac .alc } " ,
116- "Coins (Adjusted)" : f"{ ac .fc } + { ac .aac } + { ac .alc } = { ac .coins } " ,
126+ "Coins (Adjusted)" : f"{ ac .fc } + { ac .aac } = { ac .coins } " ,
117127 }
118128
119- additional_coins : Decimal = burn_rate * remaining_days
129+ additional_coins : Decimal = total_uncommitted_processing_coins + burn_rate * remaining_days
120130 predicted_total_coins : Decimal = total_coins
121131 zero : Decimal = Decimal ()
122132 if remaining_days > 0 :
@@ -126,20 +136,16 @@ def main(c_args: argparse.Namespace) -> None:
126136 p_ac : AdjustedCoins = _calculate_adjusted_coins (
127137 predicted_total_coins ,
128138 allowance ,
129- allowance_multiplier ,
130- limit ,
131- overspend_multiplier )
139+ allowance_multiplier )
132140
133- invoice ["Predicted Overspend Adjustment " ] = {
141+ invoice ["Prediction " ] = {
134142 "Coins (Burn Rate)" : str (burn_rate ),
135- "Coins (Additional Spend)" : f"{ remaining_days } x { burn_rate } = { additional_coins } " ,
143+ "Coins (Additional Spend)" : f"{ total_uncommitted_processing_coins } + { remaining_days } x { burn_rate } = { additional_coins } " ,
136144 "Coins (Total Raw)" : f"{ total_coins } + { additional_coins } = { predicted_total_coins } " ,
137145 "Coins (Penalty Free)" : str (p_ac .fc ),
138146 "Coins (In Allowance Band)" : str (p_ac .ac ),
139147 "Coins (Allowance Charge)" : f"{ p_ac .ac } x { allowance_multiplier } = { p_ac .aac } " ,
140- "Coins (Above Limit)" : str (p_ac .lc ),
141- "Coins (Overspend Charge)" : f"{ p_ac .lc } x { overspend_multiplier } = { p_ac .alc } " ,
142- "Coins (Adjusted)" : f"{ p_ac .fc } + { p_ac .aac } + { p_ac .alc } = { p_ac .coins } " ,
148+ "Coins (Adjusted)" : f"{ p_ac .fc } + { p_ac .aac } = { p_ac .coins } " ,
143149 }
144150
145151 # Now just pre-tty-print the invoice
@@ -148,9 +154,7 @@ def main(c_args: argparse.Namespace) -> None:
148154
149155def _calculate_adjusted_coins (total_coins : Decimal ,
150156 allowance : Decimal ,
151- allowance_multiplier : Decimal ,
152- limit : Decimal ,
153- overspend_multiplier : Decimal ) -> AdjustedCoins :
157+ allowance_multiplier : Decimal ) -> AdjustedCoins :
154158 """Adjust total based on allowance and limit multipliers.
155159 Coins between the allowance and limit use the allowance multiplier.
156160 Coins above the limit use the limit multiplier.
@@ -164,23 +168,16 @@ def _calculate_adjusted_coins(total_coins: Decimal,
164168 limit_coins : Decimal = Decimal ()
165169 adjusted_limit_coins : Decimal = Decimal ()
166170
167- allowance_band : Decimal = limit - allowance
168-
169171 if total_coins > allowance :
170- allowance_coins = min (total_coins - allowance , allowance_band )
172+ allowance_coins = max (total_coins - allowance , Decimal () )
171173 adjusted_allowance_coins = allowance_coins * allowance_multiplier
172- if total_coins > limit :
173- limit_coins = total_coins - limit
174- adjusted_limit_coins = limit_coins * overspend_multiplier
175174
176- adjusted_coins : Decimal = free_coins + adjusted_allowance_coins + adjusted_limit_coins
175+ adjusted_coins : Decimal = free_coins + adjusted_allowance_coins
177176
178177 return AdjustedCoins (coins = adjusted_coins ,
179178 fc = free_coins ,
180179 ac = allowance_coins ,
181- aac = adjusted_allowance_coins ,
182- lc = limit_coins ,
183- alc = adjusted_limit_coins )
180+ aac = adjusted_allowance_coins )
184181
185182
186183if __name__ == "__main__" :
0 commit comments