refactor(helcim): wrapped PATCH body, first-activation welcome email guard
Moves updateHelcimSubscription to the live-verified wrapped shape
(PATCH /subscriptions { subscriptions: [{ id, ...payload }] }), adds a prior-
status check so sendWelcomeEmail only fires on pending_payment to active
transitions, short-circuits get-or-create-customer when a valid
helcimCustomerId is already on file, and replaces member.save() Slack-status
writes with findByIdAndUpdate({ runValidators: false }) to avoid save-time
validator pitfalls.
This commit is contained in:
parent
37a58cb0eb
commit
4f567e9586
4 changed files with 100 additions and 41 deletions
|
|
@ -1,17 +1,47 @@
|
|||
// Get existing or create new Helcim customer (for upgrading members)
|
||||
import Member from '../../models/member.js'
|
||||
import { requireAuth } from '../../utils/auth.js'
|
||||
import { findHelcimCustomerByEmail, createHelcimCustomer } from '../../utils/helcim.js'
|
||||
import {
|
||||
getHelcimCustomer,
|
||||
findHelcimCustomerByEmail,
|
||||
createHelcimCustomer
|
||||
} from '../../utils/helcim.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const member = await requireAuth(event)
|
||||
|
||||
// First, try to find an existing customer
|
||||
// 1. Short-circuit: member already has a Helcim customer ID on file.
|
||||
// Verify it still resolves before falling through — otherwise we'd
|
||||
// silently orphan the old customer and create a duplicate.
|
||||
if (member.helcimCustomerId) {
|
||||
try {
|
||||
const customer = await getHelcimCustomer(member.helcimCustomerId)
|
||||
if (customer?.id) {
|
||||
return {
|
||||
success: true,
|
||||
customerId: customer.id,
|
||||
customerCode: customer.customerCode,
|
||||
existing: true
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// Only fall through on 404 (customer was deleted in Helcim).
|
||||
// Any other error must propagate — silently recreating was the
|
||||
// original duplicate-customer bug.
|
||||
if (err?.statusCode !== 404) throw err
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fall back to search by email (case-insensitive match).
|
||||
let existingCustomer = null
|
||||
try {
|
||||
const searchData = await findHelcimCustomerByEmail(member.email)
|
||||
if (searchData.customers && searchData.customers.length > 0) {
|
||||
existingCustomer = searchData.customers.find(c => c.email === member.email) || null
|
||||
const memberEmail = member.email.toLowerCase()
|
||||
if (searchData.customers?.length) {
|
||||
existingCustomer = searchData.customers.find(
|
||||
c => c.email?.toLowerCase() === memberEmail
|
||||
) || null
|
||||
}
|
||||
} catch (searchError) {
|
||||
console.error('Error searching for customer:', searchError)
|
||||
|
|
@ -20,8 +50,11 @@ export default defineEventHandler(async (event) => {
|
|||
|
||||
if (existingCustomer) {
|
||||
if (!member.helcimCustomerId) {
|
||||
member.helcimCustomerId = existingCustomer.id
|
||||
await member.save()
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { helcimCustomerId: existingCustomer.id } },
|
||||
{ runValidators: false }
|
||||
)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
|
|
@ -31,15 +64,18 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
}
|
||||
|
||||
// No existing customer found — create one
|
||||
// 3. No match anywhere — create a fresh customer.
|
||||
const customerData = await createHelcimCustomer({
|
||||
contactName: member.name,
|
||||
businessName: member.name,
|
||||
email: member.email
|
||||
})
|
||||
|
||||
member.helcimCustomerId = customerData.id
|
||||
await member.save()
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { helcimCustomerId: customerData.id } },
|
||||
{ runValidators: false }
|
||||
)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue