0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Handled mapping offer to subscription for free trials

refs https://github.com/TryGhost/Team/issues/1726

Free trial offers don't have a Stripe coupon created for them, as the trial is directly added to checkout session. So for mapping a subscription to offer, we pass the offer id directly from checkout metadata to link the subscription in backend with right offer data. This also handles the case where the offer id against a subscription can get overwritten for a subsequent subscription event, as the sub event from Stripe doesn't has the trial offer info.

- handles storing an offer id for a subscription
- updates member detail in Admin to show the offer info for a subscription
This commit is contained in:
Rishabh 2022-08-10 18:00:11 +05:30 committed by Rishabh Garg
parent 7130fc2833
commit 52e3ae2058
3 changed files with 32 additions and 13 deletions

View file

@ -170,16 +170,24 @@
<div class="gh-membertier-cancelreason"><span class="fw6">Cancellation reason:</span> {{sub.cancellationReason}}</div>
{{/if}}
{{#if sub.offer}}
<div>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
offer
{{#if (eq sub.offer.type 'fixed')}}
({{currency-symbol sub.offer.currency}}{{gh-price-amount sub.offer.amount}} off)
{{else}}
({{sub.offer.amount}}% off)
{{/if}}
applied to subscription
</div>
{{#if (eq sub.offer.type "trial")}}
<div>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
offer
({{sub.offer.amount}} days free)
</div>
{{else}}
<div>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
offer
{{#if (eq sub.offer.type 'fixed')}}
({{currency-symbol sub.offer.currency}}{{gh-price-amount sub.offer.amount}} off)
{{else}}
({{sub.offer.amount}}% off)
{{/if}}
applied to subscription
</div>
{{/if}}
{{/if}}
<div class="gh-membertier-created">
Created on {{sub.startDate}}

View file

@ -327,7 +327,7 @@ module.exports = class MemberRepository {
if (memberData.bio) {
memberData.bio = memberData.bio.trim();
}
// Determine if we need to fetch the initial member with relations
const needsProducts = this._stripeAPIService.configured && data.products;
const needsNewsletters = memberData.newsletters || typeof memberData.subscribed === 'boolean';
@ -698,6 +698,7 @@ module.exports = class MemberRepository {
* @param {Object} data
* @param {String} data.id - member ID
* @param {Object} data.subscription
* @param {String} data.offerId
* @param {*} options
* @returns
*/
@ -785,7 +786,9 @@ module.exports = class MemberRepository {
}
let stripeCouponId = subscription.discount && subscription.discount.coupon ? subscription.discount.coupon.id : null;
let offerId = null;
// For trial offers, offer id is passed from metadata as there is no stripe coupon
let offerId = data.offerId || null;
if (stripeCouponId) {
// Get the offer from our database
@ -831,6 +834,11 @@ module.exports = class MemberRepository {
let eventData = {};
if (model) {
// CASE: Offer is already mapped against sub, don't overwrite it with NULL
// Needed for trial offers, which don't have a stripe coupon/discount attached to sub
if (!subscriptionData.offer_id) {
delete subscriptionData.offer_id;
}
const updated = await this._StripeCustomerSubscription.edit(subscriptionData, {
...options,
id: model.id

View file

@ -253,9 +253,12 @@ module.exports = class WebhookController {
for (const subscription of customer.subscriptions.data) {
try {
const offerId = session.metadata?.offer;
await this.deps.memberRepository.linkSubscription({
id: member.id,
subscription
subscription,
offerId
});
} catch (err) {
if (err.code !== 'ER_DUP_ENTRY' && err.code !== 'SQLITE_CONSTRAINT') {