Last active
August 29, 2015 14:15
-
-
Save volodymyrsmirnov/814c2d754743400d9d3e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Select all users recurring user subscriptions where activation date is bigger than the lowers activation date for unexpired and enabled subscription | |
recurring_subscriptions = "select user_subscriptions for user where enabled=true and recurring=true and activation_date >= lowest_user_subscription_activation_date_for_user()" | |
# Select all users non-recurring user subscriptions where activation date is bigger than the lowers activation date for unexpired and enabled subscription (type does not matter) | |
non_recurring_subscriptions = "select user_subscriptions for user where recurring=false and activation_date >= lowest_user_subscription_activation_date_for_user()" | |
# In real world recurring_subscriptions and non_recurring_subscriptions can be joined into one DB query, I have 2 different variables here just for the ease of understanding | |
# Select all sessions starting from the lowers activation date for unexpired and enabled subscription, group them by day, month and year for performance | |
sessions = "select sessions.date.format('%d-%m-%Y') as date_formatted, SUM(bytes) as bytes_sum for user where start_date >= lowest_user_subscription_activation_date_for_user() GROUP BY date_formatter" | |
# Make the dictinary with daily summary usage, where key is date and value is sum of bytes for all sessions per day | |
usage_days = dict([ | |
session["date_formatted"], session["bytes_sum"] for session in sessions | |
]) | |
#{ | |
# "15-01-2015": 10000000, | |
# "16-01-2015": 20000000, | |
# "17-01-2015": 30000000, | |
#} | |
# Sum limit of all unexpired subscriptions | |
traffic_limit = 0 | |
# Sum of all sessions for active (unexpired) subscriptions | |
traffic_used = 0 | |
# How much traffic user still can use | |
traffic_left = 0 | |
# Function to process usage dats | |
# subscription_days - list, i.e. ["01.01.2015", "01.02.2015", ...] | |
# subscription_limit - int, bytes of subscription or period, i.e. 50000000 | |
# active_billing_period - boolean, if the subscription is still active (unexpired), or todays date is in one of the recurring subscriptions period | |
def process_usage_days(subscription_days, subscription_limit, active_billing_period): | |
# If subscription is active - it must go to traffic_limit | |
if active_billing_period: | |
traffic_limit += subscription_limit | |
# Iterate over days of subscription / subscription period | |
for day in subscription_days: | |
# If we have usage for subscription day | |
if day in usage_days: | |
day_usage = usage_days[day] | |
# Skip days with no usage | |
if day_usage == 0: | |
continue | |
# If number of bytes used over the selected day is less or equal than limit of subscription | |
if day_usage <= subscription_limit: | |
# Set day usage to 0 | |
usage_days[day] = 0 | |
# New subscription limit = subscription limit - number of bytes consumed over the day | |
subscription_limit -= day_usage | |
# If subscrption / period is active - add number of bytes to the usage | |
if active_billing_period | |
traffic_used += day_usage | |
# If number of bytes used over the selected day is bigger than a limit of subscription | |
else: | |
# New usage for day is usage for day minus the subscription bytes | |
if active_billing_period | |
traffic_used += subscription_limit | |
usage_days[day] -= subscription_limit | |
subscription_limit = 0 | |
# Recurring subscriptions have higher priority over the non_recurring | |
# That's why we process them first | |
for recurring_subscription in recurring_subscriptions: | |
# recurring_subscription.start_date = 01.01.2015 | |
# recurring_subscription.billing_period = 30 | |
# recurring_subscription.billing_period_number = 3 | |
# Get the list of the list of days per periods | |
periods = calculate_periods( | |
recurring_subscription.start_date, | |
recurring_subscription.billing_period, | |
recurring_subscription.billing_period_number, | |
) | |
# [ | |
# [01.01.2015, 01.01.2015, ..., 31.01.2015], | |
# [01.02.2015, 01.02.2015, ..., 31.02.2015], | |
# [01.03.2015, 01.03.2015, ..., 31.01.2015], | |
# ] | |
# Process usage for days in every period | |
for period_days in periods: | |
process_usage_days( | |
period_days, | |
recurring_subscription.bytes_limit, | |
datetime.datetime.now.format("%d-%m-%Y") in period # Period is active if todays date is in period days | |
) | |
# After recurring subscriptions we can process non-recurring (addon) subscriptons | |
for non_recurring_subscription in non_recurring_subscriptions: | |
# non_recurring_subscription.activated = 14.01.2015 | |
# non_recurring_subscription.expiration_date = 19.04.2015 | |
# Get the list of days between subscription activation and expiration date | |
subscription_days = days_between_dates( | |
non_recurring_subscription.activated, | |
non_recurring_subscription.expiration_date | |
) | |
# ["14.01.2015", "15.01.2015", ... ,"19.01.2015"] | |
# Process usage for days in every period | |
process_usage_days( | |
subscription_days, | |
non_recurring_subscription.bytes_limit, | |
datetime.datetime.now() <= non_recurring_subscription.expiration_date | |
) | |
# Final calculation, user has traffic left = traffic limit - traffic usage | |
traffic_left = traffic_limit - traffic_used |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment