Einmalprodukte (Normalsortiment, show_on 3) können jetzt schon beim Abo-Abschluss hinzugefügt werden – im Portal-Wizard (Abschnitt im Upgrade-Schritt) und in allen drei Sales-Center-Abo-Strecken (eigene Produktliste). Variante A: Zeilen laufen als Cart-Option abo_addon mit durch den Checkout, werden sofort bezahlt und mit der Erstlieferung verschickt (Rechnung/Lieferschein gruppieren automatisch). - Checkout persistiert is_abo_addon (CheckoutRepository, PaymentHelper) - createAboItems/ensureUserAboItemsFromLatestOrder überspringen Addons (sonst würden Einmalprodukte dauerhaft wiederkehren); amount ohne Addon-Anteil; aboHasBaseProduct ignoriert Addon-Zeilen - CreateAboReplacementOrder propagiert is_abo_addon in Ersatzbestellungen - iq-shopping-cart.js: zweite Datatable + abo_addon-Flag-Weitergabe - i18n: neue abo.onetime_create_*-Keys (de/en/es/fr); zusätzlich es/fr komplett synchronisiert (abo-Kartenblock, navigation, payment, weborder inkl. Entfernung PAYONE-Altlasten, withdrawal.php neu) - Tests: AboCreateOneTimeItemsTest, AboCreateOneTimeCartTest, AboPortalCreateOneTimeTest (17 neue, 122 Tests gesamt grün) Plan: dev/2026-07-21-abo-einmalprodukte-anlage/ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
4.8 KiB
PHP
81 lines
4.8 KiB
PHP
@props([
|
|
'products' => [],
|
|
])
|
|
|
|
{{-- Einmalprodukte (Normalsortiment) zur ersten Abo-Lieferung: eigene Cart-Zeilen mit
|
|
Option abo_addon (eigene rowId), daher eigene Warenkorb-Suche statt getCartItemByProduct. --}}
|
|
@if(count($products) > 0)
|
|
<div class="table-responsive">
|
|
<table class="table table- m-0">
|
|
<thead>
|
|
<tr>
|
|
<th>{{ __('abo.onetime_product') }}</th>
|
|
<th> </th>
|
|
<th class="text-right">{{ __('order.unit_price') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($products as $product)
|
|
|
|
@php
|
|
$cartItem = Yard::instance('subscription')->search(function ($item) use ($product) {
|
|
return (int) $item->id === (int) $product->id && ($item->options->abo_addon ?? false);
|
|
})->first();
|
|
$qty = isset($cartItem->qty) ? $cartItem->qty : 0;
|
|
$rowId = isset($cartItem->rowId) ? $cartItem->rowId : '';
|
|
@endphp
|
|
<tr>
|
|
<td class="text-center align-middle px-0" data-label="{{ __('abo.onetime_product') }}">
|
|
<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 remove-product-qty"
|
|
data-row-id="{{ $rowId }}"
|
|
data-product-id="{{ $product->id }}">-</button>
|
|
</span>
|
|
<input type="text"
|
|
class="form-control text-center input-extra table-input-event-onchange"
|
|
name="onetime_product_qty[{{ $product->id }}]"
|
|
data-row-id="{{ $rowId }}"
|
|
data-product-id="{{ $product->id }}"
|
|
value="{{ $qty }}">
|
|
<span class="input-group-append">
|
|
<button type="button" class="btn btn-secondary icon-btn md-btn-extra add-product-qty"
|
|
data-row-id="{{ $rowId }}"
|
|
data-product-id="{{ $product->id }}">+</button>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="p-4" data-label="">
|
|
<div class="media align-items-center product-inactive" id="onetime-product-{{ $product->id }}">
|
|
@if(count($product->images))
|
|
<img src="{{ route('product_image', [$product->images->first()->slug]) }}"
|
|
class="d-block ui-w-100 ui-bordered mr-4"
|
|
alt="{{ $product->getLang('name') }}">
|
|
@endif
|
|
<div class="media-body">
|
|
<h5 class="d-block text-dark">
|
|
{{$product->getLang('name')}}
|
|
<br><span class="badge badge-pill badge-warning"><i class="fa fa-bolt"></i> {{ __('abo.onetime_badge') }}</span>
|
|
</h5>
|
|
{!! $product->getLang('copy') !!}
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="text-right font-weight-semibold align-middle p-4" data-label="{{ __('order.unit_price') }}">
|
|
<span class="no-line-break">
|
|
{{ $product->getFormattedPriceWith(\App\Services\UserService::getTaxFree(), false, \App\Services\UserService::$user_country) }} €
|
|
</span>
|
|
@if(\App\Services\UserService::$user_country && \App\Services\UserService::$user_country->currency)
|
|
<span class="no-line-break">
|
|
{!! $product->getFormattedPriceCurrencyWith(\App\Services\UserService::getTaxFree(), false, \App\Services\UserService::$user_country) !!}
|
|
</span>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|