Andrew Wallo 10 个月前
父节点
当前提交
dd1b5ccc59

+ 2
- 7
app/Filament/Company/Resources/Sales/InvoiceResource/Pages/ListInvoices.php 查看文件

44
             'all' => Tab::make()
44
             'all' => Tab::make()
45
                 ->label('All'),
45
                 ->label('All'),
46
 
46
 
47
-            'overdue' => Tab::make()
48
-                ->label('Overdue')
49
-                ->modifyQueryUsing(function (Builder $query) {
50
-                    $query->where('status', InvoiceStatus::Overdue);
51
-                })
52
-                ->badge(Invoice::where('status', InvoiceStatus::Overdue)->count()),
53
-
54
             'unpaid' => Tab::make()
47
             'unpaid' => Tab::make()
55
                 ->label('Unpaid')
48
                 ->label('Unpaid')
56
                 ->modifyQueryUsing(function (Builder $query) {
49
                 ->modifyQueryUsing(function (Builder $query) {
58
                         InvoiceStatus::Unsent,
51
                         InvoiceStatus::Unsent,
59
                         InvoiceStatus::Sent,
52
                         InvoiceStatus::Sent,
60
                         InvoiceStatus::Partial,
53
                         InvoiceStatus::Partial,
54
+                        InvoiceStatus::Overdue,
61
                     ]);
55
                     ]);
62
                 })
56
                 })
63
                 ->badge(Invoice::whereIn('status', [
57
                 ->badge(Invoice::whereIn('status', [
64
                     InvoiceStatus::Unsent,
58
                     InvoiceStatus::Unsent,
65
                     InvoiceStatus::Sent,
59
                     InvoiceStatus::Sent,
66
                     InvoiceStatus::Partial,
60
                     InvoiceStatus::Partial,
61
+                    InvoiceStatus::Overdue,
67
                 ])->count()),
62
                 ])->count()),
68
 
63
 
69
             'draft' => Tab::make()
64
             'draft' => Tab::make()

+ 2
- 10
app/Filament/Company/Resources/Sales/InvoiceResource/Widgets/InvoiceOverview.php 查看文件

59
         $averageInvoiceTotal = $totalValidInvoiceCount > 0 ? $totalValidInvoiceAmount / $totalValidInvoiceCount : 0;
59
         $averageInvoiceTotal = $totalValidInvoiceCount > 0 ? $totalValidInvoiceAmount / $totalValidInvoiceCount : 0;
60
 
60
 
61
         $averagePaymentTime = $this->getPageTableQuery()
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])
62
+            ->whereNotNull('paid_at')
63
+            ->selectRaw('AVG(TIMESTAMPDIFF(DAY, date, paid_at)) as avg_days')
72
             ->value('avg_days');
64
             ->value('avg_days');
73
 
65
 
74
         return [
66
         return [

+ 11
- 37
app/Models/Accounting/Invoice.php 查看文件

17
 use Illuminate\Database\Eloquent\Factories\HasFactory;
17
 use Illuminate\Database\Eloquent\Factories\HasFactory;
18
 use Illuminate\Database\Eloquent\Model;
18
 use Illuminate\Database\Eloquent\Model;
19
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
19
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
20
-use Illuminate\Database\Eloquent\Relations\HasMany;
21
 use Illuminate\Database\Eloquent\Relations\MorphMany;
20
 use Illuminate\Database\Eloquent\Relations\MorphMany;
22
 use Illuminate\Database\Eloquent\Relations\MorphOne;
21
 use Illuminate\Database\Eloquent\Relations\MorphOne;
23
 use Illuminate\Support\Carbon;
22
 use Illuminate\Support\Carbon;
42
         'order_number',
41
         'order_number',
43
         'date',
42
         'date',
44
         'due_date',
43
         'due_date',
44
+        'approved_at',
45
+        'paid_at',
46
+        'last_sent',
45
         'status',
47
         'status',
46
         'currency_code',
48
         'currency_code',
47
         'subtotal',
49
         'subtotal',
58
     protected $casts = [
60
     protected $casts = [
59
         'date' => 'date',
61
         'date' => 'date',
60
         'due_date' => 'date',
62
         'due_date' => 'date',
63
+        'approved_at' => 'datetime',
64
+        'paid_at' => 'datetime',
65
+        'last_sent' => 'datetime',
61
         'status' => InvoiceStatus::class,
66
         'status' => InvoiceStatus::class,
62
         'subtotal' => MoneyCast::class,
67
         'subtotal' => MoneyCast::class,
63
         'tax_total' => MoneyCast::class,
68
         'tax_total' => MoneyCast::class,
97
         return $this->transactions()->where('type', TransactionType::Withdrawal)->where('is_payment', true);
102
         return $this->transactions()->where('type', TransactionType::Withdrawal)->where('is_payment', true);
98
     }
103
     }
99
 
104
 
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
-
129
     public function approvalTransaction(): MorphOne
105
     public function approvalTransaction(): MorphOne
130
     {
106
     {
131
         return $this->morphOne(Transaction::class, 'transactionable')
107
         return $this->morphOne(Transaction::class, 'transactionable')
132
             ->where('type', TransactionType::Journal);
108
             ->where('type', TransactionType::Journal);
133
     }
109
     }
134
 
110
 
135
-    public function statusHistories(): HasMany
136
-    {
137
-        return $this->hasMany(InvoiceStatusHistory::class);
138
-    }
139
-
140
     protected function isCurrentlyOverdue(): Attribute
111
     protected function isCurrentlyOverdue(): Attribute
141
     {
112
     {
142
         return Attribute::get(function () {
113
         return Attribute::get(function () {
233
         ]);
204
         ]);
234
     }
205
     }
235
 
206
 
236
-    public function approveDraft(): void
207
+    public function approveDraft(?Carbon $approvedAt = null): void
237
     {
208
     {
238
         if (! $this->isDraft()) {
209
         if (! $this->isDraft()) {
239
             throw new \RuntimeException('Invoice is not in draft status.');
210
             throw new \RuntimeException('Invoice is not in draft status.');
240
         }
211
         }
241
 
212
 
213
+        $approvedAt ??= now();
214
+
242
         $transaction = $this->transactions()->create([
215
         $transaction = $this->transactions()->create([
243
             'company_id' => $this->company_id,
216
             'company_id' => $this->company_id,
244
             'type' => TransactionType::Journal,
217
             'type' => TransactionType::Journal,
245
-            'posted_at' => now(),
218
+            'posted_at' => $approvedAt,
246
             'amount' => $this->total,
219
             'amount' => $this->total,
247
             'description' => 'Invoice Approval for Invoice #' . $this->invoice_number,
220
             'description' => 'Invoice Approval for Invoice #' . $this->invoice_number,
248
         ]);
221
         ]);
276
         }
249
         }
277
 
250
 
278
         $this->update([
251
         $this->update([
252
+            'approved_at' => $approvedAt,
279
             'status' => InvoiceStatus::Unsent,
253
             'status' => InvoiceStatus::Unsent,
280
         ]);
254
         ]);
281
     }
255
     }

+ 0
- 41
app/Models/Accounting/InvoiceStatusHistory.php 查看文件

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
-}

+ 0
- 5
app/Models/Company.php 查看文件

171
     {
171
     {
172
         return $this->hasMany(Common\Vendor::class, 'company_id');
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
-    }
179
 }
174
 }

+ 5
- 7
app/Observers/InvoiceObserver.php 查看文件

24
     public function updated(Invoice $invoice): void
24
     public function updated(Invoice $invoice): void
25
     {
25
     {
26
         if ($invoice->wasChanged('status')) {
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
-            ]);
27
+            match ($invoice->status) {
28
+                InvoiceStatus::Sent => $invoice->updateQuietly(['last_sent' => now()]),
29
+                default => null,
30
+            };
33
         }
31
         }
34
     }
32
     }
35
 
33
 
40
 
38
 
41
     public function saving(Invoice $invoice): void
39
     public function saving(Invoice $invoice): void
42
     {
40
     {
43
-        if ($invoice->is_currently_overdue) {
41
+        if ($invoice->approved_at && $invoice->is_currently_overdue) {
44
             $invoice->status = InvoiceStatus::Overdue;
42
             $invoice->status = InvoiceStatus::Overdue;
45
         }
43
         }
46
     }
44
     }

+ 16
- 6
app/Observers/TransactionObserver.php 查看文件

107
 
107
 
108
         $invoiceTotal = (int) $invoice->getRawOriginal('total');
108
         $invoiceTotal = (int) $invoice->getRawOriginal('total');
109
 
109
 
110
+        $newStatus = match (true) {
111
+            $totalPaid > $invoiceTotal => InvoiceStatus::Overpaid,
112
+            $totalPaid === $invoiceTotal => InvoiceStatus::Paid,
113
+            default => InvoiceStatus::Partial,
114
+        };
115
+
116
+        $paidAt = $invoice->paid_at;
117
+
118
+        if (in_array($newStatus, [InvoiceStatus::Paid, InvoiceStatus::Overpaid]) && ! $paidAt) {
119
+            $paidAt = $invoice->deposits()
120
+                ->latest('posted_at')
121
+                ->value('posted_at');
122
+        }
123
+
110
         $invoice->update([
124
         $invoice->update([
111
             'amount_paid' => CurrencyConverter::convertCentsToFloat($totalPaid),
125
             'amount_paid' => CurrencyConverter::convertCentsToFloat($totalPaid),
112
-            'status' => match (true) {
113
-                $totalPaid > $invoiceTotal => InvoiceStatus::Overpaid,
114
-                $totalPaid === $invoiceTotal => InvoiceStatus::Paid,
115
-                $totalPaid === 0 => InvoiceStatus::Sent,
116
-                default => InvoiceStatus::Partial,
117
-            },
126
+            'status' => $newStatus,
127
+            'paid_at' => $paidAt,
118
         ]);
128
         ]);
119
     }
129
     }
120
 }
130
 }

+ 69
- 69
composer.lock 查看文件

497
         },
497
         },
498
         {
498
         {
499
             "name": "aws/aws-sdk-php",
499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.334.0",
500
+            "version": "3.334.1",
501
             "source": {
501
             "source": {
502
                 "type": "git",
502
                 "type": "git",
503
                 "url": "https://github.com/aws/aws-sdk-php.git",
503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "8afe50cb2a93051dafef21eb616e297a449764aa"
504
+                "reference": "3938b3467f64a30fed7ee1762a6785f808a5ae4d"
505
             },
505
             },
506
             "dist": {
506
             "dist": {
507
                 "type": "zip",
507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8afe50cb2a93051dafef21eb616e297a449764aa",
509
-                "reference": "8afe50cb2a93051dafef21eb616e297a449764aa",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3938b3467f64a30fed7ee1762a6785f808a5ae4d",
509
+                "reference": "3938b3467f64a30fed7ee1762a6785f808a5ae4d",
510
                 "shasum": ""
510
                 "shasum": ""
511
             },
511
             },
512
             "require": {
512
             "require": {
589
             "support": {
589
             "support": {
590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
592
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.334.0"
592
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.334.1"
593
             },
593
             },
594
-            "time": "2024-12-04T19:09:04+00:00"
594
+            "time": "2024-12-05T01:17:41+00:00"
595
         },
595
         },
596
         {
596
         {
597
             "name": "aws/aws-sdk-php-laravel",
597
             "name": "aws/aws-sdk-php-laravel",
1664
         },
1664
         },
1665
         {
1665
         {
1666
             "name": "filament/actions",
1666
             "name": "filament/actions",
1667
-            "version": "v3.2.127",
1667
+            "version": "v3.2.128",
1668
             "source": {
1668
             "source": {
1669
                 "type": "git",
1669
                 "type": "git",
1670
                 "url": "https://github.com/filamentphp/actions.git",
1670
                 "url": "https://github.com/filamentphp/actions.git",
1671
-                "reference": "f325e315c365cfcea5c9da96662ddea37e3663fc"
1671
+                "reference": "1ee8b0a890b53e8b0b341134d3ba9bdaeee294d3"
1672
             },
1672
             },
1673
             "dist": {
1673
             "dist": {
1674
                 "type": "zip",
1674
                 "type": "zip",
1675
-                "url": "https://api.github.com/repos/filamentphp/actions/zipball/f325e315c365cfcea5c9da96662ddea37e3663fc",
1676
-                "reference": "f325e315c365cfcea5c9da96662ddea37e3663fc",
1675
+                "url": "https://api.github.com/repos/filamentphp/actions/zipball/1ee8b0a890b53e8b0b341134d3ba9bdaeee294d3",
1676
+                "reference": "1ee8b0a890b53e8b0b341134d3ba9bdaeee294d3",
1677
                 "shasum": ""
1677
                 "shasum": ""
1678
             },
1678
             },
1679
             "require": {
1679
             "require": {
1713
                 "issues": "https://github.com/filamentphp/filament/issues",
1713
                 "issues": "https://github.com/filamentphp/filament/issues",
1714
                 "source": "https://github.com/filamentphp/filament"
1714
                 "source": "https://github.com/filamentphp/filament"
1715
             },
1715
             },
1716
-            "time": "2024-11-29T09:30:57+00:00"
1716
+            "time": "2024-12-05T08:56:37+00:00"
1717
         },
1717
         },
1718
         {
1718
         {
1719
             "name": "filament/filament",
1719
             "name": "filament/filament",
1720
-            "version": "v3.2.127",
1720
+            "version": "v3.2.128",
1721
             "source": {
1721
             "source": {
1722
                 "type": "git",
1722
                 "type": "git",
1723
                 "url": "https://github.com/filamentphp/panels.git",
1723
                 "url": "https://github.com/filamentphp/panels.git",
1724
-                "reference": "4aea767e8c872842b624fe47affe078433111259"
1724
+                "reference": "27b834f6f1213c547580443e28e5028dfe125bdd"
1725
             },
1725
             },
1726
             "dist": {
1726
             "dist": {
1727
                 "type": "zip",
1727
                 "type": "zip",
1728
-                "url": "https://api.github.com/repos/filamentphp/panels/zipball/4aea767e8c872842b624fe47affe078433111259",
1729
-                "reference": "4aea767e8c872842b624fe47affe078433111259",
1728
+                "url": "https://api.github.com/repos/filamentphp/panels/zipball/27b834f6f1213c547580443e28e5028dfe125bdd",
1729
+                "reference": "27b834f6f1213c547580443e28e5028dfe125bdd",
1730
                 "shasum": ""
1730
                 "shasum": ""
1731
             },
1731
             },
1732
             "require": {
1732
             "require": {
1778
                 "issues": "https://github.com/filamentphp/filament/issues",
1778
                 "issues": "https://github.com/filamentphp/filament/issues",
1779
                 "source": "https://github.com/filamentphp/filament"
1779
                 "source": "https://github.com/filamentphp/filament"
1780
             },
1780
             },
1781
-            "time": "2024-11-29T09:30:58+00:00"
1781
+            "time": "2024-12-05T08:56:42+00:00"
1782
         },
1782
         },
1783
         {
1783
         {
1784
             "name": "filament/forms",
1784
             "name": "filament/forms",
1785
-            "version": "v3.2.127",
1785
+            "version": "v3.2.128",
1786
             "source": {
1786
             "source": {
1787
                 "type": "git",
1787
                 "type": "git",
1788
                 "url": "https://github.com/filamentphp/forms.git",
1788
                 "url": "https://github.com/filamentphp/forms.git",
1789
-                "reference": "c78071f1aabb63a0d9bf74268005d3294b61dc2a"
1789
+                "reference": "c86af3606b8fd3f908b29a03e3056628e4cea57e"
1790
             },
1790
             },
1791
             "dist": {
1791
             "dist": {
1792
                 "type": "zip",
1792
                 "type": "zip",
1793
-                "url": "https://api.github.com/repos/filamentphp/forms/zipball/c78071f1aabb63a0d9bf74268005d3294b61dc2a",
1794
-                "reference": "c78071f1aabb63a0d9bf74268005d3294b61dc2a",
1793
+                "url": "https://api.github.com/repos/filamentphp/forms/zipball/c86af3606b8fd3f908b29a03e3056628e4cea57e",
1794
+                "reference": "c86af3606b8fd3f908b29a03e3056628e4cea57e",
1795
                 "shasum": ""
1795
                 "shasum": ""
1796
             },
1796
             },
1797
             "require": {
1797
             "require": {
1834
                 "issues": "https://github.com/filamentphp/filament/issues",
1834
                 "issues": "https://github.com/filamentphp/filament/issues",
1835
                 "source": "https://github.com/filamentphp/filament"
1835
                 "source": "https://github.com/filamentphp/filament"
1836
             },
1836
             },
1837
-            "time": "2024-11-29T09:30:53+00:00"
1837
+            "time": "2024-12-05T08:56:35+00:00"
1838
         },
1838
         },
1839
         {
1839
         {
1840
             "name": "filament/infolists",
1840
             "name": "filament/infolists",
1841
-            "version": "v3.2.127",
1841
+            "version": "v3.2.128",
1842
             "source": {
1842
             "source": {
1843
                 "type": "git",
1843
                 "type": "git",
1844
                 "url": "https://github.com/filamentphp/infolists.git",
1844
                 "url": "https://github.com/filamentphp/infolists.git",
1889
         },
1889
         },
1890
         {
1890
         {
1891
             "name": "filament/notifications",
1891
             "name": "filament/notifications",
1892
-            "version": "v3.2.127",
1892
+            "version": "v3.2.128",
1893
             "source": {
1893
             "source": {
1894
                 "type": "git",
1894
                 "type": "git",
1895
                 "url": "https://github.com/filamentphp/notifications.git",
1895
                 "url": "https://github.com/filamentphp/notifications.git",
1941
         },
1941
         },
1942
         {
1942
         {
1943
             "name": "filament/support",
1943
             "name": "filament/support",
1944
-            "version": "v3.2.127",
1944
+            "version": "v3.2.128",
1945
             "source": {
1945
             "source": {
1946
                 "type": "git",
1946
                 "type": "git",
1947
                 "url": "https://github.com/filamentphp/support.git",
1947
                 "url": "https://github.com/filamentphp/support.git",
1948
-                "reference": "a720fb2508a1d84a9b35aedc9991d4b53d18fea6"
1948
+                "reference": "437d4f3305458f29c32ef4de5ef1d9dbdc74c3fe"
1949
             },
1949
             },
1950
             "dist": {
1950
             "dist": {
1951
                 "type": "zip",
1951
                 "type": "zip",
1952
-                "url": "https://api.github.com/repos/filamentphp/support/zipball/a720fb2508a1d84a9b35aedc9991d4b53d18fea6",
1953
-                "reference": "a720fb2508a1d84a9b35aedc9991d4b53d18fea6",
1952
+                "url": "https://api.github.com/repos/filamentphp/support/zipball/437d4f3305458f29c32ef4de5ef1d9dbdc74c3fe",
1953
+                "reference": "437d4f3305458f29c32ef4de5ef1d9dbdc74c3fe",
1954
                 "shasum": ""
1954
                 "shasum": ""
1955
             },
1955
             },
1956
             "require": {
1956
             "require": {
1996
                 "issues": "https://github.com/filamentphp/filament/issues",
1996
                 "issues": "https://github.com/filamentphp/filament/issues",
1997
                 "source": "https://github.com/filamentphp/filament"
1997
                 "source": "https://github.com/filamentphp/filament"
1998
             },
1998
             },
1999
-            "time": "2024-11-29T09:31:13+00:00"
1999
+            "time": "2024-12-05T08:56:49+00:00"
2000
         },
2000
         },
2001
         {
2001
         {
2002
             "name": "filament/tables",
2002
             "name": "filament/tables",
2003
-            "version": "v3.2.127",
2003
+            "version": "v3.2.128",
2004
             "source": {
2004
             "source": {
2005
                 "type": "git",
2005
                 "type": "git",
2006
                 "url": "https://github.com/filamentphp/tables.git",
2006
                 "url": "https://github.com/filamentphp/tables.git",
2007
-                "reference": "c287a68e084c96c3f2991eaddf1d6b5159af5147"
2007
+                "reference": "4a60fda65574f248e082f109345216a38567093a"
2008
             },
2008
             },
2009
             "dist": {
2009
             "dist": {
2010
                 "type": "zip",
2010
                 "type": "zip",
2011
-                "url": "https://api.github.com/repos/filamentphp/tables/zipball/c287a68e084c96c3f2991eaddf1d6b5159af5147",
2012
-                "reference": "c287a68e084c96c3f2991eaddf1d6b5159af5147",
2011
+                "url": "https://api.github.com/repos/filamentphp/tables/zipball/4a60fda65574f248e082f109345216a38567093a",
2012
+                "reference": "4a60fda65574f248e082f109345216a38567093a",
2013
                 "shasum": ""
2013
                 "shasum": ""
2014
             },
2014
             },
2015
             "require": {
2015
             "require": {
2048
                 "issues": "https://github.com/filamentphp/filament/issues",
2048
                 "issues": "https://github.com/filamentphp/filament/issues",
2049
                 "source": "https://github.com/filamentphp/filament"
2049
                 "source": "https://github.com/filamentphp/filament"
2050
             },
2050
             },
2051
-            "time": "2024-11-30T09:21:26+00:00"
2051
+            "time": "2024-12-05T08:56:53+00:00"
2052
         },
2052
         },
2053
         {
2053
         {
2054
             "name": "filament/widgets",
2054
             "name": "filament/widgets",
2055
-            "version": "v3.2.127",
2055
+            "version": "v3.2.128",
2056
             "source": {
2056
             "source": {
2057
                 "type": "git",
2057
                 "type": "git",
2058
                 "url": "https://github.com/filamentphp/widgets.git",
2058
                 "url": "https://github.com/filamentphp/widgets.git",
4442
         },
4442
         },
4443
         {
4443
         {
4444
             "name": "monolog/monolog",
4444
             "name": "monolog/monolog",
4445
-            "version": "3.8.0",
4445
+            "version": "3.8.1",
4446
             "source": {
4446
             "source": {
4447
                 "type": "git",
4447
                 "type": "git",
4448
                 "url": "https://github.com/Seldaek/monolog.git",
4448
                 "url": "https://github.com/Seldaek/monolog.git",
4449
-                "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67"
4449
+                "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4"
4450
             },
4450
             },
4451
             "dist": {
4451
             "dist": {
4452
                 "type": "zip",
4452
                 "type": "zip",
4453
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67",
4454
-                "reference": "32e515fdc02cdafbe4593e30a9350d486b125b67",
4453
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4",
4454
+                "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4",
4455
                 "shasum": ""
4455
                 "shasum": ""
4456
             },
4456
             },
4457
             "require": {
4457
             "require": {
4529
             ],
4529
             ],
4530
             "support": {
4530
             "support": {
4531
                 "issues": "https://github.com/Seldaek/monolog/issues",
4531
                 "issues": "https://github.com/Seldaek/monolog/issues",
4532
-                "source": "https://github.com/Seldaek/monolog/tree/3.8.0"
4532
+                "source": "https://github.com/Seldaek/monolog/tree/3.8.1"
4533
             },
4533
             },
4534
             "funding": [
4534
             "funding": [
4535
                 {
4535
                 {
4541
                     "type": "tidelift"
4541
                     "type": "tidelift"
4542
                 }
4542
                 }
4543
             ],
4543
             ],
4544
-            "time": "2024-11-12T13:57:08+00:00"
4544
+            "time": "2024-12-05T17:15:07+00:00"
4545
         },
4545
         },
4546
         {
4546
         {
4547
             "name": "mtdowling/jmespath.php",
4547
             "name": "mtdowling/jmespath.php",
5064
         },
5064
         },
5065
         {
5065
         {
5066
             "name": "openspout/openspout",
5066
             "name": "openspout/openspout",
5067
-            "version": "v4.28.0",
5067
+            "version": "v4.28.1",
5068
             "source": {
5068
             "source": {
5069
                 "type": "git",
5069
                 "type": "git",
5070
                 "url": "https://github.com/openspout/openspout.git",
5070
                 "url": "https://github.com/openspout/openspout.git",
5071
-                "reference": "3e9ef74f13ba5e887e4afc7a4e0110e63559e902"
5071
+                "reference": "229a9c837bd768e8767660671f9fdf429f343a74"
5072
             },
5072
             },
5073
             "dist": {
5073
             "dist": {
5074
                 "type": "zip",
5074
                 "type": "zip",
5075
-                "url": "https://api.github.com/repos/openspout/openspout/zipball/3e9ef74f13ba5e887e4afc7a4e0110e63559e902",
5076
-                "reference": "3e9ef74f13ba5e887e4afc7a4e0110e63559e902",
5075
+                "url": "https://api.github.com/repos/openspout/openspout/zipball/229a9c837bd768e8767660671f9fdf429f343a74",
5076
+                "reference": "229a9c837bd768e8767660671f9fdf429f343a74",
5077
                 "shasum": ""
5077
                 "shasum": ""
5078
             },
5078
             },
5079
             "require": {
5079
             "require": {
5141
             ],
5141
             ],
5142
             "support": {
5142
             "support": {
5143
                 "issues": "https://github.com/openspout/openspout/issues",
5143
                 "issues": "https://github.com/openspout/openspout/issues",
5144
-                "source": "https://github.com/openspout/openspout/tree/v4.28.0"
5144
+                "source": "https://github.com/openspout/openspout/tree/v4.28.1"
5145
             },
5145
             },
5146
             "funding": [
5146
             "funding": [
5147
                 {
5147
                 {
5153
                     "type": "github"
5153
                     "type": "github"
5154
                 }
5154
                 }
5155
             ],
5155
             ],
5156
-            "time": "2024-11-29T09:45:53+00:00"
5156
+            "time": "2024-12-05T13:34:00+00:00"
5157
         },
5157
         },
5158
         {
5158
         {
5159
             "name": "paragonie/constant_time_encoding",
5159
             "name": "paragonie/constant_time_encoding",
9240
     "packages-dev": [
9240
     "packages-dev": [
9241
         {
9241
         {
9242
             "name": "brianium/paratest",
9242
             "name": "brianium/paratest",
9243
-            "version": "v7.6.0",
9243
+            "version": "v7.6.1",
9244
             "source": {
9244
             "source": {
9245
                 "type": "git",
9245
                 "type": "git",
9246
                 "url": "https://github.com/paratestphp/paratest.git",
9246
                 "url": "https://github.com/paratestphp/paratest.git",
9247
-                "reference": "68ff89a8de47d086588e391a516d2a5b5fde6254"
9247
+                "reference": "9ac8eda68f17acda4dad4aa02ecdcc327d7e6675"
9248
             },
9248
             },
9249
             "dist": {
9249
             "dist": {
9250
                 "type": "zip",
9250
                 "type": "zip",
9251
-                "url": "https://api.github.com/repos/paratestphp/paratest/zipball/68ff89a8de47d086588e391a516d2a5b5fde6254",
9252
-                "reference": "68ff89a8de47d086588e391a516d2a5b5fde6254",
9251
+                "url": "https://api.github.com/repos/paratestphp/paratest/zipball/9ac8eda68f17acda4dad4aa02ecdcc327d7e6675",
9252
+                "reference": "9ac8eda68f17acda4dad4aa02ecdcc327d7e6675",
9253
                 "shasum": ""
9253
                 "shasum": ""
9254
             },
9254
             },
9255
             "require": {
9255
             "require": {
9258
                 "ext-reflection": "*",
9258
                 "ext-reflection": "*",
9259
                 "ext-simplexml": "*",
9259
                 "ext-simplexml": "*",
9260
                 "fidry/cpu-core-counter": "^1.2.0",
9260
                 "fidry/cpu-core-counter": "^1.2.0",
9261
-                "jean85/pretty-package-versions": "^2.0.6",
9261
+                "jean85/pretty-package-versions": "^2.1.0",
9262
                 "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
9262
                 "php": "~8.2.0 || ~8.3.0 || ~8.4.0",
9263
                 "phpunit/php-code-coverage": "^11.0.7",
9263
                 "phpunit/php-code-coverage": "^11.0.7",
9264
                 "phpunit/php-file-iterator": "^5.1.0",
9264
                 "phpunit/php-file-iterator": "^5.1.0",
9265
                 "phpunit/php-timer": "^7.0.1",
9265
                 "phpunit/php-timer": "^7.0.1",
9266
-                "phpunit/phpunit": "^11.4.1",
9266
+                "phpunit/phpunit": "^11.4.4",
9267
                 "sebastian/environment": "^7.2.0",
9267
                 "sebastian/environment": "^7.2.0",
9268
-                "symfony/console": "^6.4.11 || ^7.1.5",
9269
-                "symfony/process": "^6.4.8 || ^7.1.5"
9268
+                "symfony/console": "^6.4.14 || ^7.1.7",
9269
+                "symfony/process": "^6.4.14 || ^7.1.7"
9270
             },
9270
             },
9271
             "require-dev": {
9271
             "require-dev": {
9272
                 "doctrine/coding-standard": "^12.0.0",
9272
                 "doctrine/coding-standard": "^12.0.0",
9273
                 "ext-pcov": "*",
9273
                 "ext-pcov": "*",
9274
                 "ext-posix": "*",
9274
                 "ext-posix": "*",
9275
-                "phpstan/phpstan": "^1.12.6",
9276
-                "phpstan/phpstan-deprecation-rules": "^1.2.1",
9277
-                "phpstan/phpstan-phpunit": "^1.4.0",
9278
-                "phpstan/phpstan-strict-rules": "^1.6.1",
9279
-                "squizlabs/php_codesniffer": "^3.10.3",
9280
-                "symfony/filesystem": "^6.4.9 || ^7.1.5"
9275
+                "phpstan/phpstan": "^2",
9276
+                "phpstan/phpstan-deprecation-rules": "^2",
9277
+                "phpstan/phpstan-phpunit": "^2",
9278
+                "phpstan/phpstan-strict-rules": "^2",
9279
+                "squizlabs/php_codesniffer": "^3.11.1",
9280
+                "symfony/filesystem": "^6.4.13 || ^7.1.6"
9281
             },
9281
             },
9282
             "bin": [
9282
             "bin": [
9283
                 "bin/paratest",
9283
                 "bin/paratest",
9317
             ],
9317
             ],
9318
             "support": {
9318
             "support": {
9319
                 "issues": "https://github.com/paratestphp/paratest/issues",
9319
                 "issues": "https://github.com/paratestphp/paratest/issues",
9320
-                "source": "https://github.com/paratestphp/paratest/tree/v7.6.0"
9320
+                "source": "https://github.com/paratestphp/paratest/tree/v7.6.1"
9321
             },
9321
             },
9322
             "funding": [
9322
             "funding": [
9323
                 {
9323
                 {
9329
                     "type": "paypal"
9329
                     "type": "paypal"
9330
                 }
9330
                 }
9331
             ],
9331
             ],
9332
-            "time": "2024-10-15T12:38:31+00:00"
9332
+            "time": "2024-12-05T10:55:39+00:00"
9333
         },
9333
         },
9334
         {
9334
         {
9335
             "name": "fakerphp/faker",
9335
             "name": "fakerphp/faker",
11766
         },
11766
         },
11767
         {
11767
         {
11768
             "name": "sebastian/exporter",
11768
             "name": "sebastian/exporter",
11769
-            "version": "6.1.3",
11769
+            "version": "6.3.0",
11770
             "source": {
11770
             "source": {
11771
                 "type": "git",
11771
                 "type": "git",
11772
                 "url": "https://github.com/sebastianbergmann/exporter.git",
11772
                 "url": "https://github.com/sebastianbergmann/exporter.git",
11773
-                "reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e"
11773
+                "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3"
11774
             },
11774
             },
11775
             "dist": {
11775
             "dist": {
11776
                 "type": "zip",
11776
                 "type": "zip",
11777
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e",
11778
-                "reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e",
11777
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3",
11778
+                "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3",
11779
                 "shasum": ""
11779
                 "shasum": ""
11780
             },
11780
             },
11781
             "require": {
11781
             "require": {
11784
                 "sebastian/recursion-context": "^6.0"
11784
                 "sebastian/recursion-context": "^6.0"
11785
             },
11785
             },
11786
             "require-dev": {
11786
             "require-dev": {
11787
-                "phpunit/phpunit": "^11.2"
11787
+                "phpunit/phpunit": "^11.3"
11788
             },
11788
             },
11789
             "type": "library",
11789
             "type": "library",
11790
             "extra": {
11790
             "extra": {
11832
             "support": {
11832
             "support": {
11833
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
11833
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
11834
                 "security": "https://github.com/sebastianbergmann/exporter/security/policy",
11834
                 "security": "https://github.com/sebastianbergmann/exporter/security/policy",
11835
-                "source": "https://github.com/sebastianbergmann/exporter/tree/6.1.3"
11835
+                "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0"
11836
             },
11836
             },
11837
             "funding": [
11837
             "funding": [
11838
                 {
11838
                 {
11840
                     "type": "github"
11840
                     "type": "github"
11841
                 }
11841
                 }
11842
             ],
11842
             ],
11843
-            "time": "2024-07-03T04:56:19+00:00"
11843
+            "time": "2024-12-05T09:17:50+00:00"
11844
         },
11844
         },
11845
         {
11845
         {
11846
             "name": "sebastian/global-state",
11846
             "name": "sebastian/global-state",

+ 27
- 9
database/factories/Accounting/InvoiceFactory.php 查看文件

10
 use App\Models\Common\Client;
10
 use App\Models\Common\Client;
11
 use App\Utilities\Currency\CurrencyConverter;
11
 use App\Utilities\Currency\CurrencyConverter;
12
 use Illuminate\Database\Eloquent\Factories\Factory;
12
 use Illuminate\Database\Eloquent\Factories\Factory;
13
+use Illuminate\Support\Carbon;
13
 
14
 
14
 /**
15
 /**
15
  * @extends Factory<Invoice>
16
  * @extends Factory<Invoice>
28
      */
29
      */
29
     public function definition(): array
30
     public function definition(): array
30
     {
31
     {
32
+        $invoiceDate = $this->faker->dateTimeBetween('-1 year');
33
+
31
         return [
34
         return [
32
             'company_id' => 1,
35
             'company_id' => 1,
33
             'client_id' => Client::inRandomOrder()->value('id'),
36
             'client_id' => Client::inRandomOrder()->value('id'),
35
             'subheader' => 'Invoice',
38
             'subheader' => 'Invoice',
36
             'invoice_number' => $this->faker->unique()->numerify('INV-#####'),
39
             'invoice_number' => $this->faker->unique()->numerify('INV-#####'),
37
             'order_number' => $this->faker->unique()->numerify('ORD-#####'),
40
             'order_number' => $this->faker->unique()->numerify('ORD-#####'),
38
-            'date' => $this->faker->dateTimeBetween('-1 year'),
39
-            'due_date' => $this->faker->dateTimeBetween('-2 months', '+2 months'),
41
+            'date' => $invoiceDate,
42
+            'due_date' => Carbon::parse($invoiceDate)->addDays($this->faker->numberBetween(14, 60)),
40
             'status' => InvoiceStatus::Draft,
43
             'status' => InvoiceStatus::Draft,
41
             'currency_code' => 'USD',
44
             'currency_code' => 'USD',
42
             'terms' => $this->faker->sentence,
45
             'terms' => $this->faker->sentence,
60
 
63
 
61
             $this->recalculateTotals($invoice);
64
             $this->recalculateTotals($invoice);
62
 
65
 
63
-            $invoice->approveDraft();
66
+            $approvedAt = Carbon::parse($invoice->date)->addHours($this->faker->numberBetween(1, 24));
67
+
68
+            $invoice->approveDraft($approvedAt);
64
         });
69
         });
65
     }
70
     }
66
 
71
 
68
     {
73
     {
69
         return $this->afterCreating(function (Invoice $invoice) use ($invoiceStatus, $max, $min) {
74
         return $this->afterCreating(function (Invoice $invoice) use ($invoiceStatus, $max, $min) {
70
             if ($invoice->isDraft()) {
75
             if ($invoice->isDraft()) {
71
-
72
                 $this->recalculateTotals($invoice);
76
                 $this->recalculateTotals($invoice);
73
 
77
 
74
-                $invoice->approveDraft();
78
+                $approvedAt = Carbon::parse($invoice->date)->addHours($this->faker->numberBetween(1, 24));
79
+                $invoice->approveDraft($approvedAt);
75
             }
80
             }
76
 
81
 
77
             $invoice->refresh();
82
             $invoice->refresh();
89
             }
94
             }
90
 
95
 
91
             $paymentCount = $max && $min ? $this->faker->numberBetween($min, $max) : $min;
96
             $paymentCount = $max && $min ? $this->faker->numberBetween($min, $max) : $min;
92
-
93
             $paymentAmount = (int) floor($totalAmountDue / $paymentCount);
97
             $paymentAmount = (int) floor($totalAmountDue / $paymentCount);
94
             $remainingAmount = $totalAmountDue;
98
             $remainingAmount = $totalAmountDue;
95
 
99
 
100
+            $paymentDate = Carbon::parse($invoice->approved_at);
101
+            $paymentDates = [];
102
+
96
             for ($i = 0; $i < $paymentCount; $i++) {
103
             for ($i = 0; $i < $paymentCount; $i++) {
97
                 $amount = $i === $paymentCount - 1 ? $remainingAmount : $paymentAmount;
104
                 $amount = $i === $paymentCount - 1 ? $remainingAmount : $paymentAmount;
98
 
105
 
100
                     break;
107
                     break;
101
                 }
108
                 }
102
 
109
 
110
+                $postedAt = $paymentDate->copy()->addDays($this->faker->numberBetween(1, 30));
111
+                $paymentDates[] = $postedAt;
112
+
103
                 $data = [
113
                 $data = [
104
-                    'posted_at' => $invoice->date->addDay(),
114
+                    'posted_at' => $postedAt,
105
                     'amount' => CurrencyConverter::convertCentsToFormatSimple($amount, $invoice->currency_code),
115
                     'amount' => CurrencyConverter::convertCentsToFormatSimple($amount, $invoice->currency_code),
106
                     'payment_method' => $this->faker->randomElement(PaymentMethod::class),
116
                     'payment_method' => $this->faker->randomElement(PaymentMethod::class),
107
                     'bank_account_id' => BankAccount::inRandomOrder()->value('id'),
117
                     'bank_account_id' => BankAccount::inRandomOrder()->value('id'),
109
                 ];
119
                 ];
110
 
120
 
111
                 $invoice->recordPayment($data);
121
                 $invoice->recordPayment($data);
112
-
113
                 $remainingAmount -= $amount;
122
                 $remainingAmount -= $amount;
114
             }
123
             }
124
+
125
+            // If it's a paid invoice, use the latest payment date as paid_at
126
+            if ($invoiceStatus === InvoiceStatus::Paid) {
127
+                $latestPaymentDate = max($paymentDates);
128
+                $invoice->updateQuietly([
129
+                    'status' => InvoiceStatus::Paid,
130
+                    'paid_at' => $latestPaymentDate,
131
+                ]);
132
+            }
115
         });
133
         });
116
     }
134
     }
117
 
135
 
128
 
146
 
129
             $this->recalculateTotals($invoice);
147
             $this->recalculateTotals($invoice);
130
 
148
 
131
-            if ($invoice->is_currently_overdue) {
149
+            if ($invoice->approved_at && $invoice->is_currently_overdue) {
132
                 $invoice->updateQuietly([
150
                 $invoice->updateQuietly([
133
                     'status' => InvoiceStatus::Overdue,
151
                     'status' => InvoiceStatus::Overdue,
134
                 ]);
152
                 ]);

+ 0
- 23
database/factories/Accounting/InvoiceStatusHistoryFactory.php 查看文件

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/migrations/2024_11_27_223015_create_invoices_table.php 查看文件

22
             $table->string('order_number')->nullable(); // PO, SO, etc.
22
             $table->string('order_number')->nullable(); // PO, SO, etc.
23
             $table->date('date')->nullable();
23
             $table->date('date')->nullable();
24
             $table->date('due_date')->nullable();
24
             $table->date('due_date')->nullable();
25
+            $table->timestamp('approved_at')->nullable();
26
+            $table->timestamp('paid_at')->nullable();
27
+            $table->timestamp('last_sent')->nullable();
25
             $table->string('status')->default('draft');
28
             $table->string('status')->default('draft');
26
             $table->string('currency_code')->nullable();
29
             $table->string('currency_code')->nullable();
27
             $table->integer('subtotal')->default(0);
30
             $table->integer('subtotal')->default(0);

+ 0
- 33
database/migrations/2024_12_05_003805_create_invoice_status_histories_table.php 查看文件

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
-};

+ 6
- 6
package-lock.json 查看文件

1204
             "license": "MIT"
1204
             "license": "MIT"
1205
         },
1205
         },
1206
         "node_modules/electron-to-chromium": {
1206
         "node_modules/electron-to-chromium": {
1207
-            "version": "1.5.68",
1208
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.68.tgz",
1209
-            "integrity": "sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==",
1207
+            "version": "1.5.71",
1208
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz",
1209
+            "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==",
1210
             "dev": true,
1210
             "dev": true,
1211
             "license": "ISC"
1211
             "license": "ISC"
1212
         },
1212
         },
2588
             "license": "MIT"
2588
             "license": "MIT"
2589
         },
2589
         },
2590
         "node_modules/vite": {
2590
         "node_modules/vite": {
2591
-            "version": "6.0.2",
2592
-            "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.2.tgz",
2593
-            "integrity": "sha512-XdQ+VsY2tJpBsKGs0wf3U/+azx8BBpYRHFAyKm5VeEZNOJZRB63q7Sc8Iup3k0TrN3KO6QgyzFf+opSbfY1y0g==",
2591
+            "version": "6.0.3",
2592
+            "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.3.tgz",
2593
+            "integrity": "sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==",
2594
             "dev": true,
2594
             "dev": true,
2595
             "license": "MIT",
2595
             "license": "MIT",
2596
             "dependencies": {
2596
             "dependencies": {

正在加载...
取消
保存