200 lines
6.2 KiB
PHP
200 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()
|
|
->limit(self::USER_RANKING_DISPLAY_LIMIT)
|
|
->get();
|
|
|
|
$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,
|
|
'rankingDisplayLimit' => self::USER_RANKING_DISPLAY_LIMIT,
|
|
'participateHasTrackableAbos' => $participateHasTrackableAbos,
|
|
]);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|