diff --git a/server/api/helcim/subscription.post.js b/server/api/helcim/subscription.post.js index d02846f..63d9b6c 100644 --- a/server/api/helcim/subscription.post.js +++ b/server/api/helcim/subscription.post.js @@ -47,6 +47,7 @@ export default defineEventHandler(async (event) => { member.email, member.circle, member.contributionAmount, + member.billingCadence, 'manual_invitation_required' ) } @@ -79,9 +80,7 @@ export default defineEventHandler(async (event) => { const cadence = body.cadence const paymentPlanId = getHelcimPlanId(cadence) - const recurringAmount = cadence === 'annual' - ? body.contributionAmount * 12 - : body.contributionAmount + const recurringAmount = body.contributionAmount if (!paymentPlanId) { throw createError({ @@ -159,6 +158,7 @@ export default defineEventHandler(async (event) => { member.email, member.circle, member.contributionAmount, + member.billingCadence, 'manual_invitation_required' ) } diff --git a/server/api/members/create.post.js b/server/api/members/create.post.js index 9b78831..ee85350 100644 --- a/server/api/members/create.post.js +++ b/server/api/members/create.post.js @@ -43,6 +43,7 @@ export default defineEventHandler(async (event) => { member.email, member.circle, member.contributionAmount, + member.billingCadence, 'manual_invitation_required' ) } diff --git a/server/api/members/update-contribution.post.js b/server/api/members/update-contribution.post.js index 3e2c071..bc2bf4c 100644 --- a/server/api/members/update-contribution.post.js +++ b/server/api/members/update-contribution.post.js @@ -88,7 +88,7 @@ export default defineEventHandler(async (event) => { dateActivated: new Date().toISOString().split("T")[0], paymentPlanId: parseInt(paymentPlanId), customerCode, - recurringAmount: cadence === 'annual' ? newAmount * 12 : newAmount, + recurringAmount: newAmount, paymentMethod: "card", }, idempotencyKey, @@ -217,7 +217,7 @@ export default defineEventHandler(async (event) => { try { const subscriptionData = await updateHelcimSubscription( member.helcimSubscriptionId, - { recurringAmount: memberCadence === 'annual' ? newAmount * 12 : newAmount } + { recurringAmount: newAmount } ); await Member.findByIdAndUpdate( diff --git a/server/utils/slack.ts b/server/utils/slack.ts index 2216e21..0211837 100644 --- a/server/utils/slack.ts +++ b/server/utils/slack.ts @@ -90,6 +90,7 @@ export class SlackService { memberEmail: string, circle: string, contributionAmount: number, + cadence: string = 'monthly', invitationStatus: string = "manual_invitation_required", ): Promise { try { @@ -148,7 +149,7 @@ export class SlackService { }, { type: "mrkdwn", - text: `*Contribution:*\n$${contributionAmount}/month`, + text: `*Contribution:*\n$${contributionAmount}/${cadence === 'annual' ? 'yr' : 'mo'}`, }, ], }, diff --git a/tests/server/api/helcim-subscription.test.js b/tests/server/api/helcim-subscription.test.js index 6845cd4..f755297 100644 --- a/tests/server/api/helcim-subscription.test.js +++ b/tests/server/api/helcim-subscription.test.js @@ -201,7 +201,7 @@ describe('helcim subscription endpoint', () => { expect(result.subscription.nextBillingDate).toBe('2026-06-01') }) - it('annual $15 tier creates subscription with correct paymentPlanId and recurringAmount', async () => { + it('annual $180 tier creates subscription with correct paymentPlanId and recurringAmount', async () => { requireAuth.mockResolvedValue(undefined) requiresPayment.mockReturnValue(true) getHelcimPlanId.mockReturnValue('88888') @@ -211,7 +211,7 @@ describe('helcim subscription endpoint', () => { email: 'annual@example.com', name: 'Annual User', circle: 'founder', - contributionAmount: 15, + contributionAmount: 180, status: 'active', } Member.findOneAndUpdate.mockResolvedValue({ _id: 'member-3', status: 'pending_payment' }) @@ -223,7 +223,7 @@ describe('helcim subscription endpoint', () => { const event = createMockEvent({ method: 'POST', path: '/api/helcim/subscription', - body: { customerId: 'cust-1', contributionAmount: 15, customerCode: 'code-1', cardToken: 'tok-123', cadence: 'annual' } + body: { customerId: 'cust-1', contributionAmount: 180, customerCode: 'code-1', cardToken: 'tok-123', cadence: 'annual' } }) const result = await subscriptionHandler(event) @@ -235,13 +235,13 @@ describe('helcim subscription endpoint', () => { ) expect(Member.findOneAndUpdate).toHaveBeenCalledWith( { helcimCustomerId: 'cust-1' }, - { $set: expect.objectContaining({ billingCadence: 'annual', contributionAmount: 15, status: 'active' }) }, + { $set: expect.objectContaining({ billingCadence: 'annual', contributionAmount: 180, status: 'active' }) }, { new: false, runValidators: false, projection: { status: 1 } } ) expect(Member.findById).toHaveBeenCalledWith('member-3') }) - it('annual $50 tier recurringAmount is 600', async () => { + it('annual $600 tier recurringAmount is 600', async () => { requireAuth.mockResolvedValue(undefined) requiresPayment.mockReturnValue(true) getHelcimPlanId.mockReturnValue('88888') @@ -251,7 +251,7 @@ describe('helcim subscription endpoint', () => { email: 'top@example.com', name: 'Top Tier', circle: 'practitioner', - contributionAmount: 50, + contributionAmount: 600, status: 'active', } Member.findOneAndUpdate.mockResolvedValue({ _id: 'member-4', status: 'pending_payment' }) @@ -263,7 +263,7 @@ describe('helcim subscription endpoint', () => { const event = createMockEvent({ method: 'POST', path: '/api/helcim/subscription', - body: { customerId: 'cust-2', contributionAmount: 50, customerCode: 'code-2', cardToken: 'tok-456', cadence: 'annual' } + body: { customerId: 'cust-2', contributionAmount: 600, customerCode: 'code-2', cardToken: 'tok-456', cadence: 'annual' } }) await subscriptionHandler(event) diff --git a/tests/server/api/update-contribution.test.js b/tests/server/api/update-contribution.test.js index 0519c44..c71e039 100644 --- a/tests/server/api/update-contribution.test.js +++ b/tests/server/api/update-contribution.test.js @@ -83,10 +83,10 @@ describe('update-contribution endpoint — Case 3 (paid→paid)', () => { expect(result.message).toBe('Successfully updated contribution level') }) - it('annual $5 → $15: calls updateHelcimSubscription with recurringAmount 180', async () => { + it('annual $60 → $180: calls updateHelcimSubscription with recurringAmount 180', async () => { const mockMember = { _id: 'member-2', - contributionAmount: 5, + contributionAmount: 60, helcimSubscriptionId: 'sub-2', billingCadence: 'annual', } @@ -97,7 +97,7 @@ describe('update-contribution endpoint — Case 3 (paid→paid)', () => { const event = createMockEvent({ method: 'POST', path: '/api/members/update-contribution', - body: { contributionAmount: 15, cadence: 'annual' }, + body: { contributionAmount: 180, cadence: 'annual' }, }) const result = await handler(event) @@ -105,16 +105,16 @@ describe('update-contribution endpoint — Case 3 (paid→paid)', () => { expect(updateHelcimSubscription).toHaveBeenCalledWith('sub-2', { recurringAmount: 180 }) expect(Member.findByIdAndUpdate).toHaveBeenCalledWith( 'member-2', - { $set: { contributionAmount: 15 } }, + { $set: { contributionAmount: 180 } }, { runValidators: false } ) expect(result.success).toBe(true) }) - it('annual $15 → $50: calls updateHelcimSubscription with recurringAmount 600', async () => { + it('annual $180 → $600: calls updateHelcimSubscription with recurringAmount 600', async () => { const mockMember = { _id: 'member-3', - contributionAmount: 15, + contributionAmount: 180, helcimSubscriptionId: 'sub-3', billingCadence: 'annual', } @@ -125,7 +125,7 @@ describe('update-contribution endpoint — Case 3 (paid→paid)', () => { const event = createMockEvent({ method: 'POST', path: '/api/members/update-contribution', - body: { contributionAmount: 50, cadence: 'annual' }, + body: { contributionAmount: 600, cadence: 'annual' }, }) await handler(event) @@ -296,7 +296,7 @@ describe('update-contribution endpoint — Case 1 (free→paid)', () => { const event = createMockEvent({ method: 'POST', path: '/api/members/update-contribution', - body: { contributionAmount: 15, cadence: 'annual' }, + body: { contributionAmount: 180, cadence: 'annual' }, }) const result = await handler(event) @@ -307,7 +307,7 @@ describe('update-contribution endpoint — Case 1 (free→paid)', () => { ) expect(Member.findByIdAndUpdate).toHaveBeenCalledWith( 'member-c1', - { $set: expect.objectContaining({ billingCadence: 'annual', contributionAmount: 15, helcimSubscriptionId: 'sub-annual' }) }, + { $set: expect.objectContaining({ billingCadence: 'annual', contributionAmount: 180, helcimSubscriptionId: 'sub-annual' }) }, { runValidators: false } ) expect(result.success).toBe(true)