From 01c95370b0a6fecc229cb35e13e77f718d546ab6 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 11 Feb 2025 17:11:53 -0600 Subject: [PATCH] Website: Add support for promotional codes on the self-service license dispenser (#26280) Changes: - Added the ability to use coupons on the Fleet premium license dispenser - Updated the stripe webhook to support coupons on Fleet premium subscriptions - Updated the customer dashboard on the website to show decimal places in subscription/host prices. --- .../get-stripe-checkout-session-url.js | 1 + .../webhooks/receive-from-stripe.js | 24 +++++++++++++++---- website/views/pages/customers/dashboard.ejs | 6 ++--- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/website/api/controllers/customers/get-stripe-checkout-session-url.js b/website/api/controllers/customers/get-stripe-checkout-session-url.js index 324e428a91..b14968760f 100644 --- a/website/api/controllers/customers/get-stripe-checkout-session-url.js +++ b/website/api/controllers/customers/get-stripe-checkout-session-url.js @@ -54,6 +54,7 @@ module.exports = { ], mode: 'subscription', billing_address_collection: 'required',// eslint-disable-line camelcase + allow_promotion_codes: true,// eslint-disable-line camelcase tax_id_collection: {// eslint-disable-line camelcase enabled: true, required: 'if_supported' diff --git a/website/api/controllers/webhooks/receive-from-stripe.js b/website/api/controllers/webhooks/receive-from-stripe.js index 6739b64c3c..e423516e0e 100644 --- a/website/api/controllers/webhooks/receive-from-stripe.js +++ b/website/api/controllers/webhooks/receive-from-stripe.js @@ -103,7 +103,7 @@ module.exports = { // If stripe thinks this subscription renews in 7 days, we'll send the user an subscription reminder email. if(type === 'invoice.upcoming' && stripeEventData.billing_reason === 'upcoming') { // Get the subscription cost per host for the Subscription renewal notification email. - let subscriptionCostPerHost = Math.floor(subscriptionForThisEvent.subscriptionPrice / subscriptionForThisEvent.numberOfHosts / 12); + let subscriptionCostPerHost = (subscriptionForThisEvent.subscriptionPrice / subscriptionForThisEvent.numberOfHosts / 12).toFixed(2); let upcomingBillingAt = stripeEventData.next_payment_attempt * 1000; // Send a upcoming subscription renewal email. await sails.helpers.sendTemplateEmail.with({ @@ -188,6 +188,21 @@ module.exports = { // Get the updated number of hosts from the quantity of the invoice. let newNumberOfHosts = updatedSubscriptionInfo.quantity; + let subscriptionPrice = Math.floor(pricePerHost * newNumberOfHosts); + + // (Optionally) adjust the price of this subscription if a coupon was applied. + if(stripeEventData.discount){ + if(stripeEventData.discount.coupon){ + if(stripeEventData.discount.coupon.amount_off){ + // If the coupon applied takes a fixed dollar amount off of the total price, subtact the amoutn fro mthe subscriptionPrice + subscriptionPrice = _.round(subscriptionPrice - (stripeEventData.discount.coupon.amount_off / 100), 2); // Note: coupon.amount_off contains the discounted amount in cents. + } else if(stripeEventData.discount.coupon.percent_off){ + // Otherwise if it is a percent discount, + let discountAmount = subscriptionPrice * (stripeEventData.discount.coupon.percent_off / 100); + subscriptionPrice = _.round(subscriptionPrice - discountAmount, 2); + } + } + } // Generate a new license key for this subscription let newLicenseKeyForThisSubscription = await sails.helpers.createLicenseKey.with({ numberOfHosts: newNumberOfHosts, @@ -198,7 +213,7 @@ module.exports = { // Update the subscription record await Subscription.updateOne({id: subscriptionForThisEvent.id}).set({ numberOfHosts: newNumberOfHosts, - subscriptionPrice: Math.floor(pricePerHost * newNumberOfHosts), + subscriptionPrice, fleetLicenseKey: newLicenseKeyForThisSubscription, nextBillingAt: nextBillingAt }); @@ -214,10 +229,11 @@ module.exports = { let nextBillingAt = newSubscriptionDetails.current_period_end * 1000; // Get the number of Hosts. let numberOfHosts = newSubscriptionDetails.quantity; - // Get the whole dollar price per host. + // Get the whole dollar price per host by subtracting the discount amount from the plan amount. + // [?]: https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-total_details let subscriptionPricePerHost = newSubscriptionDetails.plan.amount / 100; // Determine the annual cost of this user's subscription - let subscriptionPrice = subscriptionPricePerHost * numberOfHosts; + let subscriptionPrice = (subscriptionPricePerHost * numberOfHosts) - (stripeEventData.total_details.amount_discount / 100); // Generate a new license key. let newLicenseKey = await sails.helpers.createLicenseKey.with({ numberOfHosts, diff --git a/website/views/pages/customers/dashboard.ejs b/website/views/pages/customers/dashboard.ejs index a7f8830082..bd3cc81342 100644 --- a/website/views/pages/customers/dashboard.ejs +++ b/website/views/pages/customers/dashboard.ejs @@ -31,7 +31,7 @@
Cost -

${{thisSubscription.subscriptionPrice}}.00/year

+

${{thisSubscription.subscriptionPrice.toFixed(2)}}/year

No. of devices @@ -89,8 +89,8 @@
A calendar icon
-

{{thisSubscription.numberOfHosts}} devices @ ${{thisSubscription.subscriptionPrice / thisSubscription.numberOfHosts / 12}}.00/device/month

-

Billed annually at ${{thisSubscription.subscriptionPrice}}.00/yr

+

{{thisSubscription.numberOfHosts}} devices @ ${{(thisSubscription.subscriptionPrice / thisSubscription.numberOfHosts / 12).toFixed(2)}}/device/month

+

Billed annually at ${{thisSubscription.subscriptionPrice.toFixed(2)}}/yr

Next payment on

Your subscription will expire on