diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php index 7644488a89..645e2624b2 100644 --- a/app/Http/Controllers/Account/AcceptanceController.php +++ b/app/Http/Controllers/Account/AcceptanceController.php @@ -121,7 +121,6 @@ class AcceptanceController extends Controller $pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf'; $sig_filename=''; - if ($request->input('asset_acceptance') == 'accepted') { /** @@ -153,7 +152,6 @@ class AcceptanceController extends Controller } } - // this is horrible switch($acceptance->checkoutable_type){ case 'App\Models\Asset': @@ -170,7 +168,7 @@ class AcceptanceController extends Controller $pdf_view_route ='account.accept.accept-accessory-eula'; $accessory = Accessory::find($item->id); $display_model = $accessory->name; - $assigned_to = User::find($item->assignedTo); + $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; case 'App\Models\LicenseSeat': @@ -253,11 +251,15 @@ class AcceptanceController extends Controller // This is the most horriblest switch($acceptance->checkoutable_type){ case 'App\Models\Asset': + $asset_model = AssetModel::find($item->model_id); + $display_model = $asset_model->name; $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; case 'App\Models\Accessory': - $assigned_to = User::find($item->assignedTo); + $accessory = Accessory::find($item->id); + $display_model = $accessory->name; + $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; case 'App\Models\LicenseSeat': @@ -269,6 +271,8 @@ class AcceptanceController extends Controller break; case 'App\Models\Consumable': + $consumable = Consumable::find($item->id); + $display_model = $consumable->name; $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; } @@ -292,4 +296,4 @@ class AcceptanceController extends Controller return redirect()->to('account/accept')->with('success', $return_msg); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 6898ccc2ea..ced1f013c6 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -573,9 +573,6 @@ class AssetsController extends Controller // Update custom fields in the database. // Validation for these fields is handled through the AssetRequest form request $model = AssetModel::find($request->get('model_id')); - if (!$model) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/models/message.does_not_exist')), 200); - } if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { diff --git a/app/Http/Livewire/Importer.php b/app/Http/Livewire/Importer.php index e11dd060e9..7a37b00d18 100644 --- a/app/Http/Livewire/Importer.php +++ b/app/Http/Livewire/Importer.php @@ -67,7 +67,6 @@ class Importer extends Component 'location' => 'Location', 'maintained' => 'Maintained', 'manufacturer' => 'Manufacturer', - 'notes' => 'Notes', 'order_number' => 'Order Number', 'purchase_cost' => 'Purchase Cost', 'purchase_date' => 'Purchase Date', @@ -81,11 +80,14 @@ class Importer extends Component static $accessories = [ 'model_number' => 'Model Number', + 'notes' => 'Notes', ]; static $assets = [ 'asset_tag' => 'Asset Tag', 'asset_model' => 'Model Name', + 'asset_notes' => 'Asset Notes', + 'model_notes' => 'Model Notes', 'byod' => 'BYOD', 'checkout_class' => 'Checkout Type', 'checkout_location' => 'Checkout Location', @@ -99,6 +101,7 @@ class Importer extends Component static $consumables = [ 'item_no' => "Item Number", 'model_number' => "Model Number", + 'notes' => 'Notes', 'min_amt' => "Minimum Quantity", ]; @@ -111,12 +114,14 @@ class Importer extends Component 'purchase_order' => 'Purchase Order', 'reassignable' => 'Reassignable', 'seats' => 'Seats', + 'notes' => 'Notes', ]; static $users = [ 'employee_num' => 'Employee Number', 'first_name' => 'First Name', 'last_name' => 'Last Name', + 'notes' => 'Notes', 'jobtitle' => 'Job Title', 'phone_number' => 'Phone Number', 'manager_first_name' => 'Manager First Name', @@ -144,6 +149,7 @@ class Importer extends Component 'manager_username' => 'Manager Username', 'manager' => 'Manager', 'parent_location' => 'Parent Location', + 'notes' => 'Notes', ]; //array of "real fieldnames" to a list of aliases for that field diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 8c92f8c78e..ac431253bc 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -90,7 +90,7 @@ class Asset extends Depreciable protected $rules = [ 'name' => 'max:255|nullable', - 'model_id' => 'required|integer|exists:models,id', + 'model_id' => 'required|integer|exists:models,id,deleted_at,NULL', 'status_id' => 'required|integer|exists:status_labels,id', 'company_id' => 'integer|nullable', 'warranty_months' => 'numeric|nullable|digits_between:0,240', diff --git a/app/Models/CheckoutAcceptance.php b/app/Models/CheckoutAcceptance.php index c3c34b0571..4a4360c40a 100644 --- a/app/Models/CheckoutAcceptance.php +++ b/app/Models/CheckoutAcceptance.php @@ -3,13 +3,14 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Notifications\Notifiable; class CheckoutAcceptance extends Model { - use SoftDeletes, Notifiable; + use HasFactory, SoftDeletes, Notifiable; protected $casts = [ 'accepted_at' => 'datetime', diff --git a/database/factories/CheckoutAcceptanceFactory.php b/database/factories/CheckoutAcceptanceFactory.php new file mode 100644 index 0000000000..b5744527f8 --- /dev/null +++ b/database/factories/CheckoutAcceptanceFactory.php @@ -0,0 +1,41 @@ + Asset::class, + 'checkoutable_id' => Asset::factory(), + 'assigned_to_id' => User::factory(), + ]; + } + + public function forAccessory() + { + return $this->state([ + 'checkoutable_type' => Accessory::class, + 'checkoutable_id' => Accessory::factory(), + ]); + } + + public function pending() + { + return $this->state([ + 'accepted_at' => null, + 'declined_at' => null, + ]); + } +} diff --git a/resources/views/notifications/markdown/asset-acceptance.blade.php b/resources/views/notifications/markdown/asset-acceptance.blade.php index 5616525b13..50191d4a37 100644 --- a/resources/views/notifications/markdown/asset-acceptance.blade.php +++ b/resources/views/notifications/markdown/asset-acceptance.blade.php @@ -11,7 +11,7 @@ | **{{ ucfirst(trans('general.accepted')) }}** | {{ $accepted_date }} | @endif @if (isset($declined_date)) -| **{{ trans('general.declined') }}** | {{ $declined_date }} | +| **{{ ucfirst(trans('general.declined')) }}** | {{ $declined_date }} | @endif @if ((isset($item_tag)) && ($item_tag!='')) | **{{ trans('mail.asset_tag') }}** | {{ $item_tag }} | diff --git a/routes/web.php b/routes/web.php index 4644f41ffb..39c66d35d8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -291,7 +291,8 @@ Route::group(['prefix' => 'account', 'middleware' => ['auth']], function () { Route::get('accept/{id}', [Account\AcceptanceController::class, 'create']) ->name('account.accept.item'); - Route::post('accept/{id}', [Account\AcceptanceController::class, 'store']); + Route::post('accept/{id}', [Account\AcceptanceController::class, 'store']) + ->name('account.store-acceptance'); Route::get( 'print', diff --git a/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php b/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php new file mode 100644 index 0000000000..a49b1167cb --- /dev/null +++ b/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php @@ -0,0 +1,82 @@ +settings->enableAlertEmail(); + + $acceptance = CheckoutAcceptance::factory() + ->pending() + ->for(Accessory::factory()->appleMouse(), 'checkoutable') + ->create(); + + $this->actingAs($acceptance->assignedTo) + ->post(route('account.store-acceptance', $acceptance), ['asset_acceptance' => 'accepted']) + ->assertSessionHasNoErrors(); + + $this->assertNotNull($acceptance->fresh()->accepted_at); + + Notification::assertSentTo( + $acceptance, + function (AcceptanceAssetAcceptedNotification $notification) use ($acceptance) { + $this->assertStringContainsString( + $acceptance->assignedTo->present()->fullName, + $notification->toMail()->render() + ); + + return true; + } + ); + } + + /** + * This can be absorbed into a bigger test + */ + public function testUsersNameIsIncludedInAccessoryDeclinedNotification() + { + Notification::fake(); + + $this->settings->enableAlertEmail(); + + $acceptance = CheckoutAcceptance::factory() + ->pending() + ->for(Accessory::factory()->appleMouse(), 'checkoutable') + ->create(); + + $this->actingAs($acceptance->assignedTo) + ->post(route('account.store-acceptance', $acceptance), ['asset_acceptance' => 'declined']) + ->assertSessionHasNoErrors(); + + $this->assertNotNull($acceptance->fresh()->declined_at); + + Notification::assertSentTo( + $acceptance, + function (AcceptanceAssetDeclinedNotification $notification) use ($acceptance) { + $this->assertStringContainsString( + $acceptance->assignedTo->present()->fullName, + $notification->toMail($acceptance)->render() + ); + + return true; + } + ); + } +} diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 9d4209da79..70022e53c3 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -18,6 +18,16 @@ class Settings return new self(); } + public function enableAlertEmail(string $email = 'notifications@afcrichmond.com'): Settings + { + return $this->update(['alert_email' => $email]); + } + + public function disableAlertEmail(): Settings + { + return $this->update(['alert_email' => null]); + } + public function enableMultipleFullCompanySupport(): Settings { return $this->update(['full_multiple_companies_support' => 1]);