merge: catch up with feature/helcim-plan-consolidation base
# Conflicts: # server/api/auth/member.get.js # server/api/members/update-contribution.post.js # tests/server/api/update-contribution.test.js
This commit is contained in:
commit
7704557f16
10 changed files with 160 additions and 9 deletions
|
|
@ -14,6 +14,7 @@ export default defineEventHandler(async (event) => {
|
|||
contributionAmount: member.contributionAmount,
|
||||
billingCadence: member.billingCadence,
|
||||
helcimCustomerId: member.helcimCustomerId,
|
||||
nextBillingDate: member.nextBillingDate,
|
||||
membershipLevel: `${member.circle}-${member.contributionAmount}`,
|
||||
// Profile fields
|
||||
pronouns: member.pronouns,
|
||||
|
|
|
|||
56
server/api/helcim/subscription.get.js
Normal file
56
server/api/helcim/subscription.get.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Refresh the authenticated member's cached nextBillingDate from Helcim.
|
||||
// The account page calls this only when the stored date is stale (missing,
|
||||
// past, or within ~24h). On success, writes the fresh date back to the member
|
||||
// record so subsequent loads can render instantly from /api/auth/member.
|
||||
//
|
||||
// On Helcim errors, returns { subscription: null, error: 'unavailable' } (HTTP 200)
|
||||
// so the client can fall back to the cached value (if any) without crashing.
|
||||
import { requireAuth } from '../../utils/auth.js'
|
||||
import { getHelcimSubscription } from '../../utils/helcim.js'
|
||||
import Member from '../../models/member.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const member = await requireAuth(event)
|
||||
|
||||
if (!member.helcimSubscriptionId) {
|
||||
return { subscription: null }
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await getHelcimSubscription(member.helcimSubscriptionId)
|
||||
const subscription = Array.isArray(response)
|
||||
? response[0]
|
||||
: (response?.data?.[0] || response)
|
||||
|
||||
const nextBillingDate = subscription?.nextBillingDate || null
|
||||
|
||||
if (nextBillingDate) {
|
||||
const parsed = new Date(nextBillingDate)
|
||||
if (!Number.isNaN(parsed.getTime())) {
|
||||
await connectDB()
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { nextBillingDate: parsed } },
|
||||
{ runValidators: false }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
subscription: subscription
|
||||
? {
|
||||
id: String(subscription.id ?? ''),
|
||||
status: subscription.status || '',
|
||||
nextBillingDate: nextBillingDate || '',
|
||||
}
|
||||
: null,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[subscription.get] Helcim lookup failed', {
|
||||
helcimSubscriptionId: member.helcimSubscriptionId,
|
||||
error: error?.message || error,
|
||||
})
|
||||
return { subscription: null, error: 'unavailable' }
|
||||
}
|
||||
})
|
||||
|
|
@ -165,6 +165,10 @@ export default defineEventHandler(async (event) => {
|
|||
throw createError({ statusCode: 500, statusMessage: 'Subscription creation failed' })
|
||||
}
|
||||
|
||||
const nextBillingDate = subscription.nextBillingDate
|
||||
? new Date(subscription.nextBillingDate)
|
||||
: null
|
||||
|
||||
// Update member in database
|
||||
const member = await Member.findOneAndUpdate(
|
||||
{ helcimCustomerId: body.customerId },
|
||||
|
|
@ -176,6 +180,9 @@ export default defineEventHandler(async (event) => {
|
|||
billingCadence: cadence,
|
||||
subscriptionStartDate: new Date(),
|
||||
status: 'active',
|
||||
...(nextBillingDate && !Number.isNaN(nextBillingDate.getTime())
|
||||
? { nextBillingDate }
|
||||
: {}),
|
||||
} },
|
||||
{ new: true, runValidators: false }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export default defineEventHandler(async (event) => {
|
|||
paymentMethod: 'none',
|
||||
subscriptionEndDate: new Date(),
|
||||
},
|
||||
$unset: { nextBillingDate: 1 },
|
||||
},
|
||||
{ runValidators: false }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@ export default defineEventHandler(async (event) => {
|
|||
throw new Error("No subscription returned in response");
|
||||
}
|
||||
|
||||
const nextBillingDate = subscription.nextBillingDate
|
||||
? new Date(subscription.nextBillingDate)
|
||||
: null;
|
||||
|
||||
// Update member record
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
|
|
@ -107,6 +111,9 @@ export default defineEventHandler(async (event) => {
|
|||
paymentMethod: "card",
|
||||
status: "active",
|
||||
billingCadence: cadence,
|
||||
...(nextBillingDate && !Number.isNaN(nextBillingDate.getTime())
|
||||
? { nextBillingDate }
|
||||
: {}),
|
||||
} },
|
||||
{ runValidators: false }
|
||||
);
|
||||
|
|
@ -148,7 +155,10 @@ export default defineEventHandler(async (event) => {
|
|||
// Update member to free tier
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { contributionAmount: newAmount, helcimSubscriptionId: null, paymentMethod: "none", billingCadence: "monthly" } },
|
||||
{
|
||||
$set: { contributionAmount: newAmount, helcimSubscriptionId: null, paymentMethod: "none", billingCadence: "monthly" },
|
||||
$unset: { nextBillingDate: 1 },
|
||||
},
|
||||
{ runValidators: false }
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,9 @@ const ACTIVITY_TYPES = [
|
|||
'connection_requested',
|
||||
'connection_confirmed',
|
||||
'tag_suggested',
|
||||
'billing_card_updated'
|
||||
'billing_card_updated',
|
||||
'member_onboarding_goal_completed',
|
||||
'member_onboarding_completed'
|
||||
]
|
||||
|
||||
const activityLogSchema = new mongoose.Schema({
|
||||
|
|
|
|||
|
|
@ -134,6 +134,9 @@ export const createHelcimSubscription = (subscription, idempotencyKey) =>
|
|||
errorMessage: 'Subscription creation failed'
|
||||
})
|
||||
|
||||
export const getHelcimSubscription = (id) =>
|
||||
helcimFetch(`/subscriptions/${id}`, { errorMessage: 'Subscription lookup failed' })
|
||||
|
||||
export const cancelHelcimSubscription = (id) =>
|
||||
helcimFetch(`/subscriptions/${id}`, { method: 'DELETE', errorMessage: 'Subscription cancellation failed' })
|
||||
|
||||
|
|
@ -188,7 +191,13 @@ export async function listHelcimCustomerTransactions(customerCode) {
|
|||
? response
|
||||
: (response?.transactions || response?.data || [])
|
||||
|
||||
const sorted = [...rows].sort((a, b) => {
|
||||
const filtered = rows.filter((t) => {
|
||||
const type = String(t?.type || '').toLowerCase()
|
||||
const amount = typeof t?.amount === 'number' ? t.amount : Number(t?.amount) || 0
|
||||
return type !== 'verify' && amount > 0
|
||||
})
|
||||
|
||||
const sorted = [...filtered].sort((a, b) => {
|
||||
const da = Date.parse(a?.dateCreated || '') || 0
|
||||
const db = Date.parse(b?.dateCreated || '') || 0
|
||||
return db - da
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue