diff --git a/app/Filament/Resources/MemberDues/MemberDueResource.php b/app/Filament/Resources/MemberDues/MemberDueResource.php new file mode 100644 index 0000000..3055a5a --- /dev/null +++ b/app/Filament/Resources/MemberDues/MemberDueResource.php @@ -0,0 +1,40 @@ + ListMemberDues::route('/'), + 'create' => CreateMemberDue::route('/create'), + 'edit' => EditMemberDue::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/MemberDues/Pages/CreateMemberDue.php b/app/Filament/Resources/MemberDues/Pages/CreateMemberDue.php new file mode 100644 index 0000000..dc4fe5f --- /dev/null +++ b/app/Filament/Resources/MemberDues/Pages/CreateMemberDue.php @@ -0,0 +1,11 @@ +components([ + Select::make('user_id')->label('Anggota') + ->options(User::where('status', 'aktif')->pluck('name', 'id')) + ->searchable()->required(), + TextInput::make('period')->label('Periode (YYYY-MM)') + ->placeholder(now()->format('Y-m')) + ->required(), + TextInput::make('amount')->label('Jumlah (Rp)')->numeric()->required(), + Select::make('status')->options(['lunas' => 'Lunas', 'belum' => 'Belum Lunas']) + ->default('belum')->required() + ->live(), + DatePicker::make('paid_at')->label('Tanggal Bayar') + ->visible(fn ($get) => $get('status') === 'lunas'), + Textarea::make('notes')->label('Catatan')->rows(2)->columnSpanFull(), + ]); + } +} diff --git a/app/Filament/Resources/MemberDues/Tables/MemberDuesTable.php b/app/Filament/Resources/MemberDues/Tables/MemberDuesTable.php new file mode 100644 index 0000000..3091841 --- /dev/null +++ b/app/Filament/Resources/MemberDues/Tables/MemberDuesTable.php @@ -0,0 +1,34 @@ +columns([ + TextColumn::make('user.name')->label('Anggota')->searchable()->sortable(), + TextColumn::make('period')->label('Periode')->sortable(), + TextColumn::make('amount')->label('Jumlah')->money('IDR')->sortable(), + TextColumn::make('status')->label('Status')->badge() + ->color(fn ($state) => $state === 'lunas' ? 'success' : 'danger'), + TextColumn::make('paid_at')->label('Tgl Bayar')->date('d M Y')->placeholder('-'), + TextColumn::make('notes')->label('Catatan')->limit(30)->placeholder('-'), + ]) + ->defaultSort('period', 'desc') + ->filters([ + SelectFilter::make('status')->options(['lunas' => 'Lunas', 'belum' => 'Belum Lunas']), + ]) + ->recordActions([EditAction::make()]) + ->toolbarActions([BulkActionGroup::make([DeleteBulkAction::make()])]); + } +} diff --git a/app/Models/MemberDue.php b/app/Models/MemberDue.php new file mode 100644 index 0000000..33a31f6 --- /dev/null +++ b/app/Models/MemberDue.php @@ -0,0 +1,34 @@ + 'date', + ]; + + protected static function booted(): void + { + static::creating(function (MemberDue $due) { + $due->created_by ??= auth()->id(); + }); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } + + public function creator(): BelongsTo + { + return $this->belongsTo(User::class, 'created_by'); + } +} diff --git a/database/migrations/2026_04_03_205932_create_member_dues_table.php b/database/migrations/2026_04_03_205932_create_member_dues_table.php new file mode 100644 index 0000000..2dd8669 --- /dev/null +++ b/database/migrations/2026_04_03_205932_create_member_dues_table.php @@ -0,0 +1,30 @@ +id(); + $table->foreignId('user_id')->constrained('users'); + $table->unsignedInteger('amount'); + $table->string('period'); // format: YYYY-MM + $table->enum('status', ['lunas', 'belum'])->default('belum'); + $table->date('paid_at')->nullable(); + $table->text('notes')->nullable(); + $table->foreignId('created_by')->constrained('users'); + $table->timestamps(); + + $table->unique(['user_id', 'period']); + }); + } + + public function down(): void + { + Schema::dropIfExists('member_dues'); + } +};