Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
35.71% covered (danger)
35.71%
10 / 28
28.57% covered (danger)
28.57%
2 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
AccountCategoryController
35.71% covered (danger)
35.71%
10 / 28
28.57% covered (danger)
28.57%
2 / 7
30.52
0.00% covered (danger)
0.00%
0 / 1
 index
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 store
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 edit
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 destroy
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 validated
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Http\Controllers\admin;
4
5use App\Http\Controllers\Controller;
6use App\Models\AccountCategory;
7use App\Models\Transaction;
8use Illuminate\Http\RedirectResponse;
9use Illuminate\Http\Request;
10use Illuminate\View\View;
11
12/**
13 * Settings → Accounting → Categories. The Income/Expense tree a transaction
14 * is filed under (e.g. Sales, Service under income; Rent, Salary, Utilities
15 * under expense). "Sales" and "Purchase" are seeded on first use by
16 * AccountingSeeder-style lookups in the auto-post hooks — see
17 * OrderService/PurchaseController.
18 */
19class AccountCategoryController extends Controller
20{
21    public function index(): View
22    {
23        $categories = AccountCategory::query()->with('parent')->orderBy('type')->orderBy('name')->get();
24
25        return view('admin.accounting.categories.index', compact('categories'));
26    }
27
28    public function create(): View
29    {
30        return view('admin.accounting.categories.form', [
31            'category' => new AccountCategory(['type' => 'income', 'is_active' => true]),
32            'parents' => AccountCategory::query()->whereNull('parent_id')->get(),
33        ]);
34    }
35
36    public function store(Request $request): RedirectResponse
37    {
38        AccountCategory::create($this->validated($request));
39
40        return redirect()->route('admin.account-categories.index')->with('success', 'Category created.');
41    }
42
43    public function edit(AccountCategory $accountCategory): View
44    {
45        return view('admin.accounting.categories.form', [
46            'category' => $accountCategory,
47            'parents' => AccountCategory::query()->whereNull('parent_id')->where('id', '!=', $accountCategory->id)->get(),
48        ]);
49    }
50
51    public function update(Request $request, AccountCategory $accountCategory): RedirectResponse
52    {
53        $accountCategory->update($this->validated($request));
54
55        return redirect()->route('admin.account-categories.index')->with('success', 'Category updated.');
56    }
57
58    public function destroy(AccountCategory $accountCategory): RedirectResponse
59    {
60        if ($accountCategory->children()->exists()) {
61            return back()->with('error', 'This category has sub-categories — remove those first.');
62        }
63
64        if (Transaction::where('category_id', $accountCategory->id)->exists()) {
65            return back()->with('error', 'This category has transactions posted against it and can\'t be deleted. Deactivate it instead.');
66        }
67
68        $accountCategory->delete();
69
70        return redirect()->route('admin.account-categories.index')->with('success', 'Category deleted.');
71    }
72
73    private function validated(Request $request): array
74    {
75        $data = $request->validate([
76            'name' => ['required', 'string', 'max:150'],
77            'type' => ['required', 'in:income,expense'],
78            'parent_id' => ['nullable', 'exists:account_categories,id'],
79            'is_active' => ['nullable', 'boolean'],
80        ]);
81
82        $data['is_active'] = $request->boolean('is_active');
83
84        return $data;
85    }
86}