middleware('active.account'); $this->aboRepository = $aboRepository; } public function index($view) { if ($view === 'me') { // Nur Abos des aktuellen Benutzers $user_abos = UserAbo::where('user_id', \Auth::user()->id) ->where('status', '>', 1); if ($user_abos->count() > 0) { return redirect(route('user_abos_detail', ['me', $user_abos->first()->id])); } return view('user.abo.index', [ 'user_abos' => [], 'view' => 'me', 'isAdmin' => false, ]); } if ($view === 'ot') { $selectedYear = (int) \Request::get('year', now()->year); $baseQuery = UserAbo::where('member_id', \Auth::user()->id) ->where('status', '>', 1) ->where('is_for', 'ot'); $user_abos = (clone $baseQuery) ->with(['user_abo_items', 'user_abo_items.product', 'shopping_user']) ->orderBy('id', 'desc') ->get(); return view('user.abo.index', [ '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(), ]); } // Standardfall, wenn weder 'me' noch 'ot' return view('user.abo.index', [ 'user_abos' => [], 'view' => 'me', 'isAdmin' => false, ]); } public function detail($view, $id) { $data = Request::all(); $user_abo = UserAbo::findOrFail($id); $this->checkPermissions($view, $user_abo); // init Yard AboOrderCart::initYard($user_abo); // holt die aktuellen UserAccount Daten oder die Userdaten des Abo $customer_detail = AboOrderCart::getCustomerDetail(); AboOrderCart::makeOrderYard($user_abo); $baseCompCount = Yard::instance(AboOrderCart::INSTANCE)->getNumComp(); $oneTimeWindowOpen = AboHelper::isOneTimeFeatureVisible($user_abo); if ($oneTimeWindowOpen) { AboOrderCart::addOneTimeItemsToYard($user_abo); AboOrderCart::checkNumOfCompProducts($user_abo); } $comp_products = []; if ($user_abo->is_for === 'me') { $comp_products = Shop::getCompProducts('abo-me'); } $summary = AboOrderCart::getSplitSummary(); $data = [ 'user_abo' => $user_abo, 'isAdmin' => false, 'customer_detail' => $customer_detail, 'view' => $view, 'comp_products' => $comp_products, 'one_time_window_open' => $oneTimeWindowOpen, 'summary' => $summary, 'base_comp_count' => $baseCompCount, ]; return view('user.abo.detail', $data); } public function update($view, $id) { $data = Request::all(); $user_abo = UserAbo::findOrFail($id); $this->checkPermissions($view, $user_abo); $editView = \Auth::user()?->isAdmin() ? 'admin' : $view; $isAddOnlyMode = AboHelper::isAddOnlyMode($user_abo, $editView); if (isset($data['action'])) { if ($data['action'] === 'abo_update_settings') { $user_abo = UserAbo::findOrFail($data['id']); $this->aboRepository->setModel($user_abo); $this->aboRepository->update($data); return redirect(route('user_abos_detail', [$view, $id])); } if (Request::ajax()) { $message = false; // Yard für Gewichts-/Versandprüfung initialisieren (Versandland setzen) AboOrderCart::initYard($user_abo); // addProduct if ($data['action'] === 'addProduct') { if ($product = Product::find($data['product_id'])) { if (AboOrderCart::exceedsMaxWeight($user_abo, (int) $product->weight)) { $message = __('msg.cart_max_weight_reached'); } elseif ($UserAboItem = UserAboItem::where('user_abo_id', $user_abo->id)->where('product_id', $product->id)->where('comp', 0)->first()) { $qtyBefore = $UserAboItem->qty; $UserAboItem->qty = $UserAboItem->qty + 1; $UserAboItem->save(); AboItemHistoryService::logProductAdded($user_abo, $UserAboItem, $qtyBefore, $editView); } else { $newItem = UserAboItem::create([ 'user_abo_id' => $user_abo->id, 'product_id' => $product->id, 'comp' => 0, 'qty' => 1, 'status' => 1, ]); AboItemHistoryService::logProductAdded($user_abo, $newItem, 0, $editView); } } } // updateCart if ($data['action'] === 'updateCart') { // product_id | order_item_id | cart_order_id | qty if (isset($data['product_id']) && $product = Product::find($data['product_id'])) { if (isset($data['order_item_id']) && $UserAboItem = UserAboItem::find($data['order_item_id'])) { if (isset($data['qty'])) { $qtyBefore = $UserAboItem->qty; $qty = (int) $data['qty']; $qty = $qty < 1 ? 1 : $qty; $qty = $qty > 100 ? 100 : $qty; if ($isAddOnlyMode && $qty < $UserAboItem->qty) { $qty = $UserAboItem->qty; } $additionalWeight = (int) $product->weight * ($qty - $qtyBefore); if ($additionalWeight > 0 && AboOrderCart::exceedsMaxWeight($user_abo, $additionalWeight)) { $message = __('msg.cart_max_weight_reached'); } else { $UserAboItem->qty = $qty; $UserAboItem->save(); AboItemHistoryService::logQtyChanged($user_abo, $UserAboItem, $qtyBefore, $qty, $editView); } } } } } // removeFromCart if ($data['action'] === 'removeFromCart') { if ($isAddOnlyMode) { return response()->json([ 'response' => false, 'message' => __('abo.error_add_only_no_remove'), ], 403); } if (! isset($data['product_id']) || ! ($product = Product::find($data['product_id']))) { $message = __('abo.product_not_found'); } if (! isset($data['order_item_id']) || ! ($userAboItem = UserAboItem::find($data['order_item_id']))) { $message = __('abo.abo_item_not_found'); } $has_basis_product = $this->check_need_basis_product($user_abo, $product, $data['order_item_id']); if (! $has_basis_product) { $message = __('abo.need_basis_product'); } if (! $message) { AboItemHistoryService::logProductRemoved($user_abo, $userAboItem, $editView); $userAboItem->delete(); $user_abo->refresh(); // Abo neu laden um die aktualisierten Items zu erhalten } } // updateCompProduct if ($data['action'] === 'updateCompProduct') { if ($UserAboItem = UserAboItem::where('user_abo_id', $user_abo->id)->where('comp', $data['comp_num'])->first()) { $oldProduct = $UserAboItem->product; $UserAboItem->product_id = $data['comp_product_id']; $UserAboItem->save(); $UserAboItem->load('product'); AboItemHistoryService::logCompProductChanged($user_abo, $UserAboItem, $oldProduct, $UserAboItem->product, $editView); } else { $newItem = UserAboItem::create([ 'user_abo_id' => $user_abo->id, 'product_id' => $data['comp_product_id'], 'comp' => $data['comp_num'], 'qty' => 1, 'status' => 1, ]); AboItemHistoryService::logProductAdded($user_abo, $newItem, 0, $editView); } } AboOrderCart::initYard($user_abo); AboOrderCart::makeOrderYard($user_abo); // reCalculateShippingPrice $baseCompCount = Yard::instance(AboOrderCart::INSTANCE)->getNumComp(); if (AboHelper::isOneTimeFeatureVisible($user_abo)) { AboOrderCart::addOneTimeItemsToYard($user_abo->fresh()); } AboOrderCart::checkNumOfCompProducts($user_abo); // after reCalculateShippingPrice check it and remove or add comp product if ($user_abo->is_for === 'me') { $data['comp_products'] = Shop::getCompProducts('abo-me'); } $summary = AboOrderCart::getSplitSummary(); $error_message = $message ? $message : false; $html_cart = view('admin.abo._order_abo_show', [ 'user_abo' => $user_abo, 'error_message' => $error_message, 'split_mode' => AboHelper::isOneTimeFeatureVisible($user_abo), 'summary' => $summary, 'add_only_mode' => $isAddOnlyMode, ])->render(); $html_comp = view('user.order.comp_product', array_merge($data, [ 'cart_instance' => AboOrderCart::INSTANCE, 'base_comp_count' => $baseCompCount, ]))->render(); $html_summary = view('admin.abo._order_combined_summary', [ 'summary' => $summary, ])->render(); $amount = $user_abo->getFormattedAmount(); // $html_total = view("user.homeparty.show_total_order", ['homeparty' => $homeparty])->render(); return response()->json(['response' => true, 'data' => $data, 'html_cart' => $html_cart, 'html_comp' => $html_comp, 'html_summary' => $html_summary, 'amount' => $amount]); } } } public function oneTime(AboOneTimeItemRequest $request, $view, $id) { $user_abo = UserAbo::findOrFail($id); $this->checkPermissions($view, $user_abo); $editView = \Auth::user()?->isAdmin() ? 'admin' : $view; $isAddOnlyMode = AboHelper::isAddOnlyMode($user_abo, $editView); if (! AboHelper::isOneTimeFeatureVisible($user_abo)) { return response()->json([ 'response' => false, 'message' => __('abo.onetime_window_closed'), ], 403); } AboOrderCart::initYard($user_abo); $message = (new \App\Services\AboOneTimeService)->handleAction($user_abo, $request->validated()); AboOrderCart::initYard($user_abo); AboOrderCart::makeOrderYard($user_abo); $baseCompCount = Yard::instance(AboOrderCart::INSTANCE)->getNumComp(); AboOrderCart::addOneTimeItemsToYard($user_abo->fresh()); AboOrderCart::checkNumOfCompProducts($user_abo); $user_abo = $user_abo->fresh(); $summary = AboOrderCart::getSplitSummary(); $compProducts = $user_abo->is_for === 'me' ? Shop::getCompProducts('abo-me') : []; return response()->json([ 'response' => ! $message, 'message' => $message ?: null, 'summary' => $summary, 'one_time_items' => $this->oneTimeItemsPayload($user_abo), 'html_onetime' => view('admin.abo._order_onetime_show', [ 'user_abo' => $user_abo, 'summary' => $summary, 'error_message' => $message ?: false, ])->render(), 'html_abo' => view('admin.abo._order_abo_show', [ 'user_abo' => $user_abo, 'split_mode' => true, 'summary' => $summary, 'only_show_products' => false, 'add_only_mode' => $isAddOnlyMode, ])->render(), 'html_summary' => view('admin.abo._order_combined_summary', [ 'summary' => $summary, ])->render(), 'html_comp' => view('user.order.comp_product', [ 'comp_products' => $compProducts, 'cart_instance' => AboOrderCart::INSTANCE, 'base_comp_count' => $baseCompCount, ])->render(), ]); } /** * @return array> */ private function oneTimeItemsPayload(UserAbo $user_abo): array { return $user_abo->one_time_items()->with('product')->get()->map(function (UserAboOneTimeItem $item) { return [ 'id' => $item->id, 'product_id' => $item->product_id, 'name' => $item->product?->getLang('name'), 'qty' => $item->qty, 'price' => $item->price, 'total' => round($item->price * $item->qty, 2), ]; })->all(); } public function check_need_basis_product($user_abo, $product, $order_item_id) { // Wenn das zu entfernende Produkt kein Basis-Produkt ist, keine weitere Prüfung nötig if (AboHelper::getAboShowOn($product) !== 'base') { return true; } // Prüfe ob noch ein anderes Basis-Produkt vorhanden ist (nur reguläre Items, keine Comp-Produkte) foreach ($user_abo->user_abo_items as $user_abo_item) { if ($user_abo_item->id == $order_item_id) { continue; } if ($user_abo_item->comp) { continue; } if (AboHelper::getAboShowOn($user_abo_item->product) === 'base') { return true; } } return false; } public function datatable($user_abo_id) { $user_abo = UserAbo::findOrFail($user_abo_id); if (! $user_abo) { abort(404); } // $user_abo->is_for === 'me' $show_on_ids = ['12', '13']; $query = Product::select('products.*') ->where('active', true) ->where(function ($q) use ($show_on_ids) { foreach ($show_on_ids as $id) { $q->orWhereJsonContains('show_on', $id); } }) ->orderByRaw( "CASE WHEN JSON_CONTAINS(show_on, ?, '$') THEN 1 WHEN JSON_CONTAINS(show_on, ?, '$') THEN 2 ELSE 3 END", [$show_on_ids[0], isset($show_on_ids[1]) ? $show_on_ids[1] : $show_on_ids[0]] ); return \DataTables::eloquent($query) ->addColumn('add_card', function (Product $product) use ($user_abo) { $ufactor = $user_abo->is_for === 'me' ? true : false; $tax_free = $user_abo->is_for === 'me' ? true : Yard::instance(AboOrderCart::INSTANCE)->getUserTaxFree(); $price = $product->getFormattedPriceWith($tax_free, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()); return ''; }) ->addColumn('picture', function (Product $product) { if (count($product->images)) { return ''; } return ''; }) ->addColumn('name', function (Product $product) { return ''.$product->getLang('name').'
'.get_abo_type_badge_by_product($product); }) ->addColumn('points', function (Product $product) { return ''.$product->getFormattedPoints().''; }) ->addColumn('price_net', function (Product $product) use ($user_abo) { $ufactor = $user_abo->is_for === 'me' ? true : false; return ''.$product->getFormattedPriceWith(true, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €'.''.$product->getFormattedPriceCurrencyWith(true, true, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).''; }) ->addColumn('price_gross', function (Product $product) use ($user_abo) { $ufactor = $user_abo->is_for === 'me' ? true : false; return ''.$product->getFormattedPriceWith(false, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €'.''.$product->getFormattedPriceCurrencyWith(true, true, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).''; }) ->addColumn('action', function (Product $product) { return ''; }) ->filterColumn('product', function ($query, $keyword) { if ($keyword != '') { $query->where('name', 'LIKE', '%'.$keyword.'%'); } }) ->orderColumn('name', 'name $1') ->orderColumn('product', 'name $1') ->orderColumn('number', 'number $1') ->orderColumn('points', 'points $1') ->orderColumn('price_net', 'price_net $1') ->orderColumn('price_gross', 'price_gross $1') ->orderColumn('contents_total', 'contents_total $1') ->orderColumn('weight', 'weight $1') ->rawColumns(['add_card', 'points', 'product', 'name', 'quantity', 'picture', 'price_net', 'price_gross', 'action']) ->make(true); } public function oneTimeDatatable($user_abo_id) { $user_abo = UserAbo::findOrFail($user_abo_id); abort_unless(AboHelper::isOneTimeFeatureVisible($user_abo), 403); AboOrderCart::initYard($user_abo); $show_on_ids = $user_abo->is_for === 'me' ? ['2'] : ['3']; $query = Product::select('products.*') ->where('active', true) ->where(function ($q) use ($show_on_ids) { foreach ($show_on_ids as $id) { $q->orWhereJsonContains('show_on', $id); } }) ->orderBy('name', 'asc'); return \DataTables::eloquent($query) ->addColumn('add_card', function (Product $product) use ($user_abo) { $ufactor = $user_abo->is_for === 'me' ? true : false; $tax_free = $user_abo->is_for === 'me' ? true : Yard::instance(AboOrderCart::INSTANCE)->getUserTaxFree(); $price = $product->getFormattedPriceWith($tax_free, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()); return ''; }) ->addColumn('picture', function (Product $product) { if (count($product->images)) { return ''; } return ''; }) ->addColumn('name', function (Product $product) { return ''.$product->getLang('name').''; }) ->addColumn('points', function (Product $product) { return ''.$product->getFormattedPoints().''; }) ->addColumn('price_net', function (Product $product) use ($user_abo) { $ufactor = $user_abo->is_for === 'me' ? true : false; return ''.$product->getFormattedPriceWith(true, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €'; }) ->addColumn('price_gross', function (Product $product) use ($user_abo) { $ufactor = $user_abo->is_for === 'me' ? true : false; return ''.$product->getFormattedPriceWith(false, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €'; }) ->filterColumn('product', function ($query, $keyword) { if ($keyword != '') { $query->where('name', 'LIKE', '%'.$keyword.'%'); } }) ->orderColumn('name', 'name $1') ->orderColumn('number', 'number $1') ->rawColumns(['add_card', 'points', 'name', 'picture', 'price_net', 'price_gross']) ->make(true); } public function retryPayment($view, $id, AboRetryPaymentService $retryPaymentService) { $user_abo = UserAbo::findOrFail($id); $this->checkPermissions($view, $user_abo); $result = $retryPaymentService->retry($user_abo); \Session()->flash($result['success'] ? 'alert-success' : 'alert-error', $result['message']); return redirect(route('user_abos_detail', [$view, $id])); } private function checkPermissions($view, $user_abo) { \Log::info('checkPermissions', ['view' => $view, 'user_abo' => $user_abo]); $user = \Auth::user(); // Admins dürfen alle Abos bearbeiten if ($user && $user->isAdmin()) { return; } if ($view === 'me' && $user_abo->is_for !== 'me') { abort(403, 'Unauthorized action. Is not for me'); } if ($view === 'ot' && $user_abo->is_for !== 'ot') { abort(403, 'Unauthorized action. Is not your customer'); } if ($view === 'me' && $user_abo->user_id !== $user->id) { abort(403, 'Unauthorized action. Is not my abo'); } if ($view === 'ot' && $user_abo->member_id !== $user->id) { abort(403, 'Unauthorized action. Is not my customer abo'); } } }