diff --git a/app/Events/PaymentEvent.php b/app/Events/PaymentEvent.php new file mode 100644 index 00000000..11711200 --- /dev/null +++ b/app/Events/PaymentEvent.php @@ -0,0 +1,31 @@ +user = $user; + $this->payment = $payment; + $this->shopProduct = $shopProduct; + } +} diff --git a/app/Extensions/PaymentGateways/PayPal/index.php b/app/Extensions/PaymentGateways/PayPal/index.php new file mode 100644 index 00000000..aeb2310b --- /dev/null +++ b/app/Extensions/PaymentGateways/PayPal/index.php @@ -0,0 +1,216 @@ +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"), + ], + ], + ]; +} diff --git a/app/Extensions/PaymentGateways/PayPal/web_routes.php b/app/Extensions/PaymentGateways/PayPal/web_routes.php new file mode 100644 index 00000000..56497768 --- /dev/null +++ b/app/Extensions/PaymentGateways/PayPal/web_routes.php @@ -0,0 +1,18 @@ +group(function () { + Route::get('payment/PayPalPay/{shopProduct}', function () { + PaypalPay(request()); + })->name('payment.PayPalPay'); + + Route::get( + 'payment/PayPalSuccess', + function () { + PaypalSuccess(request()); + } + )->name('payment.PayPalSuccess'); +}); diff --git a/app/Extensions/PaymentGateways/Stripe/index.php b/app/Extensions/PaymentGateways/Stripe/index.php new file mode 100644 index 00000000..ea0369e8 --- /dev/null +++ b/app/Extensions/PaymentGateways/Stripe/index.php @@ -0,0 +1,402 @@ +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"), + ], + ]; +} diff --git a/app/Extensions/PaymentGateways/Stripe/web_routes.php b/app/Extensions/PaymentGateways/Stripe/web_routes.php new file mode 100644 index 00000000..adf481da --- /dev/null +++ b/app/Extensions/PaymentGateways/Stripe/web_routes.php @@ -0,0 +1,23 @@ +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'); diff --git a/app/Helpers/ExtensionHelper.php b/app/Helpers/ExtensionHelper.php new file mode 100644 index 00000000..884b9f2f --- /dev/null +++ b/app/Helpers/ExtensionHelper.php @@ -0,0 +1,47 @@ +name = $config['name']; + $payment->image = asset('images/Extensions/PaymentGateways/' . strtolower($extensionName) . '_logo.png'); + $paymentGateways[] = $payment; + } + } + return view('store.checkout')->with([ 'product' => $shopProduct, 'discountpercent' => PartnerDiscount::getDiscount(), @@ -59,6 +62,7 @@ class PaymentController extends Controller 'taxvalue' => $shopProduct->getTaxValue(), 'taxpercent' => $shopProduct->getTaxPercent(), 'total' => $shopProduct->getTotalPrice(), + 'paymentGateways' => $paymentGateways, ]); } @@ -67,11 +71,10 @@ class PaymentController extends Controller * @param ShopProduct $shopProduct * @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% - 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 /** @var User $user */ @@ -80,9 +83,9 @@ class PaymentController extends Controller //not updating server limit //update User with bought item - if ($shopProduct->type=="Credits") { + if ($shopProduct->type == "Credits") { $user->increment('credits', $shopProduct->quantity); - }elseif ($shopProduct->type=="Server slots"){ + } elseif ($shopProduct->type == "Server slots") { $user->increment('server_limit', $shopProduct->quantity); } @@ -98,7 +101,7 @@ class PaymentController extends Controller 'type' => $shopProduct->type, 'status' => 'paid', 'amount' => $shopProduct->quantity, - 'price' => $shopProduct->price - ($shopProduct->price*PartnerDiscount::getDiscount()/100), + 'price' => $shopProduct->price - ($shopProduct->price * PartnerDiscount::getDiscount() / 100), 'tax_value' => $shopProduct->getTaxValue(), 'tax_percent' => $shopProduct->getTaxPercent(), 'total_price' => $shopProduct->getTotalPrice(), @@ -114,196 +117,12 @@ class PaymentController extends Controller return redirect()->route('home')->with('success', __('Your credit balance has been increased!')); } - /** - * @param Request $request - * @param ShopProduct $shopProduct - * @return RedirectResponse - */ - public function PaypalPay(Request $request, ShopProduct $shopProduct) + public function pay(Request $request) { - 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.')); - $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', ['product' => $shopProduct->id]), - 'brand_name' => config('app.name', 'Laravel'), - 'shipping_preference' => 'NO_SHIPPING', - ], + $product = ShopProduct::find($request->product_id); + $paymentGateway = $request->payment_method; - ]; - - 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); - } - } + return redirect()->route('payment.' . $paymentGateway . 'Pay', ['shopProduct' => $product->id]); } /** @@ -311,491 +130,9 @@ class PaymentController extends Controller */ 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('
', $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 * @@ -808,9 +145,7 @@ class PaymentController extends Controller return datatables($query) ->addColumn('user', function (Payment $payment) { - return - ($payment->user)?''.$payment->user->name.'':__('Unknown user'); - + return ($payment->user) ? '' . $payment->user->name . '' : __('Unknown user'); }) ->editColumn('price', function (Payment $payment) { return $payment->formatToCurrency($payment->price); @@ -819,18 +154,20 @@ class PaymentController extends Controller return $payment->formatToCurrency($payment->tax_value); }) ->editColumn('tax_percent', function (Payment $payment) { - return $payment->tax_percent.' %'; + return $payment->tax_percent . ' %'; }) ->editColumn('total_price', function (Payment $payment) { return $payment->formatToCurrency($payment->total_price); }) ->editColumn('created_at', function (Payment $payment) { - return ['display' => $payment->created_at ? $payment->created_at->diffForHumans() : '', - 'raw' => $payment->created_at ? strtotime($payment->created_at) : '']; + return [ + 'display' => $payment->created_at ? $payment->created_at->diffForHumans() : '', + 'raw' => $payment->created_at ? strtotime($payment->created_at) : '' + ]; }) ->addColumn('actions', function (Payment $payment) { - return ''; + return ''; }) ->rawColumns(['actions', 'user']) ->make(true); diff --git a/app/Listeners/CreateInvoice.php b/app/Listeners/CreateInvoice.php new file mode 100644 index 00000000..08d772c0 --- /dev/null +++ b/app/Listeners/CreateInvoice.php @@ -0,0 +1,31 @@ +payment->user; + + // create invoice using the trait + $this->createInvoice($user, $event->payment); + } + } +} diff --git a/app/Listeners/UserPayment.php b/app/Listeners/UserPayment.php new file mode 100644 index 00000000..be947087 --- /dev/null +++ b/app/Listeners/UserPayment.php @@ -0,0 +1,82 @@ +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); + } +} diff --git a/app/Models/Payment.php b/app/Models/Payment.php index ac281d5e..04c32831 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -7,20 +7,11 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use NumberFormatter; -use Spatie\Activitylog\LogOptions; -use Spatie\Activitylog\Traits\LogsActivity; class Payment extends Model { use HasFactory; - use LogsActivity; - public function getActivitylogOptions(): LogOptions - { - return LogOptions::defaults() - -> logOnlyDirty() - -> logOnly(['*']) - -> dontSubmitEmptyLogs(); - } + public $incrementing = false; /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index cc8427ff..bdd71a3a 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,8 +2,11 @@ namespace App\Providers; +use App\Events\PaymentEvent; use App\Events\UserUpdateCreditsEvent; +use App\Listeners\CreateInvoice; use App\Listeners\UnsuspendServers; +use App\Listeners\UserPayment; use App\Listeners\Verified; use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Listeners\SendEmailVerificationNotification; @@ -24,6 +27,10 @@ class EventServiceProvider extends ServiceProvider UserUpdateCreditsEvent::class => [ UnsuspendServers::class, ], + PaymentEvent::class => [ + CreateInvoice::class, + UserPayment::class, + ], SocialiteWasCalled::class => [ // ... other providers 'SocialiteProviders\\Discord\\DiscordExtendSocialite@handle', diff --git a/app/Traits/Invoiceable.php b/app/Traits/Invoiceable.php new file mode 100644 index 00000000..c9073d36 --- /dev/null +++ b/app/Traits/Invoiceable.php @@ -0,0 +1,91 @@ +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("
", $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)); + } +} diff --git a/public/images/paypal_logo.png b/public/images/Extensions/PaymentGateways/paypal_logo.png similarity index 100% rename from public/images/paypal_logo.png rename to public/images/Extensions/PaymentGateways/paypal_logo.png diff --git a/public/images/stripe_logo.png b/public/images/Extensions/PaymentGateways/stripe_logo.png similarity index 100% rename from public/images/stripe_logo.png rename to public/images/Extensions/PaymentGateways/stripe_logo.png diff --git a/routes/api.php b/routes/api.php index 0de04de6..74333b74 100644 --- a/routes/api.php +++ b/routes/api.php @@ -34,6 +34,8 @@ Route::middleware('api.token')->group(function () { Route::get('/notifications/{user}', [NotificationController::class, 'index']); Route::get('/notifications/{user}/{notification}', [NotificationController::class, 'view']); 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}', [NotificationController::class, 'delete']); }); + +require __DIR__ . '/extensions_api.php'; diff --git a/routes/extensions_api.php b/routes/extensions_api.php new file mode 100644 index 00000000..31fb89d3 --- /dev/null +++ b/routes/extensions_api.php @@ -0,0 +1,21 @@ + '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; + } + } +}); diff --git a/routes/extensions_web.php b/routes/extensions_web.php new file mode 100644 index 00000000..920dc299 --- /dev/null +++ b/routes/extensions_web.php @@ -0,0 +1,22 @@ + '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; + } + } +}); diff --git a/routes/web.php b/routes/web.php index 27c07c74..9c873ad1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -49,17 +49,14 @@ Route::middleware('guest')->get('/', function () { Auth::routes(['verify' => true]); -// Stripe WebhookRoute -> validation in Route Handler -Route::post('payment/StripeWebhooks', [PaymentController::class, 'StripeWebhooks'])->name('payment.StripeWebhooks'); - Route::get('/privacy', function () { -return view('information.privacy'); + return view('information.privacy'); })->name('privacy'); Route::get('/imprint', function () { -return view('information.imprint'); + return view('information.imprint'); })->name('imprint'); Route::get('/tos', function () { -return view('information.tos'); + return view('information.tos'); })->name('tos'); Route::middleware(['auth', 'checkSuspended'])->group(function () { @@ -90,10 +87,7 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () { //payments Route::get('checkout/{shopProduct}', [PaymentController::class, 'checkOut'])->name('checkout'); - Route::get('payment/PaypalPay/{shopProduct}', [PaymentController::class, 'PaypalPay'])->name('payment.PaypalPay'); - 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::post('payment/pay', [PaymentController::class, 'pay'])->name('payment.pay'); Route::get('payment/FreePay/{shopProduct}', [PaymentController::class, 'FreePay'])->name('payment.FreePay'); 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'); }); + +require __DIR__ . '/extensions_web.php'; diff --git a/themes/default/views/store/checkout.blade.php b/themes/default/views/store/checkout.blade.php index 2e0556ca..cab3d937 100644 --- a/themes/default/views/store/checkout.blade.php +++ b/themes/default/views/store/checkout.blade.php @@ -10,8 +10,7 @@