Преглед на файлове

feat: Plaid import transaction updates

3.x
wallo преди 1 година
родител
ревизия
5a6f0a5503

+ 41
- 0
app/Console/Commands/FirePlaidWebhook.php Целия файл

@@ -0,0 +1,41 @@
1
+<?php
2
+
3
+namespace App\Console\Commands;
4
+
5
+use App\Models\Banking\ConnectedBankAccount;
6
+use App\Services\PlaidService;
7
+use Illuminate\Console\Command;
8
+
9
+class FirePlaidWebhook extends Command
10
+{
11
+    /**
12
+     * The name and signature of the console command.
13
+     *
14
+     * @var string
15
+     */
16
+    protected $signature = 'plaid:fire-webhook';
17
+
18
+    /**
19
+     * The console command description.
20
+     *
21
+     * @var string
22
+     */
23
+    protected $description = 'Command description';
24
+
25
+    /**
26
+     * Execute the console command.
27
+     */
28
+    public function handle(PlaidService $plaidService): void
29
+    {
30
+        $accessToken = ConnectedBankAccount::first()->access_token;
31
+        $webhookCode = 'DEFAULT_UPDATE';
32
+        $webhookType = 'TRANSACTIONS';
33
+
34
+        try {
35
+            $response = $plaidService->fireSandboxWebhook($accessToken, $webhookCode, $webhookType);
36
+            $this->info('Webhook Fired Successfully' . PHP_EOL . json_encode($response, JSON_PRETTY_PRINT));
37
+        } catch (\Exception $e) {
38
+            $this->error('Failed to Fire Webhook' . PHP_EOL . $e->getMessage());
39
+        }
40
+    }
41
+}

+ 6
- 1
app/Filament/Company/Resources/Banking/AccountResource.php Целия файл

@@ -251,9 +251,14 @@ class AccountResource extends Resource
251 251
             ])
252 252
             ->bulkActions([
253 253
                 Tables\Actions\BulkActionGroup::make([
254
-                    Tables\Actions\DeleteBulkAction::make(),
254
+                    Tables\Actions\DeleteBulkAction::make()
255
+                        ->requiresConfirmation()
256
+                        ->modalDescription('Are you sure you want to delete the selected accounts? All transactions associated with the accounts will be deleted as well.'),
255 257
                 ]),
256 258
             ])
259
+            ->checkIfRecordIsSelectableUsing(static function (BankAccount $record) {
260
+                return $record->isDisabled();
261
+            })
257 262
             ->emptyStateActions([
258 263
                 Tables\Actions\CreateAction::make(),
259 264
             ]);

+ 1
- 2
app/Filament/Company/Resources/Banking/AccountResource/Pages/EditAccount.php Целия файл

@@ -4,7 +4,6 @@ namespace App\Filament\Company\Resources\Banking\AccountResource\Pages;
4 4
 
5 5
 use App\Concerns\HandlesResourceRecordUpdate;
6 6
 use App\Filament\Company\Resources\Banking\AccountResource;
7
-use Filament\Actions;
8 7
 use Filament\Resources\Pages\EditRecord;
9 8
 
10 9
 class EditAccount extends EditRecord
@@ -16,7 +15,7 @@ class EditAccount extends EditRecord
16 15
     protected function getHeaderActions(): array
17 16
     {
18 17
         return [
19
-            Actions\DeleteAction::make(),
18
+            //
20 19
         ];
21 20
     }
22 21
 

+ 42
- 0
app/Http/Controllers/PlaidWebhookController.php Целия файл

@@ -0,0 +1,42 @@
1
+<?php
2
+
3
+namespace App\Http\Controllers;
4
+
5
+use App\Jobs\ProcessTransactionUpdate;
6
+use App\Models\Company;
7
+use Illuminate\Http\Request;
8
+
9
+class PlaidWebhookController extends Controller
10
+{
11
+    public function handleWebhook(Request $request)
12
+    {
13
+        $payload = $request->all();
14
+
15
+        if ($payload['webhook_type'] === 'TRANSACTIONS') {
16
+            $this->handleTransactionsWebhook($payload);
17
+        }
18
+
19
+        return response()->json(['message' => 'Plaid Transaction Webhook Received']);
20
+    }
21
+
22
+    private function handleTransactionsWebhook(array $payload): void
23
+    {
24
+        if ($payload['webhook_code'] === 'DEFAULT_UPDATE') {
25
+            $this->handleDefaultUpdate($payload);
26
+        }
27
+    }
28
+
29
+    private function handleDefaultUpdate(array $payload): void
30
+    {
31
+        $newTransactions = $payload['new_transactions'];
32
+        $itemID = $payload['item_id'];
33
+
34
+        $company = Company::whereHas('connectedBankAccounts', static function ($query) use ($itemID) {
35
+            $query->where('item_id', $itemID);
36
+        })->first();
37
+
38
+        if ($company && $newTransactions > 0) {
39
+            ProcessTransactionUpdate::dispatch($company, $itemID);
40
+        }
41
+    }
42
+}

+ 4
- 0
app/Jobs/ProcessTransactionImport.php Целия файл

@@ -78,6 +78,10 @@ class ProcessTransactionImport implements ShouldQueue
78 78
 
79 79
             $transactionService->createStartingBalanceIfNeeded($this->company, $this->account, $this->bankAccount, $postedTransactions, $currentBalance, $startDate);
80 80
             $transactionService->storeTransactions($this->company, $this->bankAccount, $postedTransactions);
81
+
82
+            $this->connectedBankAccount->update([
83
+                'last_imported_at' => Carbon::now(),
84
+            ]);
81 85
         }
82 86
     }
83 87
 }

+ 88
- 0
app/Jobs/ProcessTransactionUpdate.php Целия файл

@@ -0,0 +1,88 @@
1
+<?php
2
+
3
+namespace App\Jobs;
4
+
5
+use App\Models\Banking\ConnectedBankAccount;
6
+use App\Models\Company;
7
+use App\Services\PlaidService;
8
+use App\Services\TransactionService;
9
+use Illuminate\Bus\Queueable;
10
+use Illuminate\Contracts\Queue\ShouldQueue;
11
+use Illuminate\Foundation\Bus\Dispatchable;
12
+use Illuminate\Queue\InteractsWithQueue;
13
+use Illuminate\Queue\SerializesModels;
14
+use Illuminate\Support\Carbon;
15
+
16
+class ProcessTransactionUpdate implements ShouldQueue
17
+{
18
+    use Dispatchable;
19
+    use InteractsWithQueue;
20
+    use Queueable;
21
+    use SerializesModels;
22
+
23
+    protected Company $company;
24
+
25
+    protected string $item_id;
26
+
27
+    /**
28
+     * Create a new job instance.
29
+     */
30
+    public function __construct(Company $company, string $item_id)
31
+    {
32
+        $this->company = $company;
33
+        $this->item_id = $item_id;
34
+    }
35
+
36
+    /**
37
+     * Execute the job.
38
+     */
39
+    public function handle(PlaidService $plaidService, TransactionService $transactionService): void
40
+    {
41
+        $connectedBankAccounts = $this->company->connectedBankAccounts()
42
+            ->where('item_id', $this->item_id)
43
+            ->where('import_transactions', true);
44
+
45
+        foreach ($connectedBankAccounts as $connectedBankAccount) {
46
+            /** @var ConnectedBankAccount $connectedBankAccount */
47
+            $accessToken = $connectedBankAccount->access_token;
48
+            $bankAccount = $connectedBankAccount->bankAccount;
49
+            $allTransactions = [];
50
+            $offset = 0;
51
+
52
+            $bufferDays = 15;
53
+            $lastImportedAtDate = Carbon::parse($connectedBankAccount->last_imported_at);
54
+            $startDate = $lastImportedAtDate->subDays($bufferDays)->toDateString();
55
+            $endDate = Carbon::now()->toDateString();
56
+
57
+            $transactionsResponse = $plaidService->getTransactions($accessToken, $startDate, $endDate, [
58
+                'account_ids' => [$connectedBankAccount->external_account_id],
59
+            ]);
60
+
61
+            $allTransactions = [...$allTransactions, ...$transactionsResponse->transactions];
62
+            $totalTransactions = $transactionsResponse->total_transactions;
63
+
64
+            while (count($allTransactions) < $totalTransactions) {
65
+                $offset += count($transactionsResponse->transactions);
66
+                $transactionsResponse = $plaidService->getTransactions($accessToken, $startDate, $endDate, [
67
+                    'account_ids' => [$connectedBankAccount->external_account_id],
68
+                    'offset' => $offset,
69
+                ]);
70
+
71
+                $allTransactions = [...$allTransactions, ...$transactionsResponse->transactions];
72
+            }
73
+
74
+            $existingTransactionIds = $bankAccount->transactions()->pluck('transaction_id')->toArray();
75
+            $newTransactions = array_filter($allTransactions, static function ($transaction) use ($existingTransactionIds) {
76
+                return ! in_array($transaction->transaction_id, $existingTransactionIds) && $transaction->pending === false;
77
+            });
78
+
79
+            if (count($newTransactions) > 0) {
80
+                $transactionService->storeTransactions($this->company, $bankAccount, $newTransactions);
81
+
82
+                $connectedBankAccount->update([
83
+                    'last_imported_at' => Carbon::now(),
84
+                ]);
85
+            }
86
+        }
87
+    }
88
+}

+ 1
- 0
app/Models/Accounting/Transaction.php Целия файл

@@ -28,6 +28,7 @@ class Transaction extends Model
28 28
         'company_id',
29 29
         'account_id', // Account from Chart of Accounts (Income/Expense accounts)
30 30
         'bank_account_id', // Cash/Bank Account
31
+        'plaid_transaction_id',
31 32
         'contact_id',
32 33
         'type', // 'deposit', 'withdrawal', 'journal'
33 34
         'payment_channel',

+ 2
- 0
app/Models/Banking/ConnectedBankAccount.php Целия файл

@@ -33,6 +33,7 @@ class ConnectedBankAccount extends Model
33 33
         'type',
34 34
         'subtype',
35 35
         'import_transactions',
36
+        'last_imported_at',
36 37
         'created_by',
37 38
         'updated_by',
38 39
     ];
@@ -41,6 +42,7 @@ class ConnectedBankAccount extends Model
41 42
         'import_transactions' => 'boolean',
42 43
         'type' => BankAccountType::class,
43 44
         'access_token' => 'encrypted',
45
+        'last_imported_at' => 'datetime',
44 46
     ];
45 47
 
46 48
     protected $appends = [

+ 13
- 0
app/Models/Banking/Institution.php Целия файл

@@ -57,6 +57,19 @@ class Institution extends Model
57 57
         return null;
58 58
     }
59 59
 
60
+    public function getLastImportDate(): ?string
61
+    {
62
+        $latestDate = $this->connectedBankAccounts->map(function ($connectedBankAccount) {
63
+            return $connectedBankAccount->last_imported_at;
64
+        })->filter()->max();
65
+
66
+        if ($latestDate) {
67
+            return Carbon::parse($latestDate)->diffForHumans();
68
+        }
69
+
70
+        return null;
71
+    }
72
+
60 73
     protected function logoUrl(): Attribute
61 74
     {
62 75
         return Attribute::get(static function (mixed $value, array $attributes): ?string {

+ 22
- 1
app/Observers/BankAccountObserver.php Целия файл

@@ -3,9 +3,10 @@
3 3
 namespace App\Observers;
4 4
 
5 5
 use App\Enums\Accounting\AccountType;
6
-use App\Models\Accounting\Account;
7 6
 use App\Models\Accounting\AccountSubtype;
7
+use App\Models\Accounting\Transaction;
8 8
 use App\Models\Banking\BankAccount;
9
+use Illuminate\Support\Facades\DB;
9 10
 
10 11
 class BankAccountObserver
11 12
 {
@@ -52,6 +53,26 @@ class BankAccountObserver
52 53
         //
53 54
     }
54 55
 
56
+    /**
57
+     * Handle the BankAccount "deleting" event.
58
+     */
59
+    public function deleting(BankAccount $bankAccount): void
60
+    {
61
+        DB::transaction(function () use ($bankAccount) {
62
+            $account = $bankAccount->account;
63
+            $connectedBankAccount = $bankAccount->connectedBankAccount;
64
+
65
+            if ($account) {
66
+                $bankAccount->transactions()->each(fn (Transaction $transaction) => $transaction->delete());
67
+                $account->delete();
68
+            }
69
+
70
+            if ($connectedBankAccount) {
71
+                $connectedBankAccount->delete();
72
+            }
73
+        });
74
+    }
75
+
55 76
     /**
56 77
      * Handle the BankAccount "deleted" event.
57 78
      */

+ 14
- 0
app/Services/PlaidService.php Целия файл

@@ -21,6 +21,8 @@ class PlaidService
21 21
 
22 22
     protected ?string $environment;
23 23
 
24
+    protected ?string $webhook_url;
25
+
24 26
     protected ?string $base_url;
25 27
 
26 28
     protected HttpClient $client;
@@ -51,6 +53,7 @@ class PlaidService
51 53
         $this->client_id = $this->config->get('plaid.client_id');
52 54
         $this->client_secret = $this->config->get('plaid.client_secret');
53 55
         $this->environment = $this->config->get('plaid.environment', 'sandbox');
56
+        $this->webhook_url = $this->config->get('plaid.webhook_url');
54 57
 
55 58
         $this->setBaseUrl($this->environment);
56 59
     }
@@ -191,6 +194,10 @@ class PlaidService
191 194
             $data['products'] = $products;
192 195
         }
193 196
 
197
+        if (! empty($this->webhook_url)) {
198
+            $data['webhook'] = $this->webhook_url;
199
+        }
200
+
194 201
         return $this->sendRequest('link/token/create', $data);
195 202
     }
196 203
 
@@ -244,4 +251,11 @@ class PlaidService
244 251
 
245 252
         return $this->sendRequest('transactions/get', $data);
246 253
     }
254
+
255
+    public function fireSandboxWebhook(string $access_token, string $webhook_code, string $webhook_type): object
256
+    {
257
+        $data = compact('access_token', 'webhook_code', 'webhook_type');
258
+
259
+        return $this->sendRequest('sandbox/item/fire_webhook', $data);
260
+    }
247 261
 }

+ 1
- 0
app/Services/TransactionService.php Целия файл

@@ -70,6 +70,7 @@ class TransactionService
70 70
             'company_id' => $company->id,
71 71
             'account_id' => $chartAccount->id,
72 72
             'bank_account_id' => $bankAccount->id,
73
+            'plaid_transaction_id' => $transaction->transaction_id,
73 74
             'type' => $transactionType,
74 75
             'amount' => abs($transaction->amount),
75 76
             'payment_channel' => $paymentChannel,

+ 47
- 47
composer.lock Целия файл

@@ -497,16 +497,16 @@
497 497
         },
498 498
         {
499 499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.304.3",
500
+            "version": "3.304.4",
501 501
             "source": {
502 502
                 "type": "git",
503 503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "d1ecaba720dc5d935d4ff66255f990fce3aa9727"
504
+                "reference": "20be41a5f1eef4c8a53a6ae7c0fc8b7346c0c386"
505 505
             },
506 506
             "dist": {
507 507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d1ecaba720dc5d935d4ff66255f990fce3aa9727",
509
-                "reference": "d1ecaba720dc5d935d4ff66255f990fce3aa9727",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/20be41a5f1eef4c8a53a6ae7c0fc8b7346c0c386",
509
+                "reference": "20be41a5f1eef4c8a53a6ae7c0fc8b7346c0c386",
510 510
                 "shasum": ""
511 511
             },
512 512
             "require": {
@@ -586,9 +586,9 @@
586 586
             "support": {
587 587
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
588 588
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
589
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.304.3"
589
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.304.4"
590 590
             },
591
-            "time": "2024-04-11T18:05:41+00:00"
591
+            "time": "2024-04-12T18:06:45+00:00"
592 592
         },
593 593
         {
594 594
             "name": "aws/aws-sdk-php-laravel",
@@ -1790,16 +1790,16 @@
1790 1790
         },
1791 1791
         {
1792 1792
             "name": "dompdf/dompdf",
1793
-            "version": "v2.0.4",
1793
+            "version": "v2.0.5",
1794 1794
             "source": {
1795 1795
                 "type": "git",
1796 1796
                 "url": "https://github.com/dompdf/dompdf.git",
1797
-                "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f"
1797
+                "reference": "502e966a0da0446dd6712ee4f678dc4736181fcb"
1798 1798
             },
1799 1799
             "dist": {
1800 1800
                 "type": "zip",
1801
-                "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f",
1802
-                "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f",
1801
+                "url": "https://api.github.com/repos/dompdf/dompdf/zipball/502e966a0da0446dd6712ee4f678dc4736181fcb",
1802
+                "reference": "502e966a0da0446dd6712ee4f678dc4736181fcb",
1803 1803
                 "shasum": ""
1804 1804
             },
1805 1805
             "require": {
@@ -1807,7 +1807,7 @@
1807 1807
                 "ext-mbstring": "*",
1808 1808
                 "masterminds/html5": "^2.0",
1809 1809
                 "phenx/php-font-lib": ">=0.5.4 <1.0.0",
1810
-                "phenx/php-svg-lib": ">=0.3.3 <1.0.0",
1810
+                "phenx/php-svg-lib": ">=0.5.2 <1.0.0",
1811 1811
                 "php": "^7.1 || ^8.0"
1812 1812
             },
1813 1813
             "require-dev": {
@@ -1846,9 +1846,9 @@
1846 1846
             "homepage": "https://github.com/dompdf/dompdf",
1847 1847
             "support": {
1848 1848
                 "issues": "https://github.com/dompdf/dompdf/issues",
1849
-                "source": "https://github.com/dompdf/dompdf/tree/v2.0.4"
1849
+                "source": "https://github.com/dompdf/dompdf/tree/v2.0.5"
1850 1850
             },
1851
-            "time": "2023-12-12T20:19:39+00:00"
1851
+            "time": "2024-04-11T11:59:08+00:00"
1852 1852
         },
1853 1853
         {
1854 1854
             "name": "dragonmantank/cron-expression",
@@ -1980,7 +1980,7 @@
1980 1980
         },
1981 1981
         {
1982 1982
             "name": "filament/actions",
1983
-            "version": "v3.2.65",
1983
+            "version": "v3.2.66",
1984 1984
             "source": {
1985 1985
                 "type": "git",
1986 1986
                 "url": "https://github.com/filamentphp/actions.git",
@@ -2033,16 +2033,16 @@
2033 2033
         },
2034 2034
         {
2035 2035
             "name": "filament/filament",
2036
-            "version": "v3.2.65",
2036
+            "version": "v3.2.66",
2037 2037
             "source": {
2038 2038
                 "type": "git",
2039 2039
                 "url": "https://github.com/filamentphp/panels.git",
2040
-                "reference": "669ce35aef3a577af7f5d27b8acc7e4622c45f33"
2040
+                "reference": "69c4c60fbc9c22708dde1aee017c4cc2ff99e0a1"
2041 2041
             },
2042 2042
             "dist": {
2043 2043
                 "type": "zip",
2044
-                "url": "https://api.github.com/repos/filamentphp/panels/zipball/669ce35aef3a577af7f5d27b8acc7e4622c45f33",
2045
-                "reference": "669ce35aef3a577af7f5d27b8acc7e4622c45f33",
2044
+                "url": "https://api.github.com/repos/filamentphp/panels/zipball/69c4c60fbc9c22708dde1aee017c4cc2ff99e0a1",
2045
+                "reference": "69c4c60fbc9c22708dde1aee017c4cc2ff99e0a1",
2046 2046
                 "shasum": ""
2047 2047
             },
2048 2048
             "require": {
@@ -2094,11 +2094,11 @@
2094 2094
                 "issues": "https://github.com/filamentphp/filament/issues",
2095 2095
                 "source": "https://github.com/filamentphp/filament"
2096 2096
             },
2097
-            "time": "2024-04-11T21:38:39+00:00"
2097
+            "time": "2024-04-12T14:57:11+00:00"
2098 2098
         },
2099 2099
         {
2100 2100
             "name": "filament/forms",
2101
-            "version": "v3.2.65",
2101
+            "version": "v3.2.66",
2102 2102
             "source": {
2103 2103
                 "type": "git",
2104 2104
                 "url": "https://github.com/filamentphp/forms.git",
@@ -2154,7 +2154,7 @@
2154 2154
         },
2155 2155
         {
2156 2156
             "name": "filament/infolists",
2157
-            "version": "v3.2.65",
2157
+            "version": "v3.2.66",
2158 2158
             "source": {
2159 2159
                 "type": "git",
2160 2160
                 "url": "https://github.com/filamentphp/infolists.git",
@@ -2205,7 +2205,7 @@
2205 2205
         },
2206 2206
         {
2207 2207
             "name": "filament/notifications",
2208
-            "version": "v3.2.65",
2208
+            "version": "v3.2.66",
2209 2209
             "source": {
2210 2210
                 "type": "git",
2211 2211
                 "url": "https://github.com/filamentphp/notifications.git",
@@ -2257,7 +2257,7 @@
2257 2257
         },
2258 2258
         {
2259 2259
             "name": "filament/support",
2260
-            "version": "v3.2.65",
2260
+            "version": "v3.2.66",
2261 2261
             "source": {
2262 2262
                 "type": "git",
2263 2263
                 "url": "https://github.com/filamentphp/support.git",
@@ -2315,16 +2315,16 @@
2315 2315
         },
2316 2316
         {
2317 2317
             "name": "filament/tables",
2318
-            "version": "v3.2.65",
2318
+            "version": "v3.2.66",
2319 2319
             "source": {
2320 2320
                 "type": "git",
2321 2321
                 "url": "https://github.com/filamentphp/tables.git",
2322
-                "reference": "1cdf9ee9ba35cad6e8e41725896e26e397549440"
2322
+                "reference": "0f3d2b3525a7ffd6cf71f26fcc02d33c4d6c7793"
2323 2323
             },
2324 2324
             "dist": {
2325 2325
                 "type": "zip",
2326
-                "url": "https://api.github.com/repos/filamentphp/tables/zipball/1cdf9ee9ba35cad6e8e41725896e26e397549440",
2327
-                "reference": "1cdf9ee9ba35cad6e8e41725896e26e397549440",
2326
+                "url": "https://api.github.com/repos/filamentphp/tables/zipball/0f3d2b3525a7ffd6cf71f26fcc02d33c4d6c7793",
2327
+                "reference": "0f3d2b3525a7ffd6cf71f26fcc02d33c4d6c7793",
2328 2328
                 "shasum": ""
2329 2329
             },
2330 2330
             "require": {
@@ -2364,11 +2364,11 @@
2364 2364
                 "issues": "https://github.com/filamentphp/filament/issues",
2365 2365
                 "source": "https://github.com/filamentphp/filament"
2366 2366
             },
2367
-            "time": "2024-04-11T07:41:14+00:00"
2367
+            "time": "2024-04-12T14:57:32+00:00"
2368 2368
         },
2369 2369
         {
2370 2370
             "name": "filament/widgets",
2371
-            "version": "v3.2.65",
2371
+            "version": "v3.2.66",
2372 2372
             "source": {
2373 2373
                 "type": "git",
2374 2374
                 "url": "https://github.com/filamentphp/widgets.git",
@@ -4490,16 +4490,16 @@
4490 4490
         },
4491 4491
         {
4492 4492
             "name": "matomo/device-detector",
4493
-            "version": "6.3.0",
4493
+            "version": "6.3.1",
4494 4494
             "source": {
4495 4495
                 "type": "git",
4496 4496
                 "url": "https://github.com/matomo-org/device-detector.git",
4497
-                "reference": "35efad75b31f2596701834d19f097497909572a4"
4497
+                "reference": "8096093346917ee2477d802ab3b00c4c091c5cee"
4498 4498
             },
4499 4499
             "dist": {
4500 4500
                 "type": "zip",
4501
-                "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/35efad75b31f2596701834d19f097497909572a4",
4502
-                "reference": "35efad75b31f2596701834d19f097497909572a4",
4501
+                "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/8096093346917ee2477d802ab3b00c4c091c5cee",
4502
+                "reference": "8096093346917ee2477d802ab3b00c4c091c5cee",
4503 4503
                 "shasum": ""
4504 4504
             },
4505 4505
             "require": {
@@ -4555,20 +4555,20 @@
4555 4555
                 "source": "https://github.com/matomo-org/matomo",
4556 4556
                 "wiki": "https://dev.matomo.org/"
4557 4557
             },
4558
-            "time": "2024-02-16T16:26:57+00:00"
4558
+            "time": "2024-04-12T12:16:21+00:00"
4559 4559
         },
4560 4560
         {
4561 4561
             "name": "monolog/monolog",
4562
-            "version": "3.5.0",
4562
+            "version": "3.6.0",
4563 4563
             "source": {
4564 4564
                 "type": "git",
4565 4565
                 "url": "https://github.com/Seldaek/monolog.git",
4566
-                "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448"
4566
+                "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654"
4567 4567
             },
4568 4568
             "dist": {
4569 4569
                 "type": "zip",
4570
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448",
4571
-                "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448",
4570
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
4571
+                "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654",
4572 4572
                 "shasum": ""
4573 4573
             },
4574 4574
             "require": {
@@ -4591,7 +4591,7 @@
4591 4591
                 "phpstan/phpstan": "^1.9",
4592 4592
                 "phpstan/phpstan-deprecation-rules": "^1.0",
4593 4593
                 "phpstan/phpstan-strict-rules": "^1.4",
4594
-                "phpunit/phpunit": "^10.1",
4594
+                "phpunit/phpunit": "^10.5.17",
4595 4595
                 "predis/predis": "^1.1 || ^2",
4596 4596
                 "ruflin/elastica": "^7",
4597 4597
                 "symfony/mailer": "^5.4 || ^6",
@@ -4644,7 +4644,7 @@
4644 4644
             ],
4645 4645
             "support": {
4646 4646
                 "issues": "https://github.com/Seldaek/monolog/issues",
4647
-                "source": "https://github.com/Seldaek/monolog/tree/3.5.0"
4647
+                "source": "https://github.com/Seldaek/monolog/tree/3.6.0"
4648 4648
             },
4649 4649
             "funding": [
4650 4650
                 {
@@ -4656,7 +4656,7 @@
4656 4656
                     "type": "tidelift"
4657 4657
                 }
4658 4658
             ],
4659
-            "time": "2023-10-27T15:32:31+00:00"
4659
+            "time": "2024-04-12T21:02:21+00:00"
4660 4660
         },
4661 4661
         {
4662 4662
             "name": "mtdowling/jmespath.php",
@@ -10344,16 +10344,16 @@
10344 10344
         },
10345 10345
         {
10346 10346
             "name": "phpunit/phpunit",
10347
-            "version": "10.5.17",
10347
+            "version": "10.5.18",
10348 10348
             "source": {
10349 10349
                 "type": "git",
10350 10350
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
10351
-                "reference": "c1f736a473d21957ead7e94fcc029f571895abf5"
10351
+                "reference": "835df1709ac6c968ba34bf23f3c30e5d5a266de8"
10352 10352
             },
10353 10353
             "dist": {
10354 10354
                 "type": "zip",
10355
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c1f736a473d21957ead7e94fcc029f571895abf5",
10356
-                "reference": "c1f736a473d21957ead7e94fcc029f571895abf5",
10355
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/835df1709ac6c968ba34bf23f3c30e5d5a266de8",
10356
+                "reference": "835df1709ac6c968ba34bf23f3c30e5d5a266de8",
10357 10357
                 "shasum": ""
10358 10358
             },
10359 10359
             "require": {
@@ -10425,7 +10425,7 @@
10425 10425
             "support": {
10426 10426
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
10427 10427
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
10428
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.17"
10428
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.18"
10429 10429
             },
10430 10430
             "funding": [
10431 10431
                 {
@@ -10441,7 +10441,7 @@
10441 10441
                     "type": "tidelift"
10442 10442
                 }
10443 10443
             ],
10444
-            "time": "2024-04-05T04:39:01+00:00"
10444
+            "time": "2024-04-14T07:05:31+00:00"
10445 10445
         },
10446 10446
         {
10447 10447
             "name": "sebastian/cli-parser",

+ 1
- 0
config/plaid.php Целия файл

@@ -4,4 +4,5 @@ return [
4 4
     'client_id' => env('PLAID_CLIENT_ID'),
5 5
     'client_secret' => env('PLAID_CLIENT_SECRET'),
6 6
     'environment' => env('PLAID_ENVIRONMENT', 'sandbox'),
7
+    'webhook_url' => env('PLAID_WEBHOOK_URL'), // Example: https://my-static-domain.ngrok-free.app/api/plaid/webhook
7 8
 ];

+ 1
- 0
database/migrations/2023_09_03_100000_create_accounting_tables.php Целия файл

@@ -86,6 +86,7 @@ return new class extends Migration
86 86
             $table->string('type')->default(BankAccountType::DEFAULT);
87 87
             $table->string('subtype')->nullable();
88 88
             $table->boolean('import_transactions')->default(false);
89
+            $table->timestamp('last_imported_at')->nullable();
89 90
             $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
90 91
             $table->foreignId('updated_by')->nullable()->constrained('users')->nullOnDelete();
91 92
             $table->timestamps();

+ 1
- 0
database/migrations/2024_01_01_234943_create_transactions_table.php Целия файл

@@ -16,6 +16,7 @@ return new class extends Migration
16 16
             $table->foreignId('company_id')->constrained()->cascadeOnDelete();
17 17
             $table->foreignId('account_id')->nullable()->constrained()->nullOnDelete();
18 18
             $table->foreignId('bank_account_id')->nullable()->constrained()->nullOnDelete();
19
+            $table->string('plaid_transaction_id')->nullable();
19 20
             $table->foreignId('contact_id')->nullable()->constrained()->nullOnDelete();
20 21
             $table->string('type'); // deposit, withdrawal, journal
21 22
             $table->string('payment_channel')->nullable(); // online, in store, other

+ 70
- 70
package-lock.json Целия файл

@@ -507,9 +507,9 @@
507 507
             }
508 508
         },
509 509
         "node_modules/@rollup/rollup-android-arm-eabi": {
510
-            "version": "4.14.1",
511
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.1.tgz",
512
-            "integrity": "sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==",
510
+            "version": "4.14.2",
511
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.2.tgz",
512
+            "integrity": "sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==",
513 513
             "cpu": [
514 514
                 "arm"
515 515
             ],
@@ -520,9 +520,9 @@
520 520
             ]
521 521
         },
522 522
         "node_modules/@rollup/rollup-android-arm64": {
523
-            "version": "4.14.1",
524
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.1.tgz",
525
-            "integrity": "sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==",
523
+            "version": "4.14.2",
524
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.2.tgz",
525
+            "integrity": "sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==",
526 526
             "cpu": [
527 527
                 "arm64"
528 528
             ],
@@ -533,9 +533,9 @@
533 533
             ]
534 534
         },
535 535
         "node_modules/@rollup/rollup-darwin-arm64": {
536
-            "version": "4.14.1",
537
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.1.tgz",
538
-            "integrity": "sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==",
536
+            "version": "4.14.2",
537
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.2.tgz",
538
+            "integrity": "sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==",
539 539
             "cpu": [
540 540
                 "arm64"
541 541
             ],
@@ -546,9 +546,9 @@
546 546
             ]
547 547
         },
548 548
         "node_modules/@rollup/rollup-darwin-x64": {
549
-            "version": "4.14.1",
550
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.1.tgz",
551
-            "integrity": "sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==",
549
+            "version": "4.14.2",
550
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.2.tgz",
551
+            "integrity": "sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==",
552 552
             "cpu": [
553 553
                 "x64"
554 554
             ],
@@ -559,9 +559,9 @@
559 559
             ]
560 560
         },
561 561
         "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
562
-            "version": "4.14.1",
563
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.1.tgz",
564
-            "integrity": "sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==",
562
+            "version": "4.14.2",
563
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.2.tgz",
564
+            "integrity": "sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==",
565 565
             "cpu": [
566 566
                 "arm"
567 567
             ],
@@ -572,9 +572,9 @@
572 572
             ]
573 573
         },
574 574
         "node_modules/@rollup/rollup-linux-arm64-gnu": {
575
-            "version": "4.14.1",
576
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.1.tgz",
577
-            "integrity": "sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==",
575
+            "version": "4.14.2",
576
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.2.tgz",
577
+            "integrity": "sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==",
578 578
             "cpu": [
579 579
                 "arm64"
580 580
             ],
@@ -585,9 +585,9 @@
585 585
             ]
586 586
         },
587 587
         "node_modules/@rollup/rollup-linux-arm64-musl": {
588
-            "version": "4.14.1",
589
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.1.tgz",
590
-            "integrity": "sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==",
588
+            "version": "4.14.2",
589
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.2.tgz",
590
+            "integrity": "sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==",
591 591
             "cpu": [
592 592
                 "arm64"
593 593
             ],
@@ -598,11 +598,11 @@
598 598
             ]
599 599
         },
600 600
         "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
601
-            "version": "4.14.1",
602
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.1.tgz",
603
-            "integrity": "sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==",
601
+            "version": "4.14.2",
602
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.2.tgz",
603
+            "integrity": "sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==",
604 604
             "cpu": [
605
-                "ppc64le"
605
+                "ppc64"
606 606
             ],
607 607
             "dev": true,
608 608
             "optional": true,
@@ -611,9 +611,9 @@
611 611
             ]
612 612
         },
613 613
         "node_modules/@rollup/rollup-linux-riscv64-gnu": {
614
-            "version": "4.14.1",
615
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.1.tgz",
616
-            "integrity": "sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==",
614
+            "version": "4.14.2",
615
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.2.tgz",
616
+            "integrity": "sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==",
617 617
             "cpu": [
618 618
                 "riscv64"
619 619
             ],
@@ -624,9 +624,9 @@
624 624
             ]
625 625
         },
626 626
         "node_modules/@rollup/rollup-linux-s390x-gnu": {
627
-            "version": "4.14.1",
628
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.1.tgz",
629
-            "integrity": "sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==",
627
+            "version": "4.14.2",
628
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.2.tgz",
629
+            "integrity": "sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==",
630 630
             "cpu": [
631 631
                 "s390x"
632 632
             ],
@@ -637,9 +637,9 @@
637 637
             ]
638 638
         },
639 639
         "node_modules/@rollup/rollup-linux-x64-gnu": {
640
-            "version": "4.14.1",
641
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.1.tgz",
642
-            "integrity": "sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==",
640
+            "version": "4.14.2",
641
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.2.tgz",
642
+            "integrity": "sha512-QBhtr07iFGmF9egrPOWyO5wciwgtzKkYPNLVCFZTmr4TWmY0oY2Dm/bmhHjKRwZoGiaKdNcKhFtUMBKvlchH+Q==",
643 643
             "cpu": [
644 644
                 "x64"
645 645
             ],
@@ -650,9 +650,9 @@
650 650
             ]
651 651
         },
652 652
         "node_modules/@rollup/rollup-linux-x64-musl": {
653
-            "version": "4.14.1",
654
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.1.tgz",
655
-            "integrity": "sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==",
653
+            "version": "4.14.2",
654
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.2.tgz",
655
+            "integrity": "sha512-8zfsQRQGH23O6qazZSFY5jP5gt4cFvRuKTpuBsC1ZnSWxV8ZKQpPqOZIUtdfMOugCcBvFGRa1pDC/tkf19EgBw==",
656 656
             "cpu": [
657 657
                 "x64"
658 658
             ],
@@ -663,9 +663,9 @@
663 663
             ]
664 664
         },
665 665
         "node_modules/@rollup/rollup-win32-arm64-msvc": {
666
-            "version": "4.14.1",
667
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.1.tgz",
668
-            "integrity": "sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==",
666
+            "version": "4.14.2",
667
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.2.tgz",
668
+            "integrity": "sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==",
669 669
             "cpu": [
670 670
                 "arm64"
671 671
             ],
@@ -676,9 +676,9 @@
676 676
             ]
677 677
         },
678 678
         "node_modules/@rollup/rollup-win32-ia32-msvc": {
679
-            "version": "4.14.1",
680
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.1.tgz",
681
-            "integrity": "sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==",
679
+            "version": "4.14.2",
680
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.2.tgz",
681
+            "integrity": "sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==",
682 682
             "cpu": [
683 683
                 "ia32"
684 684
             ],
@@ -689,9 +689,9 @@
689 689
             ]
690 690
         },
691 691
         "node_modules/@rollup/rollup-win32-x64-msvc": {
692
-            "version": "4.14.1",
693
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.1.tgz",
694
-            "integrity": "sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==",
692
+            "version": "4.14.2",
693
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.2.tgz",
694
+            "integrity": "sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==",
695 695
             "cpu": [
696 696
                 "x64"
697 697
             ],
@@ -918,9 +918,9 @@
918 918
             }
919 919
         },
920 920
         "node_modules/caniuse-lite": {
921
-            "version": "1.0.30001608",
922
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001608.tgz",
923
-            "integrity": "sha512-cjUJTQkk9fQlJR2s4HMuPMvTiRggl0rAVMtthQuyOlDWuqHXqN8azLq+pi8B2TjwKJ32diHjUqRIKeFX4z1FoA==",
921
+            "version": "1.0.30001609",
922
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz",
923
+            "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==",
924 924
             "dev": true,
925 925
             "funding": [
926 926
                 {
@@ -1066,9 +1066,9 @@
1066 1066
             "dev": true
1067 1067
         },
1068 1068
         "node_modules/electron-to-chromium": {
1069
-            "version": "1.4.733",
1070
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.733.tgz",
1071
-            "integrity": "sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ==",
1069
+            "version": "1.4.736",
1070
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz",
1071
+            "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q==",
1072 1072
             "dev": true
1073 1073
         },
1074 1074
         "node_modules/emoji-regex": {
@@ -1997,9 +1997,9 @@
1997 1997
             }
1998 1998
         },
1999 1999
         "node_modules/rollup": {
2000
-            "version": "4.14.1",
2001
-            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.1.tgz",
2002
-            "integrity": "sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==",
2000
+            "version": "4.14.2",
2001
+            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.2.tgz",
2002
+            "integrity": "sha512-WkeoTWvuBoFjFAhsEOHKRoZ3r9GfTyhh7Vff1zwebEFLEFjT1lG3784xEgKiTa7E+e70vsC81roVL2MP4tgEEQ==",
2003 2003
             "dev": true,
2004 2004
             "dependencies": {
2005 2005
                 "@types/estree": "1.0.5"
@@ -2012,21 +2012,21 @@
2012 2012
                 "npm": ">=8.0.0"
2013 2013
             },
2014 2014
             "optionalDependencies": {
2015
-                "@rollup/rollup-android-arm-eabi": "4.14.1",
2016
-                "@rollup/rollup-android-arm64": "4.14.1",
2017
-                "@rollup/rollup-darwin-arm64": "4.14.1",
2018
-                "@rollup/rollup-darwin-x64": "4.14.1",
2019
-                "@rollup/rollup-linux-arm-gnueabihf": "4.14.1",
2020
-                "@rollup/rollup-linux-arm64-gnu": "4.14.1",
2021
-                "@rollup/rollup-linux-arm64-musl": "4.14.1",
2022
-                "@rollup/rollup-linux-powerpc64le-gnu": "4.14.1",
2023
-                "@rollup/rollup-linux-riscv64-gnu": "4.14.1",
2024
-                "@rollup/rollup-linux-s390x-gnu": "4.14.1",
2025
-                "@rollup/rollup-linux-x64-gnu": "4.14.1",
2026
-                "@rollup/rollup-linux-x64-musl": "4.14.1",
2027
-                "@rollup/rollup-win32-arm64-msvc": "4.14.1",
2028
-                "@rollup/rollup-win32-ia32-msvc": "4.14.1",
2029
-                "@rollup/rollup-win32-x64-msvc": "4.14.1",
2015
+                "@rollup/rollup-android-arm-eabi": "4.14.2",
2016
+                "@rollup/rollup-android-arm64": "4.14.2",
2017
+                "@rollup/rollup-darwin-arm64": "4.14.2",
2018
+                "@rollup/rollup-darwin-x64": "4.14.2",
2019
+                "@rollup/rollup-linux-arm-gnueabihf": "4.14.2",
2020
+                "@rollup/rollup-linux-arm64-gnu": "4.14.2",
2021
+                "@rollup/rollup-linux-arm64-musl": "4.14.2",
2022
+                "@rollup/rollup-linux-powerpc64le-gnu": "4.14.2",
2023
+                "@rollup/rollup-linux-riscv64-gnu": "4.14.2",
2024
+                "@rollup/rollup-linux-s390x-gnu": "4.14.2",
2025
+                "@rollup/rollup-linux-x64-gnu": "4.14.2",
2026
+                "@rollup/rollup-linux-x64-musl": "4.14.2",
2027
+                "@rollup/rollup-win32-arm64-msvc": "4.14.2",
2028
+                "@rollup/rollup-win32-ia32-msvc": "4.14.2",
2029
+                "@rollup/rollup-win32-x64-msvc": "4.14.2",
2030 2030
                 "fsevents": "~2.3.2"
2031 2031
             }
2032 2032
         },

+ 2
- 2
resources/views/livewire/company/service/connected-account/list-institutions.blade.php Целия файл

@@ -19,9 +19,9 @@
19 19
                             {{ $institution->name }}
20 20
                         </h3>
21 21
 
22
-                        @if($institution->getLastTransactionDate())
22
+                        @if($institution->getLastImportDate())
23 23
                             <p class="connected-account-section-header-description text-sm leading-6 text-gray-500 dark:text-gray-400">
24
-                                {{ __('Last updated') }} {{ $institution->getLastTransactionDate() }}
24
+                                {{ __('Last updated') }} {{ $institution->getLastImportDate() }}
25 25
                             </p>
26 26
                         @endif
27 27
                     </div>

+ 3
- 0
routes/api.php Целия файл

@@ -1,8 +1,11 @@
1 1
 <?php
2 2
 
3
+use App\Http\Controllers\PlaidWebhookController;
3 4
 use Illuminate\Http\Request;
4 5
 use Illuminate\Support\Facades\Route;
5 6
 
6 7
 Route::get('/user', function (Request $request) {
7 8
     return $request->user();
8 9
 })->middleware('auth:sanctum');
10
+
11
+Route::post('/plaid/webhook', [PlaidWebhookController::class, 'handleWebhook']);

Loading…
Отказ
Запис