Remove fixture-based reporting methods

These methods probably can be reused to handle real Azure reporting data
This commit is contained in:
graham-dds 2020-02-06 15:42:08 -05:00
parent 4a78aa07c9
commit 5b60a54dbc
3 changed files with 1 additions and 219 deletions

View File

@ -1,4 +1,3 @@
from collections import defaultdict
import json
from decimal import Decimal
import pendulum
@ -12,132 +11,6 @@ def load_fixture_data():
class MockReportingProvider:
FIXTURE_SPEND_DATA = load_fixture_data()
@classmethod
def get_portfolio_monthly_spending(cls, portfolio):
"""
returns an array of application and environment spending for the
portfolio. Applications and their nested environments are sorted in
alphabetical order by name.
[
{
name
this_month
last_month
total
environments [
{
name
this_month
last_month
total
}
]
}
]
"""
fixture_apps = cls.FIXTURE_SPEND_DATA.get(portfolio.name, {}).get(
"applications", []
)
for application in portfolio.applications:
if application.name not in [app["name"] for app in fixture_apps]:
fixture_apps.append({"name": application.name, "environments": []})
return sorted(
[
cls._get_application_monthly_totals(portfolio, fixture_app)
for fixture_app in fixture_apps
if fixture_app["name"]
in [application.name for application in portfolio.applications]
],
key=lambda app: app["name"],
)
@classmethod
def _get_environment_monthly_totals(cls, environment):
"""
returns a dictionary that represents spending totals for an environment e.g.
{
name
this_month
last_month
total
}
"""
return {
"name": environment["name"],
"this_month": sum(environment["spending"]["this_month"].values()),
"last_month": sum(environment["spending"]["last_month"].values()),
"total": sum(environment["spending"]["total"].values()),
}
@classmethod
def _get_application_monthly_totals(cls, portfolio, fixture_app):
"""
returns a dictionary that represents spending totals for an application
and its environments e.g.
{
name
this_month
last_month
total
environments: [
{
name
this_month
last_month
total
}
]
}
"""
application_envs = [
env
for env in portfolio.all_environments
if env.application.name == fixture_app["name"]
]
environments = [
cls._get_environment_monthly_totals(env)
for env in fixture_app["environments"]
if env["name"] in [e.name for e in application_envs]
]
for env in application_envs:
if env.name not in [env["name"] for env in environments]:
environments.append({"name": env.name})
return {
"name": fixture_app["name"],
"this_month": sum(env.get("this_month", 0) for env in environments),
"last_month": sum(env.get("last_month", 0) for env in environments),
"total": sum(env.get("total", 0) for env in environments),
"environments": sorted(environments, key=lambda env: env["name"]),
}
@classmethod
def get_spending_by_JEDI_clin(cls, portfolio):
"""
returns an dictionary of spending per JEDI CLIN for a portfolio
{
jedi_clin: {
invoiced
estimated
},
}
"""
if portfolio.name in cls.FIXTURE_SPEND_DATA:
CLIN_spend_dict = defaultdict(lambda: defaultdict(Decimal))
for application in cls.FIXTURE_SPEND_DATA[portfolio.name]["applications"]:
for environment in application["environments"]:
for clin, spend in environment["spending"]["this_month"].items():
CLIN_spend_dict[clin]["estimated"] += Decimal(spend)
for clin, spend in environment["spending"]["total"].items():
CLIN_spend_dict[clin]["invoiced"] += Decimal(spend)
return CLIN_spend_dict
return {}
def prepare_azure_reporting_data(rows: list):
"""

View File

@ -1,5 +1,4 @@
from flask import current_app
from itertools import groupby
from atst.domain.csp.cloud.models import (
ReportingCSPPayload,
CostManagementQueryCSPResult,
@ -9,46 +8,12 @@ import pendulum
class Reports:
@classmethod
def monthly_spending(cls, portfolio):
return current_app.csp.reports.get_portfolio_monthly_spending(portfolio)
@classmethod
def expired_task_orders(cls, portfolio):
return [
task_order for task_order in portfolio.task_orders if task_order.is_expired
]
@classmethod
def obligated_funds_by_JEDI_clin(cls, portfolio):
clin_spending = current_app.csp.reports.get_spending_by_JEDI_clin(portfolio)
active_clins = portfolio.active_clins
for jedi_clin, clins in groupby(
active_clins, key=lambda clin: clin.jedi_clin_type
):
if not clin_spending.get(jedi_clin.name):
clin_spending[jedi_clin.name] = {}
clin_spending[jedi_clin.name]["obligated"] = sum(
clin.obligated_amount for clin in clins
)
output = []
for clin in clin_spending.keys():
invoiced = clin_spending[clin].get("invoiced", 0)
estimated = clin_spending[clin].get("estimated", 0)
obligated = clin_spending[clin].get("obligated", 0)
remaining = obligated - (invoiced + estimated)
output.append(
{
"name": clin,
"invoiced": invoiced,
"estimated": estimated,
"obligated": obligated,
"remaining": remaining,
}
)
return output
@classmethod
def get_portfolio_spending(cls, portfolio):
# TODO: Extend this function to make from_date and to_date configurable

View File

@ -1,65 +1,9 @@
from atst.domain.csp.reports import MockReportingProvider, prepare_azure_reporting_data
from atst.domain.csp.reports import prepare_azure_reporting_data
from tests.factories import PortfolioFactory
from decimal import Decimal
import pendulum
def test_get_environment_monthly_totals():
environment = {
"name": "Test Environment",
"spending": {
"this_month": {"JEDI_CLIN_1": 100, "JEDI_CLIN_2": 100},
"last_month": {"JEDI_CLIN_1": 200, "JEDI_CLIN_2": 200},
"total": {"JEDI_CLIN_1": 1000, "JEDI_CLIN_2": 1000},
},
}
totals = MockReportingProvider._get_environment_monthly_totals(environment)
assert totals == {
"name": "Test Environment",
"this_month": 200,
"last_month": 400,
"total": 2000,
}
def test_get_application_monthly_totals():
portfolio = PortfolioFactory.create(
applications=[
{"name": "Test Application", "environments": [{"name": "Z"}, {"name": "A"}]}
],
)
application = {
"name": "Test Application",
"environments": [
{
"name": "Z",
"spending": {
"this_month": {"JEDI_CLIN_1": 50, "JEDI_CLIN_2": 50},
"last_month": {"JEDI_CLIN_1": 150, "JEDI_CLIN_2": 150},
"total": {"JEDI_CLIN_1": 250, "JEDI_CLIN_2": 250},
},
},
{
"name": "A",
"spending": {
"this_month": {"JEDI_CLIN_1": 100, "JEDI_CLIN_2": 100},
"last_month": {"JEDI_CLIN_1": 200, "JEDI_CLIN_2": 200},
"total": {"JEDI_CLIN_1": 1000, "JEDI_CLIN_2": 1000},
},
},
],
}
totals = MockReportingProvider._get_application_monthly_totals(
portfolio, application
)
assert totals["name"] == "Test Application"
assert totals["this_month"] == 300
assert totals["last_month"] == 700
assert totals["total"] == 2500
assert [env["name"] for env in totals["environments"]] == ["A", "Z"]
class TestPrepareAzureData:
start_of_month = pendulum.today(tz="utc").start_of("month").replace(tzinfo=None)
next_month = start_of_month.add(months=1).to_atom_string()