Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
152 commits
Select commit Hold shift + click to select a range
4904fa6
feat(erp): Phase 1 — ERP foundations, React setup & authentication
claude May 24, 2026
7617c25
feat(erp): Phase 2 — Inventory module (backend + frontend)
claude May 29, 2026
c6eb117
chore: ignore .claude/ session directory
claude May 29, 2026
63df94d
feat(erp): Phase 3 — Finance module (backend + frontend)
claude May 29, 2026
e5a3705
feat(erp): Phase 4 — HR module, User Management, and Live Dashboard
claude May 29, 2026
aa2b2c2
feat(erp): Phase 5 — Analytics, Notifications, Audit Log & Settings
claude May 29, 2026
00ed26a
feat: Phase 6 — Global Search, CSV Export, Printable Invoice
claude May 29, 2026
a5988af
feat: Phase 7 partial — extract Invoice traits + bills migrations
claude May 30, 2026
0e65d5c
feat: Phase 7 — Accounts Payable (Bills) + Financial Statements
claude May 30, 2026
7759bc3
fix: Phase 7 review fixes — bill payment guard + test hardening
claude May 30, 2026
357e671
feat: Phase 8 — Aged Reports, Account Ledger, PO Receive UI, Stock Hi…
claude May 30, 2026
196e519
feat: Phase 9 WIP — Quotes models, policy, and migrations
claude May 31, 2026
78b8a85
feat: Phase 9 — Quotes (Estimates) module
claude May 31, 2026
cef9cc1
feat: Phase 10 WIP — Credit Notes backend (models, policy, controller…
claude May 31, 2026
ec75800
feat: Phase 10 — Credit Notes module + Customer Statement report
claude May 31, 2026
60ac948
feat: Phase 11 — Recurring Invoices with scheduled generation
claude May 31, 2026
ff3acb8
feat: Phase 12 — Sales Orders (fulfillment + invoice conversion)
claude May 31, 2026
d5e54a8
feat: Phase 13 (partial) — install dompdf and add PDF styles partial
claude May 31, 2026
99663dc
feat: Phase 13 — PDF generation and email delivery for invoices, quot…
claude May 31, 2026
f68f993
chore: add recharts dependency for dashboard charts
claude May 31, 2026
40b5027
feat: Phase 14 — Dashboard with KPI cards, revenue chart, and invento…
claude May 31, 2026
f5ee733
feat: Phase 15 — HR module (Employees, Departments, Leave Requests, P…
claude May 31, 2026
dba10ff
feat: Phase 16 — Multi-currency support with exchange rates
claude Jun 1, 2026
a4c0c62
feat: Phase 17 — Bank Reconciliation with CSV import and transaction …
claude Jun 1, 2026
d522d9b
feat: Phase 18 — Tax/VAT Return report
claude Jun 1, 2026
eb37e2c
feat: Phase 19 — User Management UI (invite, roles, activate/deactivate)
claude Jun 1, 2026
9ba6746
feat: Phase 20 — Company Settings (profile, currency, timezone, logo)
claude Jun 1, 2026
ec86ca7
feat: Phase 21 — CSV exports for all financial reports
claude Jun 1, 2026
413393f
feat: Phase 22 — Warehouse transfers with stock movement tracking
claude Jun 1, 2026
43386ad
feat: Phase 23 — Audit Log viewer with event and model filters
claude Jun 1, 2026
75749b2
feat: Phase 24 — In-app notifications for overdue invoices, low stock…
claude Jun 1, 2026
265728b
feat: Phase 25 — Employee Expense Claims (submit, approve, reject, re…
claude Jun 1, 2026
2c266dc
feat: Phase 26 — Budget Management with variance reporting
claude Jun 1, 2026
8625603
feat: Phase 27 — Fixed Assets register with straight-line depreciation
claude Jun 1, 2026
1086366
chore: ignore .env.bak files
claude Jun 1, 2026
a041bc8
feat: Phase 28 — Product Categories with colour badges and product fi…
claude Jun 1, 2026
06d55be
feat: Phase 29 — Reorder points with low-stock suggestions and one-cl…
claude Jun 1, 2026
f921e31
feat: Phase 30 — Price Lists with product overrides and global discounts
claude Jun 1, 2026
d756b71
feat: Phase 31 — Project Tracking with billable hours and invoice lin…
claude Jun 1, 2026
35b0d90
feat: Phase 32 — File Attachments for invoices, bills, expenses, and …
claude Jun 1, 2026
33ce8f9
feat: Phase 33 — Credit Notes for invoices and bills
claude Jun 2, 2026
66c543c
feat: Phase 34 — Recurring Invoices with auto-generation
claude Jun 2, 2026
e191fa0
feat: Phase 35 — Aged Receivables and Payables reports
claude Jun 2, 2026
44b1fbf
feat: Phase 36 — Inventory Adjustments for stock count corrections
claude Jun 3, 2026
7767ef9
feat: Phase 37 — Cash Flow Forecast report
claude Jun 3, 2026
8cd0ce5
feat: Phase 38 — Purchase Requisitions with approval workflow
claude Jun 3, 2026
60a728c
feat: Phase 39 — Batch Payments for invoices and bills
claude Jun 3, 2026
142bad4
feat: Phase 40 — Sales Orders with invoice conversion
claude Jun 3, 2026
abc465a
feat: Phase 41 — Delivery Notes linked to sales orders and invoices
claude Jun 3, 2026
f6cb966
feat: Phase 42 — Customer Statements with PDF export
claude Jun 3, 2026
71d4a2f
feat: Phase 43 — Supplier Statements report
claude Jun 3, 2026
d6550e7
feat: Phase 44 — Comparative Profit and Loss report
claude Jun 3, 2026
3d9073c
feat: Phase 45 — Employee Onboarding Checklists
claude Jun 3, 2026
04a8a31
feat: Phase 46 — Performance Reviews with ratings and goals
claude Jun 4, 2026
c3bfbaa
feat: Phase 47 — Training Records and certifications
claude Jun 4, 2026
a2c9e75
feat(hr): Phase 48 — Job Positions & Recruitment Pipeline
claude Jun 4, 2026
53aa649
feat(hr): Phase 49 — Time & Attendance tracking
claude Jun 4, 2026
4d9bec1
chore: ignore .env.bak files
claude Jun 4, 2026
22e6598
feat(inventory): Phase 50 — Asset Management
claude Jun 4, 2026
f7bb222
feat(finance): Phase 51 — Vendor Management profiles and evaluations
claude Jun 4, 2026
494e728
feat(finance): Phase 52 — Customer Portal with token-based access
claude Jun 4, 2026
dfd2ae5
feat(finance): Phase 53 — Budget Management
claude Jun 4, 2026
5d42784
feat(finance): Phase 54 — Multi-Currency Exchange Rate Management
claude Jun 4, 2026
a24c6a8
feat(core): Phase 55 — Audit Log system-wide activity trail
claude Jun 4, 2026
368cf63
feat(core): Phase 56 — Notifications & Alerts inbox
claude Jun 4, 2026
8647dd3
feat(finance): Phase 57 — Document Templates with variable substitution
claude Jun 4, 2026
b857ea1
feat(inventory): Phase 58 — Product Bundles with component tracking
claude Jun 4, 2026
aeea5db
feat(inventory): Phase 59 — Multi-Location Inventory with stock trans…
claude Jun 4, 2026
1961bc9
feat(finance): Phase 60 — Subscription Billing with recurring invoice…
claude Jun 4, 2026
e0c4a0f
feat(finance): Phase 61 — Commission Tracking for sales reps
claude Jun 4, 2026
3d00f1d
feat(finance): Phase 62 — Contract Management
claude Jun 4, 2026
fc7e10f
feat(hr): Phase 63 — Loan & Advance Management
claude Jun 4, 2026
0f051a9
feat(inventory): Phase 64 — Quality Control with checklists and inspe…
claude Jun 4, 2026
c76c3d7
feat(finance): Phase 65 — Return & Refund Management
claude Jun 4, 2026
32957df
feat(inventory): Phase 66 — Inventory Costing (FIFO / Average Cost)
claude Jun 4, 2026
3669530
feat(hr): Phase 67 — HR Shift Scheduling with templates and assignments
claude Jun 4, 2026
cd005e2
feat(hr): Phase 68 — Expense Management with approval workflow
claude Jun 4, 2026
de9c1e9
feat(finance): Phase 69 — Price Lists & Customer Pricing with tiered …
claude Jun 4, 2026
7d867b3
feat(finance): Phase 70 — Tax Management with rates, groups, and comp…
claude Jun 4, 2026
d8dbf6d
feat(hr): Phase 71 — Performance Reviews with KPIs and achievement tr…
claude Jun 4, 2026
d0dc070
feat(finance): Phase 72 — Project Management with tasks and time trac…
claude Jun 4, 2026
6c5562d
feat(hr): Phase 73 — Payroll Processing with payslip generation
claude Jun 4, 2026
00df34d
feat(finance): Phase 74 — Service Agreements & Maintenance Contracts
claude Jun 4, 2026
56154ca
feat(inventory): Phase 75 — Demand Forecasting with moving average an…
claude Jun 4, 2026
4620da2
feat(inventory): Phase 76 — Warehouse Bin & Location Tracking with zones
claude Jun 4, 2026
f309372
feat(finance): Phase 77 — Customer Loyalty & Rewards with points and …
claude Jun 4, 2026
47e2b86
feat(finance): Phase 78 — CRM Leads Pipeline with activities and win/…
claude Jun 4, 2026
c6748fb
feat(inventory): Phase 79 — Product Variants & Attributes with SKU ma…
claude Jun 5, 2026
79ef28b
feat(finance): Phase 80 — Bank Reconciliation with accounts and trans…
claude Jun 5, 2026
887dba1
feat(hr): Phase 81 — Employee Onboarding Checklists with task tracking
claude Jun 5, 2026
d26f662
feat(finance): Phase 82 — Budget Planning & Variance Tracking
claude Jun 5, 2026
b95c8ee
feat(hr): Phase 83 — Employee Leave Management with approval workflow
claude Jun 5, 2026
1c8c85d
feat(hr): Phase 84 — Employee Training & Certifications
claude Jun 5, 2026
06e8036
feat(finance): Phase 85 — Multi-Currency Support with exchange rates
claude Jun 5, 2026
d7fff49
feat(inventory): Phase 86 — Fleet & Vehicle Management with trip logs
claude Jun 5, 2026
90d2afa
feat(finance): Phase 87 — Customer Support Ticketing with comments
claude Jun 5, 2026
e1fa812
feat(inventory): Phase 88 — Supplier Performance Tracking with review…
claude Jun 5, 2026
a309069
feat(hr): Phase 89 — Disciplinary Cases & Grievance Management
claude Jun 5, 2026
ac0f504
feat(inventory): Phase 90 — Lot & Serial Number Tracking with traceab…
claude Jun 5, 2026
921746a
feat(hr): Phase 91 — Timesheet Management with weekly entries and app…
claude Jun 5, 2026
fc7fb8c
feat(finance): Phase 92 — Contract Management with lifecycle and rene…
claude Jun 5, 2026
46db117
feat(core): Phase 93 — Audit Log & Activity Tracking
claude Jun 5, 2026
f177cdd
feat(hr): Phase 94 — Employee Benefits Administration
claude Jun 5, 2026
985f057
feat(inventory): Phase 95 — Purchase Order Management with receiving …
claude Jun 5, 2026
e422d7d
feat(hr): Phase 96 — Employee Performance Reviews with ratings and wo…
claude Jun 5, 2026
5c04833
feat(finance): Phase 97 — Expense Claims Management with approval wor…
claude Jun 5, 2026
9c603e5
feat(finance): Phase 97 — Expense Claims Management with approval wor…
claude Jun 5, 2026
f4dc210
feat(inventory): Phase 98 — Sales Order Management with fulfillment w…
claude Jun 5, 2026
3fb9455
feat(hr): Phase 99 — Job Positions & Recruitment Management
claude Jun 5, 2026
5d45942
feat(hr): Phase 100 — Work Schedules & Shift Management
claude Jun 5, 2026
6f78341
feat(inventory): Phase 101 — Product Price Lists & Customer Discounts
claude Jun 5, 2026
1efca99
feat(finance): Phase 102 — Vendor Bills & Accounts Payable
claude Jun 5, 2026
0d9f25f
feat(finance): Phase 103 — Credit Notes & Invoice Adjustments
claude Jun 5, 2026
ba020a4
feat(hr): Phase 104 — Employee Document Management
claude Jun 6, 2026
f1bc91d
feat(finance): Phase 105 — Payment Terms Management
claude Jun 6, 2026
4cfae70
feat(hr): Phase 106 — Employee Skills & Competency Tracking
claude Jun 6, 2026
00297a8
feat(hr): Phase 107 — HR Announcements & Company Notices
claude Jun 6, 2026
b2ff06d
feat(inventory): Phase 108 — Units of Measure Management
claude Jun 6, 2026
6756fa7
feat(hr): Phase 109 — Employee Exit Management
claude Jun 6, 2026
a6f3beb
feat(finance): Phase 110 — Petty Cash Management
claude Jun 6, 2026
dc5dcb2
feat(inventory): Phase 111 — Inventory Cycle Counting
claude Jun 6, 2026
64c0463
feat(hr): Phase 112 — Employee Position Changes & Promotions
claude Jun 6, 2026
fc2a1b4
feat(inventory): Phase 113 — Product Tags
claude Jun 6, 2026
14463e0
feat(finance): Phase 114 — Bank Transfers between Accounts
claude Jun 6, 2026
ce7308f
feat(hr): Phase 115 — Salary Grades & Pay Bands
claude Jun 6, 2026
7212d64
feat(finance): Phase 116 — Customer Groups & Segmentation
claude Jun 6, 2026
cc3c57a
feat(finance): Phase 117 — Advance Payments & Customer Deposits
claude Jun 6, 2026
0948e15
feat(inventory): Phase 118 — Product Substitutes & Alternatives
claude Jun 6, 2026
14012ea
feat(hr): Phase 119 — Overtime Requests & Approval
claude Jun 6, 2026
f26eae4
feat(finance): Phase 120 — Finance Debit Notes
claude Jun 6, 2026
0f5a8e8
feat(hr): Phase 121 — Employee Surveys & Pulse Checks
claude Jun 6, 2026
c399476
feat(inventory): Phase 122 — Inventory Backorder Management
claude Jun 6, 2026
555a749
feat(finance): Phase 123 — Finance Write-offs (Bad Debt)
claude Jun 6, 2026
a71f322
feat(hr): Phase 124 — HR Flexible Working Arrangements
claude Jun 6, 2026
ce39d39
feat(finance): Phase 125 — Finance Intercompany Transactions
claude Jun 6, 2026
4e3a969
feat(inventory): Phase 126 — Inventory Product Bundles
claude Jun 6, 2026
33f5ba6
feat(inventory): Phase 126 — Inventory Product Bundles (revised)
claude Jun 6, 2026
eb81f73
feat(hr): Phase 127 — HR Job Offer Letters
claude Jun 6, 2026
112d54e
feat(finance): Phase 128 — Finance Budget Management
claude Jun 6, 2026
5780308
feat(hr): Phase 129 — HR Training Sessions Calendar
claude Jun 6, 2026
444701a
feat(inventory): Phase 130 — Inventory Reorder Rules
claude Jun 6, 2026
1e6d2ea
feat(finance): Phase 131 — Finance Cash Flow Forecasting
claude Jun 6, 2026
376124a
Merge branch 'claude/erp-phase-1-foundations-9miE5' of http://127.0.0…
claude Jun 6, 2026
322017b
feat(hr): Phase 132 — HR Competency Frameworks
claude Jun 6, 2026
dd658a5
feat(inventory): Phase 133 — Inventory Supplier Scorecards
claude Jun 6, 2026
f67ff91
fix(finance): add missing migration and routes for Phase 131 Cash Flo…
claude Jun 6, 2026
730ee97
feat(finance): Phase 134 — Finance Recurring Expenses
claude Jun 6, 2026
939cc29
feat(hr): Phase 135 — HR Employee Goals & KPIs
claude Jun 6, 2026
2d3f857
feat(inventory): Phase 136 — Inventory Quality Alerts
claude Jun 6, 2026
d257d1e
feat(finance): Phase 137 — Finance Vendor Payments
claude Jun 6, 2026
8ee8604
feat(hr): Phase 138 — HR Succession Planning
claude Jun 6, 2026
6154a74
feat(hr): Phase 138 — HR Succession Planning
claude Jun 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ yarn-debug.log*
yarn-error.log*
/.changelog
.npm/
.claude/
.env.bak
*.env.bak
18 changes: 18 additions & 0 deletions erp/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2

[{compose,docker-compose}.{yml,yaml}]
indent_size = 4
65 changes: 65 additions & 0 deletions erp/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US

APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database

# PHP_CLI_SERVER_WORKERS=4

BCRYPT_ROUNDS=12

LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=

SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null

BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database

CACHE_STORE=database
# CACHE_PREFIX=

MEMCACHED_HOST=127.0.0.1

REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

VITE_APP_NAME="${APP_NAME}"
11 changes: 11 additions & 0 deletions erp/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
* text=auto eol=lf

*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php

/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore
28 changes: 28 additions & 0 deletions erp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
*.log
.DS_Store
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/.codex
/.cursor/
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/fonts-manifest.dev.json
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
_ide_helper.php
Homestead.json
Homestead.yaml
Thumbs.db
erp/.env.bak
2 changes: 2 additions & 0 deletions erp/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignore-scripts=true
audit=true
58 changes: 58 additions & 0 deletions erp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>

<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>

## About Laravel

Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:

- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).

Laravel is accessible, powerful, and provides tools required for large, robust applications.

## Learning Laravel

Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.

In addition, [Laracasts](https://laracasts.com) contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.

You can also watch bite-sized lessons with real-world projects on [Laravel Learn](https://laravel.com/learn), where you will be guided through building a Laravel application from scratch while learning PHP fundamentals.

## Agentic Development

Laravel's predictable structure and conventions make it ideal for AI coding agents like Claude Code, Cursor, and GitHub Copilot. Install [Laravel Boost](https://laravel.com/docs/ai) to supercharge your AI workflow:

```bash
composer require laravel/boost --dev

php artisan boost:install
```

Boost provides your agent 15+ tools and skills that help agents build Laravel applications while following best practices.

## Contributing

Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).

## Code of Conduct

In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).

## Security Vulnerabilities

If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.

## License

The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
47 changes: 47 additions & 0 deletions erp/app/Http/Controllers/Admin/AuditLogController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Modules\Core\Models\AuditLog;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

class AuditLogController extends Controller
{
public function index(Request $request): Response
{
$this->authorize('viewAny', User::class);

$logs = AuditLog::with('user')
->where('tenant_id', auth()->user()->tenant_id)
->when($request->event, fn ($q) => $q->where('event', $request->event))
->when($request->model, fn ($q) => $q->where('auditable_type', 'like', "%{$request->model}%"))
->latest()
->paginate(50)
->withQueryString()
->through(fn ($log) => [
'id' => $log->id,
'event' => $log->event,
'model' => class_basename($log->auditable_type),
'model_id' => $log->auditable_id,
'user' => $log->user?->name ?? 'System',
'old_values' => $log->old_values,
'new_values' => $log->new_values,
'ip_address' => $log->ip_address,
'created_at' => $log->created_at->diffForHumans(),
'created_at_raw' => $log->created_at->toDateTimeString(),
]);

return Inertia::render('Admin/AuditLog/Index', [
'logs' => $logs,
'filters' => $request->only(['event', 'model']),
'breadcrumbs' => [
['label' => 'Administration'],
['label' => 'Audit Log', 'href' => route('admin.audit-log.index')],
],
]);
}
}
139 changes: 139 additions & 0 deletions erp/app/Http/Controllers/Admin/UserController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
use Inertia\Inertia;
use Inertia\Response;
use Spatie\Permission\Models\Role;

class UserController extends Controller
{
public function index(Request $request): Response
{
$this->authorize('viewAny', User::class);

$users = User::with('roles')
->when($request->search, fn ($q) => $q->where('name', 'like', "%{$request->search}%")
->orWhere('email', 'like', "%{$request->search}%"))
->where('tenant_id', auth()->user()->tenant_id)
->orderBy('name')
->paginate(25)
->withQueryString();

return Inertia::render('Admin/Users/Index', [
'users' => $users->through(fn ($u) => [
'id' => $u->id,
'name' => $u->name,
'email' => $u->email,
'roles' => $u->roles->pluck('name'),
'created_at' => $u->created_at?->toDateString(),
]),
'filters' => $request->only(['search']),
'breadcrumbs' => [
['label' => 'Administration'],
['label' => 'Users', 'href' => route('admin.users.index')],
],
]);
}

public function create(): Response
{
$this->authorize('create', User::class);

return Inertia::render('Admin/Users/Create', [
'roles' => Role::orderBy('name')->pluck('name'),
'breadcrumbs' => [
['label' => 'Administration'],
['label' => 'Users', 'href' => route('admin.users.index')],
['label' => 'New User'],
],
]);
}

public function store(Request $request): RedirectResponse
{
$this->authorize('create', User::class);

$data = $request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
'password' => ['required', Password::defaults()],
'role' => ['required', 'string', 'exists:roles,name'],
]);

$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'tenant_id' => auth()->user()->tenant_id,
]);

$user->assignRole($data['role']);

return redirect()->route('admin.users.index')
->with('success', 'User created.');
}

public function edit(User $user): Response
{
$this->authorize('update', $user);

return Inertia::render('Admin/Users/Edit', [
'user' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'role' => $user->roles->first()?->name,
],
'roles' => Role::orderBy('name')->pluck('name'),
'breadcrumbs' => [
['label' => 'Administration'],
['label' => 'Users', 'href' => route('admin.users.index')],
['label' => $user->name . ' — Edit'],
],
]);
}

public function update(Request $request, User $user): RedirectResponse
{
$this->authorize('update', $user);

$data = $request->validate([
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', "unique:users,email,{$user->id}"],
'password' => ['nullable', Password::defaults()],
'role' => ['required', 'string', 'exists:roles,name'],
]);

$user->update([
'name' => $data['name'],
'email' => $data['email'],
...(($data['password'] ?? null) ? ['password' => Hash::make($data['password'])] : []),
]);

$user->syncRoles([$data['role']]);

return redirect()->route('admin.users.index')
->with('success', 'User updated.');
}

public function destroy(User $user): RedirectResponse
{
$this->authorize('delete', $user);

if ($user->id === auth()->id()) {
return back()->withErrors(['user' => 'You cannot delete your own account.']);
}

$user->delete();

return redirect()->route('admin.users.index')
->with('success', 'User deleted.');
}
}
Loading