10.April 2026
This commit is contained in:
parent
a00c42e770
commit
f58c709945
208 changed files with 19280 additions and 2914 deletions
|
|
@ -45,9 +45,13 @@ class AboController extends Controller
|
|||
}
|
||||
|
||||
if ($view === 'ot') {
|
||||
$user_abos = UserAbo::where('member_id', \Auth::user()->id)
|
||||
$selectedYear = (int) \Request::get('year', now()->year);
|
||||
$baseQuery = UserAbo::where('member_id', \Auth::user()->id)
|
||||
->where('status', '>', 1)
|
||||
->where('is_for', 'ot')
|
||||
->where('is_for', 'ot');
|
||||
|
||||
$user_abos = (clone $baseQuery)
|
||||
->with(['user_abo_items', 'user_abo_items.product', 'shopping_user'])
|
||||
->orderBy('id', 'desc')
|
||||
->get();
|
||||
|
||||
|
|
@ -55,6 +59,10 @@ class AboController extends Controller
|
|||
'user_abos' => $user_abos,
|
||||
'view' => 'ot',
|
||||
'isAdmin' => false,
|
||||
'chartData' => AboHelper::getMonthlyAboCounts($baseQuery, $selectedYear, 'ot', \Auth::user()->id),
|
||||
'chartYear' => $selectedYear,
|
||||
'chartYears' => \App\Services\HTMLHelper::getYearRange(2026),
|
||||
'chartMonths' => \App\Services\HTMLHelper::getTransMonths(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
200
app/Http/Controllers/User/IncentiveController.php
Normal file
200
app/Http/Controllers/User/IncentiveController.php
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
||||
|
|
@ -63,7 +63,6 @@ class MembershipController extends Controller
|
|||
if ($user->isActiveAccount() && ! $user->isActiveShop()) {
|
||||
$payment_greaterThan = Carbon::parse($user->payment_account)->modify('-'.(config('mivita.renewal_days') + 1).' days');
|
||||
$userHistoryUpgradeOrder = UserHistory::whereUserId($user->id)->whereAction('upgrade_order')->where('created_at', '>=', $payment_greaterThan)->get()->last();
|
||||
|
||||
}
|
||||
$userHistoryDeleteMembership = UserHistory::whereUserId($user->id)->whereAction('delete_membership')->whereStatus(50)->get()->last();
|
||||
|
||||
|
|
@ -87,7 +86,6 @@ class MembershipController extends Controller
|
|||
];
|
||||
|
||||
return view('user.membership.index', $data);
|
||||
|
||||
}
|
||||
|
||||
private function checkShoppingCountry($user)
|
||||
|
|
@ -158,8 +156,11 @@ class MembershipController extends Controller
|
|||
if ($product->images->count()) {
|
||||
$image = $product->images->first()->slug;
|
||||
}
|
||||
$qty = Request::get('qty') ? Request::get('qty') : 1;
|
||||
$qty = $product->is_membership_only ? 1 : (Request::get('qty') ? Request::get('qty') : 1);
|
||||
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), $qty, $product->getPriceWith(\App\Services\UserService::getTaxFree(), false, \App\Services\UserService::$user_country), false, false, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission, 'no_free_shipping' => $product->no_free_shipping, 'show_on' => $product->show_on]);
|
||||
if ($cartItem->qty > 1) {
|
||||
Yard::instance('shopping')->update($cartItem->rowId, 1);
|
||||
}
|
||||
if (\App\Services\UserService::getTaxFree()) {
|
||||
Yard::setTax($cartItem->rowId, 0);
|
||||
} else {
|
||||
|
|
@ -214,7 +215,6 @@ class MembershipController extends Controller
|
|||
\Session()->flash('alert-success', __('msg.booked_package_has_been_changed'));
|
||||
|
||||
return back();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -236,11 +236,9 @@ class MembershipController extends Controller
|
|||
\Session()->flash('alert-error', __('msg.error_checkbox_not_confirm'));
|
||||
|
||||
return back();
|
||||
|
||||
}
|
||||
\Session()->flash('alert-error', __('msg.error_checkbox_not_confirm'));
|
||||
|
||||
return back();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use App\Services\AboHelper;
|
|||
use App\Services\MyLog;
|
||||
use App\Services\OrderPaymentService;
|
||||
use App\Services\Payment;
|
||||
use App\Services\ProductOrderContext;
|
||||
use App\Services\Shop;
|
||||
use App\Services\UserService;
|
||||
use App\Services\Util;
|
||||
|
|
@ -182,6 +183,16 @@ class OrderController extends Controller
|
|||
$delivery_id = $shopping_user->id;
|
||||
}
|
||||
|
||||
$isAbo = str_contains($for, 'abo');
|
||||
$previousFor = session('user_order_flow_for');
|
||||
if ($previousFor !== null && $previousFor !== $for) {
|
||||
$previousAbo = str_contains($previousFor, 'abo');
|
||||
if (ProductOrderContext::allowedShowOnIds($previousAbo, $previousFor) !== ProductOrderContext::allowedShowOnIds($isAbo, $for)) {
|
||||
Yard::instance('shopping')->destroy();
|
||||
}
|
||||
}
|
||||
session(['user_order_flow_for' => $for]);
|
||||
|
||||
if ($for === 'ot-customer' || $for === 'abo-ot-customer') {
|
||||
UserService::initCustomerYard($shopping_user, $for);
|
||||
} else {
|
||||
|
|
@ -262,7 +273,7 @@ class OrderController extends Controller
|
|||
// Prepare common data
|
||||
$data['is_from'] = 'user_order';
|
||||
$data['is_for'] = $for;
|
||||
$data['is_abo'] = $data['is_abo'] ?? 0;
|
||||
$data['is_abo'] = str_contains($for, 'abo');
|
||||
$data['abo_interval'] = $data['abo_interval'] ?? 0;
|
||||
$data['shopping_user_id'] = $id;
|
||||
$data['user_price_infos'] = Yard::instance('shopping')->getUserPriceInfos();
|
||||
|
|
@ -406,6 +417,17 @@ class OrderController extends Controller
|
|||
throw new \Exception(__('msg.shipping_country_was_not_correctly'));
|
||||
}
|
||||
|
||||
$isAbo = str_contains($data['shipping_is_for'], 'abo');
|
||||
foreach (Yard::instance('shopping')->content() as $row) {
|
||||
$product = Product::find($row->id);
|
||||
if (! $product) {
|
||||
continue;
|
||||
}
|
||||
if (! ProductOrderContext::isProductAllowedInContext($product, $isAbo, $data['shipping_is_for'])) {
|
||||
throw new \Exception(__('msg.cart_product_not_allowed_for_order_type'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['shipping_is_for'] !== 'ot-customer') {
|
||||
if (Yard::instance('shopping')->shipping_free) {
|
||||
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
|
||||
|
|
@ -748,6 +770,15 @@ class OrderController extends Controller
|
|||
return response()->json(['response' => false, 'message' => 'Product not found']);
|
||||
}
|
||||
|
||||
$isAbo = str_contains($is_for, 'abo');
|
||||
$qty = isset($data['qty']) ? (int) $data['qty'] : 0;
|
||||
if ($qty > 0 && ! ProductOrderContext::isProductAllowedInContext($product, $isAbo, $is_for)) {
|
||||
return response()->json([
|
||||
'response' => false,
|
||||
'message' => __('msg.cart_product_not_allowed_for_order_type'),
|
||||
]);
|
||||
}
|
||||
|
||||
$image = '';
|
||||
if ($product->images->count()) {
|
||||
$image = $product->images->first()->slug;
|
||||
|
|
|
|||
|
|
@ -713,9 +713,13 @@ class TeamController extends Controller
|
|||
// Hole Team-Mitglieder-IDs effizient via Sponsor-Hierarchie
|
||||
$teamUserIds = AboHelper::getTeamUserIds($user->id);
|
||||
|
||||
// Hole Abos der Team-Mitglieder
|
||||
$abos = \App\Models\UserAbo::whereIn('user_id', $teamUserIds)
|
||||
$selectedYear = (int) Request::get('year', now()->year);
|
||||
$baseQuery = \App\Models\UserAbo::whereIn('user_id', $teamUserIds)
|
||||
->where('is_for', 'me')
|
||||
->where('status', '>', 1);
|
||||
|
||||
// Hole Abos der Team-Mitglieder
|
||||
$abos = (clone $baseQuery)
|
||||
->with(['user', 'user.account', 'user_abo_items', 'user_abo_items.product'])
|
||||
->orderBy('next_date', 'asc')
|
||||
->get();
|
||||
|
|
@ -724,11 +728,45 @@ class TeamController extends Controller
|
|||
'filter_months' => HTMLHelper::getTransMonths(),
|
||||
'filter_years' => HTMLHelper::getYearRange(2022),
|
||||
'abos' => $abos,
|
||||
'chartData' => AboHelper::getMonthlyAboCounts($baseQuery, $selectedYear, 'team_abos', $user->id),
|
||||
'chartYear' => $selectedYear,
|
||||
'chartYears' => HTMLHelper::getYearRange(2026),
|
||||
'chartMonths' => HTMLHelper::getTransMonths(),
|
||||
];
|
||||
|
||||
return view('user.team.abos', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt eine Übersicht der Kunden-Abos aller Team-Mitglieder (anonymisiert)
|
||||
*/
|
||||
public function showTeamCustomerAbos(): \Illuminate\View\View
|
||||
{
|
||||
$user = User::find(\Auth::user()->id);
|
||||
$teamUserIds = AboHelper::getTeamUserIds($user->id);
|
||||
|
||||
$selectedYear = (int) Request::get('year', now()->year);
|
||||
$baseQuery = \App\Models\UserAbo::whereIn('member_id', $teamUserIds)
|
||||
->where('is_for', 'ot')
|
||||
->where('status', '>', 1);
|
||||
|
||||
$abos = (clone $baseQuery)
|
||||
->with(['member', 'member.account', 'user_abo_items', 'user_abo_items.product'])
|
||||
->orderBy('member_id')
|
||||
->orderBy('next_date', 'asc')
|
||||
->get();
|
||||
|
||||
$groupedByMember = $abos->groupBy('member_id');
|
||||
|
||||
return view('user.team.customer_abos', [
|
||||
'groupedByMember' => $groupedByMember,
|
||||
'chartData' => AboHelper::getMonthlyAboCounts($baseQuery, $selectedYear, 'team_cust_abos', $user->id),
|
||||
'chartYear' => $selectedYear,
|
||||
'chartYears' => HTMLHelper::getYearRange(2026),
|
||||
'chartMonths' => HTMLHelper::getTransMonths(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Detail-Ansicht eines Team-Abos an
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue