feat(client): add financial reports and ledger management
- Add trial balance and general ledger pages to client resource with interactive tables - Implement sales and expenses relation managers for client-specific transactions - Enhance transaction handling with proper tax and withholding calculations - Add date casting to Transaction model and define client relationships - Configure super admin role bypass in AppServiceProvider - Update Filament components and fix JavaScript formatting issues
This commit is contained in:
142
app/Filament/Resources/ClientResource/Pages/GeneralLedger.php
Normal file
142
app/Filament/Resources/ClientResource/Pages/GeneralLedger.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\ClientResource\Pages;
|
||||
|
||||
use App\Filament\Resources\ClientResource;
|
||||
use App\Models\Ledger;
|
||||
use Filament\Resources\Pages\Page;
|
||||
use Filament\Tables\Concerns\InteractsWithTable;
|
||||
use Filament\Tables\Contracts\HasTable;
|
||||
use Filament\Tables\Table;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\Filter;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Filament\Resources\Pages\Concerns\InteractsWithRecord;
|
||||
use pxlrbt\FilamentExcel\Actions\Tables\ExportAction;
|
||||
use pxlrbt\FilamentExcel\Exports\ExcelExport;
|
||||
use pxlrbt\FilamentExcel\Columns\Column;
|
||||
|
||||
class GeneralLedger extends Page implements HasTable
|
||||
{
|
||||
use InteractsWithTable;
|
||||
use InteractsWithRecord;
|
||||
|
||||
protected static string $resource = ClientResource::class;
|
||||
|
||||
protected static ?string $navigationIcon = 'heroicon-o-document-text';
|
||||
|
||||
protected static string $view = 'filament.resources.client-resource.pages.general-ledger';
|
||||
|
||||
public function mount(int | string $record): void
|
||||
{
|
||||
$this->record = $this->resolveRecord($record);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->query(
|
||||
Ledger::query()
|
||||
->where('client_id', $this->getRecord()->id)
|
||||
->with(['account', 'transaction', 'journal'])
|
||||
)
|
||||
->columns([
|
||||
TextColumn::make('date')
|
||||
->label('Date')
|
||||
->state(function (Ledger $record) {
|
||||
return $record->transaction?->happened_on?->format('Y-m-d')
|
||||
?? $record->journal?->happened_on?->format('Y-m-d')
|
||||
?? $record->created_at->format('Y-m-d');
|
||||
})
|
||||
->sortable(),
|
||||
TextColumn::make('account.account')
|
||||
->label('Account')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('description')
|
||||
->limit(50)
|
||||
->tooltip(function (TextColumn $column): ?string {
|
||||
$state = $column->getState();
|
||||
if (strlen($state) <= $column->getCharacterLimit()) {
|
||||
return null;
|
||||
}
|
||||
return $state;
|
||||
}),
|
||||
TextColumn::make('debit_amount')
|
||||
->label('Debit')
|
||||
->money('PHP')
|
||||
->sortable(),
|
||||
TextColumn::make('credit_amount')
|
||||
->label('Credit')
|
||||
->money('PHP')
|
||||
->sortable(),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('account')
|
||||
->relationship('account', 'account', fn (Builder $query) => $query->where('client_id', $this->getRecord()->id))
|
||||
->searchable()
|
||||
->preload(),
|
||||
Filter::make('date_range')
|
||||
->form([
|
||||
DatePicker::make('from'),
|
||||
DatePicker::make('to'),
|
||||
])
|
||||
->query(function (Builder $query, array $data): Builder {
|
||||
return $query
|
||||
->when(
|
||||
$data['from'],
|
||||
fn (Builder $query, $date): Builder => $query->where(function ($q) use ($date) {
|
||||
$q->whereHas('transaction', fn ($q) => $q->whereDate('happened_on', '>=', $date))
|
||||
->orWhereHas('journal', fn ($q) => $q->whereDate('happened_on', '>=', $date))
|
||||
->orWhere(fn($q) => $q->whereDoesntHave('transaction')->whereDoesntHave('journal')->whereDate('created_at', '>=', $date));
|
||||
})
|
||||
)
|
||||
->when(
|
||||
$data['to'],
|
||||
fn (Builder $query, $date): Builder => $query->where(function ($q) use ($date) {
|
||||
$q->whereHas('transaction', fn ($q) => $q->whereDate('happened_on', '<=', $date))
|
||||
->orWhereHas('journal', fn ($q) => $q->whereDate('happened_on', '<=', $date))
|
||||
->orWhere(fn($q) => $q->whereDoesntHave('transaction')->whereDoesntHave('journal')->whereDate('created_at', '<=', $date));
|
||||
})
|
||||
);
|
||||
})
|
||||
])
|
||||
->defaultSort('created_at', 'desc')
|
||||
->groups([
|
||||
'account.account',
|
||||
])
|
||||
->headerActions([
|
||||
ExportAction::make()
|
||||
->label('Export General Ledger')
|
||||
->exports([
|
||||
ExcelExport::make()
|
||||
->fromTable()
|
||||
->withFilename(fn () => $this->getRecord()->name . ' - General Ledger - ' . date('Y-m-d'))
|
||||
->withColumns([
|
||||
Column::make('date')
|
||||
->heading('Date')
|
||||
->formatStateUsing(fn ($record) => $record->transaction?->happened_on?->format('Y-m-d')
|
||||
?? $record->journal?->happened_on?->format('Y-m-d')
|
||||
?? $record->created_at->format('Y-m-d')),
|
||||
Column::make('reference')
|
||||
->heading('Reference')
|
||||
->formatStateUsing(fn ($record) => match(true) {
|
||||
$record->transaction && $record->transaction->transactionable =>
|
||||
$record->transaction->transactionable->voucher_number
|
||||
?? $record->transaction->transactionable->reference_number
|
||||
?? 'TR-'.$record->transaction->id,
|
||||
$record->transaction => 'TR-'.$record->transaction->id,
|
||||
$record->journal => $record->journal->series ?? 'JV-'.$record->journal->id,
|
||||
default => 'L-'.$record->id,
|
||||
}),
|
||||
Column::make('account.account')->heading('Account'),
|
||||
Column::make('description')->heading('Description'),
|
||||
Column::make('debit_amount')->heading('Debit'),
|
||||
Column::make('credit_amount')->heading('Credit'),
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user