status !== 3) { return [ 'success' => false, 'message' => __('abo.retry_only_hold'), ]; } if (! $userAbo->active) { return [ 'success' => false, 'message' => __('abo.retry_only_active'), ]; } if ($this->alreadyPaidToday($userAbo)) { return [ 'success' => false, 'message' => __('abo.retry_already_paid_today'), ]; } \Log::channel('abo_order')->info('AboRetryPaymentService: Starte erneuten Zahlungsversuch', [ 'abo_id' => $userAbo->id, 'email' => $userAbo->email, 'payone_userid' => $userAbo->payone_userid, ]); AboHelper::ensureUserAboItemsFromLatestOrder($userAbo); $shoppingOrder = null; $paymentAttemptRecorded = false; $userOrder = new UserMakeOrder($userAbo); try { if (! $userOrder->createShoppingUser()) { return [ 'success' => false, 'message' => __('abo.retry_error_shopping_user'), ]; } $shoppingOrder = $userOrder->makeShoppingOrder(); if (! $shoppingOrder) { return [ 'success' => false, 'message' => __('abo.retry_error_order'), ]; } $response = $this->normalizePaymentResponse($userOrder->makePayment()); if (($response['status'] ?? null) === 'APPROVED') { $this->markAboSuccess($userAbo, $shoppingOrder); $paymentAttemptRecorded = true; return [ 'success' => true, 'message' => __('abo.retry_success', ['order' => $shoppingOrder->id]), 'order_id' => $shoppingOrder->id, ]; } $this->logPaymentError($userAbo, $shoppingOrder, $response); $this->markAboError($userAbo, $shoppingOrder); $paymentAttemptRecorded = true; $this->sendPaymentErrorMail($userOrder, $shoppingOrder, $response); return [ 'success' => false, 'message' => __('abo.retry_failed', [ 'error' => $this->formatPaymentError($response), 'order' => $shoppingOrder->id, ]), 'order_id' => $shoppingOrder->id, ]; } catch (\Throwable $e) { \Log::channel('abo_order')->error('AboRetryPaymentService: Exception beim erneuten Zahlungsversuch', [ 'abo_id' => $userAbo->id, 'order_id' => $shoppingOrder?->id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); if ($shoppingOrder && ! $paymentAttemptRecorded) { $this->markAboError($userAbo, $shoppingOrder); } return [ 'success' => false, 'message' => __('abo.retry_exception', ['error' => $e->getMessage()]), 'order_id' => $shoppingOrder?->id, ]; } } private function alreadyPaidToday(UserAbo $userAbo): bool { return UserAboOrder::where('user_abo_id', $userAbo->id) ->whereDate('created_at', now()->toDateString()) ->where('paid', true) ->exists(); } /** * @return array */ private function normalizePaymentResponse(mixed $response): array { if (is_object($response)) { return (array) $response; } return is_array($response) ? $response : []; } private function markAboSuccess(UserAbo $userAbo, mixed $shoppingOrder): void { DB::transaction(function () use ($userAbo, $shoppingOrder): void { $userAbo->update([ 'status' => 2, 'active' => true, 'next_date' => AboHelper::setNextDate(now(), $userAbo->abo_interval), 'last_date' => now(), ]); UserAboOrder::create([ 'user_abo_id' => $userAbo->id, 'shopping_order_id' => $shoppingOrder->id, 'status' => 1, 'paid' => true, ]); }); try { IncentiveTracker::trackAboActivated($shoppingOrder); } catch (\Throwable $e) { \Log::channel('abo_order')->error('AboRetryPaymentService: Incentive-Tracking nach erfolgreichem Retry fehlgeschlagen', [ 'abo_id' => $userAbo->id, 'order_id' => $shoppingOrder->id, 'error' => $e->getMessage(), ]); } } private function markAboError(UserAbo $userAbo, mixed $shoppingOrder): void { DB::transaction(function () use ($userAbo, $shoppingOrder): void { $userAbo->update([ 'status' => 3, 'last_date' => now(), ]); UserAboOrder::create([ 'user_abo_id' => $userAbo->id, 'shopping_order_id' => $shoppingOrder->id, 'status' => 3, 'paid' => false, ]); }); } /** * @param array $response */ private function logPaymentError(UserAbo $userAbo, mixed $shoppingOrder, array $response): void { \Log::channel('abo_order')->error('AboRetryPaymentService: Zahlungsfehler beim erneuten Versuch', [ 'abo_id' => $userAbo->id, 'order_id' => $shoppingOrder->id, 'response' => $response, ]); MyLog::writeLog( 'userabo', 'error', 'Error:AboRetryPaymentService::retry / makePayment Error', $response ); } /** * @param array $response */ private function sendPaymentErrorMail(UserMakeOrder $userOrder, mixed $shoppingOrder, array $response): void { $shoppingPayment = $userOrder->getShoppingPayment(); if (! $shoppingPayment) { return; } try { Payment::paymentStatusSendMail($shoppingOrder, $shoppingPayment, [ 'mode' => $shoppingPayment->mode, 'txaction' => 'error', 'send_link' => false, 'payment_error' => $response, ]); } catch (\Throwable $e) { \Log::channel('abo_order')->error('AboRetryPaymentService: Fehlermail nach Zahlungsfehler konnte nicht gesendet werden', [ 'order_id' => $shoppingOrder->id, 'payment_id' => $shoppingPayment->id, 'error' => $e->getMessage(), ]); } } /** * @param array $response */ private function formatPaymentError(array $response): string { $errorCode = $response['errorcode'] ?? null; $errorMessage = $response['errormessage'] ?? $response['customermessage'] ?? ($response['status'] ?? __('payment.unknown')); if ($errorCode) { return '['.$errorCode.'] '.$errorMessage; } return (string) $errorMessage; } }