feat(payments): persist helcimCustomerCode + skip getOrCreateCustomer on card-on-file
This commit is contained in:
parent
134aef6ab0
commit
4442c57223
10 changed files with 330 additions and 33 deletions
|
|
@ -14,6 +14,7 @@ export default defineEventHandler(async (event) => {
|
|||
contributionAmount: member.contributionAmount,
|
||||
billingCadence: member.billingCadence,
|
||||
helcimCustomerId: member.helcimCustomerId,
|
||||
helcimCustomerCode: member.helcimCustomerCode,
|
||||
nextBillingDate: member.nextBillingDate,
|
||||
membershipLevel: `${member.circle}-${member.contributionAmount}`,
|
||||
// Profile fields
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ export default defineEventHandler(async (event) => {
|
|||
circle: body.circle,
|
||||
contributionAmount: body.contributionAmount,
|
||||
helcimCustomerId: customerData.id,
|
||||
helcimCustomerCode: customerData.customerCode,
|
||||
status: 'pending_payment',
|
||||
'agreement.acceptedAt': new Date()
|
||||
}
|
||||
|
|
@ -75,6 +76,7 @@ export default defineEventHandler(async (event) => {
|
|||
circle: body.circle,
|
||||
contributionAmount: body.contributionAmount,
|
||||
helcimCustomerId: customerData.id,
|
||||
helcimCustomerCode: customerData.customerCode,
|
||||
status: 'pending_payment',
|
||||
agreement: { acceptedAt: new Date() }
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@ export default defineEventHandler(async (event) => {
|
|||
try {
|
||||
const customer = await getHelcimCustomer(member.helcimCustomerId)
|
||||
if (customer?.id) {
|
||||
if (!member.helcimCustomerCode && customer.customerCode) {
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { helcimCustomerCode: customer.customerCode } },
|
||||
{ runValidators: false }
|
||||
)
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
customerId: customer.id,
|
||||
|
|
@ -49,10 +56,13 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
|
||||
if (existingCustomer) {
|
||||
if (!member.helcimCustomerId) {
|
||||
if (!member.helcimCustomerId || !member.helcimCustomerCode) {
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { helcimCustomerId: existingCustomer.id } },
|
||||
{ $set: {
|
||||
helcimCustomerId: existingCustomer.id,
|
||||
helcimCustomerCode: existingCustomer.customerCode
|
||||
} },
|
||||
{ runValidators: false }
|
||||
)
|
||||
}
|
||||
|
|
@ -73,7 +83,10 @@ export default defineEventHandler(async (event) => {
|
|||
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { helcimCustomerId: customerData.id } },
|
||||
{ $set: {
|
||||
helcimCustomerId: customerData.id,
|
||||
helcimCustomerCode: customerData.customerCode
|
||||
} },
|
||||
{ runValidators: false }
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
import Member from '../../models/member.js'
|
||||
import Payment from '../../models/payment.js'
|
||||
import { listHelcimCustomerTransactions } from '../../utils/helcim.js'
|
||||
import { getHelcimCustomer, listHelcimCustomerTransactions } from '../../utils/helcim.js'
|
||||
import { connectDB } from '../../utils/mongoose.js'
|
||||
import { upsertPaymentFromHelcim } from '../../utils/payments.js'
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ export default defineEventHandler(async (event) => {
|
|||
|
||||
const members = await Member.find(
|
||||
{ helcimCustomerId: { $exists: true, $ne: null } },
|
||||
{ _id: 1, email: 1, name: 1, helcimCustomerId: 1, helcimSubscriptionId: 1, billingCadence: 1 }
|
||||
{ _id: 1, email: 1, name: 1, helcimCustomerId: 1, helcimCustomerCode: 1, helcimSubscriptionId: 1, billingCadence: 1 }
|
||||
).lean()
|
||||
|
||||
let txExamined = 0
|
||||
|
|
@ -66,6 +66,25 @@ export default defineEventHandler(async (event) => {
|
|||
let memberErrors = 0
|
||||
|
||||
async function processMember(member) {
|
||||
// Opportunistic backfill: members predating the helcimCustomerCode field
|
||||
// get it filled in here so the daily cron acts as the migration. Only on
|
||||
// the missing path — no overwrite, no extra API call once populated.
|
||||
if (!member.helcimCustomerCode) {
|
||||
try {
|
||||
const customer = await getHelcimCustomer(member.helcimCustomerId)
|
||||
if (customer?.customerCode) {
|
||||
await Member.findByIdAndUpdate(
|
||||
member._id,
|
||||
{ $set: { helcimCustomerCode: customer.customerCode } },
|
||||
{ runValidators: false }
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
// Backfill is best-effort — never fail the reconcile run on it.
|
||||
console.warn(`[reconcile] customerCode backfill failed for member=${member._id}: ${err?.message || err}`)
|
||||
}
|
||||
}
|
||||
|
||||
let txs
|
||||
try {
|
||||
txs = await listTransactionsWithRetry(member.helcimCustomerId)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ export default defineEventHandler(async (event) => {
|
|||
bio: body.motivation || undefined,
|
||||
status: body.contributionAmount === 0 ? 'active' : 'pending_payment',
|
||||
helcimCustomerId: helcimCustomer?.id,
|
||||
helcimCustomerCode: helcimCustomer?.customerCode,
|
||||
agreement: { acceptedAt: new Date() },
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue