Skip to content

Commit

Permalink
Merge pull request #260 from ImMin5/refact-cost-report
Browse files Browse the repository at this point in the history
Remove email manager at CostReportService init
  • Loading branch information
ImMin5 authored Jul 19, 2024
2 parents c9d25c1 + c5283c4 commit 51538c2
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/spaceone/cost_analysis/manager/cost_report_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def push_creating_cost_report_job(self, params: dict) -> None:
"locator": "SERVICE",
"name": "CostReportService",
"metadata": {"token": token},
"method": "create_cost_report_by_cost_report_config_info",
"method": "create_cost_report_by_cost_report_config_id",
"params": {"params": params},
}
],
Expand Down
1 change: 1 addition & 0 deletions src/spaceone/cost_analysis/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
from spaceone.cost_analysis.model.cost_report_config.database import CostReportConfig
from spaceone.cost_analysis.model.cost_report_data.database import CostReportData
from spaceone.cost_analysis.model.cost_report.database import CostReport
from spaceone.cost_analysis.model.daily_cost_record.database import DailyCostRecord
193 changes: 177 additions & 16 deletions src/spaceone/cost_analysis/service/cost_report_serivce.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
from spaceone.core.service import *

from spaceone.cost_analysis.manager import DataSourceAccountManager
from spaceone.cost_analysis.manager.daily_cost_record_manager import (
DailyCostRecordManager,
)
from spaceone.cost_analysis.model import DailyCostRecord
from spaceone.cost_analysis.model.cost_report.database import CostReport
from spaceone.cost_analysis.model.cost_report_config.database import CostReportConfig
from spaceone.cost_analysis.model.cost_report.request import *
Expand Down Expand Up @@ -50,7 +54,6 @@ def __init__(self, *args, **kwargs):
self.ds_account_mgr = DataSourceAccountManager()
self.currency_map: Union[dict, None] = None
self.currency_date: Union[str, None] = None
self.email_mgr = EmailManager()

@transaction(exclude=["authentication", "authorization", "mutation"])
def create_cost_report_by_cost_report_config(self, params: dict) -> None:
Expand All @@ -67,15 +70,19 @@ def create_cost_report_by_cost_report_config(self, params: dict) -> None:
try:
cost_report_config_vo: CostReportConfig = cost_report_config_vo
self.cost_report_mgr.push_creating_cost_report_job(
params=cost_report_config_vo.to_dict()
params={
"domain_id": cost_report_config_vo.domain_id,
"cost_report_config_id": cost_report_config_vo.cost_report_config_id,
}
)
except Exception as e:
_LOGGER.error(
f"[create_cost_report_by_cost_report_config] failed to create cost report ({cost_report_config_vo.cost_report_config_id}), {e}"
f"[create_cost_report_by_cost_report_config] failed to create cost report ({cost_report_config_vo.cost_report_config_id}), {e}",
exc_info=True,
)

@transaction(exclude=["authentication", "authorization", "mutation"])
def create_cost_report_by_cost_report_config_info(self, params: dict):
def create_cost_report_by_cost_report_config_id(self, params: dict):
self.create_cost_report(params)

@transaction(
Expand Down Expand Up @@ -236,11 +243,14 @@ def stat(self, params: CostReportDataStatQueryRequest) -> dict:

def create_cost_report(self, params: dict):
cost_report_config_id = params["cost_report_config_id"]
domain_id = params["domain_id"]
currency = params["currency"]
data_source_filter = params.get("data_source_filter", {}) or {}
is_last_day = params.get("is_last_day", False)
issue_day = self.get_issue_day(is_last_day, params.get("issue_day"))
cost_report_config_vo = self.cost_report_config_mgr.get_cost_report_config(
params["domain_id"], cost_report_config_id
)
domain_id = cost_report_config_vo.domain_id
currency = cost_report_config_vo.currency
data_source_filter = cost_report_config_vo.data_source_filter or {}
is_last_day = cost_report_config_vo.is_last_day or False
issue_day = self.get_issue_day(is_last_day, cost_report_config_vo.issue_day)

current_date = datetime.utcnow()
currency_date = current_date
Expand Down Expand Up @@ -346,6 +356,156 @@ def create_cost_report(self, params: dict):
cost_report_created_at,
)

# self._create_daily_cost_record(
# domain_id, cost_report_config_id, current_date, currency
# )

def _create_daily_cost_record(
self,
domain_id: str,
cost_report_config_id: str,
current_date: datetime,
currency: str,
):
# check if create today's daily cost report
cost_report_data_query = {
"group_by": [
"domain_id",
"workspace_id",
"project_id",
"data_source_id",
"product",
"workspace_name",
"project_name",
],
"fields": {
"value_sum": {"key": f"cost.{currency}", "operator": "sum"},
},
"filter": [
{"k": "is_confirmed", "v": False, "o": "eq"},
{"k": "cost_report_config_id", "v": cost_report_config_id, "o": "eq"},
{"k": "domain_id", "v": domain_id, "o": "eq"},
{"k": "report_month", "v": current_date.strftime("%Y-%m"), "o": "eq"},
],
}
results = self.cost_report_data_mgr.analyze_cost_reports_data(
query=cost_report_data_query
).get("results", [])

daily_cost_record_mgr = DailyCostRecordManager()
(
daily_cost_record_vos,
daily_cost_record_total_count,
) = daily_cost_record_mgr.list_daily_cost_records(
query={
"filter": [
{"k": "domain_id", "v": domain_id, "o": "eq"},
{
"k": "record_month",
"v": current_date.strftime("%Y-%m"),
"o": "eq",
},
]
}
)

df1 = pd.DataFrame(results)

daily_cost_record_created_at = datetime.utcnow()
record_month = current_date.strftime("%Y-%m")
record_date = current_date.strftime("%Y-%m-%d")
if daily_cost_record_total_count > 0:
if self._is_daily_cost_report_created_today(daily_cost_record_vos[0]):
return

daily_cost_records_info = [
daily_cost_record_vo.to_dict()
for daily_cost_record_vo in daily_cost_record_vos
]
df2 = pd.DataFrame(daily_cost_records_info)
df2 = df2.drop(["_id"], axis=1)

joined_df = df1.merge(
df2,
on=[
"domain_id",
"workspace_id",
"project_id",
"data_source_id",
"product",
],
how="left",
)

for joined_data in joined_df.to_dict(orient="records"):
monthly_cost = joined_data.get("value_sum", 0)
before_monthly_cost = joined_data.get("monthly_cost", 0)

daily_cost_diff_percent = 0.0
daily_cost_diff = 0.0

if before_monthly_cost > 0:
daily_cost_diff = monthly_cost - before_monthly_cost
daily_cost_diff_percent = (
daily_cost_diff / before_monthly_cost
) * 100

create_params = {
"daily_cost_diff": daily_cost_diff,
"daily_cost_diff_percent": daily_cost_diff_percent,
"monthly_cost": monthly_cost,
"record_month": record_month,
"record_date": record_date,
"product": joined_data.get("product"),
"project_name": joined_data.get("project_name"),
"workspace_name": joined_data.get("workspace_name"),
"cost_report_config_id": cost_report_config_id,
"data_source_id": joined_data["data_source_id"],
"project_id": joined_data.get("project_id"),
"workspace_id": joined_data["workspace_id"],
"domain_id": joined_data["domain_id"],
}
daily_cost_record_mgr.create_daily_cost_record(create_params)

_LOGGER.debug(
f"[create_daily_cost_record] delete previous daily cost record {record_month} ({len(daily_cost_record_vos)}"
)
daily_cost_record_vos.delete()

else:
for result in results:
create_params = {
"daily_cost_diff": 0.0,
"daily_cost_diff_percent": 0.0,
"monthly_cost": result.get("value_sum", 0, 0),
"record_month": record_month,
"record_date": record_date,
"product": result.get("product"),
"project_name": result.get("project_name"),
"workspace_name": result.get("workspace_name"),
"data_source_id": result["data_source_id"],
"cost_report_config_id": cost_report_config_id,
"project_id": result.get("project_id"),
"workspace_id": result["workspace_id"],
"domain_id": result["domain_id"],
}
daily_cost_record_mgr.create_daily_cost_record(create_params)

@staticmethod
def _is_daily_cost_report_created_today(
daily_cost_record_vo: DailyCostRecord,
) -> bool:
daily_cost_record_created_at: datetime = daily_cost_record_vo.created_at
if daily_cost_record_created_at.strftime(
"%Y-%m-%d"
) == datetime.utcnow().strftime("%Y-%m-%d"):
_LOGGER.debug(
f"[_is_daily_cost_report_created_today] This workspace ({daily_cost_record_vo.workspace_id}) -> SKIP"
)
return True

return False

def _aggregate_monthly_cost_report(
self,
domain_id: str,
Expand Down Expand Up @@ -436,9 +596,9 @@ def _aggregate_monthly_cost_report(
report_month, issue_day, cost_report_idx
)

aggregated_cost_report[
"currency_date"
] = CostReportManager.get_currency_date(self.currency_date)
aggregated_cost_report["currency_date"] = (
CostReportManager.get_currency_date(self.currency_date)
)

cost_report_vo = self.cost_report_mgr.create_cost_report(
aggregated_cost_report
Expand Down Expand Up @@ -522,6 +682,7 @@ def send_cost_report(self, cost_report_vo: CostReport) -> None:
pass

if verified_users_info:
email_mgr = EmailManager()
sso_access_token = self._get_temporary_sso_access_token(
domain_id, workspace_id
)
Expand All @@ -537,7 +698,7 @@ def send_cost_report(self, cost_report_vo: CostReport) -> None:
language,
)

self.email_mgr.send_cost_report_email(
email_mgr.send_cost_report_email(
user_id, email, cost_report_link, language, cost_report_vo
)
except Exception as e:
Expand Down Expand Up @@ -655,9 +816,9 @@ def _get_virtual_workspace_ids_and_map(
for ds_account_vo in ds_account_vos:
v_workspace_ids.append(ds_account_vo.v_workspace_id)
if not v_workspace_id_map.get(ds_account_vo.v_workspace_id):
v_workspace_id_map[
ds_account_vo.v_workspace_id
] = ds_account_vo.workspace_id
v_workspace_id_map[ds_account_vo.v_workspace_id] = (
ds_account_vo.workspace_id
)

return v_workspace_ids, v_workspace_id_map

Expand Down

0 comments on commit 51538c2

Please sign in to comment.