Implement double entry accounting for filament 3 transaction resourceliberu-accounting/accounting-laravel#48
Implement double entry accounting for filament 3 transaction resource
liberu-accounting/accounting-laravel#48
> > >
✓ Completed in 7 minutes, 3 months ago using GPT-4  •  Book a call  •  Report a bug
Progress
  Create
app/Rules/DoubleEntryValidator.php
45a2fac
 1<?php
2
3namespace App\Rules;
4
5use Illuminate\Contracts\Validation\Rule;
6use Illuminate\Support\Facades\DB;
7use App\Models\Transaction;
8
9class DoubleEntryValidator implements Rule
10{
11 public function passes($attribute, $value)
12 {
13 $debitSum = request()->input('debit_account_id') ? Transaction::where('debit_account_id', request()->input('debit_account_id'))->sum('amount') : 0;
14 $creditSum = request()->input('credit_account_id') ? Transaction::where('credit_account_id', request()->input('credit_account_id'))->sum('amount') : 0;
15
16 // Adding current transaction amount to the respective sum based on the attribute being validated
17 if ($attribute === 'debit_account_id') {
18 $debitSum += $value;
19 } else if ($attribute === 'credit_account_id') {
20 $creditSum += $value;
21 }
22
23 return $debitSum == $creditSum;
24 }
25
26 public function message()
27 {
28 return 'The transaction does not adhere to double-entry accounting principles.';
29 }
30}
31
- Create a new file
DoubleEntryValidator.php
in theapp/Rules
directory. - This file will contain a custom validation rule that ensures the sum of debit transactions equals the sum of credit transactions for each entry.
- The validator will use Laravel's built-in validation rule structure and will be applied in the TransactionResource form submission.
- Import necessary models and validation classes from Laravel at the top of the file.
- Implement the passes and message methods as required by Laravel's custom validation rules.
Example structure:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class DoubleEntryValidator implements Rule
{
public function passes($attribute, $value)
{
// Logic to check if the transaction adheres to double-entry principles
}
public function message()
{
return 'The transaction does not adhere to double-entry accounting principles.';
}
}
  Run GitHub Actions for
app/Rules/DoubleEntryValidator.phpÂ
Ran GitHub Actions for 45a2fac77e863a608b1a0f03cf60953f274a81a2:
  ModifyChanged
app/Filament/Admin/Resources/TransactionResource.phpÂ
Changed app/Filament/Admin/Resources/TransactionResource.php
in b70528d
   Â
15 | use Illuminate\Database\Eloquent\Builder; | 15 | use Illuminate\Database\Eloquent\Builder; |
16 | use Filament\Forms\Components\BelongsToSelect; | 16 | use Filament\Forms\Components\BelongsToSelect; |
17 | use Illuminate\Database\Eloquent\SoftDeletingScope; | 17 | use Illuminate\Database\Eloquent\SoftDeletingScope; |
18 | use App\Rules\DoubleEntryValidator; | ||
18 | use App\Filament\Admin\Resources\TransactionResource\Pages; | 19 | use App\Filament\Admin\Resources\TransactionResource\Pages; |
19 | use App\Filament\Admin\Resources\TransactionResource\RelationManagers; | 20 | use App\Filament\Admin\Resources\TransactionResource\RelationManagers; |
20 | 21 | ||
... | |||
34 | ->label('Description'), | 35 | ->label('Description'), |
35 | TextInput::make('amount') | 36 | TextInput::make('amount') |
36 | ->numeric() | 37 | ->numeric() |
37 | ->label('Amount'), | 38 | ->label('Amount') |
39 | ->rules(['required', new DoubleEntryValidator()]), | ||
38 | BelongsToSelect::make('debit_account_id') | 40 | BelongsToSelect::make('debit_account_id') |
39 | ->relationship('debitAccount', 'name') | 41 | ->relationship('debitAccount', 'name') |
40 | ->label('Debit Account'), | 42 | ->label('Debit Account'), |
- Import the
DoubleEntryValidator
at the top of the file. - In the
form
method, add theDoubleEntryValidator
to the validation rules for theamount
field. This ensures that every transaction adheres to double-entry accounting principles before being saved. - Update the comments to reflect the inclusion of double-entry validation.
Example modification:
use App\Rules\DoubleEntryValidator;
...
TextInput::make('amount')
->numeric()
->label('Amount')
->rules(['required', new DoubleEntryValidator()]),
  Run GitHub Actions for
app/Filament/Admin/Resources/TransactionResource.phpÂ
Ran GitHub Actions for b70528d6c7d0ea475088ea7874fd41d090e44fc3:
  ModifyChanged
app/Models/Transaction.phpÂ
Changed app/Models/Transaction.php
in 0eba22a
   Â
17 | 'amount', | 17 | 'amount', |
18 | 'debit_account_id', | 18 | 'debit_account_id', |
19 | 'credit_account_id', | 19 | 'credit_account_id', |
20 | // Add any other necessary fields for double-entry accounting here | ||
20 | ]; | 21 | ]; |
21 | 22 | ||
22 | public function debitAccount() | 23 | public function debitAccount() |
- In the
Transaction
model, ensure that the relationships with debit and credit accounts are correctly defined to support double-entry accounting. - Add any necessary methods or attributes that might be needed to support the validation logic in
DoubleEntryValidator
. For example, methods to calculate the total debit and credit amounts for a transaction. - Ensure the
$fillable
property includes all fields necessary for double-entry accounting.
Example modification:
protected $fillable = [
'transaction_date',
'transaction_description',
'amount',
'debit_account_id',
'credit_account_id',
// Add any other necessary fields
];
  Run GitHub Actions for
app/Models/Transaction.phpÂ
Ran GitHub Actions for 0eba22aeef23190fde6634137c04c2297b03d3ba:
Plan
This is based on the results of the Planning step. The plan may expand from failed GitHub Actions runs.
  Create
app/Rules/DoubleEntryValidator.php
45a2fac
 1<?php
2
3namespace App\Rules;
4
5use Illuminate\Contracts\Validation\Rule;
6use Illuminate\Support\Facades\DB;
7use App\Models\Transaction;
8
9class DoubleEntryValidator implements Rule
10{
11 public function passes($attribute, $value)
12 {
13 $debitSum = request()->input('debit_account_id') ? Transaction::where('debit_account_id', request()->input('debit_account_id'))->sum('amount') : 0;
14 $creditSum = request()->input('credit_account_id') ? Transaction::where('credit_account_id', request()->input('credit_account_id'))->sum('amount') : 0;
15
16 // Adding current transaction amount to the respective sum based on the attribute being validated
17 if ($attribute === 'debit_account_id') {
18 $debitSum += $value;
19 } else if ($attribute === 'credit_account_id') {
20 $creditSum += $value;
21 }
22
23 return $debitSum == $creditSum;
24 }
25
26 public function message()
27 {
28 return 'The transaction does not adhere to double-entry accounting principles.';
29 }
30}
31
  Run GitHub Actions for
app/Rules/DoubleEntryValidator.phpÂ
  Run GitHub Actions for
app/Filament/Admin/Resources/TransactionResource.phpÂ
  Modify
app/Models/Transaction.phpÂ
  Run GitHub Actions for
app/Models/Transaction.phpÂ
Code Snippets Found
This is based on the results of the Searching step.
app/Filament/Admin/Resources/TransactionResource.php:20-97
 20
21class TransactionResource extends Resource
22{
23 protected static ?string $model = Transaction::class;
24
25 protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
26
27 public static function form(Form $form): Form
28 {
29 return $form
30 ->schema([
31 DatePicker::make('transaction_date')
32 ->label('Date'),
33 Textarea::make('transaction_description')
34 ->label('Description'),
35 TextInput::make('amount')
36 ->numeric()
37 ->label('Amount'),
38 BelongsToSelect::make('debit_account_id')
39 ->relationship('debitAccount', 'name')
40 ->label('Debit Account'),
41 BelongsToSelect::make('credit_account_id')
42 ->relationship('creditAccount', 'name')
43 ->label('Credit Account'),
44 ]);
45 }
46
47 public static function table(Table $table): Table
48 {
49 return $table
50 ->columns([
51 TextColumn::make('transaction_date')
52 ->label('Date')
53 ->searchable()
54 ->sortable(),
55 TextColumn::make('transaction_description')
56 ->label('Description')
57 ->searchable()
58 ->sortable(),
59 TextColumn::make('amount')->label('Amount')
60 ->searchable()
61 ->sortable(),
62 TextColumn::make('debit_account_id')
63 ->label('Debit Account')
64 ->searchable()
65 ->sortable(),
66 TextColumn::make('credit_account_id')
67 ->label('Credit Account')
68 ->searchable()
69 ->sortable(),
70 ])
71 ->filters([
72 //
73 ])
74 ->actions([
75 Tables\Actions\EditAction::make(),
76 ])
77 ->bulkActions([
78 Tables\Actions\BulkActionGroup::make([
79 Tables\Actions\DeleteBulkAction::make(),
80 ]),
81 ]);
82 }
83
84 public static function getRelations(): array
85 {
86 return [
87 //
88 ];
89 }
90
91 public static function getPages(): array
92 {
93 return [
94 'index' => Pages\ListTransactions::route('/'),
95 'create' => Pages\CreateTransaction::route('/create'),
96 'edit' => Pages\EditTransaction::route('/{record}/edit'),
97 ];
app/Models/Transaction.php:0-35
 1<?php
2
3namespace App\Models;
4
5use Illuminate\Database\Eloquent\Factories\HasFactory;
6use Illuminate\Database\Eloquent\Model;
7
8class Transaction extends Model
9{
10 use HasFactory;
11
12 protected $primaryKey = 'transaction_id';
13
14 protected $fillable = [
15 'transaction_date',
16 'transaction_description',
17 'amount',
18 'debit_account_id',
19 'credit_account_id',
20 ];
21
22 public function debitAccount()
23 {
24 return $this->belongsTo(Account::class, 'debit_account_id');
25 }
26
27 public function creditAccount()
28 {
29 return $this->belongsTo(Account::class, 'credit_account_id');
30 }
31
32 public function categories()
33 {
34 return $this->belongsToMany(Category::class);
35 }