Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ade7d8a
feat(company-resource): company resource, with policies/factory
RichardGL11 Aug 4, 2025
8a9db95
feat(company): making sure that slug company is unique when creating
RichardGL11 Aug 4, 2025
39296d7
refactor(NameInput): refactoring text input to NameInput
RichardGL11 Aug 4, 2025
21f4dfb
test(NameInput): name input is required
RichardGL11 Aug 4, 2025
d2647f9
test(NameInput): name input has max length 255 at default
RichardGL11 Aug 4, 2025
993209c
test(NameInput): testing default placeholder
RichardGL11 Aug 4, 2025
ae54d40
feat(Department-Resource): creating department model/resource/relatio…
RichardGL11 Aug 4, 2025
419eac6
feat(Department): creating department_users table/relationship
RichardGL11 Aug 4, 2025
2ee1399
fix: removing uuid for user and company models
RichardGL11 Aug 4, 2025
9631bce
refactor: refactoring timestamps columns to TimestampsColumns class
RichardGL11 Aug 4, 2025
95c4a37
feat(Create-Department): after create department, the manager should …
RichardGL11 Aug 4, 2025
7727e44
test(Create Department): it should be able to create a department
RichardGL11 Aug 4, 2025
bb43a91
test(CreateDepartment): department manager should be added to users r…
RichardGL11 Aug 4, 2025
388af52
feat(Report): creating report model, relationships with user/company,…
RichardGL11 Aug 5, 2025
f4d8865
feat(Report-Resource): creating resource for report
RichardGL11 Aug 5, 2025
9f40a10
feat(Category): creating category model, policy and factory
RichardGL11 Aug 5, 2025
ea047f3
feat(Category Resource): creating category resource
RichardGL11 Aug 5, 2025
ba1acd0
refactor: refactoring category and report form, changing text input f…
RichardGL11 Aug 5, 2025
060c779
test: it should create a report
RichardGL11 Aug 5, 2025
15a6c10
test(Report-Validations): testing report validations
RichardGL11 Aug 5, 2025
9cdf981
feat: adding reports relationship to company model
RichardGL11 Aug 5, 2025
ab0e5ec
test(List-Reports): listing reports test
RichardGL11 Aug 5, 2025
d561591
feat: splitting resources into separate groups
RichardGL11 Aug 5, 2025
5bb3e77
fix: fixing return type to users relationship
RichardGL11 Aug 5, 2025
2ab0054
feat(ExpenseResource): creating expense resource
RichardGL11 Aug 5, 2025
0144166
feat: adding relationships to user and company model
RichardGL11 Aug 5, 2025
284134c
test(Create-Expense): validation tests for expense creation
RichardGL11 Aug 7, 2025
b841187
refactor(Expense): refactoring file upload for expenses
RichardGL11 Aug 7, 2025
f162115
feat(Approval): Creating approval resource, policy, factory, enums
RichardGL11 Aug 7, 2025
df0e4ae
feat(ApproveReport-Page): wip approve report page
RichardGL11 Aug 7, 2025
949aec1
test(ApproveReportPage): should be able to approve or reject a report
RichardGL11 Aug 8, 2025
8af0011
test(ListReport): testing ApproveReport action on list report table
RichardGL11 Aug 8, 2025
22afbb5
test: fixing test for CreateApproval
RichardGL11 Aug 8, 2025
bdee14a
feat(Database Notifications): Database Notifications for admin panel
RichardGL11 Aug 8, 2025
a34aa84
feat(Notification): notifying report owner that report status was cha…
RichardGL11 Aug 8, 2025
a2c62ab
test: it should notify user that approval status was changed
RichardGL11 Aug 8, 2025
5198b16
feat(ChangeReportStatus): after creating an Approvals, the report sta…
RichardGL11 Aug 8, 2025
553e099
test(ChangeReportStatus): should update report status after creating …
RichardGL11 Aug 8, 2025
19275ef
refactor: refactoring attributes for ApprovalFactory
RichardGL11 Aug 8, 2025
5087927
feat: just icons for resources
RichardGL11 Aug 8, 2025
e85e3c9
feat: implementing HasColor and HasLabel interfaces for enum
RichardGL11 Aug 8, 2025
7be6e90
feat: changing main color at panel
RichardGL11 Aug 10, 2025
636ebd7
feat(Reimbursement): wip
RichardGL11 Aug 10, 2025
a7bc85b
feat: adding constrained to all migrations
RichardGL11 Aug 10, 2025
417d542
feat(Reimbursement): creating resource for reimbursement, wip
RichardGL11 Aug 11, 2025
3c966fc
feat(Reimbursement): making sure that only approved reports, and repo…
RichardGL11 Aug 11, 2025
3fe563f
test(Reimbursement): only reports that belongs to the company can be …
RichardGL11 Aug 11, 2025
c4bf36f
feat: changing icon for reimbursement resource
RichardGL11 Aug 11, 2025
9ecc2d8
refactor(CreateCompany): refactoring to creating slug automatically
RichardGL11 Aug 11, 2025
a453b31
refactor(Report): creating observer when changing status for submitted
RichardGL11 Aug 12, 2025
376cbd8
refactor(ExpenseForm): changing company relationship fields to Compan…
RichardGL11 Aug 12, 2025
4878e7c
refactor(DepartmentForm): refactoring fields to Company custom Select
RichardGL11 Aug 12, 2025
529ea9b
refactor(ApprovalForm): making sure that only loads information about…
RichardGL11 Aug 12, 2025
db87dfd
refactor(ReportForm): loading category related to company and fixing …
RichardGL11 Aug 13, 2025
9f0ee0a
feat(Report): adding total field to report model
RichardGL11 Aug 13, 2025
ef4e64c
feat(ReportsTable): adding filters to company, users, and status on R…
RichardGL11 Aug 13, 2025
8e95e2a
feat(ReimbursementsTable): adding filters to company, users through r…
RichardGL11 Aug 13, 2025
00623a1
feat(ExpensesTable): adding filters to company and for users
RichardGL11 Aug 13, 2025
c68ed98
feat(ExpensesTable): filter for category
RichardGL11 Aug 13, 2025
d275d1d
feat(ApprovalsTable): filter for approver, company and status
RichardGL11 Aug 13, 2025
1fa3668
test(ApprovalsTable): testing filters for company, status and user wh…
RichardGL11 Aug 14, 2025
fc8beca
refactor(Expense Media): refactoring to spatie media when uploading i…
RichardGL11 Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions app/Actions/Approval/CreateApprovalAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace App\Actions\Approval;

use App\DTOs\ApprovalDTO;
use App\Events\ApprovalStatusChangedEvent;
use App\Models\Approval;

final class CreateApprovalAction
{
public function execute(
ApprovalDTO $approval
): void {
Approval::query()->create([
'company_id' => $approval->companyId,
'report_id' => $approval->reportId,
'approver_id' => $approval->approverId,
'status' => $approval->status,
'level' => 'manager',
'comments' => $approval->comments,
'approved_at' => now(),
]);

ApprovalStatusChangedEvent::dispatch($approval->status, $approval->reportId);
}
}
34 changes: 34 additions & 0 deletions app/DTOs/ApprovalDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace App\DTOs;

use App\Enums\ApprovalStatus;

final readonly class ApprovalDTO
{
public function __construct(
public int $companyId,
public int $reportId,
public int $approverId,
public ApprovalStatus $status,
public string $comments
) {}

public static function make(
int $companyId,
int $reportId,
int $approverId,
ApprovalStatus $status,
string $comments
): self {
return new self(
companyId: $companyId,
reportId: $reportId,
approverId: $approverId,
status: $status,
comments: $comments
);
}
}
31 changes: 31 additions & 0 deletions app/Enums/ApprovalStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Filament\Support\Colors\Color;
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasLabel;

enum ApprovalStatus: string implements HasColor, HasLabel
{
case Approved = 'Approved';
case Rejected = 'Rejected';

public function getColor(): array
{
return match ($this) {
self::Approved => Color::Green,
self::Rejected => Color::Red,
};
}

public function getLabel(): string
{
return match ($this) {
self::Approved => 'Approved',
self::Rejected => 'Rejected',
};
}
}
37 changes: 37 additions & 0 deletions app/Enums/ReimbursementStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Filament\Support\Colors\Color;
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasLabel;

enum ReimbursementStatus: string implements HasColor, HasLabel
{
case Created = 'created';
case Approved = 'approved';
case Rejected = 'rejected';
case Refunded = 'refunded';

public function getColor(): array
{
return match ($this) {
self::Approved => Color::Green,
self::Rejected => Color::Red,
self::Created => Color::Blue,
self::Refunded => Color::Purple,
};
}

public function getLabel(): string
{
return match ($this) {
self::Approved => 'Approved',
self::Rejected => 'Rejected',
self::Created => 'Created',
self::Refunded => 'Refunded',
};
}
}
41 changes: 41 additions & 0 deletions app/Enums/ReportStatus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace App\Enums;

use Filament\Support\Colors\Color;
use Filament\Support\Contracts\HasColor;
use Filament\Support\Contracts\HasLabel;

enum ReportStatus: string implements HasColor, HasLabel
{
case Draft = 'draft';
case Submitted = 'submitted';
case Approved = 'approved';
case Rejected = 'rejected';
case Reimbursed = 'reimbursed';

public function getColor(): array
{
return match ($this) {
self::Draft => Color::Gray,
self::Submitted => Color::Blue,
self::Approved => Color::Emerald,
self::Rejected => Color::Red,
self::Reimbursed => Color::Purple,
};
}

public function getLabel(): string
{

return match ($this) {
self::Draft => 'Draft',
self::Submitted => 'Submitted',
self::Approved => 'Approved',
self::Rejected => 'Rejected',
self::Reimbursed => 'Reimbursed',
};
}
}
18 changes: 18 additions & 0 deletions app/Events/ApprovalStatusChangedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace App\Events;

use App\Enums\ApprovalStatus;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

final class ApprovalStatusChangedEvent
{
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
public function __construct(public ApprovalStatus $status, public int $reportId) {}
}
53 changes: 53 additions & 0 deletions app/Filament/Admin/Resources/Approvals/ApprovalResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

namespace App\Filament\Admin\Resources\Approvals;

use App\Filament\Admin\Resources\Approvals\Pages\CreateApproval;
use App\Filament\Admin\Resources\Approvals\Pages\EditApproval;
use App\Filament\Admin\Resources\Approvals\Pages\ListApprovals;
use App\Filament\Admin\Resources\Approvals\Schemas\ApprovalForm;
use App\Filament\Admin\Resources\Approvals\Tables\ApprovalsTable;
use App\Models\Approval;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use UnitEnum;

final class ApprovalResource extends Resource
{
protected static ?string $model = Approval::class;

protected static string|BackedEnum|null $navigationIcon = Heroicon::Banknotes;

protected static string|null|UnitEnum $navigationGroup = 'Financial';

public static function form(Schema $schema): Schema
{
return ApprovalForm::configure($schema);
}

public static function table(Table $table): Table
{
return ApprovalsTable::configure($table);
}

public static function getRelations(): array
{
return [
//
];
}

public static function getPages(): array
{
return [
'index' => ListApprovals::route('/'),
'create' => CreateApproval::route('/create'),
'edit' => EditApproval::route('/{record}/edit'),
];
}
}
21 changes: 21 additions & 0 deletions app/Filament/Admin/Resources/Approvals/Pages/CreateApproval.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace App\Filament\Admin\Resources\Approvals\Pages;

use App\Filament\Admin\Resources\Approvals\ApprovalResource;
use Filament\Resources\Pages\CreateRecord;

final class CreateApproval extends CreateRecord
{
protected static string $resource = ApprovalResource::class;

protected function mutateFormDataBeforeCreate(array $data): array
{
$data['approver_id'] = auth()->id();
$data['approved_at'] = now();

return $data;
}
}
21 changes: 21 additions & 0 deletions app/Filament/Admin/Resources/Approvals/Pages/EditApproval.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace App\Filament\Admin\Resources\Approvals\Pages;

use App\Filament\Admin\Resources\Approvals\ApprovalResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;

final class EditApproval extends EditRecord
{
protected static string $resource = ApprovalResource::class;

protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
21 changes: 21 additions & 0 deletions app/Filament/Admin/Resources/Approvals/Pages/ListApprovals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace App\Filament\Admin\Resources\Approvals\Pages;

use App\Filament\Admin\Resources\Approvals\ApprovalResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;

final class ListApprovals extends ListRecords
{
protected static string $resource = ApprovalResource::class;

protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
45 changes: 45 additions & 0 deletions app/Filament/Admin/Resources/Approvals/Schemas/ApprovalForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace App\Filament\Admin\Resources\Approvals\Schemas;

use App\Enums\ApprovalStatus;
use App\Enums\ReportStatus;
use App\Filament\Shared\Schemas\Form\CompanyDependentSelect;
use App\Models\Report;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;

final class ApprovalForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('company_id')
->relationship('company', 'name')
->required(),

CompanyDependentSelect::make('report_id', Report::class, 'title', 'status', ReportStatus::Submitted->value)
->label('Report')
->required(),

TextInput::make('level')
->required(),
Select::make('status')
->options(ApprovalStatus::class)
->enum(ApprovalStatus::class)
->required(),
TextInput::make('comments')
->required()
->minlength(3)
->maxLength(255),
DateTimePicker::make('approved_at')
->hidden()
->required(),
]);
}
}
Loading
Loading