mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-29 13:52:10 +03:00
🐛 Fixed broken redemption count for offers (#15954)
refs https://github.com/TryGhost/Team/issues/2369
- offer id was not getting attached to stripe checkout metadata, causing the checkout event to not store any offer information for a subscription. This got changed in a prev refactor [here](25d8d694a0 (diff-b7dfcd660902a2a20dff7da5e886d8e10234bda4ba78228255afc8d4a8e78cf6L206)
)
- cleans up offer id handling for checkout session event
This commit is contained in:
parent
55b0f564ba
commit
8bdad78377
@ -186,6 +186,9 @@ module.exports = class RouterController {
|
|||||||
offer = await this._offersAPI.getOffer({id: offerId});
|
offer = await this._offersAPI.getOffer({id: offerId});
|
||||||
tier = await this._tiersService.api.read(offer.tier.id);
|
tier = await this._tiersService.api.read(offer.tier.id);
|
||||||
cadence = offer.cadence;
|
cadence = offer.cadence;
|
||||||
|
// Attach offer information to stripe metadata for free trial offers
|
||||||
|
// free trial offers don't have associated stripe coupons
|
||||||
|
metadata.offer = offer.id;
|
||||||
} else {
|
} else {
|
||||||
offer = null;
|
offer = null;
|
||||||
tier = await this._tiersService.api.read(tierId);
|
tier = await this._tiersService.api.read(tierId);
|
||||||
|
@ -1033,7 +1033,7 @@ module.exports = class MemberRepository {
|
|||||||
tierId: ghostProduct?.get('id'),
|
tierId: ghostProduct?.get('id'),
|
||||||
memberId: member.id,
|
memberId: member.id,
|
||||||
subscriptionId: subscriptionModel.get('id'),
|
subscriptionId: subscriptionModel.get('id'),
|
||||||
offerId: data.offerId,
|
offerId: offerId,
|
||||||
attribution: data.attribution,
|
attribution: data.attribution,
|
||||||
batchId: options.batch_id
|
batchId: options.batch_id
|
||||||
});
|
});
|
||||||
|
93
ghost/members-api/test/unit/lib/controllers/router.test.js
Normal file
93
ghost/members-api/test/unit/lib/controllers/router.test.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
const sinon = require('sinon');
|
||||||
|
const RouterController = require('../../../../lib/controllers/router');
|
||||||
|
|
||||||
|
describe('RouterController', function () {
|
||||||
|
describe('createCheckoutSession', function (){
|
||||||
|
let offersAPI;
|
||||||
|
let paymentsService;
|
||||||
|
let tiersService;
|
||||||
|
let stripeAPIService;
|
||||||
|
let labsService;
|
||||||
|
let getPaymentLinkSpy;
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
getPaymentLinkSpy = sinon.spy();
|
||||||
|
|
||||||
|
tiersService = {
|
||||||
|
api: {
|
||||||
|
read: sinon.stub().resolves({
|
||||||
|
id: 'tier_123'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
paymentsService = {
|
||||||
|
getPaymentLink: getPaymentLinkSpy
|
||||||
|
};
|
||||||
|
|
||||||
|
offersAPI = {
|
||||||
|
getOffer: sinon.stub().resolves({
|
||||||
|
id: 'offer_123',
|
||||||
|
tier: {
|
||||||
|
id: 'tier_123'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
findOne: sinon.stub().resolves({
|
||||||
|
related: () => {
|
||||||
|
return {
|
||||||
|
query: sinon.stub().returns({
|
||||||
|
fetchOne: sinon.stub().resolves({})
|
||||||
|
}),
|
||||||
|
toJSON: sinon.stub().returns([]),
|
||||||
|
fetch: sinon.stub().resolves({
|
||||||
|
toJSON: sinon.stub().returns({})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
},
|
||||||
|
toJSON: sinon.stub().returns({})
|
||||||
|
}),
|
||||||
|
edit: sinon.stub().resolves({
|
||||||
|
attributes: {},
|
||||||
|
_previousAttributes: {}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
stripeAPIService = {
|
||||||
|
configured: true
|
||||||
|
};
|
||||||
|
labsService = {
|
||||||
|
isSet: sinon.stub().returns(true)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes offer metadata to payment link method', async function (){
|
||||||
|
const routerController = new RouterController({
|
||||||
|
tiersService,
|
||||||
|
paymentsService,
|
||||||
|
offersAPI,
|
||||||
|
stripeAPIService,
|
||||||
|
labsService
|
||||||
|
});
|
||||||
|
|
||||||
|
await routerController.createCheckoutSession({
|
||||||
|
body: {
|
||||||
|
offerId: 'offer_123'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
writeHead: () => {},
|
||||||
|
end: () => {}
|
||||||
|
});
|
||||||
|
|
||||||
|
getPaymentLinkSpy.calledOnce.should.be.true();
|
||||||
|
|
||||||
|
// Payment link is called with the offer id in metadata
|
||||||
|
getPaymentLinkSpy.calledWith(sinon.match({
|
||||||
|
metadata: {offer: 'offer_123'}
|
||||||
|
})).should.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
sinon.restore();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -141,6 +141,7 @@ describe('MemberRepository', function () {
|
|||||||
let MemberProductEvent;
|
let MemberProductEvent;
|
||||||
let stripeAPIService;
|
let stripeAPIService;
|
||||||
let productRepository;
|
let productRepository;
|
||||||
|
let offerRepository;
|
||||||
let labsService;
|
let labsService;
|
||||||
let subscriptionData;
|
let subscriptionData;
|
||||||
|
|
||||||
@ -221,6 +222,12 @@ describe('MemberRepository', function () {
|
|||||||
labsService = {
|
labsService = {
|
||||||
isSet: sinon.stub().returns(true)
|
isSet: sinon.stub().returns(true)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
offerRepository = {
|
||||||
|
getById: sinon.stub().resolves({
|
||||||
|
id: 'offer_123'
|
||||||
|
})
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dispatches paid subscription event', async function (){
|
it('dispatches paid subscription event', async function (){
|
||||||
@ -250,6 +257,42 @@ describe('MemberRepository', function () {
|
|||||||
notifySpy.calledOnce.should.be.true();
|
notifySpy.calledOnce.should.be.true();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('attaches offer information to subscription event', async function (){
|
||||||
|
const repo = new MemberRepository({
|
||||||
|
stripeAPIService,
|
||||||
|
StripeCustomerSubscription,
|
||||||
|
MemberPaidSubscriptionEvent,
|
||||||
|
MemberProductEvent,
|
||||||
|
productRepository,
|
||||||
|
offerRepository,
|
||||||
|
labsService,
|
||||||
|
Member
|
||||||
|
});
|
||||||
|
|
||||||
|
sinon.stub(repo, 'getSubscriptionByStripeID').resolves(null);
|
||||||
|
|
||||||
|
DomainEvents.subscribe(SubscriptionCreatedEvent, notifySpy);
|
||||||
|
|
||||||
|
await repo.linkSubscription({
|
||||||
|
id: 'member_id_123',
|
||||||
|
subscription: subscriptionData,
|
||||||
|
offerId: 'offer_123'
|
||||||
|
}, {
|
||||||
|
transacting: {
|
||||||
|
executionPromise: Promise.resolve()
|
||||||
|
},
|
||||||
|
context: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
notifySpy.calledOnce.should.be.true();
|
||||||
|
notifySpy.calledWith(sinon.match((event) => {
|
||||||
|
if (event.data.offerId === 'offer_123') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})).should.be.true();
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
sinon.restore();
|
sinon.restore();
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user