Skip to content

Commit 17e0e43

Browse files
committed
fix: start stats on last complete month
1 parent df3eb4e commit 17e0e43

2 files changed

Lines changed: 82 additions & 6 deletions

File tree

weblate_web/crm/tests.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,30 @@ def test_income_monthly_view_handles_boundary_year(self):
452452
self.assertEqual(response.status_code, 200)
453453
self.assertIsNone(response.context["rolling_trend"])
454454

455+
@responses.activate
456+
def test_income_monthly_view_excludes_current_month_from_rolling_trend(self):
457+
"""Test monthly rolling trend skips the current incomplete month."""
458+
cnb_mock_rates()
459+
selected_year = 2026
460+
461+
self.create_test_invoice(2024, 4, InvoiceCategory.HOSTING, Decimal(100))
462+
self.create_test_invoice(2024, 9, InvoiceCategory.HOSTING, Decimal(400))
463+
self.create_test_invoice(2025, 5, InvoiceCategory.HOSTING, Decimal(500))
464+
self.create_test_invoice(
465+
selected_year, 4, InvoiceCategory.HOSTING, Decimal(600)
466+
)
467+
468+
with patch.object(
469+
IncomeView, "_get_current_date", return_value=date(2026, 4, 15)
470+
):
471+
response = self.client.get(
472+
reverse("crm:income-month", kwargs={"year": selected_year, "month": 4})
473+
)
474+
475+
self.assertEqual(response.status_code, 200)
476+
self.assertIsNone(response.context["rolling_trend"])
477+
self.assertNotContains(response, "Rolling trend")
478+
455479
@responses.activate
456480
def test_income_filters_only_invoices(self):
457481
"""Test that income view only shows INVOICE kind, not quotes."""
@@ -736,6 +760,46 @@ def test_income_yearly_view_uses_local_year_for_trend_month(self):
736760
self.assertEqual(response.status_code, 200)
737761
self.assertEqual(response.context["rolling_trend"]["period_month"], 12)
738762

763+
@responses.activate
764+
def test_income_yearly_view_excludes_current_month_from_rolling_trend(self):
765+
"""Test yearly rolling trend ends at the last complete month."""
766+
cnb_mock_rates()
767+
selected_year = 2026
768+
769+
self.create_test_invoice(2024, 4, InvoiceCategory.HOSTING, Decimal(100))
770+
self.create_test_invoice(2024, 9, InvoiceCategory.HOSTING, Decimal(400))
771+
self.create_test_invoice(2025, 5, InvoiceCategory.HOSTING, Decimal(500))
772+
self.create_test_invoice(
773+
selected_year, 3, InvoiceCategory.HOSTING, Decimal(600)
774+
)
775+
self.create_test_invoice(
776+
selected_year, 4, InvoiceCategory.HOSTING, Decimal(700)
777+
)
778+
779+
with patch.object(
780+
IncomeView, "_get_current_date", return_value=date(2026, 4, 15)
781+
):
782+
response = self.client.get(
783+
reverse("crm:income-year", kwargs={"year": selected_year})
784+
)
785+
786+
self.assertEqual(response.status_code, 200)
787+
self.assertEqual(response.context["rolling_trend"]["period_month"], 3)
788+
self.assertEqual(
789+
response.context["rolling_trend"]["rolling_total"], Decimal(1100)
790+
)
791+
self.assertEqual(
792+
response.context["rolling_trend"]["previous_total"], Decimal(500)
793+
)
794+
795+
march_row = response.context["monthly_breakdown_rows"][2]
796+
self.assertTrue(march_row["trend_available"])
797+
self.assertEqual(march_row["rolling_total"], Decimal(1100))
798+
799+
april_row = response.context["monthly_breakdown_rows"][3]
800+
self.assertEqual(april_row["amount"], Decimal(700))
801+
self.assertFalse(april_row["trend_available"])
802+
739803
@responses.activate
740804
def test_income_yearly_breakdown_trend_uses_single_query(self):
741805
"""Test yearly trend breakdown stays constant-query."""

weblate_web/crm/views.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,9 @@ def _get_current_date(self) -> date:
782782
def _get_current_month_start(self) -> date:
783783
return self._get_current_date().replace(day=1)
784784

785+
def _get_last_complete_month_start(self) -> date | None:
786+
return self._shift_month(self._get_current_month_start(), -1)
787+
785788
def _build_rolling_window_summary(
786789
self,
787790
month_totals: dict[date, Decimal],
@@ -839,7 +842,7 @@ def get_rolling_window_summary(
839842
period_start = self._get_month_start(year, month)
840843
except ValueError:
841844
return None
842-
if period_start > self._get_current_month_start():
845+
if period_start >= self._get_current_month_start():
843846
return None
844847
lookback_start = self._shift_month(period_start, -23)
845848
month_totals, earliest_month = self._get_month_totals_in_range(
@@ -868,18 +871,18 @@ def get_yearly_breakdown_rows(
868871
except ValueError:
869872
return rows
870873

871-
current_month_start = self._get_current_month_start()
872-
if first_month > current_month_start:
874+
last_complete_month = self._get_last_complete_month_start()
875+
if last_complete_month is None or first_month > last_complete_month:
873876
return rows
874877

875-
trend_end_month = min(last_month, current_month_start)
878+
trend_end_month = min(last_month, last_complete_month)
876879
month_totals, earliest_month = self._get_month_totals_in_range(
877880
self._shift_month(first_month, -23),
878881
trend_end_month,
879882
)
880883
for row in rows:
881884
period_start = self._get_month_start(year, cast("int", row["month_number"]))
882-
if period_start > current_month_start:
885+
if period_start > trend_end_month:
883886
continue
884887

885888
rolling_summary = self._build_rolling_window_summary(
@@ -898,7 +901,16 @@ def get_yearly_rolling_summary(
898901
monthly_breakdown_rows: list[dict[str, str | int | Decimal | bool]],
899902
current_year: int,
900903
) -> dict[str, int | Decimal | bool] | None:
901-
trend_month = 12 if year < current_year else self._get_current_date().month
904+
if year < current_year:
905+
trend_month = 12
906+
elif year > current_year:
907+
return None
908+
else:
909+
last_complete_month = self._get_last_complete_month_start()
910+
if last_complete_month is None or last_complete_month.year != year:
911+
return None
912+
trend_month = last_complete_month.month
913+
902914
if not 1 <= trend_month <= len(monthly_breakdown_rows):
903915
return None
904916

0 commit comments

Comments
 (0)