DashboardNews::getActiveNews(), 'archiveNews' => DashboardNews::getArchiveNews(), ]); } // login / Dashboard public function show() { if (! Auth::check()) { return redirect('login'); } $user = Auth::user(); // Mehrere Incentives koennen parallel aktiv sein (E1): je eine Dashboard-Karte. $activeIncentives = collect(); $incentiveParticipants = collect(); if ($user->isActiveAccount()) { $activeIncentives = Incentive::activeForNavigation(); if ($activeIncentives->isNotEmpty()) { $incentiveParticipants = IncentiveParticipant::query() ->whereIn('incentive_id', $activeIncentives->pluck('id')) ->where('user_id', $user->id) ->get() ->keyBy('incentive_id'); } } $activeIncentive = $activeIncentives->first(); $incentiveParticipant = $activeIncentive ? $incentiveParticipants->get($activeIncentive->id) : null; // Eigenes Abo des Beraters für die Einmalprodukte-Dashboard-Card (nur wenn // das Zeitfenster offen ist und das Feature für den User sichtbar ist). $oneTimeAbo = null; $aboOneTimeId = UserAbo::where('user_id', $user->id) ->where('is_for', 'me') ->where('active', true) ->where('status', 2) ->value('id'); if ($aboOneTimeId) { $abo = UserAbo::find($aboOneTimeId); if ($abo && AboHelper::isOneTimeWindowOpen($abo) && AboHelper::isOneTimeFeatureVisible($abo)) { $oneTimeAbo = $abo; } } $monthlyStats = null; if ($user->isActiveAccount()) { $monthlyStats = $this->buildMonthlyStats($user); } $data = [ 'user' => $user, 'now' => Carbon::now(), 'dashboardNews' => DashboardNews::getActiveNews(), 'activeIncentive' => $activeIncentive, 'incentiveParticipant' => $incentiveParticipant, 'activeIncentives' => $activeIncentives, 'incentiveParticipants' => $incentiveParticipants, 'oneTimeAbo' => $oneTimeAbo, 'monthlyStats' => $monthlyStats, ]; return view('home', $data); } /** * Kennzahlen der Monatsstatistik-Card. Bündelt persönliche Punkte/Abos, Team-Abo-KPIs * (konsistent über {@see TeamAboOverviewService}) und die Team-Payline-Punkte. * * @return array */ private function buildMonthlyStats(User $user): array { $month = max(1, min(12, (int) Request::get('stats_month', now()->month))); $year = max(2020, min((int) now()->year + 1, (int) Request::get('stats_year', now()->year))); $salesVolume = $user->getUserSalesVolume($month, $year, 'first'); [$paylinePoints, $paylineIsLive] = $this->teamPaylinePoints($user, $month, $year); $customerPoints = $salesVolume ? (float) $salesVolume->getPointsKPSum() : 0.0; // Payline-Prognose (B10) nur für den laufenden Monat — Basis ist der heutige // Stand aus Kundenumsatz + Payline-Punkten. $isCurrentMonth = $month === (int) now()->month && $year === (int) now()->year; $paylineForecast = $isCurrentMonth ? app(PaylineForecastService::class)->forecastDays($user, $customerPoints + (float) $paylinePoints) : null; $levelForecast = $isCurrentMonth ? app(PaylineForecastService::class)->levelAndCommissionForecast($user, $month, $year) : null; $dashboardService = app(BackofficeDashboardService::class); $teamOverview = app(TeamAboOverviewService::class); $paylineService = app(PaylineForecastService::class); // Firstlines: die Neupartner-Zählung braucht alle direkten Partner (der // Scope filtert selbst), die Kachel zeigt aber nur aktive Berater — // sonst zählt sie anders als "Teampartner gesamt" daneben (F1). $firstlines = User::firstlinesOf($user->id)->get(); $firstlineIds = $firstlines->pluck('id')->map(fn ($id) => (int) $id)->all(); $activeFirstlineCount = $firstlines ->filter(fn (User $member) => $dashboardService->isActiveConsultant($member)) ->count(); // Anzeige-Zählung konsistent zu "Teampartner gesamt" (F1: nur aktive // Berater) — die Payline-Mitgliedermenge selbst enthält auch inaktive, // deren Abos weiterhin in die Abo-/Punkte-Summen der Payline zählen. $activeTeamUserIds = $dashboardService->activeTeamUserIds($user->id); $paylineMemberIds = $paylineService->paylineContext($user, $month, $year)['member_ids']; $activePaylineMemberCount = count(array_intersect($activeTeamUserIds, $paylineMemberIds)); // Abo-Zähler der Payline monatsbezogen wie die übrigen Abo-Kacheln (N2) — // sonst widersprechen sich die Kacheln beim Monatswechsel. $paylineAboCount = $teamOverview->aboStockCount($paylineMemberIds, 'user_id', 'me', $month, $year) + $teamOverview->aboStockCount($paylineMemberIds, 'member_id', 'ot', $month, $year); return array_merge( [ 'month' => $month, 'year' => $year, 'customer_points' => $customerPoints, 'team_payline_points' => $paylinePoints, 'payline_is_live' => $paylineIsLive, 'payline_forecast' => $paylineForecast, 'commission' => app(LiveCommissionService::class)->commission($user, $month, $year), 'direct_new_partners' => $dashboardService->newPartnersCount($firstlineIds, $month, $year), 'firstline_count' => $activeFirstlineCount, 'team_partner_count' => count($activeTeamUserIds), 'payline_member_count' => $activePaylineMemberCount, 'payline_abo_count' => $paylineAboCount, 'payline_abos_new' => $paylineService->newPaylineAboCount($user, $month, $year), 'level' => app(LiveCommissionService::class)->levelProgress($user, $month, $year), 'level_forecast' => $levelForecast, 'top_results' => app(TopResultsService::class)->monthlyTop3($user, $month, $year), ], $teamOverview->teamKpis($user, $month, $year), $teamOverview->personalAboKpis($user, $month, $year) ); } /** * Team-Payline-Punkte: aus dem gemeinsamen Live-Lauf ({@see LiveCommissionService}), * der auch die Provision und die Payline-Tiefe liefert — ein Baum-Lauf für alles. * * @return array{0: float, 1: bool} [Punkte, istLive] */ private function teamPaylinePoints(User $user, int $month, int $year): array { $snapshot = app(LiveCommissionService::class)->snapshot($user, $month, $year); return [$snapshot['payline_points'], $snapshot['is_live']]; } public function loadingModal() { $data = Request::get('data'); $target = Request::get('target'); $response = ''; if ($data === 'data_protection') { $data = [ 'modal' => true, 'user_shop' => true, 'isMivitaShop' => false, ]; $response = view('legal.data_protect_de', $data)->render(); } if ($data === 'imprint') { $data = [ 'modal' => true, 'user_shop' => Util::getUserShop(), ]; $response = view('legal.imprint_de', $data)->render(); } if ($data === 'shop_term_of_use') { $data = [ 'modal' => true, 'user_shop' => Util::getUserShop(), ]; $response = view('legal.shop_term_of_use_de', $data)->render(); } if ($data === 'agb') { $data = [ 'modal' => true, 'user_shop' => Util::getUserShop(), ]; $response = view('legal.agb_de', $data)->render(); } if (Request::ajax()) { return response()->json(['response' => $response, 'target' => $target]); } abort(404); } /* public function checkLogin($identify, $token) { if($identify){ //user find by $identify $user = User::where('identify', '=', $identify)->first(); if(!$user){ return abort(404); } //user - check für from $sf_guard_user - old system $sf_guard_user = SfGuardUser::where('identify', '=', $identify)->first(); if(!$sf_guard_user){ return abort(404); } if($user->id != $sf_guard_user->user_id){ return abort(404); } if($sf_guard_user->token != $token){ return abort(404); } $time = Carbon::parse($sf_guard_user->token_at); $now = Carbon::now(); $duration = $time->diffInSeconds($now); if($duration > 3){ return abort(404); } $sf_guard_user->token = null; $sf_guard_user->token_at = null; $sf_guard_user->save(); if(!Auth::check()){ $user->last_login = now(); $user->save(); Auth::login($user); } if(Auth::check()){ return redirect('/templates'); } } return abort(404); } */ public function zahlungsarten() { return view('web.templates.zahlungsarten', [ 'user_shop' => Util::getUserShop(), 'isMivitaShop' => Util::isMivitaShop(), 'yard_instance' => 'webshop', ]); } public function versandkosten() { return view('web.templates.versandkosten', [ 'user_shop' => Util::getUserShop(), 'isMivitaShop' => Util::isMivitaShop(), 'yard_instance' => 'webshop', ]); } public function legalDataProtected() { $data = [ 'modal' => false, 'user_shop' => Util::getUserShop(), 'isMivitaShop' => Util::isMivitaShop(), 'yard_instance' => 'webshop', ]; return view('legal.data_protected', $data); } public function legalAGB() { $data = [ 'modal' => false, 'user_shop' => Util::getUserShop(), 'yard_instance' => 'webshop', 'yard_instance' => 'webshop', ]; return view('legal.agb', $data); } public function legalImprint() { $data = [ 'modal' => false, 'user_shop' => Util::getUserShop(), 'yard_instance' => 'webshop', ]; return view('legal.imprint', $data); } public function verify($confirmation_code) { if (! $confirmation_code) { return redirect('/status/error'); } $user = User::whereConfirmationCode($confirmation_code)->first(); if (! $user) { return redirect('/status/not/found'); } $user_auto_login = false; if ($user->confirmed === 0) { $user->confirmed = 1; $user->confirmation_date = now(); $user_auto_login = true; // nur bei der ersten Verifizierung den user auto login } // wird nun in WizardController::releaseAccount() auf null gesetzt // $user->confirmation_code = null; // $user->confirmation_code_to = null; // $user->confirmation_code_remider = 0; $user->save(); // Login! if ($user_auto_login) { Auth::login($user); } $url = Util::getMyMivitaUrl(); return redirect($url); } public function statusRegister() { return view('status.status_register'); } public function statusVerify() { return view('status.status_verify'); } public function statusError() { return view('status.status_error'); } public function notFound() { return view('status.not_found'); } /** * @return string */ public function checkMail() { $data = Request::all(); if ($data['user_id'] === 'new') { if (User::where('email', $data['email'])->count()) { return json_encode(false); } } else { if (User::where('email', $data['email'])->where('id', '!=', $data['user_id'])->count()) { return json_encode(false); } } return json_encode(true); } public function blocked() { return view('status.user_blocked'); } public function backToShop($reference = '') { if ($reference) { $ShoppingPayment = ShoppingPayment::where('reference', $reference)->first(); if ($ShoppingPayment && $ShoppingPayment->status === 'success') { $user = Auth::user(); // is form wizard create payment if ($user && ($user->wizard == 13 || $user->wizard == 20)) { $user->wizard = 15; // realese Payments $user->save(); return redirect(route('wizard_create', [15])); } } else { \Session()->flash('alert-error', __('msg.error_occurred_with_order')); return redirect(url('/')); } } } }