344 lines
11 KiB
PHP
344 lines
11 KiB
PHP
<?php
|
|
|
|
use App\Models\Account;
|
|
use App\Models\Category;
|
|
use App\Models\Label;
|
|
use App\Models\Transaction;
|
|
use App\Models\User;
|
|
|
|
beforeEach(function () {
|
|
$this->user = User::factory()->create([
|
|
'email_verified_at' => now(),
|
|
'onboarded_at' => now(),
|
|
]);
|
|
$this->account = Account::factory()->create(['user_id' => $this->user->id]);
|
|
$this->category = Category::factory()->create(['user_id' => $this->user->id]);
|
|
});
|
|
|
|
it('can bulk update transactions by IDs', function () {
|
|
$transactions = Transaction::factory()
|
|
->count(3)
|
|
->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'category_id' => null,
|
|
]);
|
|
|
|
$newCategory = Category::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'transaction_ids' => $transactions->pluck('id')->toArray(),
|
|
'category_id' => $newCategory->id,
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
$response->assertJson([
|
|
'message' => 'Transactions updated successfully',
|
|
'count' => 3,
|
|
]);
|
|
|
|
foreach ($transactions as $transaction) {
|
|
expect($transaction->fresh()->category_id)->toBe($newCategory->id);
|
|
}
|
|
});
|
|
|
|
it('can bulk update transactions by filters with date range', function () {
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'transaction_date' => '2024-01-15',
|
|
'category_id' => null,
|
|
]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'transaction_date' => '2024-01-20',
|
|
'category_id' => null,
|
|
]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'transaction_date' => '2024-02-01',
|
|
'category_id' => null,
|
|
]);
|
|
|
|
$newCategory = Category::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'filters' => [
|
|
'date_from' => '2024-01-01',
|
|
'date_to' => '2024-01-31',
|
|
],
|
|
'category_id' => $newCategory->id,
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
$response->assertJson([
|
|
'message' => 'Transactions updated successfully',
|
|
'count' => 2,
|
|
]);
|
|
|
|
$januaryTransactions = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->whereDate('transaction_date', '>=', '2024-01-01')
|
|
->whereDate('transaction_date', '<=', '2024-01-31')
|
|
->get();
|
|
|
|
foreach ($januaryTransactions as $transaction) {
|
|
expect($transaction->category_id)->toBe($newCategory->id);
|
|
}
|
|
|
|
$februaryTransaction = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->whereDate('transaction_date', '2024-02-01')
|
|
->first();
|
|
|
|
expect($februaryTransaction->category_id)->toBeNull();
|
|
});
|
|
|
|
it('can bulk update transactions by filters with amount range', function () {
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'amount' => '5000',
|
|
'category_id' => null,
|
|
]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'amount' => '15000',
|
|
'category_id' => null,
|
|
]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'amount' => '25000',
|
|
'category_id' => null,
|
|
]);
|
|
|
|
$newCategory = Category::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'filters' => [
|
|
'amount_min' => 100,
|
|
'amount_max' => 200,
|
|
],
|
|
'category_id' => $newCategory->id,
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
|
|
$midRangeTransaction = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->where('amount', '15000')
|
|
->first();
|
|
|
|
expect($midRangeTransaction->category_id)->toBe($newCategory->id);
|
|
|
|
$lowTransaction = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->where('amount', '5000')
|
|
->first();
|
|
|
|
expect($lowTransaction->category_id)->toBeNull();
|
|
|
|
$highTransaction = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->where('amount', '25000')
|
|
->first();
|
|
|
|
expect($highTransaction->category_id)->toBeNull();
|
|
});
|
|
|
|
it('can bulk update transactions by filters with category filter', function () {
|
|
$categoryA = Category::factory()->create(['user_id' => $this->user->id]);
|
|
$categoryB = Category::factory()->create(['user_id' => $this->user->id]);
|
|
$categoryC = Category::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'category_id' => $categoryA->id,
|
|
]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'category_id' => $categoryA->id,
|
|
]);
|
|
|
|
Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'category_id' => $categoryB->id,
|
|
]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'filters' => [
|
|
'category_ids' => [$categoryA->id],
|
|
],
|
|
'category_id' => $categoryC->id,
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
$response->assertJson([
|
|
'count' => 2,
|
|
]);
|
|
|
|
$updatedTransactions = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->where('category_id', $categoryC->id)
|
|
->count();
|
|
|
|
expect($updatedTransactions)->toBe(2);
|
|
|
|
$unchangedTransaction = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->where('category_id', $categoryB->id)
|
|
->count();
|
|
|
|
expect($unchangedTransaction)->toBe(1);
|
|
});
|
|
|
|
it('can bulk update transactions with labels by IDs', function () {
|
|
$transactions = Transaction::factory()
|
|
->count(2)
|
|
->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
]);
|
|
|
|
$label1 = Label::factory()->create(['user_id' => $this->user->id]);
|
|
$label2 = Label::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'transaction_ids' => $transactions->pluck('id')->toArray(),
|
|
'label_ids' => [$label1->id, $label2->id],
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
|
|
foreach ($transactions as $transaction) {
|
|
$labelIds = $transaction->fresh()->labels->pluck('id')->toArray();
|
|
expect($labelIds)->toContain($label1->id);
|
|
expect($labelIds)->toContain($label2->id);
|
|
}
|
|
});
|
|
|
|
it('bulk update replaces labels instead of merging them', function () {
|
|
$label1 = Label::factory()->create(['user_id' => $this->user->id, 'name' => 'Old Label 1']);
|
|
$label2 = Label::factory()->create(['user_id' => $this->user->id, 'name' => 'Old Label 2']);
|
|
$label3 = Label::factory()->create(['user_id' => $this->user->id, 'name' => 'New Label']);
|
|
|
|
$transactions = Transaction::factory()
|
|
->count(2)
|
|
->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
]);
|
|
|
|
// Attach existing labels
|
|
foreach ($transactions as $transaction) {
|
|
$transaction->labels()->attach([$label1->id, $label2->id]);
|
|
}
|
|
|
|
// Bulk update with new label should replace, not merge
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'transaction_ids' => $transactions->pluck('id')->toArray(),
|
|
'label_ids' => [$label3->id],
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
|
|
// Verify labels were replaced, not merged
|
|
foreach ($transactions as $transaction) {
|
|
$labelIds = $transaction->fresh()->labels->pluck('id')->toArray();
|
|
expect($labelIds)->toHaveCount(1);
|
|
expect($labelIds)->toEqual([$label3->id]);
|
|
expect($labelIds)->not->toContain($label1->id);
|
|
expect($labelIds)->not->toContain($label2->id);
|
|
}
|
|
});
|
|
|
|
it('can update all transactions when no filters or IDs are provided', function () {
|
|
Transaction::factory()
|
|
->count(3)
|
|
->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'category_id' => null,
|
|
]);
|
|
|
|
$newCategory = Category::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'category_id' => $newCategory->id,
|
|
]);
|
|
|
|
$response->assertSuccessful();
|
|
$response->assertJson([
|
|
'message' => 'Transactions updated successfully',
|
|
'count' => 3,
|
|
]);
|
|
|
|
$allTransactions = Transaction::query()
|
|
->where('user_id', $this->user->id)
|
|
->get();
|
|
|
|
foreach ($allTransactions as $transaction) {
|
|
expect($transaction->category_id)->toBe($newCategory->id);
|
|
}
|
|
});
|
|
|
|
it('validates that at least one update field is provided', function () {
|
|
$transaction = Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'transaction_ids' => [$transaction->id],
|
|
]);
|
|
|
|
$response->assertStatus(400);
|
|
$response->assertJson([
|
|
'message' => 'No update data provided.',
|
|
]);
|
|
});
|
|
|
|
it('only updates transactions belonging to the authenticated user', function () {
|
|
$otherUser = User::factory()->create([
|
|
'email_verified_at' => now(),
|
|
'onboarded_at' => now(),
|
|
]);
|
|
$otherAccount = Account::factory()->create(['user_id' => $otherUser->id]);
|
|
|
|
$myTransaction = Transaction::factory()->create([
|
|
'user_id' => $this->user->id,
|
|
'account_id' => $this->account->id,
|
|
'category_id' => null,
|
|
]);
|
|
|
|
$otherTransaction = Transaction::factory()->create([
|
|
'user_id' => $otherUser->id,
|
|
'account_id' => $otherAccount->id,
|
|
'category_id' => null,
|
|
]);
|
|
|
|
$newCategory = Category::factory()->create(['user_id' => $this->user->id]);
|
|
|
|
$response = $this->actingAs($this->user)->patchJson('/transactions/bulk', [
|
|
'transaction_ids' => [$myTransaction->id, $otherTransaction->id],
|
|
'category_id' => $newCategory->id,
|
|
]);
|
|
|
|
$response->assertStatus(403);
|
|
|
|
expect($myTransaction->fresh()->category_id)->toBeNull();
|
|
expect($otherTransaction->fresh()->category_id)->toBeNull();
|
|
});
|