refactor(events): gate member benefits on hasMemberAccess
Extracts hasMemberAccess(member) in tickets.js and uses it across event registration, ticket purchase, and series purchase flows so guest, suspended, and cancelled records no longer count as members while pending_payment still does.
This commit is contained in:
parent
c5e901ed24
commit
15329e3e84
7 changed files with 188 additions and 30 deletions
|
|
@ -4,6 +4,7 @@ import { connectDB } from "../../../utils/mongoose.js";
|
|||
import { sendEventRegistrationEmail } from "../../../utils/resend.js";
|
||||
import { validateBody } from "../../../utils/validateBody.js";
|
||||
import { eventRegistrationSchema } from "../../../utils/schemas.js";
|
||||
import { hasMemberAccess } from "../../../utils/tickets.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
|
@ -63,10 +64,13 @@ export default defineEventHandler(async (event) => {
|
|||
});
|
||||
}
|
||||
|
||||
// Check member status and handle different registration scenarios
|
||||
// Check member status and handle different registration scenarios.
|
||||
// Member access is decoupled from payment status: active and pending_payment
|
||||
// both confer access; guest, suspended, and cancelled do not.
|
||||
const member = await Member.findOne({ email: body.email.toLowerCase() });
|
||||
const memberHasAccess = hasMemberAccess(member);
|
||||
|
||||
if (eventData.membersOnly && !member) {
|
||||
if (eventData.membersOnly && !memberHasAccess) {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage:
|
||||
|
|
@ -78,7 +82,7 @@ export default defineEventHandler(async (event) => {
|
|||
if (
|
||||
eventData.pricing?.paymentRequired &&
|
||||
!eventData.pricing?.isFree &&
|
||||
!member
|
||||
!memberHasAccess
|
||||
) {
|
||||
throw createError({
|
||||
statusCode: 402, // Payment Required
|
||||
|
|
@ -91,7 +95,7 @@ export default defineEventHandler(async (event) => {
|
|||
let isMember = false;
|
||||
let membershipLevel = "non-member";
|
||||
|
||||
if (member) {
|
||||
if (memberHasAccess) {
|
||||
isMember = true;
|
||||
membershipLevel = `${member.circle}-${member.contributionTier}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
validateTicketPurchase,
|
||||
calculateTicketPrice,
|
||||
completeTicketPurchase,
|
||||
hasMemberAccess,
|
||||
} from "../../../../utils/tickets.js";
|
||||
import { sendEventRegistrationEmail } from "../../../../utils/resend.js";
|
||||
import mongoose from "mongoose";
|
||||
|
|
@ -43,16 +44,17 @@ export default defineEventHandler(async (event) => {
|
|||
});
|
||||
}
|
||||
|
||||
// Check if user is a member. Guests don't count as members for pricing/validation.
|
||||
// Check if user is a member. Only members with access (active or
|
||||
// pending_payment) count for pricing/validation; guest, suspended,
|
||||
// and cancelled members are treated as non-members.
|
||||
let member = await Member.findOne({ email: body.email.toLowerCase() });
|
||||
let accountCreated = false;
|
||||
const isRealMember = (m) => !!m && m.status !== "guest";
|
||||
|
||||
// Validate ticket purchase
|
||||
const validation = validateTicketPurchase(eventData, {
|
||||
email: body.email,
|
||||
name: body.name,
|
||||
member: isRealMember(member) ? member : null,
|
||||
member: hasMemberAccess(member) ? member : null,
|
||||
});
|
||||
|
||||
if (!validation.valid) {
|
||||
|
|
@ -109,15 +111,15 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
|
||||
// Create registration
|
||||
const realMember = isRealMember(member);
|
||||
const memberHasAccess = hasMemberAccess(member);
|
||||
const registration = {
|
||||
memberId: member ? member._id : null,
|
||||
name: body.name,
|
||||
email: body.email.toLowerCase(),
|
||||
membershipLevel: realMember
|
||||
membershipLevel: memberHasAccess
|
||||
? `${member.circle}-${member.contributionTier}`
|
||||
: "non-member",
|
||||
isMember: realMember,
|
||||
isMember: memberHasAccess,
|
||||
ticketType: ticketInfo.ticketType,
|
||||
ticketPrice: ticketInfo.price,
|
||||
paymentStatus: requiresPayment ? "completed" : "not_required",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue