diff --git a/README.id.md b/README.id.md index 55bbe31..1687078 100644 --- a/README.id.md +++ b/README.id.md @@ -561,11 +561,11 @@ Kedua kelas Mailable berada pada **domain System**, bukan di namespace utama `Ap | File | Kunci (Key) | Tujuan | | --- | --- | --- | -| `lang/{locale}/ui.php` | `ui.excel.import.file_label` | Label unggahan FilePond di dalam modal impor. | -| `lang/{locale}/ui.php` | `ui.excel.import.success` | Pesan Toast muncul setelah impor masuk antrean. | -| `lang/{locale}/ui.php` | `ui.excel.export.success` | Pesan Toast muncul setelah ekspor masuk antrean. | -| `lang/{locale}/domains/system.php` | `notifications.excel.import_email.*` | Isi (body) email untuk pemberitahuan selesai impor. | -| `lang/{locale}/domains/system.php` | `notifications.excel.export_email.*` | Isi (body) email untuk pemberitahuan ekspor sudah siap. | +| `lang/{locale}/ui/excel.php` | `ui/excel.import.file_label` | Label unggahan FilePond di dalam modal impor. | +| `lang/{locale}/ui/excel.php` | `ui/excel.import.success` | Pesan Toast muncul setelah impor masuk antrean. | +| `lang/{locale}/ui/excel.php` | `ui/excel.export.success` | Pesan Toast muncul setelah ekspor masuk antrean. | +| `lang/{locale}/domains/system/notifications.php` | `domains/system/notifications.excel.import_email.*` | Isi (body) email untuk pemberitahuan selesai impor. | +| `lang/{locale}/domains/system/notifications.php` | `domains/system/notifications.excel.export_email.*` | Isi (body) email untuk pemberitahuan ekspor sudah siap. | --- diff --git a/README.md b/README.md index dcaee41..8a2e889 100644 --- a/README.md +++ b/README.md @@ -676,11 +676,11 @@ Both Mailable classes live in the **System domain**, not the root `App\Mail\` na | File | Key | Purpose | | --- | --- | --- | -| `lang/{locale}/ui.php` | `ui.excel.import.file_label` | FilePond upload label inside the import modal. | -| `lang/{locale}/ui.php` | `ui.excel.import.success` | Toast shown after import is queued. | -| `lang/{locale}/ui.php` | `ui.excel.export.success` | Toast shown after export is queued. | -| `lang/{locale}/domains/system.php` | `notifications.excel.import_email.*` | Email body for the import completion notification. | -| `lang/{locale}/domains/system.php` | `notifications.excel.export_email.*` | Email body for the export ready notification. | +| `lang/{locale}/ui/excel.php` | `ui/excel.import.file_label` | FilePond upload label inside the import modal. | +| `lang/{locale}/ui/excel.php` | `ui/excel.import.success` | Toast shown after import is queued. | +| `lang/{locale}/ui/excel.php` | `ui/excel.export.success` | Toast shown after export is queued. | +| `lang/{locale}/domains/system/notifications.php` | `domains/system/notifications.excel.import_email.*` | Email body for the import completion notification. | +| `lang/{locale}/domains/system/notifications.php` | `domains/system/notifications.excel.export_email.*` | Email body for the export ready notification. | --- diff --git a/app/Domains/Academic/Providers/RelationshipServiceProvider.php b/app/Domains/Academic/Providers/RelationshipServiceProvider.php index d0c982f..823ad45 100644 --- a/app/Domains/Academic/Providers/RelationshipServiceProvider.php +++ b/app/Domains/Academic/Providers/RelationshipServiceProvider.php @@ -35,17 +35,17 @@ class RelationshipServiceProvider extends ServiceProvider related: Term::class, foreignKey: 'term_id' )); - Term::resolveRelationUsing('admission_schedules', fn (Term $term) => $term->hasMany( + Term::resolveRelationUsing('admissionSchedules', fn (Term $term) => $term->hasMany( related: AdmissionSchedule::class, foreignKey: 'term_id', localKey: 'id' )); - FeeRate::resolveRelationUsing('study_program', fn (FeeRate $feeRate) => $feeRate->belongsTo( + FeeRate::resolveRelationUsing('studyProgram', fn (FeeRate $feeRate) => $feeRate->belongsTo( related: StudyProgram::class, foreignKey: 'study_program_id' )); - StudyProgram::resolveRelationUsing('fee_rates', fn (StudyProgram $studyProgram) => $studyProgram->hasMany( + StudyProgram::resolveRelationUsing('feeRates', fn (StudyProgram $studyProgram) => $studyProgram->hasMany( related: FeeRate::class, foreignKey: 'study_program_id', localKey: 'id' diff --git a/app/Domains/Academic/Queries/Lookup/FacultyLookup.php b/app/Domains/Academic/Queries/Lookup/FacultyLookup.php new file mode 100644 index 0000000..92a87c3 --- /dev/null +++ b/app/Domains/Academic/Queries/Lookup/FacultyLookup.php @@ -0,0 +1,18 @@ + Faculty::query() + ->select(['id', 'name']) + ->latest() + ->get() + ->pluck('name', 'id')); + } +} diff --git a/app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php b/app/Domains/Academic/Queries/Lookup/StudyProgramLookup.php similarity index 67% rename from app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php rename to app/Domains/Academic/Queries/Lookup/StudyProgramLookup.php index 6ccea9a..a670acb 100644 --- a/app/Domains/Academic/Queries/Selection/SelectStudyProgramQuery.php +++ b/app/Domains/Academic/Queries/Lookup/StudyProgramLookup.php @@ -1,11 +1,11 @@ StudyProgram::select('id', 'name') + return once(fn () => StudyProgram::query() + ->select('id', 'name') ->where('faculty_id', $context['faculty']) + ->latest() ->get() ->pluck('name', 'id')); } diff --git a/app/Domains/Academic/Queries/Lookup/TermLookup.php b/app/Domains/Academic/Queries/Lookup/TermLookup.php new file mode 100644 index 0000000..a67f820 --- /dev/null +++ b/app/Domains/Academic/Queries/Lookup/TermLookup.php @@ -0,0 +1,18 @@ + Term::query() + ->select(['id', 'name']) + ->when($search, fn ($query) => $query->where('name', 'like', "%{$search}%")) + ->latest('date_start') + ->pluck('name', 'name')); + } +} diff --git a/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php b/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php deleted file mode 100644 index 74345d3..0000000 --- a/app/Domains/Academic/Queries/Selection/SelectFacultyQuery.php +++ /dev/null @@ -1,15 +0,0 @@ - Faculty::all(['id', 'name']) - ->pluck('name', 'id')); - } -} diff --git a/app/Domains/Academic/Queries/Selection/SelectTermQuery.php b/app/Domains/Academic/Queries/Selection/SelectTermQuery.php deleted file mode 100644 index c596a62..0000000 --- a/app/Domains/Academic/Queries/Selection/SelectTermQuery.php +++ /dev/null @@ -1,15 +0,0 @@ - Term::all(['id', 'name']) - ->pluck('name', 'id')); - } -} diff --git a/app/Domains/Admission/Actions/AdmissionPricing/DefineFeeType.php b/app/Domains/Admission/Actions/AdmissionPricing/DefineFeeType.php index 6201794..9e9c627 100644 --- a/app/Domains/Admission/Actions/AdmissionPricing/DefineFeeType.php +++ b/app/Domains/Admission/Actions/AdmissionPricing/DefineFeeType.php @@ -11,6 +11,7 @@ class DefineFeeType { FeeType::create([ 'name' => $dto->name, + 'code' => $dto->code, 'billing_cycle' => $dto->billingCycle, ]); } diff --git a/app/Domains/Admission/Actions/AdmissionPricing/SetUpAdmissionFeeRates.php b/app/Domains/Admission/Actions/AdmissionPricing/SetUpAdmissionFeeRates.php index 5ae23b5..cf9343c 100644 --- a/app/Domains/Admission/Actions/AdmissionPricing/SetUpAdmissionFeeRates.php +++ b/app/Domains/Admission/Actions/AdmissionPricing/SetUpAdmissionFeeRates.php @@ -3,13 +3,14 @@ namespace App\Domains\Admission\Actions\AdmissionPricing; use App\Domains\Admission\DTOs\AdmissionPricing\AdmissionFeeRatesDTO; +use App\Domains\Admission\Events\Pricing\AdmissionFeeRateWasSetUp; use App\Domains\Admission\Models\FeeRate; class SetUpAdmissionFeeRates { public function execute(AdmissionFeeRatesDTO $dto): void { - FeeRate::updateOrCreate([ + $rate = FeeRate::updateOrCreate([ 'academic_program_id' => $dto->academicProgramId, 'admission_schedule_id' => $dto->admissionScheduleId, 'study_program_id' => $dto->studyProgramId, @@ -17,5 +18,9 @@ class SetUpAdmissionFeeRates ], [ 'amount' => $dto->amount, ]); + + $name = $rate->generateProductName(); + + AdmissionFeeRateWasSetUp::dispatch(productName: $name); } } diff --git a/app/Domains/Admission/DTOs/AdmissionPricing/FeeTypeDTO.php b/app/Domains/Admission/DTOs/AdmissionPricing/FeeTypeDTO.php index 11ec677..ca417d7 100644 --- a/app/Domains/Admission/DTOs/AdmissionPricing/FeeTypeDTO.php +++ b/app/Domains/Admission/DTOs/AdmissionPricing/FeeTypeDTO.php @@ -8,6 +8,7 @@ readonly class FeeTypeDTO { public function __construct( public string $name, + public string $code, public BillingCycle $billingCycle ) {} } diff --git a/app/Domains/Admission/Events/Pricing/AdmissionFeeRateWasSetUp.php b/app/Domains/Admission/Events/Pricing/AdmissionFeeRateWasSetUp.php new file mode 100644 index 0000000..0256add --- /dev/null +++ b/app/Domains/Admission/Events/Pricing/AdmissionFeeRateWasSetUp.php @@ -0,0 +1,15 @@ + $this->resolveAdmissionScheduleId($rawData['jalur'], $rawData['angkatan']), + 'academic_program_id' => $this->resolveAcademicProgramId($rawData['kode_Skuliah']), + 'study_program_id' => $this->resolveStudyProgramId($rawData['kode_prodi']), + 'fee_type_id'=> $this->resolveFeeTypeId($rawData['kode_Jtagihan']), + 'amount' => $rawData['nominal_TRFtagihan'], + ]; + } + + public function updateOrCreateDomainState(array $payload, ?Model $existingModel = null): void + { + $this->setUpAdmissionFeeRates->execute(new AdmissionFeeRatesDTO( + academicProgramId: $payload['academic_program_id'], + admissionScheduleId: $payload['admission_schedule_id'], + studyProgramId: $payload['study_program_id'], + feeTypeId: $payload['fee_type_id'], + amount: $payload['amount'], + )); + } + + /** + * @return class-string + */ + public function getModelClass(): string + { + return FeeRate::class; + } + + public function resolveAdmissionScheduleId(string $admissionTrackSlug, int $yearStudy): int { + $key = hex2bin(md5("{$admissionTrackSlug}-{$yearStudy}") ); + if (!isset(self::$cache['admission_schedule'][$key])) { + self::$cache['admission_schedule'][$key] = AdmissionSchedule::query() + ->whereHas( + 'admissionTrack', + fn($builder) => $builder->where('slug', str($admissionTrackSlug)->slug()) + )->whereHas( + 'term', + fn($builder) => $builder->where('year_study', $yearStudy) + )->first()?->id; + } + + return self::$cache['admission_schedule'][$key]; + } + + public function resolveStudyProgramId($code): int { + if (!isset(self::$cache['study_program'][$code])) { + self::$cache['study_program'][$code] = StudyProgram::where('code', $code)->first()?->id; + } + + return self::$cache['study_program'][$code]; + } + + public function resolveFeeTypeId(string $code): int { + $key = hex2bin(md5($code)); + if (!isset(self::$cache['fee_type'][$key])) { + self::$cache['fee_type'][$key] = FeeType::where('code', $code)->first()?->id; + } + + return self::$cache['fee_type'][$key]; + } + + + public function resolveAcademicProgramId(string $code): int { + $key = hex2bin(md5($code)); + if (!isset(self::$cache['academic_program'][$key])) { + self::$cache['academic_program'][$key] = AcademicProgram::where('code', $code)->first()?->id; + } + + return self::$cache['academic_program'][$key]; + } +} diff --git a/app/Domains/Admission/Integration/Mappers/FeeTypeDataMapper.php b/app/Domains/Admission/Integration/Mappers/FeeTypeDataMapper.php index f10764f..70c892b 100644 --- a/app/Domains/Admission/Integration/Mappers/FeeTypeDataMapper.php +++ b/app/Domains/Admission/Integration/Mappers/FeeTypeDataMapper.php @@ -29,6 +29,7 @@ class FeeTypeDataMapper implements DataPayloadMapper // Normalize incoming data array formats into an internal domain-safe layout return [ 'name' => $rawData['nama_Jtagihan'], + 'code' => $rawData['kode_Jtagihan'], 'billing_cycle' => $rawData['periodesasi_Jtagihan'], ]; } @@ -41,6 +42,7 @@ class FeeTypeDataMapper implements DataPayloadMapper if(!$existingModel) { $this->defineFeeType->execute(new FeeTypeDTO( name: $payload['name'], + code: $payload['code'], billingCycle: BillingCycle::tryFromPMB($payload['billing_cycle']), )); } diff --git a/app/Domains/Admission/Models/FeeRate.php b/app/Domains/Admission/Models/FeeRate.php index fcc8169..ad3cb43 100644 --- a/app/Domains/Admission/Models/FeeRate.php +++ b/app/Domains/Admission/Models/FeeRate.php @@ -3,7 +3,7 @@ namespace App\Domains\Admission\Models; use App\Domains\Admission\Policies\FeeRatePolicy; -use App\Domains\Finance\Casts\MoneyCurrency; +use App\Domains\System\Casts\MoneyCurrency; use App\Domains\System\Traits\Model\HasPublicUlid; use Database\Factories\Admission\FeeRateFactory; use Illuminate\Database\Eloquent\Attributes\Fillable; diff --git a/app/Domains/Admission/Models/FeeType.php b/app/Domains/Admission/Models/FeeType.php index 94ffc8d..2b8bf1a 100644 --- a/app/Domains/Admission/Models/FeeType.php +++ b/app/Domains/Admission/Models/FeeType.php @@ -12,7 +12,7 @@ use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; -#[Fillable(['name', 'billing_cycle'])] +#[Fillable(['name', 'billing_cycle' ,'code'])] #[UsePolicy(FeeTypePolicy::class)] class FeeType extends Model { diff --git a/app/Domains/Admission/Providers/AdmissionServiceProvider.php b/app/Domains/Admission/Providers/AdmissionServiceProvider.php index b288f93..c915bd9 100644 --- a/app/Domains/Admission/Providers/AdmissionServiceProvider.php +++ b/app/Domains/Admission/Providers/AdmissionServiceProvider.php @@ -5,6 +5,7 @@ namespace App\Domains\Admission\Providers; use App\Domains\Admission\Integration\Mappers\AcademicProgramDataMapper; use App\Domains\Admission\Integration\Mappers\AdmissionScheduleDataMapper; use App\Domains\Admission\Integration\Mappers\AdmissionTrackDataMapper; +use App\Domains\Admission\Integration\Mappers\FeeRateDataMapper; use App\Domains\Admission\Integration\Mappers\FeeTypeDataMapper; use App\Domains\Channel\Enums\Api\ApiType; use App\Domains\Channel\Support\Mapper\ApiMapperRegistry; @@ -35,6 +36,10 @@ class AdmissionServiceProvider extends ServiceProvider type: ApiType::FEE_TYPE, mapperClass: FeeTypeDataMapper::class, ); + ApiMapperRegistry::register( + type: ApiType::FEE_RATE, + mapperClass: FeeRateDataMapper::class, + ); $this->app->register(RelationshipServiceProvider::class); } diff --git a/app/Domains/Admission/Queries/Lookup/FeeTypeLookup.php b/app/Domains/Admission/Queries/Lookup/FeeTypeLookup.php new file mode 100644 index 0000000..f79e0fb --- /dev/null +++ b/app/Domains/Admission/Queries/Lookup/FeeTypeLookup.php @@ -0,0 +1,18 @@ + FeeType::query() + ->select(['id', 'name']) + ->latest() + ->get() + ->pluck('name', 'id')); + } +} diff --git a/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php b/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php deleted file mode 100644 index 1fd37bc..0000000 --- a/app/Domains/Admission/Queries/Selection/SelectFeeTypeQuery.php +++ /dev/null @@ -1,13 +0,0 @@ - $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' - )); } } diff --git a/app/Domains/Finance/Actions/DisbursementProcessing/DisburseFunds.php b/app/Domains/Finance/Actions/DisbursementProcessing/DisburseFunds.php deleted file mode 100644 index 5168e9a..0000000 --- a/app/Domains/Finance/Actions/DisbursementProcessing/DisburseFunds.php +++ /dev/null @@ -1,11 +0,0 @@ -update([ - 'code' => $dto->code, - 'classification' => $dto->classification, - 'parent_id' => $dto->parentId, - ]); - } -} diff --git a/app/Domains/Finance/Actions/LedgerConfiguration/RegisterChartOfAccount.php b/app/Domains/Finance/Actions/LedgerConfiguration/RegisterChartOfAccount.php deleted file mode 100644 index 2c7594e..0000000 --- a/app/Domains/Finance/Actions/LedgerConfiguration/RegisterChartOfAccount.php +++ /dev/null @@ -1,20 +0,0 @@ - $dto->code, - 'name' => $dto->name, - 'classification' => $dto->classification, - 'status' => $dto->status, - 'parent_id' => $dto->parentId, - ]); - } -} diff --git a/app/Domains/Finance/Actions/LedgerConfiguration/SuspendAccountPostings.php b/app/Domains/Finance/Actions/LedgerConfiguration/SuspendAccountPostings.php deleted file mode 100644 index 1886676..0000000 --- a/app/Domains/Finance/Actions/LedgerConfiguration/SuspendAccountPostings.php +++ /dev/null @@ -1,16 +0,0 @@ -update([ - 'status' => LifecycleStatus::INACTIVE, - ]); - } -} diff --git a/app/Domains/Finance/Actions/PaymentProcessing/InitializeInvoice.php b/app/Domains/Finance/Actions/PaymentProcessing/InitializeInvoice.php deleted file mode 100644 index 6c18da3..0000000 --- a/app/Domains/Finance/Actions/PaymentProcessing/InitializeInvoice.php +++ /dev/null @@ -1,23 +0,0 @@ - $dto->name, - 'detail' => $dto->detail->toArray(), - 'client_ref_id' => $dto->clientRefId, - 'type' => $dto->type, - 'amount' => $dto->amount, - 'status' => $dto->status, - 'client_id' => $dto->clientId, - 'chart_of_account_id' => $dto->coaId, - ]); - } -} diff --git a/app/Domains/Finance/Actions/PaymentProcessing/ProcessIncomingPaymentWebhook.php b/app/Domains/Finance/Actions/PaymentProcessing/ProcessIncomingPaymentWebhook.php deleted file mode 100644 index acde9a0..0000000 --- a/app/Domains/Finance/Actions/PaymentProcessing/ProcessIncomingPaymentWebhook.php +++ /dev/null @@ -1,11 +0,0 @@ -update(['chart_of_account_id' => $coaId]); - } -} diff --git a/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php b/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php deleted file mode 100644 index 2ea1a2d..0000000 --- a/app/Domains/Finance/Actions/ProductConfiguration/RegisterProductMapping.php +++ /dev/null @@ -1,18 +0,0 @@ - $dto->name, - 'code' => $dto->code, - 'chart_of_account_id' => $dto->coaId, - ]); - } -} diff --git a/app/Domains/Finance/DTOs/DisbursementProcessing/DisburseFundsDTO.php b/app/Domains/Finance/DTOs/DisbursementProcessing/DisburseFundsDTO.php deleted file mode 100644 index 5921d12..0000000 --- a/app/Domains/Finance/DTOs/DisbursementProcessing/DisburseFundsDTO.php +++ /dev/null @@ -1,10 +0,0 @@ - $this->studentId, - 'student_name' => $this->studentName, - 'faculty' => $this->faculty, - 'study_program' => $this->studyProgram, - 'term' => $this->term, - ]; - } - - public static function fromArray(array $data): self - { - return new self( - studentId: $data['student_id'], - studentName: $data['student_name'], - faculty: $data['faculty'], - studyProgram: $data['study_program'], - term: $data['term'], - ); - } -} diff --git a/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php b/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php deleted file mode 100644 index 3d86d9d..0000000 --- a/app/Domains/Finance/DTOs/PaymentProcessing/IssueInvoiceDTO.php +++ /dev/null @@ -1,21 +0,0 @@ - StudentInvoiceSchema::make(), - default => InvoiceSchema::make()->withCoaVisibility(), - }; - } - - public function dtoTransform(array $data): InvoiceDetailDTO - { - return match ($this) { - self::STUDENT_INVOICE => StudentInvoiceDetailDTO::fromArray($data), - default => false - }; - } - - /** - * Resolve all field schemas, keyed by their input keys. - * - * @return array - */ - public function getSchema(): array - { - return $this->schema()->getSchema(); - } -} diff --git a/app/Domains/Finance/Enums/PaymentDirection.php b/app/Domains/Finance/Enums/PaymentDirection.php deleted file mode 100644 index a2d335b..0000000 --- a/app/Domains/Finance/Enums/PaymentDirection.php +++ /dev/null @@ -1,16 +0,0 @@ - AccountClassification::class, - 'status' => LifecycleStatus::class, - ]; - - protected static function newFactory(): Factory - { - return ChartOfAccountFactory::new(); - } -} diff --git a/app/Domains/Finance/Models/Invoice.php b/app/Domains/Finance/Models/Invoice.php deleted file mode 100644 index 4b37d4a..0000000 --- a/app/Domains/Finance/Models/Invoice.php +++ /dev/null @@ -1,55 +0,0 @@ - MoneyCurrency::class, - 'type' => InvoiceType::class, - 'status' => InvoiceStatus::class, - ]; - - 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); - } -} diff --git a/app/Domains/Finance/Models/InvoiceReport.php b/app/Domains/Finance/Models/InvoiceReport.php deleted file mode 100644 index 73d6886..0000000 --- a/app/Domains/Finance/Models/InvoiceReport.php +++ /dev/null @@ -1,42 +0,0 @@ - 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, - ]; -} diff --git a/app/Domains/Finance/Models/Payment.php b/app/Domains/Finance/Models/Payment.php deleted file mode 100644 index a9ac3bb..0000000 --- a/app/Domains/Finance/Models/Payment.php +++ /dev/null @@ -1,49 +0,0 @@ - MoneyCurrency::class, - 'valid_until' => 'datetime_immutable', - 'direction' => PaymentDirection::class, - 'status' => PaymentStatus::class, - ]; - - protected static function newFactory(): Factory - { - return PaymentFactory::new(); - } - - public function transaction(): BelongsTo - { - return $this->belongsTo(Invoice::class); - } -} diff --git a/app/Domains/Finance/Models/ProductMapping.php b/app/Domains/Finance/Models/ProductMapping.php deleted file mode 100644 index a5dd18b..0000000 --- a/app/Domains/Finance/Models/ProductMapping.php +++ /dev/null @@ -1,24 +0,0 @@ -belongsTo(ChartOfAccount::class); - } -} diff --git a/app/Domains/Finance/Models/StudentInvoiceReport.php b/app/Domains/Finance/Models/StudentInvoiceReport.php deleted file mode 100644 index f4f3020..0000000 --- a/app/Domains/Finance/Models/StudentInvoiceReport.php +++ /dev/null @@ -1,47 +0,0 @@ - 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, - ]; -} diff --git a/app/Domains/Finance/Policies/ChartOfAccountPolicy.php b/app/Domains/Finance/Policies/ChartOfAccountPolicy.php deleted file mode 100644 index 57a1752..0000000 --- a/app/Domains/Finance/Policies/ChartOfAccountPolicy.php +++ /dev/null @@ -1,49 +0,0 @@ -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'); - } -} diff --git a/app/Domains/Finance/Policies/InvoicePolicy.php b/app/Domains/Finance/Policies/InvoicePolicy.php deleted file mode 100644 index 0287aa8..0000000 --- a/app/Domains/Finance/Policies/InvoicePolicy.php +++ /dev/null @@ -1,49 +0,0 @@ -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'); - } -} diff --git a/app/Domains/Finance/Policies/InvoiceReportPolicy.php b/app/Domains/Finance/Policies/InvoiceReportPolicy.php deleted file mode 100644 index e7bf312..0000000 --- a/app/Domains/Finance/Policies/InvoiceReportPolicy.php +++ /dev/null @@ -1,49 +0,0 @@ -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; - } -} diff --git a/app/Domains/Finance/Policies/PaymentPolicy.php b/app/Domains/Finance/Policies/PaymentPolicy.php deleted file mode 100644 index a1d826c..0000000 --- a/app/Domains/Finance/Policies/PaymentPolicy.php +++ /dev/null @@ -1,49 +0,0 @@ -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'); - } -} diff --git a/app/Domains/Finance/Policies/ProductMappingPolicy.php b/app/Domains/Finance/Policies/ProductMappingPolicy.php deleted file mode 100644 index fd1cc9e..0000000 --- a/app/Domains/Finance/Policies/ProductMappingPolicy.php +++ /dev/null @@ -1,49 +0,0 @@ -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'); - } -} diff --git a/app/Domains/Finance/Policies/StudentInvoiceReportPolicy.php b/app/Domains/Finance/Policies/StudentInvoiceReportPolicy.php deleted file mode 100644 index ab1c3de..0000000 --- a/app/Domains/Finance/Policies/StudentInvoiceReportPolicy.php +++ /dev/null @@ -1,49 +0,0 @@ -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; - } -} diff --git a/app/Domains/Finance/Providers/FinanceServiceProvider.php b/app/Domains/Finance/Providers/FinanceServiceProvider.php deleted file mode 100644 index 650a1a6..0000000 --- a/app/Domains/Finance/Providers/FinanceServiceProvider.php +++ /dev/null @@ -1,23 +0,0 @@ -app->register(RelationshipServiceProvider::class); - } - - public function boot(): void - { - $this->registerEvents(); - } -} diff --git a/app/Domains/Finance/Providers/RelationshipServiceProvider.php b/app/Domains/Finance/Providers/RelationshipServiceProvider.php deleted file mode 100644 index 73894aa..0000000 --- a/app/Domains/Finance/Providers/RelationshipServiceProvider.php +++ /dev/null @@ -1,31 +0,0 @@ - - * $order->belongsTo(Customer::class, 'customer_id') - * ); - */ - public function boot(): void - { - // Register cross-domain relationships below. - } -} diff --git a/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php b/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php deleted file mode 100644 index 8a4a44c..0000000 --- a/app/Domains/Finance/Schemas/Invoice/StudentInvoiceSchema.php +++ /dev/null @@ -1,79 +0,0 @@ -addInput( - InputSchema::make() - ->key('student_id') - ->label(__('domains/finance/field.invoice.detail.student_id')) - ->type(InputType::TEXTLINE) - ->rules(['required']) - ) - ->addInput( - InputSchema::make() - ->key('student_name') - ->label(__('domains/finance/field.invoice.detail.student_name')) - ->type(InputType::TEXTLINE) - ->rules(['required', 'string']) - ) - ->addInput( - InputSchema::make() - ->key('faculty') - ->label(__('domains/finance/field.invoice.detail.faculty')) - ->type(InputType::SELECT) - ->rules(['required', 'string']) - ->select2() - ->live() - ->options(fn () => SelectFacultyQuery::fetch()) - ) - ->addInput( - InputSchema::make() - ->key('study_program') - ->label(__('domains/finance/field.invoice.detail.study_program')) - ->type(InputType::SELECT) - ->rules(['required', 'string']) - ->select2() - ->dependsOn('faculty') - ->setContextKeys(['faculty']) - ->options(fn ($context) => SelectStudyProgramQuery::fetch($context)) - ) - ->addInput( - InputSchema::make() - ->key('term_entry') - ->label(__('domains/finance/field.invoice.detail.term_entry')) - ->type(InputType::SELECT) - ->rules(['required']) - ->options(fn () => SelectTermQuery::fetch()) - ->select2() - ) - ->addInput( - InputSchema::make() - ->key('semester') - ->label(__('domains/finance/field.invoice.detail.semester')) - ->type(InputType::SELECT) - ->rules(['required']) - ->options(array_combine(range(1, 13), range(1, 13))) - ->select2() - ) - ->addInput( - InputSchema::make() - ->key('fee_type') - ->label(__('domains/finance/field.invoice.detail.fee_type')) - ->type(InputType::SELECT) - ->rules(['required']) - ->select2() - ); - } -} diff --git a/app/Domains/Finance/Support/Schemas/InvoiceSchema.php b/app/Domains/Finance/Support/Schemas/InvoiceSchema.php deleted file mode 100644 index 71a70d2..0000000 --- a/app/Domains/Finance/Support/Schemas/InvoiceSchema.php +++ /dev/null @@ -1,25 +0,0 @@ -coaVisibility = $visible; - - return $this; - } - - public function isCoaVisible(): bool - { - return $this->coaVisibility; - } -} diff --git a/app/Domains/Finance/Casts/MoneyCurrency.php b/app/Domains/System/Casts/MoneyCurrency.php similarity index 90% rename from app/Domains/Finance/Casts/MoneyCurrency.php rename to app/Domains/System/Casts/MoneyCurrency.php index e16621b..3bb8c2f 100644 --- a/app/Domains/Finance/Casts/MoneyCurrency.php +++ b/app/Domains/System/Casts/MoneyCurrency.php @@ -1,8 +1,8 @@ InputSchema::make() ->type(InputType::SELECT) - ->default('en') + ->default('-') ->label($this->label()) ->select2() - ->options(fn() => SelectTermQuery::fetch()), + ->options(fn() => TermLookup::fetch()), self::TIMEZONE => InputSchema::make() ->type(InputType::SELECT) diff --git a/app/Domains/System/Models/SystemSettings.php b/app/Domains/System/Models/SystemSettings.php index 5e8ce64..63973c8 100644 --- a/app/Domains/System/Models/SystemSettings.php +++ b/app/Domains/System/Models/SystemSettings.php @@ -25,6 +25,9 @@ class SystemSettings extends Model if ($schema->type->isFile() && isset($this->attributes['value'])) { return asset_static($this->attributes['value']); } elseif ($schema->type->isSelect()) { + if (! isset($schema->attributes['options'][$this->attributes['value']])) { + return null; + } return $schema->attributes['options'][$this->attributes['value']]; } diff --git a/app/Domains/Finance/Support/ValueObjects/Money.php b/app/Domains/System/Support/ValueObjects/Money.php similarity index 94% rename from app/Domains/Finance/Support/ValueObjects/Money.php rename to app/Domains/System/Support/ValueObjects/Money.php index 9fd1e2e..dcbc520 100644 --- a/app/Domains/Finance/Support/ValueObjects/Money.php +++ b/app/Domains/System/Support/ValueObjects/Money.php @@ -1,6 +1,6 @@ fetch($request->input('search')) - ->map(fn ($res) => (object) [ - 'id' => $res->name, - 'text' => $res->name, - ]); + $result = $lookup->fetch($request->input('search')); return LookupResource::collection($result); } diff --git a/app/Http/Controllers/Api/V1/Lookup/TermLookupController.php b/app/Http/Controllers/Api/V1/Lookup/TermLookupController.php new file mode 100644 index 0000000..7c9961b --- /dev/null +++ b/app/Http/Controllers/Api/V1/Lookup/TermLookupController.php @@ -0,0 +1,21 @@ +fetch()->map(fn ($term) => (object) [ + 'id' => $term, + 'text' => $term, + ]); + + return LookupResource::collection($terms); + } +} diff --git a/app/Http/Controllers/Web/Finance/ChartOfAccountController.php b/app/Http/Controllers/Web/Finance/ChartOfAccountController.php deleted file mode 100644 index 1932c90..0000000 --- a/app/Http/Controllers/Web/Finance/ChartOfAccountController.php +++ /dev/null @@ -1,32 +0,0 @@ - 'dashboard', - 'domains/finance/seo.coa.title' => '', - ], - )] - public function __invoke(ChartOfAccountDataTable $dataTable) - { - return $dataTable->render('pages.finance.chart-of-account.index'); - } -} diff --git a/app/Http/Controllers/Web/Finance/InvoiceController.php b/app/Http/Controllers/Web/Finance/InvoiceController.php deleted file mode 100644 index cf1a621..0000000 --- a/app/Http/Controllers/Web/Finance/InvoiceController.php +++ /dev/null @@ -1,32 +0,0 @@ - 'dashboard', - 'domains/finance/seo.invoice.title' => '', - ], - )] - public function __invoke(InvoiceDataTable $dataTable) - { - return $dataTable->render('pages.finance.invoice.index'); - } -} diff --git a/app/Http/Controllers/Web/Finance/ProductMappingController.php b/app/Http/Controllers/Web/Finance/ProductMappingController.php deleted file mode 100644 index f5797b2..0000000 --- a/app/Http/Controllers/Web/Finance/ProductMappingController.php +++ /dev/null @@ -1,32 +0,0 @@ - 'dashboard', - 'domains/finance/seo.product_mapping.title' => '', - ], - )] - public function __invoke(ProductMappingDataTable $dataTable) - { - return $dataTable->render('pages.finance.product-mapping.index'); - } -} diff --git a/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php b/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php index cf1003e..8f4ec31 100644 --- a/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php +++ b/app/Http/DataTables/Admission/AdmissionScheduleDataTable.php @@ -3,6 +3,8 @@ namespace App\Http\DataTables\Admission; use App\Domains\Admission\Models\AdmissionSchedule; +use App\Domains\System\Enums\SystemSettingKey; +use App\Domains\System\Queries\GetSystemSettings; use Illuminate\Database\Eloquent\Builder as QueryBuilder; use Yajra\DataTables\EloquentDataTable; use Yajra\DataTables\Html\Builder as HtmlBuilder; @@ -54,10 +56,20 @@ class AdmissionScheduleDataTable extends DataTable */ public function query(AdmissionSchedule $model): QueryBuilder { - return $model->newQuery() + $query = $model->newQuery() ->join('admission_tracks', 'admission_tracks.id', '=', 'admission_schedules.admission_track_id') - ->join('terms', 'terms.id', '=', 'admission_schedules.term_id') - ->select('admission_schedules.*', 'admission_tracks.name as admission_track_name', 'terms.name as term_name'); + ->join('terms', 'terms.id', '=', 'admission_schedules.term_id'); + + if (request()->has('term') && request('term') != '') { + $query->whereHas('term', fn ($query) => $query + ->where('name', request('term'))); + } else { + $currentTerm = app(GetSystemSettings::class)->get(SystemSettingKey::CURRENT_TERM); + $query->whereHas('term', fn ($query) => $query + ->where('name', $currentTerm)); + } + + return $query->select('admission_schedules.*', 'admission_tracks.name as admission_track_name', 'terms.name as term_name'); } /** @@ -68,7 +80,11 @@ class AdmissionScheduleDataTable extends DataTable return $this->builder() ->setTableId('admissionschedule-table') ->columns($this->getColumns()) - ->minifiedAjax() + ->ajax([ + 'data' => 'function(d) { + d.term = $("#term-filter").val() + }', + ]) ->orderBy(-1) ->layout([ 'topStart' => [ @@ -78,7 +94,15 @@ class AdmissionScheduleDataTable extends DataTable ], 'topEnd' => [ 'className' => 'col-md-auto ms-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-end align-items-center align-items-md-start gap-1', - 'features' => ['search'], + 'features' => [ + [ + 'custom-features' => [ + 'targetId' => 'template-term-filter', + 'style' => 'width: 200px;', + ], + ], + 'search' + ], ], 'bottomStart' => 'info', diff --git a/app/Http/DataTables/Finance/ChartOfAccountDataTable.php b/app/Http/DataTables/Finance/ChartOfAccountDataTable.php deleted file mode 100644 index a457234..0000000 --- a/app/Http/DataTables/Finance/ChartOfAccountDataTable.php +++ /dev/null @@ -1,143 +0,0 @@ - $query Results from query() method. - */ - public function dataTable(QueryBuilder $query): EloquentDataTable - { - return (new EloquentDataTable($query)) - ->editColumn('status', fn (ChartOfAccount $coa) => view('components.badge', [ - 'label' => $coa->status->label(), - 'variant' => $coa->status->variant(), - ])) - ->editColumn('classification', fn (ChartOfAccount $coa) => $coa->classification->label()) - ->addColumn( - 'action', - fn ($coa) => view('components.datatables.action-button', [ - 'log' => true, - 'edit' => [ - 'modal' => 'chartofaccount-form-modal', - 'permission' => auth()->user()->can('update', $coa), - ], - 'delete' => [ - 'url' => null, - 'title' => __('ui/button.delete'), - 'message' => __('ui/confirmation.delete', ['resource' => __('resources.chart_of_account')]), - 'success_message' => __('ui/crud.success.deleted', ['resource' => __('resources.chart_of_account')]), - 'permission' => auth()->user()->can('delete', $coa), - ], - 'table_name' => 'chartofaccount-table', - 'id' => $coa->ulid, - ]) - ) - ->rawColumns(['action']) - ->addIndexColumn(); - } - - /** - * Get the query source of dataTable. - * - * @return QueryBuilder - */ - public function query(ChartOfAccount $model): QueryBuilder - { - return $model->newQuery(); - } - - /** - * Optional method if you want to use the html builder. - */ - public function html(): HtmlBuilder - { - return $this->builder() - ->setTableId('chartofaccount-table') - ->columns($this->getColumns()) - ->minifiedAjax() - ->orderBy(-1) - ->layout([ - 'topStart' => [ - 'rowClass' => 'row gap-1', - 'className' => 'col-md-auto me-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-start align-items-center align-items-md-start gap-1', - 'features' => ['buttons', 'pageLength'], - ], - 'topEnd' => [ - 'className' => 'col-md-auto ms-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-end align-items-center align-items-md-start gap-1', - 'features' => ['search'], - ], - - 'bottomStart' => 'info', - 'bottomEnd' => 'paging', - ]) - ->parameters([ - 'language' => [ - 'search' => '', - 'searchPlaceholder' => __('ui/button.lookup'), - ], - 'fixedColumns' => [ - 'start' => 2, - ], - 'scrollX' => true, - 'scrollCollapse' => true, - 'responsive' => true, - ]) - ->buttons([ - Button::make('add') - ->action('javascript:void(0)') - ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#chartofaccount-form-modal']) - ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) - ->addClass('btn-sm'), - Button::make('reload') - ->text(svg('tabler-reload', ['width' => 16, 'height' => 16])->toHtml()) - ->addClass('btn-sm'), - ]); - } - - /** - * Get the dataTable columns definition. - */ - public function getColumns(): array - { - return [ - Column::computed('DT_RowIndex') - ->width(10) - ->title('#'), - Column::make('code') - ->title(__('domains/finance/field.coa.code')), - Column::make('name') - ->title(__('domains/finance/field.coa.name')), - Column::make('classification') - ->title(__('domains/finance/field.coa.classification')), - Column::make('status') - ->width(100) - ->title(__('domains/finance/field.coa.status')), - Column::computed('action') - ->title(__('ui/label.actions')) - ->exportable(false) - ->printable(false) - ->width(60) - ->addClass('text-center'), - ]; - } - - /** - * Get the filename for export. - */ - protected function filename(): string - { - return 'ChartOfAccount_'.date('YmdHis'); - } -} diff --git a/app/Http/DataTables/Finance/InvoiceDataTable.php b/app/Http/DataTables/Finance/InvoiceDataTable.php deleted file mode 100644 index 177a0f2..0000000 --- a/app/Http/DataTables/Finance/InvoiceDataTable.php +++ /dev/null @@ -1,115 +0,0 @@ - $query Results from query() method. - */ - public function dataTable(QueryBuilder $query): EloquentDataTable - { - return (new EloquentDataTable($query)) - ->addColumn('action', 'invoice.action') - ->setRowId('id'); - } - - /** - * Get the query source of dataTable. - * - * @return QueryBuilder - */ - public function query(Invoice $model): QueryBuilder - { - return $model->newQuery(); - } - - /** - * Optional method if you want to use the html builder. - */ - public function html(): HtmlBuilder - { - return $this->builder() - ->setTableId('invoice-table') - ->columns($this->getColumns()) - ->minifiedAjax() - ->orderBy(-1) - ->layout([ - 'topStart' => [ - 'rowClass' => 'row gap-1', - 'className' => 'col-md-auto me-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-start align-items-center align-items-md-start gap-1', - 'features' => ['buttons', 'pageLength'], - ], - 'topEnd' => [ - 'className' => 'col-md-auto ms-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-end align-items-center align-items-md-start gap-1', - 'features' => ['search'], - ], - - 'bottomStart' => 'info', - 'bottomEnd' => 'paging', - ]) - ->parameters([ - 'language' => [ - 'search' => '', - 'searchPlaceholder' => __('ui/button.lookup'), - ], - 'fixedColumns' => [ - 'start' => 2, - ], - 'scrollX' => true, - 'scrollCollapse' => true, - 'responsive' => true, - ]) - ->buttons([ - Button::make('add') - ->action('javascript:void(0)') - ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#invoice-form-modal']) - ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) - ->addClass('btn-sm'), - Button::make('reload') - ->text(svg('tabler-reload', ['width' => 16, 'height' => 16])->toHtml()) - ->addClass('btn-sm'), - ]); - } - - /** - * Get the dataTable columns definition. - */ - public function getColumns(): array - { - return [ - Column::computed('DT_RowIndex') - ->width(10) - ->title('#'), - Column::make('name') - ->title(__('domains/finance/field.invoice.name')), - Column::make('type') - ->title(__('domains/finance/field.invoice.type')), - Column::make('amount') - ->title(__('domains/finance/field.invoice.amount')), - Column::make('client.name') - ->title(__('domains/finance/field.invoice.client_name')), - Column::make('status') - ->width(100) - ->title(__('domains/finance/field.invoice.status')), - ]; - } - - /** - * Get the filename for export. - */ - protected function filename(): string - { - return 'Invoice_'.date('YmdHis'); - } -} diff --git a/app/Http/DataTables/Finance/ProductMappingDataTable.php b/app/Http/DataTables/Finance/ProductMappingDataTable.php deleted file mode 100644 index 7ce0928..0000000 --- a/app/Http/DataTables/Finance/ProductMappingDataTable.php +++ /dev/null @@ -1,137 +0,0 @@ - $query Results from query() method. - */ - public function dataTable(QueryBuilder $query): EloquentDataTable - { - return (new EloquentDataTable($query)) - ->addColumn( - 'action', - fn ($productMapping) => view('components.datatables.action-button', [ - 'log' => true, - 'edit' => [ - 'modal' => 'product-mapping-form-modal', - 'permission' => auth()->user()->can('update', $productMapping), - ], - 'delete' => [ - 'url' => null, - 'title' => __('ui/button.delete'), - 'message' => __('ui/confirmation.delete', ['resource' => __('resources.product_mapping')]), - 'success_message' => __('ui/crud.success.deleted', ['resource' => __('resources.product_mapping')]), - 'permission' => auth()->user()->can('delete', $productMapping), - ], - 'table_name' => 'productmapping-table', - 'id' => $productMapping->ulid, - ]) - ) - ->rawColumns(['action']) - ->addIndexColumn(); - } - - /** - * Get the query source of dataTable. - * - * @return QueryBuilder - */ - public function query(ProductMapping $model): QueryBuilder - { - return $model->newQuery(); - } - - /** - * Optional method if you want to use the html builder. - */ - public function html(): HtmlBuilder - { - return $this->builder() - ->setTableId('productmapping-table') - ->columns($this->getColumns()) - ->minifiedAjax() - ->orderBy(-1) - ->layout([ - 'topStart' => [ - 'rowClass' => 'row gap-1', - 'className' => 'col-md-auto me-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-start align-items-center align-items-md-start gap-1', - 'features' => ['buttons', 'pageLength'], - ], - 'topEnd' => [ - 'className' => 'col-md-auto ms-auto d-flex flex-sm-row flex-column justify-content-center justify-content-md-end align-items-center align-items-md-start gap-1', - 'features' => ['search'], - ], - - 'bottomStart' => 'info', - 'bottomEnd' => 'paging', - ]) - ->parameters([ - 'language' => [ - 'search' => '', - 'searchPlaceholder' => __('ui/button.lookup'), - ], - 'fixedColumns' => [ - 'start' => 2, - ], - 'scrollX' => true, - 'scrollCollapse' => true, - 'responsive' => true, - ]) - ->buttons([ - Button::make('add') - ->action('javascript:void(0)') - ->attr(['data-coreui-toggle' => 'modal', 'data-coreui-target' => '#product-mapping-form-modal']) - ->text(svg('tabler-plus', ['width' => 16, 'height' => 16])->toHtml()) - ->addClass('btn-sm'), - Button::make('reload') - ->text(svg('tabler-reload', ['width' => 16, 'height' => 16])->toHtml()) - ->addClass('btn-sm'), - ]); - } - - /** - * Get the dataTable columns definition. - */ - public function getColumns(): array - { - return [ - Column::computed('DT_RowIndex') - ->width(10) - ->title('#'), - Column::make('code') - ->title(__('domains/finance/field.product_mapping.code')), - Column::make('name') - ->title(__('domains/finance/field.product_mapping.name')), - Column::make('chart_of_account.name') - ->title(__('domains/finance/field.product_mapping.coa_name')), - Column::make('client.name') - ->title(__('domains/finance/field.product_mapping.client_name')), - Column::computed('action') - ->title(__('ui/label.actions')) - ->exportable(false) - ->printable(false) - ->width(60) - ->addClass('text-center'), - ]; - } - - /** - * Get the filename for export. - */ - protected function filename(): string - { - return 'ProductMapping_'.date('YmdHis'); - } -} diff --git a/app/Http/DataTables/Identity/RoleDataTable.php b/app/Http/DataTables/Identity/RoleDataTable.php index 2847a40..e846502 100644 --- a/app/Http/DataTables/Identity/RoleDataTable.php +++ b/app/Http/DataTables/Identity/RoleDataTable.php @@ -45,7 +45,7 @@ class RoleDataTable extends DataTable 'success_message' => __('ui/crud.success.deleted', ['resource' => __('resources.role')]), ], 'table_name' => 'role-table', - 'id' => $role->ulid, + 'id' => $role->id, ]) ) ->addIndexColumn(); diff --git a/app/Livewire/Forms/Finance/InvoiceForm.php b/app/Livewire/Forms/Finance/InvoiceForm.php index 532689d..4cf4801 100644 --- a/app/Livewire/Forms/Finance/InvoiceForm.php +++ b/app/Livewire/Forms/Finance/InvoiceForm.php @@ -58,12 +58,12 @@ class InvoiceForm extends Form public function rules(): array { - return $this->type?->schema()?->getValidationRules('detail'); + return $this->type?->schema()?->getValidationRules('detail') ?? []; } public function validationAttributes(): array { - return $this->type?->schema()?->getValidationAttributes('detail'); + return $this->type?->schema()?->getValidationAttributes('detail') ?? []; } public function toDto(): IssueInvoiceDTO diff --git a/app/Livewire/Forms/Finance/ProductMappingForm.php b/app/Livewire/Forms/Finance/ProductMappingForm.php index d083b06..6a4f2a6 100644 --- a/app/Livewire/Forms/Finance/ProductMappingForm.php +++ b/app/Livewire/Forms/Finance/ProductMappingForm.php @@ -14,7 +14,7 @@ class ProductMappingForm extends Form public string $name = ''; #[Validate('required|string', as: 'domains/finance/field.product-mapping.chart_of_account')] - public string $coa_id = ''; + public ?int $chart_of_account_id = null; // #[Validate('required|string', as: 'domains/finance/field.product-mapping.client')] // public string $client = ''; diff --git a/database/migrations/2026_07_06_031009_create_fee_types_table.php b/database/migrations/2026_07_06_031009_create_fee_types_table.php index 8eefa29..6a51af1 100644 --- a/database/migrations/2026_07_06_031009_create_fee_types_table.php +++ b/database/migrations/2026_07_06_031009_create_fee_types_table.php @@ -15,6 +15,7 @@ return new class extends Migration $table->id(); $table->ulid(); $table->string('name'); + $table->string('code'); $table->string('billing_cycle'); $table->timestamps(); }); diff --git a/database/migrations/2026_07_13_045042_create_product_mappings_table.php b/database/migrations/2026_07_13_045042_create_product_mappings_table.php index 8525708..9e09670 100644 --- a/database/migrations/2026_07_13_045042_create_product_mappings_table.php +++ b/database/migrations/2026_07_13_045042_create_product_mappings_table.php @@ -16,7 +16,7 @@ return new class extends Migration $table->string('code'); $table->string('name'); $table->foreignId('chart_of_account_id')->constrained(); - $table->unsignedBigInteger('client_id')->index(); + $table->unsignedBigInteger('client_id')->index()->nullable(); $table->timestamps(); }); } diff --git a/lang/en/domains/academic/field.php b/lang/en/domains/academic/field.php index 424f6e4..5228b74 100644 --- a/lang/en/domains/academic/field.php +++ b/lang/en/domains/academic/field.php @@ -5,11 +5,14 @@ return [ 'name' => 'Faculty Name', 'code' => 'Faculty Code', 'status' => 'Status', + 'external_id' => 'External ID', ], 'study_program' => [ 'name' => 'Study Program Name', 'code' => 'Study Program Code', 'status' => 'Status', + 'level' => 'Level', + 'external_id' => 'External ID', ], 'term' => [ 'name' => 'Term Name', diff --git a/lang/en/domains/admission/field.php b/lang/en/domains/admission/field.php index 6efcbff..ca92468 100644 --- a/lang/en/domains/admission/field.php +++ b/lang/en/domains/admission/field.php @@ -27,5 +27,10 @@ return [ 'admission_schedule_detail' => [ 'schedule_detail' => 'Admission Schedule Detail', 'fee_detail' => 'Fee Detail', + 'admission_period' => 'Admission Period', + 're_registration_period' => 'Re-registration Period', + 'update_fee_rate' => 'Update Fee Rate', + 'enter_new_fee' => 'Enter the new fee amount:', + 'amount_required' => 'You need to enter an amount!', ], ]; diff --git a/lang/en/domains/admission/label.php b/lang/en/domains/admission/label.php new file mode 100644 index 0000000..6712e48 --- /dev/null +++ b/lang/en/domains/admission/label.php @@ -0,0 +1,10 @@ + [ + 'not_defined' => 'Not Set', + 'partially_defined' => 'Partial', + 'completely_defined' => 'Complete', + ], +]; diff --git a/lang/en/domains/channel/field.php b/lang/en/domains/channel/field.php index feda43a..5565145 100644 --- a/lang/en/domains/channel/field.php +++ b/lang/en/domains/channel/field.php @@ -11,5 +11,6 @@ return [ 'password' => 'Password', 'token' => 'Token', ], + 'endpoint_url' => 'Endpoint URL', ], ]; diff --git a/lang/en/domains/finance/enum.php b/lang/en/domains/finance/enum.php deleted file mode 100644 index 64de028..0000000 --- a/lang/en/domains/finance/enum.php +++ /dev/null @@ -1,38 +0,0 @@ - [ - InvoiceStatus::PAID->value => 'Paid', - InvoiceStatus::PENDING->value => 'Pending', - InvoiceStatus::PARTIALLY_PAID->value => 'Partially Paid', - InvoiceStatus::OVERDUE->value => 'Overdue', - ], - 'invoice_type' => [ - InvoiceType::STUDENT_INVOICE->value => 'Student Invoice', - InvoiceType::VENDOR_BILL->value => 'Vendor Bill', - InvoiceType::CREDIT_NOTE->value => 'Credit Note', - ], - 'payment_status' => [ - PaymentStatus::PENDING->value => 'Pending', - PaymentStatus::SUCCESS->value => 'Success', - PaymentStatus::FAILED->value => 'Failed', - PaymentStatus::EXPIRED->value => 'Expired', - ], - 'payment_direction' => [ - PaymentDirection::RECEIPT->value => 'Receipt', - PaymentDirection::DISBURSEMENT->value => 'Disbursement', - ], - 'account_classification' => [ - AccountClassification::ASSET->value => 'Asset', - AccountClassification::LIABILITY->value => 'Liability', - AccountClassification::EQUITY->value => 'Equity', - AccountClassification::REVENUE->value => 'Revenue', - AccountClassification::EXPENSE->value => 'Expense', - ], -]; diff --git a/lang/en/domains/finance/field.php b/lang/en/domains/finance/field.php deleted file mode 100644 index 7302b3a..0000000 --- a/lang/en/domains/finance/field.php +++ /dev/null @@ -1,50 +0,0 @@ - [ - 'code' => 'Account Code', - 'name' => 'Account Name', - 'classification' => 'Classification', - 'status' => 'Status', - 'parent' => 'Derived From', - ], - 'invoice' => [ - 'name' => 'Invoice Name', - 'code' => 'Invoice Code', - 'type' => 'Invoice Type', - 'amount' => 'Invoice Amount', - 'client_name' => 'Client Name', - 'status' => 'Status', - 'coa_name' => 'Account Name (COA)', - 'detail' => [ - // Detail for Student - 'student_name' => 'Student Name', - 'student_id' => 'Student ID', - 'faculty' => 'Faculty', - 'study_program' => 'Study Program', - 'term_entry' => 'Term Entry', - 'fee_type' => 'Fee Type', - 'semester' => 'Semester', - - // Vendor Bill - 'vendor_name' => 'Vendor Name', - 'vendor_id' => 'Vendor ID', - ], - ], - 'payment' => [ - 'virtual_account' => 'Virtual Account', - 'bank_ref_id' => 'Bank Reference Code', - 'bank_name' => 'Bank Name', - 'nominal' => 'Nominal', - 'validity' => 'Validity', - 'payment_date' => 'Payment Date', - 'direction' => 'Direction', - 'status' => 'Status', - ], - 'product_mapping' => [ - 'code' => 'Product Code', - 'name' => 'Product Name', - 'coa_name' => 'Account Name (COA)', - 'client_name' => 'Client Name', - ], -]; diff --git a/lang/en/domains/finance/seo.php b/lang/en/domains/finance/seo.php deleted file mode 100644 index 08d3fd9..0000000 --- a/lang/en/domains/finance/seo.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - 'title' => 'Chart of Accounts (COA) Data', - 'description' => 'Manage chart of accounts for financial records.', - 'keywords' => 'chart of accounts, coa, accounting, finance', - ], - 'invoice' => [ - 'title' => 'Invoice Data', - 'description' => 'Manage student payment invoices.', - 'keywords' => 'invoice, payment, finance', - ], - 'product_mapping' => [ - 'title' => 'Product Mapping Data', - 'description' => 'Manage cost product mappings with Chart of Accounts (COA).', - 'keywords' => 'product mapping, product, coa, finance', - ], -]; diff --git a/lang/en/domains/system/enum.php b/lang/en/domains/system/enum.php index 9104663..00e0a1a 100644 --- a/lang/en/domains/system/enum.php +++ b/lang/en/domains/system/enum.php @@ -20,6 +20,7 @@ return [ SystemSettingKey::TIMEZONE->value => 'Timezone', SystemSettingKey::GOOGLE_TAG_MANAGER_ID->value => 'Google Tag Manager ID', SystemSettingKey::GOOGLE_WEBMASTER_ID->value => 'Google Webmaster ID', + SystemSettingKey::CURRENT_TERM->value => 'Current Term', ], 'system_setting_key_options' => [ 'default_language' => [ diff --git a/lang/en/ui/button.php b/lang/en/ui/button.php index dac07b1..e33b844 100644 --- a/lang/en/ui/button.php +++ b/lang/en/ui/button.php @@ -18,4 +18,7 @@ return [ 'no' => 'No', 'lookup' => 'Search...', 'logout' => 'Logout', + 'publish' => 'Publish', + 'sync' => 'Sync', + 'run-sync' => 'Run Synchronization', ]; diff --git a/lang/en/ui/placeholder.php b/lang/en/ui/placeholder.php new file mode 100644 index 0000000..4d4e174 --- /dev/null +++ b/lang/en/ui/placeholder.php @@ -0,0 +1,7 @@ + 'Select :attribute', + 'email' => 'name@example.com', + 'filter' => ':attribute Filter', +]; diff --git a/lang/id/domains/academic/field.php b/lang/id/domains/academic/field.php index 4dde791..77d076a 100644 --- a/lang/id/domains/academic/field.php +++ b/lang/id/domains/academic/field.php @@ -5,11 +5,14 @@ return [ 'name' => 'Nama Fakultas', 'code' => 'Kode Fakultas', 'status' => 'Status', + 'external_id' => 'ID Eksternal', ], 'study_program' => [ 'name' => 'Nama Program Studi', 'code' => 'Kode Program Studi', 'status' => 'Status', + 'level' => 'Jenjang', + 'external_id' => 'ID Eksternal', ], 'term' => [ 'name' => 'Nama Tahun Ajaran', diff --git a/lang/id/domains/admission/field.php b/lang/id/domains/admission/field.php index d87a5c1..7146d58 100644 --- a/lang/id/domains/admission/field.php +++ b/lang/id/domains/admission/field.php @@ -27,5 +27,10 @@ return [ 'admission_schedule_detail' => [ 'schedule_detail' => 'Detail Jadwal Penerimaan', 'fee_detail' => 'Detail Biaya', + 'admission_period' => 'Periode Penerimaan', + 're_registration_period' => 'Periode Daftar Ulang', + 'update_fee_rate' => 'Perbarui Tarif Biaya', + 'enter_new_fee' => 'Masukkan jumlah biaya baru:', + 'amount_required' => 'Anda harus memasukkan jumlah!', ], ]; diff --git a/lang/id/domains/admission/label.php b/lang/id/domains/admission/label.php new file mode 100644 index 0000000..ee368e5 --- /dev/null +++ b/lang/id/domains/admission/label.php @@ -0,0 +1,9 @@ + [ + 'not_defined' => 'Not Set', + 'partially_defined' => 'Partial', + 'completely_defined' => 'Complete', + ], +]; diff --git a/lang/id/domains/channel/field.php b/lang/id/domains/channel/field.php index c8de994..e0ab847 100644 --- a/lang/id/domains/channel/field.php +++ b/lang/id/domains/channel/field.php @@ -11,5 +11,6 @@ return [ 'password' => 'Password', 'token' => 'Token', ], + 'endpoint_url' => 'URL Endpoint', ], ]; diff --git a/lang/id/domains/system/enum.php b/lang/id/domains/system/enum.php index aa64ff6..88efb3c 100644 --- a/lang/id/domains/system/enum.php +++ b/lang/id/domains/system/enum.php @@ -20,6 +20,7 @@ return [ SystemSettingKey::TIMEZONE->value => 'Zona Waktu', SystemSettingKey::GOOGLE_TAG_MANAGER_ID->value => 'ID Google Tag Manager', SystemSettingKey::GOOGLE_WEBMASTER_ID->value => 'ID Google Webmaster', + SystemSettingKey::CURRENT_TERM->value => 'Periode Saat Ini', ], 'system_setting_key_options' => [ 'default_language' => [ diff --git a/lang/id/ui/button.php b/lang/id/ui/button.php index 8f7c96d..6979779 100644 --- a/lang/id/ui/button.php +++ b/lang/id/ui/button.php @@ -17,4 +17,7 @@ return [ 'no' => 'Tidak', 'lookup' => 'Cari...', 'logout' => 'Keluar', + 'publish' => 'Terbitkan', + 'sync' => 'Sinkronisasi', + 'run-sync' => 'Jalankan Sinkronisasi', ]; diff --git a/lang/id/ui/placeholder.php b/lang/id/ui/placeholder.php new file mode 100644 index 0000000..115b586 --- /dev/null +++ b/lang/id/ui/placeholder.php @@ -0,0 +1,7 @@ + 'Pilih :attribute', + 'email' => 'nama@contoh.com', + 'filter' => 'Filter :attribute', +]; diff --git a/resources/views/components/datatables/⚡excel-manager.blade.php b/resources/views/components/datatables/⚡excel-manager.blade.php index 60f344e..a811a1b 100644 --- a/resources/views/components/datatables/⚡excel-manager.blade.php +++ b/resources/views/components/datatables/⚡excel-manager.blade.php @@ -96,7 +96,7 @@ new class extends Component - + @push('scripts') @vite(['resources/js/plugin/filepond.js']) diff --git a/resources/views/components/layouts/nav/sidebar.blade.php b/resources/views/components/layouts/nav/sidebar.blade.php index b4f1d2c..085746b 100644 --- a/resources/views/components/layouts/nav/sidebar.blade.php +++ b/resources/views/components/layouts/nav/sidebar.blade.php @@ -78,26 +78,6 @@ permission="client.viewAny" /> - {{ __('ui/menu.finance') }} - - - - {{ __('ui/menu.management') }}