Merge pull request #17703 from marcusmoore/17369-accessory-checkout-qty-scaffold
Fixed issues around accessory acceptance
This commit is contained in:
@@ -233,6 +233,7 @@ class AcceptanceController extends Controller
|
||||
'logo' => $path_logo,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
'admin' => auth()->user()->present()?->fullName,
|
||||
'qty' => $acceptance->qty ?? 1,
|
||||
];
|
||||
|
||||
if ($pdf_view_route!='') {
|
||||
@@ -338,6 +339,7 @@ class AcceptanceController extends Controller
|
||||
'assigned_to' => $assigned_to,
|
||||
'company_name' => $branding_settings->site_name,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
'qty' => $acceptance->qty ?? 1,
|
||||
];
|
||||
|
||||
if ($pdf_view_route!='') {
|
||||
@@ -346,7 +348,10 @@ class AcceptanceController extends Controller
|
||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||
}
|
||||
|
||||
$acceptance->decline($sig_filename, $request->input('note'));
|
||||
for ($i = 0; $i < ($acceptance->qty ?? 1); $i++) {
|
||||
$acceptance->decline($sig_filename, $request->input('note'));
|
||||
}
|
||||
|
||||
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
||||
Log::debug('New event acceptance.');
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
|
||||
@@ -242,6 +242,12 @@ class CheckoutableListener
|
||||
$acceptance->checkoutable()->associate($event->checkoutable);
|
||||
$acceptance->assignedTo()->associate($event->checkedOutTo);
|
||||
|
||||
$acceptance->qty = 1;
|
||||
|
||||
if (isset($event->checkoutable->checkout_qty)) {
|
||||
$acceptance->qty = $event->checkoutable->checkout_qty;
|
||||
}
|
||||
|
||||
$category = $this->getCategoryFromCheckoutable($event->checkoutable);
|
||||
|
||||
if ($category?->alert_on_response) {
|
||||
|
||||
@@ -148,4 +148,9 @@ class CheckoutAcceptance extends Model
|
||||
{
|
||||
return $query->whereNull('accepted_at')->whereNull('declined_at');
|
||||
}
|
||||
|
||||
public function scopeDeclined(Builder $query)
|
||||
{
|
||||
return $query->whereNull('accepted_at')->whereNotNull('declined_at');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->admin = $params['admin'] ?? null;
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->qty = $params['qty'] ?? null;
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +73,7 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
||||
'accepted_date' => $this->accepted_date,
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'intro_text' => trans('mail.acceptance_asset_accepted'),
|
||||
'admin' => $this->admin,
|
||||
])
|
||||
|
||||
@@ -29,7 +29,7 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->file = $params['file'] ?? null;
|
||||
|
||||
$this->qty = $params['qty'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,6 +66,7 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification
|
||||
'accepted_date' => $this->accepted_date,
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'intro_text' => trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->company_name ?? $this->settings->site_name]),
|
||||
])
|
||||
->attach($pdf_path)
|
||||
|
||||
@@ -30,6 +30,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
|
||||
$this->assigned_to = $params['assigned_to'];
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->qty = $params['qty'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,6 +70,7 @@ class AcceptanceAssetDeclinedNotification extends Notification
|
||||
'declined_date' => $this->declined_date,
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'qty' => $this->qty,
|
||||
'intro_text' => trans('mail.acceptance_asset_declined'),
|
||||
])
|
||||
->subject(trans('mail.acceptance_asset_declined'));
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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::whenTableDoesntHaveColumn('checkout_acceptances', 'qty', function () {
|
||||
Schema::table('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->unsignedInteger('qty')->nullable()->after('assigned_to_id')->default(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::whenTableHasColumn('checkout_acceptances', 'qty', function () {
|
||||
Schema::table('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->dropColumn('qty');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -353,9 +353,11 @@ return [
|
||||
'audit_overdue' => 'Overdue for Audit',
|
||||
'accept' => 'Accept :asset',
|
||||
'i_accept' => 'I accept',
|
||||
'i_decline_item' => 'Decline this item',
|
||||
'i_accept_item' => 'Accept this item',
|
||||
'i_accept_with_count' => 'I accept :count item|I accept :count items',
|
||||
'i_decline_item' => 'Decline this item|Decline these items',
|
||||
'i_accept_item' => 'Accept this item|Accept these items',
|
||||
'i_decline' => 'I decline',
|
||||
'i_decline_with_count' => 'I decline :count item|I decline :count items',
|
||||
'accept_decline' => 'Accept/Decline',
|
||||
'sign_tos' => 'Sign below to indicate that you agree to the terms of service:',
|
||||
'clear_signature' => 'Clear Signature',
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<p>
|
||||
{{ trans('general.date') }}: {{ date($date_settings) }} <br>
|
||||
{{ trans('general.asset_model') }}: {{ $item_model }}<br>
|
||||
{{ trans('general.quantity') }}: {{ $qty }}
|
||||
</p>
|
||||
|
||||
@if ($eula)
|
||||
@@ -44,4 +45,4 @@
|
||||
<img src="{{ $signature }}" style="max-width: 600px; border-bottom: black solid 1px;">
|
||||
@endif
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -38,8 +38,13 @@
|
||||
<div class="panel box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h2 class="box-title">
|
||||
{{ $acceptance->checkoutable->display_name }}
|
||||
{{ (($acceptance->checkoutable) && ($acceptance->checkoutable->serial)) ? ' - '.trans('general.serial_number').': '.$acceptance->checkoutable->serial : '' }}
|
||||
<div>
|
||||
{{ $acceptance->checkoutable->display_name }}
|
||||
@if ($acceptance->qty > 1)
|
||||
<strong>×{{ $acceptance->qty }}</strong>
|
||||
@endif
|
||||
</div>
|
||||
<div>{{ (($acceptance->checkoutable) && ($acceptance->checkoutable->serial)) ? trans('general.serial_number').': '.$acceptance->checkoutable->serial : '' }}</div>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
@@ -53,11 +58,19 @@
|
||||
<div class="col-md-12">
|
||||
<label class="form-control">
|
||||
<input type="radio" name="asset_acceptance" id="accepted" value="accepted">
|
||||
{{trans('general.i_accept')}}
|
||||
@if ($acceptance->qty)
|
||||
{{trans_choice('general.i_accept_with_count', $acceptance->qty)}}
|
||||
@else
|
||||
{{trans('general.i_accept')}}
|
||||
@endif
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<input type="radio" name="asset_acceptance" id="declined" value="declined">
|
||||
{{trans('general.i_decline')}}
|
||||
@if ($acceptance->qty)
|
||||
{{trans_choice('general.i_decline_with_count', $acceptance->qty)}}
|
||||
@else
|
||||
{{trans('general.i_decline')}}
|
||||
@endif
|
||||
</label>
|
||||
|
||||
</div>
|
||||
@@ -98,7 +111,7 @@
|
||||
<button type="submit" class="btn btn-success" id="submit-button">
|
||||
<i class="fa fa-check icon-white" aria-hidden="true" id="submitIcon"></i>
|
||||
<span id="buttonText">
|
||||
{{ trans('general.i_accept_item') }}
|
||||
{{ trans_choice('general.i_accept_item', $acceptance->qty ?? null) }}
|
||||
</span>
|
||||
</button>
|
||||
</div><!-- /.box-footer -->
|
||||
@@ -161,7 +174,7 @@
|
||||
$("#showSubmit").show();
|
||||
$("#submit-button").removeClass("btn-success").addClass("btn-danger").show();
|
||||
$("#submitIcon").removeClass("fa-check").addClass("fa-times");
|
||||
$("#buttonText").text('{{ trans('general.i_decline_item') }}');
|
||||
$("#buttonText").text('{{ trans_choice('general.i_decline_item', $acceptance->qty ?? 1) }}');
|
||||
$("#note").prop('required', true);
|
||||
|
||||
} else if ($(this).is(':checked') && $(this).attr('id') === 'accepted') {
|
||||
@@ -169,16 +182,9 @@
|
||||
$("#showSubmit").show();
|
||||
$("#submit-button").removeClass("btn-danger").addClass("btn-success").show();
|
||||
$("#submitIcon").removeClass("fa-check").addClass("fa-check");
|
||||
$("#buttonText").text('{{ trans('general.i_accept_item') }}');
|
||||
$("#buttonText").text('{{ trans_choice('general.i_accept_item', $acceptance->qty ?? 1) }}');
|
||||
$("#note").prop('required', false);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@stop
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
<tr>
|
||||
<th>{{ trans('general.name')}}</th>
|
||||
<th>{{ trans('general.type')}}</th>
|
||||
<th>{{ trans('general.qty') }}</th>
|
||||
<th>{{ trans('general.serial_number')}}</th>
|
||||
<th>{{ trans('table.actions')}}</th>
|
||||
</tr>
|
||||
@@ -41,8 +42,9 @@
|
||||
<tr>
|
||||
@if ($acceptance->checkoutable)
|
||||
<td>{{ ($acceptance->checkoutable) ? $acceptance->checkoutable->present()->name : '' }}</td>
|
||||
<td>{{ $acceptance->checkoutable_item_type }}</td>
|
||||
<td>{{ ($acceptance->checkoutable) ? $acceptance->checkoutable->serial : '' }}</td>
|
||||
<td>{{ $acceptance->checkoutable_item_type }}</td>
|
||||
<td>{{ $acceptance->qty ?? '1' }}</td>
|
||||
<td>{{ ($acceptance->checkoutable) ? $acceptance->checkoutable->serial : '' }}</td>
|
||||
<td><a href="{{ route('account.accept.item', $acceptance) }}" class="btn btn-default btn-sm">{{ trans('general.accept_decline') }}</a></td>
|
||||
@else
|
||||
<td> ----- </td>
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
@if (isset($item_serial))
|
||||
| **{{ trans('mail.serial') }}** | {{ $item_serial }} |
|
||||
@endif
|
||||
@if (isset($qty))
|
||||
| **{{ trans('general.qty') }}** | {{ $qty }} |
|
||||
@endif
|
||||
@if (isset($admin))
|
||||
| **{{ trans('general.administrator') }}** | {{ $admin }} |
|
||||
@endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Tests\Feature\CheckoutAcceptances\Ui;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\AccessoryCheckout;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\User;
|
||||
@@ -96,4 +97,47 @@ class AccessoryAcceptanceTest extends TestCase
|
||||
|
||||
$this->assertNull($acceptance->fresh()->accepted_at);
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://github.com/grokability/snipe-it/issues/17589
|
||||
*/
|
||||
public function test_all_accessory_checkout_entries_are_removed_when_user_declines_acceptance()
|
||||
{
|
||||
$assignee = User::factory()->create();
|
||||
|
||||
$this->actingAs(User::factory()->checkoutAccessories()->create());
|
||||
|
||||
// create accessory that requires acceptance
|
||||
$accessory = Accessory::factory()->requiringAcceptance()->create(['qty' => 5]);
|
||||
|
||||
// checkout 3 accessories to the user
|
||||
$this->post(route('accessories.checkout.store', $accessory), [
|
||||
'assigned_user' => $assignee->id,
|
||||
'checkout_qty' => 3,
|
||||
]);
|
||||
|
||||
$originalAccessoryCheckoutCount = AccessoryCheckout::count();
|
||||
|
||||
// find the acceptance to be declined
|
||||
$checkoutAcceptance = CheckoutAcceptance::query()
|
||||
->where([
|
||||
'assigned_to_id' => $assignee->id,
|
||||
'qty' => 3,
|
||||
])
|
||||
->whereNull('accepted_at')
|
||||
->whereNull('declined_at')
|
||||
->whereHasMorph(
|
||||
'checkoutable',
|
||||
[Accessory::class],
|
||||
)
|
||||
->sole();
|
||||
|
||||
// decline the checkout
|
||||
$this->actingAs($assignee)
|
||||
->post(route('account.store-acceptance', $checkoutAcceptance), [
|
||||
'asset_acceptance' => 'declined',
|
||||
]);
|
||||
|
||||
$this->assertEquals($originalAccessoryCheckoutCount - 3, AccessoryCheckout::count());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user