GithubHelp home page GithubHelp logo

Comments (22)

sandervanhooft avatar sandervanhooft commented on April 28, 2024 5

Still at it, hope to release an improved version later this week.

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024 3

Generally speaking (there may be some exceptions here as I noted above, but let's start here):

Mandate available, no trial: validate, redeem on creating the subscription. Apply coupon during processing the scheduled payment
Mandate available, with trial: validate, redeem coupon on creating the subscription. Apply coupon during processing first scheduled normal payment

Through checkout, no trial

Before checkout:

  1. validate ✅
  2. apply coupon to payment amount ✅

After checkout:

  1. skip validation ✅
  2. redeem ✅
  3. mark as already applied ✅

Through checkout, with trial

Before checkout:

  1. validate coupon ✅
  2. do not apply coupon to payment amount ❓

After checkout:

  1. skip validation ✅
  2. redeem ✅
  3. do not apply (wait for first normal payment)✅

from cashier-mollie.

RobertBoes avatar RobertBoes commented on April 28, 2024 1

Sure, here it is:

{
  "owner": {
    "type": "App\\User",
    "id": 2
  },
  "actions": [
    {
      "handler": "Laravel\\Cashier\\FirstPayment\\Actions\\StartSubscription",
      "description": "Monthly payment",
      "subtotal": {
        "currency": "EUR",
        "value": "10.00"
      },
      "plan": "example-1",
      "name": "main",
      "quantity": 1,
      "coupon": "welcome"
    }
  ]
}

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024 1

Hi @RobertBoes ,

Good news: I'm preparing the PR right now.

The issue was more complex than I expected, so I had to sit on it for a bit before moving forward. Sorry for that.

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024 1

https://github.com/laravel/cashier-mollie/releases/tag/v1.2.1

from cashier-mollie.

sebastiaands avatar sebastiaands commented on April 28, 2024 1

Yes, that works! Is it correct that coupons are not mentioned on invoices?

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

@RobertBoes that's unfortunate, will have to look into this later this week.

It may help to understand in debugging that using the coupon is actually a two-step process:

  1. redeeming the coupon
  2. applying the coupon to the Order

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

Can you tell me what subscription it is? I.e. trial subscription with payment upfront?

from cashier-mollie.

RobertBoes avatar RobertBoes commented on April 28, 2024

It's a subscription with a generic trial, so the user doesn't have a subscription yet and no payments have been made yet, i.e. the first_payment (1 euro) is not used. I'm using the example code that's provided in the readme, but I've added ->withCoupon('welcome').

I would assume that when creating a new subscription with a coupon, the coupon would be applied when making the first payment. I don't know if this doesn't work because of the errors, or because the coupon is never applied but only on subsequent payments.

This is basically the full code I'm using:

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;

class CreateSubscriptionController extends Controller
{
    /**
     * @param string $plan
     * @return \Illuminate\Http\RedirectResponse
     */
    public function __invoke(string $plan)
    {
        $user = Auth::user();

        $name = ucfirst($plan) . ' membership';

        if(!$user->subscribed($name, $plan)) {

            $result = $user->newSubscription($name, $plan)->withCoupon('welcome')->create();

            if(is_a($result, RedirectResponse::class)) {
                return $result; // Redirect to Mollie checkout
            }

            return back()->with('status', 'Welcome to the ' . $plan . ' plan');
        }

        return back()->with('status', 'You are already on the ' . $plan . ' plan');
    }
}

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

(FYI, your code looks like you're starting a normal subscription, not a generic one, but that's beside the point here 😄)

Ok. So there are a few things going on here that need attention. Let me share my thoughts here.

Right now, the business logic is as such that the coupon should not be applicable to a trial.

But...

a) it should also be possible to redeem in trial mode.

b) if applicable, an InvalidCouponException should be thrown before the customer is redirected to the checkout. This probably needs to happen in the SubscriptionBuilders.

c) an exception while handling the coupon after payment should not kill the rest of the flow. This relates to payment actions and how to (gracefully) handle exceptions.

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

@RobertBoes can you share the metadata from the payment (you can find this in the Mollie dashboard)?

from cashier-mollie.

RobertBoes avatar RobertBoes commented on April 28, 2024

I've done some more testing and it seems like the preprocessors are not applied on the first payment, is that correct?

When I create a subscription with a trial, like this:

$result = $user
    ->newSubscription($name, $plan)
    ->trialUntil(Carbon::now()->addMinutes(30))
    ->withCoupon('welcome')
    ->create();

The first_payment is used, so the first payment is the amount that specified there (which I've set to 0.01). After I run php artisan cashier:run the subsequent payment is processed, which is then charged as 10.00 minus the coupon discount of 5.00, so the total that's paid is 5.00.

However, when I run this without a trial and with a coupon, the amount that needs to be paid for the first payment is 10.00 instead of 5.00 (10.00 plan - 5.00 coupon). So the first payment ignores the preprocessors.

This might be related to the error I get within the webhook when using a coupon upon creating the subscription, but I'm not sure.

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

Thanks for following up. I have been recreating this issue this afternoon, and can confirm your suspicions about the first payment not having applied the discount yet.

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024
// FirstPaymentSubscriptionBuilderTest.php

/** @test */
    public function buildsPayloadWithCouponNoTrial()
    {
        $this->withMockedCouponRepository();

        $this->assertSame(0, RedeemedCoupon::count());
        $this->assertSame(0, AppliedCoupon::count());

        $builder = $this->getBuilder()
            ->withCoupon('test-coupon'); // 5 EUR off

        $builder->create();

        // Coupons will not be handled before payment is completed via checkout
        $this->assertSame(0, RedeemedCoupon::count());
        $this->assertSame(0, AppliedCoupon::count());

        $payload = $builder->getMandatePaymentBuilder()->getMolliePayload();
        $this->assertSame('EUR', $payload['amount']['currency']);
        $this->assertSame('7.00', $payload['amount']['value']); // <-- fails here (12.00 instead of 7.00)
    }

from cashier-mollie.

ciungulete avatar ciungulete commented on April 28, 2024

and with trial is same problem

$this->assertSame('7.00', $payload['amount']['value']); // <-- fails here (0.05 instead of 7.00)

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

I think that's correct behaviour actually @ciungulete

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

I'm digging in today/tomorrow in the coupon logic. Complex stuff, simplifying some code while going over it.

from cashier-mollie.

RobertBoes avatar RobertBoes commented on April 28, 2024

Any update on the progress? We really want to start implementing this, but we're depending on preprocessors to work for the very first payment.

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

I had to make one change, probably not breaking anything

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

I'll open a separate issue for documenting the coupon logic.

from cashier-mollie.

sebastiaands avatar sebastiaands commented on April 28, 2024

Hi @sandervanhooft ,

Thanks for your work! I tried your fix and there seems to be an issue. When I apply a coupon to a new subscription, the following metadata is sent to Mollie:

{
  "owner": {
    "type": "App\\Company",
    "id": 1
  },
  "actions": [
    {
      "handler": "Laravel\\Cashier\\FirstPayment\\Actions\\StartSubscription",
      "description": "Pro abonnement",
      "subtotal": {
        "currency": "EUR",
        "value": "19.00"
      },
      "taxPercentage": "21.0000",
      "plan": "pro",
      "name": "default",
      "quantity": 1,
      "coupon": "ptquku"
    },
    null
  ]
}

The last item in the array is null, which causes the following error when Mollie does its callback:
Trying to get property 'handler' of non-object {"exception":"[object] (ErrorException(code: 0): Trying to get property 'handler' of non-object at \\vendor\\laravel\\cashier-mollie\\src\\FirstPayment\\FirstPaymentHandler.php:84)

from cashier-mollie.

sandervanhooft avatar sandervanhooft commented on April 28, 2024

Thanks for the super fast response!

I've just released v1.2.1 to fix this issue, can you give it a spin?

from cashier-mollie.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.