mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-27 00:52:36 +03:00
Wired up OfferRedemption storage
refs https://github.com/TryGhost/Team/issues/1132 We have to include the Offer on the metadata for the Stripe Checkout - as Offers with a duration of 'once' will not always be present on the Subscription after fetching it. Once we receive the Stripe Checkout webhook we emit an event for subscription created - the reason we use an event is because this logic should eventually live in a Payments/Stripe module - and we'd want to decouple it from the Members module. The Members module is in charge of writing Offer Redemptions - rather than the Offers module - because Offer Redemptions are "owned" by a Member - and merely reference and Offer. Eventually Offer Redemptions could be replaced by Subscriptions.
This commit is contained in:
parent
05619a193c
commit
c58e83c9d7
@ -3,5 +3,6 @@ module.exports = {
|
||||
MemberUnsubscribeEvent: require('./lib/MemberUnsubscribeEvent'),
|
||||
MemberSignupEvent: require('./lib/MemberSignupEvent'),
|
||||
MemberPaidConverstionEvent: require('./lib/MemberPaidConversionEvent'),
|
||||
MemberPaidCancellationEvent: require('./lib/MemberPaidCancellationEvent')
|
||||
MemberPaidCancellationEvent: require('./lib/MemberPaidCancellationEvent'),
|
||||
SubscriptionCreatedEvent: require('./lib/SubscriptionCreatedEvent')
|
||||
};
|
||||
|
25
ghost/member-events/lib/SubscriptionCreatedEvent.js
Normal file
25
ghost/member-events/lib/SubscriptionCreatedEvent.js
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @typedef {object} SubscriptionCreatedEventData
|
||||
* @prop {string} memberId
|
||||
* @prop {string} subscriptionId
|
||||
* @prop {string} offerId
|
||||
*/
|
||||
|
||||
module.exports = class SubscriptionCreatedEvent {
|
||||
/**
|
||||
* @param {SubscriptionCreatedEventData} data
|
||||
* @param {Date} timestamp
|
||||
*/
|
||||
constructor(data, timestamp) {
|
||||
this.data = data;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SubscriptionCreatedEventData} data
|
||||
* @param {Date} [timestamp]
|
||||
*/
|
||||
static create(data, timestamp) {
|
||||
return new SubscriptionCreatedEvent(data, timestamp || new Date);
|
||||
}
|
||||
};
|
@ -49,6 +49,7 @@ module.exports = function MembersAPI({
|
||||
MemberProductEvent,
|
||||
MemberEmailChangeEvent,
|
||||
MemberAnalyticEvent,
|
||||
OfferRedemption,
|
||||
StripeProduct,
|
||||
StripePrice,
|
||||
Product,
|
||||
@ -102,6 +103,7 @@ module.exports = function MembersAPI({
|
||||
MemberEmailChangeEvent,
|
||||
MemberStatusEvent,
|
||||
MemberProductEvent,
|
||||
OfferRedemption,
|
||||
StripeCustomer,
|
||||
StripeCustomerSubscription
|
||||
});
|
||||
|
@ -123,6 +123,7 @@ module.exports = class RouterController {
|
||||
let ghostPriceId = req.body.priceId;
|
||||
const identity = req.body.identity;
|
||||
const offerId = req.body.offerId;
|
||||
const metadata = req.body.metadata;
|
||||
|
||||
if (!ghostPriceId && !offerId) {
|
||||
res.writeHead(400);
|
||||
@ -154,6 +155,8 @@ module.exports = class RouterController {
|
||||
coupon = {
|
||||
id: offer.stripe_coupon_id
|
||||
};
|
||||
|
||||
metadata.offer = offer.id;
|
||||
} catch (err) {
|
||||
res.writeHead(500);
|
||||
return res.end('Could not use Offer.');
|
||||
@ -193,7 +196,7 @@ module.exports = class RouterController {
|
||||
successUrl: req.body.successUrl || this._config.checkoutSuccessUrl,
|
||||
cancelUrl: req.body.cancelUrl || this._config.checkoutCancelUrl,
|
||||
customerEmail: req.body.customerEmail,
|
||||
metadata: req.body.metadata
|
||||
metadata: metadata
|
||||
});
|
||||
const publicKey = this._stripeAPIService.getPublicKey();
|
||||
|
||||
@ -237,7 +240,7 @@ module.exports = class RouterController {
|
||||
coupon,
|
||||
successUrl: req.body.successUrl || this._config.checkoutSuccessUrl,
|
||||
cancelUrl: req.body.cancelUrl || this._config.checkoutCancelUrl,
|
||||
metadata: req.body.metadata
|
||||
metadata: metadata
|
||||
});
|
||||
const publicKey = this._stripeAPIService.getPublicKey();
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
const _ = require('lodash');
|
||||
const errors = require('@tryghost/errors');
|
||||
const tpl = require('@tryghost/tpl');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const {SubscriptionCreatedEvent} = require('@tryghost/member-events');
|
||||
const ObjectId = require('bson-objectid');
|
||||
|
||||
const messages = {
|
||||
@ -42,6 +44,7 @@ module.exports = class MemberRepository {
|
||||
MemberProductEvent,
|
||||
StripeCustomer,
|
||||
StripeCustomerSubscription,
|
||||
OfferRedemption,
|
||||
stripeAPIService,
|
||||
productRepository,
|
||||
tokenService,
|
||||
@ -59,6 +62,18 @@ module.exports = class MemberRepository {
|
||||
this._productRepository = productRepository;
|
||||
this.tokenService = tokenService;
|
||||
this._logging = logger;
|
||||
|
||||
DomainEvents.subscribe(SubscriptionCreatedEvent, async function (event) {
|
||||
if (!event.data.offerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
await OfferRedemption.add({
|
||||
member_id: event.data.memberId,
|
||||
subscription_id: event.data.subscriptionId,
|
||||
offer_id: event.data.offerId
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
isActiveSubscriptionStatus(status) {
|
||||
@ -492,7 +507,15 @@ module.exports = class MemberRepository {
|
||||
}
|
||||
}
|
||||
|
||||
async linkSubscription(data, options) {
|
||||
async getSubscriptionByStripeID(id, options) {
|
||||
const subscription = await this._StripeCustomerSubscription.findOne({
|
||||
subscription_id: id
|
||||
}, options);
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
async linkSubscription(data, options = {}) {
|
||||
if (!this._stripeAPIService.configured) {
|
||||
throw new errors.BadRequestError(tpl(messages.noStripeConnection, {action: 'link Stripe Subscription'}));
|
||||
}
|
||||
@ -522,9 +545,8 @@ module.exports = class MemberRepository {
|
||||
}
|
||||
const paymentMethod = paymentMethodId ? await this._stripeAPIService.getCardPaymentMethod(paymentMethodId) : null;
|
||||
|
||||
const model = await this._StripeCustomerSubscription.findOne({
|
||||
subscription_id: subscription.id
|
||||
}, options);
|
||||
const model = await this.getSubscriptionByStripeID(subscription.id, options);
|
||||
|
||||
const subscriptionPriceData = _.get(subscription, 'items.data[0].price');
|
||||
let ghostProduct;
|
||||
try {
|
||||
|
@ -1,5 +1,7 @@
|
||||
const _ = require('lodash');
|
||||
const errors = require('@tryghost/errors');
|
||||
const DomainEvents = require('@tryghost/domain-events');
|
||||
const {SubscriptionCreatedEvent} = require('@tryghost/member-events');
|
||||
|
||||
module.exports = class StripeWebhookService {
|
||||
/**
|
||||
@ -274,6 +276,16 @@ module.exports = class StripeWebhookService {
|
||||
});
|
||||
}
|
||||
|
||||
const subscription = await this._memberRepository.getSubscriptionByStripeID(session.subscription);
|
||||
|
||||
const event = SubscriptionCreatedEvent.create({
|
||||
memberId: member.id,
|
||||
subscriptionId: subscription.id,
|
||||
offerId: session.metadata.offer || null
|
||||
});
|
||||
|
||||
DomainEvents.dispatch(event);
|
||||
|
||||
if (checkoutType !== 'upgrade') {
|
||||
const emailType = 'signup';
|
||||
this._sendEmailWithMagicLink({
|
||||
|
@ -27,10 +27,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryghost/debug": "^0.1.2",
|
||||
"@tryghost/domain-events": "^0.1.2",
|
||||
"@tryghost/errors": "^0.2.9",
|
||||
"@tryghost/ignition-errors": "^0.1.2",
|
||||
"@tryghost/magic-link": "^1.0.13",
|
||||
"@tryghost/member-analytics-service": "^0.1.2",
|
||||
"@tryghost/member-events": "^0.2.1",
|
||||
"@tryghost/members-analytics-ingress": "^0.1.3",
|
||||
"@tryghost/members-stripe-service": "^0.3.0",
|
||||
"@tryghost/tpl": "^0.1.2",
|
||||
|
Loading…
Reference in New Issue
Block a user