diff --git a/app/Filament/Pages/Dashboard.php b/app/Filament/Pages/Dashboard.php
index e6bc611..d32813a 100644
--- a/app/Filament/Pages/Dashboard.php
+++ b/app/Filament/Pages/Dashboard.php
@@ -34,14 +34,13 @@ protected function getWidgets(): array
{
return [
AccountWidget::class,
- FilamentInfoWidget::class,
RevenueWidget::class,
];
}
protected function getColumns(): int | string | array
{
- return 2;
+ return 1;
}
protected function getTitle(): string
diff --git a/app/Filament/Resources/AccountResource.php b/app/Filament/Resources/AccountResource.php
index f706c74..36fb63c 100644
--- a/app/Filament/Resources/AccountResource.php
+++ b/app/Filament/Resources/AccountResource.php
@@ -6,14 +6,17 @@
use App\Filament\Resources\AccountResource\RelationManagers;
use App\Models\Account;
use App\Models\AccountType;
+use Filament\Tables\Actions\Action;
use App\Models\Currency;
use Filament\Forms;
+use Filament\Forms\Components\Card;
use Filament\Forms\Components\Grid;
use Filament\Resources\Form;
use Filament\Resources\Resource;
use Filament\Resources\Table;
use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class AccountResource extends Resource
@@ -22,6 +25,8 @@ class AccountResource extends Resource
protected static ?string $navigationIcon = 'heroicon-o-cash';
+ public ?Model $record = null;
+
public static function form(Form $form): Form
{
return $form
@@ -71,6 +76,14 @@ public static function table(Table $table): Table
Tables\Filters\TrashedFilter::make(),
])
->actions([
+ Action::make('detail')
+ ->label('Detail')
+ ->color('blue')
+ ->icon('heroicon-s-document')
+ ->hidden(fn ($record) => !$record->has_any_relation)
+ ->url(function ($record) {
+ return route('filament.resources.accounts.detail', ['record' => $record]);
+ }),
Tables\Actions\ViewAction::make(),
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make()
@@ -85,6 +98,7 @@ public static function getPages(): array
{
return [
'index' => Pages\ManageAccounts::route('/'),
+ 'detail' => Pages\AccountDetail::route('/{record}/detail'),
];
}
diff --git a/app/Filament/Resources/AccountResource/Pages/AccountDetail.php b/app/Filament/Resources/AccountResource/Pages/AccountDetail.php
new file mode 100644
index 0000000..ff35b7a
--- /dev/null
+++ b/app/Filament/Resources/AccountResource/Pages/AccountDetail.php
@@ -0,0 +1,34 @@
+record = $record;
+ $this->account = Account::find($record);
+ }
+}
diff --git a/app/Filament/Resources/RevenueResource.php b/app/Filament/Resources/RevenueResource.php
index 486f65e..d44aa0e 100644
--- a/app/Filament/Resources/RevenueResource.php
+++ b/app/Filament/Resources/RevenueResource.php
@@ -8,6 +8,7 @@
use App\Filament\Resources\RevenueResource\Widgets\RevenueWidget;
use App\Models\Account;
use App\Models\Company;
+use App\Models\Invoice;
use App\Models\Revenue;
use Carbon\Carbon;
use Closure;
diff --git a/app/Http/Livewire/Account/ExpenseTable.php b/app/Http/Livewire/Account/ExpenseTable.php
new file mode 100644
index 0000000..4e4758b
--- /dev/null
+++ b/app/Http/Livewire/Account/ExpenseTable.php
@@ -0,0 +1,105 @@
+where('account_id', $this->accountID);
+ }
+
+ protected function getTableColumns(): array
+ {
+ return [
+ Tables\Columns\TextColumn::make('due_at')
+ ->label('Date')
+ ->sortable()
+ ->dateTime('d/m/Y'),
+ Tables\Columns\TextColumn::make('description')
+ ->searchable(),
+ Tables\Columns\TextColumn::make('company.name')
+ ->searchable()
+ ->label('Company'),
+ Tables\Columns\TextColumn::make('corporation.name')
+ ->searchable()
+ ->label('Corporation'),
+ Tables\Columns\TextColumn::make('amount_with_currency')
+ ->label('Amount')
+ ->formatStateUsing(fn ($state) => '-' . $state)
+ ->sortable(),
+ ];
+ }
+
+ protected function getTableFilters(): array
+ {
+ return [
+ Filter::make('due_at')
+ ->form([
+ Forms\Components\DatePicker::make('due_from')
+ ->default(Carbon::now()->subYear())
+ ->closeOnDateSelection()
+ ->timezone('Europe/Istanbul')
+ ->label('From Date'),
+ Forms\Components\DatePicker::make('due_until')
+ ->closeOnDateSelection()
+ ->timezone('Europe/Istanbul')
+ ->label('To Date')
+ ])
+ ->query(function (Builder $query, array $data): Builder {
+ return $query
+ ->when(
+ $data['due_from'],
+ fn (Builder $query, $date): Builder => $query->whereDate('due_at', '>=', $date),
+ )
+ ->when(
+ $data['due_until'],
+ fn (Builder $query, $date): Builder => $query->whereDate('due_at', '<=', $date),
+ );
+ }),
+ Filter::make('amount')
+ ->form([
+ Forms\Components\TextInput::make('min_amount')
+ ->label('Min Amount'),
+ Forms\Components\TextInput::make('max_amount')
+ ->label('Max Amount')
+ ])
+ ->query(function (Builder $query, array $data): Builder {
+ return $query
+ ->when(
+ $data['min_amount'],
+ fn (Builder $query, $amount): Builder => $query->where('amount', '>=', $amount),
+ )
+ ->when(
+ $data['max_amount'],
+ fn (Builder $query, $amount): Builder => $query->where('amount', '<=', $amount),
+ );
+ }),
+ ];
+ }
+
+ protected function getTableFiltersFormColumns(): int
+ {
+ return 2;
+ }
+
+ public function render()
+ {
+ return view('livewire.account.expense-table');
+ }
+}
diff --git a/app/Http/Livewire/Account/RevenueTable.php b/app/Http/Livewire/Account/RevenueTable.php
new file mode 100644
index 0000000..76594a6
--- /dev/null
+++ b/app/Http/Livewire/Account/RevenueTable.php
@@ -0,0 +1,104 @@
+where('account_id', $this->accountID);
+ }
+
+ protected function getTableColumns(): array
+ {
+ return [
+ Tables\Columns\TextColumn::make('due_at')
+ ->label('Date')
+ ->sortable()
+ ->dateTime('d/m/Y'),
+ Tables\Columns\TextColumn::make('description')
+ ->searchable(),
+ Tables\Columns\TextColumn::make('company.name')
+ ->searchable()
+ ->label('Company'),
+ Tables\Columns\TextColumn::make('corporation.name')
+ ->searchable()
+ ->label('Corporation'),
+ Tables\Columns\TextColumn::make('amount_with_currency')
+ ->label('Amount')
+ ->sortable(),
+ ];
+ }
+
+ protected function getTableFilters(): array
+ {
+ return [
+ Filter::make('due_at')
+ ->form([
+ Forms\Components\DatePicker::make('due_from')
+ ->default(Carbon::now()->subYear())
+ ->closeOnDateSelection()
+ ->timezone('Europe/Istanbul')
+ ->label('From Date'),
+ Forms\Components\DatePicker::make('due_until')
+ ->closeOnDateSelection()
+ ->timezone('Europe/Istanbul')
+ ->label('To Date')
+ ])
+ ->query(function (Builder $query, array $data): Builder {
+ return $query
+ ->when(
+ $data['due_from'],
+ fn (Builder $query, $date): Builder => $query->whereDate('due_at', '>=', $date),
+ )
+ ->when(
+ $data['due_until'],
+ fn (Builder $query, $date): Builder => $query->whereDate('due_at', '<=', $date),
+ );
+ }),
+ Filter::make('amount')
+ ->form([
+ Forms\Components\TextInput::make('min_amount')
+ ->label('Min Amount'),
+ Forms\Components\TextInput::make('max_amount')
+ ->label('Max Amount')
+ ])
+ ->query(function (Builder $query, array $data): Builder {
+ return $query
+ ->when(
+ $data['min_amount'],
+ fn (Builder $query, $amount): Builder => $query->where('amount', '>=', $amount),
+ )
+ ->when(
+ $data['max_amount'],
+ fn (Builder $query, $amount): Builder => $query->where('amount', '<=', $amount),
+ );
+ }),
+ ];
+ }
+
+ protected function getTableFiltersFormColumns(): int
+ {
+ return 2;
+ }
+
+ public function render(): View
+ {
+ return view('livewire.account.revenue-table');
+ }
+}
diff --git a/app/Http/Livewire/Account/TransactionTable.php b/app/Http/Livewire/Account/TransactionTable.php
new file mode 100644
index 0000000..86c4448
--- /dev/null
+++ b/app/Http/Livewire/Account/TransactionTable.php
@@ -0,0 +1,106 @@
+where('to_account_id', $this->accountID);
+ $outgoing = Transaction::query()->where('from_account_id', $this->accountID);
+ return $incoming->union($outgoing);
+ }
+
+ protected function getTableColumns(): array
+ {
+ return [
+ Tables\Columns\TextColumn::make('due_at')
+ ->label('Date')
+ ->sortable()
+ ->dateTime('d/m/Y'),
+ Tables\Columns\TextColumn::make('description')
+ ->searchable(),
+ Tables\Columns\TextColumn::make('from_account.name')
+ ->searchable()
+ ->label('Sender Account'),
+ Tables\Columns\TextColumn::make('to_account.name')
+ ->searchable()
+ ->label('Receiver Account'),
+ Tables\Columns\TextColumn::make('amount_with_currency')
+ ->label('Amount')
+ ->formatStateUsing(fn (?Model $record, $state) => $record->from_account_id !== $this->accountID ? '-' . $state : $state)
+ ];
+ }
+
+ protected function getTableFilters(): array
+ {
+ return [
+ Filter::make('due_at')
+ ->form([
+ Forms\Components\DatePicker::make('due_from')
+ ->default(Carbon::now()->subYear())
+ ->closeOnDateSelection()
+ ->timezone('Europe/Istanbul')
+ ->label('From Date'),
+ Forms\Components\DatePicker::make('due_until')
+ ->closeOnDateSelection()
+ ->timezone('Europe/Istanbul')
+ ->label('To Date')
+ ])
+ ->query(function (Builder $query, array $data): Builder {
+ return $query
+ ->when(
+ $data['due_from'],
+ fn (Builder $query, $date): Builder => $query->whereDate('due_at', '>=', $date),
+ )
+ ->when(
+ $data['due_until'],
+ fn (Builder $query, $date): Builder => $query->whereDate('due_at', '<=', $date),
+ );
+ }),
+ Filter::make('amount')
+ ->form([
+ Forms\Components\TextInput::make('min_amount')
+ ->label('Min Amount'),
+ Forms\Components\TextInput::make('max_amount')
+ ->label('Max Amount')
+ ])
+ ->query(function (Builder $query, array $data): Builder {
+ return $query
+ ->when(
+ $data['min_amount'],
+ fn (Builder $query, $amount): Builder => $query->where('amount', '>=', $amount),
+ )
+ ->when(
+ $data['max_amount'],
+ fn (Builder $query, $amount): Builder => $query->where('amount', '<=', $amount),
+ );
+ }),
+ ];
+ }
+
+ protected function getTableFiltersFormColumns(): int
+ {
+ return 2;
+ }
+
+ public function render()
+ {
+ return view('livewire.account.transaction-table');
+ }
+}
diff --git a/app/Models/Account.php b/app/Models/Account.php
index 1a89e3d..996d6d2 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -2,6 +2,8 @@
namespace App\Models;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -55,7 +57,13 @@ public function incomingTransactions()
public function getBalanceAttribute()
{
- return $this->starting_balance + $this->revenues()->sum('amount') - $this->expenses()->sum('amount') + $this->incomingTransactions()->sum('amount') - $this->outgoingTransactions()->sum('amount');
+ $balance = $this->starting_balance + $this->revenues()->sum('amount') - $this->expenses()->sum('amount') + $this->incomingTransactions()->sum('amount') - $this->outgoingTransactions()->sum('amount');
+
+ if ($this->currency->position == 'right') {
+ return number_format($balance, 2) . ' ' . $this->currency->symbol;
+ } else {
+ return $this->currency->symbol . ' ' . number_format($balance, 2);
+ }
}
public function getHasAnyRelationAttribute()
diff --git a/app/Models/Expense.php b/app/Models/Expense.php
index b430a99..c4b81a0 100644
--- a/app/Models/Expense.php
+++ b/app/Models/Expense.php
@@ -26,7 +26,9 @@ class Expense extends Model
protected $appends = [
'has_any_relation',
- 'bill_number'
+ 'bill_number',
+ 'transaction_type',
+ 'amount_with_currency'
];
public function account()
@@ -63,4 +65,13 @@ public function getBillNumberAttribute()
{
return $this->bills()->first()->number ?? null;
}
+
+ public function getAmountWithCurrencyAttribute()
+ {
+ if ($this->corporation->currency->position === "right") {
+ return number_format($this->amount, 2) . " " . $this->corporation->currency->symbol;
+ } else {
+ return $this->corporation->currency->symbol . " " . number_format($this->amount, 2);
+ }
+ }
}
diff --git a/app/Models/Revenue.php b/app/Models/Revenue.php
index 402215c..64e5f57 100644
--- a/app/Models/Revenue.php
+++ b/app/Models/Revenue.php
@@ -26,7 +26,9 @@ class Revenue extends Model
protected $appends = [
'has_any_relation',
- 'invoice_number'
+ 'invoice_number',
+ 'transaction_type',
+ 'amount_with_currency'
];
public function account()
@@ -63,4 +65,13 @@ public function getInvoiceNumberAttribute()
{
return $this->invoices()->first()->number ?? null;
}
+
+ public function getAmountWithCurrencyAttribute()
+ {
+ if ($this->corporation->currency->position === "right") {
+ return number_format($this->amount, 2) . " " . $this->corporation->currency->symbol;
+ } else {
+ return $this->corporation->currency->symbol . " " . number_format($this->amount, 2);
+ }
+ }
}
diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php
index 59ab351..99967f6 100644
--- a/app/Models/Transaction.php
+++ b/app/Models/Transaction.php
@@ -11,6 +11,16 @@ class Transaction extends Model
protected $fillable = ['from_account_id', 'to_account_id', 'amount', 'description', 'due_at'];
+ protected $appends = [
+ 'transaction_type',
+ 'amount_with_currency'
+ ];
+
+ protected $casts = [
+ 'due_at' => 'date'
+ ];
+
+
public function from_account()
{
return $this->belongsTo(Account::class, 'from_account_id');
@@ -20,4 +30,18 @@ public function to_account()
{
return $this->belongsTo(Account::class, 'to_account_id');
}
+
+ public function getTransactionTypeAttribute()
+ {
+ return $this->from_account_id || $this->to_account_id ? 'transaction' : '';
+ }
+
+ public function getAmountWithCurrencyAttribute()
+ {
+ if ($this->from_account->currency->position === "right") {
+ return number_format($this->amount, 2) . " " . $this->from_account->currency->symbol;
+ } else {
+ return $this->from_account->currency->symbol . " " . number_format($this->amount, 2);
+ }
+ }
}
diff --git a/composer.json b/composer.json
index 72e63c5..e4d21a6 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,8 @@
"laravel/sanctum": "^3.2",
"laravel/tinker": "^2.8",
"livewire/livewire": "^2.12",
- "marjose123/filament-lockscreen": "^1.1"
+ "marjose123/filament-lockscreen": "^1.1",
+ "webbingbrasil/filament-datefilter": "^1.1"
},
"require-dev": {
"doctrine/dbal": "^3.6",
diff --git a/composer.lock b/composer.lock
index c780209..d6b21c2 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "0a09f2476a72cce462cd629c22798c22",
+ "content-hash": "d8d29ad962646faca1c7ccad318b842e",
"packages": [
{
"name": "akaunting/laravel-money",
@@ -7178,6 +7178,54 @@
],
"time": "2022-03-08T17:03:00+00:00"
},
+ {
+ "name": "webbingbrasil/filament-datefilter",
+ "version": "1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/webbingbrasil/filament-datefilter.git",
+ "reference": "3613479d857ee5192966b9450441b577a3d1ed1f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/webbingbrasil/filament-datefilter/zipball/3613479d857ee5192966b9450441b577a3d1ed1f",
+ "reference": "3613479d857ee5192966b9450441b577a3d1ed1f",
+ "shasum": ""
+ },
+ "require": {
+ "filament/tables": "^2.15",
+ "php": "^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Webbingbrasil\\FilamentDateFilter\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Danilo Andrade",
+ "email": "danilo@webbingbrasil.com.br",
+ "role": "Developer"
+ }
+ ],
+ "description": "Date filter component for filament tables.",
+ "homepage": "https://github.com/webbingbrasil/filament-datefilter",
+ "keywords": [
+ "filament",
+ "filter",
+ "laravel"
+ ],
+ "support": {
+ "issues": "https://github.com/webbingbrasil/filament-datefilter/issues",
+ "source": "https://github.com/webbingbrasil/filament-datefilter/tree/1.1.1"
+ },
+ "time": "2022-10-24T21:46:22+00:00"
+ },
{
"name": "webmozart/assert",
"version": "1.11.0",
diff --git a/resources/views/filament/resources/account-resource/pages/account-detail.blade.php b/resources/views/filament/resources/account-resource/pages/account-detail.blade.php
new file mode 100644
index 0000000..2ac499c
--- /dev/null
+++ b/resources/views/filament/resources/account-resource/pages/account-detail.blade.php
@@ -0,0 +1,18 @@
+Revenues
+ Expenses
+ Transactions
+