Skip the initial checkout email to the recipient if sign_in_place was checked

This commit is contained in:
snipe
2026-04-14 19:49:05 +01:00
parent 18f67bcce5
commit 91e41049bd
7 changed files with 137 additions and 6 deletions
+4 -1
View File
@@ -22,12 +22,14 @@ class CheckoutableCheckedOut
public int $quantity;
public bool $signInPlace;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [], $quantity = 1)
public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [], $quantity = 1, bool $signInPlace = false)
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
@@ -35,5 +37,6 @@ class CheckoutableCheckedOut
$this->note = $note;
$this->originalValues = $originalValues;
$this->quantity = $quantity;
$this->signInPlace = $signInPlace;
}
}
@@ -130,7 +130,7 @@ class AssetCheckoutController extends Controller
'sign_in_place' => $request->boolean('sign_in_place'),
]);
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->input('note'), $request->input('name'))) {
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->input('note'), $request->input('name'), null, $request->boolean('sign_in_place'))) {
// When sign_in_place is requested and the target is a user, redirect to the
// acceptance/signature page so the user can sign in person. The signature is
@@ -117,6 +117,7 @@ class ConsumableCheckoutController extends Controller
$request->input('note'),
[],
$consumable->checkout_qty,
$request->boolean('sign_in_place'),
));
$request->request->add(['checkout_to_type' => 'user']);
@@ -187,7 +187,7 @@ class LicenseCheckoutController extends Controller
$licenseSeat->assigned_to = $target->assigned_to;
}
if ($licenseSeat->save()) {
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'), [], 1, request()->boolean('sign_in_place')));
return $target;
}
@@ -204,7 +204,7 @@ class LicenseCheckoutController extends Controller
$licenseSeat->assigned_to = request('assigned_to');
if ($licenseSeat->save()) {
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'), [], 1, request()->boolean('sign_in_place')));
return $target;
}
+14
View File
@@ -80,6 +80,11 @@ class CheckoutableListener
$shouldSendEmailToAlertAddress = $this->shouldSendEmailToAlertAddress($acceptance);
$shouldSendWebhookNotification = $this->shouldSendWebhookNotification();
if ($this->shouldSkipInitialAcceptanceEmail($event, $acceptance)) {
$shouldSendEmailToUser = false;
$shouldSendEmailToAlertAddress = false;
}
if (! $shouldSendEmailToUser && ! $shouldSendEmailToAlertAddress && ! $shouldSendWebhookNotification) {
return;
}
@@ -480,6 +485,15 @@ class CheckoutableListener
return false;
}
private function shouldSkipInitialAcceptanceEmail(CheckoutableCheckedOut $event, ?CheckoutAcceptance $acceptance): bool
{
if (! $event->signInPlace) {
return false;
}
return ($acceptance instanceof CheckoutAcceptance) || ! empty($event->checkoutable->getEula());
}
private function shouldSendEmailToAlertAddress($acceptance = null): bool
{
if (Context::get('action') === 'bulk_asset_checkout') {
+2 -2
View File
@@ -516,7 +516,7 @@ class Asset extends Depreciable
*
* @return bool
*/
public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null)
public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null, bool $signInPlace = false)
{
if (! $target) {
return false;
@@ -560,7 +560,7 @@ class Asset extends Depreciable
} else {
$checkedOutBy = auth()->user();
}
event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note, $originalValues));
event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note, $originalValues, 1, $signInPlace));
$this->increment('checkout_counter', 1);
@@ -0,0 +1,113 @@
<?php
namespace Tests\Feature\Notifications\Email;
use App\Mail\CheckoutAssetMail;
use App\Mail\CheckoutConsumableMail;
use App\Mail\CheckoutLicenseMail;
use App\Models\Asset;
use App\Models\AssetModel;
use App\Models\Category;
use App\Models\CheckoutAcceptance;
use App\Models\Consumable;
use App\Models\LicenseSeat;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use PHPUnit\Framework\Attributes\Group;
use Tests\TestCase;
#[Group('notifications')]
class SignInPlaceCheckoutEmailSuppressionTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
Mail::fake();
}
public function test_asset_checkout_does_not_send_initial_acceptance_email_when_sign_in_place_is_selected(): void
{
$targetUser = User::factory()->create();
$category = Category::factory()
->forAssets()
->doesNotRequireAcceptance()
->doesNotSendCheckinEmail()
->hasLocalEula()
->create();
$asset = Asset::factory()
->for(AssetModel::factory()->for($category, 'category'), 'model')
->create();
$response = $this->actingAs(User::factory()->admin()->create())
->post(route('hardware.checkout.store', $asset), [
'checkout_to_type' => 'user',
'assigned_user' => $targetUser->id,
'redirect_option' => 'index',
'sign_in_place' => 1,
]);
$acceptance = CheckoutAcceptance::query()
->where('checkoutable_type', Asset::class)
->where('checkoutable_id', $asset->id)
->where('assigned_to_id', $targetUser->id)
->pending()
->latest()
->first();
$this->assertNotNull($acceptance);
$response->assertRedirect(route('account.accept.item', $acceptance));
Mail::assertNotSent(CheckoutAssetMail::class);
}
public function test_consumable_checkout_does_not_send_initial_acceptance_email_when_sign_in_place_is_selected(): void
{
$targetUser = User::factory()->create();
$consumable = Consumable::factory()->requiringAcceptance()->create();
$response = $this->actingAs(User::factory()->admin()->create())
->post(route('consumables.checkout.store', $consumable), [
'assigned_to' => $targetUser->id,
'redirect_option' => 'index',
'checkout_qty' => 2,
'sign_in_place' => 1,
]);
$acceptance = CheckoutAcceptance::query()
->where('checkoutable_type', Consumable::class)
->where('checkoutable_id', $consumable->id)
->where('assigned_to_id', $targetUser->id)
->pending()
->latest()
->first();
$this->assertNotNull($acceptance);
$response->assertRedirect(route('account.accept.item', $acceptance));
Mail::assertNotSent(CheckoutConsumableMail::class);
}
public function test_license_checkout_does_not_send_initial_acceptance_email_when_sign_in_place_is_selected(): void
{
$targetUser = User::factory()->create();
$seat = LicenseSeat::factory()->requiringAcceptance()->create();
$response = $this->actingAs(User::factory()->admin()->create())
->post(route('licenses.checkout', $seat->license), [
'assigned_to' => $targetUser->id,
'redirect_option' => 'index',
'sign_in_place' => 1,
]);
$acceptance = CheckoutAcceptance::query()
->where('checkoutable_type', LicenseSeat::class)
->where('assigned_to_id', $targetUser->id)
->pending()
->latest()
->first();
$this->assertNotNull($acceptance);
$response->assertRedirect(route('account.accept.item', $acceptance));
Mail::assertNotSent(CheckoutLicenseMail::class);
}
}