mivita/app/Http/Controllers/User/AboController.php
Kevin 65b867f8ee Abo Einmalprodukte: Phasen 5-7, konfigurierbare Sperrfristen, Lokalisierung & Dashboard
Rechnung/Lieferschein:
- PDF-Gruppierung Abo- vs. Einmal-Artikel (is_abo_addon), rueckwaertskompatibel
- Vorschau-Command sales:preview-invoice (umgeht Test-System-Gate, ohne Rechnungsnummer)

Reminder-Mail (vorbereitet, Cron inaktiv):
- MailAboExecutionReminder + Template, abo:send-execution-reminder, Spalte onetime_reminder_sent_for
- Berater -> Sales Center, Kunde -> Portal; Vorschau abo:preview-reminder
- Datum-Fix: formatDateDB() statt formatDate() (ICU-Format)

Sperrfristen konfigurierbar (Admin-Settings):
- abo-lock-days-change (Liefertag + Abo-Produkte), abo-lock-days-pause-cancel
- Meldungen mit :lock-Platzhalter; Pausieren/Kuendigen vom Change-Lock entkoppelt
- Abo-Produkt-Aenderungen im Lock-Fenster server- + clientseitig eingefroren
- Selbstbedienung: Add-only/Lock nach $view (kein Admin-Bypass), Stale-Cache-Fix beim Mengen-Update

Dashboard:
- Einmalprodukte-Card + Team-Abo-KPI-Card, News-Card responsiv (col-xl-6)

Lokalisierung:
- Sprachdateien en/es/fr vollstaendig mit de synchronisiert (inkl. marketingplan/portal)
- LocalizationSyncTest sichert Key-Gleichheit ab

Tests: AboOneTimeInvoiceGrouping, AboExecutionReminder, AboLockDaysSetting,
AboOnetimeDashboardAndMail, PreviewInvoiceCommand, TeamAboOverview + erweiterte View-Tests

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 13:38:11 +00:00

642 lines
28 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\Abo\AboOneTimeItemRequest;
use App\Models\Product;
use App\Models\ShoppingInstance;
use App\Models\UserAbo;
use App\Models\UserAboItem;
use App\Models\UserAboOneTimeItem;
use App\Repositories\AboRepository;
use App\Services\AboHelper;
use App\Services\AboItemHistoryService;
use App\Services\AboOrderCart;
use App\Services\AboRetryPaymentService;
use App\Services\OrderPaymentService;
use App\Services\Shop;
use App\User;
use Request;
use Yard;
class AboController extends Controller
{
protected $aboRepository;
public function __construct(AboRepository $aboRepository)
{
$this->middleware('active.account');
$this->aboRepository = $aboRepository;
}
public function index($view)
{
if ($view === 'me') {
// Nur Abos des aktuellen Benutzers
$baseQuery = UserAbo::where('user_id', \Auth::user()->id)
->where('status', '>=', 1)
->where('is_for', 'me');
if ((clone $baseQuery)->where('status', 1)->exists()) {
return view('user.abo.index', [
'user_abos' => (clone $baseQuery)->orderBy('id', 'desc')->get(),
'view' => 'me',
'isAdmin' => false,
]);
}
$user_abos = (clone $baseQuery)->orderBy('id', 'desc')->get();
if ($user_abos->count() > 0) {
return redirect(route('user_abos_detail', ['me', $user_abos->first()->id]));
}
return view('user.abo.index', [
'user_abos' => $user_abos,
'view' => 'me',
'isAdmin' => false,
]);
}
if ($view === 'ot') {
$selectedYear = (int) \Request::get('year', now()->year);
$selectedMonth = (int) \Request::get('month', 0);
$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'])
->addedInMonth($selectedYear, $selectedMonth)
->orderBy('id', 'desc')
->get();
return view('user.abo.index', [
'user_abos' => $user_abos,
'abo_payment_links' => $this->getAboPaymentLinks(),
'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(),
'filterMonth' => $selectedMonth,
'filterYear' => $selectedYear,
]);
}
// 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;
// Add-only (Mindestlaufzeit) und Change-Lock richten sich nach der Abo-Sicht ($view),
// NICHT nach Admin-Status – auf der Selbstbedienungs-Seite gelten für alle (auch VIP/Admin)
// die Berater-Regeln. $editView dient nur dem History-Logging.
$isAddOnlyMode = AboHelper::isAddOnlyMode($user_abo, $view);
$changeLocked = AboHelper::isAboChangeLocked($user_abo, $view);
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);
if ($changeLocked) {
$message = __('abo.error_change_locked', [
'days' => (int) now()->diffInDays(\Carbon\Carbon::parse($user_abo->next_date), false),
'lock' => \App\Repositories\AboRepository::getLockDaysChange(),
]);
}
// addProduct
if (! $changeLocked && $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 (! $changeLocked && $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 (! $changeLocked && $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 (! $changeLocked && $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
// Relation neu laden, damit die gerenderte Menge dem gespeicherten Stand
// entspricht (sonst zeigt _order_abo_show die gecachte alte Menge → Feld „springt" zurück).
$user_abo->load('user_abo_items');
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,
'change_locked' => $changeLocked,
])->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);
// Add-only/Change-Lock nach Abo-Sicht ($view), kein Admin-Bypass (siehe update()).
$isAddOnlyMode = AboHelper::isAddOnlyMode($user_abo, $view);
$changeLocked = AboHelper::isAboChangeLocked($user_abo, $view);
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,
'change_locked' => $changeLocked,
])->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<int, array<string, mixed>>
*/
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 '<button type="button" class="btn btn-sm btn-md-extra btn-secondary add-product-basket" data-product-id="'.$product->id.'" data-product-name="'.e($product->getLang('name')).'" data-product-price="'.$price.' &euro;">
<strong>&euro; '.$price.'</strong>&nbsp; +<span class="ion ion-md-cart"></span>
</button>';
})
->addColumn('picture', function (Product $product) {
if (count($product->images)) {
return '<img class="img-fluid img-extra" alt="" src="'.route('product_image', [$product->images->first()->slug]).'">';
}
return '';
})
->addColumn('name', function (Product $product) {
return '<strong>'.$product->getLang('name').'</strong><br>'.get_abo_type_badge_by_product($product);
})
->addColumn('points', function (Product $product) {
return '<span class="no-line-break">'.$product->getFormattedPoints().'</span>';
})
->addColumn('price_net', function (Product $product) use ($user_abo) {
$ufactor = $user_abo->is_for === 'me' ? true : false;
return '<span class="no-line-break">'.$product->getFormattedPriceWith(true, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €</span>'.'<span class="no-line-break">'.$product->getFormattedPriceCurrencyWith(true, true, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).'</span>';
})
->addColumn('price_gross', function (Product $product) use ($user_abo) {
$ufactor = $user_abo->is_for === 'me' ? true : false;
return '<span class="no-line-break">'.$product->getFormattedPriceWith(false, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €</span>'.'<span class="no-line-break">'.$product->getFormattedPriceCurrencyWith(true, true, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).'</span>';
})
->addColumn('action', function (Product $product) {
return '<button class="btn btn-default btn-sm icon-btn md-btn-flat product-tooltip" title="details" data-modal="modal-lg"
data-toggle="modal" data-target="#modals-load-content" data-id="'.$product->id.'" data-route="'.route('modal_load').'"
data-action="user-order-show-product" data-view="customer"><i class="ion ion-md-eye"></i></button>';
})
->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 '<button type="button" class="btn btn-sm btn-md-extra btn-warning add-onetime-product-basket" data-product-id="'.$product->id.'" data-product-name="'.e($product->getLang('name')).'" data-product-price="'.$price.' &euro;">
<strong>&euro; '.$price.'</strong>&nbsp; +<span class="ion ion-md-cart"></span>
</button>';
})
->addColumn('picture', function (Product $product) {
if (count($product->images)) {
return '<img class="img-fluid img-extra" alt="" src="'.route('product_image', [$product->images->first()->slug]).'">';
}
return '';
})
->addColumn('name', function (Product $product) {
return '<strong>'.$product->getLang('name').'</strong>';
})
->addColumn('points', function (Product $product) {
return '<span class="no-line-break">'.$product->getFormattedPoints().'</span>';
})
->addColumn('price_net', function (Product $product) use ($user_abo) {
$ufactor = $user_abo->is_for === 'me' ? true : false;
return '<span class="no-line-break">'.$product->getFormattedPriceWith(true, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €</span>';
})
->addColumn('price_gross', function (Product $product) use ($user_abo) {
$ufactor = $user_abo->is_for === 'me' ? true : false;
return '<span class="no-line-break">'.$product->getFormattedPriceWith(false, $ufactor, Yard::instance(AboOrderCart::INSTANCE)->getUserCountry()).' €</span>';
})
->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]));
}
public function deletePending($view, $id)
{
$user_abo = UserAbo::findOrFail($id);
$this->checkPermissions($view, $user_abo);
if (! $user_abo->canDeletePendingInitialPayment()) {
\Session()->flash('alert-error', __('abo.pending_delete_not_allowed'));
return redirect(route('user_abos', [$view]));
}
\DB::transaction(function () use ($user_abo) {
$user_abo->delete();
});
\Session()->flash('alert-success', __('abo.pending_delete_success'));
return redirect(route('user_abos', [$view]));
}
public function deletePaymentLink($identifier)
{
$shoppingInstance = ShoppingInstance::where('identifier', $identifier)->firstOrFail();
$user = \Auth::user();
$userShopId = $user && $user->shop ? $user->shop->id : null;
if ((int) $shoppingInstance->user_shop_id !== (int) $userShopId || ! OrderPaymentService::isAboCustomerPaymentLink($shoppingInstance)) {
abort(403);
}
if (! OrderPaymentService::canDeleteInstance($shoppingInstance)) {
\Session()->flash('alert-error', __('abo.payment_link_delete_not_allowed'));
return redirect(route('user_abos', ['ot']));
}
OrderPaymentService::deleteInstance($identifier);
\Session()->flash('alert-success', __('abo.payment_link_delete_success'));
return redirect(route('user_abos', ['ot']));
}
private function getAboPaymentLinks()
{
$user = \Auth::user();
$userShopId = $user && $user->shop ? $user->shop->id : null;
if (! $userShopId) {
return collect();
}
return ShoppingInstance::where('user_shop_id', $userShopId)
->where('payment', 6)
->where('status', '<', 10)
->orderBy('created_at', 'desc')
->get()
->filter(fn (ShoppingInstance $shoppingInstance) => OrderPaymentService::isAboCustomerPaymentLink($shoppingInstance))
->reject(fn (ShoppingInstance $shoppingInstance) => OrderPaymentService::hasUserAboForPaymentLink($shoppingInstance, $user))
->values();
}
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');
}
}
}