Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bpmo's avatar
Level 1

Add payment gateway without package and sdk

i have three item for subscription(One time payment) for my users. i need to add features to users according to each of this item as they subscribed

below code give successful payment but redirects to give json output with orderid and amount

i need to correct it

i need to give a success message and add corresponding features to the user they selected out of three items which will be another step which i need to check item is true/active in db and allow that permission. Below is my code.

Migration



<?php



use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;



class AddSubscriptionsFieldToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
//
$table->string('subscription_order_id')->nullable();
$table->integer('subscription_amount')->nullable();
$table->dateTime('subscription_expiry_date')->nullable();
$table->boolean('domain')->default(false);
$table->boolean('themes')->default(false);
$table->boolean('general_service')->default(false);
});
}



/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
//
$table->dropColumn('subscription_order_id');
$table->dropColumn('subscription_amount');
$table->dropColumn('subscription_expiry_date');
$table->dropColumn('domain');
$table->dropColumn('themes');
$table->dropColumn('general_service');
});
}
}

route



Route::get('/payment', [PaymentController::class, 'showPaymentForm'])->name('payment.form');
Route::post('/create-order', [PaymentController::class, 'createOrder'])->name('create.order');
Route::post('/webhook', [PaymentController::class, 'handleWebhook'])->name('webhook');
Route::post('/payment/success', [PaymentController::class, 'processPayment'])->name('process.payment');



model



.......



'domain', 'themes', 'general_service', 'subscription_order_id', 'subscription_amount', 'subscription_expiry_date'
];



public function isSubscriptionActive()
{
return $this->subscription_expiry_date && now()->lt($this->subscription_expiry_date);
}



controller



<?php



namespace App\Http\Controllers;



use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Validator;



class PaymentController extends Controller
{



protected $razorpayKey;
protected $razorpaySecret;
protected $webhookSecret;



public function __construct()
{
$this->middleware('auth');



$this->razorpayKey = 'rzp_test_Xxxxxk';
$this->razorpaySecret = 'xxxxx';
$this->razorpayWebhookSecret = 'xxxxxxx';



}



public function showPaymentForm()
{
return view('payment-form');
}



public function createOrder(Request $request)
{
$validator = Validator::make($request->all(), [
'subscription_item' => 'required|array',
'subscription_item.*' => 'string|in:domain,themes,general_service',
]);



if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}



$selectedItems = $request->input('subscription_item', []);



$itemPrices = [
'domain' => 10000,
'themes' => 15000,
'general_service' => 20000,
];



$totalAmount = 0;
foreach ($selectedItems as $item) {
if (isset($itemPrices[$item])) {
$totalAmount += $itemPrices[$item];
}
}



if ($totalAmount === 0) {
return redirect()->back()->with('error', 'Please select at least one item.');
}



$orderId = 'order_' . uniqid();



$data = array(
'amount' => $totalAmount,
'currency' => 'INR',
'receipt' => $orderId,
);



$headers = array(
'Authorization' => 'Basic ' . base64_encode($this->razorpayKey . ':' . $this->razorpaySecret),
'Content-Type' => 'application/json',
);



$response = Http::withHeaders($headers)->post('https:// api. razorpay. com/v1/orders', $data);



$order = $response->json();
return response()->json(['order_id' => $order['id'], 'amount' => $totalAmount]);



}



public function handleWebhook(Request $request)
{
$payload = $request->getContent();
$headers = $request->header();
$signature = $headers['x-razorpay-signature'];



if (!$this->verifyWebhookSignature($payload, $signature)) {
return response()->json(['error' => 'Invalid webhook signature'], 400);
}



// Process the webhook payload here based on the event type
$event = json_decode($payload, true);



switch ($event['event']) {
case 'payment.authorized':
// Handle authorized payment event
$orderId = $event['payload']['payment']['entity']['order_id'];
$paymentId = $event['payload']['payment']['entity']['id'];
$paymentStatus = $event['payload']['payment']['entity']['status'];
$amount = $event['payload']['payment']['entity']['amount'];



// Get the corresponding user based on the order ID
$user = User::where('subscription_order_id', $orderId)->first();



if ($user && $paymentStatus === 'authorized' && $amount === $user->subscription_amount) {
// Payment authorized. Update user's payment status or perform any other actions.
}
break;



case 'payment.captured':
// Handle captured payment event and update user subscription
$orderId = $event['payload']['payment']['entity']['order_id'];
$paymentId = $event['payload']['payment']['entity']['id'];
$paymentStatus = $event['payload']['payment']['entity']['status'];
$amount = $event['payload']['payment']['entity']['amount'];



// Get the corresponding user based on the order ID
$user = User::where('subscription_order_id', $orderId)->first();



if ($user && $amount === $user->subscription_amount) {
if ($paymentStatus === 'captured') {
// Payment successful, extend the subscription for one year
$user->subscription_expiry_date = Carbon::now()->addYear();



// Set the selected subscription item based on the order details
$orderItems = $event['payload']['payment']['entity']['order']['entity']['items'];
$selectedSubscriptionItem = null;
foreach ($orderItems as $item) {
if ($item['entity']['type'] === 'subscription') {
$selectedSubscriptionItem = $item['entity']['name'];
break;
}
}



// Map the selected subscription item to the corresponding database field
if ($selectedSubscriptionItem === 'domain') {
$user->domain = true;
$user->themes = false;
// $user->general_service = false;
} elseif ($selectedSubscriptionItem === 'themes') {
$user->domain = false;
$user->themes = true;
$user->general_service = false;
} elseif ($selectedSubscriptionItem === 'general_service') {
$user->domain = false;
$user->themes = false;
$user->general_service = true;
}



// Set order ID and payment ID in the user model
$user->subscription_order_id = $orderId;
$user->subscription_payment_id = $paymentId;



} else {
// Payment failed, update any necessary fields or send notifications
// For example, you could log the failed payment or send an email to the user.
Log::info('Payment Failed - Order ID: ' . $orderId . ', Payment ID: ' . $paymentId);
}
$user->save();



}
break;



// Add more cases for other events as needed



default:
// Unknown event received
break;
}



// Respond with a 200 status to acknowledge the webhook
return response()->json(['success' => true], 200);



}



public function processPayment(Request $request)
{
$paymentId = $request->input('razorpay_payment_id');
$signature = $request->input('razorpay_signature');
$orderId = $request->input('order_id');
$amount = $request->input('amount');



// Verify the Razorpay signature
$isValidSignature = $this->verifyRazorpaySignature($orderId, $paymentId, $signature);



if (!$isValidSignature) {
// Handle invalid signature
return response()->json(['error' => 'Invalid payment signature.'], 400);
}



// Get the corresponding user based on the order ID
$user = User::where('subscription_order_id', $orderId)->first();



if (!$user) {
// Handle invalid order ID
return response()->json(['error' => 'Invalid order ID.'], 400);
}



// Verify if the payment amount matches the user's subscription amount
if ($amount !== $user->subscription_amount) {
// Handle mismatched payment amount
return response()->json(['error' => 'Mismatched payment amount.'], 400);
}



// Assuming the payment is successful, update the user's subscription
$user->subscription_expiry_date = Carbon::now()->addYear(); // Extend subscription for one year
$user->save();



return response()->json(['success' => 'Payment successful. Subscription extended for one year.']);
}



private function verifyWebhookSignature($payload, $signature)
{
$expectedSignature = hash_hmac('sha256', $payload, $this->webhookSecret);



return hash_equals($expectedSignature, $signature);
}
}

You removed this message

view



@extends('layouts.app')
@section('title', 'Payment Form')
@section('content')
<div class="card-header text-center bg-primary text-white">Payment Form</div>
<div class="card-body">
<form id="paymentForm" action="https:// www. monsoonmalabar. com/create-order" method="POST">
@csrf
<div class="form-check">
<input type="checkbox" class="form-check-input" name="subscription_item[]" value="domain" id="domain">
<label class="form-check-label" for="domain">Custom Domain</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="subscription_item[]" value="themes" id="themes">
<label class="form-check-label" for="themes">Premium Themes</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="subscription_item[]" value="general_service" id="general_service">
<label class="form-check-label" for="general_service">General Service</label>
</div>
@error('subscription_item')
<div class="alert alert-danger mt-3">{{ $message }}</div>
@enderror
<div class="text-center mt-4">
<button type="submit" class="btn btn-primary">Pay Now</button>
</div>
</form>



<script src="https:// checkout. razorpay. com/v1/checkout.js"></script>
<script>
// Handle form submission to create order and redirect to Razorpay checkout
document.getElementById('paymentForm').addEventListener('submit', function(event) {
event.preventDefault();
createOrder();
});



// Function to create the order and redirect to Razorpay checkout
function createOrder() {
fetch('{{ secure_url("create-order") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': '{{ csrf_token() }}'
},
body: JSON.stringify({
subscription_item: getSelectedItems()
})
})
.then(response => response.json())
.then(data => {
redirectToRazorpay(data.order_id, data.amount);
})
.catch(error => {
console.error('Error:', error);
});
}



// Function to get the selected items from the form
function getSelectedItems() {
const selectedItems = [];
const checkboxes = document.querySelectorAll('input[name="subscription_item[]"]');
checkboxes.forEach(checkbox => {
if (checkbox.checked) {
selectedItems.push(checkbox.value);
}
});
return selectedItems;
}



// Function to redirect to the Razorpay checkout page
function redirectToRazorpay(orderId, amount) {
const options = {
key: 'rzp_test_xxxxxxxxx, // Replace with your actual Razorpay API key
amount: amount,
currency: 'INR',
name: 'Your Company Name',
description: 'Subscription Payment',
image: 'https:// example .com/logo.png',
order_id: orderId,
handler: function(response) {
// Handle the Razorpay payment success response here
console.log('Payment ID:', response.razorpay_payment_id);
console.log('Signature:', response.razorpay_signature);
// Submit the form to process the payment on the server-side
document.getElementById('paymentForm').submit();
},
prefill: {
name: 'John Doe',
email: '[email protected]',
contact: '+919876543210'
},
notes: {
address: 'Your Address'
},
theme: {
color: '#F37254'
}
};
var rzp1 = new Razorpay(options);
rzp1.open();
}
</script>
@endsection

I can't post links since its my first day, so link distorted

0 likes
0 replies

Please or to participate in this conversation.