Skip to content

Commit

Permalink
msp-billing-report: fix avg.licenses per day for non-company + non-…
Browse files Browse the repository at this point in the history
…daily reports, add "initial_licenses" + "final_licences" columns for non-daily reports
  • Loading branch information
aaunario-keeper committed Dec 21, 2024
1 parent d279186 commit 1947ff5
Showing 1 changed file with 56 additions and 2 deletions.
58 changes: 56 additions & 2 deletions keepercommander/commands/msp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import json
import logging
import os
from functools import reduce
from typing import Set, Dict, List, Iterable, Any, Tuple, Union
from urllib.parse import urlparse, urlunparse

Expand Down Expand Up @@ -627,6 +628,45 @@ def get_daily_snapshots(params, year, month):
MSPBillingReportCommand.SNAPSHOT_CACHE[key] = snapshot
return MSPBillingReportCommand.SNAPSHOT_CACHE[key]

@staticmethod
def get_bounding_snapshots(period_snapshots, mc_id=None):
# type: (Dict[DailySnapshot, Dict[int, int]], Union[str, None]) -> Tuple[Union[Dict[int, int], Dict[int, Tuple[int, int]]], Union[Dict[int, int], Dict[int, Tuple[int, int]]]]

snap_keys = period_snapshots.keys()

def get_mc_bounding_snapshots(mc):
# type: (str) -> Tuple[Dict[int, int], Dict[int, int]]
mc_snapshots = {ds for ds in snap_keys if ds.mc_enterprise_id == mc}
dates = {ds.date_no for ds in mc_snapshots}
start_date, end_date = min(dates), max(dates)
start_ds = [ds for ds in mc_snapshots if ds.date_no == start_date].pop()
end_ds = [ds for ds in mc_snapshots if ds.date_no == end_date].pop()
return period_snapshots.get(start_ds), period_snapshots.get(end_ds)

if mc_id is None:
start_snapshots = []
end_snapshots = []
mc_ids = {ds.mc_enterprise_id for ds in snap_keys}
# Get the first and last snapshot for each MC
for mc in mc_ids:
start, end = get_mc_bounding_snapshots(mc)
start and start_snapshots.append(start)
end and end_snapshots.append(end)

# Merge all first snapshots together, then all last snapshots
merge_counts = lambda x, y: DailySnapshot.merge_units((x, y))
start_snapshot = reduce(merge_counts, start_snapshots)
end_snapshot = reduce(merge_counts, end_snapshots)
return start_snapshot, end_snapshot
else:
return get_mc_bounding_snapshots(mc_id)

@staticmethod
def get_num_reported_days(period_snapshots): # type: (Dict[DailySnapshot, Dict[int, int]]) -> int
dates = [ds.date_no for ds in period_snapshots]
return max(dates) - min(dates) + 1


def execute(self, params, **kwargs):
month_str = kwargs.get('month')
if not month_str:
Expand Down Expand Up @@ -663,7 +703,7 @@ def execute(self, params, **kwargs):
headers.extend(('company', 'company_id'))
headers.extend(('product', 'licenses', 'rate'))
if not show_date:
headers.append('avg_per_day')
headers.extend(['avg_per_day', 'initial_licenses', 'final_licenses'])
plan_lookup = {x[0]: x for x in constants.MSP_PLANS}
storage_lookup = {x[0]: x for x in constants.MSP_FILE_PLANS}
addon_lookup = {}
Expand All @@ -675,6 +715,9 @@ def execute(self, params, **kwargs):
for point in merged_counts:
day_str = str(datetime.date.fromordinal(point.date_no)) if show_date else ''
company = MSPBillingReportCommand.COMPANY_CACHE.get(point.mc_enterprise_id, '') if show_company else ''
start_snapshots, end_snapshots = (None, None) \
if show_date \
else MSPBillingReportCommand.get_bounding_snapshots(daily_counts, None if not show_company else point.mc_enterprise_id)
counts = merged_counts[point]
products = list(counts.keys())
products.sort()
Expand All @@ -685,7 +728,9 @@ def execute(self, params, **kwargs):
if show_company:
row.extend((company, point.mc_enterprise_id))
count_id = MSPBillingReportCommand.get_count_id(product)
count, days = counts[product]
count, days = counts[product] \
if show_company \
else (counts[product][0], MSPBillingReportCommand.get_num_reported_days(daily_counts))

product_name = ''
rate_text = ''
Expand Down Expand Up @@ -716,6 +761,15 @@ def execute(self, params, **kwargs):
row.extend((product_name, count, rate_text))
if not show_date:
row.append(round(count / days, 2))
if start_snapshots and end_snapshots:
start_counts_data = start_snapshots.get(product)
end_counts_data = end_snapshots.get(product)
if isinstance(start_counts_data, int):
start_count, end_count = start_counts_data, end_counts_data
else:
start_count, _ = start_counts_data
end_count, _ = end_counts_data
row.extend([start_count, end_count])

table.append(row)

Expand Down

0 comments on commit 1947ff5

Please sign in to comment.