Skip to content

[Reports]: Report — Net Profit made in a financial year #72

Description

@nielsdrost7

Context


The user shall be able to produce a report with the net profit made in a financial year


Specific:

As a user, I want a net profit report for a selected financial year, displaying total revenue minus total expenses.

Measurable:

The report will accurately calculate and display the net profit with a variance of no more than 0.01%.

Achievable:

This functionality can be implemented using existing financial data and reporting modules within the current system.

Relevant:

Providing net profit reports directly supports financial oversight and strategic decision-making.

Time-bound:

The net profit report functionality will be delivered and tested within one sprint (two weeks).


### Arrange:
1. Seed the database with relevant financial data (revenue and expenses) for the selected financial year.
2. Define the financial year for which the report is to be generated (e.g., 2023).
3. Mock any external dependencies or services used in the net profit calculation.

### Act:
1. Call the endpoint or method responsible for generating the net profit report for the specified financial year.
2. Store the returned report data (specifically the calculated net profit).

### Assert:
1. Assert that the response status code is 200 (OK).
2. Calculate the expected net profit manually based on the seeded revenue and expense data.
3. Assert that the calculated net profit from the report matches the expected net profit, allowing for a variance of no more than 0.01%.

Activity

  1. added this to the v2.0.0-alpha milestone on Dec 28, 2025
  2. nielsdrost7 commented on Jan 2, 2026

    @nielsdrost7
    CollaboratorAuthor

    @coderabbitai make pull-request with AAA test Scenario's: Arrange, Act, Assert. And also make sure you test edge cases

  3. coderabbitai commented on Jan 2, 2026

    @coderabbitai
    Contributor

    Rate Limit Exceeded

    @nielsdrost7 have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 43 seconds before sending another message.

  4. changed the title [-][Core] The user shall be able to produce a report with the net profit made in a financial year[/-] [+][Reports]: Report — Net Profit made in a financial year[/+] on Jun 13, 2026
  5. nielsdrost7 commented on Jul 16, 2026

    @nielsdrost7
    CollaboratorAuthor

    SMART Plan — Net Profit report for a financial year

    Context/Epic: Core (Reports) — part of epic #506

    Specific

    As a company admin, I want a net profit report for a selected financial year (revenue minus expenses). Current state: Modules\Payments\Models\Payment (payment_amount, paid_at, scopePaidBetween()) and Modules\Expenses\Models\Expense (expense_amount, expensed_at) are both company-scoped via BelongsToCompany and ready to aggregate from, but there is no NetProfitReportService (or any report service) anywhere in the codebase, and — more fundamentally — there is no "financial year" concept anywhere in this app: Company has no fiscal-year-start setting, so a "financial year" today can only mean a calendar year unless a new setting is added. The Report Builder scaffolding (Modules\Core\Enums\ReportBand, ReportDataSource, ReportFieldService) is unrelated to this — per #130's grounding, that entire area is orphaned scaffolding with no working builder behind it, so this issue needs its own standalone service, not an integration with it.

    Measurable

    • NetProfitReportService::generate($company, $year) sums payment income minus expense costs for the calendar year.
      • PHPUnit: it_calculates_net_profit_as_income_minus_expenses_for_the_year()
        #[Test]
        public function it_calculates_net_profit_as_income_minus_expenses_for_the_year(): void
        {
            /* Arrange */
            Payment::factory()->for($this->company)->create(['payment_amount' => 1000, 'paid_at' => '2026-03-01']);
            Expense::factory()->for($this->company)->create(['expense_amount' => 400, 'expensed_at' => '2026-04-01']);
    
            /* Act */
            $report = app(NetProfitReportService::class)->generate($this->company, 2026);
    
            /* Assert */
            $this->assertSame(600.0, $report->netProfit);
        }
    • Transactions outside the selected year are excluded.
      • PHPUnit: it_excludes_transactions_outside_the_selected_financial_year()
        #[Test]
        public function it_excludes_transactions_outside_the_selected_financial_year(): void
        {
            /* Arrange */
            Payment::factory()->for($this->company)->create(['payment_amount' => 1000, 'paid_at' => '2025-12-31']);
    
            /* Act */
            $report = app(NetProfitReportService::class)->generate($this->company, 2026);
    
            /* Assert */
            $this->assertSame(0.0, $report->income);
        }
    • Another company's income/expenses never leak into the figure (tenant isolation).
      • PHPUnit: it_does_not_include_another_companys_income_or_expenses()
        #[Test]
        public function it_does_not_include_another_companys_income_or_expenses(): void
        {
            /* Arrange */
            $otherCompany = Company::factory()->create();
            Payment::factory()->for($otherCompany)->create(['payment_amount' => 5000, 'paid_at' => '2026-01-01']);
    
            /* Act */
            $report = app(NetProfitReportService::class)->generate($this->company, 2026);
    
            /* Assert */
            $this->assertSame(0.0, $report->income);
        }
    • The report can be generated on demand from a company panel page.
      • Frontend/Livewire: As a company admin I want to pick a financial year and see net profit rendered so that I don't need to cross-reference invoices and expenses by hand.
        #[Test]
        public function user_can_generate_the_net_profit_report_for_a_chosen_year(): void
        {
            /* Arrange */
            Payment::factory()->for($this->company)->create(['payment_amount' => 1000, 'paid_at' => '2026-01-10']);
    
            /* Act */
            $component = Livewire::actingAs($this->user)
                ->test(NetProfitReportPage::class, ['tenant' => Str::lower($this->company->search_code)])
                ->call('generate', ['year' => 2026]);
    
            /* Assert */
            $component->assertSuccessful()->assertSet('netProfit', 1000.0);
        }

    Achievable

    1. New NetProfitReportService in Modules/Core/Services/ (or Modules/Payments/Services/, since it straddles Payments + Expenses) with generate(Company $company, int $year): NetProfitReportData, summing Payment::forCompany($company->id)->whereYear('paid_at', $year)->sum('payment_amount') minus the Expense equivalent.
    2. Confirm with the reporter whether "financial year" must support a configurable fiscal-year start (e.g. April–March) or whether calendar year is acceptable for v1 — no such setting exists on Company today, so this is a real scope decision, not an implementation detail.
    3. Build a dedicated Filament page for this report — there is currently no "Reports" navigation group in the company panel at all (see [Reports]: Reports module — v1 feature parity #145, which is building the sibling tabular-reports surface); either land alongside that work or add a minimal standalone page.
    4. Add PHPUnit coverage in Modules/Core/Tests/Feature/ (or Modules/Payments/Tests/Feature/).

    Relevant

    Net profit for a financial year is one of the most basic financial-oversight numbers a company admin needs; today it can only be reconstructed manually by cross-referencing the Payments and Expenses lists.

    Time-bound

    Sprint 7 — financial-year definition (calendar vs. configurable fiscal year) to be confirmed with the reporter before implementation starts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    refinedRefined with SMART plan / test suggestions

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions