Skip to content

Commit

Permalink
Merge pull request #97 from ElemarJR/fixing_forecast_2025
Browse files Browse the repository at this point in the history
Fixing forecast 2025
  • Loading branch information
ElemarJR authored Jan 7, 2025
2 parents 2f5b01f + 18158f4 commit 61dfd9d
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 160 deletions.
238 changes: 129 additions & 109 deletions backend/api/src/analytics/yearly_forecast.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from omni_utils.helpers.dates import get_working_days_in_month
from omni_models.analytics.revenue_tracking import compute_revenue_tracking
from omni_models.analytics.forecast import compute_forecast
from omni_utils.helpers.dates import get_last_day_of_month

import calendar
Expand All @@ -23,30 +23,42 @@ def resolve_yearly_forecast(_, info, year=None):
for month in range(1, 13):
m = month - 1 if month > 1 else 12
y = year if month > 1 else year - 1
expected_consulting_fee = get_expected_regular_consulting_revenue(y, m)
expected_pre_contracted_revenue = get_expected_pre_contracted_revenue(y, m)
#expected_consulting_fee = get_expected_regular_consulting_revenue(y, m)
#expected_pre_contracted_revenue = get_expected_pre_contracted_revenue(y, m)

last_day_of_month = get_last_day_of_month(datetime(y, m, 1))
date_of_interest = datetime(y, m, 15)
discount = main_goal / (13 - month)
if (y == current_year and m == current_month):
revenue_tracking = compute_revenue_tracking(current_date)
elif y < current_year or (y == current_year and m < current_month):
last_day_of_month = get_last_day_of_month(datetime(y, m, 1))
revenue_tracking = compute_revenue_tracking(last_day_of_month)
discount = revenue_tracking["total"]
forecast = compute_forecast(current_date)
forecast_doi = forecast
else:
revenue_tracking = None
forecast = compute_forecast(last_day_of_month)
forecast_doi = compute_forecast(date_of_interest)

actual += revenue_tracking["total"] if revenue_tracking else 0
goal = main_goal / (13 - month)
month_actual = 0
if y < current_year or (y == current_year and m < current_month):
goal = 0

month_actual = forecast["summary"]["realized"]
discount = month_actual
actual += month_actual
elif y == current_year and m == current_month:
month_actual = forecast["summary"]["realized"]
# discount = month_actual
actual += month_actual


by_month.append({
"month": m,
"goal": main_goal / (13 - month),
"goal": goal,
"working_days": len(get_working_days_in_month(y, m)),
"expected_consulting_fee": expected_consulting_fee,
"expected_squad_fee": expected_pre_contracted_revenue["squad"],
"expected_hands_on_fee": expected_pre_contracted_revenue["hands_on"],
"expected_consulting_pre_fee": expected_pre_contracted_revenue["consulting_pre"],
"actual": revenue_tracking["total"] if revenue_tracking else 0
"expected_consulting_fee": forecast_doi["by_kind"]["consulting"]['totals'].expected,
"expected_squad_fee": forecast_doi["by_kind"]["squad"]['totals'].in_analysis,
"expected_hands_on_fee": forecast_doi["by_kind"]["hands_on"]['totals'].in_analysis,
"expected_consulting_pre_fee": forecast_doi["by_kind"]["consulting_pre"]['totals'].in_analysis,
"actual": month_actual
})

main_goal -= discount
Expand Down Expand Up @@ -76,123 +88,131 @@ def resolve_yearly_forecast(_, info, year=None):
}


def get_expected_regular_consulting_revenue(year, month):
# def get_expected_regular_consulting_revenue(year, month):

result = 0
# result = 0

cases = [
case
for case in globals.omni_models.cases.get_all().values()
if case.is_active
]
# cases = [
# case
# for case in globals.omni_models.cases.get_all().values()
# if case.is_active
# ]

for case in cases:
wah = case.weekly_approved_hours
# for case in cases:
# wah = case.weekly_approved_hours

if not wah:
continue
# if not wah:
# continue

project_ = None
for project_info in case.tracker_info:
if project_info.kind == 'consulting' and project_info.rate and project_info.rate.rate:
project_ = project_info
break
# project_ = None
# for project_info in case.tracker_info:
# if project_info.kind == 'consulting' and project_info.rate and project_info.rate.rate:
# project_ = project_info
# break

if not project_:
continue
# if not project_:
# continue

working_days_in_month = get_working_days_in_month(year, month)
days_in_month = calendar.monthrange(year, month)[1]
# working_days_in_month = get_working_days_in_month(year, month)
# days_in_month = calendar.monthrange(year, month)[1]

hours_in_month = 0
daily_approved_hours = wah / 5
# hours_in_month = 0
# daily_approved_hours = wah / 5

due_on = project_.due_on.date() if project_ and project_.due_on else case.end_of_contract
# due_on = project_.due_on.date() if project_ and project_.due_on else case.end_of_contract

for day in range(1, days_in_month + 1):
date = datetime(year, month, day)
# for day in range(1, days_in_month + 1):
# date = datetime(year, month, day)

if case.start_of_contract and date.date() < case.start_of_contract:
continue
# if case.start_of_contract and date.date() < case.start_of_contract:
# continue

if due_on and date.date() > due_on:
break
# if due_on and date.date() > due_on:
# break

if date in working_days_in_month:
hours_in_month += daily_approved_hours
# if date in working_days_in_month:
# hours_in_month += daily_approved_hours

result += hours_in_month * (project_.rate.rate / 100)
# result += hours_in_month * (project_.rate.rate / 100)

return result
# return result

def get_expected_pre_contracted_revenue(year, month):

cases = [
case
for case in globals.omni_models.cases.get_all().values()
if case.is_active
]

consulting_pre = 0
hands_on = 0
squad = 0

for case in cases:
start = case.start_of_contract # .replace(day=1)
if start is None:
start = datetime(year, month, 1)
else:
start = start.replace(day=1)
# def get_expected_pre_contracted_revenue(year, month):

# cases = [
# case
# for case in globals.omni_models.cases.get_all().values()
# if case.is_active
# ]

# consulting_pre = 0
# hands_on = 0
# squad = 0

# for case in cases:
# start = case.start_of_contract # .replace(day=1)
# if start is None:
# start = datetime(year, month, 1)
# else:
# start = start.replace(day=1)

end = case.end_of_contract
if end is None:
end = datetime(year, month, calendar.monthrange(year, month)[1])
# end = case.end_of_contract
# if end is None:
# end = datetime(year, month, calendar.monthrange(year, month)[1])

in_contract = start.year <= year <= end.year
if in_contract and year == start.year:
in_contract = month >= start.month
# in_contract = start.year <= year <= end.year
# if in_contract and year == start.year:
# in_contract = month >= start.month

if in_contract and year == end.year:
in_contract = month <= end.month
# if in_contract and year == end.year:
# in_contract = month <= end.month

if not in_contract:
continue
# if not in_contract:
# continue

for project_info in case.tracker_info:
if project_info.billing and project_info.billing.fee and project_info.billing.fee != 0:
if project_info.budget and project_info.budget.period == 'general':
if start.year == end.year:
number_of_months = end.month - start.month + 1
else:
months_on_start_year = 12 - start.month + 1
months_on_end_year = end.month
if end.year - start.year > 1:
number_of_months = months_on_start_year + months_on_end_year + (end.year - start.year - 1) * 12
else:
number_of_months = months_on_start_year + months_on_end_year
# for project_info in case.tracker_info:
# if project_info.billing and project_info.billing.fee and project_info.billing.fee != 0:
# if project_info.budget and project_info.budget.period == 'general':
# if start.year == end.year:
# number_of_months = end.month - start.month + 1
# else:
# months_on_start_year = 12 - start.month + 1
# months_on_end_year = end.month
# if end.year - start.year > 1:
# number_of_months = months_on_start_year + months_on_end_year + (end.year - start.year - 1) * 12
# else:
# number_of_months = months_on_start_year + months_on_end_year

fee = project_info.billing.fee / 100 / number_of_months
# fee = project_info.billing.fee / 100 / number_of_months

if project_info.kind == 'consulting':
consulting_pre += fee
elif project_info.kind == 'squad':
squad += fee
else: # hands_on
hands_on += fee
# if project_info.kind == 'consulting':
# consulting_pre += fee
# elif project_info.kind == 'squad':
# squad += fee
# else: # hands_on
# hands_on += fee

else:
fee = project_info.billing.fee / 100
if project_info.kind == 'consulting':
consulting_pre += fee
elif project_info.kind == 'squad':
squad += fee
else: # hands_on
hands_on += fee
# else:
# fee = project_info.billing.fee / 100
# date_of_interest = datetime(year, month, 5)

# if project_info.created_at > date_of_interest:
# fee = 0

# if project_info.due_on and (project_info.due_on.date() if hasattr(project_info.due_on, 'date') else project_info.due_on) < (date_of_interest.date() if hasattr(date_of_interest, 'date') else date_of_interest):
# fee = 0

# if project_info.kind == 'consulting':
# consulting_pre += fee
# elif project_info.kind == 'squad':
# squad += fee
# else: # hands_on
# hands_on += fee


return {
"consulting_pre": consulting_pre,
"hands_on": hands_on,
"squad": squad
}
# return {
# "consulting_pre": consulting_pre,
# "hands_on": hands_on,
# "squad": squad
# }

2 changes: 1 addition & 1 deletion backend/api/src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,6 @@ def graphql_server():
app.logger.setLevel(logging.INFO)

app.logger.info("Starting the application")
globals.update()
# globals.update()

app.run(debug=args.verbose,host="0.0.0.0",port=5001)
4 changes: 3 additions & 1 deletion backend/models/src/omni_models/analytics/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,10 @@ def filter_items(items):

hours_in_month = 0
daily_approved_hours = wah / 5


due_on = project_.due_on.date() if project_.due_on else case_.end_of_contract
due_on = project_.due_on if project_.due_on else case_.end_of_contract
due_on = due_on.date() if hasattr(due_on, 'date') else due_on

for day in range(1, days_in_month + 1):
date = datetime(year, month, day)
Expand Down
Loading

0 comments on commit 61dfd9d

Please sign in to comment.