Merge pull request #17087 from grokability/#17085-checkin-and-delete-not-nulling-assigned_type

Fixed #17085 - assigned_type not being nulled on asset delete+checkin
This commit is contained in:
snipe
2025-06-03 05:53:24 +01:00
committed by GitHub
8 changed files with 96 additions and 5 deletions

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class FixUpAssignedTypeWithoutAssignedTo extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:assigned-type-fixup';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Fixes up assets that have an assigned_type but no assigned_to';
/**
* Execute the console command.
*/
public function handle()
{
DB::table('assets')->whereNotNull('assigned_type')->whereNull('assigned_to')->update(['assigned_type' => null]);
$this->info("Assets with an assigned_type but no assigned_to are fixed");
}
}

View File

@@ -28,7 +28,7 @@ class CheckoutableCheckedIn
$this->checkedOutTo = $checkedOutTo;
$this->checkedInBy = $checkedInBy;
$this->note = $note;
$this->action_date = $action_date ?? date('Y-m-d');
$this->action_date = $action_date ?? date('Y-m-d H:i:s');
$this->originalValues = $originalValues;
}
}

View File

@@ -446,7 +446,7 @@ class AssetsController extends Controller
event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on delete', $checkin_at, $originalValues));
DB::table('assets')
->where('id', $asset->id)
->update(['assigned_to' => null]);
->update(['assigned_to' => null, 'assigned_type' => null]);
}

View File

@@ -95,7 +95,7 @@ trait Loggable
$changed = [];
$array_to_flip = array_keys($fields_array);
$array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
$array_to_flip = array_merge($array_to_flip, ['name','status_id','location_id','expected_checkin']);
$originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
@@ -182,7 +182,7 @@ trait Loggable
$log->note = $note;
$log->action_date = $action_date;
if (! $log->action_date) {
if (!$action_date) {
$log->action_date = date('Y-m-d H:i:s');
}
@@ -193,7 +193,7 @@ trait Loggable
$changed = [];
$array_to_flip = array_keys($fields_array);
$array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
$array_to_flip = array_merge($array_to_flip, ['name','status_id','location_id','expected_checkin']);
$originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));

View File

@@ -62,6 +62,7 @@ class AssetObserver
$logAction = new Actionlog();
$logAction->item_type = Asset::class;
$logAction->item_id = $asset->id;
$logAction->action_date = date('Y-m-d H:i:s');
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->log_meta = json_encode($changed);
@@ -108,6 +109,7 @@ class AssetObserver
$logAction = new Actionlog();
$logAction->item_type = Asset::class; // can we instead say $logAction->item = $asset ?
$logAction->item_id = $asset->id;
$logAction->action_date = date('Y-m-d H:i:s');
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if($asset->imported) {
@@ -124,10 +126,12 @@ class AssetObserver
*/
public function deleting(Asset $asset)
{
\Log::error('deleting observer fired for asset: ' . $asset->id);
$logAction = new Actionlog();
$logAction->item_type = Asset::class;
$logAction->item_id = $asset->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->action_date = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('delete');
}
@@ -143,6 +147,7 @@ class AssetObserver
$logAction = new Actionlog();
$logAction->item_type = Asset::class;
$logAction->item_id = $asset->id;
$logAction->action_date = date('Y-m-d H:i:s');
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('restore');

View File

@@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
DB::table('assets')->whereNotNull('assigned_type')->whereNull('assigned_to')->update(['assigned_type' => null]);
}
/**
* Reverse the migrations.
*/
public function down(): void
{
}
};

View File

@@ -137,6 +137,10 @@ class BulkDeleteAssetsTest extends TestCase
'item_type' => Asset::class,
]
);
$asset->refresh();
$this->assertNull($asset->assigned_to);
$this->assertNull($asset->assigned_type);
}
public function testActionLogCreatedUponBulkRestore()

View File

@@ -48,6 +48,29 @@ class DeleteAssetTest extends TestCase
]);
}
public function testActionLogsActionDateIsPopulatedWhenAssetDeleted()
{
$actor = User::factory()->deleteAssets()->create();
$asset = Asset::factory()->create();
$this->actingAs($actor)->delete(route('hardware.destroy', $asset));
$asset->refresh();
$this->assertDatabaseHas('action_logs', [
'action_date' => $asset->updated_at,
'created_at' => $asset->updated_at,
'created_by' => $actor->id,
'action_type' => 'delete',
'target_id' => null,
'target_type' => null,
'item_type' => Asset::class,
'item_id' => $asset->id,
]);
}
public function testAssetIsCheckedInWhenDeleted()
{
Event::fake();
@@ -65,6 +88,10 @@ class DeleteAssetTest extends TestCase
'Asset still assigned to user after deletion'
);
$asset->refresh();
$this->assertNull($asset->assigned_to);
$this->assertNull($asset->assigned_type);
Event::assertDispatched(CheckoutableCheckedIn::class);
}