Kundenentscheid 25.09.2026: - Storno: Ist jede bezahlte Starterpaket-Bestellung eines Neupartners storniert (txaction = cancelled), bekommt das Tracking cancelled_at, eine Storno-Logzeile nimmt die Einmalpunkte zurueck. Nachtlauf und Neuaufbau markieren; "Meine Berechnung" zeigt den Partner durchgestrichen mit "Storniert am ..., zaehlt nicht". - Gezaehlt wird fuer alle, einen Rang bekommen nur bestaetigte Teilnehmer; Export und Summen nur fuer sie. Unbestaetigte sehen "Deine Praemie nach Bestaetigung", im Admin "Teilnahme nicht bestaetigt, keine Auszahlung". - Datenschutz: andere Berater sehen Unbestaetigte in der Rangliste nicht mehr (auch nicht anonym), VIP-Konten schon, der eigene Eintrag bleibt. - Teilnahmebedingungen Punkt 2 und 7 und Hinweistexte in de/en/es/fr. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
253 lines
14 KiB
PHP
253 lines
14 KiB
PHP
@extends('layouts.layout-2')
|
|
|
|
@section('content')
|
|
<h4 class="font-weight-bold py-2 mb-2">
|
|
{{ $incentive->name }}
|
|
<span class="badge badge-{{ $incentive->getStatusColor() }}">{{ $incentive->getStatusType() }}</span>
|
|
@if ($incentive->vip_only)
|
|
<span class="badge badge-dark" id="incentive-vip-only-badge" title="{{ __('incentive.vip_only_help') }}">{{ __('incentive.vip_only_badge') }}</span>
|
|
@endif
|
|
<div class="float-right">
|
|
<a href="{{ route('admin_incentive_edit', [$incentive->id]) }}" class="btn btn-sm btn-warning">
|
|
<span class="fa fa-edit"></span> {{ __('incentive.edit') }}
|
|
</a>
|
|
@if ($incentive->hasCashPayout())
|
|
<a href="{{ route('admin_incentive_payout_export', [$incentive->id]) }}" class="btn btn-sm btn-success"
|
|
id="incentive-payout-export">
|
|
<span class="fa fa-file-excel"></span> {{ __('incentive.payout_export') }}
|
|
</a>
|
|
@endif
|
|
{{-- <form action="{{ route('admin_incentive_recalculate', [$incentive->id]) }}" method="POST" class="d-inline">
|
|
@csrf
|
|
<button type="submit" class="btn btn-sm btn-info" onclick="return confirm('{{ __('incentive.recalculate_confirm') }}')">
|
|
<span class="fa fa-sync"></span> {{ __('incentive.recalculate') }}
|
|
</button>
|
|
</form>
|
|
<form action="{{ route('admin_incentive_recalculate', [$incentive->id]) }}" method="POST" class="d-inline">
|
|
@csrf
|
|
<input type="hidden" name="force" value="1">
|
|
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('{{ __('incentive.force_recalculate_confirm') }}')">
|
|
<span class="fa fa-redo"></span> {{ __('incentive.force_recalculate') }}
|
|
</button>
|
|
</form> --}}
|
|
</div>
|
|
</h4>
|
|
|
|
{{-- Konfiguration --}}
|
|
<div class="card mb-4">
|
|
<div class="card-header">{{ __('incentive.configuration') }}</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<strong>{{ __('incentive.qualification_start') }}:</strong>
|
|
{{ $incentive->qualification_start->format('d.m.Y') }}<br>
|
|
<strong>{{ __('incentive.qualification_end') }}:</strong>
|
|
{{ $incentive->qualification_end->format('d.m.Y') }}<br>
|
|
<strong>{{ __('incentive.calculation_end') }}:</strong>
|
|
{{ $incentive->calculation_end->format('d.m.Y') }}
|
|
</div>
|
|
<div class="col-md-4">
|
|
<strong>{{ __('incentive.points_partner_onetime') }}:</strong>
|
|
{{ $incentive->points_partner_onetime }}<br>
|
|
<strong>{{ __('incentive.points_abo_onetime') }}:</strong> {{ $incentive->points_abo_onetime }}<br>
|
|
<strong>{{ __('incentive.max_winners') }}:</strong> {{ $incentive->max_winners }}
|
|
</div>
|
|
<div class="col-md-4">
|
|
<strong>{{ __('incentive.min_direct_partners') }}:</strong> {{ $incentive->min_direct_partners }}<br>
|
|
<strong>{{ __('incentive.min_customer_abos') }}:</strong> {{ $incentive->min_customer_abos }}<br>
|
|
<strong>{{ __('incentive.include_sales_points') }}:</strong>
|
|
{{ $incentive->includesSalesPoints() ? __('incentive.yes') : __('incentive.no') }}<br>
|
|
<strong>{{ __('incentive.include_abos') }}:</strong>
|
|
{{ $incentive->includesAbos() ? __('incentive.yes') : __('incentive.no') }}
|
|
</div>
|
|
</div>
|
|
@if ($incentive->hasCashPayout())
|
|
<hr>
|
|
<div class="row" id="incentive-payout-config">
|
|
<div class="col-md-4">
|
|
<strong>{{ __('incentive.amount_per_partner') }}:</strong>
|
|
{{ \App\Services\Incentive\IncentivePayoutService::formatAmount((float) $incentive->amount_per_partner) }}
|
|
</div>
|
|
<div class="col-md-4">
|
|
@foreach ($incentive->rankBonuses() as $bonusRank => $bonusAmount)
|
|
<strong>{{ __('incentive.bonus_rank', ['n' => $bonusRank]) }}:</strong>
|
|
{{ \App\Services\Incentive\IncentivePayoutService::formatAmount($bonusAmount) }}<br>
|
|
@endforeach
|
|
</div>
|
|
@if ($payoutTotals)
|
|
<div class="col-md-4">
|
|
<strong>{{ __('incentive.payout_recipients') }}:</strong> {{ $payoutTotals['recipients'] }}<br>
|
|
<strong>{{ __('incentive.payout_partner_amount') }}:</strong>
|
|
{{ \App\Services\Incentive\IncentivePayoutService::formatAmount($payoutTotals['partner_amount']) }}<br>
|
|
<strong>{{ __('incentive.payout_rank_bonus') }}:</strong>
|
|
{{ \App\Services\Incentive\IncentivePayoutService::formatAmount($payoutTotals['rank_bonus']) }}<br>
|
|
<strong>{{ __('incentive.payout_total') }}:</strong>
|
|
<span class="font-weight-bold">{{ \App\Services\Incentive\IncentivePayoutService::formatAmount($payoutTotals['total']) }}</span>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Ranking --}}
|
|
<div class="card">
|
|
<div class="card-header">
|
|
{{ __('incentive.ranking') }} ({{ $participants->count() }} {{ __('incentive.participants') }})
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<table class="table table-striped table-bordered mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>{{ __('incentive.rank') }}</th>
|
|
<th>{{ __('incentive.consultant') }}</th>
|
|
<th>E-Mail</th>
|
|
<th>{{ __('incentive.admin_terms_accepted') }}</th>
|
|
<th>{{ __('incentive.total_points') }}</th>
|
|
<th>{{ __('incentive.partners') }}</th>
|
|
@if ($incentive->includesAbos())
|
|
<th>{{ __('incentive.abos') }}</th>
|
|
@endif
|
|
<th>{{ __('incentive.qualified') }}</th>
|
|
@if ($incentive->hasCashPayout())
|
|
<th class="text-right">{{ __('incentive.payout_total') }}</th>
|
|
@endif
|
|
<th>{{ __('incentive.status') }}</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($participants as $p)
|
|
@php
|
|
$isWinner = $p->is_qualified && $p->rank && $p->rank <= $incentive->max_winners;
|
|
@endphp
|
|
<tr
|
|
class="{{ $isWinner ? 'table-success font-weight-bold' : ($p->is_qualified ? 'font-weight-bold' : '') }}">
|
|
<td>{{ $p->rank ?? '—' }}</td>
|
|
<td>
|
|
@if ($p->user && $p->user->account)
|
|
{{ $p->user->account->first_name }} {{ $p->user->account->last_name }}
|
|
@else
|
|
{{ $p->user->email ?? 'N/A' }}
|
|
@endif
|
|
</td>
|
|
<td>{{ $p->user->email ?? '' }}</td>
|
|
<td>
|
|
@if ($p->accepted_terms_at)
|
|
<span class="badge badge-success">{{ __('incentive.yes') }}</span>
|
|
<span class="text-muted small d-block"
|
|
title="{{ __('incentive.admin_terms_accepted_at_tooltip') }}">{{ $p->accepted_terms_at->format('d.m.Y H:i') }}</span>
|
|
@else
|
|
<span class="badge badge-secondary">{{ __('incentive.admin_terms_pending') }}</span>
|
|
@endif
|
|
</td>
|
|
<td>{{ number_format($p->total_points, 0, ',', '.') }}</td>
|
|
<td>
|
|
{{ $p->qualified_partners }}/{{ $incentive->min_direct_partners }}
|
|
@if ($p->qualified_partners >= $incentive->min_direct_partners)
|
|
<span class="text-success">✓</span>
|
|
@endif
|
|
</td>
|
|
@if ($incentive->includesAbos())
|
|
<td>
|
|
{{ $p->qualified_abos }}/{{ $incentive->min_customer_abos }}
|
|
@if ($p->qualified_abos >= $incentive->min_customer_abos)
|
|
<span class="text-success">✓</span>
|
|
@endif
|
|
</td>
|
|
@endif
|
|
<td>
|
|
@if ($p->is_qualified)
|
|
<span class="badge badge-success">{{ __('incentive.yes') }}</span>
|
|
@else
|
|
<span class="badge badge-secondary">{{ __('incentive.no') }}</span>
|
|
@endif
|
|
</td>
|
|
@if ($incentive->hasCashPayout())
|
|
@php $payout = $payoutByParticipantId[$p->id] ?? null; @endphp
|
|
<td class="text-right">
|
|
@if ($payout && $payout['total'] > 0 && ! $payout['confirmed'])
|
|
<span class="text-muted">{{ \App\Services\Incentive\IncentivePayoutService::formatAmount($payout['total']) }}</span>
|
|
<small class="text-muted d-block">{{ __('incentive.payout_unconfirmed') }}</small>
|
|
@elseif ($payout && $payout['total'] > 0)
|
|
{{ \App\Services\Incentive\IncentivePayoutService::formatAmount($payout['total']) }}
|
|
@if ($payout['rank_bonus'] > 0)
|
|
<small class="text-muted d-block">{{ __('incentive.payout_incl_bonus', ['amount' => \App\Services\Incentive\IncentivePayoutService::formatAmount($payout['rank_bonus'])]) }}</small>
|
|
@endif
|
|
@else
|
|
—
|
|
@endif
|
|
</td>
|
|
@endif
|
|
<td>
|
|
@if ($isWinner)
|
|
<span class="badge badge-warning">{{ __('incentive.winner') }}</span>
|
|
@elseif($p->is_qualified)
|
|
<span class="badge badge-info">{{ __('incentive.qualified') }}</span>
|
|
@else
|
|
<span class="badge badge-secondary">{{ __('incentive.open') }}</span>
|
|
@endif
|
|
</td>
|
|
<td>
|
|
<button type="button" class="btn btn-sm btn-outline-primary btn-participant-details"
|
|
data-participant-id="{{ $p->id }}"
|
|
data-participant-name="{{ $p->user && $p->user->account ? $p->user->account->first_name . ' ' . $p->user->account->last_name : ($p->user->email ?? 'N/A') }}">
|
|
<span class="fa fa-eye"></span>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="{{ ($incentive->hasCashPayout() ? 11 : 10) - ($incentive->includesAbos() ? 0 : 1) }}" class="text-center text-muted">{{ __('incentive.no_participants') }}</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{{-- Modal: Teilnehmer-Details --}}
|
|
<div class="modal fade" id="participantDetailsModal" tabindex="-1" role="dialog">
|
|
<div class="modal-dialog modal-xl" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">{{ __('incentive.calculation_details') }}: <span
|
|
id="modalParticipantName"></span></h5>
|
|
<button type="button" class="close" data-dismiss="modal"><span>×</span></button>
|
|
</div>
|
|
<div class="modal-body" id="modalParticipantBody">
|
|
<div class="text-center py-4">
|
|
<div class="spinner-border text-primary" role="status">
|
|
<span class="sr-only">Loading...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary"
|
|
data-dismiss="modal">{{ __('incentive.close') }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
$(document).on('click', '.btn-participant-details', function() {
|
|
var participantId = $(this).data('participant-id');
|
|
var participantName = $(this).data('participant-name');
|
|
|
|
$('#modalParticipantName').text(participantName);
|
|
$('#modalParticipantBody').html(
|
|
'<div class="text-center py-4"><div class="spinner-border text-primary" role="status"><span class="sr-only">Loading...</span></div></div>'
|
|
);
|
|
$('#participantDetailsModal').modal('show');
|
|
|
|
$.get('{{ url('/admin/incentives/participant') }}/' + participantId + '/details', function(html) {
|
|
$('#modalParticipantBody').html(html);
|
|
}).fail(function() {
|
|
$('#modalParticipantBody').html(
|
|
'<div class="alert alert-danger">Fehler beim Laden der Details.</div>');
|
|
});
|
|
});
|
|
</script>
|
|
@endsection
|