mivita/app/Http/Controllers/User/IncentiveController.php
2026-04-14 18:07:45 +02:00

199 lines
6.2 KiB
PHP

<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Admin\IncentiveController as AdminIncentiveController;
use App\Http\Controllers\Controller;
use App\Models\Incentive;
use App\Models\IncentiveParticipant;
use App\Models\UserAbo;
use App\Services\Incentive\IncentivePointsLogRepairService;
use App\Services\Incentive\IncentiveTracker;
use App\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use Request;
class IncentiveController extends Controller
{
/**
* Anzahl Plaetze in der User-Live-Rangliste (Gewinner-Highlight bleibt ueber max_winners, typ. Top 20).
*/
public const USER_RANKING_DISPLAY_LIMIT = 30;
public function __construct()
{
$this->middleware('active.account');
}
public function teaser($slug)
{
$incentive = Incentive::where('slug', $slug)
->where('status', '!=', 0)
->firstOrFail();
$user = Auth::user();
$participant = IncentiveParticipant::where('incentive_id', $incentive->id)
->where('user_id', $user->id)
->first();
$galleryImages = $this->collectGalleryImages($incentive);
return view('user.incentive.teaser', [
'incentive' => $incentive,
'participant' => $participant,
'galleryImages' => $galleryImages,
]);
}
public function show($slug)
{
$incentive = Incentive::where('slug', $slug)
->where('status', '!=', 0) // not draft
->firstOrFail();
$user = Auth::user();
$participant = IncentiveParticipant::where('incentive_id', $incentive->id)
->where('user_id', $user->id)
->first();
$ranking = IncentiveParticipant::where('incentive_id', $incentive->id)
->withRankingActivity()
->with('user', 'user.account')
->orderByIncentiveLeaderboard()
->paginate(100);
$participateHasTrackableAbos = false;
if (! $participant?->accepted_terms_at) {
$participateHasTrackableAbos = $this->userHasTrackableAbosForIncentive($user, $incentive);
}
return view('user.incentive.show', [
'incentive' => $incentive,
'participant' => $participant,
'hasConfirmedParticipation' => $participant && $participant->accepted_terms_at !== null,
'ranking' => $ranking,
'participateHasTrackableAbos' => $participateHasTrackableAbos,
'isVipView' => $user->isVIP(),
]);
}
public function participate($slug)
{
$incentive = Incentive::where('slug', $slug)
->active()
->firstOrFail();
if (! Request::has('accept_terms')) {
\Session()->flash('alert-error', __('incentive.terms_required'));
return redirect(route('user_incentive_show', [$slug]));
}
$user = Auth::user();
$participant = IncentiveParticipant::firstOrCreate(
[
'incentive_id' => $incentive->id,
'user_id' => $user->id,
],
[
'accepted_terms_at' => null,
]
);
if ($participant->accepted_terms_at !== null) {
\Session()->flash('alert-info', __('incentive.already_participating'));
return redirect(route('user_incentive_show', [$slug]));
}
$participant->accepted_terms_at = Carbon::now();
$participant->save();
$repair = app(IncentivePointsLogRepairService::class);
$repair->syncMissingTrackingAbos($participant);
$repair->syncMissingSalesVolumeLogs($participant);
$participant->refresh()->recalculateFromTrackingTables()->save();
IncentiveTracker::updateRanking($incentive);
\Session()->flash('alert-success', __('incentive.participation_confirmed'));
return redirect(route('user_incentive_show', [$slug]));
}
public function details($slug)
{
$incentive = Incentive::where('slug', $slug)
->where('status', '!=', 0)
->firstOrFail();
$user = Auth::user();
$participant = IncentiveParticipant::with('incentive', 'user', 'user.account')
->where('incentive_id', $incentive->id)
->where('user_id', $user->id)
->firstOrFail();
if ($participant->accepted_terms_at === null) {
\Session()->flash('alert-info', __('incentive.details_requires_confirmation'));
return redirect(route('user_incentive_show', [$slug]));
}
$data = AdminIncentiveController::buildParticipantDetailData($participant);
return view('user.incentive.details', $data);
}
/**
* Sammelt alle verfuegbaren Galerie-Bilder aus public/img/incentive/
* (ohne das Hauptbild, das bereits als Hero verwendet wird).
*
* @return list<string>
*/
private function collectGalleryImages(Incentive $incentive): array
{
$dir = public_path('img/incentive');
if (! is_dir($dir)) {
return [];
}
$files = glob($dir.'/*.{jpg,jpeg,png,webp}', GLOB_BRACE) ?: [];
$images = [];
foreach ($files as $file) {
$basename = basename($file);
$images[] = 'img/incentive/'.$basename;
}
sort($images);
return $images;
}
/**
* Hinweis auf der Teilnehmen-Karte: Es gibt bereits ein Eigenabo oder ein Kundenabo im Qualifikationszeitraum.
*/
private function userHasTrackableAbosForIncentive(User $user, Incentive $incentive): bool
{
$qualEnd = $incentive->qualification_end->copy()->endOfDay();
$hasOwnActiveAbo = UserAbo::query()
->where('user_id', $user->id)
->where('is_for', 'me')
->where('status', 2)
->exists();
$hasCustomerAboInQualification = UserAbo::query()
->where('member_id', $user->id)
->where('is_for', 'ot')
->where('status', 2)
->whereBetween('created_at', [
$incentive->qualification_start,
$qualEnd,
])
->exists();
return $hasOwnActiveAbo || $hasCustomerAboInQualification;
}
}