Merge pull request #328 from IceToast/stripe_integration

feature: Stripe integration
This commit is contained in:
Dennis 2021-12-22 13:06:46 +01:00 committed by GitHub
commit c614e03526
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 2292 additions and 1229 deletions

View file

@ -1,4 +1,4 @@
APP_NAME=Dashboard APP_NAME=Controlpanel.gg
APP_ENV=production APP_ENV=production
APP_KEY= APP_KEY=
APP_DEBUG=false APP_DEBUG=false
@ -25,6 +25,18 @@ PAYPAL_SECRET=
PAYPAL_CLIENT_ID= PAYPAL_CLIENT_ID=
PAYPAL_EMAIL= PAYPAL_EMAIL=
#stripe details, you only need "test" for testing! you can do this by setting the APP_ENV to local
STRIPE_TEST_SECRET=
STRIPE_SECRET=
#https://dashboard.stripe.com/webhooks -> webhook route: <your.controlpanel.gg>/payment/StripeWebhooks
STRIPE_ENDPOINT_TEST_SECRET=
STRIPE_ENDPOINT_SECRET=
#stripe payment methods, comma seperated list of methods you want to support:
#read into https://stripe.com/docs/payments/payment-methods/integration-options and/or https://stripe.com/docs/payments/payment-methods/overview
#Method needs to support the currency
STRIPE_METHODS=
#set-up for extra discord verification #set-up for extra discord verification
DISCORD_CLIENT_ID= DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET= DISCORD_CLIENT_SECRET=

View file

@ -1,25 +1,32 @@
### Features ### Features
- PayPal Integration - PayPal Integration
- Email Verification - Stripe Integration
- Audit Log - Email Verification
- Admin Dashboard - Audit Log
- User/Server Management - Admin Dashboard
- Store (credit system) - User/Server Management
- Vouchers - Store (credit system)
- and so much more! - Vouchers
- and so much more!
# ControlPanel-gg # ControlPanel-gg
![controlpanel](https://user-images.githubusercontent.com/45005889/123518824-06b05000-d6a8-11eb-91b9-d1ed36bd2317.png) ![controlpanel](https://user-images.githubusercontent.com/45005889/123518824-06b05000-d6a8-11eb-91b9-d1ed36bd2317.png)
![](https://img.shields.io/github/stars/ControlPanel-gg/dashboard) ![](https://img.shields.io/github/forks/ControlPanel-gg/dashboard) ![](https://img.shields.io/github/tag/ControlPanel-gg/dashboard) [![Crowdin](https://badges.crowdin.net/controlpanelgg/localized.svg)](https://crowdin.com/project/controlpanelgg) ![](https://img.shields.io/github/issues/ControlPanel-gg/dashboard) ![](https://img.shields.io/github/license/ControlPanel-gg/dashboard) ![](https://img.shields.io/discord/787829714483019826) ![](https://img.shields.io/github/stars/ControlPanel-gg/dashboard) ![](https://img.shields.io/github/forks/ControlPanel-gg/dashboard) ![](https://img.shields.io/github/tag/ControlPanel-gg/dashboard) [![Crowdin](https://badges.crowdin.net/controlpanelgg/localized.svg)](https://crowdin.com/project/controlpanelgg) ![](https://img.shields.io/github/issues/ControlPanel-gg/dashboard) ![](https://img.shields.io/github/license/ControlPanel-gg/dashboard) ![](https://img.shields.io/discord/787829714483019826)
## About ## About
ControlPanel's Dashboard is a dashboard application designed to offer clients a management tool to manage their pterodactyl servers. This dashboard comes with a credit-based billing solution that credits users hourly for each server they have and suspends them if they run out of credits. ControlPanel's Dashboard is a dashboard application designed to offer clients a management tool to manage their pterodactyl servers. This dashboard comes with a credit-based billing solution that credits users hourly for each server they have and suspends them if they run out of credits.
This dashboard offers an easy to use and free billing solution for all starting and experienced hosting providers. This dashboard has many customization options and added discord 0auth verification to offer a solid link between your discord server and your dashboard. This dashboard offers an easy to use and free billing solution for all starting and experienced hosting providers. This dashboard has many customization options and added discord 0auth verification to offer a solid link between your discord server and your dashboard.
### [Installation](https://controlpanel.gg/docs/intro "Installation") ### [Installation](https://controlpanel.gg/docs/intro "Installation")
### [Updating](https://controlpanel.gg/docs/Installation/updating "Updating") ### [Updating](https://controlpanel.gg/docs/Installation/updating "Updating")
### [Discord](https://discord.gg/4Y6HjD2uyU "discord") ### [Discord](https://discord.gg/4Y6HjD2uyU "discord")
### [Contributing](https://controlpanel.gg/docs/Contributing/contributing "Contributing") ### [Contributing](https://controlpanel.gg/docs/Contributing/contributing "Contributing")
### [Donating](https://controlpanel.gg/docs/Contributing/donating "Donating") ### [Donating](https://controlpanel.gg/docs/Contributing/donating "Donating")

View file

@ -2,7 +2,7 @@
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Models\PaypalProduct; use App\Models\CreditProduct;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View; use Illuminate\Contracts\View\View;
@ -12,7 +12,7 @@ use Illuminate\Http\Response;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
class PaypalProductController extends Controller class CreditProductController extends Controller
{ {
/** /**
* Display a listing of the resource. * Display a listing of the resource.
@ -21,11 +21,16 @@ class PaypalProductController extends Controller
*/ */
public function index(Request $request) public function index(Request $request)
{ {
$isPaypalSetup = false; $isPaymentSetup = false;
if (env('PAYPAL_SECRET') && env('PAYPAL_CLIENT_ID')) $isPaypalSetup = true;
return view('admin.store.index' , [ if (
'isPaypalSetup' => $isPaypalSetup env('APP_ENV') == 'local' ||
env('PAYPAL_SECRET') && env('PAYPAL_CLIENT_ID') ||
env('STRIPE_SECRET') && env('STRIPE_ENDPOINT_SECRET') && env('STRIPE_METHODS')
) $isPaymentSetup = true;
return view('admin.store.index', [
'isPaymentSetup' => $isPaymentSetup
]); ]);
} }
@ -60,7 +65,7 @@ class PaypalProductController extends Controller
]); ]);
$disabled = !is_null($request->input('disabled')); $disabled = !is_null($request->input('disabled'));
PaypalProduct::create(array_merge($request->all(), ['disabled' => $disabled])); CreditProduct::create(array_merge($request->all(), ['disabled' => $disabled]));
return redirect()->route('admin.store.index')->with('success', __('Store item has been created!')); return redirect()->route('admin.store.index')->with('success', __('Store item has been created!'));
} }
@ -68,10 +73,10 @@ class PaypalProductController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
* *
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return Response * @return Response
*/ */
public function show(PaypalProduct $paypalProduct) public function show(CreditProduct $creditProduct)
{ {
// //
} }
@ -79,14 +84,14 @@ class PaypalProductController extends Controller
/** /**
* Show the form for editing the specified resource. * Show the form for editing the specified resource.
* *
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return Application|Factory|View|Response * @return Application|Factory|View|Response
*/ */
public function edit(PaypalProduct $paypalProduct) public function edit(CreditProduct $creditProduct)
{ {
return view('admin.store.edit', [ return view('admin.store.edit', [
'currencyCodes' => config('currency_codes'), 'currencyCodes' => config('currency_codes'),
'paypalProduct' => $paypalProduct 'creditProduct' => $creditProduct
]); ]);
} }
@ -94,10 +99,10 @@ class PaypalProductController extends Controller
* Update the specified resource in storage. * Update the specified resource in storage.
* *
* @param Request $request * @param Request $request
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return RedirectResponse * @return RedirectResponse
*/ */
public function update(Request $request, PaypalProduct $paypalProduct) public function update(Request $request, CreditProduct $creditProduct)
{ {
$request->validate([ $request->validate([
"disabled" => "nullable", "disabled" => "nullable",
@ -110,19 +115,19 @@ class PaypalProductController extends Controller
]); ]);
$disabled = !is_null($request->input('disabled')); $disabled = !is_null($request->input('disabled'));
$paypalProduct->update(array_merge($request->all(), ['disabled' => $disabled])); $creditProduct->update(array_merge($request->all(), ['disabled' => $disabled]));
return redirect()->route('admin.store.index')->with('success', __('Store item has been updated!')); return redirect()->route('admin.store.index')->with('success', __('Store item has been updated!'));
} }
/** /**
* @param Request $request * @param Request $request
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return RedirectResponse * @return RedirectResponse
*/ */
public function disable(Request $request, PaypalProduct $paypalProduct) public function disable(Request $request, CreditProduct $creditProduct)
{ {
$paypalProduct->update(['disabled' => !$paypalProduct->disabled]); $creditProduct->update(['disabled' => !$creditProduct->disabled]);
return redirect()->route('admin.store.index')->with('success', __('Product has been updated!')); return redirect()->route('admin.store.index')->with('success', __('Product has been updated!'));
} }
@ -130,50 +135,50 @@ class PaypalProductController extends Controller
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
* *
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return RedirectResponse * @return RedirectResponse
*/ */
public function destroy(PaypalProduct $paypalProduct) public function destroy(CreditProduct $creditProduct)
{ {
$paypalProduct->delete(); $creditProduct->delete();
return redirect()->back()->with('success', __('Store item has been removed!')); return redirect()->back()->with('success', __('Store item has been removed!'));
} }
public function dataTable() public function dataTable()
{ {
$query = PaypalProduct::query(); $query = CreditProduct::query();
return datatables($query) return datatables($query)
->addColumn('actions', function (PaypalProduct $paypalProduct) { ->addColumn('actions', function (CreditProduct $creditProduct) {
return ' return '
<a data-content="'.__("Edit").'" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.store.edit', $paypalProduct->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a> <a data-content="' . __("Edit") . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.store.edit', $creditProduct->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.store.destroy', $paypalProduct->id) . '"> <form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.store.destroy', $creditProduct->id) . '">
' . csrf_field() . ' ' . csrf_field() . '
' . method_field("DELETE") . ' ' . method_field("DELETE") . '
<button data-content="'.__("Delete").'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button> <button data-content="' . __("Delete") . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
</form> </form>
'; ';
}) })
->addColumn('disabled', function (PaypalProduct $paypalProduct) { ->addColumn('disabled', function (CreditProduct $creditProduct) {
$checked = $paypalProduct->disabled == false ? "checked" : ""; $checked = $creditProduct->disabled == false ? "checked" : "";
return ' return '
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.store.disable', $paypalProduct->id) . '"> <form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.store.disable', $creditProduct->id) . '">
' . csrf_field() . ' ' . csrf_field() . '
' . method_field("PATCH") . ' ' . method_field("PATCH") . '
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input ' . $checked . ' name="disabled" onchange="this.form.submit()" type="checkbox" class="custom-control-input" id="switch' . $paypalProduct->id . '"> <input ' . $checked . ' name="disabled" onchange="this.form.submit()" type="checkbox" class="custom-control-input" id="switch' . $creditProduct->id . '">
<label class="custom-control-label" for="switch' . $paypalProduct->id . '"></label> <label class="custom-control-label" for="switch' . $creditProduct->id . '"></label>
</div> </div>
</form> </form>
'; ';
}) })
->editColumn('created_at', function (PaypalProduct $paypalProduct) { ->editColumn('created_at', function (CreditProduct $creditProduct) {
return $paypalProduct->created_at ? $paypalProduct->created_at->diffForHumans() : ''; return $creditProduct->created_at ? $creditProduct->created_at->diffForHumans() : '';
}) })
->editColumn('price', function (PaypalProduct $paypalProduct) { ->editColumn('price', function (CreditProduct $creditProduct) {
return $paypalProduct->formatToCurrency($paypalProduct->price); return $creditProduct->formatToCurrency($creditProduct->price);
}) })
->rawColumns(['actions', 'disabled']) ->rawColumns(['actions', 'disabled'])
->make(); ->make();

View file

@ -7,9 +7,10 @@ use App\Http\Controllers\Controller;
use App\Models\Configuration; use App\Models\Configuration;
use App\Models\InvoiceSettings; use App\Models\InvoiceSettings;
use App\Models\Payment; use App\Models\Payment;
use App\Models\PaypalProduct; use App\Models\CreditProduct;
use App\Models\User; use App\Models\User;
use App\Notifications\InvoiceNotification; use App\Notifications\InvoiceNotification;
use App\Notifications\ConfirmPaymentNotification;
use Exception; use Exception;
use Illuminate\Contracts\Foundation\Application; use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\Factory;
@ -29,6 +30,8 @@ use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest; use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest; use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalHttp\HttpException; use PayPalHttp\HttpException;
use Stripe\Stripe;
class PaymentController extends Controller class PaymentController extends Controller
{ {
@ -45,25 +48,25 @@ class PaymentController extends Controller
/** /**
* @param Request $request * @param Request $request
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return Application|Factory|View * @return Application|Factory|View
*/ */
public function checkOut(Request $request, PaypalProduct $paypalProduct) public function checkOut(Request $request, CreditProduct $creditProduct)
{ {
return view('store.checkout')->with([ return view('store.checkout')->with([
'product' => $paypalProduct, 'product' => $creditProduct,
'taxvalue' => $paypalProduct->getTaxValue(), 'taxvalue' => $creditProduct->getTaxValue(),
'taxpercent' => $paypalProduct->getTaxPercent(), 'taxpercent' => $creditProduct->getTaxPercent(),
'total' => $paypalProduct->getTotalPrice() 'total' => $creditProduct->getTotalPrice()
]); ]);
} }
/** /**
* @param Request $request * @param Request $request
* @param PaypalProduct $paypalProduct * @param CreditProduct $creditProduct
* @return RedirectResponse * @return RedirectResponse
*/ */
public function pay(Request $request, PaypalProduct $paypalProduct) public function PaypalPay(Request $request, CreditProduct $creditProduct)
{ {
$request = new OrdersCreateRequest(); $request = new OrdersCreateRequest();
$request->prefer('return=representation'); $request->prefer('return=representation');
@ -72,30 +75,30 @@ class PaymentController extends Controller
"purchase_units" => [ "purchase_units" => [
[ [
"reference_id" => uniqid(), "reference_id" => uniqid(),
"description" => $paypalProduct->description, "description" => $creditProduct->description,
"amount" => [ "amount" => [
"value" => $paypalProduct->getTotalPrice(), "value" => $creditProduct->getTotalPrice(),
'currency_code' => strtoupper($paypalProduct->currency_code), 'currency_code' => strtoupper($creditProduct->currency_code),
'breakdown' => [ 'breakdown' => [
'item_total' => 'item_total' =>
[ [
'currency_code' => strtoupper($paypalProduct->currency_code), 'currency_code' => strtoupper($creditProduct->currency_code),
'value' => $paypalProduct->price, 'value' => $creditProduct->price,
], ],
'tax_total' => 'tax_total' =>
[ [
'currency_code' => strtoupper($paypalProduct->currency_code), 'currency_code' => strtoupper($creditProduct->currency_code),
'value' => $paypalProduct->getTaxValue(), 'value' => $creditProduct->getTaxValue(),
] ]
] ]
] ]
] ]
], ],
"application_context" => [ "application_context" => [
"cancel_url" => route('payment.cancel'), "cancel_url" => route('payment.Cancel'),
"return_url" => route('payment.success', ['product' => $paypalProduct->id]), "return_url" => route('payment.PaypalSuccess', ['product' => $creditProduct->id]),
'brand_name' => config('app.name', 'Laravel'), 'brand_name' => config('app.name', 'Laravel'),
'shipping_preference' => 'NO_SHIPPING' 'shipping_preference' => 'NO_SHIPPING'
] ]
@ -112,7 +115,6 @@ class PaymentController extends Controller
echo $ex->statusCode; echo $ex->statusCode;
dd(json_decode($ex->getMessage())); dd(json_decode($ex->getMessage()));
} }
} }
/** /**
@ -121,8 +123,8 @@ class PaymentController extends Controller
protected function getPayPalClient() protected function getPayPalClient()
{ {
$environment = env('APP_ENV') == 'local' $environment = env('APP_ENV') == 'local'
? new SandboxEnvironment($this->getClientId(), $this->getClientSecret()) ? new SandboxEnvironment($this->getPaypalClientId(), $this->getPaypalClientSecret())
: new ProductionEnvironment($this->getClientId(), $this->getClientSecret()); : new ProductionEnvironment($this->getPaypalClientId(), $this->getPaypalClientSecret());
return new PayPalHttpClient($environment); return new PayPalHttpClient($environment);
} }
@ -130,7 +132,7 @@ class PaymentController extends Controller
/** /**
* @return string * @return string
*/ */
protected function getClientId() protected function getPaypalClientId()
{ {
return env('APP_ENV') == 'local' ? env('PAYPAL_SANDBOX_CLIENT_ID') : env('PAYPAL_CLIENT_ID'); return env('APP_ENV') == 'local' ? env('PAYPAL_SANDBOX_CLIENT_ID') : env('PAYPAL_CLIENT_ID');
} }
@ -138,7 +140,7 @@ class PaymentController extends Controller
/** /**
* @return string * @return string
*/ */
protected function getClientSecret() protected function getPaypalClientSecret()
{ {
return env('APP_ENV') == 'local' ? env('PAYPAL_SANDBOX_SECRET') : env('PAYPAL_SECRET'); return env('APP_ENV') == 'local' ? env('PAYPAL_SANDBOX_SECRET') : env('PAYPAL_SECRET');
} }
@ -146,10 +148,11 @@ class PaymentController extends Controller
/** /**
* @param Request $laravelRequest * @param Request $laravelRequest
*/ */
public function success(Request $laravelRequest) public function PaypalSuccess(Request $laravelRequest)
{ {
/** @var PaypalProduct $paypalProduct */ /** @var CreditProduct $creditProduct */
$paypalProduct = PaypalProduct::findOrFail($laravelRequest->input('product')); $creditProduct = CreditProduct::findOrFail($laravelRequest->input('product'));
/** @var User $user */ /** @var User $user */
$user = Auth::user(); $user = Auth::user();
@ -161,7 +164,7 @@ class PaymentController extends Controller
if ($response->statusCode == 201 || $response->statusCode == 200) { if ($response->statusCode == 201 || $response->statusCode == 200) {
//update credits //update credits
$user->increment('credits', $paypalProduct->quantity); $user->increment('credits', $creditProduct->quantity);
//update server limit //update server limit
if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) { if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
@ -179,82 +182,22 @@ class PaymentController extends Controller
$payment = Payment::create([ $payment = Payment::create([
'user_id' => $user->id, 'user_id' => $user->id,
'payment_id' => $response->result->id, 'payment_id' => $response->result->id,
'payer_id' => $laravelRequest->input('PayerID'), 'payment_method' => 'paypal',
'type' => 'Credits', 'type' => 'Credits',
'status' => $response->result->status, 'status' => 'paid',
'amount' => $paypalProduct->quantity, 'amount' => $creditProduct->quantity,
'price' => $paypalProduct->price, 'price' => $creditProduct->price,
'tax_value' => $paypalProduct->getTaxValue(), 'tax_value' => $creditProduct->getTaxValue(),
'tax_percent' => $paypalProduct->getTaxPercent(), 'tax_percent' => $creditProduct->getTaxPercent(),
'total_price' => $paypalProduct->getTotalPrice(), 'total_price' => $creditProduct->getTotalPrice(),
'currency_code' => $paypalProduct->currency_code, 'currency_code' => $creditProduct->currency_code,
'payer' => json_encode($response->result->payer), 'credit_product_id' => $creditProduct->id,
]); ]);
event(new UserUpdateCreditsEvent($user)); event(new UserUpdateCreditsEvent($user));
//create invoice $this->createInvoice($user, $payment, 'paid');
$lastInvoiceID = \App\Models\Invoice::where("invoice_name", "like", "%" . now()->format('mY') . "%")->count("id");
$newInvoiceID = $lastInvoiceID + 1;
$InvoiceSettings = InvoiceSettings::query()->first();
$logoPath = storage_path('app/public/logo.png');
$seller = new Party([
'name' => $InvoiceSettings->company_name,
'phone' => $InvoiceSettings->company_phone,
'address' => $InvoiceSettings->company_adress,
'vat' => $InvoiceSettings->company_vat,
'custom_fields' => [
'E-Mail' => $InvoiceSettings->company_mail,
"Web" => $InvoiceSettings->company_web
],
]);
$customer = new Buyer([
'name' => $user->name,
'custom_fields' => [
'E-Mail' => $user->email,
'Client ID' => $user->id,
],
]);
$item = (new InvoiceItem())
->title($paypalProduct->description)
->pricePerUnit($paypalProduct->price);
$invoice = Invoice::make()
->template('controlpanel')
->name(__("Invoice"))
->buyer($customer)
->seller($seller)
->discountByPercent(0)
->taxRate(floatval($paypalProduct->getTaxPercent()))
->shipping(0)
->addItem($item)
->status(__('Paid'))
->series(now()->format('mY'))
->delimiter("-")
->sequence($newInvoiceID)
->serialNumberFormat($InvoiceSettings->invoice_prefix . '{DELIMITER}{SERIES}{SEQUENCE}');
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));
//redirect back to home //redirect back to home
return redirect()->route('home')->with('success', __('Your credit balance has been increased!')); return redirect()->route('home')->with('success', __('Your credit balance has been increased!'));
@ -267,7 +210,6 @@ class PaymentController extends Controller
} else { } else {
abort(500); abort(500);
} }
} catch (HttpException $ex) { } catch (HttpException $ex) {
if (env('APP_ENV') == 'local') { if (env('APP_ENV') == 'local') {
echo $ex->statusCode; echo $ex->statusCode;
@ -275,20 +217,344 @@ class PaymentController extends Controller
} else { } else {
abort(422); abort(422);
} }
} }
} }
/** /**
* @param Request $request * @param Request $request
*/ */
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('success', 'Payment was Canceled');
} }
/**
* @param Request $request
* @param CreditProduct $creditProduct
* @return RedirectResponse
*/
public function StripePay(Request $request, CreditProduct $creditProduct)
{
$stripeClient = $this->getStripeClient();
$request = $stripeClient->checkout->sessions->create([
'line_items' => [
[
'price_data' => [
'currency' => $creditProduct->currency_code,
'product_data' => [
'name' => $creditProduct->display,
'description' => $creditProduct->description,
],
'unit_amount_decimal' => round($creditProduct->price * 100, 2),
],
'quantity' => 1,
],
[
'price_data' => [
'currency' => $creditProduct->currency_code,
'product_data' => [
'name' => 'Product Tax',
'description' => $creditProduct->getTaxPercent() . "%",
],
'unit_amount_decimal' => round($creditProduct->getTaxValue(), 2) * 100,
],
'quantity' => 1,
]
],
'mode' => 'payment',
"payment_method_types" => str_getcsv(env('STRIPE_METHODS')),
'success_url' => route('payment.StripeSuccess', ['product' => $creditProduct->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 CreditProduct $creditProduct */
$creditProduct = CreditProduct::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 credits
$user->increment('credits', $creditProduct->quantity);
//update server limit
if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
if ($user->server_limit < Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
}
}
//update role
if ($user->role == 'member') {
$user->update(['role' => 'client']);
}
//store paid payment
$payment = Payment::create([
'user_id' => $user->id,
'payment_id' => $paymentSession->payment_intent,
'payment_method' => 'stripe',
'type' => 'Credits',
'status' => 'paid',
'amount' => $creditProduct->quantity,
'price' => $creditProduct->price,
'tax_value' => $creditProduct->getTaxValue(),
'total_price' => $creditProduct->getTotalPrice(),
'tax_percent' => $creditProduct->getTaxPercent(),
'currency_code' => $creditProduct->currency_code,
'credit_product_id' => $creditProduct->id,
]);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
$this->createInvoice($user, $payment, 'paid');
//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' => 'Credits',
'status' => 'processing',
'amount' => $creditProduct->quantity,
'price' => $creditProduct->price,
'tax_value' => $creditProduct->getTaxValue(),
'total_price' => $creditProduct->getTotalPrice(),
'tax_percent' => $creditProduct->getTaxPercent(),
'currency_code' => $creditProduct->currency_code,
'credit_product_id' => $creditProduct->id,
]);
$this->createInvoice($user, $payment, 'processing');
//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') {
// Increment User Credits
$user->increment('credits', $payment->amount);
//update server limit
if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
if ($user->server_limit < Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
$user->update(['server_limit' => Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
}
}
//update role
if ($user->role == 'member') {
$user->update(['role' => 'client']);
}
//update payment db entry status
$payment->update(['status' => 'paid']);
//payment notification
$user->notify(new ConfirmPaymentNotification($payment));
event(new UserUpdateCreditsEvent($user));
$this->createInvoice($user, $payment, 'paid');
}
} 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'
? env('STRIPE_TEST_SECRET')
: env('STRIPE_SECRET');
}
/**
* @return string
*/
protected function getStripeEndpointSecret()
{
return env('APP_ENV') == 'local'
? env('STRIPE_ENDPOINT_TEST_SECRET')
: env('STRIPE_ENDPOINT_SECRET');
}
protected function createInvoice($user, $payment, $paymentStatus)
{
$creditProduct = CreditProduct::where('id', $payment->credit_product_id)->first();
//create invoice
$lastInvoiceID = \App\Models\Invoice::where("invoice_name", "like", "%" . now()->format('mY') . "%")->count("id");
$newInvoiceID = $lastInvoiceID + 1;
$InvoiceSettings = InvoiceSettings::query()->first();
$logoPath = storage_path('app/public/logo.png');
$seller = new Party([
'name' => $InvoiceSettings->company_name,
'phone' => $InvoiceSettings->company_phone,
'address' => $InvoiceSettings->company_adress,
'vat' => $InvoiceSettings->company_vat,
'custom_fields' => [
'E-Mail' => $InvoiceSettings->company_mail,
"Web" => $InvoiceSettings->company_web
],
]);
$customer = new Buyer([
'name' => $user->name,
'custom_fields' => [
'E-Mail' => $user->email,
'Client ID' => $user->id,
],
]);
$item = (new InvoiceItem())
->title($creditProduct->description)
->pricePerUnit($creditProduct->price);
$invoice = Invoice::make()
->template('controlpanel')
->name(__("Invoice"))
->buyer($customer)
->seller($seller)
->discountByPercent(0)
->taxRate(floatval($creditProduct->getTaxPercent()))
->shipping(0)
->addItem($item)
->status(__($paymentStatus))
->series(now()->format('mY'))
->delimiter("-")
->sequence($newInvoiceID)
->serialNumberFormat($InvoiceSettings->invoice_prefix . '{DELIMITER}{SERIES}{SEQUENCE}');
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));
}
/** /**
* @return JsonResponse|mixed * @return JsonResponse|mixed
@ -308,9 +574,13 @@ class PaymentController extends Controller
->editColumn('tax_value', function (Payment $payment) { ->editColumn('tax_value', function (Payment $payment) {
return $payment->formatToCurrency($payment->tax_value); return $payment->formatToCurrency($payment->tax_value);
}) })
->editColumn('tax_percent', function (Payment $payment) {
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 $payment->created_at ? $payment->created_at->diffForHumans() : ''; return $payment->created_at ? $payment->created_at->diffForHumans() : '';
}) })

View file

@ -3,7 +3,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\Configuration; use App\Models\Configuration;
use App\Models\PaypalProduct; use App\Models\CreditProduct;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
class StoreController extends Controller class StoreController extends Controller
@ -11,10 +11,13 @@ class StoreController extends Controller
/** Display a listing of the resource. */ /** Display a listing of the resource. */
public function index() public function index()
{ {
$isPaypalSetup = false; $isPaymentSetup = false;
if (env('PAYPAL_SECRET') && env('PAYPAL_CLIENT_ID')) $isPaypalSetup = true;
if (env('APP_ENV', 'local') == 'local') $isPaypalSetup = true;
if (
env('APP_ENV') == 'local' ||
env('PAYPAL_SECRET') && env('PAYPAL_CLIENT_ID') ||
env('STRIPE_SECRET') && env('STRIPE_ENDPOINT_SECRET') && env('STRIPE_METHODS')
) $isPaymentSetup = true;
//Required Verification for creating an server //Required Verification for creating an server
if (Configuration::getValueByKey('FORCE_EMAIL_VERIFICATION', false) === 'true' && !Auth::user()->hasVerifiedEmail()) { if (Configuration::getValueByKey('FORCE_EMAIL_VERIFICATION', false) === 'true' && !Auth::user()->hasVerifiedEmail()) {
@ -27,8 +30,8 @@ class StoreController extends Controller
} }
return view('store.index')->with([ return view('store.index')->with([
'products' => PaypalProduct::where('disabled', '=', false)->orderBy('price', 'asc')->get(), 'products' => CreditProduct::where('disabled', '=', false)->orderBy('price', 'asc')->get(),
'isPaypalSetup' => $isPaypalSetup 'isPaymentSetup' => $isPaymentSetup,
]); ]);
} }
} }

View file

@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware
* @var array * @var array
*/ */
protected $except = [ protected $except = [
// 'payment/StripeWebhooks'
]; ];
} }

View file

@ -8,7 +8,7 @@ use NumberFormatter;
use Spatie\Activitylog\Traits\LogsActivity; use Spatie\Activitylog\Traits\LogsActivity;
use App\Models\Configuration; use App\Models\Configuration;
class PaypalProduct extends Model class CreditProduct extends Model
{ {
use LogsActivity; use LogsActivity;
/** /**
@ -33,10 +33,10 @@ class PaypalProduct extends Model
{ {
parent::boot(); parent::boot();
static::creating(function (PaypalProduct $paypalProduct) { static::creating(function (CreditProduct $creditProduct) {
$client = new Client(); $client = new Client();
$paypalProduct->{$paypalProduct->getKeyName()} = $client->generateId($size = 21); $creditProduct->{$creditProduct->getKeyName()} = $client->generateId($size = 21);
}); });
} }

View file

@ -23,8 +23,7 @@ class Payment extends Model
'id', 'id',
'user_id', 'user_id',
'payment_id', 'payment_id',
'payer_id', 'payment_method',
'payer',
'status', 'status',
'type', 'type',
'amount', 'amount',
@ -33,6 +32,7 @@ class Payment extends Model
'total_price', 'total_price',
'tax_percent', 'tax_percent',
'currency_code', 'currency_code',
'credit_product_id',
]; ];
public static function boot() public static function boot()
@ -57,10 +57,10 @@ class Payment extends Model
/** /**
* @param mixed $value * @param mixed $value
* @param string $locale * @param string $locale
* *
* @return float * @return float
*/ */
public function formatToCurrency($value,$locale = 'en_US') public function formatToCurrency($value, $locale = 'en_US')
{ {
$formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY); $formatter = new NumberFormatter($locale, NumberFormatter::CURRENCY);
return $formatter->formatCurrency($value, $this->currency_code); return $formatter->formatCurrency($value, $this->currency_code);

View file

@ -1,7 +1,7 @@
{ {
"name": "laravel/laravel", "name": "cpgg/dashboard",
"type": "project", "type": "project",
"description": "The Laravel Framework.", "description": "A billing and control panel made for Pterodactyl.",
"keywords": [ "keywords": [
"framework", "framework",
"laravel" "laravel"
@ -26,6 +26,7 @@
"spatie/laravel-activitylog": "^3.16", "spatie/laravel-activitylog": "^3.16",
"spatie/laravel-query-builder": "^3.6", "spatie/laravel-query-builder": "^3.6",
"spatie/laravel-validation-rules": "^3.0", "spatie/laravel-validation-rules": "^3.0",
"stripe/stripe-php": "^7.107",
"yajra/laravel-datatables-oracle": "~9.0" "yajra/laravel-datatables-oracle": "~9.0"
}, },
"require-dev": { "require-dev": {

2339
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
class CreatePaypalProductsTable extends Migration class CreateCreditProductsTable extends Migration
{ {
/** /**
* Run the migrations. * Run the migrations.
@ -13,7 +13,7 @@ class CreatePaypalProductsTable extends Migration
*/ */
public function up() public function up()
{ {
Schema::create('paypal_products', function (Blueprint $table) { Schema::create('credit_products', function (Blueprint $table) {
$table->uuid('id')->primary(); $table->uuid('id')->primary();
$table->string('type'); $table->string('type');
$table->decimal('price')->default(0); $table->decimal('price')->default(0);
@ -32,6 +32,6 @@ class CreatePaypalProductsTable extends Migration
*/ */
public function down() public function down()
{ {
Schema::dropIfExists('paypal_products'); Schema::dropIfExists('credit_products');
} }
} }

View file

@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
class AddDisplayToPaypalProductsTable extends Migration class AddDisplayToCreditProductsTable extends Migration
{ {
/** /**
* Run the migrations. * Run the migrations.
@ -13,7 +13,7 @@ class AddDisplayToPaypalProductsTable extends Migration
*/ */
public function up() public function up()
{ {
Schema::table('paypal_products', function (Blueprint $table) { Schema::table('credit_products', function (Blueprint $table) {
$table->string('display'); $table->string('display');
}); });
} }
@ -25,7 +25,7 @@ class AddDisplayToPaypalProductsTable extends Migration
*/ */
public function down() public function down()
{ {
Schema::table('paypal_products', function (Blueprint $table) { Schema::table('credit_products', function (Blueprint $table) {
$table->dropColumn('display'); $table->dropColumn('display');
}); });
} }

View file

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class UpdateToPaymentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('payments', function (Blueprint $table) {
$table->string('payment_method');
$table->dropColumn('payer');
$table->dropColumn('payer_id');
$table->string('credit_product_id');
});
DB::statement('UPDATE payments SET payment_method="paypal"');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('payments', function (Blueprint $table) {
$table->dropColumn('payment_method');
$table->string('payer_id')->nullable();
$table->text('payer')->nullable();
$table->dropColumn('credit_product_id');
});
}
}

View file

@ -3,7 +3,7 @@
namespace Database\Seeders; namespace Database\Seeders;
use Database\Seeders\Seeds\ProductSeeder; use Database\Seeders\Seeds\ProductSeeder;
use Database\Seeders\Seeds\PaypalProductSeeder; use Database\Seeders\Seeds\CreditProductSeeder;
use Database\Seeders\Seeds\ApplicationApiSeeder; use Database\Seeders\Seeds\ApplicationApiSeeder;
use Database\Seeders\Seeds\UsefulLinksSeeder; use Database\Seeders\Seeds\UsefulLinksSeeder;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
@ -19,7 +19,7 @@ class ExampleItemsSeeder extends Seeder
{ {
$this->call([ $this->call([
ProductSeeder::class, ProductSeeder::class,
PaypalProductSeeder::class, CreditProductSeeder::class,
ApplicationApiSeeder::class, ApplicationApiSeeder::class,
UsefulLinksSeeder::class UsefulLinksSeeder::class
]); ]);

View file

@ -2,10 +2,10 @@
namespace Database\Seeders\Seeds; namespace Database\Seeders\Seeds;
use App\Models\PaypalProduct; use App\Models\CreditProduct;
use Illuminate\Database\Seeder; use Illuminate\Database\Seeder;
class PaypalProductSeeder extends Seeder class CreditProductSeeder extends Seeder
{ {
/** /**
* Run the database seeds. * Run the database seeds.
@ -14,7 +14,7 @@ class PaypalProductSeeder extends Seeder
*/ */
public function run() public function run()
{ {
PaypalProduct::create([ CreditProduct::create([
'type' => 'Credits', 'type' => 'Credits',
'display' => '350', 'display' => '350',
'description' => 'Adds 350 credits to your account', 'description' => 'Adds 350 credits to your account',
@ -24,7 +24,7 @@ class PaypalProductSeeder extends Seeder
'disabled' => false, 'disabled' => false,
]); ]);
PaypalProduct::create([ CreditProduct::create([
'type' => 'Credits', 'type' => 'Credits',
'display' => '875 + 125', 'display' => '875 + 125',
'description' => 'Adds 1000 credits to your account', 'description' => 'Adds 1000 credits to your account',
@ -34,7 +34,7 @@ class PaypalProductSeeder extends Seeder
'disabled' => false, 'disabled' => false,
]); ]);
PaypalProduct::create([ CreditProduct::create([
'type' => 'Credits', 'type' => 'Credits',
'display' => '1750 + 250', 'display' => '1750 + 250',
'description' => 'Adds 2000 credits to your account', 'description' => 'Adds 2000 credits to your account',
@ -44,7 +44,7 @@ class PaypalProductSeeder extends Seeder
'disabled' => false, 'disabled' => false,
]); ]);
PaypalProduct::create([ CreditProduct::create([
'type' => 'Credits', 'type' => 'Credits',
'display' => '3500 + 500', 'display' => '3500 + 500',
'description' => 'Adds 4000 credits to your account', 'description' => 'Adds 4000 credits to your account',

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -95,8 +95,8 @@
"This is what the user sees at checkout": "Dies ist die Beschreibung auf der Rechnung und was der Kunde beim kauf sieht", "This is what the user sees at checkout": "Dies ist die Beschreibung auf der Rechnung und was der Kunde beim kauf sieht",
"Adds 1000 credits to your account": "Fügt deinem Account 1000 Credits hinzu", "Adds 1000 credits to your account": "Fügt deinem Account 1000 Credits hinzu",
"Active": "Aktiv", "Active": "Aktiv",
"Paypal is not configured.": "Paypal ist nicht konfiguriert!", "No payment method is configured.": "Keine Bezahlmethode konfiguriert!",
"To configure PayPal, head to the .env and add your PayPals client id and secret.": "Um Paypal zu konfigurieren, füge deine Paypal client ID und Secretkey in deine .env-Datei hinzu", "To configure the payment methods, head to the .env and add the required options for your prefered payment method.": "Um die Bezahlmethoden einzustellen, setze die passenden Variablen, für eine oder mehrere Bezahlmethoden, in der .env",
"Useful Links": "Nützliche Links", "Useful Links": "Nützliche Links",
"Icon class name": "Icon Klassen-Name", "Icon class name": "Icon Klassen-Name",
"You can find available free icons": "Hier gibt es kostenlose Icons", "You can find available free icons": "Hier gibt es kostenlose Icons",

View file

@ -106,8 +106,8 @@
"Adds 1000 credits to your account": "Adds 1000 credits to your account", "Adds 1000 credits to your account": "Adds 1000 credits to your account",
"Active": "Active", "Active": "Active",
"Paypal is not configured.": "Paypal is not configured.", "No payment method is configured.": "No payment method is configured.",
"To configure PayPal, head to the .env and add your PayPals client id and secret.": "To configure PayPal, head to the .env and add your PayPals client id and secret.", "To configure the payment methods, head to the .env and add the required options for your prefered payment method.": "To configure the payment methods, head to the .env and add the required options for your prefered payment method.",
"Useful Links": "Useful Links", "Useful Links": "Useful Links",
"Icon class name": "Icon class name", "Icon class name": "Icon class name",
@ -164,7 +164,7 @@
"You forgot your password? Here you can easily retrieve a new password.": "You forgot your password? Here you can easily retrieve a new password.", "You forgot your password? Here you can easily retrieve a new password.": "You forgot your password? Here you can easily retrieve a new password.",
"Request new password": "Request new password", "Request new password": "Request new password",
"Login": "Login", "Login": "Login",
"You are only one step a way from your new password, recover your password now.":"You are only one step a way from your new password, recover your password now.", "You are only one step a way from your new password, recover your password now.": "You are only one step a way from your new password, recover your password now.",
"Retype password": "Retype password", "Retype password": "Retype password",
"Change password": "Change password", "Change password": "Change password",
"I already have a membership": "I already have a membership", "I already have a membership": "I already have a membership",
@ -364,8 +364,6 @@
"Amount due": "Amount due", "Amount due": "Amount due",
"Your Payment was successful!": "Your Payment was successful!", "Your Payment was successful!": "Your Payment was successful!",
"Hello":"Hello", "Hello": "Hello",
"Your payment was processed successfully!":"Your payment was processed successfully!" "Your payment was processed successfully!": "Your payment was processed successfully!"
} }

View file

@ -26,25 +26,24 @@
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title"><i class="fas fa-money-bill-wave mr-2"></i>{{__('Payments')}}</h5> <h5 class="card-title"><i class="fas fa-money-bill-wave mr-2"></i>{{ __('Payments') }}</h5>
</div> </div>
<div class="card-body table-responsive"> <div class="card-body table-responsive">
<table id="datatable" class="table table-striped"> <table id="datatable" class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>{{__('ID')}}</th> <th>{{ __('ID') }}</th>
<th>{{__('User')}}</th> <th>{{ __('Type') }}</th>
<th>{{__('Type')}}</th> <th>{{ __('Amount') }}</th>
<th>{{__('Amount')}}</th> <th>{{ __('Product Price') }}</th>
<th>{{__('Product Price')}}</th> <th>{{ __('Tax Value') }}</th>
<th>{{__('Tax')}}</th> <th>{{ __('Tax Percentage') }}</th>
<th>{{__('Tax')}}(%)</th> <th>{{ __('Total Price') }}</th>
<th>{{__('Total Price')}}</th> <th>{{ __('Payment ID') }}</th>
<th>{{__('Payment_ID')}}</th> <th>{{ __('Payment Method') }}</th>
<th>{{__('Payer_ID')}}</th> <th>{{ __('Created at') }}</th>
<th>{{__('Created at')}}</th> </tr>
</tr>
</thead> </thead>
<tbody> <tbody>
</tbody> </tbody>
@ -59,7 +58,7 @@
<!-- END CONTENT --> <!-- END CONTENT -->
<script> <script>
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function() {
$('#datatable').DataTable({ $('#datatable').DataTable({
language: { language: {
url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{config("app.datatable_locale")}}.json' url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{config("app.datatable_locale")}}.json'
@ -67,10 +66,9 @@
processing: true, processing: true,
serverSide: true, serverSide: true,
stateSave: true, stateSave: true,
ajax: "{{route('admin.payments.datatable')}}", ajax: "{{ route('admin.payments.datatable') }}",
columns: [ columns: [
{data: 'id' , name : 'payments.id'}, {data: 'id',name: 'payments.id'},
{data: 'user', sortable: false},
{data: 'type'}, {data: 'type'},
{data: 'amount'}, {data: 'amount'},
{data: 'price'}, {data: 'price'},
@ -78,12 +76,12 @@
{data: 'tax_percent'}, {data: 'tax_percent'},
{data: 'total_price'}, {data: 'total_price'},
{data: 'payment_id'}, {data: 'payment_id'},
{data: 'payer_id'}, {data: 'payment_method'},
{data: 'created_at'}, {data: 'created_at'},
], ],
fnDrawCallback: function( oSettings ) { fnDrawCallback: function(oSettings) {
$('[data-toggle="popover"]').popover(); $('[data-toggle="popover"]').popover();
} },
}); });
}); });
</script> </script>

View file

@ -6,14 +6,14 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-sm-6"> <div class="col-sm-6">
<h1>{{__('Store')}}</h1> <h1>{{ __('Store') }}</h1>
</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 href="{{route('home')}}">{{__('Dashboard')}}</a></li> <li class="breadcrumb-item"><a href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
<li class="breadcrumb-item"><a href="{{route('admin.store.index')}}">{{__('Store')}}</a></li> <li class="breadcrumb-item"><a href="{{ route('admin.store.index') }}">{{ __('Store') }}</a></li>
<li class="breadcrumb-item"><a class="text-muted" <li class="breadcrumb-item"><a class="text-muted"
href="{{route('admin.store.edit' , $paypalProduct->id)}}">{{__('Edit')}}</a> href="{{ route('admin.store.edit', $creditProduct->id) }}">{{ __('Edit') }}</a>
</li> </li>
</ol> </ol>
</div> </div>
@ -30,127 +30,115 @@
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<form action="{{route('admin.store.update' , $paypalProduct->id)}}" method="POST"> <form action="{{ route('admin.store.update', $creditProduct->id) }}" method="POST">
@csrf @csrf
@method('PATCH') @method('PATCH')
<div class="d-flex flex-row-reverse"> <div class="d-flex flex-row-reverse">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input type="checkbox" @if($paypalProduct->disabled) checked <input type="checkbox" @if ($creditProduct->disabled) checked @endif name="disabled"
@endif name="disabled" class="custom-control-input custom-control-input-danger" id="switch1">
class="custom-control-input custom-control-input-danger" <label class="custom-control-label" for="switch1">{{ __('Disabled') }} <i
id="switch1"> data-toggle="popover" data-trigger="hover"
<label class="custom-control-label" for="switch1">{{__('Disabled')}} <i data-content="{{ __('Will hide this option from being selected') }}"
data-toggle="popover"
data-trigger="hover"
data-content="{{__('Will hide this option from being selected')}}"
class="fas fa-info-circle"></i></label> class="fas fa-info-circle"></i></label>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="type">{{__('Type')}}</label> <label for="type">{{ __('Type') }}</label>
<select required name="type" id="type" <select required name="type" id="type"
class="custom-select @error('name') is-invalid @enderror"> class="custom-select @error('name') is-invalid @enderror">
<option selected value="Credits">{{CREDITS_DISPLAY_NAME}}</option> <option selected value="Credits">{{ CREDITS_DISPLAY_NAME }}</option>
</select> </select>
@error('name') @error('name')
<div class="text-danger"> <div class="text-danger">
{{$message}} {{ $message }}
</div> </div>
@enderror @enderror
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="currency_code">{{__('Currency code')}}</label> <label for="currency_code">{{ __('Currency code') }}</label>
<select required name="currency_code" id="currency_code" <select required name="currency_code" id="currency_code"
class="custom-select @error('name') is-invalid @enderror"> class="custom-select @error('name') is-invalid @enderror">
@foreach($currencyCodes as $code) @foreach ($currencyCodes as $code)
<option @if($paypalProduct->currency_code == $code) selected <option @if ($creditProduct->currency_code == $code) selected @endif value="{{ $code }}">
@endif value="{{$code}}">{{$code}}</option> {{ $code }}</option>
@endforeach @endforeach
</select> </select>
@error('currency_code') @error('currency_code')
<div class="text-danger"> <div class="text-danger">
{{$message}} {{ $message }}
</div> </div>
@enderror @enderror
<div class="text-muted"> <div class="text-muted">
{{__('Checkout the paypal docs to select the appropriate code')}} <a {{ __('Checkout the paypal docs to select the appropriate code') }} <a
target="_blank" target="_blank"
href="https://developer.paypal.com/docs/api/reference/currency-codes/">link</a> href="https://developer.paypal.com/docs/api/reference/currency-codes/">link</a>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="price">{{__('Price')}}</label> <label for="price">Price</label>
<input value="{{$paypalProduct->price}}" id="price" name="price" <input value="{{ $creditProduct->price }}" id="price" name="price" type="number"
type="number" placeholder="10.00" step="any"
placeholder="10.00" class="form-control @error('price') is-invalid @enderror" required="required">
step="any"
class="form-control @error('price') is-invalid @enderror"
required="required">
@error('price') @error('price')
<div class="invalid-feedback"> <div class="invalid-feedback">
{{$message}} {{ $message }}
</div> </div>
@enderror @enderror
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="quantity">{{__('Quantity')}}</label> <label for="quantity">Quantity</label>
<input value="{{$paypalProduct->quantity}}" id="quantity" name="quantity" <input value="{{ $creditProduct->quantity }}" id="quantity" name="quantity"
type="number" type="number" placeholder="1000"
placeholder="1000" class="form-control @error('quantity') is-invalid @enderror" required="required">
class="form-control @error('quantity') is-invalid @enderror"
required="required">
@error('quantity') @error('quantity')
<div class="invalid-feedback"> <div class="invalid-feedback">
{{$message}} {{ $message }}
</div> </div>
@enderror @enderror
<div class="text-muted"> <div class="text-muted">
{{__('Amount given to the user after purchasing')}} {{ __('Amount given to the user after purchasing') }}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="display">{{__('Display')}}</label> <label for="display">Display</label>
<input value="{{$paypalProduct->display}}" id="display" name="display" <input value="{{ $creditProduct->display }}" id="display" name="display" type="text"
type="text" placeholder="750 + 250" class="form-control @error('display') is-invalid @enderror"
placeholder="750 + 250" required="required">
class="form-control @error('display') is-invalid @enderror"
required="required">
@error('display') @error('display')
<div class="invalid-feedback"> <div class="invalid-feedback">
{{$message}} {{ $message }}
</div> </div>
@enderror @enderror
<div class="text-muted"> <div class="text-muted">
{{__('This is what the user sees at store and checkout')}} {{ __('This is what the user sees at store and checkout') }}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="description">{{__('Description')}}</label> <label for="description">Description</label>
<input value="{{$paypalProduct->description}}" id="description" name="description" <input value="{{ $creditProduct->description }}" id="description" name="description"
type="text" type="text" placeholder="{{ __('Adds 1000 credits to your account') }}"
placeholder="{{__('Adds 1000 credits to your account')}}" class="form-control @error('description') is-invalid @enderror" required="required">
class="form-control @error('description') is-invalid @enderror"
required="required">
@error('description') @error('description')
<div class="invalid-feedback"> <div class="invalid-feedback">
{{$message}} {{ $message }}
</div> </div>
@enderror @enderror
<div class="text-muted"> <div class="text-muted">
{{__('This is what the user sees at checkout')}} {{ __('This is what the user sees at checkout') }}
</div> </div>
</div> </div>
<div class="form-group text-right"> <div class="form-group text-right">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary">
{{__('Submit')}} {{ __('Submit') }}
</button> </button>
</div> </div>
</form> </form>

View file

@ -6,13 +6,13 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-sm-6"> <div class="col-sm-6">
<h1>{{__('Store')}}</h1> <h1>{{ __('Store') }}</h1>
</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 href="{{route('home')}}">{{__('Dashboard')}}</a></li> <li class="breadcrumb-item"><a href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
<li class="breadcrumb-item"><a class="text-muted" <li class="breadcrumb-item"><a class="text-muted"
href="{{route('admin.store.index')}}">{{__('Store')}}</a></li> href="{{ route('admin.store.index') }}">{{ __('Store') }}</a></li>
</ol> </ol>
</div> </div>
</div> </div>
@ -26,12 +26,14 @@
<div class="row"> <div class="row">
<div class="col-lg-4"> <div class="col-lg-4">
@if($isPaypalSetup == false) @if ($isPaymentSetup == false)
<div class="callout callout-danger"> <div class="callout callout-danger">
<h4>{{__('Paypal is not configured.')}}</h4> <h4>{{ __('No payment method is configured.') }}</h4>
<p>{{__('To configure PayPal, head to the .env and add your PayPals client id and secret.')}}</p> <p>{{ __('To configure the payment methods, head to the .env and add the required options for your prefered payment method.') }}
</p>
</div> </div>
@endif @endif
</div> </div>
</div> </div>
@ -39,9 +41,9 @@
<div class="card-header"> <div class="card-header">
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<h5 class="card-title"><i class="fas fa-sliders-h mr-2"></i>{{__('Store')}}</h5> <h5 class="card-title"><i class="fas fa-sliders-h mr-2"></i>{{ __('Store') }}</h5>
<a href="{{route('admin.store.create')}}" class="btn btn-sm btn-primary"><i <a href="{{ route('admin.store.create') }}" class="btn btn-sm btn-primary"><i
class="fas fa-plus mr-1"></i>{{__('Create new')}}</a> class="fas fa-plus mr-1"></i>{{ __('Create new') }}</a>
</div> </div>
</div> </div>
@ -49,15 +51,15 @@
<table id="datatable" class="table table-striped"> <table id="datatable" class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>{{__('Active')}}</th> <th>{{ __('Active') }}</th>
<th>{{__('Type')}}</th> <th>{{ __('Type') }}</th>
<th>{{__('Price')}}</th> <th>{{ __('Price') }}</th>
<th>{{__('Display')}}</th> <th>{{ __('Display') }}</th>
<th>{{__('Description')}}</th> <th>{{ __('Description') }}</th>
<th>{{__('Created at')}}</th> <th>{{ __('Created at') }}</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
</tbody> </tbody>
@ -78,26 +80,42 @@
return confirm("Are you sure you wish to delete?") !== false; return confirm("Are you sure you wish to delete?") !== false;
} }
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function() {
$('#datatable').DataTable({ $('#datatable').DataTable({
language: { language: {
url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{config("app.datatable_locale")}}.json' url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{ config('app.datatable_locale') }}.json'
}, },
processing: true, processing: true,
serverSide: true, serverSide: true,
stateSave: true, stateSave: true,
ajax: "{{route('admin.store.datatable')}}", ajax: "{{ route('admin.store.datatable') }}",
order: [[ 2, "desc" ]], order: [
columns: [ [2, "desc"]
{data: 'disabled'},
{data: 'type'},
{data: 'price'},
{data: 'display'},
{data: 'description'},
{data: 'created_at'},
{data: 'actions', sortable: false},
], ],
fnDrawCallback: function( oSettings ) { columns: [{
data: 'disabled'
},
{
data: 'type'
},
{
data: 'price'
},
{
data: 'display'
},
{
data: 'description'
},
{
data: 'created_at'
},
{
data: 'actions',
sortable: false
},
],
fnDrawCallback: function(oSettings) {
$('[data-toggle="popover"]').popover(); $('[data-toggle="popover"]').popover();
} }
}); });

View file

@ -6,12 +6,15 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-sm-6"> <div class="col-sm-6">
<h1>{{__('Store')}}</h1> <h1>{{ __('Store') }}</h1>
</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="" href="{{route('home')}}">{{__('Dashboard')}}</a></li> <li class="breadcrumb-item"><a class=""
<li class="breadcrumb-item"><a class="text-muted" href="{{route('store.index')}}">{{__('Store')}}</a></li> href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
<li class="breadcrumb-item"><a class="text-muted"
href="{{ route('store.index') }}">{{ __('Store') }}</a>
</li>
</ol> </ol>
</div> </div>
</div> </div>
@ -20,7 +23,7 @@
<!-- END CONTENT HEADER --> <!-- END CONTENT HEADER -->
<!-- MAIN CONTENT --> <!-- MAIN CONTENT -->
<section class="content"> <section x-data="serverApp()" x-init="$watch('paymentMethod', value => setPaymentRoute(value))" class="content">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
@ -34,7 +37,8 @@
<div class="col-12"> <div class="col-12">
<h4> <h4>
<i class="fas fa-globe"></i> {{ config('app.name', 'Laravel') }} <i class="fas fa-globe"></i> {{ config('app.name', 'Laravel') }}
<small class="float-right">{{__('Date')}}: {{Carbon\Carbon::now()->isoFormat('LL')}}</small> <small class="float-right">{{ __('Date') }}:
{{ Carbon\Carbon::now()->isoFormat('LL') }}</small>
</h4> </h4>
</div> </div>
<!-- /.col --> <!-- /.col -->
@ -42,25 +46,25 @@
<!-- info row --> <!-- info row -->
<div class="row invoice-info"> <div class="row invoice-info">
<div class="col-sm-4 invoice-col"> <div class="col-sm-4 invoice-col">
{{__('To')}} {{ __('To') }}
<address> <address>
<strong>{{config('app.name' , 'Laravel')}}</strong><br> <strong>{{ config('app.name', 'Controlpanel.GG') }}</strong><br>
{{__('Email')}}: {{env('PAYPAL_EMAIL' , env('MAIL_FROM_NAME'))}} {{ __('Email') }}: {{ env('PAYPAL_EMAIL', env('MAIL_FROM_NAME')) }}
</address> </address>
</div> </div>
<!-- /.col --> <!-- /.col -->
<div class="col-sm-4 invoice-col"> <div class="col-sm-4 invoice-col">
{{__('From')}} {{ __('From') }}
<address> <address>
<strong>{{Auth::user()->name}}</strong><br> <strong>{{ Auth::user()->name }}</strong><br>
{{__('Email')}}: {{Auth::user()->email}} {{ __('Email') }}: {{ Auth::user()->email }}
</address> </address>
</div> </div>
<!-- /.col --> <!-- /.col -->
<div class="col-sm-4 invoice-col"> <div class="col-sm-4 invoice-col">
<b>{{__('Status')}}</b><br> <b>{{ __('Status') }}</b><br>
<span class="badge badge-warning">{{__('Pending')}}</span><br> <span class="badge badge-warning">{{ __('Pending') }}</span><br>
{{-- <b>Order ID:</b> 4F3S8J<br>--}} {{-- <b>Order ID:</b> 4F3S8J<br> --}}
</div> </div>
<!-- /.col --> <!-- /.col -->
</div> </div>
@ -71,20 +75,22 @@
<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}} {{strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type}}</td> <td><i class="fa fa-coins mr-2"></i>{{ $product->quantity }}
<td>{{$product->description}}</td> {{ strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type }}
<td>{{$product->formatToCurrency($product->price)}}</td> </td>
</tr> <td>{{ $product->description }}</td>
<td>{{ $product->formatToCurrency($product->price) }}</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
@ -95,35 +101,53 @@
<div class="row"> <div class="row">
<!-- accepted payments column --> <!-- accepted payments column -->
<div class="col-6"> <div class="col-6">
<p class="lead">{{__('Payment Methods')}}:</p> <p class="lead">{{ __('Payment Methods') }}:</p>
<img src="https://www.paypalobjects.com/digitalassets/c/website/logo/full-text/pp_fc_hl.svg" alt="Paypal"> <div>
@if (env('PAYPAL_SANDBOX_SECRET') || env('PAYPAL_SECRET'))
<label class="text-center " for="paypal">
<img class="mb-3" height="50"
src="{{ url('/images/paypal_logo.png') }}"></br>
<input x-model="paymentMethod" type="radio" id="paypal" value="paypal"
name="payment_method">
</input>
</label>
@endif
@if (env('STRIPE_TEST_SECRET') || env('STRIPE_SECRET'))
<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>
<p class="text-muted well well-sm shadow-none" style="margin-top: 10px;">
{{__('By purchasing this product you agree and accept our terms of service')}}</a>
</p>
</div> </div>
<!-- /.col --> <!-- /.col -->
<div class="col-6"> <div class="col-6">
<p class="lead">{{__('Amount due')}} {{Carbon\Carbon::now()->isoFormat('LL')}}</p> <p class="lead">{{ __('Amount Due') }}
{{ Carbon\Carbon::now()->isoFormat('LL') }}</p>
<div class="table-responsive"> <div class="table-responsive">
<table class="table"> <table class="table">
<tr> <tr>
<th style="width:50%">{{__('Subtotal')}}:</th> <th style="width:50%">{{ __('Subtotal') }}:</th>
<td>{{$product->formatToCurrency($product->price)}}</td> <td>{{ $product->formatToCurrency($product->price) }}</td>
</tr> </tr>
<tr> <tr>
<th>{{__('Tax')}} ({{$taxpercent}}%)</th> <th>{{ __('Tax') }} ({{ $taxpercent }}%)</th>
<td>{{$product->formatToCurrency($taxvalue)}}</td> <td>{{ $product->formatToCurrency($taxvalue) }}</td>
</tr> </tr>
<tr> <tr>
<th>{{__('Quantity')}}:</th> <th>{{ __('Quantity') }}:</th>
<td>1</td> <td>1</td>
</tr> </tr>
<tr> <tr>
<th>{{__('Total')}}:</th> <th>{{ __('Total') }}:</th>
<td>{{$product->formatToCurrency($total)}}</td> <td>{{ $product->formatToCurrency($total) }}</td>
</tr> </tr>
</table> </table>
</div> </div>
@ -135,7 +159,10 @@
<!-- this row will not appear when printing --> <!-- this row will not appear when printing -->
<div class="row no-print"> <div class="row no-print">
<div class="col-12"> <div class="col-12">
<a href="{{route('payment.pay' , $product->id)}}" type="button" class="btn btn-success float-right"><i class="far fa-credit-card mr-2"></i> {{__('Submit Payment')}} <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> </a>
</div> </div>
</div> </div>
@ -143,10 +170,35 @@
<!-- /.invoice --> <!-- /.invoice -->
</div><!-- /.col --> </div><!-- /.col -->
</div><!-- /.row --> </div><!-- /.row -->
</div> </div>
</section> </section>
<!-- END CONTENT --> <!-- END CONTENT -->
<script>
function serverApp() {
return {
//loading
paymentMethod: '',
paymentRoute: '',
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 @endsection

View file

@ -1,5 +1,5 @@
@extends('layouts.main') @extends('layouts.main')
<?php use App\Models\PaypalProduct; ?> <?php use App\Models\CreditProduct; ?>
@section('content') @section('content')
<!-- CONTENT HEADER --> <!-- CONTENT HEADER -->
@ -7,12 +7,14 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-sm-6"> <div class="col-sm-6">
<h1>{{__('Store')}}</h1> <h1>{{ __('Store') }}</h1>
</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="" href="{{route('home')}}">{{__('Dashboard')}}</a></li> <li class="breadcrumb-item"><a class=""
<li class="breadcrumb-item"><a class="text-muted" href="{{route('store.index')}}">{{__('Store')}}</a></li> href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
<li class="breadcrumb-item"><a class="text-muted"
href="{{ route('store.index') }}">{{ __('Store') }}</a></li>
</ol> </ol>
</div> </div>
</div> </div>
@ -26,37 +28,40 @@
<div class="text-right mb-3"> <div class="text-right mb-3">
<button type="button" data-toggle="modal" data-target="#redeemVoucherModal" class="btn btn-primary"> <button type="button" data-toggle="modal" data-target="#redeemVoucherModal" class="btn btn-primary">
<i class="fas fa-money-check-alt mr-2"></i>{{__('Redeem code')}} <i class="fas fa-money-check-alt mr-2"></i>{{ __('Redeem code') }}
</button> </button>
</div> </div>
@if($isPaypalSetup && $products->count() > 0) @if ($isPaymentSetup && $products->count() > 0)
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h5 class="card-title"><i class="fa fa-coins mr-2"></i>{{CREDITS_DISPLAY_NAME}}</h5> <h5 class="card-title"><i class="fa fa-coins mr-2"></i>{{ CREDITS_DISPLAY_NAME }}</h5>
</div> </div>
<div class="card-body"> <div class="card-body">
<table class="table table-striped table-responsive-sm"> <table class="table table-striped table-responsive-sm">
<thead> <thead>
<tr> <tr>
<th>{{__('Price')}}</th> <th>{{ __('Price') }}</th>
<th>{{__('Type')}}</th> <th>{{ __('Type') }}</th>
<th>{{__('Description')}}</th> <th>{{ __('Description') }}</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php /** @var $product PaypalProduct */?> <?php /** @var $product CreditProduct */
@foreach($products as $product) ?>
<tr> @foreach ($products as $product)
<td>{{$product->formatToCurrency($product->price)}}</td> <tr>
<td>{{strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type}}</td> <td>{{ $product->formatToCurrency($product->price) }}</td>
<td><i class="fa fa-coins mr-2"></i>{{$product->display}}</td> <td>{{ strtolower($product->type) == 'credits' ? CREDITS_DISPLAY_NAME : $product->type }}
<td><a href="{{route('checkout' , $product->id)}}" class="btn btn-info">{{__('Purchase')}}</a> </td>
</td> <td><i class="fa fa-coins mr-2"></i>{{ $product->display }}</td>
</tr> <td><a href="{{ route('checkout', $product->id) }}"
@endforeach class="btn btn-info">{{ __('Purchase') }}</a>
</td>
</tr>
@endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
@ -65,7 +70,7 @@
@else @else
<div class="alert alert-danger alert-dismissible"> <div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h4><i class="icon fa fa-ban"></i> @if($products->count() == 0) {{__('There are no store products!')}} @else {{__('The store is not correctly configured!')}} @endif <h4><i class="icon fa fa-ban"></i> @if ($products->count() == 0) {{ __('There are no store products!') }} @else {{ __('The store is not correctly configured!') }} @endif
</h4> </h4>
</div> </div>

View file

@ -5,7 +5,7 @@ use App\Http\Controllers\Admin\ApplicationApiController;
use App\Http\Controllers\Admin\ConfigurationController; use App\Http\Controllers\Admin\ConfigurationController;
use App\Http\Controllers\Admin\OverViewController; use App\Http\Controllers\Admin\OverViewController;
use App\Http\Controllers\Admin\PaymentController; use App\Http\Controllers\Admin\PaymentController;
use App\Http\Controllers\Admin\PaypalProductController; use App\Http\Controllers\Admin\CreditProductController;
use App\Http\Controllers\Admin\ProductController; use App\Http\Controllers\Admin\ProductController;
use App\Http\Controllers\Admin\ServerController as AdminServerController; use App\Http\Controllers\Admin\ServerController as AdminServerController;
use App\Http\Controllers\Admin\SettingsController; use App\Http\Controllers\Admin\SettingsController;
@ -40,6 +40,9 @@ 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::middleware(['auth', 'checkSuspended'])->group(function () { Route::middleware(['auth', 'checkSuspended'])->group(function () {
#resend verification email #resend verification email
Route::get('/email/verification-notification', function (Request $request) { Route::get('/email/verification-notification', function (Request $request) {
@ -61,10 +64,14 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
Route::get('/products/products/{egg?}/{node?}', [FrontProductController::class, 'getProductsBasedOnNode'])->name('products.products.node'); Route::get('/products/products/{egg?}/{node?}', [FrontProductController::class, 'getProductsBasedOnNode'])->name('products.products.node');
#payments #payments
Route::get('checkout/{paypalProduct}', [PaymentController::class, 'checkOut'])->name('checkout'); Route::get('checkout/{creditProduct}', [PaymentController::class, 'checkOut'])->name('checkout');
Route::get('payment/success', [PaymentController::class, 'success'])->name('payment.success'); Route::get('payment/PaypalPay/{creditProduct}', [PaymentController::class, 'PaypalPay'])->name('payment.PaypalPay');
Route::get('payment/cancel', [PaymentController::class, 'cancel'])->name('payment.cancel'); Route::get('payment/PaypalSuccess', [PaymentController::class, 'PaypalSuccess'])->name('payment.PaypalSuccess');
Route::get('payment/pay/{paypalProduct}', [PaymentController::class, 'pay'])->name('payment.pay'); Route::get('payment/StripePay/{creditProduct}', [PaymentController::class, 'StripePay'])->name('payment.StripePay');
Route::get('payment/StripeSuccess', [PaymentController::class, 'StripeSuccess'])->name('payment.StripeSuccess');
Route::get('payment/Cancel', [PaymentController::class, 'Cancel'])->name('payment.Cancel');
Route::get('users/logbackin', [UserController::class, 'logBackIn'])->name('users.logbackin'); Route::get('users/logbackin', [UserController::class, 'logBackIn'])->name('users.logbackin');
@ -100,10 +107,10 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
Route::patch('products/disable/{product}', [ProductController::class, 'disable'])->name('products.disable'); Route::patch('products/disable/{product}', [ProductController::class, 'disable'])->name('products.disable');
Route::resource('products', ProductController::class); Route::resource('products', ProductController::class);
Route::get('store/datatable', [PaypalProductController::class, 'datatable'])->name('store.datatable'); Route::get('store/datatable', [CreditProductController::class, 'datatable'])->name('store.datatable');
Route::patch('store/disable/{paypalProduct}', [PaypalProductController::class, 'disable'])->name('store.disable'); Route::patch('store/disable/{creditProduct}', [CreditProductController::class, 'disable'])->name('store.disable');
Route::resource('store', PaypalProductController::class)->parameters([ Route::resource('store', CreditProductController::class)->parameters([
'store' => 'paypalProduct', 'store' => 'creditProduct',
]); ]);
Route::get('payments/datatable', [PaymentController::class, 'datatable'])->name('payments.datatable'); Route::get('payments/datatable', [PaymentController::class, 'datatable'])->name('payments.datatable');