fix(join): persist billingCadence on /join signup
Mirror of the invite-accept fix (c3b1c59) for the self-serve /join path. A joiner who picked annual but abandoned before /api/helcim/subscription ran was left at billingCadence:'monthly' (the model default) with a cadence-unit contributionAmount, rendering $180/mo in admin views.
join.vue now sends cadence to /api/helcim/customer; helcimCustomerSchema accepts cadence (defaults 'monthly'); customer.post.js persists billingCadence in both the new-member create branch and the guest-upgrade $set branch, forced to 'monthly' for $0 signups.
This commit is contained in:
parent
c3b1c59779
commit
426f233ccd
4 changed files with 67 additions and 0 deletions
|
|
@ -385,4 +385,67 @@ describe('POST /api/helcim/customer', () => {
|
|||
expect(setAuthCookie).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
// Regression: a joiner who picks annual but abandons before
|
||||
// /api/helcim/subscription runs must already have billingCadence persisted,
|
||||
// otherwise contributionAmount (cadence-unit, e.g. 180) renders as "$180/mo".
|
||||
describe('billingCadence persistence', () => {
|
||||
it('persists billingCadence "annual" when a new member signs up annual', async () => {
|
||||
Member.findOne.mockResolvedValue(null)
|
||||
const event = build({
|
||||
body: {
|
||||
name: 'Annual Joiner',
|
||||
email: 'annual@example.com',
|
||||
circle: 'community',
|
||||
contributionAmount: 180,
|
||||
cadence: 'annual',
|
||||
agreedToGuidelines: true
|
||||
}
|
||||
})
|
||||
await customerHandler(event)
|
||||
expect(Member.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ contributionAmount: 180, billingCadence: 'annual' })
|
||||
)
|
||||
})
|
||||
|
||||
it('persists billingCadence "annual" when upgrading a guest who signs up annual', async () => {
|
||||
Member.findOne.mockResolvedValue({
|
||||
_id: 'guest-annual',
|
||||
email: 'guest@example.com',
|
||||
status: 'guest'
|
||||
})
|
||||
const event = build({
|
||||
body: {
|
||||
name: 'Guest Annual',
|
||||
email: 'guest@example.com',
|
||||
circle: 'founder',
|
||||
contributionAmount: 180,
|
||||
cadence: 'annual',
|
||||
agreedToGuidelines: true
|
||||
}
|
||||
})
|
||||
await customerHandler(event)
|
||||
expect(Member.create).not.toHaveBeenCalled()
|
||||
const [, updatePayload] = Member.findByIdAndUpdate.mock.calls[0]
|
||||
expect(updatePayload.$set).toMatchObject({ contributionAmount: 180, billingCadence: 'annual' })
|
||||
})
|
||||
|
||||
it('forces billingCadence "monthly" for a $0 signup even when cadence is annual', async () => {
|
||||
Member.findOne.mockResolvedValue(null)
|
||||
const event = build({
|
||||
body: {
|
||||
name: 'Free Joiner',
|
||||
email: 'free@example.com',
|
||||
circle: 'community',
|
||||
contributionAmount: 0,
|
||||
cadence: 'annual',
|
||||
agreedToGuidelines: true
|
||||
}
|
||||
})
|
||||
await customerHandler(event)
|
||||
expect(Member.create).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ contributionAmount: 0, billingCadence: 'monthly' })
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue