Compare commits
2 Commits
97495f9991
...
782dbd4aaa
| Author | SHA1 | Date |
|---|---|---|
|
|
782dbd4aaa | 2 months ago |
|
|
b2e90078bb | 2 months ago |
301 changed files with 7428 additions and 272 deletions
@ -0,0 +1,21 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Calendar; |
|||
|
|||
use App\Domains\Academic\DTOs\Calendar\InitializeAcademicTermDTO; |
|||
use App\Domains\Academic\Models\Term; |
|||
|
|||
class InitializeAcademicTerm |
|||
{ |
|||
public function execute(InitializeAcademicTermDTO $dto): void |
|||
{ |
|||
Term::create([ |
|||
'name' => $dto->name, |
|||
'code' => $dto->code, |
|||
'year_study' => $dto->yearStudy, |
|||
'semester' => $dto->semester, |
|||
'date_start' => $dto->startDate, |
|||
'date_end' => $dto->endDate, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Calendar; |
|||
|
|||
use App\Domains\Academic\DTOs\Calendar\ModifyTermDTO; |
|||
use App\Domains\Academic\Models\Term; |
|||
|
|||
class ModifyTerm |
|||
{ |
|||
public function execute(Term $term, ModifyTermDTO $dto): void |
|||
{ |
|||
$term->update([ |
|||
'date_start' => $dto->startDate, |
|||
'date_end' => $dto->endDate, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Calendar; |
|||
|
|||
use App\Domains\Academic\DTOs\Calendar\ModifyTermDateDTO; |
|||
use App\Domains\Academic\Models\Term; |
|||
|
|||
class ModifyTermDate |
|||
{ |
|||
public function execute(Term $term, ModifyTermDateDTO $dto): void |
|||
{ |
|||
$term->update([ |
|||
'date_start' => $dto->startDate, |
|||
'date_end' => $dto->endDate, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Curriculum; |
|||
|
|||
use App\Domains\Academic\DTOs\Curriculum\AdjustStudyProgramDTO; |
|||
use App\Domains\Academic\Models\StudyProgram; |
|||
|
|||
class AdjustStudyProgramDetails |
|||
{ |
|||
public function execute(StudyProgram $studyProgram, AdjustStudyProgramDTO $dto): void |
|||
{ |
|||
$studyProgram->update([ |
|||
'level' => $dto->level, |
|||
'status' => $dto->status, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Curriculum; |
|||
|
|||
use App\Domains\Academic\DTOs\Curriculum\EstablishFacultyDTO; |
|||
use App\Domains\Academic\Models\Faculty; |
|||
|
|||
class EstablishFaculty |
|||
{ |
|||
public function execute(EstablishFacultyDTO $dto): void |
|||
{ |
|||
Faculty::create([ |
|||
'name' => $dto->name, |
|||
'code' => $dto->code, |
|||
'external_id' => $dto->externalId, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Curriculum; |
|||
|
|||
use App\Domains\Academic\DTOs\Curriculum\ModifyFacultyDetailsDTO; |
|||
use App\Domains\Academic\Models\Faculty; |
|||
|
|||
class ModifyFacultyDetails |
|||
{ |
|||
public function execute(Faculty $faculty, ModifyFacultyDetailsDTO $dto): void |
|||
{ |
|||
$faculty->update([ |
|||
'name' => $dto->name, |
|||
'code' => $dto->code, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Actions\Curriculum; |
|||
|
|||
use App\Domains\Academic\DTOs\Curriculum\RegisterStudyProgramDTO; |
|||
use App\Domains\Academic\Models\StudyProgram; |
|||
|
|||
class RegisterStudyProgram |
|||
{ |
|||
public function execute(RegisterStudyProgramDTO $dto): void |
|||
{ |
|||
StudyProgram::create([ |
|||
'name' => $dto->name, |
|||
'code' => $dto->code, |
|||
'level' => $dto->level, |
|||
'status' => $dto->status, |
|||
'faculty_id' => $dto->facultyId, |
|||
'external_id' => $dto->externalId, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Calendar; |
|||
|
|||
use Carbon\CarbonImmutable; |
|||
|
|||
readonly class InitializeAcademicTermDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code, |
|||
public string $yearStudy, |
|||
public string $semester, |
|||
public CarbonImmutable $startDate, |
|||
public CarbonImmutable $endDate, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Calendar; |
|||
|
|||
use Carbon\CarbonImmutable; |
|||
|
|||
readonly class ModifyTermDTO |
|||
{ |
|||
public function __construct( |
|||
public CarbonImmutable $startDate, |
|||
public CarbonImmutable $endDate, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Calendar; |
|||
|
|||
use Carbon\CarbonImmutable; |
|||
|
|||
readonly class ModifyTermDateDTO |
|||
{ |
|||
public function __construct( |
|||
public CarbonImmutable $startDate, |
|||
public CarbonImmutable $endDate, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Curriculum; |
|||
|
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
|
|||
readonly class AdjustStudyProgramDTO |
|||
{ |
|||
public function __construct( |
|||
public string $level, |
|||
public LifecycleStatus $status, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Curriculum; |
|||
|
|||
readonly class EstablishFacultyDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code, |
|||
public ?string $externalId = null |
|||
) {} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Curriculum; |
|||
|
|||
readonly class ModifyFacultyDetailsDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code |
|||
) {} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\DTOs\Curriculum; |
|||
|
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
|
|||
readonly class RegisterStudyProgramDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code, |
|||
public string $level, |
|||
public LifecycleStatus $status, |
|||
public int $facultyId, |
|||
public int $externalId, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Models; |
|||
|
|||
use App\Domains\Academic\Policies\FacultyPolicy; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
use Database\Factories\Academic\FacultyFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable(['name', 'code', 'status', 'external_id'])] |
|||
#[UsePolicy(FacultyPolicy::class)] |
|||
class Faculty extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'status' => LifecycleStatus::class, |
|||
]; |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return FacultyFactory::new(); |
|||
} |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Models; |
|||
|
|||
use App\Domains\Academic\Policies\StudyProgramPolicy; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
use Database\Factories\Academic\StudyProgramFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|||
|
|||
#[Fillable([ |
|||
'name', |
|||
'code', |
|||
'level', |
|||
'status', |
|||
'faculty_id', |
|||
'external_id', |
|||
])] |
|||
#[UsePolicy(StudyProgramPolicy::class)] |
|||
class StudyProgram extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'status' => LifecycleStatus::class, |
|||
]; |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return StudyProgramFactory::new(); |
|||
} |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
public function faculty(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(Faculty::class); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Models; |
|||
|
|||
use App\Domains\Academic\Policies\TermPolicy; |
|||
use Database\Factories\Academic\TermFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable(['name', 'code', 'year_study', 'semester', 'date_start', 'date_end'])] |
|||
#[UsePolicy(TermPolicy::class)] |
|||
class Term extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return TermFactory::new(); |
|||
} |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Policies; |
|||
|
|||
use App\Domains\Academic\Models\Faculty; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class FacultyPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('faculty.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, Faculty $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('faculty.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('faculty.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, Faculty $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('faculty.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, Faculty $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('faculty.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Policies; |
|||
|
|||
use App\Domains\Academic\Models\StudyProgram; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class StudyProgramPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('study-program.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, StudyProgram $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('study-program.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('study-program.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, StudyProgram $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('study-program.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, StudyProgram $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('study-program.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Policies; |
|||
|
|||
use App\Domains\Academic\Models\Term; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class TermPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('term.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, Term $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('term.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('term.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, Term $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('term.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, Term $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('term.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Providers; |
|||
|
|||
use App\Domains\System\Traits\Provider\RegistersDomainEvents; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class AcademicServiceProvider extends ServiceProvider |
|||
{ |
|||
use RegistersDomainEvents; |
|||
|
|||
protected array $listen = []; |
|||
|
|||
public function register(): void |
|||
{ |
|||
$this->app->register(RelationshipServiceProvider::class); |
|||
} |
|||
|
|||
public function boot(): void |
|||
{ |
|||
$this->registerEvents(); |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Academic\Providers; |
|||
|
|||
use App\Domains\Academic\Models\StudyProgram; |
|||
use App\Domains\Academic\Models\Term; |
|||
use App\Domains\Admission\Models\AdmissionSchedule; |
|||
use App\Domains\Admission\Models\FeeRate; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class RelationshipServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* Boot cross-domain runtime relationships. |
|||
* |
|||
* This provider is strictly dedicated to runtime, decoupled cross-domain |
|||
* relationship definitions. Use Model::resolveRelationUsing() here to wire |
|||
* explicit polymorphic or foreign-key macros between models that live in |
|||
* different domains — without introducing a hard compile-time dependency |
|||
* between those domains. |
|||
* |
|||
* Do NOT add route registrations, bindings, event listeners, or any other |
|||
* bootstrapping logic here. Keep this file focused on relationships only. |
|||
* |
|||
* Example: |
|||
* |
|||
* Order::resolveRelationUsing('customer', fn (Order $order) => |
|||
* $order->belongsTo(Customer::class, 'customer_id') |
|||
* ); |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
// Register cross-domain relationships below. |
|||
AdmissionSchedule::resolveRelationUsing('term', fn (AdmissionSchedule $admissionSchedule) => $admissionSchedule->belongsTo( |
|||
related: Term::class, |
|||
foreignKey: 'term_id' |
|||
)); |
|||
Term::resolveRelationUsing('admission_schedules', fn (Term $term) => $term->hasMany( |
|||
related: AdmissionSchedule::class, |
|||
foreignKey: 'term_id', |
|||
localKey: 'id' |
|||
)); |
|||
|
|||
FeeRate::resolveRelationUsing('study_program', fn (FeeRate $feeRate) => $feeRate->belongsTo( |
|||
related: StudyProgram::class, |
|||
foreignKey: 'study_program_id' |
|||
)); |
|||
StudyProgram::resolveRelationUsing('fee_rates', fn (StudyProgram $studyProgram) => $studyProgram->hasMany( |
|||
related: FeeRate::class, |
|||
foreignKey: 'study_program_id', |
|||
localKey: 'id' |
|||
)); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Actions\AdmissionPricing; |
|||
|
|||
use App\Domains\Admission\DTOs\AdmissionPricing\FeeTypeDTO; |
|||
use App\Domains\Admission\Models\FeeType; |
|||
|
|||
class DefineFeeType |
|||
{ |
|||
public function execute(FeeTypeDTO $dto): void |
|||
{ |
|||
FeeType::create([ |
|||
'name' => $dto->name, |
|||
'billing_cycle' => $dto->billingCycle, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Actions\AdmissionPricing; |
|||
|
|||
class SetUpAdmissionFeeRates |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Actions\IntakeScheduling; |
|||
|
|||
use App\Domains\Admission\DTOs\IntakeScheduling\AdjustAdmissionScheduleDurationDTO; |
|||
use App\Domains\Admission\Models\AdmissionSchedule; |
|||
|
|||
class AdjustAdmissionScheduleDuration |
|||
{ |
|||
public function execute(AdmissionSchedule $admissionSchedule, AdjustAdmissionScheduleDurationDTO $dto): void |
|||
{ |
|||
$admissionSchedule->update([ |
|||
'date_start' => $dto->startData, |
|||
'date_end' => $dto->endData, |
|||
're_registration_date_start' => $dto->reRegisterStartData, |
|||
're_registration_date_end' => $dto->reRegisterEndData, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Actions\IntakeScheduling; |
|||
|
|||
use App\Domains\Admission\DTOs\IntakeScheduling\PublishAdmissionScheduleDTO; |
|||
use App\Domains\Admission\Models\AdmissionSchedule; |
|||
|
|||
class PublishAdmissionSchedule |
|||
{ |
|||
public function execute(PublishAdmissionScheduleDTO $dto): void |
|||
{ |
|||
AdmissionSchedule::create([ |
|||
'date_start' => $dto->startData, |
|||
'date_end' => $dto->endData, |
|||
're_registration_date_start' => $dto->reRegisterStartData, |
|||
're_registration_date_end' => $dto->reRegisterEndData, |
|||
'status' => $dto->status, |
|||
'term_id' => $dto->termId, |
|||
'admission_track_id' => $dto->admissionTrackId, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Actions\IntakeSourcing; |
|||
|
|||
use App\Domains\Admission\DTOs\IntakeSourcing\InitializeAdmissionTrackDTO; |
|||
use App\Domains\Admission\Models\AdmissionTrack; |
|||
|
|||
class InitializeAdmissionTrack |
|||
{ |
|||
public function execute(InitializeAdmissionTrackDTO $dto): void |
|||
{ |
|||
AdmissionTrack::create([ |
|||
'name' => $dto->name, |
|||
'status' => $dto->status, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Actions\StudyModeProvisioning; |
|||
|
|||
use App\Domains\Admission\DTOs\StudyModeProvisioning\DefineAcademicProgramDTO; |
|||
use App\Domains\Admission\Models\AcademicProgram; |
|||
|
|||
class DefineAcademicProgram |
|||
{ |
|||
public function execute(DefineAcademicProgramDTO $dto): void |
|||
{ |
|||
AcademicProgram::create([ |
|||
'name' => $dto->name, |
|||
'code' => $dto->code, |
|||
'status' => $dto->status, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\DTOs\AdmissionPricing; |
|||
|
|||
readonly class AdmissionFeeRatesDTO |
|||
{ |
|||
public function __construct( |
|||
public int $termId, |
|||
public int $academicProgramId, |
|||
public int $admissionTrackId, |
|||
public int $feeTypeId, |
|||
public float $amount, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\DTOs\AdmissionPricing; |
|||
|
|||
readonly class FeeTypeDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $billingCycle |
|||
) {} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\DTOs\IntakeScheduling; |
|||
|
|||
use Carbon\CarbonImmutable; |
|||
|
|||
readonly class AdjustAdmissionScheduleDurationDTO |
|||
{ |
|||
public function __construct( |
|||
public CarbonImmutable $startData, |
|||
public CarbonImmutable $endData, |
|||
public CarbonImmutable $reRegisterStartData, |
|||
public CarbonImmutable $reRegisterEndData, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\DTOs\IntakeScheduling; |
|||
|
|||
use App\Domains\Admission\Enums\AdmissionStatus; |
|||
use Carbon\CarbonImmutable; |
|||
|
|||
readonly class PublishAdmissionScheduleDTO |
|||
{ |
|||
public function __construct( |
|||
public CarbonImmutable $startData, |
|||
public CarbonImmutable $endData, |
|||
public CarbonImmutable $reRegisterStartData, |
|||
public CarbonImmutable $reRegisterEndData, |
|||
public AdmissionStatus $status, |
|||
public int $termId, |
|||
public int $admissionTrackId |
|||
) {} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\DTOs\IntakeSourcing; |
|||
|
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
|
|||
readonly class InitializeAdmissionTrackDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public LifecycleStatus $status, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\DTOs\StudyModeProvisioning; |
|||
|
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
|
|||
readonly class DefineAcademicProgramDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code, |
|||
public LifecycleStatus $status, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
use App\UI\Enums\Contracts\HasUiBadge; |
|||
|
|||
enum AdmissionStatus: string implements HasLabel, HasUiBadge |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case PUBLISHED = 'published'; |
|||
case DRAFT = 'draft'; |
|||
case ARCHIVED = 'archived'; |
|||
|
|||
public function variant(): string |
|||
{ |
|||
return match ($this) { |
|||
self::PUBLISHED => 'success', |
|||
self::DRAFT => 'warning', |
|||
self::ARCHIVED => 'danger', |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
|
|||
enum BillingCycle: string implements HasLabel |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case ONCE = 'once'; |
|||
case MONTHLY = 'monthly'; |
|||
case SEMESTER = 'semester'; |
|||
case ANNUAL = 'annual'; |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Models; |
|||
|
|||
use App\Domains\Admission\Policies\AcademicProgramPolicy; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
use Database\Factories\Academic\AcademicProgramFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable(['code', 'name', 'status'])] |
|||
#[UsePolicy(AcademicProgramPolicy::class)] |
|||
class AcademicProgram extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'status' => LifecycleStatus::class, |
|||
]; |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return AcademicProgramFactory::new(); |
|||
} |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Models; |
|||
|
|||
use App\Domains\Admission\Policies\AdmissionSchedulePolicy; |
|||
use App\Domains\Admission\Enums\AdmissionStatus; |
|||
use Database\Factories\Admission\AdmissionScheduleFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|||
|
|||
#[Fillable([ |
|||
'date_start', |
|||
'date_end', |
|||
're_registration_date_start', |
|||
're_registration_date_end', |
|||
'admission_track_id', |
|||
'status', |
|||
'term_id', |
|||
])] |
|||
#[UsePolicy(AdmissionSchedulePolicy::class)] |
|||
class AdmissionSchedule extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'date_start' => 'date', |
|||
'date_end' => 'date', |
|||
're_registration_date_start' => 'date', |
|||
're_registration_date_end' => 'date', |
|||
'status' => AdmissionStatus::class, |
|||
]; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return AdmissionScheduleFactory::new(); |
|||
} |
|||
|
|||
public function admissionTrack(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(AdmissionTrack::class); |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Models; |
|||
|
|||
use App\Domains\Admission\Policies\AdmissionTrackPolicy; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
use App\Domains\System\Traits\Model\HasSlugs; |
|||
use Database\Factories\Admission\AdmissionTrackFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable(['name', 'slug', 'status'])] |
|||
#[UsePolicy(AdmissionTrackPolicy::class)] |
|||
class AdmissionTrack extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
use HasSlugs; |
|||
|
|||
protected $casts = [ |
|||
'status' => LifecycleStatus::class, |
|||
]; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return AdmissionTrackFactory::new(); |
|||
} |
|||
|
|||
public function sluggable(): string |
|||
{ |
|||
return 'name'; |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Models; |
|||
|
|||
use App\Domains\Admission\Policies\FeeRatePolicy; |
|||
use Database\Factories\Admission\FeeRateFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|||
|
|||
#[Fillable([ |
|||
'admission_schedule_id', |
|||
'academic_program_id', |
|||
'study_program_id', |
|||
'fee_type_id', |
|||
'amount', |
|||
])] |
|||
#[UsePolicy(FeeRatePolicy::class)] |
|||
class FeeRate extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return FeeRateFactory::new(); |
|||
} |
|||
|
|||
public function admissionSchedule(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(AdmissionSchedule::class); |
|||
} |
|||
|
|||
public function academicProgram(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(AcademicProgram::class); |
|||
} |
|||
|
|||
public function feeType(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(FeeType::class); |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Models; |
|||
|
|||
use App\Domains\Admission\Enums\BillingCycle; |
|||
use App\Domains\Admission\Policies\FeeTypePolicy; |
|||
use Database\Factories\Admission\FeeTypeFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable(['name', 'billing_cycle'])] |
|||
#[UsePolicy(FeeTypePolicy::class)] |
|||
class FeeType extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'billing_cycle' => BillingCycle::class, |
|||
]; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return FeeTypeFactory::new(); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Policies; |
|||
|
|||
use App\Domains\Admission\Models\AcademicProgram; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class AcademicProgramPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('academic-program.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, AcademicProgram $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('academic-program.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('academic-program.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, AcademicProgram $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('academic-program.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, AcademicProgram $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('academic-program.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Policies; |
|||
|
|||
use App\Domains\Admission\Models\AdmissionSchedule; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class AdmissionSchedulePolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-schedule.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, AdmissionSchedule $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-schedule.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-schedule.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, AdmissionSchedule $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-schedule.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, AdmissionSchedule $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-schedule.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Policies; |
|||
|
|||
use App\Domains\Admission\Models\AdmissionTrack; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class AdmissionTrackPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-track.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, AdmissionTrack $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-track.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-track.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, AdmissionTrack $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-track.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, AdmissionTrack $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('admission-track.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Policies; |
|||
|
|||
use App\Domains\Admission\Models\FeeRate; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class FeeRatePolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-rate.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, FeeRate $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-rate.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-rate.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, FeeRate $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-rate.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, FeeRate $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-rate.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Policies; |
|||
|
|||
use App\Domains\Admission\Models\FeeType; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class FeeTypePolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-type.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, FeeType $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-type.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-type.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, FeeType $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-type.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, FeeType $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('fee-type.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Providers; |
|||
|
|||
use App\Domains\System\Traits\Provider\RegistersDomainEvents; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class AdmissionServiceProvider extends ServiceProvider |
|||
{ |
|||
use RegistersDomainEvents; |
|||
|
|||
protected array $listen = []; |
|||
|
|||
public function register(): void |
|||
{ |
|||
$this->app->register(RelationshipServiceProvider::class); |
|||
} |
|||
|
|||
public function boot(): void |
|||
{ |
|||
$this->registerEvents(); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Admission\Providers; |
|||
|
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class RelationshipServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* Boot cross-domain runtime relationships. |
|||
* |
|||
* This provider is strictly dedicated to runtime, decoupled cross-domain |
|||
* relationship definitions. Use Model::resolveRelationUsing() here to wire |
|||
* explicit polymorphic or foreign-key macros between models that live in |
|||
* different domains — without introducing a hard compile-time dependency |
|||
* between those domains. |
|||
* |
|||
* Do NOT add route registrations, bindings, event listeners, or any other |
|||
* bootstrapping logic here. Keep this file focused on relationships only. |
|||
* |
|||
* Example: |
|||
* |
|||
* Order::resolveRelationUsing('customer', fn (Order $order) => |
|||
* $order->belongsTo(Customer::class, 'customer_id') |
|||
* ); |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
// Register cross-domain relationships below. |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Actions\AppProvisioning; |
|||
|
|||
use App\Domains\Channel\Models\Client; |
|||
|
|||
class DeauthorizConsumerApp |
|||
{ |
|||
public function execute(Client $client): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Actions\AppProvisioning; |
|||
|
|||
use App\Domains\Channel\Models\Client; |
|||
|
|||
class DeauthorizeConsumerApp |
|||
{ |
|||
public function execute(Client $client): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Actions\AppProvisioning; |
|||
|
|||
use App\Domains\Channel\DTOs\AppProvisioning\ProvisionConsumerAppDTO; |
|||
use App\Domains\Channel\Models\Client; |
|||
|
|||
class ProvisionConsumerApp |
|||
{ |
|||
public function execute(ProvisionConsumerAppDTO $dto): void |
|||
{ |
|||
Client::create([ |
|||
'name' => $dto->name, |
|||
'code' => $dto->code, |
|||
'url' => $dto->url, |
|||
'secret' => encrypt(uuid_create()), |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Actions\AppProvisioning; |
|||
|
|||
use App\Domains\Channel\Models\Client; |
|||
|
|||
class RotateSecretKey |
|||
{ |
|||
public function execute(Client $client): void |
|||
{ |
|||
$key = encrypt(uuid_create()); |
|||
$client->update(['secret' => $key]); |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\DTOs\AppProvisioning; |
|||
|
|||
readonly class ProvisionConsumerAppDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code, |
|||
public string $url, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Models; |
|||
|
|||
use App\Domains\Channel\Policies\ClientPolicy; |
|||
use Database\Factories\Channel\ClientFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable(['name', 'url', 'code', 'secret'])] |
|||
#[UsePolicy(ClientPolicy::class)] |
|||
class Client extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'secret' => 'encrypted', |
|||
]; |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return ClientFactory::new(); |
|||
} |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Policies; |
|||
|
|||
use App\Domains\Channel\Models\Client; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class ClientPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('client.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, Client $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('client.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('client.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, Client $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('client.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, Client $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('client.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Providers; |
|||
|
|||
use App\Domains\System\Traits\Provider\RegistersDomainEvents; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class ChannelServiceProvider extends ServiceProvider |
|||
{ |
|||
use RegistersDomainEvents; |
|||
|
|||
protected array $listen = []; |
|||
|
|||
public function register(): void |
|||
{ |
|||
$this->app->register(RelationshipServiceProvider::class); |
|||
} |
|||
|
|||
public function boot(): void |
|||
{ |
|||
$this->registerEvents(); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Channel\Providers; |
|||
|
|||
use App\Domains\Channel\Models\Client; |
|||
use App\Domains\Finance\Models\Invoice; |
|||
use App\Domains\Finance\Models\ProductMapping; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class RelationshipServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* Boot cross-domain runtime relationships. |
|||
* |
|||
* This provider is strictly dedicated to runtime, decoupled cross-domain |
|||
* relationship definitions. Use Model::resolveRelationUsing() here to wire |
|||
* explicit polymorphic or foreign-key macros between models that live in |
|||
* different domains — without introducing a hard compile-time dependency |
|||
* between those domains. |
|||
* |
|||
* Do NOT add route registrations, bindings, event listeners, or any other |
|||
* bootstrapping logic here. Keep this file focused on relationships only. |
|||
* |
|||
* Example: |
|||
* |
|||
* Order::resolveRelationUsing('customer', fn (Order $order) => |
|||
* $order->belongsTo(Customer::class, 'customer_id') |
|||
* ); |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
// Register cross-domain relationships below. |
|||
Client::resolveRelationUsing('transaction', fn (Client $client) => $client->hasMany( |
|||
related: Invoice::class, |
|||
foreignKey: 'client_id' |
|||
)); |
|||
Invoice::resolveRelationUsing('client', fn (Invoice $transaction) => $transaction->belongsTo( |
|||
related: Client::class, |
|||
foreignKey: 'client_id' |
|||
)); |
|||
|
|||
Client::resolveRelationUsing('product_mapping', fn (Client $client) => $client->hasMany( |
|||
related: ProductMapping::class, |
|||
foreignKey: 'client_id' |
|||
)); |
|||
ProductMapping::resolveRelationUsing('client', fn (ProductMapping $productMapping) => $productMapping->belongsTo( |
|||
related: Client::class, |
|||
foreignKey: 'client_id' |
|||
)); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\DisbursementProcessing; |
|||
|
|||
class DisburseFunds |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\DisbursementProcessing; |
|||
|
|||
class RecordVendorBill |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\LedgerConfiguration; |
|||
|
|||
use App\Domains\Finance\DTOs\LedgerConfiguration\AdjustAccountClassificationDTO; |
|||
use App\Domains\Finance\Models\ChartOfAccount; |
|||
|
|||
class AdjustAccountClassification |
|||
{ |
|||
public function execute(ChartOfAccount $coa, AdjustAccountClassificationDTO $dto): void |
|||
{ |
|||
$coa->update([ |
|||
'code' => $dto->code, |
|||
'name' => $dto->name, |
|||
'classification' => $dto->classification, |
|||
'parent_id' => $dto->parentId, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\LedgerConfiguration; |
|||
|
|||
use App\Domains\Finance\DTOs\LedgerConfiguration\RegisterChartOfAccountDTO; |
|||
use App\Domains\Finance\Models\ChartOfAccount; |
|||
|
|||
class RegisterChartOfAccount |
|||
{ |
|||
public function execute(RegisterChartOfAccountDTO $dto): void |
|||
{ |
|||
ChartOfAccount::create([ |
|||
'code' => $dto->code, |
|||
'name' => $dto->name, |
|||
'classification' => $dto->classification, |
|||
'status' => $dto->status, |
|||
'parent_id' => $dto->parentId, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\LedgerConfiguration; |
|||
|
|||
use App\Domains\Finance\Models\ChartOfAccount; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
|
|||
class SuspendAccountPostings |
|||
{ |
|||
public function execute(ChartOfAccount $coa): void |
|||
{ |
|||
$coa->update([ |
|||
'status' => LifecycleStatus::ARCHIVED, |
|||
]); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\PaymentProcessing; |
|||
|
|||
class InitializeInvoice |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\PaymentProcessing; |
|||
|
|||
class ProcessIncomingPaymentWebhook |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\ProductConfiguration; |
|||
|
|||
class CreateProductMapping |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Actions\ProductConfiguration; |
|||
|
|||
class RegisterProductMapping |
|||
{ |
|||
public function execute(): void |
|||
{ |
|||
// |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Casts; |
|||
|
|||
use App\Domains\Finance\Support\ValueObjects\Money; |
|||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use InvalidArgumentException; |
|||
|
|||
class MoneyCurrency implements CastsAttributes |
|||
{ |
|||
public function get(Model $model, string $key, mixed $value, array $attributes): ?Money |
|||
{ |
|||
if (is_null($value)) { |
|||
return null; |
|||
} |
|||
|
|||
return new Money((int) $value); |
|||
} |
|||
|
|||
public function set(Model $model, string $key, mixed $value, array $attributes): ?float |
|||
{ |
|||
if (is_null($value)) { |
|||
return null; |
|||
} |
|||
|
|||
if ($value instanceof Money) { |
|||
return $value->amount; |
|||
} |
|||
|
|||
if (is_numeric($value)) { |
|||
return (float) $value; |
|||
} |
|||
|
|||
throw new InvalidArgumentException("The {$key} attribute must be an float or an instance of Money."); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\DisbursementProcessing; |
|||
|
|||
readonly class DisburseFundsDTO |
|||
{ |
|||
public function __construct( |
|||
// |
|||
) {} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\DisbursementProcessing; |
|||
|
|||
readonly class VendorBillDTO |
|||
{ |
|||
public function __construct( |
|||
// |
|||
) {} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\LedgerConfiguration; |
|||
|
|||
use App\Domains\Finance\Enums\AccountClassification; |
|||
|
|||
readonly class AdjustAccountClassificationDTO |
|||
{ |
|||
public function __construct( |
|||
public string $code, |
|||
public string $name, |
|||
public AccountClassification $classification, |
|||
public ?int $parentId, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\LedgerConfiguration; |
|||
|
|||
use App\Domains\Finance\Enums\AccountClassification; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
|
|||
readonly class RegisterChartOfAccountDTO |
|||
{ |
|||
public function __construct( |
|||
public string $code, |
|||
public string $name, |
|||
public AccountClassification $classification, |
|||
public LifecycleStatus $status, |
|||
public ?int $parentId, |
|||
) {} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\PaymentProcessing; |
|||
|
|||
use Carbon\CarbonImmutable; |
|||
|
|||
readonly class BankWebhookPayloadDTO |
|||
{ |
|||
public function __construct( |
|||
public int $virtualAccount, |
|||
public string $bankRefId, |
|||
public CarbonImmutable $validUntil, |
|||
public float $amount, |
|||
public string $status, |
|||
public string $transactionId |
|||
) {} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\PaymentProcessing; |
|||
|
|||
readonly class IssueInvoiceDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $clientRefId, |
|||
public string $detail, |
|||
public string $type, |
|||
public string $status, |
|||
public string $clientId |
|||
) {} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\DTOs\ProductConfiguration; |
|||
|
|||
readonly class RegisterProductMappingDTO |
|||
{ |
|||
public function __construct( |
|||
public string $name, |
|||
public string $code, |
|||
public int $coaId |
|||
) {} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
|
|||
enum AccountClassification: string implements HasLabel |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case ASSET = 'asset'; |
|||
case LIABILITY = 'liability'; |
|||
case EQUITY = 'equity'; |
|||
case REVENUE = 'revenue'; |
|||
case EXPENSE = 'expense'; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
|
|||
enum InvoiceStatus: string implements HasLabel |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case PAID = 'paid'; |
|||
case PENDING = 'pending'; |
|||
case PARTIALLY_PAID = 'partially_paid'; |
|||
case OVERDUE = 'overdue'; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
|
|||
enum InvoiceType: string implements HasLabel |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case CUSTOMER_INVOICE = 'customer_invoice'; |
|||
case VENDOR_BILL = 'vendor_bill'; |
|||
case CREDIT_NOTE = 'credit_note'; |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
|
|||
enum PaymentDirection: string implements HasLabel |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case RECEIPT = 'receipt'; |
|||
case DISBURSEMENT = 'disbursement'; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Enums; |
|||
|
|||
use App\Domains\System\Traits\Enum\HasPredicateMethod; |
|||
use App\UI\Enums\Concerns\InteractsWithLabels; |
|||
use App\UI\Enums\Contracts\HasLabel; |
|||
|
|||
enum PaymentStatus: string implements HasLabel |
|||
{ |
|||
use HasPredicateMethod; |
|||
use InteractsWithLabels; |
|||
|
|||
case PENDING = 'pending'; |
|||
case SUCCESS = 'success'; |
|||
case FAILED = 'failed'; |
|||
case EXPIRED = 'expired'; |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Models; |
|||
|
|||
use App\Domains\Finance\Enums\AccountClassification; |
|||
use App\Domains\Finance\Policies\ChartOfAccountPolicy; |
|||
use App\Domains\System\Enums\LifecycleStatus; |
|||
use Database\Factories\Finance\ChartOfAccountFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable([ |
|||
'code', |
|||
'name', |
|||
'classification', |
|||
'status', |
|||
'parent_id', |
|||
])] |
|||
#[UsePolicy(ChartOfAccountPolicy::class)] |
|||
class ChartOfAccount extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'classification' => AccountClassification::class, |
|||
'status' => LifecycleStatus::class, |
|||
]; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return ChartOfAccountFactory::new(); |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Models; |
|||
|
|||
use App\Domains\Finance\Casts\MoneyCurrency; |
|||
use App\Domains\Finance\Enums\InvoiceStatus; |
|||
use App\Domains\Finance\Enums\InvoiceType; |
|||
use App\Domains\Finance\Policies\InvoicePolicy; |
|||
use Database\Factories\Finance\InvoiceFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|||
use Illuminate\Database\Eloquent\Relations\HasMany; |
|||
|
|||
#[Fillable([ |
|||
'name', |
|||
'detail', |
|||
'client_ref_id', |
|||
'type', |
|||
'amount', |
|||
'status', |
|||
'client_id', |
|||
'chart_of_account_id', |
|||
])] |
|||
#[UsePolicy(InvoicePolicy::class)] |
|||
class Invoice extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'amount' => MoneyCurrency::class, |
|||
'type' => InvoiceType::class, |
|||
'status' => InvoiceStatus::class, |
|||
]; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return InvoiceFactory::new(); |
|||
} |
|||
|
|||
public function chartOfAccount(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(ChartOfAccount::class); |
|||
} |
|||
|
|||
public function payments(): HasMany |
|||
{ |
|||
return $this->hasMany(Payment::class); |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Models; |
|||
|
|||
use App\Domains\Finance\Casts\MoneyCurrency; |
|||
use App\Domains\Finance\Enums\InvoiceStatus; |
|||
use App\Domains\Finance\Policies\InvoiceReportPolicy; |
|||
use BadMethodCallException; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable([ |
|||
'invoice_id', |
|||
'invoice_name', |
|||
'customer_id', |
|||
'customer_name', |
|||
'amount', |
|||
'paid_amount', |
|||
'issued_at', |
|||
'paid_at', |
|||
'status', |
|||
])] |
|||
#[UsePolicy(InvoiceReportPolicy::class)] |
|||
class InvoiceReport extends Model |
|||
{ |
|||
public static function boot(): void |
|||
{ |
|||
self::boot(); |
|||
static::creating(fn (InvoiceReport $invoiceReport) => throw new BadMethodCallException('Cannot create invoice report from here, use event instead.')); |
|||
static::deleting(fn (InvoiceReport $invoiceReport) => throw new BadMethodCallException('Cannot delete invoice report.')); |
|||
static::updating(fn (InvoiceReport $invoiceReport) => throw new BadMethodCallException('Cannot update invoice report.')); |
|||
} |
|||
|
|||
protected $casts = [ |
|||
'amount' => MoneyCurrency::class, |
|||
'paid_amount' => MoneyCurrency::class, |
|||
'issued_at' => 'datetime', |
|||
'paid_at' => 'datetime', |
|||
'status' => InvoiceStatus::class, |
|||
]; |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Models; |
|||
|
|||
use App\Domains\Finance\Casts\MoneyCurrency; |
|||
use App\Domains\Finance\Enums\PaymentDirection; |
|||
use App\Domains\Finance\Enums\PaymentStatus; |
|||
use App\Domains\Finance\Policies\PaymentPolicy; |
|||
use Database\Factories\Finance\PaymentFactory; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Concerns\HasUlids; |
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|||
|
|||
#[Fillable([ |
|||
'virtual_account', |
|||
'bank_ref_id', |
|||
'amount', |
|||
'valid_until', |
|||
'direction', |
|||
'status', |
|||
'transaction_id', |
|||
])] |
|||
#[UsePolicy(PaymentPolicy::class)] |
|||
class Payment extends Model |
|||
{ |
|||
use HasFactory; |
|||
use HasUlids; |
|||
|
|||
protected $casts = [ |
|||
'amount' => MoneyCurrency::class, |
|||
'valid_until' => 'datetime_immutable', |
|||
'direction' => PaymentDirection::class, |
|||
'status' => PaymentStatus::class, |
|||
]; |
|||
|
|||
public function uniqueIds(): array |
|||
{ |
|||
return ['ulid']; |
|||
} |
|||
|
|||
protected static function newFactory(): Factory |
|||
{ |
|||
return PaymentFactory::new(); |
|||
} |
|||
|
|||
public function transaction(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(Invoice::class); |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Models; |
|||
|
|||
use App\Domains\Finance\Policies\ProductMappingPolicy; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|||
|
|||
#[Fillable([ |
|||
'code', |
|||
'name', |
|||
'chart_of_account_id', |
|||
'client_id', |
|||
])] |
|||
#[UsePolicy(ProductMappingPolicy::class)] |
|||
class ProductMapping extends Model |
|||
{ |
|||
public function chartOfAccount(): BelongsTo |
|||
{ |
|||
return $this->belongsTo(ChartOfAccount::class); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Models; |
|||
|
|||
use App\Domains\Finance\Casts\MoneyCurrency; |
|||
use App\Domains\Finance\Enums\InvoiceStatus; |
|||
use App\Domains\Finance\Policies\StudentInvoiceReportPolicy; |
|||
use BadMethodCallException; |
|||
use Illuminate\Database\Eloquent\Attributes\Fillable; |
|||
use Illuminate\Database\Eloquent\Attributes\UsePolicy; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
#[Fillable([ |
|||
'invoice_id', |
|||
'student_id', |
|||
'name', |
|||
'faculty_id', |
|||
'faculty_name', |
|||
'study_program_id', |
|||
'study_program_name', |
|||
'term_id', |
|||
'term_name', |
|||
'amount', |
|||
'paid_amount', |
|||
'issued_at', |
|||
'paid_at', |
|||
'status', |
|||
])] |
|||
#[UsePolicy(StudentInvoiceReportPolicy::class)] |
|||
class StudentInvoiceReport extends Model |
|||
{ |
|||
public static function boot(): void |
|||
{ |
|||
self::boot(); |
|||
static::creating(fn (InvoiceReport $invoiceReport) => throw new BadMethodCallException('Cannot create invoice report from here, use event instead.')); |
|||
static::deleting(fn (InvoiceReport $invoiceReport) => throw new BadMethodCallException('Cannot delete invoice report.')); |
|||
static::updating(fn (InvoiceReport $invoiceReport) => throw new BadMethodCallException('Cannot update invoice report.')); |
|||
} |
|||
|
|||
protected $casts = [ |
|||
'amount' => MoneyCurrency::class, |
|||
'paid_amount' => MoneyCurrency::class, |
|||
'issued_at' => 'datetime', |
|||
'paid_at' => 'datetime', |
|||
'status' => InvoiceStatus::class, |
|||
]; |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Policies; |
|||
|
|||
use App\Domains\Finance\Models\ChartOfAccount; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class ChartOfAccountPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('chart-of-account.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, ChartOfAccount $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('chart-of-account.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('chart-of-account.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, ChartOfAccount $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('chart-of-account.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, ChartOfAccount $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('chart-of-account.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Policies; |
|||
|
|||
use App\Domains\Finance\Models\Invoice; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class InvoicePolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, Invoice $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, Invoice $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, Invoice $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Policies; |
|||
|
|||
use App\Domains\Finance\Models\InvoiceReport; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class InvoiceReportPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice-report.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, InvoiceReport $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('invoice-report.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, InvoiceReport $model): bool |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, InvoiceReport $model): bool |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Policies; |
|||
|
|||
use App\Domains\Finance\Models\Payment; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class PaymentPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('payment.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, Payment $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('payment.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('payment.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, Payment $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('payment.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, Payment $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('payment.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Policies; |
|||
|
|||
use App\Domains\Finance\Models\ProductMapping; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class ProductMappingPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('product-mapping.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, ProductMapping $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('product-mapping.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('product-mapping.create'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, ProductMapping $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('product-mapping.update'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, ProductMapping $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('product-mapping.delete'); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Policies; |
|||
|
|||
use App\Domains\Finance\Models\StudentInvoiceReport; |
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class StudentInvoiceReportPolicy |
|||
{ |
|||
/** |
|||
* Determine whether the user can view any models. |
|||
*/ |
|||
public function viewAny(User $user): bool |
|||
{ |
|||
return $user->hasPermissionTo('student-invoice-report.viewAny'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can view the model. |
|||
*/ |
|||
public function view(User $user, StudentInvoiceReport $model): bool |
|||
{ |
|||
return $user->hasPermissionTo('student-invoice-report.view'); |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can create models. |
|||
*/ |
|||
public function create(User $user): bool |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can update the model. |
|||
*/ |
|||
public function update(User $user, StudentInvoiceReport $model): bool |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Determine whether the user can delete the model. |
|||
*/ |
|||
public function delete(User $user, StudentInvoiceReport $model): bool |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Providers; |
|||
|
|||
use App\Domains\System\Traits\Provider\RegistersDomainEvents; |
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class FinanceServiceProvider extends ServiceProvider |
|||
{ |
|||
use RegistersDomainEvents; |
|||
|
|||
protected array $listen = []; |
|||
|
|||
public function register(): void |
|||
{ |
|||
$this->app->register(RelationshipServiceProvider::class); |
|||
} |
|||
|
|||
public function boot(): void |
|||
{ |
|||
$this->registerEvents(); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Providers; |
|||
|
|||
use Illuminate\Support\ServiceProvider; |
|||
|
|||
class RelationshipServiceProvider extends ServiceProvider |
|||
{ |
|||
/** |
|||
* Boot cross-domain runtime relationships. |
|||
* |
|||
* This provider is strictly dedicated to runtime, decoupled cross-domain |
|||
* relationship definitions. Use Model::resolveRelationUsing() here to wire |
|||
* explicit polymorphic or foreign-key macros between models that live in |
|||
* different domains — without introducing a hard compile-time dependency |
|||
* between those domains. |
|||
* |
|||
* Do NOT add route registrations, bindings, event listeners, or any other |
|||
* bootstrapping logic here. Keep this file focused on relationships only. |
|||
* |
|||
* Example: |
|||
* |
|||
* Order::resolveRelationUsing('customer', fn (Order $order) => |
|||
* $order->belongsTo(Customer::class, 'customer_id') |
|||
* ); |
|||
*/ |
|||
public function boot(): void |
|||
{ |
|||
// Register cross-domain relationships below. |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Finance\Support\ValueObjects; |
|||
|
|||
use InvalidArgumentException; |
|||
use NumberFormatter; |
|||
use Stringable; |
|||
|
|||
class Money implements Stringable |
|||
{ |
|||
public function __construct(public float $amount) |
|||
{ |
|||
if ($this->amount < 0) { |
|||
throw new InvalidArgumentException('Money cannot be negative.'); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Format the bytes into a human-readable string. |
|||
*/ |
|||
public function format(string $currency = 'IDR'): string |
|||
{ |
|||
$format = new NumberFormatter(app()->getLocale(), NumberFormatter::CURRENCY); |
|||
|
|||
return $format->formatCurrency($this->amount, $currency); |
|||
} |
|||
|
|||
/** |
|||
* Automatically format when echoed in Blade (e.g., {{ $model->amount }}). |
|||
*/ |
|||
public function __toString(): string |
|||
{ |
|||
return $this->format(); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Identity\Actions\AccessControl; |
|||
|
|||
use App\Domains\Identity\DTOs\AccessControl\CreateRoleDTO; |
|||
use App\Domains\Identity\Models\Role; |
|||
use Illuminate\Support\Facades\DB; |
|||
use Throwable; |
|||
|
|||
class DefineSystemRole |
|||
{ |
|||
/** |
|||
* @throws Throwable |
|||
*/ |
|||
public function execute(CreateRoleDTO $dto): bool |
|||
{ |
|||
return DB::transaction(function () use ($dto) { |
|||
$role = Role::create([ |
|||
'name' => $dto->name, |
|||
]); |
|||
$role->syncPermissions($dto->permissions); |
|||
|
|||
return true; |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Identity\Actions\AccessControl; |
|||
|
|||
use App\Domains\Identity\Enums\RoleType; |
|||
use App\Domains\Identity\Models\Role; |
|||
use Exception; |
|||
|
|||
use function in_array; |
|||
|
|||
class DeleteSystemRole |
|||
{ |
|||
/** |
|||
* @throws Exception |
|||
*/ |
|||
public function execute(Role $role): void |
|||
{ |
|||
if (in_array($role->name, [RoleType::ADMIN->value, RoleType::SYSTEM_ADMIN->value])) { |
|||
throw new Exception(__('domains/identity/messages.exceptions.cannot_remove_system_role')); |
|||
} |
|||
|
|||
if ($role->users()->exists()) { |
|||
throw new Exception(__('domains/identity/messages.exceptions.role_has_users')); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
namespace App\Domains\Identity\Actions\Governance; |
|||
|
|||
use App\Domains\Identity\Models\User; |
|||
|
|||
class DeleteUser |
|||
{ |
|||
public function __construct( |
|||
protected PurgeUser $purgeUser, |
|||
protected SuspendUser $suspendUser |
|||
) {} |
|||
|
|||
public function execute(User $user): void |
|||
{ |
|||
if ($user->status->isActive()) { |
|||
$this->suspendUser->execute($user); |
|||
} else { |
|||
$this->purgeUser->execute($user); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue