@@ -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."""
0 commit comments