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

View file

@ -327,7 +327,7 @@ module.exports = class MemberRepository {
if (memberData.bio) { if (memberData.bio) {
memberData.bio = memberData.bio.trim(); memberData.bio = memberData.bio.trim();
} }
// Determine if we need to fetch the initial member with relations // Determine if we need to fetch the initial member with relations
const needsProducts = this._stripeAPIService.configured && data.products; const needsProducts = this._stripeAPIService.configured && data.products;
const needsNewsletters = memberData.newsletters || typeof memberData.subscribed === 'boolean'; const needsNewsletters = memberData.newsletters || typeof memberData.subscribed === 'boolean';
@ -698,6 +698,7 @@ module.exports = class MemberRepository {
* @param {Object} data * @param {Object} data
* @param {String} data.id - member ID * @param {String} data.id - member ID
* @param {Object} data.subscription * @param {Object} data.subscription
* @param {String} data.offerId
* @param {*} options * @param {*} options
* @returns * @returns
*/ */
@ -785,7 +786,9 @@ module.exports = class MemberRepository {
} }
let stripeCouponId = subscription.discount && subscription.discount.coupon ? subscription.discount.coupon.id : null; 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) { if (stripeCouponId) {
// Get the offer from our database // Get the offer from our database
@ -831,6 +834,11 @@ module.exports = class MemberRepository {
let eventData = {}; let eventData = {};
if (model) { 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, { const updated = await this._StripeCustomerSubscription.edit(subscriptionData, {
...options, ...options,
id: model.id id: model.id

View file

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