3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-06-14 02:53:25 +00:00
Files
snipe-it/tests/Feature/Console/CleanIncorrectCheckoutAcceptancesTest.php
2026-05-15 01:56:22 +01:00

136 lines
4.7 KiB
PHP

<?php
namespace Tests\Feature\Console;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\Location;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Tests\TestCase;
class CleanIncorrectCheckoutAcceptancesTest extends TestCase
{
public function test_deletes_acceptance_when_checkout_target_is_non_user()
{
$location = Location::factory()->create();
$asset = Asset::factory()->create();
$now = now();
$badAcceptance = CheckoutAcceptance::factory()
->withoutActionLog()
->create([
'checkoutable_type' => Asset::class,
'checkoutable_id' => $asset->id,
'assigned_to_id' => $location->id,
'created_at' => $now,
]);
Actionlog::factory()->create([
'action_type' => 'checkout',
'target_id' => $location->id,
'target_type' => Location::class,
'item_id' => $asset->id,
'item_type' => Asset::class,
'created_at' => $now,
]);
$this->artisan('snipeit:clean-checkout-acceptances')->assertExitCode(0);
$this->assertDatabaseMissing('checkout_acceptances', ['id' => $badAcceptance->id]);
}
public function test_preserves_acceptance_when_checkout_target_is_user()
{
// The factory creates a matching action_log with target_type = User::class by default
$goodAcceptance = CheckoutAcceptance::factory()->create();
$this->artisan('snipeit:clean-checkout-acceptances')->assertExitCode(0);
$this->assertDatabaseHas('checkout_acceptances', ['id' => $goodAcceptance->id]);
}
public function test_preserves_acceptance_when_action_log_timestamp_is_too_far_apart()
{
$location = Location::factory()->create();
$asset = Asset::factory()->create();
$now = now();
$acceptance = CheckoutAcceptance::factory()
->withoutActionLog()
->create([
'checkoutable_type' => Asset::class,
'checkoutable_id' => $asset->id,
'assigned_to_id' => $location->id,
'created_at' => $now,
]);
// 10 seconds away — outside the ±5-second window
Actionlog::factory()->create([
'action_type' => 'checkout',
'target_id' => $location->id,
'target_type' => Location::class,
'item_id' => $asset->id,
'item_type' => Asset::class,
'created_at' => $now->copy()->addSeconds(10),
]);
$this->artisan('snipeit:clean-checkout-acceptances')->assertExitCode(0);
$this->assertDatabaseHas('checkout_acceptances', ['id' => $acceptance->id]);
}
public function test_skips_acceptance_with_soft_deleted_checkoutable()
{
$acceptance = CheckoutAcceptance::factory()->withoutActionLog()->create();
Model::withoutEvents(fn () => $acceptance->checkoutable->delete());
$this->artisan('snipeit:clean-checkout-acceptances')->assertExitCode(0);
$this->assertDatabaseHas('checkout_acceptances', ['id' => $acceptance->id]);
}
public function test_skips_acceptance_with_null_created_at(): void
{
$acceptance = CheckoutAcceptance::factory()->withoutActionLog()->create(['created_at' => null]);
$this->artisan('snipeit:clean-checkout-acceptances')->assertExitCode(0);
$this->assertDatabaseHas('checkout_acceptances', ['id' => $acceptance->id]);
}
public function test_deletes_license_seat_acceptance_when_checkout_target_is_non_user()
{
$location = Location::factory()->create();
$licenseSeat = LicenseSeat::factory()->create();
$license = $licenseSeat->license;
$now = now();
$badAcceptance = CheckoutAcceptance::factory()
->withoutActionLog()
->create([
'checkoutable_type' => LicenseSeat::class,
'checkoutable_id' => $licenseSeat->id,
'assigned_to_id' => $location->id,
'created_at' => $now,
]);
// Action log lives on the License, not the LicenseSeat
Actionlog::factory()->create([
'action_type' => 'checkout',
'target_id' => $location->id,
'target_type' => Location::class,
'item_id' => $license->id,
'item_type' => License::class,
'created_at' => $now,
]);
$this->artisan('snipeit:clean-checkout-acceptances')->assertExitCode(0);
$this->assertDatabaseMissing('checkout_acceptances', ['id' => $badAcceptance->id]);
}
}