Moved checkbox

This commit is contained in:
snipe
2026-04-29 16:06:44 +01:00
parent ead0047629
commit 75a276d9fa
12 changed files with 240 additions and 84 deletions
@@ -36,7 +36,8 @@ class AcceptanceController extends Controller
*/
public function index(): View
{
$acceptances = CheckoutAcceptance::forUser(auth()->user())->pending()->get();
$user = auth()->user();
$acceptances = CheckoutAcceptance::forUser($user)->pending()->get();
return view('account/accept.index', compact('acceptances'));
}
@@ -229,15 +230,21 @@ class AcceptanceController extends Controller
}
if ($request->input('asset_acceptance') === 'accepted') {
$pdf_filename = 'accepted-'.$acceptance->checkoutable_id.'-'.$acceptance->display_checkoutable_type.'-eula-'.date('Y-m-d-h-i-s').'.pdf';
// Generate the PDF content
$pdf_content = $acceptance->generateAcceptancePdf($data, $acceptance);
Storage::put('private_uploads/eula-pdfs/'.$pdf_filename, $pdf_content);
// Set sign_in_place fields if this is a sign-in-place admin flow
if ($isSignInPlaceAdminFlow) {
$acceptance->signed_in_place = true;
$acceptance->signed_in_place_admin = $currentUser->id;
$acceptance->save();
}
// Log the acceptance
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
$accept_qty = $request->input('accept_qty', $acceptance->qty ?? 1);
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'), $accept_qty);
// Send the PDF to the signing user
if (($request->input('send_copy') === '1') && ($assignedUser->email !== '')) {
@@ -89,14 +89,14 @@ class ConsumableCheckoutController extends Controller
// Update the consumable data
$consumable->assigned_to = e($request->input('assigned_to'));
for ($i = 0; $i < $quantity; $i++) {
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'created_by' => $admin_user->id,
'assigned_to' => e($request->input('assigned_to')),
'note' => $request->input('note'),
]);
}
// Attach the consumable to the user ONCE with the correct qty and note
$consumable->users()->attach($consumable->id, [
'consumable_id' => $consumable->id,
'created_by' => $admin_user->id,
'assigned_to' => $assigned_to,
'note' => $request->input('note'),
'qty' => $quantity,
]);
$consumable->checkout_qty = $quantity;
+15
View File
@@ -23,6 +23,21 @@ class CheckoutAcceptance extends Model
'alert_on_response_id' => 'integer',
];
protected $fillable = [
'assigned_to_id',
'checkoutable_type',
'checkoutable_id',
'accepted_at',
'declined_at',
'note',
'signature_filename',
'stored_eula',
'stored_eula_file',
'qty',
'signed_in_place',
'signed_in_place_admin',
];
/**
* Get the mail recipient from the config
*
+3 -5
View File
@@ -525,14 +525,13 @@ class Consumable extends SnipeModel
// Attach the consumable to the user if not already attached
$pivot = $acceptedBy->consumables()->where('consumable_id', $this->id)->first();
if (!$pivot) {
if (! $pivot) {
$acceptedBy->consumables()->attach($this->id, [
'created_by' => $acceptance?->created_by ?? null,
]);
}
// Log the acceptance action
$this->logActionAcceptance('accepted', $acceptedBy, $acceptance?->qty ?? 1, $acceptance?->note);
// Logging handled by event listener; do not log here to avoid duplicates.
}
/**
@@ -556,8 +555,7 @@ class Consumable extends SnipeModel
// Detach the consumable from the user (if present)
$declinedBy->consumables()->detach($this->id);
// Log the decline action
$this->logActionAcceptance('declined', $declinedBy, $qty, $note);
// Logging handled by event listener; do not log here to avoid duplicates.
}
/**
+8
View File
@@ -546,4 +546,12 @@ return [
*/
'always_send_email' => env('ALWAYS_SEND_EMAIL', false),
/*
|--------------------------------------------------------------------------
| Always Send EULA
|--------------------------------------------------------------------------
| If true, the EULA will always be sent and the checkbox will be hidden.
*/
'always_send_eula' => env('ALWAYS_SEND_EULA', false),
];
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('checkout_acceptances', function (Blueprint $table) {
$table->boolean('signed_in_place')->default(false)->after('declined_at');
$table->unsignedBigInteger('signed_in_place_admin')->nullable()->after('signed_in_place');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('checkout_acceptances', function (Blueprint $table) {
$table->dropColumn(['signed_in_place', 'signed_in_place_admin']);
});
}
};
+1
View File
@@ -590,6 +590,7 @@ return [
'address2' => 'Address Line 2',
'import_note' => 'Imported using csv importer',
],
'acceptance_email_always_sent' => 'An email will be sent to the accepting user automatically.',
'remove_customfield_association' => 'Remove this field from the fieldset. This will not delete the custom field, only this field\'s association with this fieldset.',
'checked_out_to_fields' => 'Checked Out To Fields',
'percent_complete' => '% complete',
@@ -125,12 +125,19 @@
<div class="row">
<div class="col-md-7">
@if ($acceptance->assignedTo?->email)
<div class="col-md-12" style="display: none;" id="showEmailBox">
<label class="form-control">
<input type="checkbox" value="1" name="send_copy" id="send_copy" checked="checked" aria-label="send_copy">
{{ trans('mail.send_pdf_copy') }} ({{ $acceptance->assignedTo->email }})
</label>
</div>
@if (config('app.always_send_email')!='true')
<div class="col-md-12">
{{ trans('general.acceptance_email_always_sent') }}
({{ $acceptance->assignedTo->email }})
</div>
@else
<div class="col-md-12" style="display: none;" id="showEmailBox">
<label class="form-control">
<input type="checkbox" value="1" name="send_copy" id="send_copy" checked="checked" aria-label="send_copy">
{{ trans('mail.send_pdf_copy') }} ({{ $acceptance->assignedTo->email }})
</label>
</div>
@endif
@endif
</div>
<div class="col-md-5 text-right">
+73 -61
View File
@@ -10,7 +10,7 @@
@section('content')
<div class="row">
<div class="col-md-9">
<div class="col-md-6 col-md-offset-3">
<form class="form-horizontal" id="checkout_form" method="post" action="" autocomplete="off">
<!-- CSRF Token -->
@@ -81,71 +81,83 @@
<!-- User -->
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_to', 'required'=> 'true'])
@if ($consumable->requireAcceptance() || (string) $snipeSettings->require_accept_signature === '1' || $consumable->getEula() || ($snipeSettings->webhook_endpoint!=''))
<div class="form-group notification-callout">
<div class="col-md-8 col-md-offset-3">
<div class="callout callout-info">
@if ($consumable->category->require_acceptance=='1')
<i class="far fa-envelope"></i>
{{ trans('admin/categories/general.required_acceptance') }}
<br>
@endif
@if ($consumable->getEula())
<i class="far fa-envelope"></i>
{{ trans('admin/categories/general.required_eula') }}
<br>
@endif
@if (($consumable->category) && ($consumable->category->checkin_email))
<i class="far fa-envelope"></i>
{{ trans('admin/categories/general.checkin_email_notification') }}
<br>
@endif
@if ($snipeSettings->webhook_endpoint!='')
<i class="fab fa-slack"></i>
{{ trans('general.webhook_msg_note') }}
@endif
<!-- Checkout QTY -->
<div class="form-group {{ $errors->has('qty') ? 'error' : '' }} ">
<label for="qty" class="col-md-3 control-label">{{ trans('general.qty') }}</label>
<div class="col-md-7 col-sm-12 required">
<div class="col-md-2" style="padding-left:0px">
<input class="form-control" type="number" name="checkout_qty" id="checkout_qty" value="1" min="1" max="{{$consumable->numRemaining()}}" maxlength="999999"/>
</div>
</div>
</div>
<!-- Sign in place checkbox -->
@if ($consumable->requireAcceptance() || (string) $snipeSettings->require_accept_signature === '1')
<div id="sign_in_place_div" class="col-md-7 col-md-offset-3">
<label class="form-control">
<input type="checkbox" value="1" name="sign_in_place" @checked(old('sign_in_place', session('sign_in_place', false))) aria-label="sign_in_place">
{{ trans('general.sign_in_place') }}
</label>
<p class="help-block">
{{ trans('general.sign_in_place_help') }}
</p>
</div>
@endif
{!! $errors->first('qty', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span></div>') !!}
</div>
@endif
<!-- Checkout QTY -->
<div class="form-group {{ $errors->has('qty') ? 'error' : '' }} ">
<label for="qty" class="col-md-3 control-label">{{ trans('general.qty') }}</label>
<div class="col-md-7 col-sm-12 required">
<div class="col-md-2" style="padding-left:0px">
<input class="form-control" type="number" name="checkout_qty" id="checkout_qty" value="1" min="1" max="{{$consumable->numRemaining()}}" maxlength="999999" />
<!-- Note -->
<div class="form-group {{ $errors->has('note') ? 'error' : '' }}">
<label for="note" class="col-md-3 control-label">{{ trans('admin/hardware/form.notes') }}</label>
<div class="col-md-7">
<textarea class="col-md-6 form-control" name="note">{{ old('note') }}</textarea>
{!! $errors->first('note', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>
{!! $errors->first('qty', '<div class="col-md-8 col-md-offset-3"><span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span></div>') !!}
</div>
<!-- Note -->
<div class="form-group {{ $errors->has('note') ? 'error' : '' }}">
<label for="note" class="col-md-3 control-label">{{ trans('admin/hardware/form.notes') }}</label>
<div class="col-md-7">
<textarea class="col-md-6 form-control" name="note">{{ old('note') }}</textarea>
{!! $errors->first('note', '<span class="alert-msg" aria-hidden="true"><i class="fas fa-times" aria-hidden="true"></i> :message</span>') !!}
</div>
</div>
@if ($consumable->requireAcceptance() || (string) $snipeSettings->require_accept_signature === '1' || $consumable->getEula() || ($snipeSettings->webhook_endpoint!=''))
<div class="form-group notification-callout">
<div class="col-md-8 col-md-offset-3">
<div class="callout callout-info">
@if ($consumable->category->require_acceptance=='1')
<i class="far fa-envelope"></i>
{{ trans('admin/categories/general.required_acceptance') }}
<br>
@endif
@if ($consumable->getEula())
<i class="far fa-envelope"></i>
{{ trans('admin/categories/general.required_eula') }}
<br>
@endif
@if (($consumable->category) && ($consumable->category->checkin_email))
<i class="far fa-envelope"></i>
{{ trans('admin/categories/general.checkin_email_notification') }}
<br>
@endif
@if ($snipeSettings->webhook_endpoint!='')
<i class="fab fa-slack"></i>
{{ trans('general.webhook_msg_note') }}
@endif
</div>
</div>
<!-- EULA/email checkbox or info message -->
@if ($consumable->getEula())
<div class="col-md-8 col-md-offset-3">
<label class="form-control">
<input type="checkbox" value="1" name="send_eula_copy" id="send_eula_copy" checked="checked" aria-label="send_eula_copy">
{{ trans('mail.send_pdf_copy') }}
</label>
</div>
@endif
<!-- Sign in place checkbox -->
@if ($consumable->requireAcceptance() || (string) $snipeSettings->require_accept_signature === '1')
<div id="sign_in_place_div" class="col-md-7 col-md-offset-3">
<label class="form-control">
<input type="checkbox" value="1" name="sign_in_place" @checked(old('sign_in_place', session('sign_in_place', false))) aria-label="sign_in_place">
{{ trans('general.sign_in_place') }}
</label>
<p class="help-block">
{{ trans('general.sign_in_place_help') }}
</p>
</div>
@endif
</div>
@endif
</div> <!-- .box-body -->
<x-redirect_submit_options
index_route="consumables.index"
@@ -235,4 +235,30 @@ class AccessoryAcceptanceTest extends TestCase
$this->assertNotNull($checkoutAcceptance->refresh()->accepted_at);
}
public function test_acceptance_create_page_shows_email_info_when_always_send_email_enabled()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
config(['app.always_send_email' => true]);
$response = $this->actingAs($checkoutAcceptance->assignedTo)
->get(route('account.accept.item', $checkoutAcceptance));
$response->assertOk();
$response->assertSee(trans('general.acceptance_email_always_sent'), false);
$response->assertDontSee(trans('mail.send_pdf_copy'), false);
}
public function test_acceptance_create_page_shows_checkbox_when_always_send_email_disabled()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
config(['app.always_send_email' => false]);
$response = $this->actingAs($checkoutAcceptance->assignedTo)
->get(route('account.accept.item', $checkoutAcceptance));
$response->assertOk();
$response->assertSee(trans('mail.send_pdf_copy'), false);
$response->assertDontSee(trans('general.acceptance_email_always_sent'), false);
}
}
@@ -320,4 +320,30 @@ class AssetAcceptanceTest extends TestCase
->assertDontSee(route('users.show', $assignee), false)
->assertDontSee(route('hardware.checkout.create', $asset), false);
}
public function test_acceptance_create_page_shows_email_info_when_always_send_email_enabled()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
config(['app.always_send_email' => true]);
$response = $this->actingAs($checkoutAcceptance->assignedTo)
->get(route('account.accept.item', $checkoutAcceptance));
$response->assertOk();
$response->assertSee(trans('general.acceptance_email_always_sent'), false);
$response->assertDontSee(trans('mail.send_pdf_copy'), false);
}
public function test_acceptance_create_page_shows_checkbox_when_always_send_email_disabled()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
config(['app.always_send_email' => false]);
$response = $this->actingAs($checkoutAcceptance->assignedTo)
->get(route('account.accept.item', $checkoutAcceptance));
$response->assertOk();
$response->assertSee(trans('mail.send_pdf_copy'), false);
$response->assertDontSee(trans('general.acceptance_email_always_sent'), false);
}
}
@@ -74,4 +74,30 @@ class ConsumableAcceptanceTest extends TestCase
'quantity' => 2,
]);
}
public function test_acceptance_create_page_shows_email_info_when_always_send_email_enabled()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
config(['app.always_send_email' => true]);
$response = $this->actingAs($checkoutAcceptance->assignedTo)
->get(route('account.accept.item', $checkoutAcceptance));
$response->assertOk();
$response->assertSee(trans('general.acceptance_email_always_sent'), false);
$response->assertDontSee(trans('mail.send_pdf_copy'), false);
}
public function test_acceptance_create_page_shows_checkbox_when_always_send_email_disabled()
{
$checkoutAcceptance = CheckoutAcceptance::factory()->pending()->create();
config(['app.always_send_email' => false]);
$response = $this->actingAs($checkoutAcceptance->assignedTo)
->get(route('account.accept.item', $checkoutAcceptance));
$response->assertOk();
$response->assertSee(trans('mail.send_pdf_copy'), false);
$response->assertDontSee(trans('general.acceptance_email_always_sent'), false);
}
}