Comments (22)
Still at it, hope to release an improved version later this week.
from cashier-mollie.
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:
- validate ✅
- apply coupon to payment amount ✅
After checkout:
- skip validation ✅
- redeem ✅
- mark as already applied ✅
Through checkout, with trial
Before checkout:
- validate coupon ✅
- do not apply coupon to payment amount ❓
After checkout:
- skip validation ✅
- redeem ✅
- do not apply (wait for first normal payment)✅
from cashier-mollie.
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.
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.
https://github.com/laravel/cashier-mollie/releases/tag/v1.2.1
from cashier-mollie.
Yes, that works! Is it correct that coupons are not mentioned on invoices?
from cashier-mollie.
@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:
- redeeming the coupon
- applying the coupon to the Order
from cashier-mollie.
Can you tell me what subscription it is? I.e. trial subscription with payment upfront?
from cashier-mollie.
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.
(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 SubscriptionBuilder
s.
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.
@RobertBoes can you share the metadata from the payment (you can find this in the Mollie dashboard)?
from cashier-mollie.
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.
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.
// 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.
and with trial is same problem
$this->assertSame('7.00', $payload['amount']['value']); // <-- fails here (0.05 instead of 7.00)
from cashier-mollie.
I think that's correct behaviour actually @ciungulete
from cashier-mollie.
I'm digging in today/tomorrow in the coupon logic. Complex stuff, simplifying some code while going over it.
from cashier-mollie.
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.
I had to make one change, probably not breaking anything
from cashier-mollie.
I'll open a separate issue for documenting the coupon logic.
from cashier-mollie.
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.
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)
- Same plan with different intervals HOT 1
- Questions HOT 3
- First 1500 customer one year €25 discount / Exclude customers from discount when they have already have one HOT 3
- Guzzle timeout when trying to create a new customer. HOT 5
- PHP8 update confilct HOT 1
- Recurrent payment HOT 17
- Testing webhooks locally HOT 3
- Question about events HOT 6
- Get checkout URL for failed order payments HOT 1
- user id rounded up HOT 1
- Question regarding API KEY HOT 1
- Not Understanding HOT 1
- See when a subscription is up for renewal HOT 1
- Event OrderInvoiceAvailable is dispatched multiple times HOT 1
- 1305 SAVEPOINT trans2 does not exist HOT 1
- Charge based on days of the month left HOT 1
- How to create different pricings for subscriptions based on user country? HOT 2
- Current subscription end date HOT 5
- Is it possible to mandate multiple subscriptions in one initial payment HOT 3
- Interval of subscription not updating
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cashier-mollie.