From 923a383ec52fa6dcdade657a91024e8b3e015cff Mon Sep 17 00:00:00 2001 From: Darko Gjorgjijoski Date: Fri, 21 Aug 2026 10:51:26 +0200 Subject: [PATCH] chore(reporting): remove legacy-era reporting sources --- .../Company/DashboardController.php | 165 ------------------ .../Controllers/Company/SearchController.php | 50 ------ .../CustomerSalesReportController.php | 99 ----------- .../Controllers/ExpensesReportController.php | 98 ----------- .../Controllers/ItemSalesReportController.php | 85 --------- .../ProfitLossReportController.php | 92 ---------- .../TaxSummaryReportController.php | 96 ---------- .../Reporting/Policies/DashboardPolicy.php | 22 --- .../Reporting/Policies/ReportPolicy.php | 22 --- 9 files changed, 729 deletions(-) delete mode 100644 app/Domains/Reporting/Http/Controllers/Company/DashboardController.php delete mode 100644 app/Domains/Reporting/Http/Controllers/Company/SearchController.php delete mode 100644 app/Domains/Reporting/Http/Controllers/CustomerSalesReportController.php delete mode 100644 app/Domains/Reporting/Http/Controllers/ExpensesReportController.php delete mode 100644 app/Domains/Reporting/Http/Controllers/ItemSalesReportController.php delete mode 100644 app/Domains/Reporting/Http/Controllers/ProfitLossReportController.php delete mode 100644 app/Domains/Reporting/Http/Controllers/TaxSummaryReportController.php delete mode 100644 app/Domains/Reporting/Policies/DashboardPolicy.php delete mode 100644 app/Domains/Reporting/Policies/ReportPolicy.php diff --git a/app/Domains/Reporting/Http/Controllers/Company/DashboardController.php b/app/Domains/Reporting/Http/Controllers/Company/DashboardController.php deleted file mode 100644 index 0eea67dd..00000000 --- a/app/Domains/Reporting/Http/Controllers/Company/DashboardController.php +++ /dev/null @@ -1,165 +0,0 @@ -header('company')); - - $this->authorize('view dashboard', $company); - - $invoice_totals = []; - $expense_totals = []; - $receipt_totals = []; - $net_income_totals = []; - - $i = 0; - $months = []; - $monthCounter = 0; - $fiscalYear = CompanySetting::getSetting('fiscal_year', $request->header('company')); - $startDate = Carbon::now(); - $start = Carbon::now(); - $end = Carbon::now(); - $terms = explode('-', $fiscalYear); - $companyStartMonth = intval($terms[0]); - - if ($companyStartMonth <= $start->month) { - $startDate->month($companyStartMonth)->startOfMonth(); - $start->month($companyStartMonth)->startOfMonth(); - $end->month($companyStartMonth)->endOfMonth(); - } else { - $startDate->subYear()->month($companyStartMonth)->startOfMonth(); - $start->subYear()->month($companyStartMonth)->startOfMonth(); - $end->subYear()->month($companyStartMonth)->endOfMonth(); - } - - if ($request->has('previous_year')) { - $startDate->subYear()->startOfMonth(); - $start->subYear()->startOfMonth(); - $end->subYear()->endOfMonth(); - } - - while ($monthCounter < 12) { - $invoice_totals[] = Invoice::whereBetween( - 'invoice_date', - [$start->format('Y-m-d'), $end->format('Y-m-d')] - ) - ->whereCompany() - ->sum('base_total'); - $expense_totals[] = Expense::whereBetween( - 'expense_date', - [$start->format('Y-m-d'), $end->format('Y-m-d')] - ) - ->whereCompany() - ->sum('base_amount'); - $receipt_totals[] = Payment::whereBetween( - 'payment_date', - [$start->format('Y-m-d'), $end->format('Y-m-d')] - ) - ->whereCompany() - ->sum('base_amount'); - $net_income_totals[] = ($receipt_totals[$i] - $expense_totals[$i]); - $i++; - $months[] = $start->translatedFormat('M'); - $monthCounter++; - $end->startOfMonth(); - $start->addMonth()->startOfMonth(); - $end->addMonth()->endOfMonth(); - } - - $start->subMonth()->endOfMonth(); - - $total_sales = Invoice::whereBetween( - 'invoice_date', - [$startDate->format('Y-m-d'), $start->format('Y-m-d')] - ) - ->whereCompany() - ->sum('base_total'); - - $total_receipts = Payment::whereBetween( - 'payment_date', - [$startDate->format('Y-m-d'), $start->format('Y-m-d')] - ) - ->whereCompany() - ->sum('base_amount'); - - $total_expenses = Expense::whereBetween( - 'expense_date', - [$startDate->format('Y-m-d'), $start->format('Y-m-d')] - ) - ->whereCompany() - ->sum('base_amount'); - - $total_net_income = (int) $total_receipts - (int) $total_expenses; - - $chart_data = [ - 'months' => $months, - 'invoice_totals' => $invoice_totals, - 'expense_totals' => $expense_totals, - 'receipt_totals' => $receipt_totals, - 'net_income_totals' => $net_income_totals, - ]; - - $total_customer_count = Customer::whereCompany()->count(); - // "How many invoices did we issue" counts issued documents, so the - // reversals are excluded. The sums above deliberately keep them: a - // credit note's negated total is exactly what nets sales back out. - $total_invoice_count = Invoice::whereCompany() - ->where('type', Invoice::TYPE_INVOICE) - ->count(); - $total_estimate_count = Estimate::whereCompany()->count(); - $total_amount_due = Invoice::whereCompany() - ->sum('base_due_amount'); - - // Raw models, not InvoiceResource: every loaded relation is serialized - // with the full $appends set, so a column-limited creditNotes load blew - // up in the date accessors (no company_id on the children) and a full - // load would run the appends per credit note for nothing. The rows do - // not need the relation: credited_status is a resource-level field, and - // a fully credited invoice has no due amount so it never appears here. - $recent_due_invoices = Invoice::with('customer') - ->whereCompany() - ->where('base_due_amount', '>', 0) - ->take(5) - ->latest() - ->get(); - $recent_estimates = Estimate::with('customer')->whereCompany()->take(5)->latest()->get(); - - return response()->json([ - 'total_amount_due' => $total_amount_due, - 'total_customer_count' => $total_customer_count, - 'total_invoice_count' => $total_invoice_count, - 'total_estimate_count' => $total_estimate_count, - - 'recent_due_invoices' => BouncerFacade::can('view-invoice', Invoice::class) ? $recent_due_invoices : [], - 'recent_estimates' => BouncerFacade::can('view-estimate', Estimate::class) ? $recent_estimates : [], - - 'chart_data' => $chart_data, - - 'total_sales' => $total_sales, - 'total_receipts' => $total_receipts, - 'total_expenses' => $total_expenses, - 'total_net_income' => $total_net_income, - ]); - } -} diff --git a/app/Domains/Reporting/Http/Controllers/Company/SearchController.php b/app/Domains/Reporting/Http/Controllers/Company/SearchController.php deleted file mode 100644 index a78311b7..00000000 --- a/app/Domains/Reporting/Http/Controllers/Company/SearchController.php +++ /dev/null @@ -1,50 +0,0 @@ -user(); - - $customers = Customer::applyFilters($request->only(['search'])) - ->whereCompany() - ->latest() - ->paginate(10); - - if ($user->isOwner()) { - $users = User::whereCompany() - ->applyFilters($request->only(['search'])) - ->latest() - ->paginate(10); - } - - return response()->json([ - 'customers' => $customers, - 'users' => $users ?? [], - ]); - } - - public function users(Request $request) - { - $this->authorize('create', User::class); - - $users = User::whereEmail($request->email) - ->latest() - ->paginate(10); - - return response()->json(['users' => $users]); - } -} diff --git a/app/Domains/Reporting/Http/Controllers/CustomerSalesReportController.php b/app/Domains/Reporting/Http/Controllers/CustomerSalesReportController.php deleted file mode 100644 index 66d672d8..00000000 --- a/app/Domains/Reporting/Http/Controllers/CustomerSalesReportController.php +++ /dev/null @@ -1,99 +0,0 @@ -firstOrFail(); - - // These routes carry no company header, so ScopeBouncer is not in their - // middleware stack and the ability scope was never set. 'view-financial-reports' - // is stored scoped to a company, so the unscoped check always failed and every - // report PDF answered 403. Scope to the company named in the URL: the policy - // still checks membership, so this grants nothing new. - BouncerFacade::scope()->to($company->id); - - $this->authorize('view report', $company); - - $locale = CompanySetting::getSetting('language', $company->id); - - App::setLocale($locale); - - $start = Carbon::createFromFormat('Y-m-d', $request->from_date); - $end = Carbon::createFromFormat('Y-m-d', $request->to_date); - - $customers = Customer::with(['invoices' => function ($query) use ($start, $end) { - $query->whereBetween( - 'invoice_date', - [$start->format('Y-m-d'), $end->format('Y-m-d')] - ); - }]) - ->where('company_id', $company->id) - ->applyInvoiceFilters($request->only(['from_date', 'to_date'])) - ->get(); - - $totalAmount = 0; - foreach ($customers as $customer) { - $customerTotalAmount = 0; - foreach ($customer->invoices as $invoice) { - $customerTotalAmount += $invoice->base_total; - } - $customer->totalAmount = $customerTotalAmount; - $totalAmount += $customerTotalAmount; - } - - $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); - $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat); - $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat); - $currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id)); - - view()->share([ - 'customers' => $customers, - 'totalAmount' => $totalAmount, - 'company' => $company, - 'logo' => $company->logo_path, - 'from_date' => $from_date, - 'to_date' => $to_date, - 'currency' => $currency, - ]); - - // Renders a same-named file from storage/app/templates/pdf/reports/ - // when one exists, so a report can be overridden without a - // template picker it has no concept of. - $templatePath = PdfTemplateUtils::resolveView('reports', 'sales-customers'); - - $pdf = Pdf::loadView($templatePath, [], PdfPageSetup::forReports()); - - if ($request->has('preview')) { - return view($templatePath); - } - - if ($request->has('download')) { - return $pdf->download(); - } - - return $pdf->stream(); - } -} diff --git a/app/Domains/Reporting/Http/Controllers/ExpensesReportController.php b/app/Domains/Reporting/Http/Controllers/ExpensesReportController.php deleted file mode 100644 index 242c7551..00000000 --- a/app/Domains/Reporting/Http/Controllers/ExpensesReportController.php +++ /dev/null @@ -1,98 +0,0 @@ -firstOrFail(); - - // These routes carry no company header, so ScopeBouncer is not in their - // middleware stack and the ability scope was never set. 'view-financial-reports' - // is stored scoped to a company, so the unscoped check always failed and every - // report PDF answered 403. Scope to the company named in the URL: the policy - // still checks membership, so this grants nothing new. - BouncerFacade::scope()->to($company->id); - - $this->authorize('view report', $company); - - $locale = CompanySetting::getSetting('language', $company->id); - - App::setLocale($locale); - - // Fetch individual expenses (filtered and ordered by date), then group by category - $expenses = Expense::with('category') - ->whereCompanyId($company->id) - ->applyFilters($request->only(['from_date', 'to_date', 'expense_category_id'])) - ->orderBy('expense_date', 'asc') - ->get(); - - $totalAmount = $expenses->sum('base_amount'); - - $grouped = $expenses->groupBy(function ($item) { - return $item->category ? $item->category->name : trans('expenses.uncategorized'); - }); - - $expenseGroups = collect(); - foreach ($grouped as $categoryName => $group) { - $expenseGroups->push([ - 'name' => $categoryName, - 'expenses' => $group, - 'total' => $group->sum('base_amount'), - ]); - } - - $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); - $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat); - $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat); - $currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id)); - - view()->share([ - 'expenseGroups' => $expenseGroups, - 'totalExpense' => $totalAmount, - 'company' => $company, - 'logo' => $company->logo_path, - 'from_date' => $from_date, - 'to_date' => $to_date, - 'currency' => $currency, - ]); - // Renders a same-named file from storage/app/templates/pdf/reports/ - // when one exists, so a report can be overridden without a - // template picker it has no concept of. - $templatePath = PdfTemplateUtils::resolveView('reports', 'expenses'); - - $pdf = Pdf::loadView($templatePath, [], PdfPageSetup::forReports()); - - if ($request->has('preview')) { - return view($templatePath); - } - - if ($request->has('download')) { - return $pdf->download(); - } - - return $pdf->stream(); - } -} diff --git a/app/Domains/Reporting/Http/Controllers/ItemSalesReportController.php b/app/Domains/Reporting/Http/Controllers/ItemSalesReportController.php deleted file mode 100644 index 1cc9f9c2..00000000 --- a/app/Domains/Reporting/Http/Controllers/ItemSalesReportController.php +++ /dev/null @@ -1,85 +0,0 @@ -firstOrFail(); - - // These routes carry no company header, so ScopeBouncer is not in their - // middleware stack and the ability scope was never set. 'view-financial-reports' - // is stored scoped to a company, so the unscoped check always failed and every - // report PDF answered 403. Scope to the company named in the URL: the policy - // still checks membership, so this grants nothing new. - BouncerFacade::scope()->to($company->id); - - $this->authorize('view report', $company); - - $locale = CompanySetting::getSetting('language', $company->id); - - App::setLocale($locale); - - $items = InvoiceItem::whereCompany($company->id) - ->applyInvoiceFilters($request->only(['from_date', 'to_date'])) - ->itemAttributes() - ->get(); - - $totalAmount = 0; - foreach ($items as $item) { - $totalAmount += $item->total_amount; - } - - $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); - $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat); - $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat); - $currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id)); - - view()->share([ - 'items' => $items, - 'totalAmount' => $totalAmount, - 'company' => $company, - 'logo' => $company->logo_path, - 'from_date' => $from_date, - 'to_date' => $to_date, - 'currency' => $currency, - ]); - // Renders a same-named file from storage/app/templates/pdf/reports/ - // when one exists, so a report can be overridden without a - // template picker it has no concept of. - $templatePath = PdfTemplateUtils::resolveView('reports', 'sales-items'); - - $pdf = Pdf::loadView($templatePath, [], PdfPageSetup::forReports()); - - if ($request->has('preview')) { - return view($templatePath); - } - - if ($request->has('download')) { - return $pdf->download(); - } - - return $pdf->stream(); - } -} diff --git a/app/Domains/Reporting/Http/Controllers/ProfitLossReportController.php b/app/Domains/Reporting/Http/Controllers/ProfitLossReportController.php deleted file mode 100644 index 98859f97..00000000 --- a/app/Domains/Reporting/Http/Controllers/ProfitLossReportController.php +++ /dev/null @@ -1,92 +0,0 @@ -firstOrFail(); - - // These routes carry no company header, so ScopeBouncer is not in their - // middleware stack and the ability scope was never set. 'view-financial-reports' - // is stored scoped to a company, so the unscoped check always failed and every - // report PDF answered 403. Scope to the company named in the URL: the policy - // still checks membership, so this grants nothing new. - BouncerFacade::scope()->to($company->id); - - $this->authorize('view report', $company); - - $locale = CompanySetting::getSetting('language', $company->id); - - App::setLocale($locale); - - $paymentsAmount = Payment::whereCompanyId($company->id) - ->applyFilters($request->only(['from_date', 'to_date'])) - ->sum('base_amount'); - - $expenseCategories = Expense::with('category') - ->whereCompanyId($company->id) - ->applyFilters($request->only(['from_date', 'to_date'])) - ->expensesAttributes() - ->get(); - - $totalAmount = 0; - foreach ($expenseCategories as $category) { - $totalAmount += $category->total_amount; - } - - $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); - $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat); - $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat); - $currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id)); - - view()->share([ - 'income' => $paymentsAmount, - 'expenseCategories' => $expenseCategories, - 'totalExpense' => $totalAmount, - 'company' => $company, - 'logo' => $company->logo_path, - 'from_date' => $from_date, - 'to_date' => $to_date, - 'currency' => $currency, - ]); - // Renders a same-named file from storage/app/templates/pdf/reports/ - // when one exists, so a report can be overridden without a - // template picker it has no concept of. - $templatePath = PdfTemplateUtils::resolveView('reports', 'profit-loss'); - - $pdf = Pdf::loadView($templatePath, [], PdfPageSetup::forReports()); - - if ($request->has('preview')) { - return view($templatePath); - } - - if ($request->has('download')) { - return $pdf->download(); - } - - return $pdf->stream(); - } -} diff --git a/app/Domains/Reporting/Http/Controllers/TaxSummaryReportController.php b/app/Domains/Reporting/Http/Controllers/TaxSummaryReportController.php deleted file mode 100644 index 2cc54071..00000000 --- a/app/Domains/Reporting/Http/Controllers/TaxSummaryReportController.php +++ /dev/null @@ -1,96 +0,0 @@ -firstOrFail(); - - // These routes carry no company header, so ScopeBouncer is not in their - // middleware stack and the ability scope was never set. 'view-financial-reports' - // is stored scoped to a company, so the unscoped check always failed and every - // report PDF answered 403. Scope to the company named in the URL: the policy - // still checks membership, so this grants nothing new. - BouncerFacade::scope()->to($company->id); - - $this->authorize('view report', $company); - - $locale = CompanySetting::getSetting('language', $company->id); - - App::setLocale($locale); - - $taxTypes = Tax::with('taxType') - ->whereCompany($company->id) - ->whereInvoicesFilters($request->only(['from_date', 'to_date'])) - ->taxAttributes() - ->get(); - - $totalAmount = (int) $taxTypes->sum('total_tax_amount'); - - $expenseTaxTypes = Tax::with('taxType') - ->whereCompany($company->id) - ->whereExpensesFilters($request->only(['from_date', 'to_date'])) - ->taxAttributes() - ->get(); - - $totalExpenseTaxAmount = (int) $expenseTaxTypes->sum('total_tax_amount'); - $netTaxAmount = $totalAmount - $totalExpenseTaxAmount; - - $dateFormat = CompanySetting::getSetting('carbon_date_format', $company->id); - $from_date = Carbon::createFromFormat('Y-m-d', $request->from_date)->translatedFormat($dateFormat); - $to_date = Carbon::createFromFormat('Y-m-d', $request->to_date)->translatedFormat($dateFormat); - $currency = Currency::findOrFail(CompanySetting::getSetting('currency', $company->id)); - - view()->share([ - 'taxTypes' => $taxTypes, - 'totalTaxAmount' => $totalAmount, - 'expenseTaxTypes' => $expenseTaxTypes, - 'totalExpenseTaxAmount' => $totalExpenseTaxAmount, - 'netTaxAmount' => $netTaxAmount, - 'company' => $company, - 'logo' => $company->logo_path, - 'from_date' => $from_date, - 'to_date' => $to_date, - 'currency' => $currency, - ]); - - // Renders a same-named file from storage/app/templates/pdf/reports/ - // when one exists, so a report can be overridden without a - // template picker it has no concept of. - $templatePath = PdfTemplateUtils::resolveView('reports', 'tax-summary'); - - $pdf = Pdf::loadView($templatePath, [], PdfPageSetup::forReports()); - - if ($request->has('preview')) { - return view($templatePath); - } - - if ($request->has('download')) { - return $pdf->download(); - } - - return $pdf->stream(); - } -} diff --git a/app/Domains/Reporting/Policies/DashboardPolicy.php b/app/Domains/Reporting/Policies/DashboardPolicy.php deleted file mode 100644 index b5408f91..00000000 --- a/app/Domains/Reporting/Policies/DashboardPolicy.php +++ /dev/null @@ -1,22 +0,0 @@ -hasCompany($company->id)) { - return true; - } - - return false; - } -} diff --git a/app/Domains/Reporting/Policies/ReportPolicy.php b/app/Domains/Reporting/Policies/ReportPolicy.php deleted file mode 100644 index 16e264e4..00000000 --- a/app/Domains/Reporting/Policies/ReportPolicy.php +++ /dev/null @@ -1,22 +0,0 @@ -hasCompany($company->id)) { - return true; - } - - return false; - } -}