20-02-2026

This commit is contained in:
Kevin Adametz 2026-02-20 17:55:06 +01:00
parent a8b395e20d
commit a00c42e770
252 changed files with 28785 additions and 8907 deletions

View file

@ -0,0 +1,62 @@
@php
$changeHistory = $user_abo->getChangeHistory();
$priceLabel = $user_abo->is_for === 'me' ? __('abo_history.price_net') : __('abo_history.price_gross');
@endphp
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="font-weight-semibold mb-0">
<i class="fas fa-history"></i> {{ __('abo_history.change_history') }}
</h5>
@if(isset($isAdmin) && $isAdmin && $user_abo->getInitialItems()->isNotEmpty())
{{-- <form action="{{ route('admin_abos_rollback', [$user_abo->id]) }}" method="POST"
onsubmit="return confirm('{{ __('abo_history.rollback_confirm') }}')">
@csrf
<button type="submit" class="btn btn-sm btn-outline-danger">
<i class="fas fa-undo"></i> {{ __('abo_history.rollback_btn') }}
</button>
</form>
--}}
@endif
</div>
@if($changeHistory->isEmpty())
<p class="text-muted mb-0">
<i class="fas fa-info-circle"></i> {{ __('abo_history.no_changes') }}
</p>
@else
<div class="table-responsive">
<table class="table table-sm table-striped mb-0">
<thead>
<tr>
<th>{{ __('abo_history.col_date') }}</th>
<th>{{ __('abo_history.col_action') }}</th>
<th>{{ __('abo_history.col_product') }}</th>
<th>{{ __('abo_history.col_details') }}</th>
<th class="text-right">{{ __('tables.price') }} <small class="text-muted">({{ $priceLabel }})</small></th>
<th>{{ __('abo_history.col_changed_by') }}</th>
<th>{{ __('abo_history.col_channel') }}</th>
</tr>
</thead>
<tbody>
@foreach($changeHistory as $entry)
<tr>
<td class="text-nowrap small">{{ $entry->getFormattedDate() }}</td>
<td>{!! $entry->getActionBadge() !!}</td>
<td>
<strong>{{ $entry->product_name }}</strong>
@if($entry->product_number)
<br><small class="text-muted">{{ $entry->product_number }}</small>
@endif
</td>
<td class="small">{{ $entry->getChangeDescription() }}</td>
<td class="text-right text-nowrap">{{ $entry->getFormattedTotalPrice() }} &euro;</td>
<td class="small">{{ $entry->changed_by_name }}</td>
<td>{!! $entry->getChannelBadge() !!}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>

View file

@ -0,0 +1,59 @@
@php
$initialItems = $user_abo->getInitialItems();
$initialCompItems = $user_abo->getInitialCompItems();
$priceLabel = $user_abo->is_for === 'me' ? __('abo_history.price_net') : __('abo_history.price_gross');
@endphp
<div class="card-body">
<h5 class="font-weight-semibold">
<i class="fas fa-box-open"></i> {{ __('abo_history.initial_composition') }}
</h5>
@if($initialItems->isEmpty() && $initialCompItems->isEmpty())
<p class="text-muted mb-0">
<i class="fas fa-info-circle"></i> {{ __('abo_history.no_initial_data') }}
</p>
@else
<div class="table-responsive">
<table class="table table-sm mb-0">
<thead>
<tr>
<th>{{ __('order.article') }}</th>
<th>{{ __('order.art_no') }}</th>
<th class="text-center">{{ __('tables.quantity') }}</th>
<th class="text-right">{{ __('tables.price') }} <small class="text-muted">({{ $priceLabel }})</small></th>
<th class="text-right">{{ __('order.total_sum') }} <small class="text-muted">({{ $priceLabel }})</small></th>
</tr>
</thead>
<tbody>
@foreach($initialItems as $item)
<tr>
<td>
<strong>{{ $item->product_name }}</strong>
@if($item->product)
&nbsp; {!! \App\Services\AboHelper::getAboTypeBadge(\App\Services\AboHelper::getAboShowOn($item->product)) !!}
@endif
</td>
<td class="text-muted">{{ $item->product_number }}</td>
<td class="text-center">{{ $item->qty_after }}</td>
<td class="text-right text-nowrap">{{ $item->getFormattedUnitPrice() }} &euro;</td>
<td class="text-right text-nowrap font-weight-semibold">{{ $item->getFormattedTotalPrice() }} &euro;</td>
</tr>
@endforeach
@foreach($initialCompItems as $item)
<tr class="bg-light">
<td>
<span class="badge badge-outline-secondary">Comp</span>
{{ $item->product_name }}
</td>
<td class="text-muted">{{ $item->product_number }}</td>
<td class="text-center">{{ $item->qty_after }}</td>
<td class="text-right text-nowrap">{{ $item->getFormattedUnitPrice() }} &euro;</td>
<td class="text-right text-nowrap font-weight-semibold">{{ $item->getFormattedTotalPrice() }} &euro;</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>

View file

@ -108,9 +108,19 @@
{{ __('abo.abo_order_hl') }}
</h5>
@if(isset($only_show_products) && $only_show_products === true)
<p>{!! __('abo.abo_order_info_block', ['abo-min-duration' => \App\Models\Setting::getContentBySlug('abo-min-duration')]) !!}</p>
@if($view === 'team')
<div class="alert alert-info">{!! __('abo.abo_order_info_block_team', ['abo-min-duration' => \App\Models\Setting::getContentBySlug('abo-min-duration')]) !!}</div>
@else
<div class="alert alert-info">{!! __('abo.abo_order_info_block', ['abo-min-duration' => \App\Models\Setting::getContentBySlug('abo-min-duration')]) !!}</div>
@endif
@elseif(isset($add_only_mode) && $add_only_mode)
@if($view === 'ot')
<div class="alert alert-info">{!! __('abo.abo_order_info_block_customer', ['abo-min-duration' => \App\Models\Setting::getContentBySlug('abo-min-duration')]) !!}</div>
@else
<div class="alert alert-info">{!! __('abo.abo_order_info_add_only', ['abo-min-duration' => \App\Models\Setting::getContentBySlug('abo-min-duration')]) !!}</div>
@endif
@else
<p>{{ __('abo.abo_order_info_2') }}</p>
<div class="alert alert-info">{{ __('abo.abo_order_info_2') }}</div>
@endif
<hr>
@include('user.abo.vat_info')
@ -121,8 +131,11 @@
data-route="{{ route('modal_load') }}"><i class="fa fa-plus-circle"></i> {{ __('abo.add_product') }}</button>
@endif
<div class="" id="insert_show_products_order" data-cart-order-id="{{ $user_abo->id }}">
@php $only_show_products = isset($only_show_products) ? $only_show_products : false; @endphp
@include('admin.abo._order_abo_show', ['only_show_products' => $only_show_products])
@php
$only_show_products = isset($only_show_products) ? $only_show_products : false;
$add_only_mode = isset($add_only_mode) ? $add_only_mode : false;
@endphp
@include('admin.abo._order_abo_show', ['only_show_products' => $only_show_products, 'add_only_mode' => $add_only_mode])
</div>
</div>

View file

@ -28,7 +28,7 @@
<div>{{ __('order.content') }}: {{ $abo_item->product->contents }}</div>
<div>{{ __('order.art_no') }}: {{ $abo_item->product->number }}</div>
</div>
@if(!isset($only_show_products) || !$only_show_products)
@if((!isset($only_show_products) || !$only_show_products) && (!isset($add_only_mode) || !$add_only_mode))
<div class="options">
<a href="#" class="auto-delete-product remove_item_form_cart product-tooltip" data-order-item-id="{{$abo_item->id}}" data-product-id="{{ $abo_item->product->id }}"><i class="fa fa-times"></i> {{ __('order.article_remove') }}</a>
</div>
@ -38,12 +38,14 @@
@if(!isset($only_show_products) || !$only_show_products)
<div class="no-line-break input-group-min-w">
<div class="input-group d-inline-flex w-auto">
@if(!isset($add_only_mode) || !$add_only_mode)
<span class="input-group-prepend">
<button type="button" class="btn btn-secondary icon-btn md-btn-extra remove-from-basket" data-order-item-id="{{$abo_item->id}}" data-product-id="{{ $abo_item->product->id }}">-</button>
</span>
<input type="text" class="form-control text-center input-extra table-input-event-onchange" name="product_qty_{{$abo_item->id}}" data-order-item-id="{{$abo_item->id}}" data-product-id="{{ $abo_item->product->id }}" value="{{$abo_item->qty}}">
@endif
<input type="text" class="form-control text-center input-extra table-input-event-onchange" name="product_qty_{{$abo_item->id}}" data-order-item-id="{{$abo_item->id}}" data-product-id="{{ $abo_item->product->id }}" value="{{$abo_item->qty}}" {{ (isset($add_only_mode) && $add_only_mode) ? 'readonly' : '' }}>
<span class="input-group-append">
<button type="button" class="btn btn-secondary icon-btn md-btn-extra add-from-basket" data-order-item-id="{{$abo_item->id}}" data-product-id="{{ $abo_item->product->id }}">+</button>
<button type="button" class="btn btn-secondary icon-btn md-btn-extra add-from-basket" data-order-item-id="{{$abo_item->id}}" data-product-id="{{ $abo_item->product->id }}" data-product-name="{{ $abo_item->product->getLang('name') }}" data-product-price="{{ $abo_item->getFormattedPrice() }} &euro;">+</button>
</span>
</div>
</div>

View file

@ -41,6 +41,14 @@
{{ Form::close() }}
<div class="card mt-3">
@include('admin.abo._initial_composition')
</div>
<div class="card mt-3">
@include('admin.abo._change_history')
</div>
<div class="card mt-3">
@include('admin.abo._executions')
</div>
@ -48,7 +56,45 @@
<a href="{{route('admin_abos')}}" class="btn btn-sm btn-default mt-2 float-right">{{ __('back') }}</a>
<div class="modal fade" id="modal-confirm-add" tabindex="-1" role="dialog" aria-labelledby="modal-confirm-add-label" aria-hidden="true"
data-title-add-only="{{ __('abo.confirm_add_title') }}"
data-title-normal="{{ __('abo.confirm_add_title_normal') }}"
data-warning-add-only="{{ __('abo.confirm_add_warning') }}"
data-warning-normal="{{ __('abo.confirm_add_warning_normal') }}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-confirm-add-label"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="alert alert-warning mb-3">
<i class="fa fa-exclamation-triangle"></i> <span id="confirm-add-warning-text"></span>
</div>
<table class="table table-sm mb-0">
<tr>
<td class="font-weight-bold">{{ __('order.article') }}:</td>
<td id="confirm-add-product-name"></td>
</tr>
<tr>
<td class="font-weight-bold">{{ __('tables.price') }}:</td>
<td id="confirm-add-product-price"></td>
</tr>
<tr>
<td class="font-weight-bold">{{ __('tables.quantity') }}:</td>
<td id="confirm-add-qty-info"></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ __('abo.confirm_add_cancel') }}</button>
<button type="button" class="btn btn-primary" id="confirm-add-btn">{{ __('abo.confirm_add_ok') }}</button>
</div>
</div>
</div>
</div>
@endsection

View file

@ -18,6 +18,7 @@
placeholder="mivita" required>
</div>
</div>
{{-- Basis-Informationen --}}
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
@ -33,25 +34,183 @@
@if($userSalesVolume)
<tr>
<td>{{ $userSalesVolume->date }}</td>
<td>{{ $userSalesVolume->getFormattedPoints() }}</td>
<td>{{ formatNumber($userSalesVolume->total_net) }} &euro;</td>
<td>{{ $userSalesVolume->getStatusType() }}</td>
<td>
<strong class="{{ $userSalesVolume->points < 0 ? 'text-danger' : '' }}">
{{ $userSalesVolume->getFormattedPoints() }}
</strong>
</td>
<td class="{{ $userSalesVolume->total_net < 0 ? 'text-danger' : '' }}">
{{ formatNumber($userSalesVolume->total_net) }} &euro;
</td>
<td>
<span class="badge badge-{{ $userSalesVolume->getStatusColor() }}">
{{ $userSalesVolume->getStatusType() }}
</span>
</td>
<td>@if($userSalesVolume->user)
{{ $userSalesVolume->user->getFullName() }}
@else
nicht zugewiesen
<span class="text-muted">nicht zugewiesen</span>
@endif
</td>
</tr>
@if($userSalesVolume->message)
<tr>
<td colspan="5">{{ $userSalesVolume->message }}</td>
<td colspan="5"><i class="fa fa-info-circle"></i> {{ $userSalesVolume->message }}</td>
</tr>
@endif
@endif
</tbody>
</table>
</div>
{{-- Erweiterte Informationen --}}
@if($userSalesVolume)
<div class="row mb-3">
<div class="col-md-6">
<h6 class="mb-2"><strong>Verknüpfungen</strong></h6>
<div class="list-group list-group-flush">
{{-- Bestellung --}}
@if($userSalesVolume->shopping_order)
<div class="list-group-item px-0 py-2">
<strong>Bestellung:</strong>
@if($userSalesVolume->status === 1)
<a href="{{ route('admin_sales_users_detail', [$userSalesVolume->shopping_order->id]) }}"
class="btn btn-xs btn-primary" target="_blank">
<i class="fa fa-shopping-cart"></i> #{{ $userSalesVolume->shopping_order->id }}
</a>
@elseif($userSalesVolume->status === 2 || $userSalesVolume->status === 3)
<a href="{{ route('admin_sales_customers_detail', [$userSalesVolume->shopping_order->id]) }}"
class="btn btn-xs btn-secondary" target="_blank">
<i class="fa fa-shopping-cart"></i> #{{ $userSalesVolume->shopping_order->id }}
</a>
@elseif($userSalesVolume->status === 6)
@php
$route = ($userSalesVolume->shopping_order->payment_for === 6 || $userSalesVolume->shopping_order->payment_for === 7)
? route('admin_sales_customers_detail', [$userSalesVolume->shopping_order->id])
: route('admin_sales_users_detail', [$userSalesVolume->shopping_order->id]);
@endphp
<a href="{{ $route }}" class="btn btn-xs btn-danger" target="_blank">
<i class="fa fa-undo"></i> #{{ $userSalesVolume->shopping_order->id }} (Storno)
</a>
@endif
</div>
@endif
{{-- Rechnung --}}
@if($userSalesVolume->user_invoice)
<div class="list-group-item px-0 py-2">
@if($userSalesVolume->user_invoice->cancellation)
<strong>Stornorechnung:</strong>
<span class="badge badge-danger">Storno</span>
<a href="{{ route('storage_file', [$userSalesVolume->user_invoice->shopping_order_id, 'cancellation', 'stream']) }}"
class="btn btn-xs btn-danger" target="_blank">
<i class="fa fa-file-pdf"></i> {{ $userSalesVolume->user_invoice->full_number }}
</a>
{{-- Link zur Original-Rechnung --}}
@if($userSalesVolume->shopping_order && $userSalesVolume->shopping_order->user_invoice)
<br><small class="text-muted">Original:
<a href="{{ route('storage_file', [$userSalesVolume->shopping_order->id, 'invoice', 'stream']) }}"
class="text-muted" target="_blank">
{{ $userSalesVolume->shopping_order->user_invoice->full_number }}
</a>
</small>
@endif
@else
<strong>Rechnung:</strong>
<a href="{{ route('storage_file', [$userSalesVolume->user_invoice->shopping_order_id, 'invoice', 'stream']) }}"
class="btn btn-xs btn-info" target="_blank">
<i class="fa fa-file-pdf"></i> {{ $userSalesVolume->user_invoice->full_number }}
</a>
@endif
</div>
@endif
{{-- Info/Notiz --}}
@if($userSalesVolume->info)
<div class="list-group-item px-0 py-2">
<strong>Notiz:</strong> {{ $userSalesVolume->info }}
</div>
@endif
</div>
</div>
<div class="col-md-6">
<h6 class="mb-2"><strong>Monatssummen (kumuliert)</strong></h6>
<div class="list-group list-group-flush">
<div class="list-group-item px-0 py-2">
<strong>KP-Punkte (Eigene):</strong>
<span class="badge badge-primary">{{ formatNumber($userSalesVolume->month_KP_points) }}</span>
</div>
<div class="list-group-item px-0 py-2">
<strong>TP-Punkte (Team):</strong>
<span class="badge badge-success">{{ formatNumber($userSalesVolume->month_TP_points) }}</span>
</div>
<div class="list-group-item px-0 py-2">
<strong>Shop-Punkte:</strong>
<span class="badge badge-secondary">{{ formatNumber($userSalesVolume->month_shop_points) }}</span>
</div>
<div class="list-group-item px-0 py-2">
<strong>Umsatz (netto):</strong>
{{ formatNumber($userSalesVolume->month_total_net) }} &euro;
</div>
<div class="list-group-item px-0 py-2">
<strong>Shop-Umsatz:</strong>
{{ formatNumber($userSalesVolume->month_shop_total_net) }} &euro;
</div>
</div>
</div>
</div>
{{-- Status-Details --}}
<div class="row mb-3">
<div class="col-md-12">
<h6 class="mb-2"><strong>Status-Details</strong></h6>
<div class="d-flex flex-wrap gap-2">
<span class="badge badge-{{ $userSalesVolume->getStatusColor() }} mr-2">
<i class="fa fa-tag"></i> {{ $userSalesVolume->getStatusType() }}
</span>
<span class="badge badge-{{ $userSalesVolume->getStatusPointsColor() }} mr-2">
<i class="fa fa-calculator"></i> {{ $userSalesVolume->getStatusPointsType() }}
</span>
@if($userSalesVolume->status_turnover)
<span class="badge badge-{{ $userSalesVolume->getStatusTurnoverColor() }} mr-2">
<i class="fa fa-chart-line"></i> {{ $userSalesVolume->getStatusTurnoverType() }}
</span>
@endif
</div>
</div>
</div>
{{-- Änderungshistorie (Syslog) --}}
@if($userSalesVolume->syslog && count($userSalesVolume->syslog) > 0)
<div class="row mb-3">
<div class="col-md-12">
<h6 class="mb-2"><strong>Änderungshistorie</strong></h6>
<div class="alert alert-light p-2">
<ul class="mb-0 pl-3">
@foreach($userSalesVolume->syslog as $timestamp => $log_entry)
<li><small><code>{{ $timestamp }}</code>: {{ $log_entry }}</small></li>
@endforeach
</ul>
</div>
</div>
</div>
@endif
{{-- Timestamps --}}
<div class="row mb-3">
<div class="col-md-12">
<small class="text-muted">
<i class="fa fa-clock"></i> Erstellt: {{ $userSalesVolume->created_at->format('d.m.Y H:i:s') }}
@if($userSalesVolume->updated_at && $userSalesVolume->updated_at != $userSalesVolume->created_at)
| Aktualisiert: {{ $userSalesVolume->updated_at->format('d.m.Y H:i:s') }}
@endif
</small>
</div>
</div>
@endif
<hr>
@if($userSalesVolume->isCurrentMonthYear())
<div class="form-row">

View file

@ -51,6 +51,10 @@
<div class="text-muted small">{{ __('E-Mail') }}</div>
@if($shopping_user->faker_mail) "-" @else {{ $shopping_user->billing_email }} @endif
</div>
<div class="col-md-3 mb-3">
<div class="text-muted small">{{ __('account.preferred_language') }}</div>
{{ \App\Models\ShoppingUser::getAvailableLanguages()[$shopping_user->language] ?? $shopping_user->language }}
</div>
</div>
</div>
<hr class="m-0">

View file

@ -48,6 +48,7 @@
<a class="btn btn-sm btn-secondary mt-2" href="{{route('user_customer_edit', [$shopping_user->id])}}">{{ __('customer.edit_customer_data') }}</a>
@endif
</div>
</div>
@endif
</div>

View file

@ -283,10 +283,22 @@
{{ Form::textarea('remarks', $shopping_user->remarks, array('placeholder'=>__('Comments'), 'class'=>'form-control', 'rows'=>4, 'id'=>'remarks')) }}
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label class="form-label" for="language">{{ __('account.preferred_language') }}</label>
<select class="selectpicker" name="language" id="language" data-style="btn-light">
@foreach(\App\Models\ShoppingUser::getAvailableLanguages() as $code => $label)
<option value="{{ $code }}" {{ $shopping_user->language === $code ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
<p class="badge badge-default mt-2">{{ __('customer.language_hint') }}</p>
</div>
</div>
<hr>
{{ Form::hidden('faker_mail', $shopping_user->faker_mail) }}
{{ Form::hidden('language', $shopping_user->language) }}
@if($isView === 'customer-add')
{{ Form::hidden('billing_email_1', $billing_email) }}

View file

@ -345,11 +345,11 @@
</td>
</tr>
@endif
@if($shipment->recipient && isset($shipment->recipient['street']))
@if($shipment->recipient && isset($shipment->recipient['postnumber']))
<tr>
<td class="font-weight-semibold">Straße:</td>
<td class="font-weight-semibold">Postnummer:</td>
<td>
{{ $shipment->recipient['street'] }}
{{ $shipment->recipient['postnumber'] }}
</td>
</tr>
@endif
@ -539,16 +539,24 @@
<!-- Tracking Information -->
@if($shipment->tracking_status || $shipment->dhl_shipment_no)
<div class="card mb-4">
<div class="card-header">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-route text-info"></i>
Tracking-Informationen
</h5>
@if($shipment->dhl_shipment_no)
<a href="https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?lang=de&idc={{ $shipment->dhl_shipment_no }}"
target="_blank"
class="btn btn-sm btn-warning">
<i class="fas fa-external-link-alt"></i>
Bei DHL verfolgen
</a>
@endif
</div>
<div class="card-body">
@if($shipment->tracking_status)
<div class="alert alert-info">
<h6 class="alert-heading">
<div class="alert alert-info mb-4">
<h6 class="alert-heading mb-1">
<i class="fas fa-map-marker-alt"></i>
Aktueller Status: {{ $shipment->tracking_status }}
</h6>
@ -559,24 +567,52 @@
@endif
</div>
@endif
@if($shipment->dhl_shipment_no)
<div class="text-center">
<p>Verfolgen Sie diese Sendung direkt bei DHL:</p>
<a href="https://www.dhl.de/de/privatkunden/pakete-empfangen/verfolgen.html?lang=de&idc={{ $shipment->dhl_shipment_no }}"
target="_blank"
class="btn btn-warning">
<i class="fas fa-external-link-alt"></i>
Bei DHL verfolgen
</a>
{{-- TODO: Tracking-Nummer ist nicht mehr verfügbar
<a href="{{ route('public.tracking') }}?tracking_number={{ $shipment->dhl_shipment_no }}"
target="_blank"
class="btn btn-outline-info ml-2">
<i class="fas fa-search"></i>
Lokales Tracking
</a>
--}}
{{-- Tracking Events Timeline --}}
@if($shipment->trackingEvents && $shipment->trackingEvents->count() > 0)
<div class="tracking-timeline">
@foreach($shipment->trackingEvents as $index => $event)
<div class="d-flex mb-3 {{ $index === 0 ? '' : 'text-muted' }}">
<div class="mr-3 text-center" style="min-width: 40px;">
@if($index === 0)
@if($event->status_code === 'delivered')
<i class="fas fa-check-circle fa-lg text-success"></i>
@elseif($event->status_code === 'transit')
<i class="fas fa-truck fa-lg text-primary"></i>
@elseif($event->status_code === 'out-for-delivery')
<i class="fas fa-shipping-fast fa-lg text-warning"></i>
@elseif($event->status_code === 'failure' || $event->status_code === 'exception')
<i class="fas fa-exclamation-circle fa-lg text-danger"></i>
@elseif($event->status_code === 'returned')
<i class="fas fa-undo fa-lg text-secondary"></i>
@else
<i class="fas fa-circle fa-lg text-info"></i>
@endif
@else
<i class="fas fa-circle text-muted" style="font-size: 0.6rem; margin-top: 6px;"></i>
@endif
</div>
<div class="flex-grow-1">
<div class="{{ $index === 0 ? 'font-weight-bold' : '' }}">
{{ $event->status_text }}
</div>
<small class="text-muted">
{{ $event->event_time->format('d.m.Y H:i') }} Uhr
@if($event->location)
&middot; {{ $event->location }}
@endif
</small>
</div>
</div>
@if(!$loop->last)
<div class="ml-3 border-left" style="height: 8px; margin-left: 19px;"></div>
@endif
@endforeach
</div>
@elseif(!$shipment->tracking_status)
<div class="text-center text-muted py-3">
<i class="fas fa-info-circle"></i>
Noch keine Tracking-Daten vorhanden. Klicken Sie auf "Tracking aktualisieren" um die Daten abzurufen.
</div>
@endif
</div>

View file

@ -26,6 +26,8 @@
{!! Form::open(['action' => route('admin_lead_store')."?show=".$show, 'class' => 'form-horizontal', 'id'=>'lead-form-validation']) !!}
<input type="hidden" name="user_id" value="{{ $user->id }}">
<div class="text-left mt-0 mb-2">
<button type="submit" class="btn btn-submit btn-primary">{{ __('save') }}</button>&nbsp;
<a href="{{ route('admin_leads') }}" class="btn btn-default">{{ __('back') }}</a>
@ -46,7 +48,55 @@
</div>
{!! Form::close() !!}
<!-- Modal für Vertragsneuerstellung -->
<div class="modal fade" id="modal-recreate-contract">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Beratervertrag neu erstellen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
</div>
<div class="modal-body">
<p class="mb-3">
<strong>Der Vertrag wird neu erstellt (DE @if($user->account->language !== 'de') + {{ strtoupper($user->account->language) }}@endif).</strong><br>
Dies überschreibt die bestehenden Vertragsdateien.
</p>
<p class="mb-2">Welches Datum soll im Vertrag verwendet werden?</p>
<div class="alert alert-info">
@if($user->active_date)
<strong>Bestehendes Vertragsdatum:</strong> {{ $user->getActiveDateFormat(false) }}
@else
<strong>Hinweis:</strong> Kein bestehendes Vertragsdatum gefunden.
@endif
</div>
</div>
<div class="modal-footer">
<form action="{{ route('admin_lead_store') }}?show={{$show}}" method="POST" class="d-inline">
@csrf
<input type="hidden" name="user_id" value="{{ $user->id }}">
<input type="hidden" name="action" value="recreate_contract">
<input type="hidden" name="use_current_date" value="1">
<button type="submit" class="btn btn-primary">
<i class="fa fa-calendar"></i> Mit aktuellem Datum
</button>
</form>
@if($user->active_date)
<form action="{{ route('admin_lead_store') }}?show={{$show}}" method="POST" class="d-inline">
@csrf
<input type="hidden" name="user_id" value="{{ $user->id }}">
<input type="hidden" name="action" value="recreate_contract">
<input type="hidden" name="use_current_date" value="0">
<button type="submit" class="btn btn-success">
<i class="fa fa-calendar-check"></i> Mit bestehendem Datum ({{ $user->getActiveDateFormat(false) }})
</button>
</form>
@endif
</div>
</div>
</div>
</div>
<!-- Modal template -->

View file

@ -11,7 +11,6 @@
<div class="card-body p-0">
{!! Form::open(['action' => route('admin_leads'), 'class' => 'form-horizontal', 'id'=>'form_admin_leads']) !!}
<div class="form-row align-items-center px-4 pb-2 pt-3">
<div class="col-12 col-sm-4 col-md-4 col-lg-4 mb-1">
<select class="selectpicker on_change_select" data-style="btn-default" name="leads_filter_sponsor_id" id="leads_filter_sponsor_id" data-live-search="true">

View file

@ -38,7 +38,7 @@
<strong>{{__('Daten vollständig, freigeschaltet')}}</strong>: {{ $user->getActiveDateFormat() }}</p>
@if($user->files->count())
@foreach($user->files()->whereIdentifier('contract')->get() as $file)
<a class="btn btn-secondary" href="{{ route('storage_file', [$file->id, 'user']) }}" target="_blank">MIVITA_Beratervertrag.pdf</a>
<a class="btn btn-secondary" href="{{ route('storage_file', [$file->id, 'user']) }}" target="_blank">{{ $file->original_name }}</a>
@endforeach
@endif
@else
@ -72,6 +72,7 @@
@endif
</div>
<div class="col-sm-12">
@if(!$user->active)
<hr>
@if($user->release_account)
@ -83,6 +84,11 @@
@else
<strong><span class="text-danger">Berater muss Registrierung noch abschließen</span></strong>
@endif
@else
<hr>
<button type="button" class="btn btn-sm btn-info" data-toggle="modal" data-target="#modal-recreate-contract">
<i class="fa fa-file-pdf"></i> Vertrag neu erstellen (DE @if($user->account->language !== 'de') | {{ strtoupper($user->account->language) }}@endif)
</button>
@endif
</div>
</div>
@ -183,3 +189,4 @@
</div>
</div>

View file

@ -11,6 +11,56 @@
<div class="modal-body modal-body-overflow">
<table class="table user-view-table m-0">
<tbody>
{{-- Status & Business --}}
<tr>
<td>{{ __('team.account') }}:</td>
<td>
@if($user->isActive())
<span class="badge badge-outline-success">{{ __('team.active') }}</span>
@else
<span class="badge badge-outline-danger">{{ __('team.not_active') }}</span>
@endif
@if($user->payment_account)
{{ __('team.until') }}: {{ $user->getPaymentAccountDateFormat(false) }}
@endif
</td>
</tr>
@if($user->payment_shop)
<tr>
<td>{{ __('team.shop') }}:</td>
<td>{{ __('team.until') }}: {{ $user->getPaymentShopDateFormat(false) }}</td>
</tr>
@endif
@if($user->account->m_account)
<tr>
<td>{{ __('team.ID') }}:</td>
<td>{{ $user->account->m_account }}</td>
</tr>
@endif
@if($user->user_level)
<tr>
<td>{{ __('team.career_level') }}:</td>
<td>{{ \App\Services\TranslationHelper::transUserLevelName($user->user_level->name) }}</td>
</tr>
@endif
@if($user->user_sponsor && $user->user_sponsor->account)
<tr>
<td>{{ __('team.sponsor') }}:</td>
<td>{{ $user->user_sponsor->account->first_name }} {{ $user->user_sponsor->account->last_name }} | {{ $user->user_sponsor->email }}</td>
</tr>
@endif
@if($user->last_login)
<tr>
<td>{{ __('team.last_login') }}:</td>
<td>{{ \Carbon\Carbon::parse($user->last_login)->format(\Util::formatDateTimeDB()) }}</td>
</tr>
@endif
<tr>
<td>{{ __('team.registered_at') }}:</td>
<td>{{ $user->created_at ? $user->created_at->format(\Util::formatDateDB()) : '-' }}</td>
</tr>
<tr><td colspan="2"></td></tr>
{{-- Stammdaten --}}
<tr>
<td>{{ __('Company name') }}:</td>
<td> {{ $user->account->company }} </td>
@ -47,6 +97,10 @@
<td>{{ __('Country') }}:</td>
<td>{{ $user->account->country->getLocated() }}</td>
</tr>
<tr>
<td>{{ __('account.preferred_language') }}:</td>
<td>{{ \App\Models\UserAccount::getAvailableLanguages()[$user->account->getLocale()] ?? $user->account->getLocale() }}</td>
</tr>
<tr>
<td>{{ __('Date of birth') }}:</td>
<td>{{ $user->account->birthday }}</td>
@ -63,6 +117,18 @@
<td>{{ __('E-Mail') }}:</td>
<td>{{ $user->email }}</td>
</tr>
@if($user->account->tax_number)
<tr>
<td>{{ __('account.tax_number') }}:</td>
<td>{{ $user->account->tax_number }}</td>
</tr>
@endif
@if($user->account->tax_identification_number)
<tr>
<td>{{ __('account.VAT_ID_number') }}:</td>
<td>{{ $user->account->tax_identification_number }}</td>
</tr>
@endif
<tr>
</tr>
@if($user->account->same_as_billing)

View file

@ -2,128 +2,536 @@
@section('content')
@if ($errors->any())
<div class="row">
<div class="col-sm-12">
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
</div>
@if (session('success'))
<div class="alert alert-success alert-dismissible fade show">
{{ session('success') }}
<button type="button" class="close" data-dismiss="alert"><span>&times;</span></button>
</div>
@endif
@if (session('error'))
<div class="alert alert-danger alert-dismissible fade show">
{{ session('error') }}
<button type="button" class="close" data-dismiss="alert"><span>&times;</span></button>
</div>
@endif
@if (session('info'))
<div class="alert alert-info alert-dismissible fade show">
{{ session('info') }}
<button type="button" class="close" data-dismiss="alert"><span>&times;</span></button>
</div>
@endif
<div class="card">
<h5 class="card-header">
{{ __('navigation.payments') }} {{ __('navigation.tax_advisor') }}
<i class="fas fa-file-invoice"></i> &nbsp;DATEV Export - Steuerberater
</h5>
<div class="alert alert-danger">
<ul>
Modul ist in Arbeit! Noch nicht verwenden.
</ul>
</div>
<div class="card-body">
{!! Form::open(['action' => route('admin_payments_taxadvisor_download'), 'class' => '']) !!}
{!! Form::hidden('key', 'value') !!}
<button type="submit" name="action" value="export" class="btn btn-md btn-primary mb-2"><i class="ion ion-md-download"></i> &nbsp;Export als xls</button>
<hr>
<div class="form-row align-items-center px-0 pb-2 pt-0">
<div class="col-6 col-sm-4 col-md-4 col-lg-4 mb-1">
<select class="custom-select on_change_select_filter" name="payment_taxadvisor_filter_month">
@foreach($filter_months as $key=>$value)
<option value="{{$key}}" @if(session('payment_taxadvisor_filter_month') == $key) selected @endif>{{$value}}</option>
@endforeach
</select>
</div>
<div class="col-6 col-sm-4 col-md-4 col-lg-4 mb-1">
<select class="custom-select on_change_select_filter" name="payment_taxadvisor_filter_year">
@foreach($filter_years as $key=>$value)
<option value="{{$value}}" @if(session('payment_taxadvisor_filter_year') == $value) selected @endif>{{$value}}</option>
@endforeach
</select>
</div>
</div>
{!! Form::close() !!}
<div class="card">
<div class="card-datatable table-responsive">
<table class="table table-striped table-bordered" id="datatable-payment-taxadvisor">
<thead>
<div class="form-row align-items-center px-0 pb-2 pt-0">
<div class="col-6 col-sm-3 col-md-3 col-lg-2 mb-1">
<label class="small mb-1">Monat</label>
<select class="custom-select" name="payment_taxadvisor_filter_month" id="filter_month">
@foreach ($filter_months as $key => $value)
<option value="{{ $key }}" @if (session('payment_taxadvisor_filter_month') == $key) selected @endif>
{{ $value }}</option>
@endforeach
</select>
</div>
<div class="col-6 col-sm-3 col-md-3 col-lg-2 mb-1">
<label class="small mb-1">Jahr</label>
<select class="custom-select" name="payment_taxadvisor_filter_year" id="filter_year">
@foreach ($filter_years as $key => $value)
<option value="{{ $value }}" @if (session('payment_taxadvisor_filter_year') == $value) selected @endif>
{{ $value }}</option>
@endforeach
</select>
</div>
<div class="col-12 col-sm-6 col-md-6 col-lg-4 mb-1 d-flex align-items-end">
<button type="button" class="btn btn-info mr-2" id="btn-preview">
<i class="fas fa-search"></i> Vorschau laden
</button>
<button type="button" class="btn btn-primary" id="btn-generate"
@if ($current_export && $current_export->isLocked()) disabled @endif>
<i class="fas fa-cogs"></i> Export generieren
</button>
</div>
</div>
@if ($current_export)
<div class="alert alert-{{ $current_export->isLocked() ? 'secondary' : 'info' }} mt-3">
<div class="d-flex justify-content-between align-items-center flex-wrap">
<div class="mb-1">
<strong>Aktueller Export:</strong>
{!! $current_export->status_badge !!}
&mdash; {{ $current_export->total_lines }} Zeilen
({{ $current_export->invoice_count }} RE,
{{ $current_export->credit_count }} GS,
{{ $current_export->cancellation_count }} ST)
&mdash; {{ $current_export->created_at->format('d.m.Y H:i') }}
@if ($current_export->warning_count > 0)
<span class="badge badge-warning ml-1">{{ $current_export->warning_count }}
Warnungen</span>
@endif
</div>
<div class="mb-1">
<a href="{{ route('admin_payments_taxadvisor_download', $current_export->id) }}"
class="btn btn-sm btn-success">
<i class="fas fa-download"></i> CSV
</a>
@if (!$current_export->isLocked())
<form action="{{ route('admin_payments_taxadvisor_lock', $current_export->id) }}"
method="POST" class="d-inline" onsubmit="return confirm('Export wirklich sperren?')">
@csrf
<button type="submit" class="btn btn-sm btn-dark">
<i class="fas fa-lock"></i> Sperren
</button>
</form>
@endif
</div>
</div>
</div>
@endif
</div>
</div>
<div id="preview-section" style="display:none;">
<div class="row mb-3">
<div class="col-sm-6 col-md-3">
<div class="card text-center">
<div class="card-body py-3">
<div class="text-muted small">Rechnungen</div>
<h4 class="mb-0" id="stat-invoices">0</h4>
</div>
</div>
</div>
<div class="col-sm-6 col-md-3">
<div class="card text-center">
<div class="card-body py-3">
<div class="text-muted small">Gutschriften</div>
<h4 class="mb-0" id="stat-credits">0</h4>
</div>
</div>
</div>
<div class="col-sm-6 col-md-3">
<div class="card text-center">
<div class="card-body py-3">
<div class="text-muted small">Stornos</div>
<h4 class="mb-0" id="stat-cancellations">0</h4>
</div>
</div>
</div>
<div class="col-sm-6 col-md-3">
<div class="card text-center">
<div class="card-body py-3">
<div class="text-muted small">Gesamt Zeilen</div>
<h4 class="mb-0" id="stat-total">0</h4>
</div>
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-sm-6 col-md-4">
<div class="card">
<div class="card-body py-3">
<div class="text-muted small">Umsatz (Haben)</div>
<h5 class="mb-0 text-success" id="stat-revenue">0,00 EUR</h5>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="card">
<div class="card-body py-3">
<div class="text-muted small">Provisionen (Soll)</div>
<h5 class="mb-0 text-warning" id="stat-commissions">0,00 EUR</h5>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="card">
<div class="card-body py-3">
<div class="text-muted small">Stornos (Soll)</div>
<h5 class="mb-0 text-danger" id="stat-cancellation-amount">0,00 EUR</h5>
</div>
</div>
</div>
</div>
<div id="validation-section" style="display:none;">
<div id="validation-errors" class="alert alert-danger" style="display:none;">
<strong><i class="fas fa-exclamation-triangle"></i> Fehler:</strong>
<ul id="validation-errors-list" class="mb-0 mt-1"></ul>
</div>
<div id="validation-warnings" class="alert alert-warning" style="display:none;">
<strong><i class="fas fa-exclamation-circle"></i> Warnungen:</strong>
<ul id="validation-warnings-list" class="mb-0 mt-1"></ul>
</div>
</div>
<div class="card">
<h5 class="card-header">Vorschau: Konten-Zusammenfassung</h5>
<div class="card-body p-0">
<table class="table table-striped table-bordered mb-0">
<thead>
<tr>
<th>{{__('#') }}</th>
<th>{{__('Umsatz (ohne Soll/Haben-Kz)')}}</th>
<th>{{__('Soll/Haben-Kennzeichen')}}</th>
<th>{{__('Konto')}}</th>
<th>{{__('Gegenkonto (ohne BU-Schlüssel)')}}</th>
<th>{{__('BU-Schlüssel')}}</th>
<th>{{__('Belegdatum')}}</th>
<th>{{__('Belegfeld 1')}}</th>
<th>{{__('Buchungstext')}}</th>
<th>{{__('Datum')}}</th>
<th>{{__('Rechnung')}}</th>
<th>Konto</th>
<th>BU-Schl.</th>
<th>S/H</th>
<th>Anzahl</th>
<th class="text-right">Summe</th>
</tr>
</thead>
<tbody id="preview-table-body">
</tbody>
</table>
</div>
</div>
</div>
@if ($current_export)
<div class="card mt-3">
<h5 class="card-header">
Buchungszeilen (Export {{ $current_export->period_label }})
</h5>
<div class="card-body">
<div class="card-datatable table-responsive">
<table class="table table-striped table-bordered" id="datatable-datev-lines">
<thead>
<tr>
<th>#</th>
<th>Typ</th>
<th>Umsatz</th>
<th>S/H</th>
<th>Konto</th>
<th>Gegenkonto</th>
<th>BU</th>
<th>Belegdatum</th>
<th>Belegfeld 1</th>
<th>Buchungstext</th>
<th>USt-ID</th>
</tr>
</thead>
<tbody>
</tbody>
<tbody></tbody>
</table>
</div>
</div>
</div>
@endif
@if ($recent_exports->count() > 0)
<div class="card mt-3">
<h5 class="card-header">
<i class="fas fa-history"></i> Export-Historie
</h5>
<div class="card-body p-0">
<table class="table table-striped table-bordered mb-0">
<thead>
<tr>
<th>Periode</th>
<th>Status</th>
<th>Zeilen</th>
<th class="text-right">Umsatz</th>
<th class="text-right">Provisionen</th>
<th>Erstellt</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
@foreach ($recent_exports as $exp)
<tr>
<td>{{ $exp->period_label }}</td>
<td>{!! $exp->status_badge !!}</td>
<td>{{ $exp->total_lines }}</td>
<td class="text-right">{{ number_format($exp->total_revenue, 2, ',', '.') }} EUR</td>
<td class="text-right">{{ number_format($exp->total_commissions, 2, ',', '.') }} EUR</td>
<td>{{ $exp->created_at->format('d.m.Y H:i') }}</td>
<td>
<a href="{{ route('admin_payments_taxadvisor_download', $exp->id) }}"
class="btn btn-xs btn-success" title="Download">
<i class="fas fa-download"></i>
</a>
@if (!$exp->isLocked())
<form action="{{ route('admin_payments_taxadvisor_lock', $exp->id) }}"
method="POST" class="d-inline" onsubmit="return confirm('Export sperren?')">
@csrf
<button type="submit" class="btn btn-xs btn-dark" title="Sperren">
<i class="fas fa-lock"></i>
</button>
</form>
<form action="{{ route('admin_payments_taxadvisor_destroy', $exp->id) }}"
method="POST" class="d-inline"
onsubmit="return confirm('Export wirklich loeschen?')">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-xs btn-danger" title="Loeschen">
<i class="fas fa-trash"></i>
</button>
</form>
@else
<span class="badge badge-dark"><i class="fas fa-lock"></i></span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
<div class="modal fade" id="generateModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">DATEV Export generieren</h5>
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
</div>
<div class="modal-body">
<p>Soll der DATEV-Export fuer <strong id="modal-period"></strong> generiert werden?</p>
<p class="text-muted small">Ein vorhandener frueherer Export wird ersetzt.</p>
<div id="modal-preview-stats" class="mb-2"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Abbrechen</button>
<form id="form-generate" method="POST" action="{{ route('admin_payments_taxadvisor_generate') }}">
@csrf
<input type="hidden" name="month" id="generate-month">
<input type="hidden" name="year" id="generate-year">
<button type="submit" class="btn btn-primary">
<i class="fas fa-cogs"></i> Jetzt generieren
</button>
</form>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
<script>
function fmtNum(num) {
return new Intl.NumberFormat('de-DE', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(num);
}
$( document ).ready(function() {
var oTable = $('#datatable-payment-taxadvisor').DataTable({
"processing": true,
"serverSide": true,
"stateSave": true,
"searching": false,
function renderValidationEntry(entry) {
if (typeof entry === 'string') {
return entry;
}
var html = '<span>' + entry.message + '</span>';
var links = [];
if (entry.source_id && entry.belegfeld1) {
links.push('<a href="{{ url('/admin/payments/invoice') }}?search=' + entry.belegfeld1 +
'" target="_blank" title="Rechnung anzeigen"><i class="fas fa-file-invoice"></i> ' +
entry.belegfeld1 + '</a>');
}
if (entry.user_id) {
links.push('<a href="{{ url('/admin/sales/users/detail') }}/' + entry.user_id +
'" target="_blank" title="Berater anzeigen"><i class="fas fa-user"></i> User #' + entry
.user_id + '</a>');
}
if (links.length > 0) {
html += ' <span class="ml-2">' + links.join(' &middot; ') + '</span>';
}
return html;
}
$('#btn-preview').on('click', function() {
var btn = $(this);
var month = $('#filter_month').val();
var year = $('#filter_year').val();
btn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Laden...');
$.ajax({
url: '{!! route('admin_payments_taxadvisor_preview') !!}',
method: 'POST',
data: {
_token: '{{ csrf_token() }}',
month: month,
year: year
},
success: function(res) {
if (res.success) {
var s = res.data.summary;
$('#stat-invoices').text(s.invoice_count);
$('#stat-credits').text(s.credit_count);
$('#stat-cancellations').text(s.cancellation_count);
$('#stat-total').text(s.total_lines);
$('#stat-revenue').text(fmtNum(s.total_revenue) + ' EUR');
$('#stat-commissions').text(fmtNum(s.total_commissions) + ' EUR');
$('#stat-cancellation-amount').text(fmtNum(s.total_cancellations) +
' EUR');
var tbody = $('#preview-table-body');
tbody.empty();
var grouped = res.data.grouped;
if (grouped && grouped.length > 0) {
for (var i = 0; i < grouped.length; i++) {
var r = grouped[i];
var cls = r.soll_haben === 'H' ? 'badge-success' :
'badge-warning';
tbody.append('<tr><td>' + r.konto + '</td><td>' + r
.bu_schluessel + '</td><td><span class="badge ' +
cls + '">' + r.soll_haben + '</span></td><td>' + r
.count + '</td><td class="text-right">' + fmtNum(r
.total) + ' EUR</td></tr>');
}
} else {
tbody.append(
'<tr><td colspan="5" class="text-center text-muted">Keine Daten</td></tr>'
);
}
var v = res.data.validation;
$('#validation-section').show();
if (v.errors && v.errors.length > 0) {
var el = $('#validation-errors-list');
el.empty();
for (var e = 0; e < v.errors.length; e++) {
el.append('<li>' + renderValidationEntry(v.errors[e]) +
'</li>');
}
$('#validation-errors').show();
} else {
$('#validation-errors').hide();
}
if (v.warnings && v.warnings.length > 0) {
var wl = $('#validation-warnings-list');
wl.empty();
var max = Math.min(v.warnings.length, 20);
for (var w = 0; w < max; w++) {
wl.append('<li>' + renderValidationEntry(v.warnings[w]) +
'</li>');
}
if (v.warnings.length > 20) {
wl.append('<li><em>... und ' + (v.warnings.length - 20) +
' weitere</em></li>');
}
$('#validation-warnings').show();
} else {
$('#validation-warnings').hide();
}
$('#preview-section').slideDown();
}
},
error: function(xhr) {
alert('Fehler: ' + (xhr.responseJSON ? xhr.responseJSON.message :
'Unbekannt'));
},
complete: function() {
btn.prop('disabled', false).html(
'<i class="fas fa-search"></i> Vorschau laden');
}
});
});
$('#btn-generate').on('click', function() {
var month = $('#filter_month').val();
var year = $('#filter_year').val();
var monthText = $('#filter_month option:selected').text();
$('#modal-period').text(monthText + ' ' + year);
$('#generate-month').val(month);
$('#generate-year').val(year);
var stats = '';
var inv = $('#stat-invoices').text();
if (inv !== '0') {
stats = '<div class="small text-muted">' + inv + ' Rechnungen, ' + $('#stat-credits')
.text() + ' Gutschriften, ' + $('#stat-cancellations').text() + ' Stornos</div>';
}
$('#modal-preview-stats').html(stats);
$('#generateModal').modal('show');
});
$('#filter_month, #filter_year').on('change', function() {
var month = $('#filter_month').val();
var year = $('#filter_year').val();
window.location.href = '{!! route('admin_payments_taxadvisor') !!}?payment_taxadvisor_filter_month=' + month +
'&payment_taxadvisor_filter_year=' + year;
});
@if ($current_export)
$('#datatable-datev-lines').DataTable({
processing: true,
serverSide: true,
stateSave: true,
ajax: {
url: '{!! route('admin_payments_taxadvisor_datatable') !!}',
data: function(d) {
d.payment_taxadvisor_filter_month = $('select[name=payment_taxadvisor_filter_month]').val();
d.payment_taxadvisor_filter_year = $('select[name=payment_taxadvisor_filter_year]').val();
d.export_id = {{ $current_export->id }};
}
},
"order": [[0, "asc" ]],
"columns": [
{ data: 'id', orderable: true, searchable: false },
{ data: 'turnover', name: 'turnover', orderable: false, searchable: false },
{ data: 'debit_credit_indicator', name: 'debit_credit_indicator', orderable: false, searchable: false },
{ data: 'account', name: 'account', orderable: false, searchable: false },
{ data: 'contra_account', name: 'contra_account', orderable: false, searchable: false },
{ data: 'bu_key', name: 'bu_key', orderable: false, searchable: false },
{ data: 'voucher_date', name: 'voucher_date', orderable: true, searchable: false },
{ data: 'document_field_1', name: 'document_field_1', orderable: false, searchable: false },
{ data: 'posting_text', name: 'posting_text', orderable: false, searchable: false },
{ data: 'date', name: 'date', orderable: true, searchable: false },
{ data: 'invoice', name: 'invoice', searchable: false },
order: [
[0, 'asc']
],
"bLengthChange": false,
"iDisplayLength": 100,
"language": {
"url": "/js/datatables-{{ \App::getLocale() }}.json"
columns: [{
data: 'line_number',
orderable: true,
searchable: false
},
{
data: 'source_type_label',
orderable: false,
searchable: true
},
{
data: 'amount_display',
orderable: false,
searchable: false
},
{
data: 'soll_haben',
orderable: false,
searchable: true
},
{
data: 'konto',
orderable: false,
searchable: true
},
{
data: 'gegenkonto',
orderable: false,
searchable: true
},
{
data: 'bu_schluessel',
orderable: false,
searchable: true
},
{
data: 'belegdatum_display',
orderable: false,
searchable: false
},
{
data: 'belegfeld1',
orderable: false,
searchable: true
},
{
data: 'buchungstext',
orderable: false,
searchable: true
},
{
data: 'eu_ustid',
orderable: false,
searchable: true
},
],
bLengthChange: false,
iDisplayLength: 50,
language: {
url: '/js/datatables-{{ \App::getLocale() }}.json'
}
});
@endif
});
</script>
$('select.on_change_select_filter').on('change', function(){
oTable.draw();
});
$('input.on_keyup_input_filter').on('keyup', function(){
oTable.draw();
});
});
</script>
@endsection

View file

@ -121,6 +121,26 @@
</div>
</div>
<hr>
<div class="form-row">
<div class="form-group col-sm-12">
<label class="form-label">Versandkostenfrei für Berater (FcB.)</label>
<label class="custom-control custom-checkbox">
{!! Form::checkbox('free_shipping_consultant', 1, $product->free_shipping_consultant, ['class'=>'custom-control-input', 'id'=>'free_shipping_consultant']) !!}
<span class="custom-control-label">Versandkosten für Berater sind bei diesem Produkt immer 0 (z.B. Starterpakete).</span>
</label>
</div>
</div>
<hr>
<div class="form-row">
<div class="form-group col-sm-12">
<label class="form-label">Reine Mitgliedschaft (MoP.)</label>
<label class="custom-control custom-checkbox">
{!! Form::checkbox('is_membership_only', 1, $product->is_membership_only, ['class'=>'custom-control-input', 'id'=>'is_membership_only']) !!}
<span class="custom-control-label">Dieses Produkt ist eine reine Mitgliedschaft ohne Starterpaket (Warnung im Wizard).</span>
</label>
</div>
</div>
<hr>
<div class="form-row">
<div class="form-group col-sm-8">
<label class="form-label">Kaufeinschränkung Berater</label>

View file

@ -4,14 +4,15 @@
<div class="row">
<div class="col-md-2 mb-1">
<strong class="mr-2">{{ __('Status') }}:</strong>
<span class="text-big">
{!! \App\Services\Payment::getShoppingOrderBadge($shopping_order) !!}
</span>
<div class="d-flex flex-wrap align-items-center mt-1" style="gap: 6px;">
<span class="text-big">
{!! \App\Services\Payment::getShoppingOrderBadge($shopping_order) !!}
</span>
</div>
</div>
<div class="col-md-4 mb-1">
<div class="col-md-3 mb-1">
<strong class="mr-2">{{ __('order.shipping') }}:</strong>
<div style="display: inline-block;">
@if($shopping_order->payment_for !== 8)
<div class="d-flex flex-wrap align-items-center mt-1" style="gap: 6px;"> @if($shopping_order->payment_for !== 8)
@if ($isAdmin)
<button type="button" class="btn btn-sm btn-{{ $shopping_order->getShippedColor() }}"
data-toggle="modal" data-target="#modals-shipped" data-id="{{ $shopping_order->id }}"
@ -37,15 +38,26 @@
@endif
</div>
</div>
<div class="col-md-3 mb-1">
<div class="col-md-4 mb-2">
<strong class="mr-2">{{ __('order.invoice') }}:</strong>
<div style="display: inline-block;">
<div class="d-flex flex-wrap align-items-center mt-1" style="gap: 6px;">
@if ($isAdmin)
@if ($shopping_order->isInvoice())
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'download']) }}"
class="btn btn-primary btn-sm"><i class="fa fa-download"></i></a>
class="btn btn-primary btn-sm" title="Download DE"><i class="fa fa-download"></i></a>
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'stream']) }}"
target="_blank" class="btn btn-warning btn-sm"><i class="fa fa-eye"></i></a>
target="_blank" class="btn btn-warning btn-sm" title="Ansicht DE"><i class="fa fa-eye"></i></a>
{{-- Lokalisierte Versionen --}}
@foreach($shopping_order->user_invoice->getAvailableLocales() as $locale)
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'download', $locale]) }}"
class="btn btn-outline-primary btn-sm" title="Download {{ strtoupper($locale) }}">
<i class="fa fa-download"></i> {{ strtoupper($locale) }}
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'stream', $locale]) }}"
class="btn btn-outline-warning btn-sm" title="Ansicht {{ strtoupper($locale) }}">
<i class="fa fa-eye"></i> {{ strtoupper($locale) }}
</a>
@endforeach
@if (Auth::user()->isSySAdmin())
<button type="button" class="btn btn-sm btn-info" data-toggle="modal"
data-target="#modals-invoice" data-id="{{ $shopping_order->id }}" //TODO
@ -67,9 +79,20 @@
@else
@if ($shopping_order->isInvoice())
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'download']) }}"
class="btn btn-primary btn-sm"><i class="fa fa-download"></i></a>
class="btn btn-primary btn-sm" title="Download DE"><i class="fa fa-download"></i></a>
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'stream']) }}"
target="_blank" class="btn btn-warning btn-sm"><i class="fa fa-eye"></i></a>
target="_blank" class="btn btn-warning btn-sm" title="Ansicht DE"><i class="fa fa-eye"></i></a>
{{-- Lokalisierte Versionen --}}
@foreach($shopping_order->user_invoice->getAvailableLocales() as $locale)
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'download', $locale]) }}"
class="btn btn-outline-primary btn-sm" title="Download {{ strtoupper($locale) }}">
<i class="fa fa-download"></i> {{ strtoupper($locale) }}
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'invoice', 'stream', $locale]) }}"
class="btn btn-outline-warning btn-sm" title="Ansicht {{ strtoupper($locale) }}">
<i class="fa fa-eye"></i> {{ strtoupper($locale) }}
</a>
@endforeach
@endif
@endif
@if (($shopping_order->txaction === 'extern' || $shopping_order->txaction === 'extern_paid') && $shopping_order->wp_invoice_path)
@ -78,19 +101,65 @@
@endif
</div>
</div>
<div class="col-md-3 mb-1">
@if ($isAdmin && $shopping_order->payment_for != 8)
@if ($isAdmin && $shopping_order->payment_for != 8)
<div class="col-md-3 mb-2">
<strong class="mr-2">{{ __('order.delivery_note') }}:</strong>
<div style="display: inline-block;">
<div class="d-flex flex-wrap align-items-center mt-1" style="gap: 6px;">
@if ($shopping_order->isInvoice())
<a href="{{ route('storage_file', [$shopping_order->id, 'delivery', 'download']) }}"
class="btn btn-primary btn-sm"><i class="fa fa-download"></i></a>
class="btn btn-primary btn-sm" title="Download DE"><i class="fa fa-download"></i></a>
<a href="{{ route('storage_file', [$shopping_order->id, 'delivery', 'stream']) }}"
target="_blank" class="btn btn-warning btn-sm"><i class="fa fa-eye"></i></a>
target="_blank" class="btn btn-warning btn-sm" title="Ansicht DE"><i class="fa fa-eye"></i></a>
{{-- Lokalisierte Versionen --}}
@foreach($shopping_order->user_invoice->getAvailableLocales() as $locale)
<a href="{{ route('storage_file', [$shopping_order->id, 'delivery', 'download', $locale]) }}"
class="btn btn-outline-primary btn-sm" title="Download {{ strtoupper($locale) }}">
<i class="fa fa-download"></i> {{ strtoupper($locale) }}
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'delivery', 'stream', $locale]) }}"
class="btn btn-outline-warning btn-sm" title="Ansicht {{ strtoupper($locale) }}">
<i class="fa fa-eye"></i> {{ strtoupper($locale) }}
</a>
@endforeach
@endif
</div>
@endif
</div>
@endif
<div class="col-md-3 mb-2">
@if (!$isAdmin && $shopping_order->isCancellationInvoice())
@php
$cancellation_invoice = $shopping_order->getCancellationInvoice();
@endphp
@if($cancellation_invoice)
<strong class="mr-2">Stornorechnung:</strong><span class="badge badge-danger">{{ $cancellation_invoice->full_number }}</span>
<br>
<div class="d-flex flex-wrap align-items-center mt-1" style="gap: 6px;">
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'download']) }}"
class="btn btn-danger btn-sm" title="Stornorechnung herunterladen DE">
<i class="fa fa-download"></i>
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'stream']) }}"
target="_blank" class="btn btn-danger btn-sm" title="Stornorechnung anzeigen DE">
<i class="fa fa-eye"></i>
</a>
{{-- Lokalisierte Versionen der Stornorechnung --}}
@foreach($cancellation_invoice->getAvailableLocales() as $locale)
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'download', $locale]) }}"
class="btn btn-outline-danger btn-sm" title="Download {{ strtoupper($locale) }}">
<i class="fa fa-download"></i> {{ strtoupper($locale) }}
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'stream', $locale]) }}"
class="btn btn-outline-danger btn-sm" title="Ansicht {{ strtoupper($locale) }}">
<i class="fa fa-eye"></i> {{ strtoupper($locale) }}
</a>
@endforeach
</div>
@endif
@endif
</div>
</div>
</div>
@ -122,7 +191,7 @@
<div class="card-body pb-1">
<div class="row">
<div class="col-md-12 mb-3">
<div class="col-md-9 mb-3">
<div class="text-muted small">{{ __('order.points_turnover_assigned') }}</div>
@if($shopping_order->user_sales_volume && $shopping_order->user_sales_volume->user)
{{ $shopping_order->user_sales_volume->user->getFullName() }}
@ -133,7 +202,48 @@
data-action="shopping-order-change-points" data-view="{{ $isView }}"
data-route="{{ route('modal_load') }}"><span class="fa fa-edit"></span></button>
@endif
</div>
<div class="col-md-3 mb-3">
@if ($isAdmin)
@if ($shopping_order->isCancellationInvoice())
@php
$cancellation_invoice = $shopping_order->getCancellationInvoice();
@endphp
@if($cancellation_invoice)
<strong class="mr-2">Stornorechnung:</strong><br>
<span class="badge badge-danger">{{ $cancellation_invoice->full_number }}</span>
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'download']) }}"
class="btn btn-danger btn-sm" title="Stornorechnung herunterladen DE">
<i class="fa fa-download"></i>
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'stream']) }}"
target="_blank" class="btn btn-danger btn-sm" title="Stornorechnung anzeigen DE">
<i class="fa fa-eye"></i>
</a>
{{-- Lokalisierte Versionen der Stornorechnung --}}
@foreach($cancellation_invoice->getAvailableLocales() as $locale)
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'download', $locale]) }}"
class="btn btn-outline-danger btn-sm" title="Download {{ strtoupper($locale) }}">
<i class="fa fa-download"></i> {{ strtoupper($locale) }}
</a>
<a href="{{ route('storage_file', [$shopping_order->id, 'cancellation', 'stream', $locale]) }}"
class="btn btn-outline-danger btn-sm" title="Ansicht {{ strtoupper($locale) }}">
<i class="fa fa-eye"></i> {{ strtoupper($locale) }}
</a>
@endforeach
<br><small class="text-muted">Erstellt am: {{ $cancellation_invoice->date }}</small>
@endif
@else
@if ($shopping_order->isInvoice())
<button type="button" class="btn btn-sm btn-outline-warning" data-toggle="modal"
data-target="#modals-cancellation-invoice" data-id="{{ $shopping_order->id }}"
data-back="{{ url()->current() }}" data-action="create_cancellation_invoice">
<span class="fa fa-undo"></span> <strong>Stornorechnung erstellen</strong>
</button>
@endif
@endif
@endif
</div>
</div>
</div>
@ -324,6 +434,10 @@
<div class="text-muted small">{{ __('Country') }}</div>
{{ $shopping_order->shopping_user->billing_country->getLocated() }}
</div>
<div class="col-md-3 mb-3">
<div class="text-muted small">{{ __('account.preferred_language') }}</div>
{{ \App\Models\ShoppingUser::getAvailableLanguages()[$shopping_order->shopping_user->language] ?? $shopping_order->shopping_user->language }}
</div>
</div>
</div>
<!-- / Billing -->
@ -671,7 +785,7 @@
<div class="form-group col-sm-12">
<label class="custom-control custom-checkbox">
{!! Form::checkbox('invoice_send_mail', 1, false, ['class' => 'custom-control-input']) !!}
<span class="custom-control-label">{{ __('order.invoice') }} <strong>nicht</strong> senden an:
<span class="custom-control-label">{{ __('order.invoice') }} senden an:
{{ $shopping_order->shopping_user->billing_email }}</span>
</label>
</div>
@ -713,6 +827,63 @@
</div>
</div>
<div class="modal fade" id="modals-cancellation-invoice">
<div class="modal-dialog">
<form class="modal-content form-prevent-multiple-submits"
action="{{ route('admin_sales_invoice_cancellation') }}" method="post">
@csrf
<input type="hidden" name="id" value="{{ $shopping_order->id }}">
<input type="hidden" name="action" value="create_cancellation_invoice">
<input type="hidden" name="back" value="{{ url()->current() }}">
<div class="modal-header">
<h5 class="modal-title">{{ __('Stornorechnung erstellen') }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
</div>
<div class="modal-body">
<div class="alert alert-warning">
<strong>Achtung!</strong> Sie sind dabei, eine Stornorechnung zu erstellen. Diese wird die
ursprüngliche Rechnung mit negativen Beträgen stornieren.
</div>
<div class="form-group col-sm-12">
<label class="form-label">{{ __('Ursprüngliche Rechnung') }}</label>
<div class="form-control-plaintext">
<strong>Rechnungsnummer:</strong>
{{ App\Services\Invoice::getNumber($shopping_order) }}<br>
<strong>Rechnungsdatum:</strong> {{ App\Services\Invoice::getDate($shopping_order) }}<br>
<strong>Betrag:</strong> {{ $shopping_order->getFormattedTotalShipping() }}
</div>
</div>
<div class="form-group col-sm-12">
<label class="form-label" for="cancellation_date">{{ __('Stornodatum') }}</label>
{!! Form::text('cancellation_date', now()->format('d.m.Y'), ['class' => 'form-control datepicker-base']) !!}
</div>
<div class="form-group col-sm-12">
<label class="form-label" for="cancellation_number">{{ __('Stornonummer') }}</label>
{!! Form::text('cancellation_number', App\Services\Invoice::getInvoiceNumber(), [
'class' => 'form-control',
'disabled',
]) !!}
<em> nächste Rechnungsnummer <a href="{{ route('admin_settings') }}"><i
class="fa fa-edit"></i></a></em>
</div>
<div class="form-group col-sm-12">
<label class="custom-control custom-checkbox">
{!! Form::checkbox('cancellation_send_mail', 1, false, ['class' => 'custom-control-input']) !!}
<span class="custom-control-label">Stornorechnung an
{{ $shopping_order->shopping_user->billing_email }}</span>
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
data-dismiss="modal">{{ __('close') }}</button>
<button type="submit" class="btn btn-danger button-prevent-multiple-submits"><i
class="spinner fa fa-spinner fa-spin"></i> Stornorechnung erstellen</button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function() {

View file

@ -136,8 +136,13 @@
<!-- DHL Standard-Einstellungen -->
<div class="form-row">
<div class="col-sm-12">
<h5>Standard-Einstellungen</h5>
<h5>Standard-Einstellungen @if(config('dhl.config_source') == 'database')
<span class="badge badge-success">Database</span>
@else
<span class="badge badge-primary">Environment</span>
@endif</h5>
</div>
<div class="form-group col-sm-4">
<label class="form-label">{{ __('API Basis URL') }}*</label>
{{ Form::text('settings[dhl_base_url][val]', \App\Models\Setting::getContentBySlug('dhl_base_url') ?: 'https://api-eu.dhl.com', array('class'=>'form-control')) }}

View file

@ -0,0 +1,692 @@
@extends('layouts.layout-2')
@push('head')
<style>
/* Bootstrap-select Dropdown im Modal */
.bootstrap-select .dropdown-menu {
z-index: 10060 !important;
}
</style>
@endpush
@section('content')
<h4 class="font-weight-bold py-2 mb-2">
<i class="ion ion-ios-people"></i> {{ __('navigation.user_cleanup') }}
</h4>
<div class="row mb-3">
<div class="col">
<div class="alert alert-info">
<strong>Info:</strong> Diese Übersicht zeigt alle deaktivierten und gelöschten User.
Deaktivierte User können ihre Downline behalten oder an den Sponsor übertragen haben.
Gelöschte User haben alle Daten an den Sponsor übertragen.
</div>
</div>
</div>
<div class="nav-tabs-top mb-4">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" href="{{ route('admin_user_cleanup') }}">
<i class="ion ion-ios-people"></i> Deaktivierte/Gelöschte User
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin_user_cleanup_logs') }}">
<i class="ion ion-md-git-network"></i> Downline-Übertragungen
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin_user_cleanup_shopping_logs') }}">
<i class="ion ion-md-cart"></i> Kunden-Übertragungen
</a>
</li>
</ul>
</div>
<div class="card">
<div class="card-datatable table-responsive">
<table class="datatables-cleanup table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>{{ __('tables.firstname') }}</th>
<th>{{ __('tables.lastname') }}</th>
<th>{{ __('E-Mail') }}</th>
<th>M-Account</th>
<th>Status</th>
<th>Gelöscht am</th>
<th>Account bis</th>
<th>Sponsor</th>
<th>Pre-Sponsor</th>
<th>Downline</th>
<th>Kunden</th>
<th> #</th>
</tr>
</thead>
</table>
</div>
</div>
<!-- Modal User Historie -->
<div class="modal fade" id="modal-user-history" tabindex="-1" role="dialog">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fa fa-history"></i> User Historie & Details
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
</div>
<div class="modal-body" id="history-content" style="max-height: 75vh; overflow-y: auto;">
<div class="text-center py-5">
<i class="fa fa-spinner fa-spin fa-3x"></i>
<p class="mt-3">Lade Daten...</p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ __('close') }}</button>
</div>
</div>
</div>
</div>
<!-- Modal Restore User -->
<div class="modal fade" id="modal-restore-user">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">User wiederherstellen</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">×</button>
</div>
<div class="modal-body">
<input type="hidden" id="restore-user-id">
<div class="form-group">
<label>E-Mail:</label>
<input type="text" class="form-control" id="restore-user-email" readonly>
</div>
<div class="alert alert-warning">
<strong>Hinweis:</strong> Dies führt den Artisan-Befehl <code>user:restore</code> aus.
Bitte in den Logs überprüfen ob die Wiederherstellung erfolgreich war.
</div>
<div class="alert alert-info">
<strong>Was wird wiederhergestellt:</strong>
<ul class="mb-0">
<li>User wird reaktiviert (active=true)</li>
<li>Sponsor wird aus pre_sponsor wiederhergestellt</li>
<li>Downline-Struktur wird wiederhergestellt</li>
</ul>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ __('close') }}</button>
<button type="button" class="btn btn-success" id="btn-restore-user">
<i class="fa fa-undo"></i> User wiederherstellen
</button>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
$('.datatables-cleanup').dataTable({
"processing": true,
"serverSide": true,
"ajax": '{!! route('admin_user_cleanup_datatable') !!}',
"order": [[0, "desc"]],
"columns": [
{ data: 'user_id', name: 'id' },
{ data: 'first_name', name: 'account.first_name' },
{ data: 'last_name', name: 'account.last_name' },
{ data: 'email', name: 'email' },
{ data: 'm_account', name: 'account.m_account' },
{ data: 'status', name: 'status' },
{ data: 'deleted_at', name: 'pre_deleted_at', orderable: true },
{ data: 'payment_account', name: 'payment_account' },
{ data: 'm_sponsor', name: 'm_sponsor', orderable: false },
{ data: 'pre_sponsor', name: 'pre_sponsor', orderable: false },
{ data: 'childs_count', name: 'childs_count', orderable: false, searchable: false },
{ data: 'shopping_users_count', name: 'shopping_users_count', orderable: false, searchable: false },
{ data: 'action', orderable: false, searchable: false }
],
"bLengthChange": false,
"iDisplayLength": 50,
"language": {
"url": "/js/datatables-{{ \App::getLocale() }}.json"
}
});
// Modal Cleanup beim Schließen
$('#modal-user-history').on('hidden.bs.modal', function() {
// Zerstöre selectpicker Instanz wenn vorhanden
if ($('#select-new-sponsor').length && $('#select-new-sponsor').hasClass('selectpicker')) {
$('#select-new-sponsor').selectpicker('destroy');
}
currentUserId = null;
});
// Modal Historie Handler
$(document).on('click', '.btn-user-history', function() {
var userId = $(this).data('id');
var userEmail = $(this).data('email');
$('#modal-user-history').modal('show');
$('#history-content').html('<div class="text-center py-5"><i class="fa fa-spinner fa-spin fa-3x"></i><p class="mt-3">Lade Daten...</p></div>');
$.ajax({
url: '{{ route('admin_user_cleanup_history', ['userId' => ':userId']) }}'.replace(':userId', userId),
type: 'GET',
success: function(response) {
if (response.success) {
renderHistory(response);
} else {
$('#history-content').html('<div class="alert alert-danger">Fehler: ' + response.message + '</div>');
}
},
error: function(xhr) {
$('#history-content').html('<div class="alert alert-danger">Fehler beim Laden der Daten: ' + xhr.responseText + '</div>');
}
});
});
var currentUserId = null;
function renderHistory(data) {
currentUserId = data.user.id;
var html = '';
// User Info
html += '<div class="card mb-3">';
html += '<div class="card-header"><h5><i class="fa fa-user"></i> User Informationen</h5></div>';
html += '<div class="card-body">';
html += '<div class="row">';
html += '<div class="col-md-6"><strong>Name:</strong> ' + data.user.name + '</div>';
html += '<div class="col-md-6"><strong>E-Mail:</strong> ' + data.user.email + '</div>';
html += '<div class="col-md-6"><strong>M-Account:</strong> ' + data.user.m_account + '</div>';
html += '<div class="col-md-6"><strong>Status:</strong> ';
if (data.user.deleted) {
html += '<span class="badge badge-danger">Gelöscht am ' + data.user.deleted_at + '</span>';
} else if (data.user.active) {
html += '<span class="badge badge-success">Aktiv</span>';
} else {
html += '<span class="badge badge-warning">Deaktiviert</span>';
}
html += '</div>';
html += '</div></div></div>';
// Sponsor Neu-Zuweisen
// Die zu übertragenden Werte kommen IMMER aus den Logs (bereits übertragene, die neu zugewiesen werden sollen)
var childrenCount = data.cleanup_logs ? data.cleanup_logs.length : 0;
var customersCount = data.shopping_logs ? data.shopping_logs.length : 0;
html += '<div class="card mb-3 border-warning">';
html += '<div class="card-header bg-warning"><h5><i class="fa fa-exchange-alt"></i> Sponsor manuell neu zuweisen</h5></div>';
html += '<div class="card-body">';
html += '<div class="alert alert-warning">';
html += '<strong>⚠️ Achtung:</strong> Diese Funktion ermöglicht die manuelle Korrektur eines falsch zugewiesenen Sponsors. ';
html += 'Alle Änderungen werden vollständig geloggt und können bei Bedarf rückgängig gemacht werden.';
html += '</div>';
// Bereits übertragene Zuordnungen anzeigen (aus Logs)
html += '<div class="alert alert-info mb-3">';
html += '<strong>📊 Bereits übertragene Zuordnungen (können neu zugewiesen werden):</strong><br>';
html += '<div class="row mt-2">';
html += '<div class="col-6">';
html += '<i class="fa fa-users"></i> <strong>Downline:</strong> ';
if (childrenCount > 0) {
html += '<span class="badge badge-warning">' + childrenCount + ' bereits übertragen</span>';
} else {
html += '<span class="text-muted">Keine Übertragungen</span>';
}
html += '</div>';
html += '<div class="col-6">';
html += '<i class="fa fa-shopping-cart"></i> <strong>Kunden:</strong> ';
if (customersCount > 0) {
html += '<span class="badge badge-warning">' + customersCount + ' bereits übertragen</span>';
} else {
html += '<span class="text-muted">Keine Übertragungen</span>';
}
html += '</div>';
html += '</div>';
html += '</div>';
html += '<div class="form-group">';
html += '<label for="select-new-sponsor"><strong>Neuer Sponsor auswählen:</strong></label>';
html += '<select id="select-new-sponsor" class="selectpicker" data-style="btn-light" data-live-search="true" data-size="8" style="width: 100%;">';
html += '<option value="">Bitte auswählen...</option>';
html += '</select>';
html += '<small class="form-text text-muted">Suche nach Name, E-Mail oder M-Account</small>';
html += '</div>';
html += '<hr>';
html += '<h6 class="mb-3">Was soll mit übertragen werden?</h6>';
html += '<div class="form-group">';
html += '<div class="custom-control custom-checkbox">';
html += '<input type="checkbox" class="custom-control-input" id="transfer-downline" ' + (childrenCount > 0 ? 'checked' : 'disabled') + '>';
html += '<label class="custom-control-label" for="transfer-downline">';
html += '<strong>Downline neu zuweisen</strong> ';
if (childrenCount > 0) {
html += '<span class="badge badge-primary">' + childrenCount + '</span>';
} else {
html += '<span class="text-muted">(keine Übertragungen vorhanden)</span>';
}
html += '</label>';
html += '</div>';
html += '<small class="form-text text-muted">Die bereits übertragenen Downline-Mitglieder werden dem neuen Sponsor zugewiesen</small>';
html += '</div>';
html += '<div class="form-group">';
html += '<div class="custom-control custom-checkbox">';
html += '<input type="checkbox" class="custom-control-input" id="transfer-customers" ' + (customersCount > 0 ? 'checked' : 'disabled') + '>';
html += '<label class="custom-control-label" for="transfer-customers">';
html += '<strong>Shopping-Kunden neu zuweisen</strong> ';
if (customersCount > 0) {
html += '<span class="badge badge-primary">' + customersCount + '</span>';
} else {
html += '<span class="text-muted">(keine Übertragungen vorhanden)</span>';
}
html += '</label>';
html += '</div>';
html += '<small class="form-text text-muted">Die bereits übertragenen Shopping-Kunden werden dem neuen Berater zugewiesen</small>';
html += '</div>';
html += '<button type="button" class="btn btn-warning btn-block btn-lg" id="btn-reassign-sponsor">';
html += '<i class="fa fa-exchange-alt"></i> Sponsor jetzt neu zuweisen';
html += '</button>';
html += '</div></div>';
// Downline Position
html += '<div class="card mb-3">';
html += '<div class="card-header">';
html += '<h5 class="mb-0"><i class="fa fa-sitemap"></i> Position in der Downline</h5>';
html += '</div>';
html += '<div class="card-body">';
// Sponsor-Info
html += '<div class="row mb-3">';
html += '<div class="col-md-6">';
html += '<strong>Aktueller Sponsor:</strong><br>';
if (data.sponsor) {
html += '<span class="badge badge-' + (data.sponsor.active ? 'success' : 'warning') + '">' + data.sponsor.name + '</span> ';
html += '<small class="text-muted">(' + data.sponsor.email + ')</small>';
} else {
html += '<em class="text-muted">Nicht vorhanden</em>';
}
html += '</div>';
if (data.pre_sponsor) {
html += '<div class="col-md-6">';
html += '<strong>Vorheriger Sponsor (Pre-Sponsor):</strong><br>';
html += '<span class="badge badge-info">' + data.pre_sponsor.name + '</span> ';
html += '<small class="text-muted">(' + data.pre_sponsor.email + ')</small>';
html += '</div>';
}
html += '</div>';
html += '<hr>';
// Downline mit Badge
html += '<div class="mb-2">';
html += '<strong>Direkte Downline:</strong> ';
if (data.children.length > 0) {
html += '<span class="badge badge-primary">' + data.children.length + ' Mitglieder</span>';
} else {
html += '<span class="badge badge-secondary">0 Mitglieder</span>';
}
html += '</div>';
if (data.children.length > 0) {
html += '<table class="table table-sm mt-2">';
html += '<thead><tr><th>Name</th><th>E-Mail</th><th>Status</th></tr></thead><tbody>';
data.children.forEach(function(child) {
html += '<tr>';
html += '<td>' + child.name + '</td>';
html += '<td>' + child.email + '</td>';
html += '<td>';
if (child.deleted) {
html += '<span class="badge badge-danger">Gelöscht</span>';
} else if (child.active) {
html += '<span class="badge badge-success">Aktiv</span>';
} else {
html += '<span class="badge badge-warning">Inaktiv</span>';
}
if (child.is_pre_sponsor) {
html += ' <span class="badge badge-info">Pre-Sponsor</span>';
}
html += '</td></tr>';
});
html += '</tbody></table>';
} else {
html += '<p class="mt-2 mb-0"><em>Keine direkten Downline-Mitglieder</em></p>';
}
html += '</div></div></div>';
// Shopping Kunden
html += '<div class="card mb-3">';
html += '<div class="card-header">';
html += '<h5 class="mb-0">';
html += '<i class="fa fa-shopping-cart"></i> Shopping-Kunden ';
if (data.shopping_users.length > 0) {
html += '<span class="badge badge-primary">' + data.shopping_users.length + '</span>';
} else {
html += '<span class="badge badge-secondary">0</span>';
}
html += '</h5>';
html += '</div>';
html += '<div class="card-body">';
if (data.shopping_users.length > 0) {
html += '<table class="table table-sm">';
html += '<thead><tr><th>Name</th><th>E-Mail</th><th>Stadt</th><th>Erstellt am</th></tr></thead><tbody>';
data.shopping_users.forEach(function(customer) {
html += '<tr>';
html += '<td>' + customer.name + '</td>';
html += '<td>' + customer.email + '</td>';
html += '<td>' + customer.city + '</td>';
html += '<td>' + customer.created_at + '</td>';
html += '</tr>';
});
html += '</tbody></table>';
} else {
html += '<p class="mb-0"><em>Keine Shopping-Kunden vorhanden</em></p>';
}
html += '</div></div>';
// Cleanup Logs
if (data.cleanup_logs.length > 0) {
html += '<div class="card mb-3">';
html += '<div class="card-header">';
html += '<h5 class="mb-0">';
html += '<i class="fa fa-exchange-alt"></i> Downline-Übertragungen (Protokoll) ';
html += '<span class="badge badge-info">' + data.cleanup_logs.length + '</span>';
html += '</h5>';
html += '</div>';
html += '<div class="card-body">';
html += '<table class="table table-sm">';
html += '<thead><tr><th>Betroffener User</th><th>Status</th><th>Von Sponsor</th><th>Zu Sponsor</th><th>Datum</th></tr></thead><tbody>';
data.cleanup_logs.forEach(function(log) {
html += '<tr>';
html += '<td>' + (log.child_user ? log.child_user.name + '<br><small>' + log.child_user.email + '</small>' : 'N/A') + '</td>';
html += '<td>';
if (log.child_user) {
if (log.child_user.deleted) {
html += '<span class="badge badge-danger">Gelöscht</span>';
} else if (log.child_user.active) {
html += '<span class="badge badge-success">Aktiv</span>';
} else {
html += '<span class="badge badge-warning">Inaktiv</span>';
}
} else {
html += 'N/A';
}
html += '</td>';
html += '<td>' + (log.inactive_sponsor ? log.inactive_sponsor.name + '<br><small>' + log.inactive_sponsor.email + '</small>' : 'N/A') + '</td>';
html += '<td>';
// Ursprünglicher Sponsor aus dem Log
if (log.new_sponsor) {
html += '<small class="text-muted">Damals:</small><br>';
html += log.new_sponsor.name + '<br><small>' + log.new_sponsor.email + '</small>';
// Falls aktueller Sponsor anders ist
if (log.current_sponsor) {
html += '<hr class="my-1">';
html += '<span class="badge badge-warning">Geändert!</span><br>';
html += '<small class="text-success">Aktuell:</small><br>';
html += '<strong>' + log.current_sponsor.name + '</strong><br>';
html += '<small>' + log.current_sponsor.email + '</small>';
}
} else {
html += 'N/A';
}
html += '</td>';
html += '<td>' + log.created_at + '</td>';
html += '</tr>';
});
html += '</tbody></table></div></div>';
}
// Shopping Logs
if (data.shopping_logs.length > 0) {
html += '<div class="card mb-3">';
html += '<div class="card-header">';
html += '<h5 class="mb-0">';
html += '<i class="fa fa-users"></i> Kunden-Übertragungen (Protokoll) ';
html += '<span class="badge badge-info">' + data.shopping_logs.length + '</span>';
html += '</h5>';
html += '</div>';
html += '<div class="card-body">';
html += '<table class="table table-sm">';
html += '<thead><tr><th>Kunde</th><th>Neuer Berater</th><th>Datum</th></tr></thead><tbody>';
data.shopping_logs.forEach(function(log) {
html += '<tr>';
html += '<td>' + log.customer_name + '<br><small>' + log.customer_email + '</small></td>';
html += '<td>';
// Ursprünglicher Berater aus dem Log
if (log.new_member) {
html += '<small class="text-muted">Damals:</small><br>';
html += log.new_member.name + '<br><small>' + log.new_member.email + '</small>';
// Falls aktueller Berater anders ist
if (log.current_member) {
html += '<hr class="my-1">';
html += '<span class="badge badge-warning">Geändert!</span><br>';
html += '<small class="text-success">Aktuell:</small><br>';
html += '<strong>' + log.current_member.name + '</strong><br>';
html += '<small>' + log.current_member.email + '</small>';
}
} else {
html += 'N/A';
}
html += '</td>';
html += '<td>' + log.created_at + '</td>';
html += '</tr>';
});
html += '</tbody></table></div></div>';
}
$('#history-content').html(html);
// Lade Sponsoren und initialisiere selectpicker
setTimeout(function() {
var selectElement = $('#select-new-sponsor');
if (selectElement.length) {
console.log('Lade Sponsoren für selectpicker...');
// Lade alle aktiven Sponsoren
$.ajax({
url: '{{ route('admin_user_cleanup_search_sponsors') }}',
type: 'GET',
data: {
q: '', // Leere Suche = alle laden
exclude_user_id: currentUserId,
load_all: true
},
success: function(response) {
if (response.results && response.results.length > 0) {
// Füge alle Sponsoren als Options hinzu
response.results.forEach(function(sponsor) {
selectElement.append(
$('<option></option>')
.val(sponsor.id)
.text(sponsor.text)
);
});
// Initialisiere selectpicker
selectElement.selectpicker('refresh');
console.log('Selectpicker initialisiert mit ' + response.results.length + ' Sponsoren');
} else {
console.warn('Keine Sponsoren gefunden');
}
},
error: function(xhr) {
console.error('Fehler beim Laden der Sponsoren:', xhr);
}
});
} else {
console.error('Select Element nicht gefunden');
}
}, 200);
// Reassign Sponsor Handler
$('#btn-reassign-sponsor').off('click').on('click', function() {
var newSponsorId = $('#select-new-sponsor').val();
var transferDownline = $('#transfer-downline').is(':checked');
var transferCustomers = $('#transfer-customers').is(':checked');
if (!newSponsorId) {
alert('Bitte wählen Sie einen neuen Sponsor aus!');
return;
}
var sponsorName = $('#select-new-sponsor option:selected').text() || 'ID: ' + newSponsorId;
var confirmMsg = '═══════════════════════════════════════\n';
confirmMsg += 'SPONSOR NEU ZUWEISEN - BESTÄTIGUNG\n';
confirmMsg += '═══════════════════════════════════════\n\n';
confirmMsg += '👤 User:\n ' + data.user.name + '\n ' + data.user.email + '\n\n';
confirmMsg += '➡️ Neuer Sponsor:\n ' + sponsorName + '\n\n';
confirmMsg += '───────────────────────────────────────\n';
confirmMsg += 'WAS WIRD NEU ZUGEWIESEN?\n';
confirmMsg += '───────────────────────────────────────\n\n';
if (transferDownline && childrenCount > 0) {
confirmMsg += '✅ Downline: ' + childrenCount + ' bereits übertragene Kinder\n';
} else if (childrenCount > 0) {
confirmMsg += '❌ Downline: ' + childrenCount + ' Kinder (NICHT neu zuweisen)\n';
} else {
confirmMsg += '⚪ Downline: Keine Übertragungen vorhanden\n';
}
if (transferCustomers && customersCount > 0) {
confirmMsg += '✅ Kunden: ' + customersCount + ' bereits übertragene Kunden\n';
} else if (customersCount > 0) {
confirmMsg += '❌ Kunden: ' + customersCount + ' Kunden (NICHT neu zuweisen)\n';
} else {
confirmMsg += '⚪ Kunden: Keine Übertragungen vorhanden\n';
}
confirmMsg += '\n───────────────────────────────────────\n';
confirmMsg += '📝 WICHTIG:\n';
confirmMsg += ' • Alle Änderungen werden geloggt\n';
confirmMsg += ' • Kann rückgängig gemacht werden\n';
confirmMsg += ' • User wird dem neuen Sponsor zugewiesen\n\n';
confirmMsg += '═══════════════════════════════════════\n\n';
confirmMsg += 'Fortfahren?';
if (!confirm(confirmMsg)) {
return;
}
var btn = $(this);
btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Wird neu zugewiesen...');
$.ajax({
url: '{{ route('admin_user_cleanup_reassign_sponsor') }}',
type: 'POST',
data: {
_token: '{{ csrf_token() }}',
user_id: currentUserId,
new_sponsor_id: newSponsorId,
transfer_downline: transferDownline,
transfer_customers: transferCustomers
},
success: function(response) {
if (response.success) {
var msg = '═══════════════════════════════════════\n';
msg += '✅ ERFOLGREICH ABGESCHLOSSEN\n';
msg += '═══════════════════════════════════════\n\n';
msg += 'Der Sponsor wurde erfolgreich neu zugewiesen!\n\n';
if (response.logs && response.logs.length > 0) {
msg += '───────────────────────────────────────\n';
msg += '📋 Durchgeführte Änderungen:\n';
msg += '───────────────────────────────────────\n\n';
response.logs.forEach(function(log) {
msg += '• ' + log + '\n';
});
msg += '\n';
}
if (response.transferred) {
msg += '───────────────────────────────────────\n';
msg += '📊 Zusammenfassung:\n';
msg += '───────────────────────────────────────\n\n';
if (response.transferred.downline > 0) {
msg += '✓ Downline übertragen\n';
}
if (response.transferred.customers > 0) {
msg += '✓ Kunden übertragen\n';
}
msg += '✓ User neu zugewiesen\n\n';
}
msg += '═══════════════════════════════════════';
alert(msg);
$('#modal-user-history').modal('hide');
$('.datatables-cleanup').DataTable().ajax.reload();
} else {
alert('❌ FEHLER\n\n' + response.message);
btn.prop('disabled', false).html('<i class="fa fa-exchange-alt"></i> Sponsor jetzt neu zuweisen');
}
},
error: function(xhr) {
var errorMsg = 'Fehler beim Neu-Zuweisen';
try {
var response = JSON.parse(xhr.responseText);
errorMsg += ': ' + response.message;
} catch(e) {
errorMsg += ': ' + xhr.responseText;
}
alert(errorMsg);
btn.prop('disabled', false).html('<i class="fa fa-exchange-alt"></i> Sponsor jetzt neu zuweisen');
}
});
});
}
// Modal Restore Handler
$('#modal-restore-user').on('show.bs.modal', function(event) {
var button = $(event.relatedTarget);
$('#restore-user-id').val(button.data('id'));
$('#restore-user-email').val(button.data('email'));
});
$('#btn-restore-user').click(function() {
var userId = $('#restore-user-id').val();
var btn = $(this);
btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> Wird wiederhergestellt...');
$.ajax({
url: '{{ route('admin_user_cleanup_restore') }}',
type: 'POST',
data: {
_token: '{{ csrf_token() }}',
user_id: userId
},
success: function(response) {
if (response.success) {
alert('User wurde erfolgreich wiederhergestellt!');
$('#modal-restore-user').modal('hide');
$('.datatables-cleanup').DataTable().ajax.reload();
} else {
alert('Fehler: ' + response.message);
}
btn.prop('disabled', false).html('<i class="fa fa-undo"></i> User wiederherstellen');
},
error: function(xhr) {
alert('Fehler beim Wiederherstellen: ' + xhr.responseText);
btn.prop('disabled', false).html('<i class="fa fa-undo"></i> User wiederherstellen');
}
});
});
});
</script>
@endsection

View file

@ -0,0 +1,75 @@
@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">
<i class="ion ion-md-git-network"></i> Downline-Übertragungen (User Cleanup Logs)
</h4>
<div class="row mb-3">
<div class="col">
<div class="alert alert-info">
<strong>Info:</strong> Diese Übersicht zeigt alle Downline-Übertragungen bei User-Deaktivierungen.
Wenn ein User deaktiviert wird, werden seine Vertriebspartner-Kinder dem nächsten aktiven Sponsor zugewiesen.
</div>
</div>
</div>
<div class="nav-tabs-top mb-4">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link" href="{{ route('admin_user_cleanup') }}">
<i class="ion ion-ios-people"></i> Deaktivierte/Gelöschte User
</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="{{ route('admin_user_cleanup_logs') }}">
<i class="ion ion-md-git-network"></i> Downline-Übertragungen
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin_user_cleanup_shopping_logs') }}">
<i class="ion ion-md-cart"></i> Kunden-Übertragungen
</a>
</li>
</ul>
</div>
<div class="card">
<div class="card-datatable table-responsive">
<table class="datatables-logs table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Inaktiver Sponsor</th>
<th>Betroffenes Kind (Downline)</th>
<th>Neuer Sponsor</th>
<th>Übertragen am</th>
</tr>
</thead>
</table>
</div>
</div>
<script>
$(document).ready(function() {
$('.datatables-logs').dataTable({
"processing": true,
"serverSide": true,
"ajax": '{!! route('admin_user_cleanup_logs_datatable') !!}',
"order": [[0, "desc"]],
"columns": [
{ data: 'id', name: 'id' },
{ data: 'inactive_sponsor', name: 'inactive_sponsor_id' },
{ data: 'child_user', name: 'child_user_id' },
{ data: 'new_sponsor', name: 'new_sponsor_id' },
{ data: 'created_at', name: 'created_at' }
],
"bLengthChange": false,
"iDisplayLength": 50,
"language": {
"url": "/js/datatables-{{ \App::getLocale() }}.json"
}
});
});
</script>
@endsection

View file

@ -0,0 +1,75 @@
@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">
<i class="ion ion-md-cart"></i> Kunden-Übertragungen (Shopping User Member Logs)
</h4>
<div class="row mb-3">
<div class="col">
<div class="alert alert-info">
<strong>Info:</strong> Diese Übersicht zeigt alle Shopping-Kunden-Übertragungen bei User-Löschungen.
Wenn ein User gelöscht wird, werden seine Shopping-Kunden dem neuen Sponsor übertragen.
</div>
</div>
</div>
<div class="nav-tabs-top mb-4">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link" href="{{ route('admin_user_cleanup') }}">
<i class="ion ion-ios-people"></i> Deaktivierte/Gelöschte User
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('admin_user_cleanup_logs') }}">
<i class="ion ion-md-git-network"></i> Downline-Übertragungen
</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="{{ route('admin_user_cleanup_shopping_logs') }}">
<i class="ion ion-md-cart"></i> Kunden-Übertragungen
</a>
</li>
</ul>
</div>
<div class="card">
<div class="card-datatable table-responsive">
<table class="datatables-shopping-logs table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Vorheriger Berater</th>
<th>Shopping-Kunde</th>
<th>Neuer Berater</th>
<th>Übertragen am</th>
</tr>
</thead>
</table>
</div>
</div>
<script>
$(document).ready(function() {
$('.datatables-shopping-logs').dataTable({
"processing": true,
"serverSide": true,
"ajax": '{!! route('admin_user_cleanup_shopping_logs_datatable') !!}',
"order": [[0, "desc"]],
"columns": [
{ data: 'id', name: 'id' },
{ data: 'pre_member', name: 'pre_member_id' },
{ data: 'shopping_user', name: 'shopping_user_id' },
{ data: 'new_member', name: 'new_member_id' },
{ data: 'created_at', name: 'created_at' }
],
"bLengthChange": false,
"iDisplayLength": 50,
"language": {
"url": "/js/datatables-{{ \App::getLocale() }}.json"
}
});
});
</script>
@endsection