mirror of
https://github.com/snipe/snipe-it.git
synced 2025-01-22 11:10:48 -08:00
Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
bd42505799
|
@ -613,7 +613,7 @@ class AssetsController extends Controller
|
||||||
$asset->image = $asset->getImageUrl();
|
$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);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||||
|
@ -692,7 +692,7 @@ class AssetsController extends Controller
|
||||||
$asset->image = $asset->getImageUrl();
|
$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);
|
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace App\Http\Requests;
|
||||||
|
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Carbon\Exceptions\InvalidFormatException;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
class StoreAssetRequest extends ImageUploadRequest
|
class StoreAssetRequest extends ImageUploadRequest
|
||||||
|
@ -27,6 +29,8 @@ class StoreAssetRequest extends ImageUploadRequest
|
||||||
? Company::getIdForCurrentUser($this->company_id)
|
? Company::getIdForCurrentUser($this->company_id)
|
||||||
: $this->company_id;
|
: $this->company_id;
|
||||||
|
|
||||||
|
$this->parseLastAuditDate();
|
||||||
|
|
||||||
$this->merge([
|
$this->merge([
|
||||||
'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(),
|
'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(),
|
||||||
'company_id' => $idForCurrentUser,
|
'company_id' => $idForCurrentUser,
|
||||||
|
@ -48,4 +52,21 @@ class StoreAssetRequest extends ImageUploadRequest
|
||||||
|
|
||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function parseLastAuditDate(): 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,8 @@ class Asset extends Depreciable
|
||||||
'warranty_months' => 'nullable|numeric|digits_between:0,240',
|
'warranty_months' => 'nullable|numeric|digits_between:0,240',
|
||||||
'last_checkout' => 'nullable|date_format:Y-m-d H:i:s',
|
'last_checkout' => 'nullable|date_format:Y-m-d H:i:s',
|
||||||
'expected_checkin' => 'nullable|date',
|
'expected_checkin' => 'nullable|date',
|
||||||
|
'last_audit_date' => 'nullable|date_format:Y-m-d H:i:s',
|
||||||
|
'next_audit_date' => 'nullable|date|after:last_audit_date',
|
||||||
'location_id' => 'nullable|exists:locations,id',
|
'location_id' => 'nullable|exists:locations,id',
|
||||||
'rtd_location_id' => 'nullable|exists:locations,id',
|
'rtd_location_id' => 'nullable|exists:locations,id',
|
||||||
'purchase_date' => 'nullable|date|date_format:Y-m-d',
|
'purchase_date' => 'nullable|date|date_format:Y-m-d',
|
||||||
|
|
89
app/Models/Labels/Tapes/Dymo/Label_Writer_2112283.php
Normal file
89
app/Models/Labels/Tapes/Dymo/Label_Writer_2112283.php
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Labels\Tapes\Dymo;
|
||||||
|
|
||||||
|
|
||||||
|
class LabelWriter_2112283 extends LabelWriter
|
||||||
|
{
|
||||||
|
private const BARCODE_MARGIN = 1.80;
|
||||||
|
private const TAG_SIZE = 2.80;
|
||||||
|
private const TITLE_SIZE = 2.80;
|
||||||
|
private const TITLE_MARGIN = 0.50;
|
||||||
|
private const LABEL_SIZE = 2.80;
|
||||||
|
private const LABEL_MARGIN = - 0.35;
|
||||||
|
private const FIELD_SIZE = 2.80;
|
||||||
|
private const FIELD_MARGIN = 0.15;
|
||||||
|
|
||||||
|
public function getUnit() { return 'mm'; }
|
||||||
|
public function getWidth() { return 54; }
|
||||||
|
public function getHeight() { return 25; }
|
||||||
|
public function getSupportAssetTag() { return true; }
|
||||||
|
public function getSupport1DBarcode() { return true; }
|
||||||
|
public function getSupport2DBarcode() { return true; }
|
||||||
|
public function getSupportFields() { return 5; }
|
||||||
|
public function getSupportLogo() { return false; }
|
||||||
|
public function getSupportTitle() { return true; }
|
||||||
|
|
||||||
|
public function preparePDF($pdf) {}
|
||||||
|
|
||||||
|
public function write($pdf, $record) {
|
||||||
|
$pa = $this->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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -904,27 +904,18 @@
|
||||||
@endcan
|
@endcan
|
||||||
|
|
||||||
@can('delete', $asset)
|
@can('delete', $asset)
|
||||||
@if ($asset->deleted_at=='')
|
<div class="col-md-12" style="padding-top: 30px; padding-bottom: 30px;">
|
||||||
<div class="col-md-12" style="padding-top: 30px; padding-bottom: 30px;">
|
@if ($asset->deleted_at=='')
|
||||||
<button class="btn btn-block btn-danger delete-asset" data-toggle="modal" data-title="{{ trans('general.delete') }}" data-content="{{ trans('general.sure_to_delete', ['item' => $asset->asset_tag]) }}" data-target="#dataConfirmModal">{{ trans('general.delete') }} </button>
|
<button class="btn btn-sm btn-block btn-danger delete-asset" data-toggle="modal" data-title="{{ trans('general.delete') }}" data-content="{{ trans('general.sure_to_delete_var', ['item' => $asset->asset_tag]) }}" data-target="#dataConfirmModal">{{ trans('general.delete') }} </button>
|
||||||
<span class="sr-only">{{ trans('general.delete') }}</span>
|
<span class="sr-only">{{ trans('general.delete') }}</span>
|
||||||
</div>
|
@else
|
||||||
@endif
|
<form method="POST" action="{{ route('restore/hardware', ['assetId' => $asset->id]) }}">
|
||||||
|
@csrf
|
||||||
|
<button class="btn btn-sm btn-warning col-md-12">{{ trans('general.restore') }}</button>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
@endcan
|
@endcan
|
||||||
|
|
||||||
@if ($asset->deleted_at!='')
|
|
||||||
<div class="text-center col-md-12" style="padding-top: 30px; padding-bottom: 30px;">
|
|
||||||
<form method="POST" action="{{ route('restore/hardware', ['assetId' => $asset->id]) }}">
|
|
||||||
@csrf
|
|
||||||
<button class="btn btn-danger col-md-12">{{ trans('general.restore') }}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if ($snipeSettings->qr_code=='1')
|
|
||||||
<img src="{{ config('app.url') }}/hardware/{{ $asset->id }}/qr_code" class="img-thumbnail pull-right" style="height: 100px; width: 100px; margin-right: 10px;" alt="QR code for {{ $asset->getDisplayNameAttribute() }}">
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (($asset->assignedTo) && ($asset->deleted_at==''))
|
@if (($asset->assignedTo) && ($asset->deleted_at==''))
|
||||||
<div style="text-align: left">
|
<div style="text-align: left">
|
||||||
<h2>{{ trans('admin/hardware/form.checkedout_to') }}</h2>
|
<h2>{{ trans('admin/hardware/form.checkedout_to') }}</h2>
|
||||||
|
@ -982,6 +973,13 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@if ($snipeSettings->qr_code=='1')
|
||||||
|
<div class="col-md-12" style="padding-top: 15px;">
|
||||||
|
<img src="{{ config('app.url') }}/hardware/{{ $asset->id }}/qr_code" class="img-thumbnail pull-right" style="height: 100px; width: 100px; margin-right: 10px;" alt="QR code for {{ $asset->getDisplayNameAttribute() }}">
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
</div> <!-- div.col-md-4 -->
|
</div> <!-- div.col-md-4 -->
|
||||||
</div><!-- /row -->
|
</div><!-- /row -->
|
||||||
</div><!-- /.tab-pane asset details -->
|
</div><!-- /.tab-pane asset details -->
|
||||||
|
|
|
@ -236,6 +236,12 @@
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@if ($model->created_at)
|
||||||
|
<li>{{ trans('general.created_at') }}:
|
||||||
|
{{ Helper::getFormattedDateObject($model->created_at, 'datetime', false) }}
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if ($model->min_amt)
|
@if ($model->min_amt)
|
||||||
<li>{{ trans('general.min_amt') }}:
|
<li>{{ trans('general.min_amt') }}:
|
||||||
{{$model->min_amt }}
|
{{$model->min_amt }}
|
||||||
|
@ -313,11 +319,6 @@
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@if ($model->deleted_at!='')
|
|
||||||
<li><br /><a href="{{ route('models.restore.store', $model->id) }}" class="btn-flat large info ">{{ trans('admin/models/general.restore') }}</a></li>
|
|
||||||
@endif
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@if ($model->note)
|
@if ($model->note)
|
||||||
|
@ -337,22 +338,32 @@
|
||||||
|
|
||||||
@can('create', \App\Models\AssetModel::class)
|
@can('create', \App\Models\AssetModel::class)
|
||||||
<div class="col-md-12" style="padding-bottom: 5px;">
|
<div class="col-md-12" style="padding-bottom: 5px;">
|
||||||
<a href="{{ route('models.clone.create', $model->id) }}" style="width: 100%;" class="btn btn-sm btn-warning hidden-print">{{ trans('admin/models/table.clone') }}</a>
|
<a href="{{ route('models.clone.create', $model->id) }}" style="width: 100%;" class="btn btn-sm btn-primary hidden-print">{{ trans('admin/models/table.clone') }}</a>
|
||||||
</div>
|
</div>
|
||||||
@endcan
|
@endcan
|
||||||
|
|
||||||
@can('delete', \App\Models\AssetModel::class)
|
@can('delete', \App\Models\AssetModel::class)
|
||||||
@if ($model->assets_count > 0)
|
@if ($model->assets_count > 0)
|
||||||
|
|
||||||
<div class="col-md-12" style="padding-bottom: 5px;">
|
<div class="col-md-12" style="padding-bottom: 5px;">
|
||||||
<button class="btn btn-block btn-sm btn-danger hidden-print disabled" data-tooltip="true" data-placement="top" data-title="{{ trans('general.cannot_be_deleted') }}">{{ trans('general.delete') }}</button>
|
<button class="btn btn-block btn-sm btn-primary hidden-print disabled" data-tooltip="true" data-placement="top" data-title="{{ trans('general.cannot_be_deleted') }}">{{ trans('general.delete') }}</button>
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="col-md-12" style="padding-bottom: 10px;">
|
|
||||||
<button class="btn btn-block btn-danger delete-asset" data-toggle="modal" title="{{ trans('general.delete_what', ['item'=> trans('general.asset_model')]) }}" data-content="{{ trans('general.sure_to_delete_var', ['item' => $model->name]) }}" data-target="#dataConfirmModal" data-tooltip="true" data-placement="top" data-title="{{ trans('general.delete_what', ['item'=> trans('general.asset_model')]) }}">{{ trans('general.delete') }} </button>
|
|
||||||
<span class="sr-only">{{ trans('general.delete') }}</span>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
||||||
|
<div class="text-center col-md-12" style="padding-top: 30px; padding-bottom: 30px;">
|
||||||
|
@if ($model->deleted_at!='')
|
||||||
|
<form method="POST" action="{{ route('models.restore.store', $model->id) }}">
|
||||||
|
@csrf
|
||||||
|
<button style="width: 100%;" class="btn btn-sm btn-warning hidden-print">{{ trans('button.restore') }}</button>
|
||||||
|
</form>
|
||||||
|
@else
|
||||||
|
<button class="btn btn-block btn-sm btn-danger delete-asset" data-toggle="modal" title="{{ trans('general.delete_what', ['item'=> trans('general.asset_model')]) }}" data-content="{{ trans('general.sure_to_delete_var', ['item' => $model->name]) }}" data-target="#dataConfirmModal" data-tooltip="true" data-placement="top" data-title="{{ trans('general.delete_what', ['item'=> trans('general.asset_model')]) }}">{{ trans('general.delete') }} </button>
|
||||||
|
<span class="sr-only">{{ trans('general.delete') }}</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
@endcan
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- /.row -->
|
</div> <!-- /.row -->
|
||||||
|
|
|
@ -65,8 +65,7 @@ class AssetStoreTest extends TestCase
|
||||||
$this->assertEquals('random_string', $asset->asset_tag);
|
$this->assertEquals('random_string', $asset->asset_tag);
|
||||||
$this->assertEquals($userAssigned->id, $asset->assigned_to);
|
$this->assertEquals($userAssigned->id, $asset->assigned_to);
|
||||||
$this->assertTrue($asset->company->is($company));
|
$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 00:00:00', $asset->last_audit_date->format('Y-m-d H:i:s'));
|
||||||
// $this->assertEquals('2023-09-03', $asset->last_audit_date);
|
|
||||||
$this->assertTrue($asset->location->is($location));
|
$this->assertTrue($asset->location->is($location));
|
||||||
$this->assertTrue($asset->model->is($model));
|
$this->assertTrue($asset->model->is($model));
|
||||||
$this->assertEquals('A New Asset', $asset->name);
|
$this->assertEquals('A New Asset', $asset->name);
|
||||||
|
@ -82,6 +81,52 @@ class AssetStoreTest extends TestCase
|
||||||
$this->assertEquals(10, $asset->warranty_months);
|
$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 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 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()
|
public function testArchivedDepreciateAndPhysicalCanBeNull()
|
||||||
{
|
{
|
||||||
$model = AssetModel::factory()->ipadModel()->create();
|
$model = AssetModel::factory()->ipadModel()->create();
|
||||||
|
|
Loading…
Reference in a new issue