Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class MemberWelcomeEmailService {
}
}

async send({member, memberStatus = 'free'}) {
async send({member, memberStatus}) {
const name = member?.name ? `${member.name} at ` : '';
logging.info(`${MEMBER_WELCOME_EMAIL_LOG_KEY} Sending welcome email to ${name}${member?.email}`);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,19 @@ module.exports = class MemberRepository {
if (config.get('memberWelcomeEmailTestInbox') && WELCOME_EMAIL_SOURCES.includes(source)) {
const freeWelcomeEmail = this._AutomatedEmail ? await this._AutomatedEmail.findOne({slug: MEMBER_WELCOME_EMAIL_SLUGS.free}) : null;
const isFreeWelcomeEmailActive = freeWelcomeEmail && freeWelcomeEmail.get('lexical') && freeWelcomeEmail.get('status') === 'active';

var isFreeSignup = !stripeCustomer;

const runMemberCreation = async (transacting) => {
const newMember = await this._Member.add({
...memberData,
...memberStatusData,
labels
}, {...memberAddOptions, transacting});

if (isFreeWelcomeEmailActive) {
// Only send the free welcome email if:
// 1. The free welcome email is active
// 2. The member is not signing up for a paid subscription (no stripeCustomer)
if (isFreeWelcomeEmailActive && isFreeSignup) {
const timestamp = eventData.created_at || newMember.get('created_at');

await this._Outbox.add({
Expand All @@ -366,7 +370,8 @@ module.exports = class MemberRepository {
email: newMember.get('email'),
name: newMember.get('name'),
source,
timestamp
timestamp,
status: 'free'
})
}, {transacting});
}
Expand All @@ -380,7 +385,7 @@ module.exports = class MemberRepository {
member = await this._Member.transaction(runMemberCreation);
}

if (isFreeWelcomeEmailActive) {
if (isFreeWelcomeEmailActive && isFreeSignup) {
this.dispatchEvent(StartOutboxProcessingEvent.create({memberId: member.id}), memberAddOptions);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ const memberWelcomeEmailService = require('../../member-welcome-emails/service')
const LOG_KEY = `${OUTBOX_LOG_KEY}[MEMBER-WELCOME-EMAIL]`;

async function handle({payload}) {
// TODO: derive memberStatus from payload when paid welcome emails are added
const memberStatus = 'free';
await memberWelcomeEmailService.api.send({member: payload, memberStatus});
await memberWelcomeEmailService.api.send({member: payload, memberStatus: payload.status});
}

function getLogInfo(payload) {
Expand Down
24 changes: 16 additions & 8 deletions ghost/core/test/integration/jobs/process-outbox.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ describe('Process Outbox Job', function () {
memberId: 'member123',
email: 'test@example.com',
name: 'Test Member',
source: 'member'
source: 'member',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING
});
Expand Down Expand Up @@ -115,7 +116,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member1',
email: 'test1@example.com',
name: 'Test Member 1'
name: 'Test Member 1',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING
});
Expand All @@ -125,7 +127,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member2',
email: 'test2@example.com',
name: 'Test Member 2'
name: 'Test Member 2',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING
});
Expand All @@ -135,7 +138,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member3',
email: 'test3@example.com',
name: 'Test Member 3'
name: 'Test Member 3',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING
});
Expand All @@ -156,7 +160,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member1',
email: 'test1@example.com',
name: 'Test Member 1'
name: 'Test Member 1',
status: 'free'
}),
status: OUTBOX_STATUSES.PROCESSING
});
Expand All @@ -166,7 +171,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member2',
email: 'test2@example.com',
name: 'Test Member 2'
name: 'Test Member 2',
status: 'free'
}),
status: OUTBOX_STATUSES.FAILED
});
Expand All @@ -189,7 +195,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member1',
email: 'retry@example.com',
name: 'Retry Member'
name: 'Retry Member',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING,
retry_count: 0
Expand All @@ -214,7 +221,8 @@ describe('Process Outbox Job', function () {
payload: JSON.stringify({
memberId: 'member1',
email: 'maxretry@example.com',
name: 'Max Retry Member'
name: 'Max Retry Member',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING,
retry_count: 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ describe('Member Welcome Emails Integration', function () {
assert.equal(payload.email, 'welcome-test@example.com');
assert.equal(payload.name, 'Welcome Test Member');
assert.equal(payload.source, 'member');
assert.equal(payload.status, 'free');
});

it('does NOT create outbox entry when config is not set', async function () {
Expand Down Expand Up @@ -197,7 +198,8 @@ describe('Member Welcome Emails Integration', function () {
payload: JSON.stringify({
memberId: 'member1',
email: 'inactive@example.com',
name: 'Inactive Template Member'
name: 'Inactive Template Member',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING
});
Expand All @@ -219,7 +221,8 @@ describe('Member Welcome Emails Integration', function () {
payload: JSON.stringify({
memberId: 'member1',
email: 'notemplate@example.com',
name: 'No Template Member'
name: 'No Template Member',
status: 'free'
}),
status: OUTBOX_STATUSES.PENDING
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,5 +669,49 @@ describe('MemberRepository', function () {

sinon.assert.notCalled(Outbox.add);
});

it('does NOT create outbox entry when member is signing up for a paid subscription (stripeCustomer is present)', async function () {
sinon.stub(config, 'get').withArgs('memberWelcomeEmailTestInbox').returns('test-inbox@example.com');

const StripeCustomer = {
upsert: sinon.stub().resolves()
};

const repo = new MemberRepository({
Member,
Outbox,
MemberStatusEvent,
MemberSubscribeEventModel: MemberSubscribeEvent,
newslettersService,
AutomatedEmail,
StripeCustomer,
OfferRedemption: mockOfferRedemption
});

// Stub linkSubscription to avoid needing all the stripe-related mocks
sinon.stub(repo, 'linkSubscription').resolves();
sinon.stub(repo, 'upsertCustomer').resolves();

// Create a member with a stripeCustomer (i.e., signing up for paid subscription)
await repo.create({
email: 'test@example.com',
name: 'Test Member',
stripeCustomer: {
id: 'cus_123',
name: 'Test Member',
email: 'test@example.com',
subscriptions: {
data: [{
id: 'sub_123',
customer: 'cus_123',
status: 'active'
}]
}
}
}, {});

// The free welcome email should NOT be sent when stripeCustomer is present
sinon.assert.notCalled(Outbox.add);
});
});
});
Loading