Moved checkbox
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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),
|
||||
|
||||
];
|
||||
|
||||
+30
@@ -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']);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user