238 lines
7.6 KiB
PHP
238 lines
7.6 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Cron\UserMakeOrder;
|
|
use App\Models\UserAbo;
|
|
use App\Models\UserAboOrder;
|
|
use App\Services\Incentive\IncentiveTracker;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class AboRetryPaymentService
|
|
{
|
|
/**
|
|
* @return array{success: bool, message: string, order_id?: int}
|
|
*/
|
|
public function retry(UserAbo $userAbo): array
|
|
{
|
|
if ($userAbo->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<string, mixed>
|
|
*/
|
|
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<string, mixed> $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<string, mixed> $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<string, mixed> $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;
|
|
}
|
|
}
|