From 828b84084d00761d41b6fb8787919d59ff04c19f Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 21 Mar 2024 18:29:38 +0000 Subject: [PATCH 01/12] Added validation for last_audit_date and next_audit_date Signed-off-by: snipe --- app/Http/Controllers/Api/AssetsController.php | 4 ++-- app/Models/Asset.php | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index b26887b6ce..c672781e6f 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -613,7 +613,7 @@ class AssetsController extends Controller $asset->image = $asset->getImageUrl(); } - return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success'))); + return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success'))); } return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200); @@ -692,7 +692,7 @@ class AssetsController extends Controller $asset->image = $asset->getImageUrl(); } - return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success'))); + return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success'))); } return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200); diff --git a/app/Models/Asset.php b/app/Models/Asset.php index c2a2a8d995..981d785251 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -97,6 +97,8 @@ class Asset extends Depreciable 'warranty_months' => 'nullable|numeric|digits_between:0,240', 'last_checkout' => 'nullable|date_format:Y-m-d H:i:s', 'expected_checkin' => 'nullable|date', + 'last_audit_date' => 'nullable|date_format:Y-m-d H:i:s', + 'next_audit_date' => 'nullable|date|date_format:Y-m-d', 'location_id' => 'nullable|exists:locations,id', 'rtd_location_id' => 'nullable|exists:locations,id', 'purchase_date' => 'nullable|date|date_format:Y-m-d', From e9e6f925bf6dc119608986a28b427e9eeb0b4e42 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 21 Mar 2024 18:34:39 +0000 Subject: [PATCH 02/12] Updated validation Signed-off-by: snipe --- app/Models/Asset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 981d785251..2830eca7e5 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -98,7 +98,7 @@ class Asset extends Depreciable 'last_checkout' => 'nullable|date_format:Y-m-d H:i:s', 'expected_checkin' => 'nullable|date', 'last_audit_date' => 'nullable|date_format:Y-m-d H:i:s', - 'next_audit_date' => 'nullable|date|date_format:Y-m-d', + 'next_audit_date' => 'nullable|date|after:last_audit_date', 'location_id' => 'nullable|exists:locations,id', 'rtd_location_id' => 'nullable|exists:locations,id', 'purchase_date' => 'nullable|date|date_format:Y-m-d', From e45fd4088f8438e7e301a1608fddd455bf20f536 Mon Sep 17 00:00:00 2001 From: Phil J R <52716446+PP-JN-RL@users.noreply.github.com> Date: Mon, 25 Mar 2024 16:31:20 +0000 Subject: [PATCH 03/12] Created Dymo LabelWriter Label 2112283 I have added the layout for the Dymo LabelWriter 2112283 Labels. They are: DYMO 2112283 DURABLE SMALL MULTI PURPOSE LABELS (160 LABELS) - 25 X 54MM --- .../Tapes/Dymo/Label_Writer_2112283.php | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 app/Models/Labels/Tapes/Dymo/Label_Writer_2112283.php diff --git a/app/Models/Labels/Tapes/Dymo/Label_Writer_2112283.php b/app/Models/Labels/Tapes/Dymo/Label_Writer_2112283.php new file mode 100644 index 0000000000..e1305bd068 --- /dev/null +++ b/app/Models/Labels/Tapes/Dymo/Label_Writer_2112283.php @@ -0,0 +1,89 @@ +getPrintableArea(); + + $currentX = $pa->x1; + $currentY = $pa->y1; + $usableWidth = $pa->w; + + $barcodeSize = $pa->h - self::TAG_SIZE; + + if ($record->has('barcode2d')) { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'C', + $barcodeSize, self::TAG_SIZE, true, 0 + ); + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $currentX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + self::BARCODE_MARGIN; + $usableWidth -= $barcodeSize + self::BARCODE_MARGIN; + } else { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'R', + $usableWidth, self::TAG_SIZE, true, 0 + ); + } + + if ($record->has('title')) { + static::writeText( + $pdf, $record->get('title'), + $currentX, $currentY, + 'freesans', 'b', self::TITLE_SIZE, 'L', + $usableWidth, self::TITLE_SIZE, true, 0 + ); + $currentY += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $field) { + static::writeText( + $pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'], + $currentX, $currentY, + 'freesans', '', self::FIELD_SIZE, 'L', + $usableWidth, self::FIELD_SIZE, true, 0, 0.3 + ); + $currentY += self::FIELD_SIZE + self::FIELD_MARGIN; + } + + if ($record->has('barcode1d')) { + static::write1DBarcode( + $pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type, + $currentX, $barcodeSize + self::BARCODE_MARGIN, $usableWidth - self::TAG_SIZE, self::TAG_SIZE + ); + } + } + +} From 66ba96d5315cb6b042eb2887b4a53f75a7f4497c Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 12:38:12 -0700 Subject: [PATCH 04/12] Set last_audit_date to valid format in StoreAssetRequest --- app/Http/Requests/StoreAssetRequest.php | 2 ++ tests/Feature/Api/Assets/AssetStoreTest.php | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 74988b6c62..e46128b6ff 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -4,6 +4,7 @@ namespace App\Http\Requests; use App\Models\Asset; use App\Models\Company; +use Carbon\Carbon; use Illuminate\Support\Facades\Gate; class StoreAssetRequest extends ImageUploadRequest @@ -31,6 +32,7 @@ class StoreAssetRequest extends ImageUploadRequest 'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(), 'company_id' => $idForCurrentUser, 'assigned_to' => $assigned_to ?? null, + 'last_audit_date' => Carbon::parse($this->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s'), ]); } diff --git a/tests/Feature/Api/Assets/AssetStoreTest.php b/tests/Feature/Api/Assets/AssetStoreTest.php index ceae053648..91c10a936c 100644 --- a/tests/Feature/Api/Assets/AssetStoreTest.php +++ b/tests/Feature/Api/Assets/AssetStoreTest.php @@ -65,8 +65,7 @@ class AssetStoreTest extends TestCase $this->assertEquals('random_string', $asset->asset_tag); $this->assertEquals($userAssigned->id, $asset->assigned_to); $this->assertTrue($asset->company->is($company)); - // I don't see this on the GUI side either, but it's in the docs so I'm guessing that's a mistake? It wasn't in the controller. - // $this->assertEquals('2023-09-03', $asset->last_audit_date); + $this->assertEquals('2023-09-03 00:00:00', $asset->last_audit_date->format('Y-m-d H:i:s')); $this->assertTrue($asset->location->is($location)); $this->assertTrue($asset->model->is($model)); $this->assertEquals('A New Asset', $asset->name); @@ -82,6 +81,22 @@ class AssetStoreTest extends TestCase $this->assertEquals(10, $asset->warranty_months); } + public function testSetsLastAuditDateToMidnightOfProvidedDate() + { + $response = $this->actingAsForApi(User::factory()->superuser()->create()) + ->postJson(route('api.assets.store'), [ + 'last_audit_date' => '2023-09-03 12:23:45', + 'asset_tag' => '1234', + 'model_id' => AssetModel::factory()->create()->id, + 'status_id' => Statuslabel::factory()->create()->id, + ]) + ->assertOk() + ->assertStatusMessageIs('success'); + + $asset = Asset::find($response['payload']['id']); + $this->assertEquals('00:00:00', $asset->last_audit_date->format('H:i:s')); + } + public function testArchivedDepreciateAndPhysicalCanBeNull() { $model = AssetModel::factory()->ipadModel()->create(); From 5f4c964309c14eeaf8038c0ed4b3f3b78ceb8eda Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 12:45:11 -0700 Subject: [PATCH 05/12] Account for `last_audit_date` not being provided --- app/Http/Requests/StoreAssetRequest.php | 7 ++++++- tests/Feature/Api/Assets/AssetStoreTest.php | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index e46128b6ff..d87d5bc2fb 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -28,11 +28,16 @@ class StoreAssetRequest extends ImageUploadRequest ? Company::getIdForCurrentUser($this->company_id) : $this->company_id; + if ($this->input('last_audit_date')) { + $this->merge([ + 'last_audit_date' => Carbon::parse($this->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s'), + ]); + } + $this->merge([ 'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(), 'company_id' => $idForCurrentUser, 'assigned_to' => $assigned_to ?? null, - 'last_audit_date' => Carbon::parse($this->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s'), ]); } diff --git a/tests/Feature/Api/Assets/AssetStoreTest.php b/tests/Feature/Api/Assets/AssetStoreTest.php index 91c10a936c..4b4f66f3df 100644 --- a/tests/Feature/Api/Assets/AssetStoreTest.php +++ b/tests/Feature/Api/Assets/AssetStoreTest.php @@ -97,6 +97,22 @@ class AssetStoreTest extends TestCase $this->assertEquals('00:00:00', $asset->last_audit_date->format('H:i:s')); } + public function testLastAuditDateCanBeNull() + { + $response = $this->actingAsForApi(User::factory()->superuser()->create()) + ->postJson(route('api.assets.store'), [ + // 'last_audit_date' => '2023-09-03 12:23:45', + 'asset_tag' => '1234', + 'model_id' => AssetModel::factory()->create()->id, + 'status_id' => Statuslabel::factory()->create()->id, + ]) + ->assertOk() + ->assertStatusMessageIs('success'); + + $asset = Asset::find($response['payload']['id']); + $this->assertNull($asset->last_audit_date); + } + public function testArchivedDepreciateAndPhysicalCanBeNull() { $model = AssetModel::factory()->ipadModel()->create(); From 675717ff82b3e30ba7e76cbe4cec25def5615c0d Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 13:46:22 -0700 Subject: [PATCH 06/12] Add failing test --- tests/Feature/Api/Assets/AssetStoreTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Feature/Api/Assets/AssetStoreTest.php b/tests/Feature/Api/Assets/AssetStoreTest.php index 4b4f66f3df..e98da36cf9 100644 --- a/tests/Feature/Api/Assets/AssetStoreTest.php +++ b/tests/Feature/Api/Assets/AssetStoreTest.php @@ -113,6 +113,20 @@ class AssetStoreTest extends TestCase $this->assertNull($asset->last_audit_date); } + public function testNonDateUsedForLastAuditDateReturnsValidationError() + { + $response = $this->actingAsForApi(User::factory()->superuser()->create()) + ->postJson(route('api.assets.store'), [ + 'last_audit_date' => 'this-is-not-valid', + 'asset_tag' => '1234', + 'model_id' => AssetModel::factory()->create()->id, + 'status_id' => Statuslabel::factory()->create()->id, + ]) + ->assertStatusMessageIs('error'); + + $this->assertNotNull($response->json('messages.last_audit_date')); + } + public function testArchivedDepreciateAndPhysicalCanBeNull() { $model = AssetModel::factory()->ipadModel()->create(); From c98b9da612a701a49119bdc0a1b7ff8dfe928ab8 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 13:47:24 -0700 Subject: [PATCH 07/12] Pass last_audit_date through for model level validation if not a date --- app/Http/Requests/StoreAssetRequest.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index d87d5bc2fb..918972c6cc 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -5,6 +5,7 @@ namespace App\Http\Requests; use App\Models\Asset; use App\Models\Company; use Carbon\Carbon; +use Carbon\Exceptions\InvalidFormatException; use Illuminate\Support\Facades\Gate; class StoreAssetRequest extends ImageUploadRequest @@ -29,9 +30,15 @@ class StoreAssetRequest extends ImageUploadRequest : $this->company_id; if ($this->input('last_audit_date')) { - $this->merge([ - 'last_audit_date' => Carbon::parse($this->input('last_audit_date'))->startOfDay()->format('Y-m-d H:i:s'), - ]); + try { + $lastAuditDate = Carbon::parse($this->input('last_audit_date')); + + $this->merge([ + 'last_audit_date' => $lastAuditDate->startOfDay()->format('Y-m-d H:i:s'), + ]); + } catch (InvalidFormatException $e) { + // we don't need to do anything here... + } } $this->merge([ From a2625c889ac307556badd99fe28b15c09392494d Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 13:48:32 -0700 Subject: [PATCH 08/12] Improve comment --- app/Http/Requests/StoreAssetRequest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 918972c6cc..20b801a52c 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -38,6 +38,8 @@ class StoreAssetRequest extends ImageUploadRequest ]); } catch (InvalidFormatException $e) { // we don't need to do anything here... + // we'll keep the provided date in an + // invalid format so validation picks it up later } } From 71722b753d87e056e366450604dda21c7b8e189c Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 13:49:03 -0700 Subject: [PATCH 09/12] Little bit of clean up --- app/Http/Requests/StoreAssetRequest.php | 31 ++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 20b801a52c..70e7195c7d 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -29,19 +29,7 @@ class StoreAssetRequest extends ImageUploadRequest ? Company::getIdForCurrentUser($this->company_id) : $this->company_id; - if ($this->input('last_audit_date')) { - try { - $lastAuditDate = Carbon::parse($this->input('last_audit_date')); - - $this->merge([ - 'last_audit_date' => $lastAuditDate->startOfDay()->format('Y-m-d H:i:s'), - ]); - } catch (InvalidFormatException $e) { - // we don't need to do anything here... - // we'll keep the provided date in an - // invalid format so validation picks it up later - } - } + $this->formatLastAuditDate(); $this->merge([ 'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(), @@ -64,4 +52,21 @@ class StoreAssetRequest extends ImageUploadRequest return $rules; } + + private function formatLastAuditDate(): void + { + if ($this->input('last_audit_date')) { + try { + $lastAuditDate = Carbon::parse($this->input('last_audit_date')); + + $this->merge([ + 'last_audit_date' => $lastAuditDate->startOfDay()->format('Y-m-d H:i:s'), + ]); + } catch (InvalidFormatException $e) { + // we don't need to do anything here... + // we'll keep the provided date in an + // invalid format so validation picks it up later + } + } + } } From 57d1c036ecbf3d1b67c1c0e721641c769839d34e Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 25 Mar 2024 13:53:30 -0700 Subject: [PATCH 10/12] Improve method name --- app/Http/Requests/StoreAssetRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 70e7195c7d..8e7559673e 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -29,7 +29,7 @@ class StoreAssetRequest extends ImageUploadRequest ? Company::getIdForCurrentUser($this->company_id) : $this->company_id; - $this->formatLastAuditDate(); + $this->parseLastAuditDate(); $this->merge([ 'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(), @@ -53,7 +53,7 @@ class StoreAssetRequest extends ImageUploadRequest return $rules; } - private function formatLastAuditDate(): void + private function parseLastAuditDate(): void { if ($this->input('last_audit_date')) { try { From 7ebbef25e77c22815db85862addf336bd0c2c649 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 26 Mar 2024 08:18:36 +0000 Subject: [PATCH 11/12] Standardize button styling Signed-off-by: snipe --- resources/views/hardware/view.blade.php | 34 ++++++++++++------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index a32503d7ea..ce814d5c76 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -904,27 +904,18 @@ @endcan @can('delete', $asset) - @if ($asset->deleted_at=='') -
- +
+ @if ($asset->deleted_at=='') + {{ trans('general.delete') }} -
- @endif + @else +
+ @csrf + +
+ @endif @endcan - @if ($asset->deleted_at!='') -
-
- @csrf - -
-
- @endif - - @if ($snipeSettings->qr_code=='1') - QR code for {{ $asset->getDisplayNameAttribute() }} - @endif - @if (($asset->assignedTo) && ($asset->deleted_at==''))

{{ trans('admin/hardware/form.checkedout_to') }}

@@ -982,6 +973,13 @@
@endif + + @if ($snipeSettings->qr_code=='1') +
+ QR code for {{ $asset->getDisplayNameAttribute() }} +
+ @endif +
From 31a57cdf141ecebd1827cfbf38089f071845821e Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 26 Mar 2024 08:18:59 +0000 Subject: [PATCH 12/12] Fixed #14482 - bad method call on restore from view Signed-off-by: snipe --- resources/views/models/view.blade.php | 35 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/resources/views/models/view.blade.php b/resources/views/models/view.blade.php index 91f112d8aa..76d3322998 100755 --- a/resources/views/models/view.blade.php +++ b/resources/views/models/view.blade.php @@ -236,6 +236,12 @@ @endif + @if ($model->created_at) +
  • {{ trans('general.created_at') }}: + {{ Helper::getFormattedDateObject($model->created_at, 'datetime', false) }} +
  • + @endif + @if ($model->min_amt)
  • {{ trans('general.min_amt') }}: {{$model->min_amt }} @@ -313,11 +319,6 @@
  • @endif - - - @if ($model->deleted_at!='') -

  • {{ trans('admin/models/general.restore') }}
  • - @endif @if ($model->note) @@ -337,22 +338,32 @@ @can('create', \App\Models\AssetModel::class) @endcan @can('delete', \App\Models\AssetModel::class) @if ($model->assets_count > 0) -
    - +
    @else -
    - - {{ trans('general.delete') }} -
    + @endif + + +
    + @if ($model->deleted_at!='') +
    + @csrf + +
    + @else + + {{ trans('general.delete') }} + @endif +
    + @endcan