viewData([ 'order' => null, 'prefill_order' => request('order'), 'prefill_email' => request('email'), ])); } public function lookup(WithdrawalLookupRequest $request): View|RedirectResponse { $order = $this->findOrder((string) $request->string('order_number'), (string) $request->string('email')); if (! $order) { return back() ->withInput() ->with('alert-error', __('withdrawal.not_found')); } return view('web.templates.widerruf', $this->viewData([ 'order' => $order, 'prefill_order' => (string) $request->string('order_number'), 'prefill_email' => (string) $request->string('email'), ])); } public function store(WithdrawalStoreRequest $request): View|RedirectResponse { $order = $this->findOrder((string) $request->string('order_number'), (string) $request->string('email')); if (! $order) { return redirect() ->route('withdrawal.create') ->with('alert-error', __('withdrawal.not_found')); } $isPartial = $request->input('scope') === OrderWithdrawal::TYPE_PARTIAL; $selectedItems = $this->collectSelectedItems($order, $isPartial ? (array) $request->input('items', []) : []); if ($isPartial && empty($selectedItems)) { return back() ->withInput() ->with('alert-error', __('withdrawal.no_items_selected')); } $withdrawal = OrderWithdrawal::create([ 'shopping_order_id' => $order->id, 'user_shop_id' => $order->user_shop_id, 'type' => $isPartial ? OrderWithdrawal::TYPE_PARTIAL : OrderWithdrawal::TYPE_FULL, 'status' => OrderWithdrawal::STATUS_RECEIVED, 'order_reference' => (string) $order->id, 'customer_email' => mb_strtolower((string) $request->string('email')), 'customer_name' => trim(($order->shopping_user->billing_firstname ?? '').' '.($order->shopping_user->billing_lastname ?? '')) ?: null, 'reason' => $request->input('reason'), 'items' => $isPartial ? $selectedItems : $this->collectSelectedItems($order, $this->allItemQuantities($order)), 'ip_address' => $request->ip(), 'user_agent' => (string) $request->userAgent(), 'declared_at' => now(), ]); $this->sendConfirmation($withdrawal, $order); return view('web.templates.widerruf-final', $this->viewData([ 'withdrawal' => $withdrawal, ])); } /** * Findet eine Verbraucher-Shop-Bestellung anhand der vom Kunden bekannten Nummer * (Bestell-ID, Zahlungsreferenz oder Rechnungsnummer) in Kombination mit der E-Mail-Adresse. */ private function findOrder(string $orderNumber, string $email): ?ShoppingOrder { $orderNumber = trim($orderNumber); $email = mb_strtolower(trim($email)); if ($orderNumber === '' || $email === '') { return null; } return ShoppingOrder::query() ->where('payment_for', self::SHOP_PAYMENT_FOR) ->whereHas('shopping_user', function ($query) use ($email): void { $query->whereRaw('LOWER(billing_email) = ?', [$email]); }) ->where(function ($query) use ($orderNumber): void { if (ctype_digit($orderNumber)) { $query->orWhere('id', (int) $orderNumber); } $query->orWhereHas('shopping_payments', function ($payment) use ($orderNumber): void { $payment->where('reference', $orderNumber); }); $query->orWhereHas('user_invoices', function ($invoice) use ($orderNumber): void { $invoice->where('full_number', $orderNumber); }); }) ->with(['shopping_order_items.product', 'shopping_user']) ->latest('id') ->first(); } /** * @return array */ private function allItemQuantities(ShoppingOrder $order): array { return $order->shopping_order_items ->mapWithKeys(fn ($item): array => [$item->id => (int) $item->qty]) ->all(); } /** * Erstellt einen Snapshot der widerrufenen Positionen. * * @param array $quantities * @return array */ private function collectSelectedItems(ShoppingOrder $order, array $quantities): array { $selected = []; foreach ($order->shopping_order_items as $item) { $requestedQty = (int) ($quantities[$item->id] ?? 0); if ($requestedQty <= 0) { continue; } $qty = min($requestedQty, (int) $item->qty); $selected[] = [ 'shopping_order_item_id' => $item->id, 'product_id' => $item->product_id, 'name' => $item->product?->getLang('name') ?? ('#'.$item->product_id), 'qty' => $qty, ]; } return $selected; } private function sendConfirmation(OrderWithdrawal $withdrawal, ShoppingOrder $order): void { $bcc = config('app.withdrawal_mail'); Mail::to($withdrawal->customer_email) ->bcc($bcc) ->locale($order->getLocale()) ->send(new MailWithdrawalConfirmation($withdrawal, $order)); } /** * @param array $extra * @return array */ private function viewData(array $extra = []): array { return array_merge([ 'user_shop' => Util::getUserShop(), 'mylangs' => Shop::getLangChange('webshop'), 'yard_instance' => 'webshop', ], $extra); } }