json($this->payments->publicOptions()); } public function initiate(Request $request) { $gateway = $this->payments->resolve(); if (!$gateway || !$gateway->isAvailable()) { throw new UnprocessableEntityHttpException('پرداخت آنلاین در حال حاضر فعال نیست'); } $amount = (int) $request->input('value', $request->input('amount', 0)); $minDeposit = $this->config->getInt('min_deposit', 0); if ($amount < 1000) { throw new UnprocessableEntityHttpException('حداقل مبلغ پرداخت ۱۰۰۰ ریال است'); } if ($minDeposit > 0 && $amount < $minDeposit) { throw new UnprocessableEntityHttpException( 'حداقل مقدار واریز ' . number_format($minDeposit) . ' ریال است' ); } $customer = auth('customer')->user(); $withdraw = Withdraw::create([ 'customer_id' => $customer->id, 'cash' => $amount, 'note' => 'واریز آنلاین', 'sts' => 1, ]); $referenceId = 'WD-' . $withdraw->id; try { $result = $gateway->initiate([ 'amount' => $amount, 'reference_id' => $referenceId, 'description' => 'شارژ کیف پول کاربر ' . ($customer->name ?? $customer->id), 'metadata' => [ 'withdraw_id' => $withdraw->id, 'customer_id' => $customer->id, ], ]); } catch (RuntimeException $e) { $withdraw->sts = 3; $withdraw->save(); \Log::warning('wallet.payment.initiate_failed', [ 'withdraw_id' => $withdraw->id, 'message' => $e->getMessage(), ]); return response()->json([ 'message' => $e->getMessage() ?: 'مشکل در ارتباط با درگاه', ], 422); } if (!empty($result['session_id'])) { $withdraw->tracked_number = (string) $result['session_id']; $withdraw->save(); } // حداقل اطلاعات برای redirect — بدون credential و بدون جزئیات داخلی درگاه return response()->json([ 'payment_url' => $result['payment_url'], ], 201); } /** * وریفای برگشت مرورگر از فرانت — امضا و شارژ سمت سرور؛ بدون افشای secret. * Body یا query: status, reference_id, session_id, amount, track_number, timestamp, signature */ public function verifyReturn(Request $request) { $gateway = $this->payments->resolve(); if (!$gateway) { throw new UnprocessableEntityHttpException('پرداخت آنلاین فعال نیست'); } $payload = []; foreach ([ 'status', 'reference_id', 'session_id', 'amount', 'track_number', 'timestamp', 'signature', ] as $key) { if (!$request->has($key)) { continue; } $value = $request->input($key); if ($value === null || is_array($value)) { continue; } // track_number خالی هم ممکن است در امضا باشد $payload[$key] = (string) $value; } if (($payload['signature'] ?? '') === '' || ($payload['reference_id'] ?? '') === '') { return response()->json([ 'ok' => false, 'message' => 'پارامترهای بازگشت ناقص است', ], 422); } $result = $gateway->handleReturnPayload($payload); if (!($result['ok'] ?? false)) { return response()->json([ 'ok' => false, 'message' => $result['message'] ?? 'خطا در تأیید پرداخت', ], (int) ($result['http_status'] ?? 400)); } /** @var Withdraw|null $withdraw */ $withdraw = $result['withdraw'] ?? null; if (!$withdraw) { return response()->json(['ok' => false, 'message' => 'سفارش یافت نشد'], 404); } $customerId = (int) auth('customer')->id(); if ((int) $withdraw->customer_id !== $customerId) { return response()->json(['ok' => false, 'message' => 'دسترسی غیرمجاز'], 403); } $sts = (int) $withdraw->sts; $paid = $sts === 2; return response()->json([ 'ok' => true, 'paid' => $paid, 'status' => $paid ? 'success' : ((string) ($payload['status'] ?? '') === 'success' ? 'pending' : 'failed'), 'amount' => (int) $withdraw->cash, 'reference_id' => 'WD-' . $withdraw->id, 'withdraw_id' => $withdraw->id, 'track_number' => $withdraw->tracked_number, ]); } public function returnFromGateway(Request $request, string $provider) { try { $gateway = $this->payments->resolveOrFail($provider); } catch (InvalidArgumentException $e) { return response('درگاه نامعتبر', 404); } $result = $gateway->handleReturn($request); if (!($result['ok'] ?? false)) { return response( (string) ($result['message'] ?? 'خطا'), (int) ($result['http_status'] ?? 400) ); } $Withdraw = $result['withdraw']; $site_url = $this->config->resolvePublicSiteUrl($request) ?: '/'; return view('showTransactionReport', compact('Withdraw', 'site_url')); } public function webhook(Request $request, string $provider) { try { $gateway = $this->payments->resolveOrFail($provider); } catch (InvalidArgumentException $e) { return response()->json(['message' => 'invalid_provider'], 404); } $result = $gateway->handleWebhook($request); $status = (int) ($result['http_status'] ?? 200); if (!($result['ok'] ?? false)) { return response()->json([ 'message' => $result['message'] ?? 'error', ], $status >= 400 ? $status : 400); } return response()->json([ 'ok' => true, 'ignored' => (bool) ($result['ignored'] ?? false), ]); } /** سازگاری با URLهای قبلی external-payment/* → montify */ public function returnLegacy(Request $request) { return $this->returnFromGateway($request, WalletPaymentManager::PROVIDER_MONTIFY); } public function webhookLegacy(Request $request) { return $this->webhook($request, WalletPaymentManager::PROVIDER_MONTIFY); } }