- Pay-now-Flow: bei fehlgeschlagenem Abo (Status 3) begleicht der Inhaber die offene Rechnung im Standard-Checkout mit frei waehlbarer, abo-faehiger Zahlart (nur eigenes Abo: Berater me-View + Kundenportal), payNow-Controller + Routen - AboRecoveryCheckoutService baut die ShoppingInstance aus den Abo-Artikeln; neue Spalte shopping_orders.recovery_user_abo_id verknuepft Bestellung<->Abo - Bei Erfolg: AboHelper::advanceAboAfterRecoveryPayment schreibt das Abo fort (Status->2, next_date) und uebernimmt die gewaehlte Zahlart als neues Token fuer kuenftige Abbuchungen - Neue Pay-now-Fehlermail (AboPaymentFailedMail) ersetzt die generische Fehlermail im Abo-Cron; Link fuehrt auf die Abo-Detailseite (CRM bzw. Portal) - Retry-/"extern erledigt"-Buttons nur noch fuer Admins; tote user/portal- Retry-Routen entfernt - Checkout: Recovery-Hinweis statt "Abschluss des Abonnements", Lieferadresse vorbelegt, korrekter Zurueck-Link (Abo statt Shop) - UserAbo::selfServiceDetailUrl zentralisiert die Abo-URL (Mail, Back-Links) - Test-Command abo:test-recovery; Tests fuer payNow, Advance-Logik, Fehlermail Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
187 lines
7.2 KiB
PHP
Executable file
187 lines
7.2 KiB
PHP
Executable file
@extends('portal.layouts.layout-2')
|
|
|
|
@section('content')
|
|
|
|
<h4 class="font-weight-bold py-2 mb-2">
|
|
{{ __('navigation.my_abo') }}
|
|
<span class="text-muted">{{ '#' . $user_abo->payone_userid }}</span>
|
|
</h4>
|
|
|
|
@if (Session::has('alert-success'))
|
|
<div class="col-sm-12">
|
|
<div class="alert alert-success p-2 mt-2">
|
|
<ul>
|
|
<li>{{ Session::get('alert-success') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
@if (Session::has('alert-error'))
|
|
<div class="col-sm-12">
|
|
<div class="alert alert-danger p-2 mt-2">
|
|
<ul>
|
|
<li>{{ Session::get('alert-error') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($user_abo->isPendingInitialPayment())
|
|
<div class="alert alert-warning">
|
|
<strong>{{ __('abo.pending_payment_waiting_title') }}</strong><br>
|
|
@if ($user_abo->hasFailedInitialPayment())
|
|
{{ __('abo.pending_payment_failed_copy') }}
|
|
@elseif($user_abo->hasInitialPaymentStatus())
|
|
{{ __('abo.pending_payment_processing_copy') }}
|
|
@else
|
|
{{ __('abo.pending_payment_waiting_copy') }}
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
@if ($user_abo->status === 3 && $user_abo->active)
|
|
<div class="card mt-3 mb-3 border-info">
|
|
<div class="card-body">
|
|
<h6 class="font-weight-bold text-info">{{ __('abo.pay_now_title') }}</h6>
|
|
<p class="mb-2">{{ __('abo.pay_now_copy') }}</p>
|
|
<form method="POST" action="{{ route('portal_abos_pay_now', [$user_abo->id]) }}">
|
|
@csrf
|
|
<button type="submit" class="btn btn-info">
|
|
<i class="ion ion-md-card mr-1"></i>{{ __('abo.pay_now_button') }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
|
|
<div class="card">
|
|
@include('admin.abo._detail')
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
@include('admin.customer._customer_detail', ['shopping_user' => $customer_detail])
|
|
</div>
|
|
|
|
@php
|
|
$addOnlyMode = App\Services\AboHelper::isAddOnlyMode($user_abo, $view);
|
|
$aboChangeLocked = App\Services\AboHelper::isAboChangeLocked($user_abo, $view);
|
|
@endphp
|
|
{!! Form::open([
|
|
'action' => route('user_abos_update', [$view, $user_abo->id]),
|
|
'class' => 'form-horizontal',
|
|
'id' => 'cart-order-form',
|
|
'data-add-only-mode' => $addOnlyMode ? '1' : '0',
|
|
]) !!}
|
|
<input type="hidden" name="is_for" value="{{ $user_abo->is_for }}">
|
|
@php
|
|
$oneTimeWindowOpen = isset($one_time_window_open) ? $one_time_window_open : false;
|
|
$summary = isset($summary) ? $summary : null;
|
|
$cartInstance = \App\Services\AboOrderCart::INSTANCE;
|
|
@endphp
|
|
@if ($oneTimeWindowOpen)
|
|
<div class="row mt-3">
|
|
<div class="col-lg-8">
|
|
<div class="card" id="onetime_order_card"
|
|
data-onetime-route="{{ route('user_abos_onetime', [$view, $user_abo->id]) }}">
|
|
@include('admin.abo._order_onetime', ['summary' => $summary])
|
|
</div>
|
|
<div class="card mt-3 mb-3">
|
|
@include('admin.abo._order_abo', [
|
|
'add_only_mode' => $addOnlyMode,
|
|
'split_mode' => true,
|
|
'summary' => $summary,
|
|
'change_locked' => $aboChangeLocked,
|
|
])
|
|
</div>
|
|
<div id="holder_html_view_comp_product">
|
|
@if ($comp_products && Yard::instance($cartInstance)->getNumComp() > 0)
|
|
@include('user.order.comp_product', [
|
|
'cart_instance' => $cartInstance,
|
|
'base_comp_count' => $base_comp_count ?? Yard::instance($cartInstance)->getNumComp(),
|
|
])
|
|
@endif
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4" id="combined_summary_col">
|
|
<div class="card js-abo-sticky" id="combined_summary_card">
|
|
@include('admin.abo._order_combined_summary', ['summary' => $summary])
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<div class="card mt-3">
|
|
@include('admin.abo._order_abo', [
|
|
'add_only_mode' => $addOnlyMode,
|
|
'change_locked' => $aboChangeLocked,
|
|
])
|
|
</div>
|
|
|
|
<div id="holder_html_view_comp_product">
|
|
@if ($comp_products && Yard::instance($cartInstance)->getNumComp() > 0)
|
|
@include('user.order.comp_product', [
|
|
'cart_instance' => $cartInstance,
|
|
'base_comp_count' => $base_comp_count ?? Yard::instance($cartInstance)->getNumComp(),
|
|
])
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
{{ Form::close() }}
|
|
|
|
<div class="card mt-3 mb-3">
|
|
@include('admin.abo._executions')
|
|
</div>
|
|
|
|
@if ($user_abo->isCreditCard())
|
|
<div class="card mt-3 mb-3">
|
|
<div class="card-body">
|
|
<h6 class="font-weight-bold">{{ __('abo.payment_method') }}</h6>
|
|
<p class="mb-2">
|
|
{{ __('payment.credit_card') }}@if ($user_abo->maskedCard())
|
|
: {{ $user_abo->maskedCard() }}
|
|
@endif
|
|
</p>
|
|
@if ($user_abo->canUpdatePaymentMethod())
|
|
<a href="{{ route('portal_abos_payment_method_edit', [$user_abo->id]) }}"
|
|
class="btn btn-sm btn-primary">
|
|
{{ __('abo.update_payment_method') }}
|
|
</a>
|
|
@endif
|
|
|
|
@if ($user_abo->card_changes->isNotEmpty())
|
|
<div class="mt-3">
|
|
<small class="text-muted d-block mb-1">{{ __('abo.card_change_history') }}</small>
|
|
<ul class="list-unstyled mb-0 small">
|
|
@foreach ($user_abo->card_changes->take(5) as $change)
|
|
<li>
|
|
<i class="ion ion-md-time text-muted mr-1"></i>
|
|
{{ $change->created_at->format('d.m.Y H:i') }}@if ($change->masked_card)
|
|
— {{ $change->masked_card }}
|
|
@endif
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
|
|
<a href="{{ route('portal.my_subscriptions') }}" class="btn btn-sm btn-default float-right">{{ __('abo.back') }}</a>
|
|
|
|
@include('admin.abo._confirm_add_modal')
|
|
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script src="{{ asset('/js/iq-modal-cart.js') }}?v=1{{ get_file_last_time('/js/iq-modal-cart.js') }}"></script>
|
|
<script src="{{ asset('/js/iq-abo-onetime.js') }}?v=1{{ get_file_last_time('/js/iq-abo-onetime.js') }}"></script>
|
|
<script type="application/javascript">
|
|
var iqModalCart = IqModalCart.init();
|
|
var iqAboOneTime = IqAboOneTime.init();
|
|
$( document ).ready(function() {
|
|
});
|
|
</script>
|
|
@endsection
|