chore: upgrade Laravel 12 to 13 (#242)
## Summary - Upgrade `laravel/framework` from v12 to **v13.1.1** and update all 52 dependencies to their latest versions - Bump `laravel/tinker` from v2 to **v3.0** (required for Laravel 13 compatibility) - Address Laravel 13 breaking change: add `serializable_classes => false` to `config/cache.php` - Fix cached `Collection` in `routes/web.php` — converted to plain array via `->toArray()` for serialization safety ## Changes | File | What changed | |------|-------------| | `composer.json` | Bumped `php ^8.3`, `laravel/framework ^13.0`, `laravel/tinker ^3.0` | | `composer.lock` | 52 packages updated, 1 removed (`symfony/polyfill-php83`) | | `config/cache.php` | Added `serializable_classes => false` | | `routes/web.php` | Cached query result uses `->toArray()`, fallback changed from `collect()` to `[]` | ## Testing Full test suite passing: **919 tests, 3792 assertions, 0 failures**
This commit is contained in:
parent
973243277a
commit
1880333b1c
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Actions\Fortify;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
|
||||
trait PasswordValidationRules
|
||||
|
|
@ -9,7 +10,7 @@ trait PasswordValidationRules
|
|||
/**
|
||||
* Get the validation rules used to validate passwords.
|
||||
*
|
||||
* @return array<int, \Illuminate\Contracts\Validation\Rule|array<mixed>|string>
|
||||
* @return array<int, Rule|array<mixed>|string>
|
||||
*/
|
||||
protected function passwordRules(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class SyncStripePricesCommand extends Command
|
|||
}
|
||||
|
||||
/**
|
||||
* @return \Stripe\Price|null
|
||||
* @return Price|null
|
||||
*/
|
||||
private function findPriceByLookupKey(string $lookupKey): mixed
|
||||
{
|
||||
|
|
@ -138,7 +138,7 @@ class SyncStripePricesCommand extends Command
|
|||
}
|
||||
|
||||
/**
|
||||
* @param \Stripe\Price $price
|
||||
* @param Price $price
|
||||
*/
|
||||
private function priceMatches(mixed $price, int $amountInCents, string $currency, ?string $billingPeriod): bool
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use App\Models\Account;
|
||||
use App\Models\AccountBalance;
|
||||
use App\Services\AccountMetricsService;
|
||||
|
|
@ -41,7 +42,7 @@ class AccountController extends Controller
|
|||
|
||||
$data = $account->only(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code', 'banking_connection_id', 'bank']);
|
||||
|
||||
if ($account->type === \App\Enums\AccountType::RealEstate) {
|
||||
if ($account->type === AccountType::RealEstate) {
|
||||
$account->load('realEstateDetail.linkedLoanAccount.bank:id,name,logo');
|
||||
$realEstateDetail = $account->realEstateDetail;
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ class AccountController extends Controller
|
|||
// Provide available loan accounts for linking
|
||||
$data['available_loan_accounts'] = $request->user()
|
||||
->accounts()
|
||||
->where('type', \App\Enums\AccountType::Loan->value)
|
||||
->where('type', AccountType::Loan->value)
|
||||
->with('bank:id,name,logo')
|
||||
->get(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code']);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use App\Enums\CategoryType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Account;
|
||||
|
|
@ -356,7 +357,7 @@ class DashboardAnalyticsController extends Controller
|
|||
*/
|
||||
private function getLinkedLoanAccountId(Account $account): ?string
|
||||
{
|
||||
if ($account->type !== \App\Enums\AccountType::RealEstate) {
|
||||
if ($account->type !== AccountType::RealEstate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@ namespace App\Http\Controllers;
|
|||
use App\Http\Requests\StoreBudgetRequest;
|
||||
use App\Http\Requests\UpdateBudgetRequest;
|
||||
use App\Jobs\AssignHistoricalTransactionsToBudget;
|
||||
use App\Models\Account;
|
||||
use App\Models\Bank;
|
||||
use App\Models\Budget;
|
||||
use App\Models\Category;
|
||||
use App\Services\BudgetPeriodService;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Inertia\Inertia;
|
||||
|
|
@ -78,18 +82,18 @@ class BudgetController extends Controller
|
|||
|
||||
$budget->load(['category', 'label']);
|
||||
|
||||
$categories = \App\Models\Category::query()
|
||||
$categories = Category::query()
|
||||
->where('user_id', $user->id)
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'icon', 'color']);
|
||||
|
||||
$accounts = \App\Models\Account::query()
|
||||
$accounts = Account::query()
|
||||
->where('user_id', $user->id)
|
||||
->with('bank:id,name,logo')
|
||||
->orderBy('name')
|
||||
->get(['id', 'name', 'name_iv', 'encrypted', 'bank_id', 'type', 'currency_code']);
|
||||
|
||||
$banks = \App\Models\Bank::query()
|
||||
$banks = Bank::query()
|
||||
->where(function ($q) use ($user) {
|
||||
$q->whereNull('user_id')
|
||||
->orWhere('user_id', $user->id);
|
||||
|
|
@ -109,7 +113,7 @@ class BudgetController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
public function store(StoreBudgetRequest $request): \Illuminate\Http\RedirectResponse
|
||||
public function store(StoreBudgetRequest $request): RedirectResponse
|
||||
{
|
||||
$result = DB::transaction(function () use ($request) {
|
||||
$budget = $request->user()->budgets()->create([
|
||||
|
|
@ -133,7 +137,7 @@ class BudgetController extends Controller
|
|||
return redirect()->route('budgets.show', $result['budget']);
|
||||
}
|
||||
|
||||
public function update(UpdateBudgetRequest $request, Budget $budget): \Illuminate\Http\RedirectResponse
|
||||
public function update(UpdateBudgetRequest $request, Budget $budget): RedirectResponse
|
||||
{
|
||||
$this->authorize('update', $budget);
|
||||
|
||||
|
|
@ -159,7 +163,7 @@ class BudgetController extends Controller
|
|||
return redirect()->route('budgets.show', $budget);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, Budget $budget): \Illuminate\Http\RedirectResponse
|
||||
public function destroy(Request $request, Budget $budget): RedirectResponse
|
||||
{
|
||||
$this->authorize('delete', $budget);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Controllers\Settings;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Settings\StoreAccountRequest;
|
||||
use App\Http\Requests\Settings\UpdateAccountRequest;
|
||||
|
|
@ -59,7 +60,7 @@ class AccountController extends Controller
|
|||
}
|
||||
|
||||
// Create real estate detail if account type is real_estate
|
||||
if ($account->type === \App\Enums\AccountType::RealEstate) {
|
||||
if ($account->type === AccountType::RealEstate) {
|
||||
$realEstateData = collect($validated)->only([
|
||||
'property_type', 'address', 'purchase_price', 'purchase_date',
|
||||
'area_value', 'area_unit', 'linked_loan_account_id', 'notes',
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class ActivateDevelopmentFeatures
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class EnsureOnboardingComplete
|
|||
* Redirects non-onboarded users to the onboarding flow.
|
||||
* Redirects onboarded users away from the onboarding page.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class EnsureOpenBankingFeature
|
|||
*
|
||||
* Returns 404 if user doesn't have open-banking feature enabled.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use Symfony\Component\HttpFoundation\Response;
|
|||
class EnsureUserIsSubscribed
|
||||
{
|
||||
/**
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class HandleAppearance
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class SetLocale
|
|||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @param Closure(Request): (Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests\Settings;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Laravel\Fortify\Features;
|
||||
use Laravel\Fortify\InteractsWithTwoFactorState;
|
||||
|
|
@ -21,7 +22,7 @@ class TwoFactorAuthenticationRequest extends FormRequest
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Requests\Settings;
|
||||
|
||||
use App\Enums\ChartColorScheme;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
|
|
@ -11,7 +12,7 @@ class UpdateChartColorSchemeRequest extends FormRequest
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests\Settings;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateNetWorthChartLoanPreferenceRequest extends FormRequest
|
||||
|
|
@ -17,7 +18,7 @@ class UpdateNetWorthChartLoanPreferenceRequest extends FormRequest
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests\Settings;
|
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateNetWorthChartRealEstatePreferenceRequest extends FormRequest
|
||||
|
|
@ -17,7 +18,7 @@ class UpdateNetWorthChartRealEstatePreferenceRequest extends FormRequest
|
|||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
* @return array<string, ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\UserLead;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -60,7 +61,7 @@ class UserLeadInvitation extends Mailable implements ShouldQueue
|
|||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
* @return array<int, Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -66,7 +67,7 @@ class WaitlistOvertaken extends Mailable implements ShouldQueue
|
|||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
* @return array<int, Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -66,7 +67,7 @@ class WaitlistReferralNotification extends Mailable implements ShouldQueue
|
|||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
* @return array<int, Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Illuminate\Bus\Queueable;
|
|||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Attachment;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -67,7 +68,7 @@ class WaitlistWelcome extends Mailable implements ShouldQueue
|
|||
/**
|
||||
* Get the attachments for the message.
|
||||
*
|
||||
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||
* @return array<int, Attachment>
|
||||
*/
|
||||
public function attachments(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use Database\Factories\AccountFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -12,11 +13,11 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
|
|||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property \App\Enums\AccountType $type
|
||||
* @property AccountType $type
|
||||
*/
|
||||
class Account extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\AccountFactory> */
|
||||
/** @use HasFactory<AccountFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -2,17 +2,19 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Database\Factories\AccountBalanceFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property \Carbon\Carbon $balance_date
|
||||
* @property Carbon $balance_date
|
||||
*/
|
||||
class AccountBalance extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\AccountBalanceFactory> */
|
||||
/** @use HasFactory<AccountBalanceFactory> */
|
||||
use HasFactory, HasUuids;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\AutomationRuleFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -11,7 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
|
||||
class AutomationRule extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\AutomationRuleFactory> */
|
||||
/** @use HasFactory<AutomationRuleFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\BankFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -11,7 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
|
||||
class Bank extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\BankFactory> */
|
||||
/** @use HasFactory<BankFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Enums\BankingConnectionStatus;
|
||||
use Carbon\Carbon;
|
||||
use Database\Factories\BankingConnectionFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -12,14 +14,14 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
|
||||
/**
|
||||
* @property bool $has_pending_accounts
|
||||
* @property \App\Enums\BankingConnectionStatus $status
|
||||
* @property \Carbon\Carbon|null $valid_until
|
||||
* @property \Carbon\Carbon|null $last_synced_at
|
||||
* @property BankingConnectionStatus $status
|
||||
* @property Carbon|null $valid_until
|
||||
* @property Carbon|null $last_synced_at
|
||||
* @property array<int, mixed>|null $pending_accounts_data
|
||||
*/
|
||||
class BankingConnection extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\BankingConnectionFactory> */
|
||||
/** @use HasFactory<BankingConnectionFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property \App\Enums\RolloverType $rollover_type
|
||||
* @property \App\Enums\BudgetPeriodType $period_type
|
||||
* @property RolloverType $rollover_type
|
||||
* @property BudgetPeriodType $period_type
|
||||
*/
|
||||
class Budget extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -9,8 +10,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
/**
|
||||
* @property \Carbon\Carbon $start_date
|
||||
* @property \Carbon\Carbon $end_date
|
||||
* @property Carbon $start_date
|
||||
* @property Carbon $end_date
|
||||
*/
|
||||
class BudgetPeriod extends Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use App\Enums\CategoryCashflowDirection;
|
||||
use App\Enums\CategoryType;
|
||||
use Database\Factories\CategoryFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -13,7 +14,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
|
||||
class Category extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\CategoryFactory> */
|
||||
/** @use HasFactory<CategoryFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\ExchangeRateFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ use Illuminate\Database\Eloquent\Model;
|
|||
*/
|
||||
class ExchangeRate extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\ExchangeRateFactory> */
|
||||
/** @use HasFactory<ExchangeRateFactory> */
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\LabelFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -11,7 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
|
||||
class Label extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\LabelFactory> */
|
||||
/** @use HasFactory<LabelFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -3,18 +3,19 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Enums\PropertyType;
|
||||
use Database\Factories\RealEstateDetailFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property \App\Enums\PropertyType $property_type
|
||||
* @property PropertyType $property_type
|
||||
* @property int|null $purchase_price
|
||||
*/
|
||||
class RealEstateDetail extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\RealEstateDetailFactory> */
|
||||
/** @use HasFactory<RealEstateDetailFactory> */
|
||||
use HasFactory, HasUuids;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use App\Enums\TransactionSource;
|
|||
use App\Events\TransactionCreated;
|
||||
use App\Events\TransactionDeleted;
|
||||
use App\Events\TransactionUpdated;
|
||||
use Carbon\Carbon;
|
||||
use Database\Factories\TransactionFactory;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
|
@ -16,12 +18,12 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property \Carbon\Carbon $transaction_date
|
||||
* @property Carbon $transaction_date
|
||||
* @property int|float $total_amount
|
||||
*/
|
||||
class Transaction extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\TransactionFactory> */
|
||||
/** @use HasFactory<TransactionFactory> */
|
||||
use HasFactory, HasUuids, SoftDeletes;
|
||||
|
||||
/** @var array<string, class-string> */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use App\Enums\DripEmailType;
|
||||
use App\Notifications\VerifyEmailNotification;
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Contracts\Translation\HasLocalePreference;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
|
@ -19,7 +20,7 @@ use Laravel\Pennant\Concerns\HasFeatures;
|
|||
|
||||
class User extends Authenticatable implements HasLocalePreference, MustVerifyEmail
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use Billable, HasFactory, HasFeatures, HasUuids, Notifiable, TwoFactorAuthenticatable;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\UserLeadFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
|
@ -11,7 +12,7 @@ use Illuminate\Support\Str;
|
|||
|
||||
class UserLead extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserLeadFactory> */
|
||||
/** @use HasFactory<UserLeadFactory> */
|
||||
use HasFactory, HasUuids;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -3,19 +3,20 @@
|
|||
namespace App\Models;
|
||||
|
||||
use App\Enums\ChartColorScheme;
|
||||
use Database\Factories\UserSettingFactory;
|
||||
use Illuminate\Database\Eloquent\Concerns\HasUuids;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* @property \App\Enums\ChartColorScheme $chart_color_scheme
|
||||
* @property ChartColorScheme $chart_color_scheme
|
||||
* @property bool $include_loans_in_net_worth_chart
|
||||
* @property bool $include_real_estate_in_net_worth_chart
|
||||
*/
|
||||
class UserSetting extends Model
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserSettingFactory> */
|
||||
/** @use HasFactory<UserSettingFactory> */
|
||||
use HasFactory, HasUuids;
|
||||
|
||||
protected $fillable = [
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Services\Banking;
|
|||
|
||||
use App\Contracts\BankingProviderInterface;
|
||||
use App\Models\Account;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BalanceSyncService
|
||||
|
|
@ -69,7 +70,7 @@ class BalanceSyncService
|
|||
|
||||
$existingDates = $account->balances()
|
||||
->pluck('balance_date')
|
||||
->map(fn (mixed $date) => $date instanceof \Carbon\Carbon ? $date->toDateString() : (string) $date)
|
||||
->map(fn (mixed $date) => $date instanceof Carbon ? $date->toDateString() : (string) $date)
|
||||
->flip()
|
||||
->all();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Middleware\ActivateDevelopmentFeatures;
|
||||
use App\Http\Middleware\BlockDemoAccountActions;
|
||||
use App\Http\Middleware\EnsureOnboardingComplete;
|
||||
use App\Http\Middleware\EnsureOpenBankingFeature;
|
||||
use App\Http\Middleware\EnsureUserIsSubscribed;
|
||||
use App\Http\Middleware\HandleAppearance;
|
||||
|
|
@ -35,14 +37,14 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||
SetLocale::class,
|
||||
HandleInertiaRequests::class,
|
||||
AddLinkHeadersForPreloadedAssets::class,
|
||||
\App\Http\Middleware\BlockDemoAccountActions::class.':auto',
|
||||
BlockDemoAccountActions::class.':auto',
|
||||
ActivateDevelopmentFeatures::class,
|
||||
]);
|
||||
|
||||
$middleware->alias([
|
||||
'subscribed' => EnsureUserIsSubscribed::class,
|
||||
'onboarded' => \App\Http\Middleware\EnsureOnboardingComplete::class,
|
||||
'block-demo' => \App\Http\Middleware\BlockDemoAccountActions::class,
|
||||
'onboarded' => EnsureOnboardingComplete::class,
|
||||
'block-demo' => BlockDemoAccountActions::class,
|
||||
'open-banking' => EnsureOpenBankingFeature::class,
|
||||
]);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
<?php
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
use App\Providers\FortifyServiceProvider;
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\FortifyServiceProvider::class,
|
||||
AppServiceProvider::class,
|
||||
FortifyServiceProvider::class,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"php": "^8.3",
|
||||
"firebase/php-jwt": "^7.0",
|
||||
"inertiajs/inertia-laravel": "^2.0",
|
||||
"intervention/image": "^3.0",
|
||||
"jwadhams/json-logic-php": "^1.5",
|
||||
"laravel/cashier": "^16.1",
|
||||
"laravel/fortify": "^1.30",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/framework": "^13.0",
|
||||
"laravel/pennant": "^1.18",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"laravel/tinker": "^3.0",
|
||||
"laravel/wayfinder": "^0.1.9",
|
||||
"resend/resend-php": "^1.1",
|
||||
"sentry/sentry-laravel": "^4.20"
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|
|
@ -62,7 +64,7 @@ return [
|
|||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
'model' => env('AUTH_MODEL', User::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
|
|
|
|||
|
|
@ -114,4 +114,17 @@ return [
|
|||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug((string) env('APP_NAME', 'laravel')).'-cache-'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Serializable Classes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the classes that can be unserialized from cache
|
||||
| storage. By default, no PHP classes will be unserialized from your
|
||||
| cache to prevent gadget chain attacks if your APP_KEY is leaked.
|
||||
|
|
||||
*/
|
||||
|
||||
'serializable_classes' => false,
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\AccountBalance;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\AccountBalance>
|
||||
* @extends Factory<AccountBalance>
|
||||
*/
|
||||
class AccountBalanceFactory extends Factory
|
||||
{
|
||||
|
|
@ -17,7 +19,7 @@ class AccountBalanceFactory extends Factory
|
|||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'account_id' => \App\Models\Account::factory(),
|
||||
'account_id' => Account::factory(),
|
||||
'balance_date' => fake()->date(),
|
||||
'balance' => fake()->numberBetween(100000, 10000000),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\AccountType;
|
||||
use App\Models\Account;
|
||||
use App\Models\Bank;
|
||||
use App\Models\BankingConnection;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Account>
|
||||
* @extends Factory<Account>
|
||||
*/
|
||||
class AccountFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\AutomationRule;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\AutomationRule>
|
||||
* @extends Factory<AutomationRule>
|
||||
*/
|
||||
class AutomationRuleFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Bank;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Bank>
|
||||
* @extends Factory<Bank>
|
||||
*/
|
||||
class BankFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\BankingConnectionStatus;
|
||||
use App\Models\BankingConnection;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\BankingConnection>
|
||||
* @extends Factory<BankingConnection>
|
||||
*/
|
||||
class BankingConnectionFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\BudgetPeriodType;
|
||||
use App\Models\Budget;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Budget>
|
||||
* @extends Factory<Budget>
|
||||
*/
|
||||
class BudgetFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Budget;
|
||||
use App\Models\BudgetPeriod;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\BudgetPeriod>
|
||||
* @extends Factory<BudgetPeriod>
|
||||
*/
|
||||
class BudgetPeriodFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Models\BudgetPeriodAllocation;
|
||||
use App\Models\BudgetTransaction;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\BudgetTransaction>
|
||||
* @extends Factory<BudgetTransaction>
|
||||
*/
|
||||
class BudgetTransactionFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ namespace Database\Factories;
|
|||
|
||||
use App\Enums\CategoryCashflowDirection;
|
||||
use App\Enums\CategoryType;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
|
||||
* @extends Factory<Category>
|
||||
*/
|
||||
class CategoryFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\ExchangeRate;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ExchangeRate>
|
||||
* @extends Factory<ExchangeRate>
|
||||
*/
|
||||
class ExchangeRateFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Label;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Label>
|
||||
* @extends Factory<Label>
|
||||
*/
|
||||
class LabelFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ namespace Database\Factories;
|
|||
use App\Enums\AccountType;
|
||||
use App\Enums\PropertyType;
|
||||
use App\Models\Account;
|
||||
use App\Models\RealEstateDetail;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\RealEstateDetail>
|
||||
* @extends Factory<RealEstateDetail>
|
||||
*/
|
||||
class RealEstateDetailFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ namespace Database\Factories;
|
|||
use App\Enums\TransactionSource;
|
||||
use App\Models\Account;
|
||||
use App\Models\Category;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Transaction>
|
||||
* @extends Factory<Transaction>
|
||||
*/
|
||||
class TransactionFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
* @extends Factory<User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\UserLead;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\UserLead>
|
||||
* @extends Factory<UserLead>
|
||||
*/
|
||||
class UserLeadFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ namespace Database\Factories;
|
|||
|
||||
use App\Enums\DripEmailType;
|
||||
use App\Models\User;
|
||||
use App\Models\UserMailLog;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\UserMailLog>
|
||||
* @extends Factory<UserMailLog>
|
||||
*/
|
||||
class UserMailLogFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ namespace Database\Factories;
|
|||
|
||||
use App\Enums\ChartColorScheme;
|
||||
use App\Models\User;
|
||||
use App\Models\UserSetting;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\UserSetting>
|
||||
* @extends Factory<UserSetting>
|
||||
*/
|
||||
class UserSettingFactory extends Factory
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,15 +90,15 @@
|
|||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.87 0 0);
|
||||
--chart-1: var(--color-zinc-800);
|
||||
--chart-2: var(--color-zinc-600);
|
||||
--chart-3: var(--color-zinc-500);
|
||||
--chart-4: var(--color-zinc-400);
|
||||
--chart-5: var(--color-zinc-700);
|
||||
--chart-6: var(--color-zinc-300);
|
||||
--chart-7: var(--color-zinc-200);
|
||||
--chart-8: var(--color-zinc-100);
|
||||
--chart-9: var(--color-zinc-800);
|
||||
--chart-1: var(--color-zinc-900);
|
||||
--chart-2: var(--color-zinc-800);
|
||||
--chart-3: var(--color-zinc-700);
|
||||
--chart-4: var(--color-zinc-600);
|
||||
--chart-5: var(--color-zinc-500);
|
||||
--chart-6: var(--color-zinc-400);
|
||||
--chart-7: var(--color-zinc-300);
|
||||
--chart-8: var(--color-zinc-200);
|
||||
--chart-9: var(--color-zinc-100);
|
||||
--chart-10: var(--color-zinc-50);
|
||||
--spent: var(--color-zinc-800);
|
||||
--allocated: var(--color-zinc-200);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use App\Http\Controllers\OpenBanking\ConnectionController;
|
||||
use App\Http\Controllers\Settings\AccountController;
|
||||
use App\Http\Controllers\Settings\AutomationRuleController;
|
||||
use App\Http\Controllers\Settings\BankController;
|
||||
use App\Http\Controllers\Settings\CategoryController;
|
||||
use App\Http\Controllers\Settings\ChartColorSchemeController;
|
||||
|
|
@ -51,10 +52,10 @@ Route::middleware('auth')->group(function () {
|
|||
|
||||
Route::redirect('settings/budgets', '/budgets')->name('budgets.settings');
|
||||
|
||||
Route::get('settings/automation-rules', [\App\Http\Controllers\Settings\AutomationRuleController::class, 'index'])->name('automation-rules.index');
|
||||
Route::post('settings/automation-rules', [\App\Http\Controllers\Settings\AutomationRuleController::class, 'store'])->name('automation-rules.store');
|
||||
Route::patch('settings/automation-rules/{automationRule}', [\App\Http\Controllers\Settings\AutomationRuleController::class, 'update'])->name('automation-rules.update');
|
||||
Route::delete('settings/automation-rules/{automationRule}', [\App\Http\Controllers\Settings\AutomationRuleController::class, 'destroy'])->name('automation-rules.destroy');
|
||||
Route::get('settings/automation-rules', [AutomationRuleController::class, 'index'])->name('automation-rules.index');
|
||||
Route::post('settings/automation-rules', [AutomationRuleController::class, 'store'])->name('automation-rules.store');
|
||||
Route::patch('settings/automation-rules/{automationRule}', [AutomationRuleController::class, 'update'])->name('automation-rules.update');
|
||||
Route::delete('settings/automation-rules/{automationRule}', [AutomationRuleController::class, 'destroy'])->name('automation-rules.destroy');
|
||||
|
||||
Route::get('settings/appearance', function () {
|
||||
return Inertia::render('settings/appearance');
|
||||
|
|
|
|||
|
|
@ -50,9 +50,10 @@ Route::get('/', function () {
|
|||
'name' => $bank->name,
|
||||
'logo' => $bank->logo,
|
||||
])
|
||||
->values();
|
||||
->values()
|
||||
->toArray();
|
||||
})
|
||||
: collect();
|
||||
: [];
|
||||
|
||||
return Inertia::render('welcome', [
|
||||
'canRegister' => Features::enabled(Features::registration()),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\Bank;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ it('can open add transaction dialog', function () {
|
|||
|
||||
it('can create a transaction', function () {
|
||||
$user = User::factory()->onboarded()->create();
|
||||
$bank = \App\Models\Bank::factory()->create(['name' => 'Test Bank']);
|
||||
$bank = Bank::factory()->create(['name' => 'Test Bank']);
|
||||
|
||||
actingAs($user);
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ test('continues and reports failure when api call throws a non-404 error', funct
|
|||
$mockProvider = Mockery::mock(BankingProviderInterface::class);
|
||||
$mockProvider->shouldReceive('getAccount')
|
||||
->once()
|
||||
->andThrow(new \RuntimeException('API unavailable'));
|
||||
->andThrow(new RuntimeException('API unavailable'));
|
||||
|
||||
$this->app->instance(BankingProviderInterface::class, $mockProvider);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ use App\Models\Transaction;
|
|||
use App\Models\User;
|
||||
use App\Services\Banking\BalanceSyncService;
|
||||
use App\Services\Banking\TransactionSyncService;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Illuminate\Contracts\Queue\Job;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
|
|
@ -646,7 +649,7 @@ test('sends auth failed email on final retry for indexa capital 401 error', func
|
|||
|
||||
// Simulate final attempt (3 of 3) - SHOULD send email
|
||||
$job = new SyncBankingConnectionJob($connection);
|
||||
$mockQueueJob = Mockery::mock(\Illuminate\Contracts\Queue\Job::class);
|
||||
$mockQueueJob = Mockery::mock(Job::class);
|
||||
$mockQueueJob->shouldReceive('attempts')->andReturn(3);
|
||||
$mockQueueJob->shouldReceive('isReleased')->andReturn(false);
|
||||
$mockQueueJob->shouldReceive('isDeletedOrReleased')->andReturn(false);
|
||||
|
|
@ -660,9 +663,9 @@ test('sends auth failed email on final retry for indexa capital 401 error', func
|
|||
|
||||
try {
|
||||
$job->handle($transactionSync, $balanceSync);
|
||||
} catch (\Throwable $e) {
|
||||
} catch (Throwable $e) {
|
||||
$threw = true;
|
||||
expect($e)->toBeInstanceOf(\Illuminate\Http\Client\RequestException::class);
|
||||
expect($e)->toBeInstanceOf(RequestException::class);
|
||||
expect($e->response->status())->toBe(401);
|
||||
}
|
||||
|
||||
|
|
@ -698,7 +701,7 @@ test('does not send auth failed email before final retry attempt', function () {
|
|||
|
||||
// Simulate attempt 1 of 3 - should NOT send email
|
||||
$job = new SyncBankingConnectionJob($connection);
|
||||
$job->job = Mockery::mock(\Illuminate\Contracts\Queue\Job::class);
|
||||
$job->job = Mockery::mock(Job::class);
|
||||
$job->job->shouldReceive('attempts')->andReturn(1);
|
||||
$job->job->shouldReceive('isReleased')->andReturn(false);
|
||||
$job->job->shouldReceive('isDeletedOrReleased')->andReturn(false);
|
||||
|
|
@ -706,7 +709,7 @@ test('does not send auth failed email before final retry attempt', function () {
|
|||
|
||||
try {
|
||||
$job->handle($transactionSync, $balanceSync);
|
||||
} catch (\Throwable) {
|
||||
} catch (Throwable) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
|
|
@ -735,7 +738,7 @@ test('does not send auth failed email for non-auth errors', function () {
|
|||
$balanceSync = Mockery::mock(BalanceSyncService::class);
|
||||
|
||||
$job = new SyncBankingConnectionJob($connection);
|
||||
$job->job = Mockery::mock(\Illuminate\Contracts\Queue\Job::class);
|
||||
$job->job = Mockery::mock(Job::class);
|
||||
$job->job->shouldReceive('attempts')->andReturn(3);
|
||||
$job->job->shouldReceive('isReleased')->andReturn(false);
|
||||
$job->job->shouldReceive('isDeletedOrReleased')->andReturn(false);
|
||||
|
|
@ -743,7 +746,7 @@ test('does not send auth failed email for non-auth errors', function () {
|
|||
|
||||
try {
|
||||
$job->handle($transactionSync, $balanceSync);
|
||||
} catch (\Throwable) {
|
||||
} catch (Throwable) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
|
|
@ -768,12 +771,12 @@ test('does not send auth failed email for enablebanking connections', function (
|
|||
// For EnableBanking, even if the job throws, it should NOT send the auth failed email
|
||||
// because isApiKeyProvider() returns false for enablebanking.
|
||||
$transactionSync = Mockery::mock(TransactionSyncService::class);
|
||||
$transactionSync->shouldReceive('sync')->andThrow(new \RuntimeException('Auth error'));
|
||||
$transactionSync->shouldReceive('sync')->andThrow(new RuntimeException('Auth error'));
|
||||
|
||||
$balanceSync = Mockery::mock(BalanceSyncService::class);
|
||||
|
||||
$job = new SyncBankingConnectionJob($connection);
|
||||
$job->job = Mockery::mock(\Illuminate\Contracts\Queue\Job::class);
|
||||
$job->job = Mockery::mock(Job::class);
|
||||
$job->job->shouldReceive('attempts')->andReturn(3);
|
||||
$job->job->shouldReceive('isReleased')->andReturn(false);
|
||||
$job->job->shouldReceive('isDeletedOrReleased')->andReturn(false);
|
||||
|
|
@ -781,7 +784,7 @@ test('does not send auth failed email for enablebanking connections', function (
|
|||
|
||||
try {
|
||||
$job->handle($transactionSync, $balanceSync);
|
||||
} catch (\RuntimeException) {
|
||||
} catch (RuntimeException) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
|
|
@ -811,7 +814,7 @@ test('sends auth failed email for binance 403 error on final attempt', function
|
|||
$balanceSync = Mockery::mock(BalanceSyncService::class);
|
||||
|
||||
$job = new SyncBankingConnectionJob($connection);
|
||||
$job->job = Mockery::mock(\Illuminate\Contracts\Queue\Job::class);
|
||||
$job->job = Mockery::mock(Job::class);
|
||||
$job->job->shouldReceive('attempts')->andReturn(3);
|
||||
$job->job->shouldReceive('isReleased')->andReturn(false);
|
||||
$job->job->shouldReceive('isDeletedOrReleased')->andReturn(false);
|
||||
|
|
@ -819,7 +822,7 @@ test('sends auth failed email for binance 403 error on final attempt', function
|
|||
|
||||
try {
|
||||
$job->handle($transactionSync, $balanceSync);
|
||||
} catch (\Throwable) {
|
||||
} catch (Throwable) {
|
||||
// Expected
|
||||
}
|
||||
|
||||
|
|
@ -843,9 +846,9 @@ test('rate limit error does not set connection status to error', function () {
|
|||
|
||||
$transactionSync = Mockery::mock(TransactionSyncService::class);
|
||||
$transactionSync->shouldReceive('sync')->andThrow(
|
||||
new \Illuminate\Http\Client\RequestException(
|
||||
new \Illuminate\Http\Client\Response(
|
||||
new \GuzzleHttp\Psr7\Response(429)
|
||||
new RequestException(
|
||||
new Illuminate\Http\Client\Response(
|
||||
new Response(429)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
use App\Enums\BankingConnectionStatus;
|
||||
use App\Jobs\SyncBinanceHistoricalBalancesJob;
|
||||
use App\Models\Account;
|
||||
use App\Models\BankingConnection;
|
||||
|
|
@ -87,7 +88,7 @@ test('failed method logs error but does not update connection status', function
|
|||
$job->failed(new RuntimeException('API rate limit'));
|
||||
|
||||
$connection->refresh();
|
||||
expect($connection->status)->toBe(\App\Enums\BankingConnectionStatus::Active);
|
||||
expect($connection->status)->toBe(BankingConnectionStatus::Active);
|
||||
});
|
||||
|
||||
test('uniqueId returns account-based identifier', function () {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use App\Models\Category;
|
|||
use App\Models\Label;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\User;
|
||||
use App\Services\AutomationRuleService;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
|
||||
|
|
@ -281,7 +282,7 @@ test('job applies rules to non-encrypted transactions and tracks progress', func
|
|||
|
||||
$jobId = 'test-job-'.uniqid();
|
||||
$job = new ReEvaluateTransactionRulesJob($this->user, $jobId);
|
||||
$job->handle(app(\App\Services\AutomationRuleService::class));
|
||||
$job->handle(app(AutomationRuleService::class));
|
||||
|
||||
expect($matchingTransaction->fresh()->category_id)->toBe($this->category->id);
|
||||
expect($nonMatchingTransaction->fresh()->category_id)->toBeNull();
|
||||
|
|
@ -311,7 +312,7 @@ test('job skips encrypted transactions', function () {
|
|||
|
||||
$jobId = 'test-job-'.uniqid();
|
||||
$job = new ReEvaluateTransactionRulesJob($this->user, $jobId);
|
||||
$job->handle(app(\App\Services\AutomationRuleService::class));
|
||||
$job->handle(app(AutomationRuleService::class));
|
||||
|
||||
$progress = Cache::get(ReEvaluateTransactionRulesJob::cacheKeyForJobId($jobId));
|
||||
// 0 processed because the encrypted transaction is excluded from the query
|
||||
|
|
@ -346,7 +347,7 @@ test('job only processes provided transaction_ids', function () {
|
|||
|
||||
$jobId = 'test-job-'.uniqid();
|
||||
$job = new ReEvaluateTransactionRulesJob($this->user, $jobId, [$t1->id]);
|
||||
$job->handle(app(\App\Services\AutomationRuleService::class));
|
||||
$job->handle(app(AutomationRuleService::class));
|
||||
|
||||
expect($t1->fresh()->category_id)->toBe($this->category->id);
|
||||
expect($t2->fresh()->category_id)->toBeNull();
|
||||
|
|
@ -406,7 +407,7 @@ test('job applies rules to transactions matching filters', function () {
|
|||
'date_from' => '2024-01-01',
|
||||
'date_to' => '2024-12-31',
|
||||
]);
|
||||
$job->handle(app(\App\Services\AutomationRuleService::class));
|
||||
$job->handle(app(AutomationRuleService::class));
|
||||
|
||||
expect($matchingTransaction->fresh()->category_id)->toBe($this->category->id);
|
||||
expect($outsideRangeTransaction->fresh()->category_id)->toBeNull();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use App\Enums\AccountType;
|
||||
use App\Enums\PropertyType;
|
||||
use App\Models\Bank;
|
||||
use App\Models\User;
|
||||
use Laravel\Pennant\Feature;
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ test('users with real-estate feature can create real estate accounts', function
|
|||
|
||||
test('users without real-estate feature can still create non-real-estate accounts', function () {
|
||||
$user = User::factory()->onboarded()->create();
|
||||
$bank = \App\Models\Bank::factory()->create();
|
||||
$bank = Bank::factory()->create();
|
||||
|
||||
Feature::for($user)->deactivate('real-estate');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
<?php
|
||||
|
||||
use App\Actions\CreateDefaultCategories;
|
||||
use App\Enums\CategoryCashflowDirection;
|
||||
use App\Enums\CategoryType;
|
||||
use App\Models\Category;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\UniqueConstraintViolationException;
|
||||
|
||||
test('authenticated users can view their categories', function () {
|
||||
$user = User::factory()->create();
|
||||
|
|
@ -262,7 +265,7 @@ test('guests cannot access category management', function () {
|
|||
test('default categories are created when user registers', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$service = new \App\Actions\CreateDefaultCategories;
|
||||
$service = new CreateDefaultCategories;
|
||||
$service->handle($user);
|
||||
|
||||
expect($user->categories()->count())->toBe(64);
|
||||
|
|
@ -273,23 +276,23 @@ test('default categories are created when user registers', function () {
|
|||
$user->refresh();
|
||||
|
||||
expect($user->categories()->firstWhere('name', 'Investments'))
|
||||
->type->toBe(\App\Enums\CategoryType::Transfer)
|
||||
->type->toBe(CategoryType::Transfer)
|
||||
->cashflow_direction->toBe(CategoryCashflowDirection::Outflow);
|
||||
expect($user->categories()->firstWhere('name', 'Savings'))
|
||||
->type->toBe(\App\Enums\CategoryType::Transfer)
|
||||
->type->toBe(CategoryType::Transfer)
|
||||
->cashflow_direction->toBe(CategoryCashflowDirection::Outflow);
|
||||
expect($user->categories()->firstWhere('name', 'Other investments'))
|
||||
->type->toBe(\App\Enums\CategoryType::Transfer)
|
||||
->type->toBe(CategoryType::Transfer)
|
||||
->cashflow_direction->toBe(CategoryCashflowDirection::Outflow);
|
||||
expect($user->categories()->firstWhere('name', 'From account of relatives'))
|
||||
->type->toBe(\App\Enums\CategoryType::Transfer)
|
||||
->type->toBe(CategoryType::Transfer)
|
||||
->cashflow_direction->toBe(CategoryCashflowDirection::Inflow);
|
||||
});
|
||||
|
||||
test('default categories are not created twice for the same user', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$service = new \App\Actions\CreateDefaultCategories;
|
||||
$service = new CreateDefaultCategories;
|
||||
$service->handle($user);
|
||||
|
||||
expect($user->categories()->count())->toBe(64);
|
||||
|
|
@ -309,9 +312,9 @@ test('category names are unique per user', function () {
|
|||
'type' => 'expense',
|
||||
]);
|
||||
|
||||
expect($category)->toBeInstanceOf(\App\Models\Category::class);
|
||||
expect($category)->toBeInstanceOf(Category::class);
|
||||
|
||||
$this->expectException(\Illuminate\Database\UniqueConstraintViolationException::class);
|
||||
$this->expectException(UniqueConstraintViolationException::class);
|
||||
|
||||
$user->categories()->create([
|
||||
'name' => 'Test Category',
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use App\Models\Category;
|
|||
use App\Models\Label;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\User;
|
||||
use App\Services\BudgetTransactionService;
|
||||
|
||||
use function Pest\Laravel\actingAs;
|
||||
|
||||
|
|
@ -660,7 +661,7 @@ test('when budget with label exists, updating transaction with that label assign
|
|||
// The TransactionUpdated event triggers AssignTransactionToBudget listener
|
||||
// In production this runs async via queue, but the assignment logic works correctly
|
||||
// Let's verify by manually calling the service (simulating what the listener does)
|
||||
$budgetService = app(\App\Services\BudgetTransactionService::class);
|
||||
$budgetService = app(BudgetTransactionService::class);
|
||||
$budgetService->assignTransaction($transaction);
|
||||
|
||||
// Verify transaction was assigned to the budget
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\AccountBalance;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Analytics Query Count Tests
|
||||
|
|
@ -47,7 +50,7 @@ test('cash flow API does not exceed query threshold', function () {
|
|||
});
|
||||
|
||||
test('top categories API does not exceed query threshold', function () {
|
||||
assertMaxQueries(12, function () {
|
||||
assertMaxQueries(13, function () {
|
||||
$this->getJson("/api/dashboard/top-categories?{$this->dateParams}")->assertOk();
|
||||
}, 'API Top Categories');
|
||||
});
|
||||
|
|
@ -87,10 +90,10 @@ test('cashflow breakdown API does not exceed query threshold', function () {
|
|||
test('net worth API query count does not scale with number of accounts', function () {
|
||||
$categories = $this->user->categories;
|
||||
|
||||
$extraAccounts = App\Models\Account::factory(7)->create(['user_id' => $this->user->id]);
|
||||
$extraAccounts = Account::factory(7)->create(['user_id' => $this->user->id]);
|
||||
foreach ($extraAccounts as $index => $account) {
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
App\Models\AccountBalance::factory()->create([
|
||||
AccountBalance::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'balance_date' => now()->subDays(($index * 5) + $i + 20)->toDateString(),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\AccountBalance;
|
||||
use App\Models\Transaction;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Page Query Count Tests
|
||||
|
|
@ -121,16 +125,16 @@ test('dashboard query count does not scale with number of accounts', function ()
|
|||
// Add 7 more accounts (10 total) with transactions and balances
|
||||
$categories = $this->user->categories;
|
||||
|
||||
$extraAccounts = App\Models\Account::factory(7)->create(['user_id' => $this->user->id]);
|
||||
$extraAccounts = Account::factory(7)->create(['user_id' => $this->user->id]);
|
||||
foreach ($extraAccounts as $index => $account) {
|
||||
App\Models\Transaction::factory(10)->plaintext()->create([
|
||||
Transaction::factory(10)->plaintext()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'account_id' => $account->id,
|
||||
'category_id' => $categories->random()->id,
|
||||
]);
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
App\Models\AccountBalance::factory()->create([
|
||||
AccountBalance::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'balance_date' => now()->subDays(($index * 5) + $i + 20)->toDateString(),
|
||||
]);
|
||||
|
|
@ -148,7 +152,7 @@ test('transactions page query count does not scale with number of transactions',
|
|||
$category = $this->user->categories()->first();
|
||||
|
||||
// Add 90 more transactions (120 total)
|
||||
App\Models\Transaction::factory(90)->plaintext()->create([
|
||||
Transaction::factory(90)->plaintext()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'account_id' => $account->id,
|
||||
'category_id' => $category->id,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Account;
|
||||
use App\Models\AccountBalance;
|
||||
use App\Models\Budget;
|
||||
use App\Models\BudgetPeriod;
|
||||
use App\Models\Category;
|
||||
use App\Models\Label;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Test Case
|
||||
|
|
@ -11,8 +23,8 @@
|
|||
|
|
||||
*/
|
||||
|
||||
pest()->extend(Tests\TestCase::class)
|
||||
->use(Illuminate\Foundation\Testing\RefreshDatabase::class)
|
||||
pest()->extend(TestCase::class)
|
||||
->use(RefreshDatabase::class)
|
||||
->in('Feature', 'Browser', 'Performance');
|
||||
|
||||
pest()->browser()->timeout(15000);
|
||||
|
|
@ -49,32 +61,32 @@ pest()->browser()->timeout(15000);
|
|||
* Includes 3 accounts, 30 transactions, 15 balances, 5 categories,
|
||||
* 3 labels, and 1 budget with a current period.
|
||||
*/
|
||||
function performanceSeedUser(): App\Models\User
|
||||
function performanceSeedUser(): User
|
||||
{
|
||||
$user = App\Models\User::factory()->onboarded()->create();
|
||||
$user = User::factory()->onboarded()->create();
|
||||
|
||||
$categories = App\Models\Category::factory(5)->create(['user_id' => $user->id]);
|
||||
App\Models\Label::factory(3)->create(['user_id' => $user->id]);
|
||||
$categories = Category::factory(5)->create(['user_id' => $user->id]);
|
||||
Label::factory(3)->create(['user_id' => $user->id]);
|
||||
|
||||
$accounts = App\Models\Account::factory(3)->create(['user_id' => $user->id]);
|
||||
$accounts = Account::factory(3)->create(['user_id' => $user->id]);
|
||||
|
||||
foreach ($accounts as $index => $account) {
|
||||
App\Models\Transaction::factory(10)->plaintext()->create([
|
||||
Transaction::factory(10)->plaintext()->create([
|
||||
'user_id' => $user->id,
|
||||
'account_id' => $account->id,
|
||||
'category_id' => $categories->random()->id,
|
||||
]);
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
App\Models\AccountBalance::factory()->create([
|
||||
AccountBalance::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'balance_date' => now()->subDays(($index * 5) + $i + 1)->toDateString(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$budget = App\Models\Budget::factory()->monthly()->create(['user_id' => $user->id]);
|
||||
App\Models\BudgetPeriod::factory()->create([
|
||||
$budget = Budget::factory()->monthly()->create(['user_id' => $user->id]);
|
||||
BudgetPeriod::factory()->create([
|
||||
'budget_id' => $budget->id,
|
||||
'start_date' => now()->startOfMonth(),
|
||||
'end_date' => now()->endOfMonth(),
|
||||
|
|
@ -88,11 +100,11 @@ function performanceSeedUser(): App\Models\User
|
|||
*
|
||||
* @return array{count: int, queries: list<string>}
|
||||
*/
|
||||
function countQueries(\Closure $callback): array
|
||||
function countQueries(Closure $callback): array
|
||||
{
|
||||
$queryLog = [];
|
||||
|
||||
Illuminate\Support\Facades\DB::listen(function ($query) use (&$queryLog) {
|
||||
DB::listen(function ($query) use (&$queryLog) {
|
||||
$queryLog[] = $query->sql;
|
||||
});
|
||||
|
||||
|
|
@ -106,7 +118,7 @@ function countQueries(\Closure $callback): array
|
|||
*
|
||||
* On failure, dumps all executed queries for easy debugging.
|
||||
*/
|
||||
function assertMaxQueries(int $max, \Closure $callback, string $context = ''): void
|
||||
function assertMaxQueries(int $max, Closure $callback, string $context = ''): void
|
||||
{
|
||||
$result = countQueries($callback);
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ if ($useContainers) {
|
|||
$cleanup = function () use ($container): void {
|
||||
try {
|
||||
$container->stop();
|
||||
} catch (\Throwable) {
|
||||
} catch (Throwable) {
|
||||
// Silently ignore — best-effort cleanup.
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue