Statistiken/Abo: Kundenfeedback 2026-07-24 komplett umgesetzt + Steuern: DATEV-Fixes 08+09/2025 (Sammel-Commit Branch-WIP)
Feedback-Umsetzung (dev/2026-07-22/feedback-analyse-2026-07-24.md, alle 10 Punkte):
- VIP-Statistik: eigener Berater ('ich', Linie 0) in Neue-Kundenabos- und beiden Top-10-Listen; Top-10-Umsatz sortiert nach abgerechneten Ist-Punkten + Abo-Anzahl-Spalte; Fußnote nicht-payline-wirksame Punkte (SalesVolumePoints::nonPaylinePoints)
- Führungskräfte-Liste: beide Sichten 'direkt' (an nächster FK abgeschnitten, additiv) und 'gesamt' (komplette Downline), Gesamt-Spalte nach Kundenzählweise
- Team-Abos: je Ebene 'abgerechnet (Monat)' und 'bis zum 25. erwartet'; Payline-Karte mit Teamabo-/Kundenabo-Zählern
- Incentive-Live-Ranking: Qualifizierte zuerst nummeriert (fixt auch isWinner rank<=max_winners)
- Porto: Netto-/Brutto-Kennzeichnung (Berater netto, Endkunden inkl. MwSt., portal_view-Flag; auch CRM-/Shop-Warenkorb + Checkout), Yard::shipping_tax-Fix
- Struktur-Ansicht: Abo-Badges 'A' (eigenes Abo) und '(n)' (Kundenabos) je Teampartner, gebatcht
- Abo-Löschung: Softdelete setzt active=0 (UserAbo deleting-Hook) + Bereinigungs-Migration für gelöschte-aber-aktive Abos
- Doku: technische Analyse + Kundinnen-Feedback-Dokument unter dev/2026-07-22/
- Tests: IncentiveRankingTest, TeamStructureAboBadgesTest, YardShippingTaxTest (neu); BackofficeStatisticsListsTest, TeamAboOverviewTest, PaylineForecastServiceTest, AboAdminDeleteTest, AboOneTimeViewTest erweitert
Außerdem enthalten (Branch-WIP vor dem Feedback): DATEV-Abgleich-Fixes 08+09/2025, USt-ID-Live-Validierung sowie restliche unkommittete Stände (u. a. Abo-Pause-Sprachkeys).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c06740b9be
commit
d4e9d108ad
137 changed files with 7610 additions and 2955 deletions
|
|
@ -7,15 +7,15 @@ use App\Models\Incentive;
|
|||
use App\Models\IncentiveParticipant;
|
||||
use App\Models\ShoppingPayment;
|
||||
use App\Models\UserAbo;
|
||||
use App\Models\UserBusiness;
|
||||
use App\Services\Abo\PaylineForecastService;
|
||||
use App\Services\Abo\TeamAboOverviewService;
|
||||
use App\Services\AboHelper;
|
||||
use App\Services\Backoffice\BackofficeDashboardService;
|
||||
use App\Services\BusinessPlan\TreeCalcBot;
|
||||
use App\Services\BusinessPlan\LiveCommissionService;
|
||||
use App\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\View\View;
|
||||
use Request;
|
||||
use Util;
|
||||
|
||||
|
|
@ -38,11 +38,11 @@ class HomeController extends Controller
|
|||
return redirect('home');
|
||||
}
|
||||
|
||||
public function newsArchive(): \Illuminate\View\View
|
||||
public function newsArchive(): View
|
||||
{
|
||||
return view('dashboard.news_archive', [
|
||||
'currentNews' => \App\Models\DashboardNews::getActiveNews(),
|
||||
'archiveNews' => \App\Models\DashboardNews::getArchiveNews(),
|
||||
'currentNews' => DashboardNews::getActiveNews(),
|
||||
'archiveNews' => DashboardNews::getArchiveNews(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -111,10 +111,18 @@ class HomeController extends Controller
|
|||
private function buildMonthlyStats(User $user): array
|
||||
{
|
||||
$month = max(1, min(12, (int) Request::get('stats_month', now()->month)));
|
||||
$year = (int) Request::get('stats_year', now()->year);
|
||||
$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;
|
||||
|
||||
$firstlineIds = User::where('m_sponsor', $user->id)
|
||||
->whereColumn('id', '!=', 'm_sponsor')
|
||||
|
|
@ -130,9 +138,11 @@ class HomeController extends Controller
|
|||
[
|
||||
'month' => $month,
|
||||
'year' => $year,
|
||||
'customer_points' => $salesVolume ? (float) $salesVolume->getPointsKPSum() : 0.0,
|
||||
'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),
|
||||
],
|
||||
$teamOverview->teamKpis($user, $month, $year),
|
||||
|
|
@ -141,45 +151,16 @@ class HomeController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* Team-Payline-Punkte: aus dem UserBusiness-Snapshot (abgeschlossene Monate) oder
|
||||
* – für den laufenden Monat – einmalig live berechnet und für Folge-Aufrufe gecacht.
|
||||
* 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
|
||||
{
|
||||
$userBusiness = UserBusiness::where('user_id', $user->id)
|
||||
->where('month', $month)
|
||||
->where('year', $year)
|
||||
->first();
|
||||
$snapshot = app(LiveCommissionService::class)->snapshot($user, $month, $year);
|
||||
|
||||
if ($userBusiness) {
|
||||
return [(float) ($userBusiness->payline_points ?? 0), false];
|
||||
}
|
||||
|
||||
$points = Cache::remember(
|
||||
"home_payline_{$user->id}_{$month}_{$year}",
|
||||
now()->addHours(6),
|
||||
fn (): float => $this->calculatePaylineLive($user, $month, $year)
|
||||
);
|
||||
|
||||
return [(float) $points, true];
|
||||
}
|
||||
|
||||
private function calculatePaylineLive(User $user, int $month, int $year): float
|
||||
{
|
||||
try {
|
||||
$treeCalcBot = new TreeCalcBot($month, $year, 'member');
|
||||
$treeCalcBot->initBusinesslUserDetail($user);
|
||||
|
||||
if ($treeCalcBot->business_user) {
|
||||
return (float) ($treeCalcBot->business_user->payline_points ?? 0);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
\Log::warning("Live-Berechnung Payline-Punkte fehlgeschlagen für User {$user->id}: ".$e->getMessage());
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
return [$snapshot['payline_points'], $snapshot['is_live']];
|
||||
}
|
||||
|
||||
public function loadingModal()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue