Maintenances: Fixed FD-55977 - Cross-company asset maintenance re-parenting via API update

This commit is contained in:
snipe
2026-06-12 19:17:44 +01:00
parent 802067f398
commit 905d498ecd
2 changed files with 96 additions and 7 deletions
@@ -269,17 +269,33 @@ class MaintenancesController extends Controller
if ($maintenance = Maintenance::with('asset')->find($id)) {
// Can this user manage this asset?
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')])));
}
// The asset this miantenance is attached to is not valid or has been deleted
// The asset this maintenance is attached to is not valid or has been deleted
if (! $maintenance->asset) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('general.asset'), 'id' => $id])));
}
$maintenance->fill($request->all());
// Can this user manage the existing asset?
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')])));
}
// If the request changes asset_id, verify the new asset is accessible
if ($request->filled('asset_id') && (int) $request->input('asset_id') !== $maintenance->asset_id) {
$newAsset = Asset::find($request->input('asset_id'));
if (! $newAsset) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('general.asset'), 'id' => $request->input('asset_id')])));
}
if (! Company::isCurrentUserHasAccess($newAsset)) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('general.asset'), 'id' => $request->input('asset_id'), 'action' => trans('general.edit')])), 403);
}
$maintenance->fill($request->except('asset_id'));
$maintenance->asset_id = $newAsset->id;
} else {
$maintenance->fill($request->except('asset_id'));
}
if ($maintenance->save()) {
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/maintenances/message.edit.success')));
@@ -3,6 +3,7 @@
namespace Tests\Feature\Maintenances\Api;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Maintenance;
use App\Models\MaintenanceType;
@@ -98,4 +99,76 @@ class EditMaintenanceTest extends TestCase
'name' => 'Should Not Update',
]);
}
public function test_can_update_maintenance_without_changing_asset_id()
{
$this->settings->enableMultipleFullCompanySupport();
$company = Company::factory()->create();
$user = $company->users()->save(User::factory()->editAssets()->make());
$asset = Asset::factory()->create(['company_id' => $company->id]);
$maintenance = Maintenance::factory()->create(['asset_id' => $asset->id]);
$this->actingAsForApi($user)
->patchJson(route('api.maintenances.update', $maintenance), [
'name' => 'Updated Name',
'start_date' => '2024-01-01',
])
->assertStatusMessageIs('success');
$this->assertDatabaseHas('maintenances', [
'id' => $maintenance->id,
'asset_id' => $asset->id,
'name' => 'Updated Name',
]);
}
public function test_can_update_maintenance_to_another_asset_in_same_company()
{
$this->settings->enableMultipleFullCompanySupport();
$company = Company::factory()->create();
$user = $company->users()->save(User::factory()->editAssets()->make());
$assetA = Asset::factory()->create(['company_id' => $company->id]);
$assetB = Asset::factory()->create(['company_id' => $company->id]);
$maintenance = Maintenance::factory()->create(['asset_id' => $assetA->id]);
$this->actingAsForApi($user)
->patchJson(route('api.maintenances.update', $maintenance), [
'name' => 'Moved Maintenance',
'asset_id' => $assetB->id,
'start_date' => '2024-01-01',
])
->assertStatusMessageIs('success');
$this->assertDatabaseHas('maintenances', [
'id' => $maintenance->id,
'asset_id' => $assetB->id,
]);
}
public function test_cannot_reparent_maintenance_to_asset_in_another_company()
{
$this->settings->enableMultipleFullCompanySupport();
[$companyA, $companyB] = Company::factory()->count(2)->create();
$user = $companyA->users()->save(User::factory()->editAssets()->make());
$assetA = Asset::factory()->create(['company_id' => $companyA->id]);
$assetB = Asset::factory()->create(['company_id' => $companyB->id]);
$maintenance = Maintenance::factory()->create(['asset_id' => $assetA->id]);
$this->actingAsForApi($user)
->patchJson(route('api.maintenances.update', $maintenance), [
'name' => 'Cross-company reparent attempt',
'asset_id' => $assetB->id,
'start_date' => '2024-01-01',
])
->assertStatusMessageIs('error');
$this->assertDatabaseHas('maintenances', [
'id' => $maintenance->id,
'asset_id' => $assetA->id,
]);
}
}