Widerruf: Gesetzliche Online-Widerrufsfunktion (Formular, Bestätigungsmail, Admin-Verwaltung)
- Öffentliches Widerrufsformular /widerruf mit Bestell-Lookup (throttled) - Bestätigungsmail an Kunde + Weiterleitung an bestellungen@ (config app.withdrawal_mail) - Admin-Übersicht/-Detail unter /admin/withdrawals inkl. Sidenav-Eintrag - Widerruf-Button in Portal-Bestellansicht und Footer-Links - Model OrderWithdrawal + Migration + Factory + Tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
eac923968d
commit
63c36555a5
24 changed files with 1607 additions and 92 deletions
|
|
@ -97,6 +97,9 @@
|
|||
<li class=""><a target="_blank"
|
||||
href="{{ asset('download/mivita_widerruf_formular.pdf') }}">{{ __('website.cancellation_policy') }} </a></li>
|
||||
<li>•</li>
|
||||
<li class="{{ Request::is('widerruf') ? ' active' : '' }}"><a
|
||||
href="{{ route('withdrawal.create') }}">{{ __('withdrawal.button_label') }} </a></li>
|
||||
<li>•</li>
|
||||
<li class="{{ Request::is('datenschutz') ? ' active' : '' }}"><a
|
||||
href="{{ url('/datenschutz') }}">{{ __('website.privacy_policy') }} </a></li>
|
||||
<li>•</li>
|
||||
|
|
|
|||
49
resources/views/web/templates/widerruf-final.blade.php
Normal file
49
resources/views/web/templates/widerruf-final.blade.php
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
@extends($user_shop ? 'web.user.layouts.layout' : 'web.layouts.layout')
|
||||
|
||||
@section('content')
|
||||
|
||||
<section class="page-header page-header-xlg parallax parallax-3"
|
||||
style="background-image:url('/assets/images/vision-min.jpg')">
|
||||
<div class="overlay dark-1"></div>
|
||||
<div class="container"></div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="panel panel-default" style="max-width: 760px; margin: 0 auto;">
|
||||
<div class="panel-body">
|
||||
<h3><i class="fa fa-check-circle text-success"></i> {{ __('withdrawal.success_hl') }}</h3>
|
||||
<p>{{ __('withdrawal.success_intro') }}</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<strong>{{ __('withdrawal.success_received_at') }}:</strong>
|
||||
{{ optional($withdrawal->declared_at)->format('d.m.Y H:i') }} {{ __('withdrawal.clock') }}<br>
|
||||
<strong>{{ __('withdrawal.order_number') }}:</strong> #{{ $withdrawal->order_reference }}<br>
|
||||
<strong>{{ __('withdrawal.success_reference') }}:</strong> {{ $withdrawal->id }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@if ($withdrawal->isFullWithdrawal())
|
||||
{{ __('withdrawal.success_full') }}
|
||||
@else
|
||||
{{ __('withdrawal.success_partial') }}
|
||||
@endif
|
||||
</p>
|
||||
|
||||
@if (! empty($withdrawal->items))
|
||||
<ul>
|
||||
@foreach ($withdrawal->items as $item)
|
||||
<li>{{ $item['qty'] }} × {{ $item['name'] }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
@endif
|
||||
|
||||
<hr>
|
||||
<p>{{ __('withdrawal.success_email_sent', ['email' => $withdrawal->customer_email]) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@endsection
|
||||
160
resources/views/web/templates/widerruf.blade.php
Normal file
160
resources/views/web/templates/widerruf.blade.php
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
@extends($user_shop ? 'web.user.layouts.layout' : 'web.layouts.layout')
|
||||
|
||||
@section('content')
|
||||
|
||||
<section class="page-header page-header-xlg parallax parallax-3"
|
||||
style="background-image:url('/assets/images/vision-min.jpg')">
|
||||
<div class="overlay dark-1"></div>
|
||||
<div class="container"></div>
|
||||
</section>
|
||||
|
||||
<style type="text/css">
|
||||
.withdrawal-box {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.withdrawal-box .alert.error {
|
||||
font-weight: bold;
|
||||
}
|
||||
.withdrawal-scope label {
|
||||
display: block;
|
||||
font-size: 15px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.withdrawal-items .qty-input {
|
||||
max-width: 90px;
|
||||
}
|
||||
.legal-note {
|
||||
font-size: 13px;
|
||||
color: #6b7758;
|
||||
}
|
||||
</style>
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="withdrawal-box box-static box-transparent box-bordered padding-20">
|
||||
<h1>{{ __('withdrawal.page_title') }}</h1>
|
||||
<p>{{ __('withdrawal.intro') }}</p>
|
||||
|
||||
@if (session('alert-error'))
|
||||
<div class="alert alert-danger error">{{ session('alert-error') }}</div>
|
||||
@endif
|
||||
|
||||
@if (! $order)
|
||||
{{-- Phase 1: Bestellung identifizieren --}}
|
||||
<hr>
|
||||
<h3>{{ __('withdrawal.identify_hl') }}</h3>
|
||||
{!! Form::open(['route' => 'withdrawal.lookup', 'method' => 'post']) !!}
|
||||
<div class="form-group">
|
||||
{!! Form::label('order_number', __('withdrawal.order_number') . '*') !!}
|
||||
{!! Form::text('order_number', old('order_number', $prefill_order), ['class' => 'form-control ' . ($errors->has('order_number') ? 'error is-invalid' : ''), 'placeholder' => __('withdrawal.order_number_placeholder')]) !!}
|
||||
<small class="form-text text-muted">{{ __('withdrawal.order_number_help') }}</small>
|
||||
@if ($errors->has('order_number'))
|
||||
<div class="alert alert-danger error">{{ $errors->first('order_number') }}</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="form-group">
|
||||
{!! Form::label('email', __('withdrawal.email') . '*') !!}
|
||||
{!! Form::email('email', old('email', $prefill_email), ['class' => 'form-control ' . ($errors->has('email') ? 'error is-invalid' : ''), 'placeholder' => __('withdrawal.email_placeholder')]) !!}
|
||||
@if ($errors->has('email'))
|
||||
<div class="alert alert-danger error">{{ $errors->first('email') }}</div>
|
||||
@endif
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-text-500">
|
||||
<i class="fa fa-search"></i> {{ __('withdrawal.find_order') }}
|
||||
</button>
|
||||
{!! Form::close() !!}
|
||||
@else
|
||||
{{-- Phase 2: Umfang wählen und absenden --}}
|
||||
<hr>
|
||||
<h3>{{ __('withdrawal.order_found_hl') }}</h3>
|
||||
<p>
|
||||
<strong>{{ __('withdrawal.order_number') }}:</strong> #{{ $order->id }}<br>
|
||||
<strong>{{ __('withdrawal.order_date') }}:</strong> {{ optional($order->created_at)->format('d.m.Y H:i') }}
|
||||
</p>
|
||||
|
||||
{!! Form::open(['route' => 'withdrawal.store', 'method' => 'post']) !!}
|
||||
{!! Form::hidden('order_number', $order->id) !!}
|
||||
{!! Form::hidden('email', $prefill_email) !!}
|
||||
|
||||
<hr>
|
||||
<h4>{{ __('withdrawal.choose_scope_hl') }}</h4>
|
||||
<div class="withdrawal-scope">
|
||||
<label class="radio">
|
||||
{!! Form::radio('scope', \App\Models\OrderWithdrawal::TYPE_FULL, old('scope', 'full') === 'full', ['id' => 'scope_full']) !!}
|
||||
<i></i> {{ __('withdrawal.scope_full') }}
|
||||
</label>
|
||||
<label class="radio">
|
||||
{!! Form::radio('scope', \App\Models\OrderWithdrawal::TYPE_PARTIAL, old('scope') === 'partial', ['id' => 'scope_partial']) !!}
|
||||
<i></i> {{ __('withdrawal.scope_partial') }}
|
||||
</label>
|
||||
@if ($errors->has('scope'))
|
||||
<div class="alert alert-danger error">{{ $errors->first('scope') }}</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div id="withdrawal_items" class="withdrawal-items" style="display: none;">
|
||||
<hr>
|
||||
<h4>{{ __('withdrawal.select_items_hl') }}</h4>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('withdrawal.product') }}</th>
|
||||
<th class="text-center">{{ __('withdrawal.quantity') }}</th>
|
||||
<th class="text-center">{{ __('withdrawal.withdraw_quantity') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($order->shopping_order_items as $item)
|
||||
<tr>
|
||||
<td>{{ $item->product?->getLang('name') ?? ('#' . $item->product_id) }}</td>
|
||||
<td class="text-center">{{ (int) $item->qty }}</td>
|
||||
<td class="text-center">
|
||||
{!! Form::number('items[' . $item->id . ']', old('items.' . $item->id, 0), ['class' => 'form-control qty-input mx-auto', 'min' => 0, 'max' => (int) $item->qty]) !!}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="form-group">
|
||||
{!! Form::label('reason', __('withdrawal.reason')) !!}
|
||||
{!! Form::textarea('reason', old('reason'), ['class' => 'form-control', 'rows' => 3, 'placeholder' => __('withdrawal.reason_placeholder')]) !!}
|
||||
</div>
|
||||
|
||||
<p class="legal-note">{{ __('withdrawal.legal_note') }}</p>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{{ route('withdrawal.create') }}" class="btn btn-default btn-text-500">
|
||||
<i class="fa fa-angle-left"></i> {{ __('withdrawal.back') }}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary btn-text-500">
|
||||
<i class="fa fa-check"></i> {{ __('withdrawal.submit') }}
|
||||
</button>
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
function toggleItems() {
|
||||
if ($('#scope_partial').is(':checked')) {
|
||||
$('#withdrawal_items').show();
|
||||
} else {
|
||||
$('#withdrawal_items').hide();
|
||||
}
|
||||
}
|
||||
|
||||
$('input[type=radio][name=scope]').on('change', toggleItems);
|
||||
toggleItems();
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -138,6 +138,9 @@
|
|||
<li class=""><a target="_blank"
|
||||
href="{{ asset('download/mivita_widerruf_formular.pdf') }}">{{ __('website.cancellation_policy') }}</a></li>
|
||||
<li>•</li>
|
||||
<li class="{{ Request::is('widerruf') ? ' active' : '' }}"><a
|
||||
href="{{ route('withdrawal.create') }}">{{ __('withdrawal.button_label') }}</a></li>
|
||||
<li>•</li>
|
||||
<li class="{{ Request::is('datenschutz') ? ' active' : '' }}"><a
|
||||
href="{{ legal_url('/datenschutz') }}">{{ __('website.privacy_policy') }}</a></li>
|
||||
<li>•</li>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue