Skip to content

Instantly share code, notes, and snippets.

@bulentsakarya
Created July 26, 2024 15:10
Show Gist options
  • Save bulentsakarya/a76a4333704bcb0be811f17bb308adc2 to your computer and use it in GitHub Desktop.
Save bulentsakarya/a76a4333704bcb0be811f17bb308adc2 to your computer and use it in GitHub Desktop.
Laravel Paytr Ödeme Entegrasyonu
<?php
return [
'merchant_id' => env('PAYTR_MERCHANT_ID', "PAYTR_MERCHANT_ID"),
'merchant_key' => env('PAYTR_MERCHANT_KEY', "PAYTR_MERCHANT_KEY"),
'merchant_salt' => env('PAYTR_MERCHANT_SALT', "PAYTR_MERCHANT_SALT"),
'max_installment' => 0,
'no_installment' => 0,
'test_mode' => 1,
'debug_on' => 1,
'non_3d' => 0,
'lang' => 'tr',
'merchant_ok_url' => env('PAYTR_OK_URL', "PAYTR_OK_URL"),
'merchant_fail_url' => env('PAYTR_FAIL_URL', "PAYTR_FAIL_URL"),
'timeout_limit' => 30,
'currency' => 'TRY',
'api_type' => 2,
'api_url' => env('PAYTR_API_URL', "PAYTR_API_URL"),
];
<?php
namespace App\Http\Controllers\User\Payment;
use App\Http\Controllers\Controller;
use App\Models\Service;
use App\Models\Order;
use App\Services\User\PaymentService;
use Illuminate\Http\Request;
class PaymentController extends Controller
{
protected $paymentService;
public function __construct(PaymentService $paymentService)
{
$this->paymentService = $paymentService;
}
public function showPaymentPage(Request $request, Service $service)
{
$user = auth()->user();
$invoiceDetails = [
'company_name' => $request->input('company_name'),
'address' => $request->input('company_address'),
'phone' => $request->input('company_phone'),
];
$iframeUrl = $this->paymentService->initiatePayment($service, $invoiceDetails);
return view('user.payment.new', compact('iframeUrl', 'service'));
}
public function paymentCallback(Request $request)
{
$result = $this->paymentService->handleCallback($request);
if (!$result) {
return response('PAYTR notification failed: bad hash', 400);
}
return response('OK');
}
public function paymentSuccess(Request $request)
{
$order = Order::where('order_id', $request->merchant_oid)->firstOrFail();
if ($order->status !== 'completed') {
return view('payment.waiting', ['order' => $order]);
}
return redirect()->route('app.services')
->with('success', 'Ödemeniz başarıyla gerçekleşti ve servisiniz etkinleştirildi.');
}
public function paymentFail(Request $request)
{
$order = Order::where('order_id', $request->merchant_oid)->firstOrFail();
if ($order->status !== 'failed') {
$order->update(['status' => 'failed']);
}
return redirect()->route('app.services')
->with('error', 'Ödeme işlemi başarısız oldu. Lütfen daha sonra tekrar deneyiniz.');
}
public function checkPaymentStatus(Order $order)
{
return response()->json(['status' => $order->status]);
}
}
<?php
namespace App\Services\User;
use App\Models\Order;
use App\Models\Service;
use Carbon\Carbon;
class PaymentService
{
public function initiatePayment(Service $service, array $invoiceDetails)
{
$user = auth()->user();
$orderData = $this->prepareOrderData($service, $user, $invoiceDetails);
$postVals = $this->preparePostVals($orderData);
$result = $this->sendPaytrRequest($postVals);
if ($result['status'] == 'success') {
$this->createOrder($user, $service, $orderData, $result['token']);
return 'https://www.paytr.com/odeme/guvenli/' . $result['token'];
} else {
throw new \Exception('PAYTR IFRAME failed. reason: ' . $result['reason']);
}
}
protected function prepareOrderData($service, $user, $invoiceDetails)
{
return [
'merchant_id' => config('paytr.merchant_id'),
'user_ip' => app('request')->ip(),
'merchant_oid' => uniqid(),
'email' => $invoiceDetails['email_address'] ?? $user->email,
'payment_amount' => $service->price * 100,
'user_basket' => base64_encode(json_encode([[$service->title, $service->price, 1]])),
'user_name' => $invoiceDetails['company_name'] ?? "{$user->name} {$user->surname}",
'user_address' => $invoiceDetails['address'] ?? 'Adres bilgisi yok',
'user_phone' => $invoiceDetails['phone'] ?? 'Telefon bilgisi yok',
];
}
protected function preparePostVals($orderData)
{
$hashStr = $orderData['merchant_id'] . $orderData['user_ip'] . $orderData['merchant_oid'] . $orderData['email'] . $orderData['payment_amount'] . $orderData['user_basket'] . config('paytr.no_installment') . config('paytr.max_installment') . config('paytr.currency') . config('paytr.test_mode') . config('paytr.merchant_salt');
$token = base64_encode(hash_hmac('sha256', $hashStr, config('paytr.merchant_key'), true));
return array_merge($orderData, [
'paytr_token' => $token,
'debug_on' => config('paytr.debug_on'),
'no_installment' => config('paytr.no_installment'),
'max_installment' => config('paytr.max_installment'),
'merchant_ok_url' => config('paytr.merchant_ok_url'),
'merchant_fail_url' => config('paytr.merchant_fail_url'),
'timeout_limit' => config('paytr.timeout_limit'),
'currency' => config('paytr.currency'),
'test_mode' => config('paytr.test_mode')
]);
}
protected function sendPaytrRequest($postVals)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.paytr.com/odeme/api/get-token");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postVals);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
$result = @curl_exec($ch);
if (curl_errno($ch)) {
throw new \Exception("PAYTR IFRAME connection error. err:" . curl_error($ch));
}
curl_close($ch);
return json_decode($result, true);
}
protected function createOrder($user, $service, $orderData, $token)
{
Order::create([
'user_id' => $user->id,
'service_id' => $service->id,
'order_id' => $orderData['merchant_oid'],
'amount' => $service->price,
'status' => 'pending',
'payment_token' => $token,
]);
}
public function handleCallback($request)
{
if (!$this->validateCallback($request)) {
return false;
}
$order = Order::where('order_id', $request->merchant_oid)->firstOrFail();
$request->status == 'success'
? $this->processSuccessfulPayment($order)
: $this->processFailedPayment($order);
return true;
}
protected function validateCallback($request)
{
$merchant_key = config('paytr.merchant_key');
$merchant_salt = config('paytr.merchant_salt');
$hash = base64_encode(hash_hmac('sha256', $request->merchant_oid . $merchant_salt . $request->status . $request->total_amount, $merchant_key, true));
return $hash === $request->hash;
}
protected function processSuccessfulPayment(Order $order)
{
$order->update(['status' => 'completed']);
$user = $order->user;
$service = $order->service;
$activatedAt = Carbon::now();
$user->services()->attach($service->id, [
'is_active' => true,
'activated_at' => $activatedAt,
'expires_at' => $activatedAt->copy()->addYear(),
]);
}
protected function processFailedPayment(Order $order)
{
$order->update(['status' => 'failed']);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment