[FEATURE] Extension Support & Payment Gateways as Extensions 🔥

[FEATURE] Extension Support & Payment Gateways as Extensions 🔥
This commit is contained in:
Dennis 2023-01-19 11:29:27 +01:00 committed by GitHub
commit 7a91013bd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 1140 additions and 854 deletions

View file

@ -0,0 +1,31 @@
<?php
namespace App\Events;
use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class PaymentEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public User $user;
public Payment $payment;
public ShopProduct $shopProduct;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct(User $user, Payment $payment, ShopProduct $shopProduct)
{
$this->user = $user;
$this->payment = $payment;
$this->shopProduct = $shopProduct;
}
}

View file

@ -0,0 +1,216 @@
<?php
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\Product;
use App\Models\ShopProduct;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redirect;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalHttp\HttpException;
/**
* @param Request $request
* @param ShopProduct $shopProduct
*/
function PaypalPay(Request $request)
{
/** @var User $user */
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
// create a new payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'paypal',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * PartnerDiscount::getDiscount() / 100),
'tax_value' => $shopProduct->getTaxValue(),
'tax_percent' => $shopProduct->getTaxPercent(),
'total_price' => $shopProduct->getTotalPrice(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = [
"intent" => "CAPTURE",
"purchase_units" => [
[
"reference_id" => uniqid(),
"description" => $shopProduct->display . (PartnerDiscount::getDiscount() ? (" (" . __('Discount') . " " . PartnerDiscount::getDiscount() . '%)') : ""),
"amount" => [
"value" => $shopProduct->getTotalPrice(),
'currency_code' => strtoupper($shopProduct->currency_code),
'breakdown' => [
'item_total' =>
[
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getPriceAfterDiscount(),
],
'tax_total' =>
[
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getTaxValue(),
]
]
]
]
],
"application_context" => [
"cancel_url" => route('payment.Cancel'),
"return_url" => route('payment.PayPalSuccess', ['payment' => $payment->id]),
'brand_name' => config('app.name', 'Laravel'),
'shipping_preference' => 'NO_SHIPPING'
]
];
try {
// Call API with your client and get a response for your call
$response = getPayPalClient()->execute($request);
Redirect::away($response->result->links[1]->href)->send();
return;
} catch (HttpException $ex) {
error_log($ex->statusCode);
error_log($ex->getMessage());
$payment->delete();
Redirect::route('payment.Cancel');
return;
}
}
/**
* @param Request $laravelRequest
*/
function PaypalSuccess(Request $laravelRequest)
{
$user = Auth::user();
$user = User::findOrFail($user->id);
$payment = Payment::findOrFail($laravelRequest->payment);
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
$request = new OrdersCaptureRequest($laravelRequest->input('token'));
$request->prefer('return=representation');
try {
// Call API with your client and get a response for your call
$response = getPayPalClient()->execute($request);
if ($response->statusCode == 201 || $response->statusCode == 200) {
//update payment
$payment->update([
'status' => 'paid',
'payment_id' => $response->result->id,
]);
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
// redirect to the payment success page with success message
Redirect::route('home')->with('success', 'Payment successful')->send();
} elseif (env('APP_ENV') == 'local') {
// If call returns body in response, you can get the deserialized version from the result attribute of the response
$payment->delete();
dd($response);
} else {
$payment->update([
'status' => 'cancelled',
'payment_id' => $response->result->id,
]);
abort(500);
}
} catch (HttpException $ex) {
if (env('APP_ENV') == 'local') {
echo $ex->statusCode;
$payment->delete();
dd($ex->getMessage());
} else {
$payment->update([
'status' => 'cancelled',
'payment_id' => $response->result->id,
]);
abort(422);
}
}
}
/**
* @return PayPalHttpClient
*/
function getPayPalClient()
{
$environment = env('APP_ENV') == 'local'
? new SandboxEnvironment(getPaypalClientId(), getPaypalClientSecret())
: new ProductionEnvironment(getPaypalClientId(), getPaypalClientSecret());
return new PayPalHttpClient($environment);
}
/**
* @return string
*/
function getPaypalClientId()
{
return env('APP_ENV') == 'local' ? config("SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID") : config("SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID");
}
/**
* @return string
*/
function getPaypalClientSecret()
{
return env('APP_ENV') == 'local' ? config("SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET") : config("SETTINGS::PAYMENTS:PAYPAL:SECRET");
}
function getPayPalConfig()
{
return [
"name" => "PayPal",
"description" => "PayPal payment gateway",
"settings" => [
"mode" => [
"type" => "select",
"label" => "Mode",
"value" => config("APP_ENV") == 'local' ? "sandbox" : "live",
"options" => [
"sandbox" => "Sandbox",
"live" => "Live",
],
],
"CLIENT_ID" => [
"type" => "text",
"label" => "PayPal Client ID",
"value" => config("SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID"),
],
"SECRET" => [
"type" => "text",
"label" => "PayPal Secret",
"value" => config("SETTINGS::PAYMENTS:PAYPAL:SECRET"),
],
"SANDBOX_CLIENT_ID" => [
"type" => "text",
"label" => "PayPal Sandbox Client ID",
"value" => config("SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID"),
],
"SANDBOX_SECRET" => [
"type" => "text",
"label" => "PayPal Sandbox Secret",
"value" => config("SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET"),
],
],
];
}

View file

@ -0,0 +1,18 @@
<?php
use Illuminate\Support\Facades\Route;
include_once(__DIR__ . '/index.php');
Route::middleware(['web', 'auth'])->group(function () {
Route::get('payment/PayPalPay/{shopProduct}', function () {
PaypalPay(request());
})->name('payment.PayPalPay');
Route::get(
'payment/PayPalSuccess',
function () {
PaypalSuccess(request());
}
)->name('payment.PayPalSuccess');
});

View file

@ -0,0 +1,402 @@
<?php
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent;
use App\Models\PartnerDiscount;
use App\Models\Payment;
use App\Models\Product;
use App\Models\ShopProduct;
use App\Models\User;
use App\Notifications\ConfirmPaymentNotification;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redirect;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Stripe;
use Stripe\StripeClient;
/**
* @param Request $request
* @param ShopProduct $shopProduct
*/
function StripePay(Request $request)
{
$user = Auth::user();
$shopProduct = ShopProduct::findOrFail($request->shopProduct);
// check if the price is valid for stripe
if (!checkPriceAmount($shopProduct->getTotalPrice(), strtoupper($shopProduct->currency_code), 'stripe')) {
Redirect::route('home')->with('error', __('The product you chose can\'t be purchased with this payment method. The total amount is too small. Please buy a bigger amount or try a different payment method.'))->send();
return;
}
// create payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => null,
'payment_method' => 'stripe',
'type' => $shopProduct->type,
'status' => 'open',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * PartnerDiscount::getDiscount() / 100),
'tax_value' => $shopProduct->getTaxValue(),
'total_price' => $shopProduct->getTotalPrice(),
'tax_percent' => $shopProduct->getTaxPercent(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
$stripeClient = getStripeClient();
$request = $stripeClient->checkout->sessions->create([
'line_items' => [
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => $shopProduct->display . (PartnerDiscount::getDiscount() ? (' (' . __('Discount') . ' ' . PartnerDiscount::getDiscount() . '%)') : ''),
'description' => $shopProduct->description,
],
'unit_amount_decimal' => round($shopProduct->getPriceAfterDiscount() * 100, 2),
],
'quantity' => 1,
],
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => __('Tax'),
'description' => $shopProduct->getTaxPercent() . '%',
],
'unit_amount_decimal' => round($shopProduct->getTaxValue(), 2) * 100,
],
'quantity' => 1,
],
],
'mode' => 'payment',
'payment_method_types' => str_getcsv(config('SETTINGS::PAYMENTS:STRIPE:METHODS')),
'success_url' => route('payment.StripeSuccess', ['payment' => $payment->id]) . '&session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('payment.Cancel'),
]);
Redirect::to($request->url)->send();
}
/**
* @param Request $request
*/
function StripeSuccess(Request $request)
{
$user = Auth::user();
$user = User::findOrFail($user->id);
$payment = Payment::findOrFail($request->input('payment'));
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
$stripeClient = getStripeClient();
try {
//get stripe data
$paymentSession = $stripeClient->checkout->sessions->retrieve($request->input('session_id'));
$paymentIntent = $stripeClient->paymentIntents->retrieve($paymentSession->payment_intent);
//get DB entry of this payment ID if existing
$paymentDbEntry = Payment::where('payment_id', $paymentSession->payment_intent)->count();
// check if payment is 100% completed and payment does not exist in db already
if ($paymentSession->status == 'complete' && $paymentIntent->status == 'succeeded' && $paymentDbEntry == 0) {
//update payment
$payment->update([
'payment_id' => $paymentSession->payment_intent,
'status' => 'paid',
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
//redirect back to home
Redirect::route('home')->with('success', 'Payment successful')->send();
} else {
if ($paymentIntent->status == 'processing') {
//update payment
$payment->update([
'payment_id' => $paymentSession->payment_intent,
'status' => 'processing',
]);
event(new PaymentEvent($user, $payment, $shopProduct));
Redirect::route('home')->with('success', 'Your payment is being processed')->send();
}
if ($paymentDbEntry == 0 && $paymentIntent->status != 'processing') {
$stripeClient->paymentIntents->cancel($paymentIntent->id);
//redirect back to home
Redirect::route('home')->with('info', __('Your payment has been canceled!'))->send();
} else {
abort(402);
}
}
} catch (Exception $e) {
if (env('APP_ENV') == 'local') {
dd($e->getMessage());
} else {
abort(422);
}
}
}
/**
* @param Request $request
*/
function handleStripePaymentSuccessHook($paymentIntent)
{
try {
// Get payment db entry
$payment = Payment::where('payment_id', $paymentIntent->id)->first();
$user = User::where('id', $payment->user_id)->first();
$shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
if ($paymentIntent->status == 'succeeded' && $payment->status == 'processing') {
//update payment db entry status
$payment->update(['status' => 'paid']);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
event(new PaymentEvent($user, $payment, $shopProduct));
}
// return 200
return response()->json(['success' => true], 200);
} catch (Exception $ex) {
abort(422);
}
}
/**
* @param Request $request
*/
function StripeWebhooks(Request $request)
{
Stripe::setApiKey(getStripeSecret());
try {
$payload = @file_get_contents('php://input');
$sig_header = $request->header('Stripe-Signature');
$event = null;
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
getStripeEndpointSecret()
);
} catch (\UnexpectedValueException $e) {
// Invalid payload
abort(400);
} catch (SignatureVerificationException $e) {
// Invalid signature
abort(400);
}
// Handle the event
switch ($event->type) {
case 'payment_intent.succeeded':
$paymentIntent = $event->data->object; // contains a \Stripe\PaymentIntent
handleStripePaymentSuccessHook($paymentIntent);
break;
default:
echo 'Received unknown event type ' . $event->type;
}
}
/**
* @return \Stripe\StripeClient
*/
function getStripeClient()
{
return new StripeClient(getStripeSecret());
}
/**
* @return string
*/
function getStripeSecret()
{
return env('APP_ENV') == 'local'
? config('SETTINGS::PAYMENTS:STRIPE:TEST_SECRET')
: config('SETTINGS::PAYMENTS:STRIPE:SECRET');
}
/**
* @return string
*/
function getStripeEndpointSecret()
{
return env('APP_ENV') == 'local'
? config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET')
: config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET');
}
/**
* @param $amount
* @param $currencyCode
* @param $payment_method
* @return bool
* @description check if the amount is higher than the minimum amount for the stripe gateway
*/
function checkPriceAmount($amount, $currencyCode, $payment_method)
{
$minimums = [
"USD" => [
"paypal" => 0,
"stripe" => 0.5
],
"AED" => [
"paypal" => 0,
"stripe" => 2
],
"AUD" => [
"paypal" => 0,
"stripe" => 0.5
],
"BGN" => [
"paypal" => 0,
"stripe" => 1
],
"BRL" => [
"paypal" => 0,
"stripe" => 0.5
],
"CAD" => [
"paypal" => 0,
"stripe" => 0.5
],
"CHF" => [
"paypal" => 0,
"stripe" => 0.5
],
"CZK" => [
"paypal" => 0,
"stripe" => 15
],
"DKK" => [
"paypal" => 0,
"stripe" => 2.5
],
"EUR" => [
"paypal" => 0,
"stripe" => 0.5
],
"GBP" => [
"paypal" => 0,
"stripe" => 0.3
],
"HKD" => [
"paypal" => 0,
"stripe" => 4
],
"HRK" => [
"paypal" => 0,
"stripe" => 0.5
],
"HUF" => [
"paypal" => 0,
"stripe" => 175
],
"INR" => [
"paypal" => 0,
"stripe" => 0.5
],
"JPY" => [
"paypal" => 0,
"stripe" => 0.5
],
"MXN" => [
"paypal" => 0,
"stripe" => 10
],
"MYR" => [
"paypal" => 0,
"stripe" => 2
],
"NOK" => [
"paypal" => 0,
"stripe" => 3
],
"NZD" => [
"paypal" => 0,
"stripe" => 0.5
],
"PLN" => [
"paypal" => 0,
"stripe" => 2
],
"RON" => [
"paypal" => 0,
"stripe" => 2
],
"SEK" => [
"paypal" => 0,
"stripe" => 3
],
"SGD" => [
"paypal" => 0,
"stripe" => 0.5
],
"THB" => [
"paypal" => 0,
"stripe" => 10
]
];
return $amount >= $minimums[$currencyCode][$payment_method];
}
function getStripeConfig()
{
return [
"name" => "Stripe",
"description" => "Stripe payment gateway",
"mode" => [
"type" => "select",
"label" => "Mode",
"value" => config("APP_ENV") == 'local' ? "sandbox" : "live",
"options" => [
"sandbox" => "Sandbox",
"live" => "Live",
],
],
"TEST_SECRET" => [
"type" => "text",
"label" => "Test Secret Key",
"value" => config("SETTINGS::PAYMENTS:STRIPE:TEST_SECRET"),
],
"SECRET" => [
"type" => "text",
"label" => "Live Secret Key",
"value" => config("SETTINGS::PAYMENTS:STRIPE:SECRET"),
],
"ENDPOINT_TEST_SECRET" => [
"type" => "text",
"label" => "Test Endpoint Secret",
"value" => config("SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET"),
],
"ENDPOINT_SECRET" => [
"type" => "text",
"label" => "Live Endpoint Secret",
"value" => config("SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET"),
],
];
}

View file

@ -0,0 +1,23 @@
<?php
use Illuminate\Support\Facades\Route;
include_once(__DIR__ . '/index.php');
Route::middleware(['web', 'auth'])->group(function () {
Route::get('payment/StripePay/{shopProduct}', function () {
StripePay(request());
})->name('payment.StripePay');
Route::get(
'payment/StripeSuccess',
function () {
StripeSuccess(request());
}
)->name('payment.StripeSuccess');
});
// Stripe WebhookRoute -> validation in Route Handler
Route::post('payment/StripeWebhooks', function () {
StripeWebhooks(request());
})->name('payment.StripeWebhooks');

View file

@ -0,0 +1,47 @@
<?php
namespace App\Helpers;
class ExtensionHelper
{
public static function getExtensionConfig($extensionName, $nameSpace)
{
$extension = app_path() . '/Extensions/' . $nameSpace . "/" . $extensionName . "/index.php";
// Check if extension exists
if (!file_exists($extension)) {
return null;
}
// call the getConfig function from the index.php file of the extension
$config = include_once $extension;
// Check if the getConfig function exists
if (!function_exists('get' . $extensionName . 'Config')) {
return null;
}
$config = call_user_func('get' . $extensionName . 'Config');
// Check if the getConfig function returned an array
if (!is_array($config)) {
return null;
}
return $config;
}
public static function getPayMethod($extensionName, $nameSpace)
{
// return the payment method of the extension to be used elsewhere
// for example in the payment controller
// the function starts with the name of the extension and ends with Pay
$config = self::getExtensionConfig($extensionName, $nameSpace);
if ($config == null) {
return null;
}
return $config['payMethod'];
}
}

View file

@ -6,10 +6,8 @@ use App\Events\UserUpdateCreditsEvent;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\PartnerDiscount; use App\Models\PartnerDiscount;
use App\Models\Payment; use App\Models\Payment;
use App\Models\ShopProduct;
use App\Models\User; use App\Models\User;
use App\Notifications\ConfirmPaymentNotification; use App\Models\ShopProduct;
use App\Notifications\InvoiceNotification;
use Exception; use Exception;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
@ -18,19 +16,8 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB; use App\Helpers\ExtensionHelper;
use Illuminate\Support\Facades\Storage;
use LaravelDaily\Invoices\Classes\Buyer;
use LaravelDaily\Invoices\Classes\InvoiceItem;
use LaravelDaily\Invoices\Classes\Party;
use LaravelDaily\Invoices\Invoice;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalHttp\HttpException;
use Symfony\Component\Intl\Currencies;
class PaymentController extends Controller class PaymentController extends Controller
{ {
@ -49,8 +36,24 @@ class PaymentController extends Controller
* @param ShopProduct $shopProduct * @param ShopProduct $shopProduct
* @return Application|Factory|View * @return Application|Factory|View
*/ */
public function checkOut(Request $request, ShopProduct $shopProduct) public function checkOut(ShopProduct $shopProduct)
{ {
// get all payment gateway extensions
$extensions = glob(app_path() . '/Extensions/PaymentGateways/*', GLOB_ONLYDIR);
// build a paymentgateways array that contains the routes for the payment gateways and the image path for the payment gateway which lays in public/images/Extensions/PaymentGateways with the extensionname in lowercase
$paymentGateways = [];
foreach ($extensions as $extension) {
$extensionName = basename($extension);
$config = ExtensionHelper::getExtensionConfig($extensionName, 'PaymentGateways');
if ($config) {
$payment = new \stdClass();
$payment->name = $config['name'];
$payment->image = asset('images/Extensions/PaymentGateways/' . strtolower($extensionName) . '_logo.png');
$paymentGateways[] = $payment;
}
}
return view('store.checkout')->with([ return view('store.checkout')->with([
'product' => $shopProduct, 'product' => $shopProduct,
'discountpercent' => PartnerDiscount::getDiscount(), 'discountpercent' => PartnerDiscount::getDiscount(),
@ -59,6 +62,7 @@ class PaymentController extends Controller
'taxvalue' => $shopProduct->getTaxValue(), 'taxvalue' => $shopProduct->getTaxValue(),
'taxpercent' => $shopProduct->getTaxPercent(), 'taxpercent' => $shopProduct->getTaxPercent(),
'total' => $shopProduct->getTotalPrice(), 'total' => $shopProduct->getTotalPrice(),
'paymentGateways' => $paymentGateways,
]); ]);
} }
@ -67,11 +71,10 @@ class PaymentController extends Controller
* @param ShopProduct $shopProduct * @param ShopProduct $shopProduct
* @return RedirectResponse * @return RedirectResponse
*/ */
public function FreePay(Request $request, ShopProduct $shopProduct) public function FreePay(ShopProduct $shopProduct)
{ {
//dd($shopProduct);
//check if the product is really free or the discount is 100% //check if the product is really free or the discount is 100%
if($shopProduct->getTotalPrice()>0) return redirect()->route('home')->with('error', __('An error ocured. Please try again.')); if ($shopProduct->getTotalPrice() > 0) return redirect()->route('home')->with('error', __('An error ocured. Please try again.'));
//give product //give product
/** @var User $user */ /** @var User $user */
@ -80,9 +83,9 @@ class PaymentController extends Controller
//not updating server limit //not updating server limit
//update User with bought item //update User with bought item
if ($shopProduct->type=="Credits") { if ($shopProduct->type == "Credits") {
$user->increment('credits', $shopProduct->quantity); $user->increment('credits', $shopProduct->quantity);
}elseif ($shopProduct->type=="Server slots"){ } elseif ($shopProduct->type == "Server slots") {
$user->increment('server_limit', $shopProduct->quantity); $user->increment('server_limit', $shopProduct->quantity);
} }
@ -98,7 +101,7 @@ class PaymentController extends Controller
'type' => $shopProduct->type, 'type' => $shopProduct->type,
'status' => 'paid', 'status' => 'paid',
'amount' => $shopProduct->quantity, 'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price*PartnerDiscount::getDiscount()/100), 'price' => $shopProduct->price - ($shopProduct->price * PartnerDiscount::getDiscount() / 100),
'tax_value' => $shopProduct->getTaxValue(), 'tax_value' => $shopProduct->getTaxValue(),
'tax_percent' => $shopProduct->getTaxPercent(), 'tax_percent' => $shopProduct->getTaxPercent(),
'total_price' => $shopProduct->getTotalPrice(), 'total_price' => $shopProduct->getTotalPrice(),
@ -114,196 +117,12 @@ class PaymentController extends Controller
return redirect()->route('home')->with('success', __('Your credit balance has been increased!')); return redirect()->route('home')->with('success', __('Your credit balance has been increased!'));
} }
/** public function pay(Request $request)
* @param Request $request
* @param ShopProduct $shopProduct
* @return RedirectResponse
*/
public function PaypalPay(Request $request, ShopProduct $shopProduct)
{ {
if(!$this->checkAmount($shopProduct->getTotalPrice(), strtoupper($shopProduct->currency_code), "paypal")) return redirect()->route('home')->with('error', __('The product you chose can´t be purchased with this payment method. The total amount is too small. Please buy a bigger amount or try a different payment method.')); $product = ShopProduct::find($request->product_id);
$request = new OrdersCreateRequest(); $paymentGateway = $request->payment_method;
$request->prefer('return=representation');
$request->body = [
'intent' => 'CAPTURE',
'purchase_units' => [
[
'reference_id' => uniqid(),
'description' => $shopProduct->display.(PartnerDiscount::getDiscount() ? (' ('.__('Discount').' '.PartnerDiscount::getDiscount().'%)') : ''),
'amount' => [
'value' => $shopProduct->getTotalPrice(),
'currency_code' => strtoupper($shopProduct->currency_code),
'breakdown' => [
'item_total' => [
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getPriceAfterDiscount(),
],
'tax_total' => [
'currency_code' => strtoupper($shopProduct->currency_code),
'value' => $shopProduct->getTaxValue(),
],
],
],
],
],
'application_context' => [
'cancel_url' => route('payment.Cancel'),
'return_url' => route('payment.PaypalSuccess', ['product' => $shopProduct->id]),
'brand_name' => config('app.name', 'Laravel'),
'shipping_preference' => 'NO_SHIPPING',
],
]; return redirect()->route('payment.' . $paymentGateway . 'Pay', ['shopProduct' => $product->id]);
try {
// Call API with your client and get a response for your call
$response = $this->getPayPalClient()->execute($request);
return redirect()->away($response->result->links[1]->href);
// If call returns body in response, you can get the deserialized version from the result attribute of the response
} catch (HttpException $ex) {
echo $ex->statusCode;
dd(json_decode($ex->getMessage()));
}
}
/**
* @return PayPalHttpClient
*/
protected function getPayPalClient()
{
$environment = env('APP_ENV') == 'local'
? new SandboxEnvironment($this->getPaypalClientId(), $this->getPaypalClientSecret())
: new ProductionEnvironment($this->getPaypalClientId(), $this->getPaypalClientSecret());
return new PayPalHttpClient($environment);
}
/**
* @return string
*/
protected function getPaypalClientId()
{
return env('APP_ENV') == 'local' ? config('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_CLIENT_ID') : config('SETTINGS::PAYMENTS:PAYPAL:CLIENT_ID');
}
/**
* @return string
*/
protected function getPaypalClientSecret()
{
return env('APP_ENV') == 'local' ? config('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET') : config('SETTINGS::PAYMENTS:PAYPAL:SECRET');
}
/**
* @param Request $laravelRequest
*/
public function PaypalSuccess(Request $laravelRequest)
{
/** @var ShopProduct $shopProduct */
$shopProduct = ShopProduct::findOrFail($laravelRequest->input('product'));
/** @var User $user */
$user = Auth::user();
$request = new OrdersCaptureRequest($laravelRequest->input('token'));
$request->prefer('return=representation');
try {
// Call API with your client and get a response for your call
$response = $this->getPayPalClient()->execute($request);
if ($response->statusCode == 201 || $response->statusCode == 200) {
//update server limit
if (config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
if ($user->server_limit < config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
}
}
//update User with bought item
if ($shopProduct->type == 'Credits') {
$user->increment('credits', $shopProduct->quantity);
} elseif ($shopProduct->type == 'Server slots') {
$user->increment('server_limit', $shopProduct->quantity);
}
//give referral commission always
if ((config('SETTINGS::REFERRAL:MODE') == 'commission' || config('SETTINGS::REFERRAL:MODE') == 'both') && $shopProduct->type == 'Credits' && config('SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION') == 'true') {
if ($ref_user = DB::table('user_referrals')->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, '', '');
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained '.$increment.' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').' for commission-referral of '.$user->name.' (ID:'.$user->id.')');
}
}
//update role give Referral-reward
if ($user->role == 'member') {
$user->update(['role' => 'client']);
//give referral commission only on first purchase
if ((config('SETTINGS::REFERRAL:MODE') == 'commission' || config('SETTINGS::REFERRAL:MODE') == 'both') && $shopProduct->type == 'Credits' && config('SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION') == 'false') {
if ($ref_user = DB::table('user_referrals')->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, '', '');
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained '.$increment.' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').' for commission-referral of '.$user->name.' (ID:'.$user->id.')');
}
}
}
//store payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => $response->result->id,
'payment_method' => 'paypal',
'type' => $shopProduct->type,
'status' => 'paid',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * PartnerDiscount::getDiscount() / 100),
'tax_value' => $shopProduct->getTaxValue(),
'tax_percent' => $shopProduct->getTaxPercent(),
'total_price' => $shopProduct->getTotalPrice(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
event(new UserUpdateCreditsEvent($user));
//only create invoice if SETTINGS::INVOICE:ENABLED is true
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
$this->createInvoice($user, $payment, 'paid', $shopProduct->currency_code);
}
//redirect back to home
return redirect()->route('home')->with('success', __('Your credit balance has been increased!'));
}
// If call returns body in response, you can get the deserialized version from the result attribute of the response
if (env('APP_ENV') == 'local') {
dd($response);
} else {
abort(500);
}
} catch (HttpException $ex) {
if (env('APP_ENV') == 'local') {
echo $ex->statusCode;
dd($ex->getMessage());
} else {
abort(422);
}
}
} }
/** /**
@ -311,491 +130,9 @@ class PaymentController extends Controller
*/ */
public function Cancel(Request $request) public function Cancel(Request $request)
{ {
return redirect()->route('store.index')->with('success', 'Payment was Canceled'); return redirect()->route('store.index')->with('info', 'Payment was Canceled');
} }
/**
* @param Request $request
* @param ShopProduct $shopProduct
* @return RedirectResponse
*/
public function StripePay(Request $request, ShopProduct $shopProduct)
{
if(!$this->checkAmount($shopProduct->getTotalPrice(), strtoupper($shopProduct->currency_code), "stripe")) return redirect()->route('home')->with('error', __('The product you chose can´t be purchased with this payment method. The total amount is too small. Please buy a bigger amount or try a different payment method.'));
$stripeClient = $this->getStripeClient();
$request = $stripeClient->checkout->sessions->create([
'line_items' => [
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => $shopProduct->display.(PartnerDiscount::getDiscount() ? (' ('.__('Discount').' '.PartnerDiscount::getDiscount().'%)') : ''),
'description' => $shopProduct->description,
],
'unit_amount_decimal' => round($shopProduct->getPriceAfterDiscount() * 100, 2),
],
'quantity' => 1,
],
[
'price_data' => [
'currency' => $shopProduct->currency_code,
'product_data' => [
'name' => __('Tax'),
'description' => $shopProduct->getTaxPercent().'%',
],
'unit_amount_decimal' => round($shopProduct->getTaxValue(), 2) * 100,
],
'quantity' => 1,
],
],
'mode' => 'payment',
'payment_method_types' => str_getcsv(config('SETTINGS::PAYMENTS:STRIPE:METHODS')),
'success_url' => route('payment.StripeSuccess', ['product' => $shopProduct->id]).'&session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('payment.Cancel'),
]);
return redirect($request->url, 303);
}
/**
* @param Request $request
*/
public function StripeSuccess(Request $request)
{
/** @var ShopProduct $shopProduct */
$shopProduct = ShopProduct::findOrFail($request->input('product'));
/** @var User $user */
$user = Auth::user();
$stripeClient = $this->getStripeClient();
try {
//get stripe data
$paymentSession = $stripeClient->checkout->sessions->retrieve($request->input('session_id'));
$paymentIntent = $stripeClient->paymentIntents->retrieve($paymentSession->payment_intent);
//get DB entry of this payment ID if existing
$paymentDbEntry = Payment::where('payment_id', $paymentSession->payment_intent)->count();
// check if payment is 100% completed and payment does not exist in db already
if ($paymentSession->status == 'complete' && $paymentIntent->status == 'succeeded' && $paymentDbEntry == 0) {
//update server limit
if (config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
if ($user->server_limit < config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
}
}
//update User with bought item
if ($shopProduct->type == 'Credits') {
$user->increment('credits', $shopProduct->quantity);
} elseif ($shopProduct->type == 'Server slots') {
$user->increment('server_limit', $shopProduct->quantity);
}
//update role give Referral-reward
if ($user->role == 'member') {
$user->update(['role' => 'client']);
if ((config('SETTINGS::REFERRAL:MODE') == 'commission' || config('SETTINGS::REFERRAL:MODE') == 'both') && $shopProduct->type == 'Credits') {
if ($ref_user = DB::table('user_referrals')->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity / 100 * config('SETTINGS::REFERRAL:PERCENTAGE'), 0, '', '');
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained '.$increment.' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').' for commission-referral of '.$user->name.' (ID:'.$user->id.')');
}
}
}
//store paid payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => $paymentSession->payment_intent,
'payment_method' => 'stripe',
'type' => $shopProduct->type,
'status' => 'paid',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price - ($shopProduct->price * PartnerDiscount::getDiscount() / 100),
'tax_value' => $shopProduct->getTaxValue(),
'total_price' => $shopProduct->getTotalPrice(),
'tax_percent' => $shopProduct->getTaxPercent(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
//only create invoice if SETTINGS::INVOICE:ENABLED is true
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
$this->createInvoice($user, $payment, 'paid', $shopProduct->currency_code);
}
//redirect back to home
return redirect()->route('home')->with('success', __('Your credit balance has been increased!'));
} else {
if ($paymentIntent->status == 'processing') {
//store processing payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => $paymentSession->payment_intent,
'payment_method' => 'stripe',
'type' => $shopProduct->type,
'status' => 'processing',
'amount' => $shopProduct->quantity,
'price' => $shopProduct->price,
'tax_value' => $shopProduct->getTaxValue(),
'total_price' => $shopProduct->getTotalPrice(),
'tax_percent' => $shopProduct->getTaxPercent(),
'currency_code' => $shopProduct->currency_code,
'shop_item_product_id' => $shopProduct->id,
]);
//only create invoice if SETTINGS::INVOICE:ENABLED is true
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
$this->createInvoice($user, $payment, 'paid', $shopProduct->currency_code);
}
//redirect back to home
return redirect()->route('home')->with('success', __('Your payment is being processed!'));
}
if ($paymentDbEntry == 0 && $paymentIntent->status != 'processing') {
$stripeClient->paymentIntents->cancel($paymentIntent->id);
//redirect back to home
return redirect()->route('home')->with('success', __('Your payment has been canceled!'));
} else {
abort(402);
}
}
} catch (HttpException $ex) {
if (env('APP_ENV') == 'local') {
echo $ex->statusCode;
dd($ex->getMessage());
} else {
abort(422);
}
}
}
/**
* @param Request $request
*/
protected function handleStripePaymentSuccessHook($paymentIntent)
{
try {
// Get payment db entry
$payment = Payment::where('payment_id', $paymentIntent->id)->first();
$user = User::where('id', $payment->user_id)->first();
if ($paymentIntent->status == 'succeeded' && $payment->status == 'processing') {
//update server limit
if (config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
if ($user->server_limit < config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
}
}
//update User with bought item
if ($shopProduct->type == 'Credits') {
$user->increment('credits', $shopProduct->quantity);
} elseif ($shopProduct->type == 'Server slots') {
$user->increment('server_limit', $shopProduct->quantity);
}
//update role give Referral-reward
if ($user->role == 'member') {
$user->update(['role' => 'client']);
if ((config('SETTINGS::REFERRAL:MODE') == 'commission' || config('SETTINGS::REFERRAL:MODE') == 'both') && $shopProduct->type == 'Credits') {
if ($ref_user = DB::table('user_referrals')->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity / 100 * config('SETTINGS::REFERRAL:PERCENTAGE'), 0, '', '');
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained '.$increment.' '.config('SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME').' for commission-referral of '.$user->name.' (ID:'.$user->id.')');
}
}
}
//update payment db entry status
$payment->update(['status' => 'paid']);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
//only create invoice if SETTINGS::INVOICE:ENABLED is true
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
$this->createInvoice($user, $payment, 'paid', strtoupper($paymentIntent->currency));
}
}
} catch (HttpException $ex) {
abort(422);
}
}
/**
* @param Request $request
*/
public function StripeWebhooks(Request $request)
{
\Stripe\Stripe::setApiKey($this->getStripeSecret());
try {
$payload = @file_get_contents('php://input');
$sig_header = $request->header('Stripe-Signature');
$event = null;
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
$this->getStripeEndpointSecret()
);
} catch (\UnexpectedValueException $e) {
// Invalid payload
abort(400);
} catch (\Stripe\Exception\SignatureVerificationException $e) {
// Invalid signature
abort(400);
}
// Handle the event
switch ($event->type) {
case 'payment_intent.succeeded':
$paymentIntent = $event->data->object; // contains a \Stripe\PaymentIntent
$this->handleStripePaymentSuccessHook($paymentIntent);
break;
default:
echo 'Received unknown event type '.$event->type;
}
}
/**
* @return \Stripe\StripeClient
*/
protected function getStripeClient()
{
return new \Stripe\StripeClient($this->getStripeSecret());
}
/**
* @return string
*/
protected function getStripeSecret()
{
return env('APP_ENV') == 'local'
? config('SETTINGS::PAYMENTS:STRIPE:TEST_SECRET')
: config('SETTINGS::PAYMENTS:STRIPE:SECRET');
}
/**
* @return string
*/
protected function getStripeEndpointSecret()
{
return env('APP_ENV') == 'local'
? config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_TEST_SECRET')
: config('SETTINGS::PAYMENTS:STRIPE:ENDPOINT_SECRET');
}
protected function createInvoice($user, $payment, $paymentStatus, $currencyCode)
{
$shopProduct = ShopProduct::where('id', $payment->shop_item_product_id)->first();
//create invoice
$lastInvoiceID = \App\Models\Invoice::where('invoice_name', 'like', '%'.now()->format('mY').'%')->count('id');
$newInvoiceID = $lastInvoiceID + 1;
$logoPath = storage_path('app/public/logo.png');
$seller = new Party([
'name' => config('SETTINGS::INVOICE:COMPANY_NAME'),
'phone' => config('SETTINGS::INVOICE:COMPANY_PHONE'),
'address' => config('SETTINGS::INVOICE:COMPANY_ADDRESS'),
'vat' => config('SETTINGS::INVOICE:COMPANY_VAT'),
'custom_fields' => [
'E-Mail' => config('SETTINGS::INVOICE:COMPANY_MAIL'),
'Web' => config('SETTINGS::INVOICE:COMPANY_WEBSITE'),
],
]);
$customer = new Buyer([
'name' => $user->name,
'custom_fields' => [
'E-Mail' => $user->email,
'Client ID' => $user->id,
],
]);
$item = (new InvoiceItem())
->title($shopProduct->description)
->pricePerUnit($shopProduct->price);
$notes = [
__('Payment method').': '.$payment->payment_method,
];
$notes = implode('<br>', $notes);
$invoice = Invoice::make()
->template('controlpanel')
->name(__('Invoice'))
->buyer($customer)
->seller($seller)
->discountByPercent(PartnerDiscount::getDiscount())
->taxRate(floatval($shopProduct->getTaxPercent()))
->shipping(0)
->addItem($item)
->status(__($paymentStatus))
->series(now()->format('mY'))
->delimiter('-')
->sequence($newInvoiceID)
->serialNumberFormat(config('SETTINGS::INVOICE:PREFIX').'{DELIMITER}{SERIES}{SEQUENCE}')
->currencyCode($currencyCode)
->currencySymbol(Currencies::getSymbol($currencyCode))
->notes($notes);
if (file_exists($logoPath)) {
$invoice->logo($logoPath);
}
//Save the invoice in "storage\app\invoice\USER_ID\YEAR"
$invoice->filename = $invoice->getSerialNumber().'.pdf';
$invoice->render();
Storage::disk('local')->put('invoice/'.$user->id.'/'.now()->format('Y').'/'.$invoice->filename, $invoice->output);
\App\Models\Invoice::create([
'invoice_user' => $user->id,
'invoice_name' => $invoice->getSerialNumber(),
'payment_id' => $payment->payment_id,
]);
//Send Invoice per Mail
$user->notify(new InvoiceNotification($invoice, $user, $payment));
}
public function checkAmount($amount, $currencyCode, $payment_method)
{
$minimums = [
"USD" => [
"paypal" => 0,
"stripe" => 0.5
],
"AED" => [
"paypal" => 0,
"stripe" => 2
],
"AUD" => [
"paypal" => 0,
"stripe" => 0.5
],
"BGN" => [
"paypal" => 0,
"stripe" => 1
],
"BRL" => [
"paypal" => 0,
"stripe" => 0.5
],
"CAD" => [
"paypal" => 0,
"stripe" => 0.5
],
"CHF" => [
"paypal" => 0,
"stripe" => 0.5
],
"CZK" => [
"paypal" => 0,
"stripe" => 15
],
"DKK" => [
"paypal" => 0,
"stripe" => 2.5
],
"EUR" => [
"paypal" => 0,
"stripe" => 0.5
],
"GBP" => [
"paypal" => 0,
"stripe" => 0.3
],
"HKD" => [
"paypal" => 0,
"stripe" => 4
],
"HRK" => [
"paypal" => 0,
"stripe" => 0.5
],
"HUF" => [
"paypal" => 0,
"stripe" => 175
],
"INR" => [
"paypal" => 0,
"stripe" => 0.5
],
"JPY" => [
"paypal" => 0,
"stripe" => 0.5
],
"MXN" => [
"paypal" => 0,
"stripe" => 10
],
"MYR" => [
"paypal" => 0,
"stripe" => 2
],
"NOK" => [
"paypal" => 0,
"stripe" => 3
],
"NZD" => [
"paypal" => 0,
"stripe" => 0.5
],
"PLN" => [
"paypal" => 0,
"stripe" => 2
],
"RON" => [
"paypal" => 0,
"stripe" => 2
],
"SEK" => [
"paypal" => 0,
"stripe" => 3
],
"SGD" => [
"paypal" => 0,
"stripe" => 0.5
],
"THB" => [
"paypal" => 0,
"stripe" => 10
]
];
return $amount >= $minimums[$currencyCode][$payment_method];
}
/** /**
* @return JsonResponse|mixed * @return JsonResponse|mixed
* *
@ -808,9 +145,7 @@ class PaymentController extends Controller
return datatables($query) return datatables($query)
->addColumn('user', function (Payment $payment) { ->addColumn('user', function (Payment $payment) {
return return ($payment->user) ? '<a href="' . route('admin.users.show', $payment->user->id) . '">' . $payment->user->name . '</a>' : __('Unknown user');
($payment->user)?'<a href="'.route('admin.users.show', $payment->user->id).'">'.$payment->user->name.'</a>':__('Unknown user');
}) })
->editColumn('price', function (Payment $payment) { ->editColumn('price', function (Payment $payment) {
return $payment->formatToCurrency($payment->price); return $payment->formatToCurrency($payment->price);
@ -819,18 +154,20 @@ class PaymentController extends Controller
return $payment->formatToCurrency($payment->tax_value); return $payment->formatToCurrency($payment->tax_value);
}) })
->editColumn('tax_percent', function (Payment $payment) { ->editColumn('tax_percent', function (Payment $payment) {
return $payment->tax_percent.' %'; return $payment->tax_percent . ' %';
}) })
->editColumn('total_price', function (Payment $payment) { ->editColumn('total_price', function (Payment $payment) {
return $payment->formatToCurrency($payment->total_price); return $payment->formatToCurrency($payment->total_price);
}) })
->editColumn('created_at', function (Payment $payment) { ->editColumn('created_at', function (Payment $payment) {
return ['display' => $payment->created_at ? $payment->created_at->diffForHumans() : '', return [
'raw' => $payment->created_at ? strtotime($payment->created_at) : '']; 'display' => $payment->created_at ? $payment->created_at->diffForHumans() : '',
'raw' => $payment->created_at ? strtotime($payment->created_at) : ''
];
}) })
->addColumn('actions', function (Payment $payment) { ->addColumn('actions', function (Payment $payment) {
return '<a data-content="'.__('Download').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.invoices.downloadSingleInvoice', 'id='.$payment->payment_id).'" class="btn btn-sm text-white btn-info mr-1"><i class="fas fa-file-download"></i></a>'; return '<a data-content="' . __('Download') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.invoices.downloadSingleInvoice', 'id=' . $payment->payment_id) . '" class="btn btn-sm text-white btn-info mr-1"><i class="fas fa-file-download"></i></a>';
}) })
->rawColumns(['actions', 'user']) ->rawColumns(['actions', 'user'])
->make(true); ->make(true);

View file

@ -0,0 +1,31 @@
<?php
namespace App\Listeners;
use App\Events\PaymentEvent;
use App\Traits\Invoiceable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class CreateInvoice implements ShouldQueue
{
use Invoiceable;
/**
* Handle the event.
*
* @param \App\Events\PaymentEvent $event
* @return void
*/
public function handle(PaymentEvent $event)
{
if (config('SETTINGS::INVOICE:ENABLED') == 'true') {
// get user from payment which does hold the user_id
$user = $event->payment->user;
// create invoice using the trait
$this->createInvoice($user, $event->payment);
}
}
}

View file

@ -0,0 +1,82 @@
<?php
namespace App\Listeners;
use App\Events\PaymentEvent;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use App\Models\PartnerDiscount;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class UserPayment
{
/**
* Handle the event.
*
* @param \App\Events\PaymentEvent $event
* @return void
*/
public function handle(PaymentEvent $event)
{
$user = $event->user;
$shopProduct = $event->shopProduct;
// only update user if payment is paid
if ($event->payment->status != "paid") {
return;
}
//update server limit
if (config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0 && $user->server_limit < config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => config('SETTINGS::USER:SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
}
//update User with bought item
if ($shopProduct->type == "Credits") {
$user->increment('credits', $shopProduct->quantity);
} elseif ($shopProduct->type == "Server slots") {
$user->increment('server_limit', $shopProduct->quantity);
}
//give referral commission always
if ((config("SETTINGS::REFERRAL:MODE") == "commission" || config("SETTINGS::REFERRAL:MODE") == "both") && $shopProduct->type == "Credits" && config("SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION") == "true") {
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, "", "");
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained ' . $increment . ' ' . config("SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME") . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
}
}
//update role give Referral-reward
if ($user->role == 'member') {
$user->update(['role' => 'client']);
//give referral commission only on first purchase
if ((config("SETTINGS::REFERRAL:MODE") == "commission" || config("SETTINGS::REFERRAL:MODE") == "both") && $shopProduct->type == "Credits" && config("SETTINGS::REFERRAL::ALWAYS_GIVE_COMMISSION") == "false") {
if ($ref_user = DB::table("user_referrals")->where('registered_user_id', '=', $user->id)->first()) {
$ref_user = User::findOrFail($ref_user->referral_id);
$increment = number_format($shopProduct->quantity * (PartnerDiscount::getCommission($ref_user->id)) / 100, 0, "", "");
$ref_user->increment('credits', $increment);
//LOGS REFERRALS IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($ref_user)
->log('gained ' . $increment . ' ' . config("SETTINGS::SYSTEM:CREDITS_DISPLAY_NAME") . ' for commission-referral of ' . $user->name . ' (ID:' . $user->id . ')');
}
}
}
// LOGS PAYMENT IN THE ACTIVITY LOG
activity()
->performedOn($user)
->causedBy($user)
->log('bought ' . $shopProduct->quantity . ' ' . $shopProduct->type . ' for ' . $shopProduct->price . $shopProduct->currency_code);
}
}

View file

@ -7,20 +7,11 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use NumberFormatter; use NumberFormatter;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
class Payment extends Model class Payment extends Model
{ {
use HasFactory; use HasFactory;
use LogsActivity;
public function getActivitylogOptions(): LogOptions
{
return LogOptions::defaults()
-> logOnlyDirty()
-> logOnly(['*'])
-> dontSubmitEmptyLogs();
}
public $incrementing = false; public $incrementing = false;
/** /**

View file

@ -2,8 +2,11 @@
namespace App\Providers; namespace App\Providers;
use App\Events\PaymentEvent;
use App\Events\UserUpdateCreditsEvent; use App\Events\UserUpdateCreditsEvent;
use App\Listeners\CreateInvoice;
use App\Listeners\UnsuspendServers; use App\Listeners\UnsuspendServers;
use App\Listeners\UserPayment;
use App\Listeners\Verified; use App\Listeners\Verified;
use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification; use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
@ -24,6 +27,10 @@ class EventServiceProvider extends ServiceProvider
UserUpdateCreditsEvent::class => [ UserUpdateCreditsEvent::class => [
UnsuspendServers::class, UnsuspendServers::class,
], ],
PaymentEvent::class => [
CreateInvoice::class,
UserPayment::class,
],
SocialiteWasCalled::class => [ SocialiteWasCalled::class => [
// ... other providers // ... other providers
'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle', 'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle',

View file

@ -0,0 +1,91 @@
<?php
namespace App\Traits;
use App\Models\PartnerDiscount;
use App\Models\ShopProduct;
use App\Notifications\InvoiceNotification;
use Illuminate\Support\Facades\Storage;
use LaravelDaily\Invoices\Classes\Buyer;
use LaravelDaily\Invoices\Classes\InvoiceItem;
use LaravelDaily\Invoices\Classes\Party;
use LaravelDaily\Invoices\Invoice;
use Symfony\Component\Intl\Currencies;
trait Invoiceable
{
public function createInvoice($user, $payment)
{
$shopProduct = ShopProduct::where('id', $payment->shop_item_product_id)->first();
//create invoice
$lastInvoiceID = \App\Models\Invoice::where("invoice_name", "like", "%" . now()->format('mY') . "%")->count("id");
$newInvoiceID = $lastInvoiceID + 1;
$logoPath = storage_path('app/public/logo.png');
$seller = new Party([
'name' => config("SETTINGS::INVOICE:COMPANY_NAME"),
'phone' => config("SETTINGS::INVOICE:COMPANY_PHONE"),
'address' => config("SETTINGS::INVOICE:COMPANY_ADDRESS"),
'vat' => config("SETTINGS::INVOICE:COMPANY_VAT"),
'custom_fields' => [
'E-Mail' => config("SETTINGS::INVOICE:COMPANY_MAIL"),
"Web" => config("SETTINGS::INVOICE:COMPANY_WEBSITE")
],
]);
$customer = new Buyer([
'name' => $user->name,
'custom_fields' => [
'E-Mail' => $user->email,
'Client ID' => $user->id,
],
]);
$item = (new InvoiceItem())
->title($shopProduct->description)
->pricePerUnit($shopProduct->price);
$notes = [
__("Payment method") . ": " . $payment->payment_method,
];
$notes = implode("<br>", $notes);
$invoice = Invoice::make()
->template('controlpanel')
->name(__("Invoice"))
->buyer($customer)
->seller($seller)
->discountByPercent(PartnerDiscount::getDiscount())
->taxRate(floatval($shopProduct->getTaxPercent()))
->shipping(0)
->addItem($item)
->status(__($payment->status))
->series(now()->format('mY'))
->delimiter("-")
->sequence($newInvoiceID)
->serialNumberFormat(config("SETTINGS::INVOICE:PREFIX") . '{DELIMITER}{SERIES}{SEQUENCE}')
->currencyCode(strtoupper($payment->currency_code))
->currencySymbol(Currencies::getSymbol(strtoupper($payment->currency_code)))
->notes($notes);
if (file_exists($logoPath)) {
$invoice->logo($logoPath);
}
//Save the invoice in "storage\app\invoice\USER_ID\YEAR"
$invoice->filename = $invoice->getSerialNumber() . '.pdf';
$invoice->render();
Storage::disk("local")->put("invoice/" . $user->id . "/" . now()->format('Y') . "/" . $invoice->filename, $invoice->output);
\App\Models\Invoice::create([
'invoice_user' => $user->id,
'invoice_name' => $invoice->getSerialNumber(),
'payment_id' => $payment->payment_id,
]);
//Send Invoice per Mail
$user->notify(new InvoiceNotification($invoice, $user, $payment));
}
}

View file

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -34,6 +34,8 @@ Route::middleware('api.token')->group(function () {
Route::get('/notifications/{user}', [NotificationController::class, 'index']); Route::get('/notifications/{user}', [NotificationController::class, 'index']);
Route::get('/notifications/{user}/{notification}', [NotificationController::class, 'view']); Route::get('/notifications/{user}/{notification}', [NotificationController::class, 'view']);
Route::post('/notifications', [NotificationController::class, 'send']); Route::post('/notifications', [NotificationController::class, 'send']);
Route::delete('/notifications/{user}', [NotificationController::class, 'delete']);
Route::delete('/notifications/{user}/{notification}', [NotificationController::class, 'deleteOne']); Route::delete('/notifications/{user}/{notification}', [NotificationController::class, 'deleteOne']);
Route::delete('/notifications/{user}', [NotificationController::class, 'delete']);
}); });
require __DIR__ . '/extensions_api.php';

21
routes/extensions_api.php Normal file
View file

@ -0,0 +1,21 @@
<?php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'extensions', 'middleware' => 'api.token'], function () {
// get all extensions that are inside App/Extensions
// It is important that the extensions are inside a folder with the name of the extension
// while those folders are inside Folders with the name of the type of extension like PaymentGateways, Themes, etc.
$extensionNamespaces = glob(app_path() . '/Extensions/*', GLOB_ONLYDIR);
$extensions = [];
foreach ($extensionNamespaces as $extensionNamespace) {
$extensions = array_merge($extensions, glob($extensionNamespace . '/*', GLOB_ONLYDIR));
}
foreach ($extensions as $extension) {
$routesFile = $extension . '/api_routes.php';
if (file_exists($routesFile)) {
include_once $routesFile;
}
}
});

22
routes/extensions_web.php Normal file
View file

@ -0,0 +1,22 @@
<?php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'extensions'], function () {
// get all extensions that are inside App/Extensions
// It is important that the extensions are inside a folder with the name of the extension
// while those folders are inside Folders with the name of the type of extension like PaymentGateways, Themes, etc.
$extensionNamespaces = glob(app_path() . '/Extensions/*', GLOB_ONLYDIR);
$extensions = [];
foreach ($extensionNamespaces as $extensionNamespace) {
$extensions = array_merge($extensions, glob($extensionNamespace . '/*', GLOB_ONLYDIR));
}
foreach ($extensions as $extension) {
$routesFile = $extension . '/web_routes.php';
if (file_exists($routesFile)) {
include_once $routesFile;
}
}
});

View file

@ -49,17 +49,14 @@ Route::middleware('guest')->get('/', function () {
Auth::routes(['verify' => true]); Auth::routes(['verify' => true]);
// Stripe WebhookRoute -> validation in Route Handler
Route::post('payment/StripeWebhooks', [PaymentController::class, 'StripeWebhooks'])->name('payment.StripeWebhooks');
Route::get('/privacy', function () { Route::get('/privacy', function () {
return view('information.privacy'); return view('information.privacy');
})->name('privacy'); })->name('privacy');
Route::get('/imprint', function () { Route::get('/imprint', function () {
return view('information.imprint'); return view('information.imprint');
})->name('imprint'); })->name('imprint');
Route::get('/tos', function () { Route::get('/tos', function () {
return view('information.tos'); return view('information.tos');
})->name('tos'); })->name('tos');
Route::middleware(['auth', 'checkSuspended'])->group(function () { Route::middleware(['auth', 'checkSuspended'])->group(function () {
@ -90,10 +87,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
//payments //payments
Route::get('checkout/{shopProduct}', [PaymentController::class, 'checkOut'])->name('checkout'); Route::get('checkout/{shopProduct}', [PaymentController::class, 'checkOut'])->name('checkout');
Route::get('payment/PaypalPay/{shopProduct}', [PaymentController::class, 'PaypalPay'])->name('payment.PaypalPay'); Route::post('payment/pay', [PaymentController::class, 'pay'])->name('payment.pay');
Route::get('payment/PaypalSuccess', [PaymentController::class, 'PaypalSuccess'])->name('payment.PaypalSuccess');
Route::get('payment/StripePay/{shopProduct}', [PaymentController::class, 'StripePay'])->name('payment.StripePay');
Route::get('payment/StripeSuccess', [PaymentController::class, 'StripeSuccess'])->name('payment.StripeSuccess');
Route::get('payment/FreePay/{shopProduct}', [PaymentController::class, 'FreePay'])->name('payment.FreePay'); Route::get('payment/FreePay/{shopProduct}', [PaymentController::class, 'FreePay'])->name('payment.FreePay');
Route::get('payment/Cancel', [PaymentController::class, 'Cancel'])->name('payment.Cancel'); Route::get('payment/Cancel', [PaymentController::class, 'Cancel'])->name('payment.Cancel');
@ -221,3 +215,5 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
Route::get('/home', [HomeController::class, 'index'])->name('home'); Route::get('/home', [HomeController::class, 'index'])->name('home');
}); });
require __DIR__ . '/extensions_web.php';

View file

@ -10,8 +10,7 @@
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<ol class="breadcrumb float-sm-right"> <ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a class="" <li class="breadcrumb-item"><a class="" href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
<li class="breadcrumb-item"><a class="text-muted" <li class="breadcrumb-item"><a class="text-muted"
href="{{ route('store.index') }}">{{ __('Store') }}</a> href="{{ route('store.index') }}">{{ __('Store') }}</a>
</li> </li>
@ -23,157 +22,127 @@
<!-- END CONTENT HEADER --> <!-- END CONTENT HEADER -->
<!-- MAIN CONTENT --> <!-- MAIN CONTENT -->
<section x-data="serverApp()" x-init="$watch('paymentMethod', value => setPaymentRoute(value))" class="content"> <section class="content">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<form x-data="{ payment_method: '', clicked: false }" action="{{ route('payment.pay') }}" method="POST">
<!-- Main content --> @csrf
<div class="invoice p-3 mb-3"> @method('post')
<!-- title row --> <!-- Main content -->
<div class="row"> <div class="invoice p-3 mb-3">
<div class="col-12"> <!-- title row -->
<h4> <div class="row">
<i class="fas fa-globe"></i> {{ config('app.name', 'Laravel') }} <div class="col-12">
<small class="float-right">{{ __('Date') }}: <h4>
{{ Carbon\Carbon::now()->isoFormat('LL') }}</small> <i class="fas fa-globe"></i> {{ config('app.name', 'Laravel') }}
</h4> <small class="float-right">{{ __('Date') }}:
{{ Carbon\Carbon::now()->isoFormat('LL') }}</small>
</h4>
</div>
<!-- /.col -->
</div> </div>
<!-- /.col -->
</div>
<!-- Table row --> <!-- Table row -->
<div class="row"> <div class="row">
<div class="col-12 table-responsive"> <div class="col-12 table-responsive">
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>{{ __('Quantity') }}</th> <th>{{ __('Quantity') }}</th>
<th>{{ __('Product') }}</th> <th>{{ __('Product') }}</th>
<th>{{ __('Description') }}</th> <th>{{ __('Description') }}</th>
<th>{{ __('Subtotal') }}</th> <th>{{ __('Subtotal') }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td>1</td> <td>1</td>
<td><i class="fa fa-coins mr-2"></i>{{ $product->quantity }} <td><i class="fa fa-coins mr-2"></i>{{ $product->quantity }}
{{ strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type }} {{ strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type }}
</td> </td>
<td>{{ $product->description }}</td> <td>{{ $product->description }}</td>
<td>{{ $product->formatToCurrency($product->price) }}</td> <td>{{ $product->formatToCurrency($product->price) }}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<input type="hidden" name="product_id" value="{{ $product->id }}">
</div>
<!-- /.col -->
</div> </div>
<!-- /.col --> <!-- /.row -->
</div>
<!-- /.row -->
<div class="row"> <div class="row">
<!-- accepted payments column --> <!-- accepted payments column -->
<div class="col-6"> <div class="col-6">
@if($total!=0)
<p class="lead">{{ __('Payment Methods') }}:</p> <p class="lead">{{ __('Payment Methods') }}:</p>
<div> <div class="d-flex flex-wrap flex-direction-row">
@if (config('SETTINGS::PAYMENTS:PAYPAL:SECRET') || config('SETTINGS::PAYMENTS:PAYPAL:SANDBOX_SECRET')) @foreach ($paymentGateways as $gateway)
<label class="text-center " for="paypal"> <div class="ml-2">
<img class="mb-3" height="50" <label class="text-center" for="{{ $gateway->name }}">
src="{{ url('/images/paypal_logo.png') }}"></br> <img class="mb-3" height="50" src="{{ $gateway->image }}"></br>
<input x-on:click="console.log(payment_method)" x-model="payment_method"
<input x-model="paymentMethod" type="radio" id="paypal" value="paypal" type="radio" id="{{ $gateway->name }}"
name="payment_method"> value="{{ $gateway->name }}">
</input> </input>
</label> </label>
@endif </div>
@if (config('SETTINGS::PAYMENTS:STRIPE:TEST_SECRET') || config('SETTINGS::PAYMENTS:STRIPE:SECRET')) @endforeach
<label class="ml-5 text-center " for="stripe">
<img class="mb-3" height="50"
src="{{ url('/images/stripe_logo.png') }}" /></br>
<input x-model="paymentMethod" type="radio" id="stripe" value="stripe"
name="payment_method">
</input>
</label>
@endif
</div> </div>
@else
<p class="lead" style="text-align: center">{{ __('This product is free for you') }}.</p>
@endif
</div>
<!-- /.col -->
<div class="col-6">
<p class="lead">{{ __('Amount Due') }}
{{ Carbon\Carbon::now()->isoFormat('LL') }}</p>
<div class="table-responsive"> </div>
<table class="table"> <!-- /.col -->
@if($discountpercent&&$discountvalue) <div class="col-6">
<p class="lead">{{ __('Amount Due') }}
{{ Carbon\Carbon::now()->isoFormat('LL') }}</p>
<div class="table-responsive">
<table class="table">
@if ($discountpercent && $discountvalue)
<tr>
<th>{{ __('Discount') }} ({{ $discountpercent }}%):</th>
<td>{{ $product->formatToCurrency($discountvalue) }}</td>
</tr>
@endif
<tr> <tr>
<th>{{ __('Discount') }} ({{ $discountpercent }}%):</th> <th style="width:50%">{{ __('Subtotal') }}:</th>
<td>{{$product->formatToCurrency($discountvalue)}}</td> <td>{{ $product->formatToCurrency($discountedprice) }}</td>
</tr> </tr>
@endif <tr>
<tr> <th>{{ __('Tax') }} ({{ $taxpercent }}%):</th>
<th style="width:50%">{{ __('Subtotal') }}:</th> <td>{{ $product->formatToCurrency($taxvalue) }}</td>
<td>{{ $product->formatToCurrency($discountedprice) }}</td> </tr>
</tr> <tr>
<tr> <th>{{ __('Total') }}:</th>
<th>{{ __('Tax') }} ({{ $taxpercent }}%):</th> <td>{{ $product->formatToCurrency($total) }}</td>
<td>{{ $product->formatToCurrency($taxvalue) }}</td> </tr>
</tr> </table>
<tr> </div>
<th>{{ __('Total') }}:</th> </div>
<td>{{ $product->formatToCurrency($total) }}</td> <!-- /.col -->
</tr> </div>
</table> <!-- /.row -->
<!-- this row will not appear when printing -->
<div class="row no-print">
<div class="col-12">
<button :disabled="!payment_method || clicked"
:class="!payment_method || clicked ? 'disabled' : ''"
class="btn btn-success float-right"><i class="far fa-credit-card mr-2"
@click="clicked = true"></i>
{{ __('Submit Payment') }}
</button>
</div> </div>
</div> </div>
<!-- /.col -->
</div> </div>
<!-- /.row --> </form>
<!-- this row will not appear when printing -->
<div class="row no-print">
<div class="col-12">
<a type="button" :href="paymentRoute" :disabled="!paymentRoute"
:class="!paymentRoute ? 'disabled' : ''" class="btn btn-success float-right"><i
class="far fa-credit-card mr-2"></i>
{{ __('Submit Payment') }}
</a>
</div>
</div>
</div>
<!-- /.invoice --> <!-- /.invoice -->
</div><!-- /.col --> </div><!-- /.col -->
</div><!-- /.row --> </div><!-- /.row -->
</div> </div>
</section> </section>
<!-- END CONTENT --> <!-- END CONTENT -->
@endsection
<script>
function serverApp() {
return {
//loading
paymentMethod: '',
paymentRoute: ({{ $total }} == 0)?('{{ route('payment.FreePay', $product->id) }}'):'',
setPaymentRoute(provider) {
switch (provider) {
case 'paypal':
this.paymentRoute = '{{ route('payment.PaypalPay', $product->id) }}';
break;
case 'stripe':
this.paymentRoute = '{{ route('payment.StripePay', $product->id) }}';
break;
default:
this.paymentRoute = '{{ route('payment.PaypalPay', $product->id) }}';
}
},
}
}
</script>
@endsection