249 lines
8.4 KiB
PHP
249 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Payment;
|
|
use Illuminate\Http\Request;
|
|
use GuzzleHttp\Client;
|
|
use Illuminate\Support\Facades\Log;
|
|
use GuzzleHttp\Exception\ClientException;
|
|
use GuzzleHttp\Exception\ServerException;
|
|
|
|
class WisePaymentController extends Controller
|
|
{
|
|
private $wiseClient;
|
|
private $wiseApiKey;
|
|
private $profileId;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->wiseApiKey = env('WISE_API_KEY');
|
|
$this->profileId = env('WISE_PROFILE_ID'); // Your Wise business/profile ID
|
|
|
|
$this->wiseClient = new Client([
|
|
'base_uri' => 'https://api.wise.com/v1/',
|
|
'headers' => [
|
|
'Authorization' => 'Bearer ' . $this->wiseApiKey,
|
|
'Content-Type' => 'application/json',
|
|
],
|
|
]);
|
|
}
|
|
|
|
public function createTransfer(Request $request)
|
|
{
|
|
// Validate the incoming request data
|
|
$validatedData = $request->validate([
|
|
'amount' => 'required|numeric|min:0.01',
|
|
'source_currency' => 'required|string|size:3',
|
|
'target_currency' => 'required|string|size:3',
|
|
'recipient_name' => 'required|string|max:255',
|
|
'recipient_email' => 'required|email',
|
|
'recipient_account_number' => 'required|string',
|
|
'recipient_bank_code' => 'sometimes|string', // Needed for some countries
|
|
'recipient_address' => 'sometimes|array',
|
|
'reason' => 'sometimes|string|max:255',
|
|
]);
|
|
|
|
try {
|
|
// Create a new Payment record
|
|
$payment = new Payment([
|
|
'amount' => $validatedData['amount'],
|
|
'currency' => $validatedData['source_currency'],
|
|
'target_currency' => $validatedData['target_currency'],
|
|
'recipient_name' => $validatedData['recipient_name'],
|
|
'recipient_email' => $validatedData['recipient_email'],
|
|
'status' => 'pending',
|
|
'client_session_id' => $request->client_session_id ?? uniqid('wise_', true)
|
|
]);
|
|
$payment->save();
|
|
|
|
// Create recipient account
|
|
$recipient = $this->createRecipient($validatedData);
|
|
|
|
// Create quote
|
|
$quote = $this->createQuote($validatedData);
|
|
|
|
// Create transfer
|
|
$transfer = $this->createTransferWise($quote, $recipient, $validatedData);
|
|
|
|
// Fund the transfer
|
|
$this->fundTransfer($transfer['id']);
|
|
|
|
// Update the Payment record
|
|
$payment->wise_transfer_id = $transfer['id'];
|
|
$payment->wise_recipient_id = $recipient['id'];
|
|
$payment->wise_quote_id = $quote['id'];
|
|
$payment->status = 'processing';
|
|
$payment->save();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Transfer initiated successfully.',
|
|
'transfer_id' => $transfer['id'],
|
|
'payment_id' => $payment->id
|
|
]);
|
|
|
|
} catch (ClientException $e) {
|
|
$response = $e->getResponse();
|
|
$body = json_decode($response->getBody()->getContents(), true);
|
|
|
|
Log::error('Wise Client Error:', [
|
|
'code' => $e->getCode(),
|
|
'message' => $e->getMessage(),
|
|
'details' => $body
|
|
]);
|
|
|
|
if (isset($payment)) {
|
|
$payment->status = 'failed';
|
|
$payment->error_message = $e->getMessage();
|
|
$payment->save();
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Wise API failed to process the request.',
|
|
'error' => $body['errors'] ?? $e->getMessage()
|
|
], 400);
|
|
|
|
} catch (\Exception $e) {
|
|
Log::error('General Wise API Error:', [
|
|
'message' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
|
|
if (isset($payment)) {
|
|
$payment->status = 'failed';
|
|
$payment->error_message = $e->getMessage();
|
|
$payment->save();
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'An unexpected error occurred.',
|
|
'error' => $e->getMessage()
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function handleWebhook(Request $request)
|
|
{
|
|
// Verify the webhook signature if needed
|
|
$payload = $request->all();
|
|
|
|
Log::info('Wise Webhook Received:', $payload);
|
|
|
|
if (isset($payload['data']['resource']['id'])) {
|
|
$transferId = $payload['data']['resource']['id'];
|
|
|
|
// Find the payment by transfer ID
|
|
$payment = Payment::where('wise_transfer_id', $transferId)->first();
|
|
|
|
if ($payment) {
|
|
$payment->status = $payload['data']['current_state'] ?? 'unknown';
|
|
$payment->save();
|
|
|
|
// You might want to trigger other actions based on status change
|
|
}
|
|
}
|
|
|
|
return response()->json(['status' => 'ok']);
|
|
}
|
|
|
|
// Helper methods to interact with Wise API
|
|
private function createRecipient($data)
|
|
{
|
|
$response = $this->wiseClient->post('accounts', [
|
|
'json' => [
|
|
'profile' => $this->profileId,
|
|
'accountHolderName' => $data['recipient_name'],
|
|
'currency' => $data['target_currency'],
|
|
'type' => 'email', // or 'sort_code', 'aba', 'iban' etc. based on country
|
|
'details' => [
|
|
'email' => $data['recipient_email'],
|
|
// Add more details based on account type and country
|
|
'legalType' => 'PRIVATE',
|
|
// 'accountNumber' => $data['recipient_account_number'],
|
|
// 'bankCode' => $data['recipient_bank_code'] ?? null,
|
|
]
|
|
],
|
|
]);
|
|
|
|
return json_decode($response->getBody(), true);
|
|
}
|
|
|
|
private function createQuote($data)
|
|
{
|
|
$response = $this->wiseClient->post('quotes', [
|
|
'json' => [
|
|
'profile' => $this->profileId,
|
|
'source' => $data['source_currency'],
|
|
'target' => $data['target_currency'],
|
|
'rateType' => 'FIXED', // or 'FLOAT'
|
|
'sourceAmount' => $data['amount'],
|
|
'type' => 'BALANCE_PAYOUT' // or 'BALANCE_CONVERSION'
|
|
],
|
|
]);
|
|
|
|
return json_decode($response->getBody(), true);
|
|
}
|
|
|
|
private function createTransferWise($quote, $recipient, $data)
|
|
{
|
|
$response = $this->wiseClient->post('transfers', [
|
|
'json' => [
|
|
'targetAccount' => $recipient['id'],
|
|
'quote' => $quote['id'],
|
|
'customerTransactionId' => uniqid('cti_', true),
|
|
'details' => [
|
|
'reference' => $data['reason'] ?? 'Payment for services',
|
|
'transferPurpose' => $data['reason'] ?? 'Payment for services',
|
|
]
|
|
],
|
|
]);
|
|
|
|
return json_decode($response->getBody(), true);
|
|
}
|
|
|
|
private function fundTransfer($transferId)
|
|
{
|
|
// Check if the transfer requires funding
|
|
$transfer = $this->wiseClient->get("transfers/{$transferId}");
|
|
$transferData = json_decode($transfer->getBody(), true);
|
|
|
|
if ($transferData['status'] === 'pending') {
|
|
// Fund the transfer from your balance
|
|
$this->wiseClient->post("transfers/{$transferId}/payments", [
|
|
'json' => [
|
|
'type' => 'BALANCE',
|
|
'profile' => $this->profileId
|
|
]
|
|
]);
|
|
}
|
|
}
|
|
|
|
// Additional helper method to check transfer status
|
|
public function checkTransferStatus($paymentId)
|
|
{
|
|
$payment = Payment::findOrFail($paymentId);
|
|
|
|
try {
|
|
$response = $this->wiseClient->get("transfers/{$payment->wise_transfer_id}");
|
|
$transferData = json_decode($response->getBody(), true);
|
|
|
|
$payment->status = $transferData['status'];
|
|
$payment->save();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'status' => $transferData['status']
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Failed to check transfer status'
|
|
], 500);
|
|
}
|
|
}
|
|
}
|