- modified: routes/web.php
- modified: resources/views/admin/finance/settings/index.blade.php
- modified: app/Http/Controllers/Admin/FinanceSettingController.php
- modified: app/Http/Controllers/User/PaymentController.php
- modified: config/services.php
- created : app/Services/BkashService.php
- created : public/img/payments/bkash.png
- created : Insert New row in Payment Platform table
- modified: Env
Past Line Number 610
Route::get('/payments/approved/bkash', 'approvedBkash')->name('user.payments.approved.bkash');
Past Line Number 77 - 172
<div class="card border-0 special-shadow">
<div class="card-body">
<h6 class="fs-12 font-weight-bold mb-4"><i class="fa-brands fa-cc-paypal fs-16 mr-2"></i>Bkash Payment Gateway
<span class="text-primary">({{ __('All Plans') }})</span></h6>
<div class="row">
<div class="col-md-6 col-sm-12 mb-2">
<div class="form-group">
<label class="custom-switch">
<input type="checkbox" name="bkash_enable" class="custom-switch-input" @if (config('services.bkash.enable') == true) checked @endif>
<span class="custom-switch-indicator"></span>
<span class="custom-switch-description">Enable Bkash</span>
</label>
</div>
</div>
<div class="col-md-6 col-sm-12 mb-2">
<div class="form-group">
<label class="custom-switch">
<input type="checkbox" name="bkash_subscription" class="custom-switch-input" @if (config('services.bkash.subscription') == true) checked @endif>
<span class="custom-switch-indicator"></span>
<span class="custom-switch-description">Enable Bkash Subscription</span>
</label>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="input-box">
<h6>App Key <span class="text-required"><i class="fa-solid fa-asterisk"></i></span></h6>
<div class="form-group">
<input type="text" class="form-control @error('bkash_app_key') is-danger @enderror"
id="bkash_app_key" name="bkash_app_key"
value="{{ config('services.bkash.app_key') }}" autocomplete="off">
</div>
@error('bkash_app_key')
<p class="text-danger">{{ $errors->first('bkash_app_key') }}</p>
@enderror
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="input-box">
<h6>App Secret <span class="text-required"><i class="fa-solid fa-asterisk"></i></span></h6>
<div class="form-group">
<input type="text" class="form-control @error('bkash_app_secret') is-danger @enderror"
id="bkash_app_secret" name="bkash_app_secret"
value="{{ config('services.bkash.app_secret') }}" autocomplete="off">
</div>
@error('bkash_app_secret')
<p class="text-danger">{{ $errors->first('bkash_app_secret') }}</p>
@enderror
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="input-box">
<h6>Username <span class="text-required"><i class="fa-solid fa-asterisk"></i></span></h6>
<div class="form-group">
<input type="text" class="form-control @error('bkash_username') is-danger @enderror"
id="bkash_username" name="bkash_username"
value="{{ config('services.bkash.username') }}" autocomplete="off">
</div>
@error('bkash_username')
<p class="text-danger">{{ $errors->first('bkash_username') }}</p>
@enderror
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="input-box">
<h6>Password <span class="text-required"><i class="fa-solid fa-asterisk"></i></span></h6>
<div class="form-group">
<input type="text" class="form-control @error('bkash_password') is-danger @enderror"
id="bkash_password" name="bkash_password"
value="{{ config('services.bkash.password') }}" autocomplete="off">
</div>
@error('bkash_password')
<p class="text-danger">{{ $errors->first('bkash_password') }}</p>
@enderror
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
<div class="input-box">
<h6>Bkash Base URI <span class="text-required"><i class="fa-solid fa-asterisk"></i></span></h6>
<select id="paypal-url" name="bkash_base_uri"
data-placeholder="{{ __('Choose Payment Option') }}:">
<option value="https://tokenized.pay.bka.sh/v1.2.0-beta" @if(config('services.bkash.base_uri')=='https://tokenized.pay.bka.sh/v1.2.0-beta' ) selected @endif>Live URL
</option>
<option value="https://tokenized.sandbox.bka.sh/v1.2.0-beta" @if(config('services.bkash.base_uri')=='https://tokenized.sandbox.bka.sh/v1.2.0-beta' ) selected @endif>
Sandbox URL</option>
</select>
@error('bkash_base_uri')
<p class="text-danger">{{ $errors->first('bkash_base_uri') }}</p>
@enderror
</div>
</div>
</div>
</div>
</div>
Past Line Number 44 - 52
'bkash_enable' => 'sometimes|required',
'bkash_subscription' => 'sometimes|required',
'bkash_app_key' => 'required_if:enable-bkash,on',
'bkash_app_secret' => 'required_if:enable-bkash,on',
'bkash_username' => 'required_if:enable-bkash,on',
'bkash_password' => 'required_if:enable-bkash,on',
'bkash_base_uri' => 'required_if:enable-bkash,on',
Past Line Number 129 - 439
$this->storeConfiguration('BKASH_ENABLE', request('bkash_enable'));
$this->storeConfiguration('BKASH_SUBSCRIPTION', request('bkash_subscription'));
$this->storeConfiguration('BKASH_APP_KEY', request('bkash_app_key'));
$this->storeConfiguration('BKASH_APP_SECRET', request('bkash_app_secret'));
$this->storeConfiguration('BKASH_USERNAME', request('bkash_username'));
$this->storeConfiguration('BKASH_PASSWORD', request('bkash_password'));
$this->storeConfiguration('BKASH_BASE_URI', request('bkash_base_uri'));
Past Line Number 197 - 209
# Enable/Disable Payment Gateways
if (request('bkash_enable') == 'on') {
$bkash = PaymentPlatform::where('name', 'Bkash')->first();
$bkash->enabled = 1;
$bkash->save();
} else {
$bkash = PaymentPlatform::where('name', 'Bkash')->first();
$bkash->enabled = 0;
$bkash->save();
}
Past Line Number 296 - 309
# Enable/Disable Payment Gateways Subscription
// BKASH -Subscription Enable
if (request('bkash_subscription') == 'on') {
$bkash = PaymentPlatform::where('name', 'Bkash')->first();
$bkash->subscriptions_enabled = 1;
$bkash->save();
} else {
$bkash = PaymentPlatform::where('name', 'Bkash')->first();
$bkash->subscriptions_enabled = 0;
$bkash->save();
}
Past Line Number 627
public function approvedBkash(Request $request)
{
if (session()->has('paymentPlatformID')) {
$paymentPlatform = $this->paymentPlatformResolver->resolveService(session()->get('paymentPlatformID'));
return $paymentPlatform->handleApproval($request);
}
if (session()->has('subscriptionPlatformID')) {
$paymentPlatform = $this->paymentPlatformResolver->resolveService(session()->get('subscriptionPlatformID'));
return $paymentPlatform->handleApproval($request);
}
toastr()->error(__('There was an error while retrieving payment gateway. Please try again'));
return redirect()->back();
}
Past Line Number 208
'bkash' => [
"enable" => env("BKASH_ENABLE", true),
"subscription" => env("BKASH_SUBSCRIPTION", true),
"app_key" => env("BKASH_APP_KEY", "4f6o0cjiki2rfm34kfdadl1eqq"),
"app_secret" => env("BKASH_APP_SECRET", "2is7hdktrekvrbljjh44ll3d9l1dtjo4pasmjvs5vl5qr3fug4b"),
"username" => env("BKASH_USERNAME", "sandboxTokenizedUser02"),
"password" => env("BKASH_PASSWORD", "sandboxTokenizedUser02@12345"),
"base_uri" => env("BKASH_BASE_URI", "https://tokenized.sandbox.bka.sh/v1.2.0-beta"),
"callback" => env("BKASH_callback", ''),
'class' => App\Services\BkashService::class,
],
Create new service named #BkashService.php
<?php
namespace App\Services;
use Carbon\Carbon;
use App\Models\User;
use App\Models\Payment;
use App\Models\Setting;
use App\Models\Subscriber;
use App\Models\PrepaidPlan;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Events\PaymentProcessed;
use App\Models\SubscriptionPlan;
use Illuminate\Support\Facades\URL;
use Spatie\Backup\Listeners\Listener;
use App\Traits\ConsumesExternalServiceTrait;
class BkashService
{
use ConsumesExternalServiceTrait;
private $app_key;
private $app_secret;
private $username;
private $password;
private $base_url;
public function __construct()
{
$this->app_key = config('services.bkash.app_key');
$this->app_secret = config('services.bkash.app_secret');
$this->username = config('services.bkash.username');
$this->password = config('services.bkash.password');
$this->base_url = config('services.bkash.base_uri');
}
public function authHeaders()
{
return array(
'Content-Type:application/json',
'Authorization:' .$this->grant(),
'X-APP-Key:'. $this->app_key,
);
}
public function curlWithBody($url, $header, $method, $body_data_json)
{
$curl = curl_init($this->base_url.$url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body_data_json);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
public function grant()
{
$header = array(
'Content-Type:application/json',
'username:'.$this->username,
'password:'.$this->password,
);
$header_data_json=json_encode($header);
$body_data = array('app_key'=> $this->app_key, 'app_secret'=> $this->app_secret);
$body_data_json=json_encode($body_data);
$response = $this->curlWithBody('/tokenized/checkout/token/grant', $header, 'POST', $body_data_json);
$token = json_decode($response)->id_token;
return $token;
}
public function handlePaymentSubscription(Request $request, SubscriptionPlan $plan)
{
$duration = ($plan->payment_frequency == 'monthly') ? 30 : 365;
$orderID = strtoupper("INV-".Str::random(10));
$tax_value = (config('payment.payment_tax') > 0) ? $tax = $plan->price * config('payment.payment_tax') / 100 : 0;
$total_value = $tax_value + $plan->price;
$currency = $plan->currency;
$subscription = Subscriber::create([
'active_until' => Carbon::now()->addDays($duration),
'user_id' => auth()->user()->id,
'plan_id' => $plan->id,
'status' => 'Pending',
'created_at' => now(),
'gateway' => 'Bkash',
'frequency' => $plan->payment_frequency,
'plan_name' => $plan->plan_name,
'words' => $plan->words,
'images' => $plan->images,
'characters' => $plan->characters,
'minutes' => $plan->minutes,
'subscription_id' => $orderID,
]);
session()->put('handel_subscription', true);
session()->put('subscription', $subscription);
session()->put('amount', $total_value);
session()->put('plan_id', $plan);
return $this->createPayment($total_value, $orderID);
}
public function handlePaymentPrePaid(Request $request, $plan, $type)
{
if ($request->type == 'lifetime') {
$plan = SubscriptionPlan::where('id', $plan)->first();
$type = 'lifetime';
} else {
$plan = PrepaidPlan::where('id', $plan)->first();
$type = 'prepaid';
}
$tax_value = (config('payment.payment_tax') > 0) ? $tax = $plan->price * config('payment.payment_tax') / 100 : 0;
$total_value = $tax_value + $plan->price;
$currency = $plan->currency;
$orderID = strtoupper("INV-".Str::random(10));
session()->put('amount', $total_value);
session()->put('type', $type);
session()->put('plan_id', $plan);
return $this->createPayment($total_value, $orderID);
}
public function handleApproval(Request $request)
{
$plan = session()->get('plan_id');
$type = session()->get('type');
$order_id = '';
if(isset($request->status) && $request->status == 'failure') {
toastr()->error(__('Payment Failed, please try again'));
return redirect(route('user.dashboard'));
} elseif(isset($request->status) && $request->status == 'cancel') {
toastr()->error(__('Payment was cancell, please try again'));
return redirect(route('user.dashboard'));
} elseif(isset($request->status) && $request->status == 'success') { // if payment success
$order_id = $request->paymentID;
$response = $this->executePayment($request->paymentID);
$arr = json_decode($response, true);
if(array_key_exists("statusCode", $arr) && $arr['statusCode'] != '0000') {
toastr()->error(__($arr['statusMessage']));
return redirect(route('user.dashboard'));
} elseif (array_key_exists("message", $arr)) { // if execute api failed to response
sleep(1);
$query = $this->queryPayment($request->paymentID);
return view('user.plans.success', compact('plan', 'order_id'));
}
return view('user.plans.success', compact('plan', 'order_id'));
}
toastr()->error(__('Payment was not successful, please try again'));
return redirect(route('user.dashboard'));
}
public function createPayment($amount, $orderID = 0)
{
$header =$this->authHeaders();
$website_url = URL::to("/");
$body_data = array(
'mode' => '0011',
'payerReference' => ' ',
'callbackURL' => route('user.payments.approved.bkash'),
'amount' => $amount ? $amount : 10,
'currency' => 'BDT',
'intent' => 'sale',
// 'merchantInvoiceNumber' => "INV-".Str::random(8)// you can pass here OrderID
'merchantInvoiceNumber' => $orderID
);
$body_data_json=json_encode($body_data);
$response = $this->curlWithBody('/tokenized/checkout/create', $header, 'POST', $body_data_json);
return redirect((json_decode($response)->bkashURL));
}
public function executePayment($paymentID)
{
$header =$this->authHeaders();
$body_data = array(
'paymentID' => $paymentID
);
$body_data_json=json_encode($body_data);
$response = $this->curlWithBody('/tokenized/checkout/execute', $header, 'POST', $body_data_json);
$res_array = json_decode($response, true);
if(isset($res_array['trxID'])) {
// your database insert operation
$this->dboperation($paymentID);
}
return $response;
}
public function queryPayment($paymentID)
{
$header =$this->authHeaders();
$body_data = array(
'paymentID' => $paymentID,
);
$body_data_json=json_encode($body_data);
$response = $this->curlWithBody('/tokenized/checkout/payment/status', $header, 'POST', $body_data_json);
$res_array = json_decode($response, true);
if(isset($res_array['trxID'])) {
// your database insert operation
$this->dboperation($paymentID);
}
return $response;
}
public function dboperation($paymentID)
{
$plan = session()->get('plan_id');
$type = session()->get('type');
$amount = session()->get('amount');
$subscription = session()->has('subscription')?session()->get('subscription'):null;
$user = User::where('id', auth()->user()->id)->first();
if ($type == 'lifetime') {
$days = 18250;
$subscription = Subscriber::create([
'user_id' => auth()->user()->id,
'plan_id' => $plan->id,
'status' => 'Active',
'created_at' => now(),
'gateway' => 'Bkash',
'frequency' => 'lifetime',
'plan_name' => $plan->plan_name,
'words' => $plan->words,
'images' => $plan->images,
'characters' => $plan->characters,
'minutes' => $plan->minutes,
'subscription_id' => $paymentID,
'active_until' => Carbon::now()->addDays($days),
]);
}
if (session()->has('handel_subscription') && session()->get('handel_subscription') == true && $subscription != null) {
$subscription->update([
'status' => 'Active',
'subscription_id' => $paymentID,
]);
}
$record_payment = new Payment();
$record_payment->user_id = auth()->user()->id;
$record_payment->order_id = $paymentID;
$record_payment->plan_id = $plan->id;
$record_payment->plan_name = $plan->plan_name;
$record_payment->price = $amount;
$record_payment->currency = $plan->currency;
$record_payment->gateway = 'Bkash';
$record_payment->frequency = $type;
$record_payment->status = 'completed';
$record_payment->words = $plan->words;
$record_payment->images = $plan->images;
$record_payment->characters = $plan->characters;
$record_payment->minutes = $plan->minutes;
$record_payment->save();
$user = User::where('id', auth()->user()->id)->first();
if ($type == 'lifetime') {
$group = (auth()->user()->hasRole('admin'))? 'admin' : 'subscriber';
$user->syncRoles($group);
$user->group = $group;
$user->plan_id = $plan->id;
$user->total_words = $plan->words;
$user->total_images = $plan->images;
$user->total_chars = $plan->characters;
$user->total_minutes = $plan->minutes;
$user->available_words = $plan->words;
$user->available_images = $plan->images;
$user->available_chars = $plan->characters;
$user->available_minutes = $plan->minutes;
} else {
$user->available_words_prepaid = $user->available_words_prepaid + $plan->words;
$user->available_images_prepaid = $user->available_images_prepaid + $plan->images;
$user->available_chars_prepaid = $user->available_chars_prepaid + $plan->characters;
$user->available_minutes_prepaid = $user->available_minutes_prepaid + $plan->minutes;
}
$user->save();
event(new PaymentProcessed(auth()->user()));
}
}
INSERT INTO `payment_platforms` (`id`, `name`, `image`, `enabled`, `subscriptions_enabled`, `created_at`, `updated_at`) VALUES (NULL, 'Bkash', 'img/payments/bkash.png', '1', '1', NULL, NULL);
Past Line Number 142
# BKASH
BKASH_ENABLE=
BKASH_SUBSCRIPTION=
BKASH_APP_KEY=
BKASH_APP_SECRET=
BKASH_USERNAME=
BKASH_PASSWORD=
BKASH_BASE_URI=