diff --git a/app/Observers/AssetObserver.php b/app/Observers/AssetObserver.php index 3cbaedded..c15c54a56 100644 --- a/app/Observers/AssetObserver.php +++ b/app/Observers/AssetObserver.php @@ -120,17 +120,30 @@ class AssetObserver $logAction->user_id = Auth::id(); $logAction->logaction('delete'); } - + + /** + * Executes every time an asset is saved. + * + * This matters specifically because any database fields affected here MUST already exist on + * the assets table (and/or any related models), or related migrations WILL fail. + * + * For example, if there is a database migration that's a bit older and modifies an asset, if the save + * fires before a field gets created in a later migration and that field in the later migration + * is used in this observer, it doesn't actually exist yet and the migration will break unless we + * use saveQuietly() in the migration which skips this observer. + * + * @see https://github.com/snipe/snipe-it/issues/13723#issuecomment-1761315938 + */ public function saving(Asset $asset) { - //determine if calculated eol and then calculate it - this should only happen on a new asset - if(is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && !is_null($asset->model->eol)){ + // determine if calculated eol and then calculate it - this should only happen on a new asset + if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && !is_null($asset->model->eol)){ $asset->asset_eol_date = $asset->purchase_date->addMonths($asset->model->eol)->format('Y-m-d'); $asset->eol_explicit = false; } - //determine if explicit and set eol_explit to true - if(!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) { + // determine if explicit and set eol_explicit to true + if (!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) { if($asset->model->eol) { $months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date); if($months != $asset->model->eol) { diff --git a/database/migrations/2023_01_21_225350_add_eol_date_on_assets_table.php b/database/migrations/2023_01_21_225350_add_eol_date_on_assets_table.php index 9f5c5aa1e..aa9086a7c 100644 --- a/database/migrations/2023_01_21_225350_add_eol_date_on_assets_table.php +++ b/database/migrations/2023_01_21_225350_add_eol_date_on_assets_table.php @@ -17,19 +17,30 @@ class AddEolDateOnAssetsTable extends Migration { Schema::table('assets', function (Blueprint $table) { + if (!Schema::hasColumn('assets', 'asset_eol_date')) { $table->date('asset_eol_date')->after('purchase_date')->nullable()->default(null); } + + // This is a temporary shim so we don't have to modify the asset observer for migrations where + // there is a large version difference. (See the AssetObserver notes). This column gets created + // later in 2023_07_13_052204_denormalized_eol_and_add_column_for_explicit_date_to_assets.php + // but we have to temporarily create it now so the save method below doesn't break + if (!Schema::hasColumn('assets', 'eol_explicit')) { + $table->boolean('eol_explicit')->default(false)->after('asset_eol_date'); + } }); // Chunk the model query to get the models that do have an EOL date + // We use saveQuietly() here to skip the AssetObserver, since it modifies fields + // that do not yet exist on the assets table. AssetModel::whereNotNull('eol')->chunk(10, function ($models) { foreach ($models as $model) { foreach ($model->assets as $asset) { if ($asset->purchase_date!='') { $asset->asset_eol_date = $asset->present()->eol_date(); - $asset->save(); + $asset->saveQuietly(); } } diff --git a/database/migrations/2023_07_13_052204_denormalized_eol_and_add_column_for_explicit_date_to_assets.php b/database/migrations/2023_07_13_052204_denormalized_eol_and_add_column_for_explicit_date_to_assets.php index 8d3ca9682..982bd8ac0 100644 --- a/database/migrations/2023_07_13_052204_denormalized_eol_and_add_column_for_explicit_date_to_assets.php +++ b/database/migrations/2023_07_13_052204_denormalized_eol_and_add_column_for_explicit_date_to_assets.php @@ -18,7 +18,9 @@ class DenormalizedEolAndAddColumnForExplicitDateToAssets extends Migration public function up() { Schema::table('assets', function (Blueprint $table) { - $table->boolean('eol_explicit')->default(false)->after('asset_eol_date'); + if (!Schema::hasColumn('assets', 'eol_explicit')) { + $table->boolean('eol_explicit')->default(false)->after('asset_eol_date'); + } });