PLATFORM
  • Tails

    Create websites with TailwindCSS

  • Blocks

    Design blocks for your website

  • Wave

    Start building the next great SAAS

  • Pines

    Alpine & Tailwind UI Library

  • Auth

    Plug'n Play Authentication for Laravel

  • Designer comingsoon

    Create website designs with AI

  • DevBlog comingsoon

    Blog platform for developers

  • Static

    Build a simple static website

  • SaaS Adventure

    21-day program to build a SAAS

Question By
Solved

Adding a custom view with a button to allow payments

Solved
mikemastercorp

Jul 2nd, 2024 12:21 PM

Hello Dear DevDojo team.

I am working on a template as part of my project where I need to add a button which would trigger a payment and after a successful one will allow the storing of the required data.

Are there any tutorials/manuals or recommended videos how to achieve that with already existing project of Wave SAAS as I've used the STRIPE pull and now need to develop some payment plans and featured services on my project?

I was also wondering, is there any latest built Wave SAAS with Stripe that you have pushed/stashed somewhere as Bobby suggested me to use a pull request etc. but it seems like I was not able to combine the two easily?

Maybe a few simple steps of how to get the latest Wave SAAS and implement the Stripe payment will help a lot for starters, so that I can analyze the existing structure/button triggers and see how those can fit in my project needs.

Thanks in advance for the kind assistance and can't wait to see what magic will come out from the next Wave SAAS version which will combine my favorite Filament admin ;)

bobbyiliev

Jul 4th, 2024 12:38 AM

Hi there!

I believe that you should be able to use the get started button from the existing plans view:

plans.blade.php

Along with the logic from the checkout blade:

checkout.blade.php

For the time being, using that PR as the baseline for implementing Stripe to the existing Wave v2 is the best way to go. We've decided not to proceed with that PR merge yet, but we will be planning the Stripe support for Wave v3!

Hope that this helps!

- Bobby

mikemastercorp

Jul 11th, 2024 08:32 AM

Hey Bobby, thanks for sharing the files to look at.

I've downloaded the wave latest from github and attempted to fetch the #38 but there are multiple merge conflicts and I am not sure how to handle it properly so that I finish with the latest version ov wave + PR#38

Can you please share the steps to achieve that?

mikemastercorp

Jul 11th, 2024 12:41 PM

So I've figured it out, I had some local issues to resolve. Here are the steps in case anybody needs them:

  1. Clone Wave SAAS from the GH repo: git clone https://github.com/thedevdojo/wave.git wavestripe

  2. Get inside the downloaded folder (in step 1 I used wavestripe, but feel free to change it as it may suite): cd wavestripe

  3. Fetch the PR #38 which contains the Stripe changes (final is my preferred branch name, so feel free to change it as it may suite too): git fetch origin pull/38/head:final

  4. Switch to the new branch (in my case was final) git switch final

  5. Run composer installation as listed in the steps on Wave GH repo composer install

-NOTE- If you are using PHP 8.3 you might get a warning that the composer lock is outdated and it will suggest you to execute a command: composer update.

Since the REPO is using an older version of Laravel (8.83) you need to create the DB file manually in /database and name it database.sqlite

If you run in an issue with /config/trustedproxies.php (line 18) where it states that the expose() null is deprecated, just replace the line with the following and redo the migration:

'proxies' => explode(',', env('TRUSTED_PROXIES', '')), // Note the empty string ''

For sure, do not forget to edit the .env and add the STRIPE sandbox account, but that is part of the development now, so from here you are on your own :)

Happy coding!

Report
1
mikemastercorp

Jul 13th, 2024 05:19 AM

Hello Bobby.

I am having a small question here. It is clear to me that I can modify the JavaScript as I want to fit my buttons, however can you share a bit more about what is the logic behind

@subscribed($plan->slug) @notsubscribed @subscriber @notsubscriber @endsubscriber @endsubscribed

I see those are functions in Users model but it is not yet very clear what each does and I need to add some custom logic to my own markup so that the payments are set with the proper linking and detected by the cashier.blade.php javascript

bobbyiliev

Jul 15th, 2024 12:23 AM

Hey 👋

Hope that you hade a great weekend! And happy to hear that you've got that all working now 👏

Regarding the @subscribed functions, those are custom blade directives defined here:

wave/src/WaveServiceProvider.php#L82-L92

Code snippet:

        Blade::directive('subscribed', function ($plan) {
            return "<?php if (!auth()->guest() && auth()->user()->subscribed($plan)) { ?>";
        });

        Blade::directive('notsubscribed', function () {
            return "<?php } else { ?>";
        });

        Blade::directive('endsubscribed', function () {
            return "<?php } ?>";
        });

Those just check if the user is subscribed or not based on the above logic it just has been abstracted to blade directives for a more convenient way of doing the check using the @ syntax.

You can modify the logic of those blade directibes to match your needs.

Let me know if this works!

- Bobby

mikemastercorp

Jul 16th, 2024 12:05 AM

Hey Bobby,

Thanks for clarifying the blade directives I must have had some hard time finding those. I am not sure though how these directives are allowed to be used in blade views - are they allowed for every view and we can define some extra directives to simplify the views code or there were some tricks to make those available?

Also, i am having a weird issue with a fresh wavestripe installation where I added my pk_test and sk_test keys, I've added the 3 plans in Stripe and set the plan IDs on each plan from the admin. It should have all gone well, but I am getting an error 500 and I just cant figure out how can i obtain some more information about what goes wrong as in the dev concole of Firefox I can see the request data etc. but there seems to be no returned reason about the failure. i made sure the .evn has the proper app url and it points to https to make sure this is not the issue but am still getting the 500 on post the minute I click on any of the plans.

The plan ID's we copy from Stripe for each plan after we create it, correct? Any ideas about what could be the possible reason as I've double checked every plan and every ID, as well as the pk/sk keys it all matches the Stripe Development keys and should be all good but...

mikemastercorp

Jul 19th, 2024 06:33 AM

So I am using my own view design now and I've added 3 separate reoccurring products with the payment terms etc. and I've filled every product/subscription ID to each plan from the Wave Admin.

The issue that I am experiencing is that usually we provide the product_id to each button and we pass it as a parameter, but in Wave case, we have a checkout JavaScript code that is included in partials as well as we have a controller which seems not being modified and have a connection only for Paddle (SubscriptionController::checkout).

So what I am trying to determine is how can I add a link like:

<a href="{{ route('checkout', ['plan' => 'price_1Pe4p8P7ZXiN2qo8kEMzYllD']) }}" which will show the Stripe payment form, allow the various payment gateways like google pay etc. and then upon success return me back with the confirmation message and apply all the changes...

I thought with Stripe pull 38 the controller will get a function that will check if the .env parameter was set as Stripe or Paddle and process accordingly but I do not find such code in it.

So I will go over the academy videos to check again what changes needs to be applied but it is still a bit blurry for me about how to setup Stripe with WAVE. For sure I can generate my own controller with my own checkup function, redirects etc. but I am not sure if all the rest of the code that Wave requires for billing etc. will be working well...

bobbyiliev

Jul 21st, 2024 03:43 AM

Best Answer

Hey!

Yep indeed, that checkout route in the Stripe PR is still only for Paddle.

The Stripe routes are:

if (env('CASHIER_VENDOR') == 'stripe') {
	Route::post('stripe/create-checkout-session', '\Wave\Http\Controllers\StripeController@postCreateCheckoutSession')->name('stripe.create-checkout-session');
	Route::get('stripe/success-checkout-session', '\Wave\Http\Controllers\StripeController@postSuccessCheckout')->name('stripe.success-checkout');
	Route::get('stripe/error-checkout-session', '\Wave\Http\Controllers\StripeController@postErrorCheckout')->name('stripe.error-checkout');
	
	Route::get('stripe/billing-portal', '\Wave\Http\Controllers\StripeController@getBillingPortal')->name('stripe.billing-portal')->middleware('auth');

	Route::post('wave-stripe/webhook', '\Wave\Http\Controllers\WebhookController@handleWebhook')->name('stripe.webhook');
}

The logic in the checkout blade for stripe is:

wave/resources/views/checkout.blade.php#L1-L63

And her is how you could pass the plan id:

plans-minimal.blade.php#L61-L65

The PR was never merged so there might be some open questions indeed as it was never officially supported, we would try to make this a more straight forward process with Wave V3 once it is ready!

- Bobby

mikemastercorp

Jul 21st, 2024 07:44 AM

Sorry Bobby. Forgot to update that I've discovered the issue and had it fixed.it is I portant to update maybe the readme to share that with Stripe users should pass the 'price_id' and not the 'product_if' as this was the issue on my side and as far as I've switched, it all started working as it should.

I will still have to figure out the billing part to add that too in my custom user panel, but that is beyond this discussion as the initial issue got fixed by supplying the proce_id in admin-/plans.

I would have a few suggestions in terms of the v3 with Stripe but it is not the right place to share those, so will do so where in the proper thread.

I've added the plan duration as a string to the plans BRRAD as a drop-down matching the Stripe terms which then I used in the frontend where I usually it was just a text / per year or so.

I've also marked as input description for plan_id that for Stripe it is 'price_id' so that anybody can avoid my silly issue and not ask again or search for answers on the same issue.

Thanks again and I see some development progress on v3 so I will gladly follow up the thread and if any other suggestions/ideas come up, will gladly share those...

mikemastercorp

Jul 22nd, 2024 05:44 PM

I just have a small question about the implementation itself of the payments. Based on the documentation, we are simply able to add a button for each plan and using a foreach iteration to pass the price_id for each plan.

In the official code a JavaScript is used that reads button classes etc. etc. instead of converting buttons to 'a href' tags and pass a route to checkout accepting as a parameter the price_id.

This way we can get rid of the entire JavaScript and if needed have multiple payments with various validations, terms etc. without passing queries via Ajax and dealing directly with our controller code and logic for validating, purchase itself and storing the end result to DB or return to user the error.

E.g. using this example for selling subscriptions (straight from Laravell Cashier docs):

use Illuminate\Http\Request;
 
Route::get('/subscription-checkout', function (Request $request) {
    return $request->user()
        ->newSubscription('default', $price_id)
        ->trialDays(5)
        ->allowPromotionCodes()
        ->checkout([
            'success_url' => route('your-success-route'),
            'cancel_url' => route('your-cancel-route'),
        ]);
});

I find it much more simple to read and manipulate the code if there are no JavaScript/Jquery scripts involved as the logic of MVC is to let the controller deal with the operations as much as possible and use the view for presenting ;)

For sure, in order for this to work, we need a proper checkout route defined in web.php:

Route::get('checkout/{plan?}/{type?"recurring"}}', CheckoutController::class)->middleware(['auth', 'verified'])->name('checkout');

Would you share any thoughts about using the standard method over the official Ajax/Javascript way it was implemented with?