Abo Einmalprodukte: Review-Gate (VIP), Verbindlichkeit & Summen-Layout
- Live-Review-Gate: Einmalprodukte nur fuer VIP im Sales Center sichtbar, Portal ausgeblendet (AboHelper::isOneTimeFeatureVisible + Gates in Controllern) - Nur verbindlich bestaetigte Einmal-Artikel fliessen in die Lieferung; Service-Helfer confirmedItems/pendingItems/pendingGross - Footer-Layout der Einmalprodukt-Liste: bestaetigte Summe + Gesamtbetrag, Trennstrich, offener Betrag und neue Gesamtsumme (dunkelgruen) - Uebersetzungen DE/EN/ES/FR (onetime_new_total u.a.), Tests angepasst/ergaenzt Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2269ce031f
commit
8288ea59ac
16 changed files with 356 additions and 46 deletions
|
|
@ -114,6 +114,12 @@ return [
|
|||
'onetime_reset_hint' => 'Einmalige Produkte werden nur deiner nächsten Lieferung beigelegt und danach automatisch wieder aus dem Abo entfernt.',
|
||||
'add_onetime_product' => 'Einmaliges Produkt hinzufügen',
|
||||
'onetime_subtotal' => 'Zwischensumme einmalige Produkte',
|
||||
'onetime_confirmed_subtotal' => 'Zwischensumme bestätigt (wird versandt)',
|
||||
'onetime_pending_subtotal' => 'Noch zu bestätigen (nicht verbindlich)',
|
||||
'onetime_new_total' => 'Neue Gesamtsumme nach Bestätigung',
|
||||
'onetime_status_confirmed' => 'Bestätigt',
|
||||
'onetime_status_pending' => 'Noch zu bestätigen',
|
||||
'onetime_pending_hint' => 'Bereits bestätigte Produkte werden mit der nächsten Lieferung versandt – unabhängig davon, ob du diese neuen Produkte bestätigst.',
|
||||
'onetime_next_delivery_total' => 'Gesamtbetrag der nächsten Lieferung (Abo + Einmalig)',
|
||||
'onetime_legal_notice' => 'Die hinzugefügten Produkte werden einmalig am :nextBillingDate versendet. Es gelten unsere :agb und die :withdrawal.',
|
||||
'onetime_discard_changes' => 'Änderungen verwerfen',
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@ return [
|
|||
'onetime_reset_hint' => 'One-time products are added only to your next delivery and are automatically removed from the subscription afterwards.',
|
||||
'add_onetime_product' => 'Add one-time product',
|
||||
'onetime_subtotal' => 'Subtotal one-time products',
|
||||
'onetime_confirmed_subtotal' => 'Subtotal confirmed (will be shipped)',
|
||||
'onetime_pending_subtotal' => 'Pending confirmation (not binding)',
|
||||
'onetime_new_total' => 'New total after confirmation',
|
||||
'onetime_status_confirmed' => 'Confirmed',
|
||||
'onetime_status_pending' => 'To be confirmed',
|
||||
'onetime_pending_hint' => 'Products you have already confirmed will be shipped with your next delivery, regardless of whether you confirm these new products.',
|
||||
'onetime_next_delivery_total' => 'Total amount of next delivery (subscription + one-time)',
|
||||
'onetime_legal_notice' => 'The added products will be shipped once on :nextBillingDate. Our :agb and :withdrawal apply.',
|
||||
'onetime_discard_changes' => 'Discard changes',
|
||||
|
|
|
|||
|
|
@ -105,6 +105,12 @@ return [
|
|||
'onetime_reset_hint' => 'Los productos únicos solo se añaden a su próxima entrega y después se eliminan automáticamente de la suscripción.',
|
||||
'add_onetime_product' => 'Añadir producto único',
|
||||
'onetime_subtotal' => 'Subtotal productos únicos',
|
||||
'onetime_confirmed_subtotal' => 'Subtotal confirmado (se enviará)',
|
||||
'onetime_pending_subtotal' => 'Pendiente de confirmar (no vinculante)',
|
||||
'onetime_new_total' => 'Nuevo total tras la confirmación',
|
||||
'onetime_status_confirmed' => 'Confirmado',
|
||||
'onetime_status_pending' => 'Por confirmar',
|
||||
'onetime_pending_hint' => 'Los productos que ya has confirmado se enviarán con tu próxima entrega, independientemente de si confirmas estos nuevos productos.',
|
||||
'onetime_next_delivery_total' => 'Importe total de la próxima entrega (suscripción + único)',
|
||||
'onetime_legal_notice' => 'Los productos añadidos se enviarán una sola vez el :nextBillingDate. Se aplican nuestros :agb y el :withdrawal.',
|
||||
'onetime_discard_changes' => 'Descartar cambios',
|
||||
|
|
|
|||
|
|
@ -114,6 +114,12 @@ return [
|
|||
'onetime_reset_hint' => 'Les produits ponctuels sont ajoutés uniquement à votre prochaine livraison puis supprimés automatiquement de l\'abonnement.',
|
||||
'add_onetime_product' => 'Ajouter un produit ponctuel',
|
||||
'onetime_subtotal' => 'Sous-total produits ponctuels',
|
||||
'onetime_confirmed_subtotal' => 'Sous-total confirmé (sera expédié)',
|
||||
'onetime_pending_subtotal' => 'À confirmer (non contraignant)',
|
||||
'onetime_new_total' => 'Nouveau total après confirmation',
|
||||
'onetime_status_confirmed' => 'Confirmé',
|
||||
'onetime_status_pending' => 'À confirmer',
|
||||
'onetime_pending_hint' => 'Les produits déjà confirmés seront expédiés avec votre prochaine livraison, que vous confirmiez ou non ces nouveaux produits.',
|
||||
'onetime_next_delivery_total' => 'Montant total de la prochaine livraison (abonnement + ponctuel)',
|
||||
'onetime_legal_notice' => 'Les produits ajoutés seront expédiés une seule fois le :nextBillingDate. Nos :agb et le :withdrawal s’appliquent.',
|
||||
'onetime_discard_changes' => 'Annuler les modifications',
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="font-weight-semibold mb-0">{{ __('abo.combined_summary_hl') }}</h5>
|
||||
</div>
|
||||
<div class="card-body bg-light">
|
||||
<div class="card-body bg-warning-light" style="background-color: rgba(227, 227, 54, 0.5) !important;">
|
||||
<table class="table table-product m-0">
|
||||
<tbody>
|
||||
@if(($summary['one_time']['gross'] ?? 0) > 0)
|
||||
@if (($summary['one_time']['gross'] ?? 0) > 0)
|
||||
<tr>
|
||||
<td class="small"><strong>{{ __('abo.onetime_subtotal') }}:</strong></td>
|
||||
<td class="text-right small">{{ formatNumber($summary['one_time']['gross']) }} €</td>
|
||||
|
|
@ -20,30 +20,37 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="small no-border-top"><strong>{{ __('Delivery country') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->getShippingCountryName() }}</td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->getShippingCountryName() }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="small no-border-top"><strong>{{ __('order.shipping_costs') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ $taxFree ? Yard::instance($cartInstance)->shippingNet() : Yard::instance($cartInstance)->shipping() }} €</td>
|
||||
<td class="text-right small no-border-top">
|
||||
{{ $taxFree ? Yard::instance($cartInstance)->shippingNet() : Yard::instance($cartInstance)->shipping() }}
|
||||
€</td>
|
||||
</tr>
|
||||
@if($taxFree)
|
||||
@if ($taxFree)
|
||||
<tr>
|
||||
<td class="small no-border-top"><strong>{{ __('order.sum_net') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->subtotalWithShipping() }} €</td>
|
||||
<td class="text-right small no-border-top">
|
||||
{{ Yard::instance($cartInstance)->subtotalWithShipping() }} €</td>
|
||||
</tr>
|
||||
@else
|
||||
<tr>
|
||||
<td class="small no-border-top"><strong>{{ __('order.total_without_VAT') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->subtotalWithShipping() }} €</td>
|
||||
<td class="text-right small no-border-top">
|
||||
{{ Yard::instance($cartInstance)->subtotalWithShipping() }} €</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="small no-border-top"><strong>{{ __('order.plus_VAT') }}:</strong></td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->taxWithShipping() }} €</td>
|
||||
<td class="text-right small no-border-top">{{ Yard::instance($cartInstance)->taxWithShipping() }} €
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr class="bg-white">
|
||||
<td class="pt-2 pb-2"><strong>{{ __('order.total_sum') }}:</strong></td>
|
||||
<td class="text-right font-weight-bold pt-2 pb-2">{{ Yard::instance($cartInstance)->totalWithShipping() }} €</td>
|
||||
<td class="text-right font-weight-bold pt-2 pb-2">
|
||||
{{ Yard::instance($cartInstance)->totalWithShipping() }} €</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
$one_time_items = $user_abo->one_time_items()->with('product')->get();
|
||||
$hasOneTimeChanges = \App\Services\AboOneTimeService::hasUnconfirmedChanges($user_abo);
|
||||
$hasConfirmedOneTimeItems = \App\Services\AboOneTimeService::hasConfirmedItems($user_abo);
|
||||
$oneTimeGross = $summary['one_time']['gross'] ?? 0;
|
||||
$hasBindingConfirmed = \App\Services\AboOneTimeService::confirmedItems($user_abo)->isNotEmpty();
|
||||
$confirmedGross = $summary['one_time']['gross'] ?? 0;
|
||||
$pendingGross = \App\Services\AboOneTimeService::pendingGross($user_abo);
|
||||
$nextDeliveryTotal = $summary['total_with_shipping'] ?? 0;
|
||||
$oneTimeConfirmationState = $hasOneTimeChanges ? 'changed' : ($hasConfirmedOneTimeItems ? 'confirmed' : 'empty');
|
||||
@endphp
|
||||
@if(isset($error_message) && $error_message)
|
||||
@if (isset($error_message) && $error_message)
|
||||
<div class="alert alert-danger mt-2" id="insert_onetime_error_message">{{ $error_message }}</div>
|
||||
@endif
|
||||
<div class="table-responsive">
|
||||
|
|
@ -23,30 +25,48 @@
|
|||
@forelse($one_time_items as $one_time_item)
|
||||
<tr>
|
||||
<td>
|
||||
@if($one_time_item->product && count($one_time_item->product->images))
|
||||
<img class="img-fluid img-extra" alt="" src="{{ route('product_image', [$one_time_item->product->images->first()->slug]) }}">
|
||||
@if ($one_time_item->product && count($one_time_item->product->images))
|
||||
<img class="img-fluid img-extra" alt=""
|
||||
src="{{ route('product_image', [$one_time_item->product->images->first()->slug]) }}">
|
||||
@endif
|
||||
</td>
|
||||
<td class="min-width-80">
|
||||
<strong>{{ $one_time_item->product?->getLang('name') }}</strong>
|
||||
<span class="badge badge-pill badge-warning"><i class="fa fa-bolt"></i> {{ __('abo.onetime_badge') }}</span>
|
||||
<span class="badge badge-pill badge-warning"><i class="fa fa-bolt"></i>
|
||||
{{ __('abo.onetime_badge') }}</span>
|
||||
@if ($one_time_item->isConfirmed())
|
||||
<span class="badge badge-pill badge-success"><i class="fa fa-check"></i>
|
||||
{{ __('abo.onetime_status_confirmed') }}</span>
|
||||
@else
|
||||
<span class="badge badge-pill badge-secondary"><i class="fa fa-clock"></i>
|
||||
{{ __('abo.onetime_status_pending') }}</span>
|
||||
@endif
|
||||
<div class="text-body">
|
||||
<div>{{ __('order.content') }}: {{ $one_time_item->product?->contents }}</div>
|
||||
<div>{{ __('order.art_no') }}: {{ $one_time_item->product?->number }}</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<a href="#" class="auto-delete-product remove_onetime_from_cart product-tooltip" data-onetime-item-id="{{ $one_time_item->id }}"><i class="fa fa-times"></i> {{ __('order.article_remove') }}</a>
|
||||
<a href="#" class="auto-delete-product remove_onetime_from_cart product-tooltip"
|
||||
data-onetime-item-id="{{ $one_time_item->id }}"><i class="fa fa-times"></i>
|
||||
{{ __('order.article_remove') }}</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="no-line-break input-group-min-w">
|
||||
<div class="input-group d-inline-flex w-auto">
|
||||
<span class="input-group-prepend">
|
||||
<button type="button" class="btn btn-secondary icon-btn md-btn-extra onetime-remove-from-basket" data-onetime-item-id="{{ $one_time_item->id }}">-</button>
|
||||
<button type="button"
|
||||
class="btn btn-secondary icon-btn md-btn-extra onetime-remove-from-basket"
|
||||
data-onetime-item-id="{{ $one_time_item->id }}">-</button>
|
||||
</span>
|
||||
<input type="text" class="form-control text-center input-extra onetime-input-onchange" name="onetime_qty_{{ $one_time_item->id }}" data-onetime-item-id="{{ $one_time_item->id }}" value="{{ $one_time_item->qty }}">
|
||||
<input type="text"
|
||||
class="form-control text-center input-extra onetime-input-onchange"
|
||||
name="onetime_qty_{{ $one_time_item->id }}"
|
||||
data-onetime-item-id="{{ $one_time_item->id }}" value="{{ $one_time_item->qty }}">
|
||||
<span class="input-group-append">
|
||||
<button type="button" class="btn btn-secondary icon-btn md-btn-extra onetime-add-from-basket" data-onetime-item-id="{{ $one_time_item->id }}">+</button>
|
||||
<button type="button"
|
||||
class="btn btn-secondary icon-btn md-btn-extra onetime-add-from-basket"
|
||||
data-onetime-item-id="{{ $one_time_item->id }}">+</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -63,31 +83,67 @@
|
|||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="4"><hr></td>
|
||||
<td colspan="4">
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="text-right small"><strong>{{ __('abo.onetime_subtotal') }}:</strong></td>
|
||||
<td class="text-right small">{{ formatNumber($summary['one_time']['gross'] ?? 0) }} €</td>
|
||||
</tr>
|
||||
@if($oneTimeGross > 0 || $hasOneTimeChanges || $hasConfirmedOneTimeItems)
|
||||
@if ($hasBindingConfirmed)
|
||||
<tr>
|
||||
<td colspan="3" class="text-right small no-border-top"><strong>{{ __('abo.onetime_next_delivery_total') }}:</strong></td>
|
||||
<td colspan="3" class="text-right small">
|
||||
<strong>{{ __('abo.onetime_confirmed_subtotal') }}:</strong>
|
||||
</td>
|
||||
<td class="text-right small">{{ formatNumber($confirmedGross) }} €</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="text-right small no-border-top">
|
||||
<strong>{{ __('abo.onetime_next_delivery_total') }}:</strong>
|
||||
</td>
|
||||
<td class="text-right small no-border-top">{{ formatNumber($nextDeliveryTotal) }} €</td>
|
||||
</tr>
|
||||
@endif
|
||||
@if ($pendingGross > 0)
|
||||
@if ($hasBindingConfirmed)
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<hr>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr>
|
||||
<td colspan="3" class="text-right small no-border-top text-danger">
|
||||
<strong>{{ __('abo.onetime_pending_subtotal') }}:</strong>
|
||||
</td>
|
||||
<td class="text-right small no-border-top text-danger">+
|
||||
{{ formatNumber($pendingGross) }} €</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" class="text-right no-border-top text-danger">
|
||||
<strong>{{ __('abo.onetime_new_total') }}:</strong>
|
||||
</td>
|
||||
<td class="text-right no-border-top font-weight-bold text-danger">
|
||||
{{ formatNumber(($hasBindingConfirmed ? $confirmedGross : 0) + $pendingGross) }} €</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
@if($oneTimeGross > 0 || $hasOneTimeChanges || $hasConfirmedOneTimeItems)
|
||||
<div class="mt-3" id="onetime_confirmation_block" data-confirmation-state="{{ $oneTimeConfirmationState }}" aria-live="polite">
|
||||
@if ($one_time_items->count() > 0)
|
||||
<div class="mt-3" id="onetime_confirmation_block" data-confirmation-state="{{ $oneTimeConfirmationState }}"
|
||||
aria-live="polite">
|
||||
|
||||
<p class="small text-muted mb-2">
|
||||
{!! __('abo.onetime_legal_notice', [
|
||||
'nextBillingDate' => $user_abo->next_date ?: __('abo.confirm_next_delivery_unknown'),
|
||||
'agb' => '<a href="'.url('/agb').'" target="_blank">'.__('abo.confirm_terms_link').'</a>',
|
||||
'withdrawal' => '<a href="'.asset('download/mivita_widerruf_formular.pdf').'" target="_blank">'.__('abo.confirm_withdrawal_link').'</a>',
|
||||
'agb' => '<a href="' . url('/agb') . '" target="_blank">' . __('abo.confirm_terms_link') . '</a>',
|
||||
'withdrawal' =>
|
||||
'<a href="' .
|
||||
asset('download/mivita_widerruf_formular.pdf') .
|
||||
'" target="_blank">' .
|
||||
__('abo.confirm_withdrawal_link') .
|
||||
'</a>',
|
||||
]) !!}
|
||||
</p>
|
||||
@if($hasOneTimeChanges)
|
||||
@if ($hasOneTimeChanges)
|
||||
<div class="d-flex flex-wrap justify-content-end">
|
||||
<button type="button" class="btn btn-default mr-2 mb-2 onetime-discard-changes">
|
||||
{{ __('abo.onetime_discard_changes') }}
|
||||
|
|
@ -101,5 +157,9 @@
|
|||
<span aria-hidden="true">✓</span> {{ __('abo.onetime_confirm_success') }}
|
||||
</div>
|
||||
@endif
|
||||
@if ($hasOneTimeChanges && $hasConfirmedOneTimeItems)
|
||||
<hr>
|
||||
<div class="alert alert-info small mb-2">{{ __('abo.onetime_pending_hint') }}</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue