baseUrl = config('wellnet.credit_api.base_url'); $this->companyCode = config('wellnet.credit_api.company_code'); $this->authKey = config('wellnet.credit_api.auth_key'); $this->timeout = config('wellnet.credit_api.timeout', 120); } /** * 与信照会要求(Authorize) * * @param string $memberNo 会員番号 * @param int $payAmount 決済金額 * @param int|null $cardNoSeq カード連番(未指定時はデフォルト使用) * @return array レスポンスデータ * @throws RuntimeException APIエラー時 */ public function authorize(string $memberNo, int $payAmount, ?int $cardNoSeq = null): array { $payload = [ 'requestId' => $this->generateRequestId(), 'companyCode' => $this->companyCode, 'authKey' => $this->authKey, 'memberNo' => $memberNo, 'payAmount' => $payAmount, ]; if ($cardNoSeq !== null) { $payload['cardNoSeq'] = $cardNoSeq; } return $this->post('/api/authori', $payload); } /** * 売上確定要求(Capture) * * @param string $paymentNumber 決済番号 * @return array レスポンスデータ * @throws RuntimeException APIエラー時 */ public function capture(string $paymentNumber): array { $payload = [ 'requestId' => $this->generateRequestId(), 'companyCode' => $this->companyCode, 'authKey' => $this->authKey, 'paymentNumber' => $paymentNumber, ]; return $this->post('/api/definiteTanking', $payload); } /** * 与信取消要求(全額取消) * * @param string $paymentNumber 決済番号 * @return array レスポンスデータ * @throws RuntimeException APIエラー時 */ public function cancelAuthorize(string $paymentNumber): array { $payload = [ 'requestId' => $this->generateRequestId(), 'companyCode' => $this->companyCode, 'authKey' => $this->authKey, 'paymentNumber' => $paymentNumber, ]; try { return $this->post('/api/cancelAuthori', $payload); } catch (RuntimeException $e) { if ((int) $e->getCode() === 404) { return $this->post('/api/cancelPayment', $payload); } throw $e; } } /** * 差額返金要求(部分返金/全額返金) * * @param string $paymentNumber 決済番号 * @param int $afterRefundPayAmount 返金後の残額(全額返金時は0) * @return array レスポンスデータ * @throws RuntimeException APIエラー時 */ public function refund(string $paymentNumber, int $afterRefundPayAmount): array { $payload = [ 'requestId' => $this->generateRequestId(), 'companyCode' => $this->companyCode, 'authKey' => $this->authKey, 'paymentNumber' => $paymentNumber, 'afterRefundPayAmount' => $afterRefundPayAmount, ]; try { return $this->post('/api/refund', $payload); } catch (RuntimeException $e) { if ((int) $e->getCode() === 404) { return $this->post('/api/refundPayment', $payload); } throw $e; } } /** * HTTP POST送信 * * @param string $path APIパス * @param array $payload リクエストボディ * @return array レスポンスデータ * @throws RuntimeException 通信エラー・APIエラー時 */ private function post(string $path, array $payload): array { $url = rtrim($this->baseUrl, '/') . $path; $response = Http::timeout($this->timeout) ->acceptJson() ->post($url, $payload); if (!$response->successful()) { $body = $response->json() ?? []; $errorDesc = $body['errorDescription'] ?? $body['result'] ?? 'HTTP ' . $response->status(); throw new RuntimeException( 'クレジットAPIエラー: ' . $errorDesc, $response->status() ); } $data = $response->json(); if (isset($data['result']) && $data['result'] !== 'SUCCESS') { throw new RuntimeException( 'クレジットAPIエラー: ' . ($data['errorDescription'] ?? $data['result']), 400 ); } return $data; } /** * リクエストID自動採番 * * @return string 一意のリクエストID */ private function generateRequestId(): string { return 'REQ-' . date('YmdHis') . '-' . Str::random(6); } }