Andrew Wallo 10 maanden geleden
bovenliggende
commit
452b0a06b2

+ 9
- 0
app/Collections/Accounting/InvoiceCollection.php Bestand weergeven

@@ -24,4 +24,13 @@ class InvoiceCollection extends Collection
24 24
 
25 25
         return CurrencyConverter::convertCentsToFormatSimple($totalCents, $currency);
26 26
     }
27
+
28
+    public function sumMoneyFormatted(string $column, ?string $currency = null): string
29
+    {
30
+        $currency ??= CurrencyAccessor::getDefaultCurrency();
31
+
32
+        $totalCents = $this->sumMoneyInCents($column);
33
+
34
+        return CurrencyConverter::formatCentsToMoney($totalCents, $currency);
35
+    }
27 36
 }

+ 5
- 0
app/Filament/Company/Pages/Accounting/Transactions.php Bestand weergeven

@@ -88,6 +88,11 @@ class Transactions extends Page implements HasTable
88 88
         return static::getModel()::query();
89 89
     }
90 90
 
91
+    public function getMaxContentWidth(): MaxWidth | string | null
92
+    {
93
+        return 'max-w-8xl';
94
+    }
95
+
91 96
     protected function getHeaderActions(): array
92 97
     {
93 98
         return [

+ 6
- 0
app/Filament/Company/Resources/Banking/AccountResource/Pages/ListAccounts.php Bestand weergeven

@@ -5,6 +5,7 @@ namespace App\Filament\Company\Resources\Banking\AccountResource\Pages;
5 5
 use App\Filament\Company\Resources\Banking\AccountResource;
6 6
 use Filament\Actions;
7 7
 use Filament\Resources\Pages\ListRecords;
8
+use Filament\Support\Enums\MaxWidth;
8 9
 
9 10
 class ListAccounts extends ListRecords
10 11
 {
@@ -16,4 +17,9 @@ class ListAccounts extends ListRecords
16 17
             Actions\CreateAction::make(),
17 18
         ];
18 19
     }
20
+
21
+    public function getMaxContentWidth(): MaxWidth | string | null
22
+    {
23
+        return 'max-w-8xl';
24
+    }
19 25
 }

+ 6
- 0
app/Filament/Company/Resources/Common/OfferingResource/Pages/ListOfferings.php Bestand weergeven

@@ -5,6 +5,7 @@ namespace App\Filament\Company\Resources\Common\OfferingResource\Pages;
5 5
 use App\Filament\Company\Resources\Common\OfferingResource;
6 6
 use Filament\Actions;
7 7
 use Filament\Resources\Pages\ListRecords;
8
+use Filament\Support\Enums\MaxWidth;
8 9
 
9 10
 class ListOfferings extends ListRecords
10 11
 {
@@ -16,4 +17,9 @@ class ListOfferings extends ListRecords
16 17
             Actions\CreateAction::make(),
17 18
         ];
18 19
     }
20
+
21
+    public function getMaxContentWidth(): MaxWidth | string | null
22
+    {
23
+        return 'max-w-8xl';
24
+    }
19 25
 }

+ 6
- 0
app/Filament/Company/Resources/Purchases/BillResource/Pages/ListBills.php Bestand weergeven

@@ -5,6 +5,7 @@ namespace App\Filament\Company\Resources\Purchases\BillResource\Pages;
5 5
 use App\Filament\Company\Resources\Purchases\BillResource;
6 6
 use Filament\Actions;
7 7
 use Filament\Resources\Pages\ListRecords;
8
+use Filament\Support\Enums\MaxWidth;
8 9
 
9 10
 class ListBills extends ListRecords
10 11
 {
@@ -16,4 +17,9 @@ class ListBills extends ListRecords
16 17
             Actions\CreateAction::make(),
17 18
         ];
18 19
     }
20
+
21
+    public function getMaxContentWidth(): MaxWidth | string | null
22
+    {
23
+        return 'max-w-8xl';
24
+    }
19 25
 }

+ 6
- 0
app/Filament/Company/Resources/Purchases/VendorResource/Pages/ListVendors.php Bestand weergeven

@@ -5,6 +5,7 @@ namespace App\Filament\Company\Resources\Purchases\VendorResource\Pages;
5 5
 use App\Filament\Company\Resources\Purchases\VendorResource;
6 6
 use Filament\Actions;
7 7
 use Filament\Resources\Pages\ListRecords;
8
+use Filament\Support\Enums\MaxWidth;
8 9
 
9 10
 class ListVendors extends ListRecords
10 11
 {
@@ -16,4 +17,9 @@ class ListVendors extends ListRecords
16 17
             Actions\CreateAction::make(),
17 18
         ];
18 19
     }
20
+
21
+    public function getMaxContentWidth(): MaxWidth | string | null
22
+    {
23
+        return 'max-w-8xl';
24
+    }
19 25
 }

+ 6
- 0
app/Filament/Company/Resources/Sales/ClientResource/Pages/ListClients.php Bestand weergeven

@@ -5,6 +5,7 @@ namespace App\Filament\Company\Resources\Sales\ClientResource\Pages;
5 5
 use App\Filament\Company\Resources\Sales\ClientResource;
6 6
 use Filament\Actions;
7 7
 use Filament\Resources\Pages\ListRecords;
8
+use Filament\Support\Enums\MaxWidth;
8 9
 
9 10
 class ListClients extends ListRecords
10 11
 {
@@ -16,4 +17,9 @@ class ListClients extends ListRecords
16 17
             Actions\CreateAction::make(),
17 18
         ];
18 19
     }
20
+
21
+    public function getMaxContentWidth(): MaxWidth | string | null
22
+    {
23
+        return 'max-w-8xl';
24
+    }
19 25
 }

+ 18
- 5
app/Filament/Company/Resources/Sales/InvoiceResource.php Bestand weergeven

@@ -7,6 +7,7 @@ use App\Enums\Accounting\InvoiceStatus;
7 7
 use App\Enums\Accounting\PaymentMethod;
8 8
 use App\Filament\Company\Resources\Sales\InvoiceResource\Pages;
9 9
 use App\Filament\Company\Resources\Sales\InvoiceResource\RelationManagers;
10
+use App\Filament\Company\Resources\Sales\InvoiceResource\Widgets;
10 11
 use App\Filament\Tables\Actions\ReplicateBulkAction;
11 12
 use App\Filament\Tables\Filters\DateRangeFilter;
12 13
 use App\Models\Accounting\Adjustment;
@@ -420,6 +421,7 @@ class InvoiceResource extends Resource
420 421
     public static function table(Table $table): Table
421 422
     {
422 423
         return $table
424
+            ->defaultSort('due_date')
423 425
             ->columns([
424 426
                 Tables\Columns\TextColumn::make('status')
425 427
                     ->badge()
@@ -451,15 +453,19 @@ class InvoiceResource extends Resource
451 453
                     ->searchable()
452 454
                     ->sortable(),
453 455
                 Tables\Columns\TextColumn::make('client.name')
454
-                    ->sortable(),
456
+                    ->sortable()
457
+                    ->searchable(),
455 458
                 Tables\Columns\TextColumn::make('total')
456
-                    ->currency(),
459
+                    ->currency()
460
+                    ->sortable(),
457 461
                 Tables\Columns\TextColumn::make('amount_paid')
458 462
                     ->label('Amount Paid')
459
-                    ->currency(),
463
+                    ->currency()
464
+                    ->sortable(),
460 465
                 Tables\Columns\TextColumn::make('amount_due')
461 466
                     ->label('Amount Due')
462
-                    ->currency(),
467
+                    ->currency()
468
+                    ->sortable(),
463 469
             ])
464 470
             ->filters([
465 471
                 Tables\Filters\SelectFilter::make('client')
@@ -545,7 +551,7 @@ class InvoiceResource extends Resource
545 551
                         })
546 552
                         ->successNotificationTitle('Invoice Sent')
547 553
                         ->action(function (Invoice $record, Tables\Actions\Action $action) {
548
-                            $record->updateQuietly([
554
+                            $record->update([
549 555
                                 'status' => InvoiceStatus::Sent,
550 556
                             ]);
551 557
 
@@ -845,4 +851,11 @@ class InvoiceResource extends Resource
845 851
             'edit' => Pages\EditInvoice::route('/{record}/edit'),
846 852
         ];
847 853
     }
854
+
855
+    public static function getWidgets(): array
856
+    {
857
+        return [
858
+            Widgets\InvoiceOverview::class,
859
+        ];
860
+    }
848 861
 }

+ 17
- 0
app/Filament/Company/Resources/Sales/InvoiceResource/Pages/ListInvoices.php Bestand weergeven

@@ -4,14 +4,19 @@ namespace App\Filament\Company\Resources\Sales\InvoiceResource\Pages;
4 4
 
5 5
 use App\Enums\Accounting\InvoiceStatus;
6 6
 use App\Filament\Company\Resources\Sales\InvoiceResource;
7
+use App\Filament\Company\Resources\Sales\InvoiceResource\Widgets;
7 8
 use App\Models\Accounting\Invoice;
8 9
 use Filament\Actions;
10
+use Filament\Pages\Concerns\ExposesTableToWidgets;
9 11
 use Filament\Resources\Components\Tab;
10 12
 use Filament\Resources\Pages\ListRecords;
13
+use Filament\Support\Enums\MaxWidth;
11 14
 use Illuminate\Database\Eloquent\Builder;
12 15
 
13 16
 class ListInvoices extends ListRecords
14 17
 {
18
+    use ExposesTableToWidgets;
19
+
15 20
     protected static string $resource = InvoiceResource::class;
16 21
 
17 22
     protected function getHeaderActions(): array
@@ -21,6 +26,18 @@ class ListInvoices extends ListRecords
21 26
         ];
22 27
     }
23 28
 
29
+    protected function getHeaderWidgets(): array
30
+    {
31
+        return [
32
+            Widgets\InvoiceOverview::make(),
33
+        ];
34
+    }
35
+
36
+    public function getMaxContentWidth(): MaxWidth | string | null
37
+    {
38
+        return 'max-w-8xl';
39
+    }
40
+
24 41
     public function getTabs(): array
25 42
     {
26 43
         return [

+ 17
- 17
app/Filament/Company/Resources/Sales/InvoiceResource/Pages/ViewInvoice.php Bestand weergeven

@@ -2,7 +2,6 @@
2 2
 
3 3
 namespace App\Filament\Company\Resources\Sales\InvoiceResource\Pages;
4 4
 
5
-use App\Enums\Accounting\InvoiceStatus;
6 5
 use App\Filament\Company\Resources\Sales\ClientResource;
7 6
 use App\Filament\Company\Resources\Sales\InvoiceResource;
8 7
 use App\Models\Accounting\Invoice;
@@ -27,7 +26,7 @@ class ViewInvoice extends ViewRecord
27 26
         return $infolist
28 27
             ->schema([
29 28
                 Section::make('Invoice Details')
30
-                    ->columns(3)
29
+                    ->columns(4)
31 30
                     ->schema([
32 31
                         TextEntry::make('invoice_number')
33 32
                             ->label('Invoice #'),
@@ -44,8 +43,11 @@ class ViewInvoice extends ViewRecord
44 43
                         TextEntry::make('amount_due')
45 44
                             ->label('Amount Due')
46 45
                             ->money(),
46
+                        TextEntry::make('date')
47
+                            ->label('Date')
48
+                            ->date(),
47 49
                         TextEntry::make('due_date')
48
-                            ->label('Due Date')
50
+                            ->label('Due')
49 51
                             ->formatStateUsing(function (TextEntry $entry, mixed $state) {
50 52
                                 if (blank($state)) {
51 53
                                     return null;
@@ -62,21 +64,19 @@ class ViewInvoice extends ViewRecord
62 64
                                     'options' => CarbonInterface::ONE_DAY_WORDS,
63 65
                                 ]);
64 66
                             }),
67
+                        TextEntry::make('approved_at')
68
+                            ->label('Approved At')
69
+                            ->placeholder('Not Approved')
70
+                            ->date(),
71
+                        TextEntry::make('last_sent')
72
+                            ->label('Last Sent')
73
+                            ->placeholder('Never')
74
+                            ->date(),
75
+                        TextEntry::make('paid_at')
76
+                            ->label('Paid At')
77
+                            ->placeholder('Not Paid')
78
+                            ->date(),
65 79
                     ]),
66 80
             ]);
67 81
     }
68
-
69
-    public function approveDraft(): void
70
-    {
71
-        $this->record->update([
72
-            'status' => InvoiceStatus::Unsent,
73
-        ]);
74
-    }
75
-
76
-    public function markAsSent(): void
77
-    {
78
-        $this->record->update([
79
-            'status' => InvoiceStatus::Sent,
80
-        ]);
81
-    }
82 82
 }

+ 84
- 0
app/Filament/Company/Resources/Sales/InvoiceResource/Widgets/InvoiceOverview.php Bestand weergeven

@@ -0,0 +1,84 @@
1
+<?php
2
+
3
+namespace App\Filament\Company\Resources\Sales\InvoiceResource\Widgets;
4
+
5
+use App\Enums\Accounting\InvoiceStatus;
6
+use App\Filament\Company\Resources\Sales\InvoiceResource\Pages\ListInvoices;
7
+use App\Utilities\Currency\CurrencyConverter;
8
+use Filament\Widgets\Concerns\InteractsWithPageTable;
9
+use Filament\Widgets\StatsOverviewWidget as BaseWidget;
10
+use Filament\Widgets\StatsOverviewWidget\Stat;
11
+use Illuminate\Support\Number;
12
+
13
+class InvoiceOverview extends BaseWidget
14
+{
15
+    use InteractsWithPageTable;
16
+
17
+    protected static ?string $pollingInterval = null;
18
+
19
+    protected function getTablePage(): string
20
+    {
21
+        return ListInvoices::class;
22
+    }
23
+
24
+    protected function getStats(): array
25
+    {
26
+        $outstandingInvoices = $this->getPageTableQuery()
27
+            ->whereNotIn('status', [
28
+                InvoiceStatus::Paid,
29
+                InvoiceStatus::Void,
30
+                InvoiceStatus::Draft,
31
+                InvoiceStatus::Overpaid,
32
+            ]);
33
+
34
+        $amountOutstanding = $outstandingInvoices
35
+            ->clone()
36
+            ->sum('amount_due');
37
+
38
+        $amountOverdue = $outstandingInvoices
39
+            ->clone()
40
+            ->where('status', InvoiceStatus::Overdue)
41
+            ->sum('amount_due');
42
+
43
+        $amountDueWithin30Days = $outstandingInvoices
44
+            ->clone()
45
+            ->where('due_date', '>=', today())
46
+            ->where('due_date', '<=', today()->addDays(30))
47
+            ->sum('amount_due');
48
+
49
+        $validInvoices = $this->getPageTableQuery()
50
+            ->whereNotIn('status', [
51
+                InvoiceStatus::Void,
52
+                InvoiceStatus::Draft,
53
+            ]);
54
+
55
+        $totalValidInvoiceAmount = $validInvoices->clone()->sum('amount_due');
56
+
57
+        $totalValidInvoiceCount = $validInvoices->clone()->count();
58
+
59
+        $averageInvoiceTotal = $totalValidInvoiceCount > 0 ? $totalValidInvoiceAmount / $totalValidInvoiceCount : 0;
60
+
61
+        $averagePaymentTime = $this->getPageTableQuery()
62
+            ->withWhereHas('statusHistories', function ($query) {
63
+                $query->where('new_status', InvoiceStatus::Paid);
64
+            })
65
+            ->selectRaw('AVG(TIMESTAMPDIFF(DAY, date, (
66
+                SELECT changed_at
67
+                FROM invoice_status_histories
68
+                WHERE invoice_status_histories.invoice_id = invoices.id
69
+                AND status = ?
70
+                LIMIT 1
71
+            ))) as avg_days', [InvoiceStatus::Paid])
72
+            ->value('avg_days');
73
+
74
+        return [
75
+            Stat::make('Total Outstanding', CurrencyConverter::formatCentsToMoney($amountOutstanding))
76
+                ->description('Includes ' . CurrencyConverter::formatCentsToMoney($amountOverdue) . ' overdue'),
77
+            Stat::make('Due Within 30 Days', CurrencyConverter::formatCentsToMoney($amountDueWithin30Days)),
78
+            Stat::make('Average Payment Time', Number::format($averagePaymentTime ?? 0, maxPrecision: 1) . ' days')
79
+                ->description('From invoice date to payment received'),
80
+            Stat::make('Average Invoice Total', CurrencyConverter::formatCentsToMoney($averageInvoiceTotal))
81
+                ->description('Excludes void and draft invoices'),
82
+        ];
83
+    }
84
+}

+ 36
- 0
app/Models/Accounting/Invoice.php Bestand weergeven

@@ -17,8 +17,10 @@ use Illuminate\Database\Eloquent\Casts\Attribute;
17 17
 use Illuminate\Database\Eloquent\Factories\HasFactory;
18 18
 use Illuminate\Database\Eloquent\Model;
19 19
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
20
+use Illuminate\Database\Eloquent\Relations\HasMany;
20 21
 use Illuminate\Database\Eloquent\Relations\MorphMany;
21 22
 use Illuminate\Database\Eloquent\Relations\MorphOne;
23
+use Illuminate\Support\Carbon;
22 24
 
23 25
 #[ObservedBy(InvoiceObserver::class)]
24 26
 #[CollectedBy(InvoiceCollection::class)]
@@ -95,12 +97,46 @@ class Invoice extends Model
95 97
         return $this->transactions()->where('type', TransactionType::Withdrawal)->where('is_payment', true);
96 98
     }
97 99
 
100
+    protected function lastSent(): Attribute
101
+    {
102
+        return Attribute::get(function () {
103
+            return $this->getStatusChangedAt(InvoiceStatus::Sent);
104
+        });
105
+    }
106
+
107
+    protected function approvedAt(): Attribute
108
+    {
109
+        return Attribute::get(function () {
110
+            return $this->getStatusChangedAt(InvoiceStatus::Unsent);
111
+        });
112
+    }
113
+
114
+    protected function paidAt(): Attribute
115
+    {
116
+        return Attribute::get(function () {
117
+            return $this->getStatusChangedAt(InvoiceStatus::Paid);
118
+        });
119
+    }
120
+
121
+    protected function getStatusChangedAt(InvoiceStatus $status): ?Carbon
122
+    {
123
+        return $this->statusHistories
124
+            ->where('new_status', $status)
125
+            ->sortByDesc('changed_at')
126
+            ->first()?->changed_at;
127
+    }
128
+
98 129
     public function approvalTransaction(): MorphOne
99 130
     {
100 131
         return $this->morphOne(Transaction::class, 'transactionable')
101 132
             ->where('type', TransactionType::Journal);
102 133
     }
103 134
 
135
+    public function statusHistories(): HasMany
136
+    {
137
+        return $this->hasMany(InvoiceStatusHistory::class);
138
+    }
139
+
104 140
     protected function isCurrentlyOverdue(): Attribute
105 141
     {
106 142
         return Attribute::get(function () {

+ 41
- 0
app/Models/Accounting/InvoiceStatusHistory.php Bestand weergeven

@@ -0,0 +1,41 @@
1
+<?php
2
+
3
+namespace App\Models\Accounting;
4
+
5
+use App\Concerns\CompanyOwned;
6
+use App\Enums\Accounting\InvoiceStatus;
7
+use App\Models\User;
8
+use Illuminate\Database\Eloquent\Factories\HasFactory;
9
+use Illuminate\Database\Eloquent\Model;
10
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
11
+
12
+class InvoiceStatusHistory extends Model
13
+{
14
+    use CompanyOwned;
15
+    use HasFactory;
16
+
17
+    protected $fillable = [
18
+        'company_id',
19
+        'invoice_id',
20
+        'old_status',
21
+        'new_status',
22
+        'changed_by',
23
+        'changed_at',
24
+    ];
25
+
26
+    protected $casts = [
27
+        'changed_at' => 'datetime',
28
+        'old_status' => InvoiceStatus::class,
29
+        'new_status' => InvoiceStatus::class,
30
+    ];
31
+
32
+    public function invoice(): BelongsTo
33
+    {
34
+        return $this->belongsTo(Invoice::class);
35
+    }
36
+
37
+    public function changedBy(): BelongsTo
38
+    {
39
+        return $this->belongsTo(User::class, 'changed_by');
40
+    }
41
+}

+ 5
- 0
app/Models/Company.php Bestand weergeven

@@ -171,4 +171,9 @@ class Company extends FilamentCompaniesCompany implements HasAvatar
171 171
     {
172 172
         return $this->hasMany(Common\Vendor::class, 'company_id');
173 173
     }
174
+
175
+    public function invoiceStatusHistories(): HasMany
176
+    {
177
+        return $this->hasMany(Accounting\InvoiceStatusHistory::class, 'company_id');
178
+    }
174 179
 }

+ 8
- 1
app/Observers/InvoiceObserver.php Bestand weergeven

@@ -23,7 +23,14 @@ class InvoiceObserver
23 23
      */
24 24
     public function updated(Invoice $invoice): void
25 25
     {
26
-        //
26
+        if ($invoice->wasChanged('status')) {
27
+            $invoice->statusHistories()->create([
28
+                'company_id' => $invoice->company_id,
29
+                'old_status' => $invoice->getOriginal('status'),
30
+                'new_status' => $invoice->status,
31
+                'changed_by' => $invoice->updated_by,
32
+            ]);
33
+        }
27 34
     }
28 35
 
29 36
     public function deleting(Invoice $invoice): void

+ 6
- 6
composer.lock Bestand weergeven

@@ -497,16 +497,16 @@
497 497
         },
498 498
         {
499 499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.333.0",
500
+            "version": "3.334.0",
501 501
             "source": {
502 502
                 "type": "git",
503 503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "11bb2709885c9954004620d3648e9355feb92a41"
504
+                "reference": "8afe50cb2a93051dafef21eb616e297a449764aa"
505 505
             },
506 506
             "dist": {
507 507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/11bb2709885c9954004620d3648e9355feb92a41",
509
-                "reference": "11bb2709885c9954004620d3648e9355feb92a41",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8afe50cb2a93051dafef21eb616e297a449764aa",
509
+                "reference": "8afe50cb2a93051dafef21eb616e297a449764aa",
510 510
                 "shasum": ""
511 511
             },
512 512
             "require": {
@@ -589,9 +589,9 @@
589 589
             "support": {
590 590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
591 591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
592
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.333.0"
592
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.334.0"
593 593
             },
594
-            "time": "2024-12-03T19:06:47+00:00"
594
+            "time": "2024-12-04T19:09:04+00:00"
595 595
         },
596 596
         {
597 597
             "name": "aws/aws-sdk-php-laravel",

+ 23
- 0
database/factories/Accounting/InvoiceStatusHistoryFactory.php Bestand weergeven

@@ -0,0 +1,23 @@
1
+<?php
2
+
3
+namespace Database\Factories\Accounting;
4
+
5
+use Illuminate\Database\Eloquent\Factories\Factory;
6
+
7
+/**
8
+ * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Accounting\InvoiceStatusHistory>
9
+ */
10
+class InvoiceStatusHistoryFactory extends Factory
11
+{
12
+    /**
13
+     * Define the model's default state.
14
+     *
15
+     * @return array<string, mixed>
16
+     */
17
+    public function definition(): array
18
+    {
19
+        return [
20
+            //
21
+        ];
22
+    }
23
+}

+ 3
- 0
database/factories/CompanyFactory.php Bestand weergeven

@@ -129,6 +129,7 @@ class CompanyFactory extends Factory
129 129
             Invoice::factory()
130 130
                 ->count($paidCount)
131 131
                 ->withLineItems()
132
+                ->approved()
132 133
                 ->withPayments(max: 4)
133 134
                 ->create([
134 135
                     'company_id' => $company->id,
@@ -139,6 +140,7 @@ class CompanyFactory extends Factory
139 140
             Invoice::factory()
140 141
                 ->count($partialCount)
141 142
                 ->withLineItems()
143
+                ->approved()
142 144
                 ->withPayments(max: 4, invoiceStatus: InvoiceStatus::Partial)
143 145
                 ->create([
144 146
                     'company_id' => $company->id,
@@ -149,6 +151,7 @@ class CompanyFactory extends Factory
149 151
             Invoice::factory()
150 152
                 ->count($overpaidCount)
151 153
                 ->withLineItems()
154
+                ->approved()
152 155
                 ->withPayments(max: 4, invoiceStatus: InvoiceStatus::Overpaid)
153 156
                 ->create([
154 157
                     'company_id' => $company->id,

+ 33
- 0
database/migrations/2024_12_05_003805_create_invoice_status_histories_table.php Bestand weergeven

@@ -0,0 +1,33 @@
1
+<?php
2
+
3
+use Illuminate\Database\Migrations\Migration;
4
+use Illuminate\Database\Schema\Blueprint;
5
+use Illuminate\Support\Facades\Schema;
6
+
7
+return new class extends Migration
8
+{
9
+    /**
10
+     * Run the migrations.
11
+     */
12
+    public function up(): void
13
+    {
14
+        Schema::create('invoice_status_histories', function (Blueprint $table) {
15
+            $table->id();
16
+            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17
+            $table->foreignId('invoice_id')->constrained()->cascadeOnDelete();
18
+            $table->string('old_status');
19
+            $table->string('new_status');
20
+            $table->foreignId('changed_by')->nullable()->constrained('users')->nullOnDelete();
21
+            $table->timestamp('changed_at')->useCurrent();
22
+            $table->timestamps();
23
+        });
24
+    }
25
+
26
+    /**
27
+     * Reverse the migrations.
28
+     */
29
+    public function down(): void
30
+    {
31
+        Schema::dropIfExists('invoice_status_histories');
32
+    }
33
+};

+ 3
- 3
package-lock.json Bestand weergeven

@@ -945,9 +945,9 @@
945 945
             }
946 946
         },
947 947
         "node_modules/axios": {
948
-            "version": "1.7.8",
949
-            "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
950
-            "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
948
+            "version": "1.7.9",
949
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
950
+            "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
951 951
             "dev": true,
952 952
             "license": "MIT",
953 953
             "dependencies": {

+ 3
- 0
resources/css/filament/company/tailwind.config.js Bestand weergeven

@@ -20,6 +20,9 @@ export default {
20 20
                 white: '#F3F4F6',
21 21
                 platinum: '#E8E9EB',
22 22
             },
23
+            maxWidth: {
24
+                '8xl': '88rem',
25
+            },
23 26
             transitionTimingFunction: {
24 27
                 'ease-smooth': 'cubic-bezier(0.08, 0.52, 0.52, 1)',
25 28
             }

Laden…
Annuleren
Opslaan