Closed evertjanMlbrgn closed 1 month ago
Hi @evertjanMlbrgn,
thanks for your issue!
like others have mentioned, there is no CouponRepository interface, but i managed to implement it. It would be nice to have an interface though.
I am not sure what you mean by that. As shown in your code snippet, you are using the provided interface Laravel\Cashier\Coupon\Contracts\CouponRepository
.
I've notice that somehow i have to save the discount value (the discount amount) in decimal notation in my database, otherwise the discount will be way too height. :-)
Let me explain the workflow of the coupon feature.
First the user redeems the coupon, by inserting it in some input and you calling the code that ultimately triggers RedeemedCoupon::record($coupon, $subscription)
.
// for new subscription
$user->newSubscription($name, $plan)
->withCoupon('your-coupon-code')
->create();
// for active subscription
$user->redeemCoupon('your-coupon-code');
Next, cashier:run is executed all
OrderItemsthat are due (
processed_at < now() and order_id === null) are queried, grouped for each user and currency and then passed into the
Order::createFromItems()method. There we call the
$items->preprocess()method, which triggers the execution of all preprocessors defined in
cashier_plans.defaults.order_item_preprocessorsvia
Subscription::preprocessOrderItem()`.
The CouponOrderItemPreprocessor
is responsible for checking if an active ReedemCoupon
was associated with the active subscription (essentially if owner_type
equals Subscription::class
and owner_id
matches the active subscription id. When this is the case the CouponOrderItemPreprocessor
will add a new OrderItem
to the collection of items which will be added to the current order. The resulting OrderItem
has a negative unit_price
and is calculated via the FixedDiscountHandler@unitPrice()
, which passes the coupon's discount
value from the context
inside the mollie_array_to_money()
which looks like the following.
function mollie_array_to_money(array $array)
{
return decimal_to_money($array['value'], $array['currency']);
}
And now we are finally at the point where you can see that you don't necessarily have to store the coupon value as decimal inside your DB. You just have to make sure to convert the value from the DB to a decimal value before calling new CashierCoupon($coupon, $handler, $couponModel->coupon_context);
.
tl;dr;
Like the rest of the prices in the cashier_plan
the coupon functionality relies on the provided amount to be in decimal notation. ou can store the value in any format, but ensure it’s converted to decimal notation before passing it to the Coupon class within the $context array.
Thanks for the great explanation, it works.
I've create a custom CouponRepository that stores coupons in a database.
like others have mentioned, there is no CouponRepository interface, but i managed to implement it. It would be nice to have an interface though.
Now for the real question. I've notice that somehow i have to save the discount value (the discount amount) in decimal notation in my database, otherwise the discount will be way too height. :-)
I suspect this is because I use the FixedDiscountHandler provided by Laravel Cashier Mollie and it expects decimal notation, and usually coupon discount values are written in decimal notation in the cashier_coupons.php config file. I find it a bit hard to test however since the orders are generated on the background and i'm not sure how to debug there.
My DatabaseCouponRepository code:
My Coupon model
I have registered the custom DatabaseCouponHandler in my AppServiceProvider and that works fine