Fix some for sign body to montify and not get 401 error|
This commit is contained in:
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\pay;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Withdraw;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\Payment\Contracts\SupportsStatusQuery;
|
||||
use App\Services\Payment\WalletDepositCreditor;
|
||||
use App\Services\Payment\WalletPaymentManager;
|
||||
use Illuminate\Http\Request;
|
||||
use InvalidArgumentException;
|
||||
@@ -20,6 +22,7 @@ class WalletPaymentController extends Controller
|
||||
public function __construct(
|
||||
private WalletPaymentManager $payments,
|
||||
private ConfigService $config,
|
||||
private WalletDepositCreditor $creditor,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -105,25 +108,17 @@ class WalletPaymentController extends Controller
|
||||
throw new UnprocessableEntityHttpException('پرداخت آنلاین فعال نیست');
|
||||
}
|
||||
|
||||
// همه پارامترهای برگشت عیناً وارد امضا میشوند؛ whitelist کردن باعث
|
||||
// مغایرت امضا میشود اگر پارتنر پارامتر اضافهای بفرستد.
|
||||
$payload = [];
|
||||
foreach ([
|
||||
'status',
|
||||
'reference_id',
|
||||
'session_id',
|
||||
'amount',
|
||||
'track_number',
|
||||
'timestamp',
|
||||
'signature',
|
||||
] as $key) {
|
||||
if (!$request->has($key)) {
|
||||
foreach ($request->all() as $key => $value) {
|
||||
if (!is_string($key) || $key === '' || is_array($value) || $value === null) {
|
||||
continue;
|
||||
}
|
||||
$value = $request->input($key);
|
||||
if ($value === null || is_array($value)) {
|
||||
continue;
|
||||
if (count($payload) >= 30) {
|
||||
break;
|
||||
}
|
||||
// track_number خالی هم ممکن است در امضا باشد
|
||||
$payload[$key] = (string) $value;
|
||||
$payload[$key] = is_bool($value) ? ($value ? 'true' : 'false') : (string) $value;
|
||||
}
|
||||
|
||||
if (($payload['signature'] ?? '') === '' || ($payload['reference_id'] ?? '') === '') {
|
||||
@@ -136,6 +131,12 @@ class WalletPaymentController extends Controller
|
||||
$result = $gateway->handleReturnPayload($payload);
|
||||
|
||||
if (!($result['ok'] ?? false)) {
|
||||
// redirect مرورگر قابل اعتماد نیست؛ منبع حقیقت، استعلام مستقیم از درگاه است.
|
||||
$fallback = $this->statusFallback((string) $payload['reference_id']);
|
||||
if ($fallback) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => $result['message'] ?? 'خطا در تأیید پرداخت',
|
||||
@@ -148,18 +149,77 @@ class WalletPaymentController extends Controller
|
||||
return response()->json(['ok' => false, 'message' => 'سفارش یافت نشد'], 404);
|
||||
}
|
||||
|
||||
$customerId = (int) auth('customer')->id();
|
||||
if ((int) $withdraw->customer_id !== $customerId) {
|
||||
if (!$this->ownsWithdraw($withdraw)) {
|
||||
return response()->json(['ok' => false, 'message' => 'دسترسی غیرمجاز'], 403);
|
||||
}
|
||||
|
||||
$sts = (int) $withdraw->sts;
|
||||
$paid = $sts === 2;
|
||||
$paid = (int) $withdraw->sts === 2;
|
||||
|
||||
return $this->paymentStateResponse(
|
||||
$withdraw,
|
||||
$paid ? 'success' : ((string) ($payload['status'] ?? '') === 'success' ? 'pending' : 'failed')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* استعلام وضعیت یک پرداخت از درگاه — برای polling فرانت وقتی نتیجه هنوز قطعی نیست.
|
||||
*/
|
||||
public function status(Request $request)
|
||||
{
|
||||
$referenceId = trim((string) $request->input('reference_id', ''));
|
||||
if ($referenceId === '') {
|
||||
return response()->json(['ok' => false, 'message' => 'شناسه پرداخت ارسال نشده'], 422);
|
||||
}
|
||||
|
||||
$response = $this->statusFallback($referenceId);
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return response()->json(['ok' => false, 'message' => 'سفارش یافت نشد'], 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* استعلام مستقیم وضعیت از درگاه با بررسی مالکیت سفارش.
|
||||
*/
|
||||
private function statusFallback(string $referenceId): ?\Illuminate\Http\JsonResponse
|
||||
{
|
||||
$withdraw = $this->creditor->findByReference($referenceId);
|
||||
if (!$withdraw || !$this->ownsWithdraw($withdraw)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((int) $withdraw->sts !== 2) {
|
||||
$gateway = $this->payments->resolve();
|
||||
if ($gateway instanceof SupportsStatusQuery) {
|
||||
$gateway->syncStatusByReference($referenceId);
|
||||
$withdraw = $withdraw->fresh() ?: $withdraw;
|
||||
}
|
||||
}
|
||||
|
||||
$sts = (int) $withdraw->sts;
|
||||
|
||||
return $this->paymentStateResponse(
|
||||
$withdraw,
|
||||
match ($sts) {
|
||||
2 => 'success',
|
||||
3 => 'failed',
|
||||
default => 'pending',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function ownsWithdraw(Withdraw $withdraw): bool
|
||||
{
|
||||
return (int) $withdraw->customer_id === (int) auth('customer')->id();
|
||||
}
|
||||
|
||||
private function paymentStateResponse(Withdraw $withdraw, string $status): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'paid' => $paid,
|
||||
'status' => $paid ? 'success' : ((string) ($payload['status'] ?? '') === 'success' ? 'pending' : 'failed'),
|
||||
'paid' => (int) $withdraw->sts === 2,
|
||||
'status' => $status,
|
||||
'amount' => (int) $withdraw->cash,
|
||||
'reference_id' => 'WD-' . $withdraw->id,
|
||||
'withdraw_id' => $withdraw->id,
|
||||
|
||||
Reference in New Issue
Block a user