From 4c5f1be3417c8f91a51c1d0a56f7880f7cb1c7cd Mon Sep 17 00:00:00 2001 From: Sean Marlow Date: Wed, 10 Apr 2024 15:26:27 -0400 Subject: [PATCH] Add a one billing period free trial This will run a empty metering on the first bill and archive the usage records. After the first billing period the adapter will begin billing usage as normal. --- csp_billing_adapter/adapter.py | 30 ++++++++++++++++++++++-------- csp_billing_adapter/bill_utils.py | 8 ++++++-- csp_billing_adapter/csp_cache.py | 3 ++- tests/unit/test_adapter.py | 2 ++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/csp_billing_adapter/adapter.py b/csp_billing_adapter/adapter.py index c207ea4..042ed4b 100644 --- a/csp_billing_adapter/adapter.py +++ b/csp_billing_adapter/adapter.py @@ -259,15 +259,29 @@ def event_loop_handler( cache['next_bill_time'] ) + trial_remaining = cache.get('trial_remaining', 0) + if now >= string_to_date(cache['next_bill_time']): - log.info('Attempt a billing cycle update') - process_metering( - hook, - config, - now, - cache, - csp_config - ) + if trial_remaining > 0: + log.info('Attempt a free trial billing cycle update') + process_metering( + hook, + config, + now, + cache, + csp_config, + empty_metering=True, + free_trial=True + ) + else: + log.info('Attempt a billing cycle update') + process_metering( + hook, + config, + now, + cache, + csp_config + ) elif now >= string_to_date(cache['next_reporting_time']): log.info('Attempt a reporting cycle update') process_metering( diff --git a/csp_billing_adapter/bill_utils.py b/csp_billing_adapter/bill_utils.py index 2e42d1d..de488ac 100644 --- a/csp_billing_adapter/bill_utils.py +++ b/csp_billing_adapter/bill_utils.py @@ -485,7 +485,8 @@ def process_metering( now: datetime.datetime, cache: dict, csp_config: dict, - empty_metering: bool = False + empty_metering: bool = False, + free_trial: bool = False ) -> None: """ Handle the CSP metering process, updating the csp_config and cache @@ -628,7 +629,7 @@ def process_metering( csp_config['billing_api_access_ok'] = True csp_config['expire'] = next_reporting_time - if not empty_metering: + if not empty_metering or free_trial: # Usage was billed next_bill_time = date_to_string( get_next_bill_time( @@ -674,3 +675,6 @@ def process_metering( except Exception as error: # Non-fatal error is only logged log.exception(error) + + if free_trial: + cache['trial_remaining'] = cache['trial_remaining'] - 1 diff --git a/csp_billing_adapter/csp_cache.py b/csp_billing_adapter/csp_cache.py index ce57f3d..54cde5d 100644 --- a/csp_billing_adapter/csp_cache.py +++ b/csp_billing_adapter/csp_cache.py @@ -60,7 +60,8 @@ def create_cache(hook, config: Config) -> dict: 'next_bill_time': date_to_string(next_bill_time), 'next_reporting_time': date_to_string(next_reporting_time), 'usage_records': [], - 'last_bill': {} + 'last_bill': {}, + 'trial_remaining': 1 } try: diff --git a/tests/unit/test_adapter.py b/tests/unit/test_adapter.py index 89de4ef..e2af698 100644 --- a/tests/unit/test_adapter.py +++ b/tests/unit/test_adapter.py @@ -251,6 +251,7 @@ def test_event_loop_handler( assert cache['usage_records'] != [] assert len(cache['usage_records']) == 1 assert cache['last_bill'] == {} + assert cache['trial_remaining'] == 1 # Similarly the meter_billing() call should have succeeded # not triggered the generation of a new bill. @@ -324,6 +325,7 @@ def test_event_loop_handler( assert cache != {} assert cache['usage_records'] == [] assert cache['last_bill'] != {} + assert cache['trial_remaining'] == 0 assert 'dimensions' in cache['last_bill'] assert 'billing_status' in cache['last_bill'] assert 'metering_time' in cache['last_bill']