Files
uldp-degree-mangement-system/models/activity.js
r2xrzh9q2z-lab d1b931d547 first commit
2026-02-02 11:07:09 +07:00

195 lines
5.6 KiB
JavaScript

const mongoose = require("mongoose");
const activitySchema = new mongoose.Schema(
{
// Hero section for activity page header (supports Activities and Booking variants)
hero: {
titleActivities: {
type: String,
trim: true,
default: ''
},
titleBooking: {
type: String,
trim: true,
default: ''
},
bannerImageActivities: {
type: String,
trim: true,
default: ''
},
bannerImageBooking: {
type: String,
trim: true,
default: ''
},
},
name: {
type: String,
required: true,
trim: true,
},
price: {
type: Number,
required: true,
min: 0,
},
priceText: {
type: String,
trim: true,
},
season: [
{
type: String,
enum: ["spring", "summer", "autumn", "winter"],
},
],
age: {
type: [Number],
validate: {
validator: function (v) {
return v.length === 2 && v[0] <= v[1];
},
message: "Age must be an array of [minAge, maxAge]",
},
},
locations: [
{
type: String,
trim: true,
},
],
image: {
type: String,
trim: true,
},
link: {
type: String,
trim: true,
},
// Global filters document (single document in Activity collection)
filters: [
{
label: { type: String, required: true, trim: true },
value: { type: String, required: true, trim: true },
items: [
{
value: { type: String, required: true },
label: { type: String, required: true },
},
],
order: { type: Number, default: 0 },
},
],
program: {
type: String,
trim: true,
},
rating: {
type: Number,
min: 1,
max: 5,
default: 4,
},
isActive: {
type: Boolean,
default: true,
},
order: {
type: Number,
default: 0,
},
// marker for the single document that stores global filters
isFiltersDoc: {
type: Boolean,
default: false,
},
// Rich camp details from camp-detail field in activities.json
campDetail: {
type: mongoose.Schema.Types.Mixed,
default: {},
},
// Booking sessions - các đợt booking với thông số riêng
bookingSessions: [
{
sessionId: { type: String, required: true },
startDate: { type: Date, required: true },
endDate: { type: Date, required: true },
overnightStays: { type: Number, required: true, default: 14 },
// Spots theo giới tính
totalMaleSpots: { type: Number, default: 25 },
totalFemaleSpots: { type: Number, default: 25 },
bookedMaleSpots: { type: Number, default: 0 },
bookedFemaleSpots: { type: Number, default: 0 },
price: { type: Number },
isActive: { type: Boolean, default: true },
// Danh sách booking cho session này
bookingList: [
{
address: { type: String, required: true },
agreeNewsletter: { type: Boolean, default: false },
agreeTerms: { type: Boolean, required: true },
city: { type: String, required: true },
country: { type: String, required: true },
dietaryRestrictions: {
type: String,
enum: ['none', 'vegetarian', 'vegan', 'halal', 'kosher', 'gluten-free', 'other'],
default: 'none'
},
email: {
type: String,
required: true,
lowercase: true,
trim: true
},
emergencyContact: { type: String, required: true },
emergencyPhone: { type: String, required: true },
medicalConditions: { type: String, default: '' },
numberOfParticipants: { type: Number, required: true, min: 1 },
parentFirstName: { type: String, required: true, trim: true },
parentLastName: { type: String, required: true, trim: true },
participantBirthDate: { type: Date, required: true },
participantFirstName: { type: String, required: true, trim: true },
participantGender: {
type: String,
enum: ['male', 'female', 'other'],
required: true
},
participantLastName: { type: String, required: true, trim: true },
phone: { type: String, required: true },
postalCode: { type: String, required: true },
sessionDate: { type: String, required: true }, // sessionId reference
specialRequests: { type: String, default: '' },
// Thêm các trường quản lý
bookingStatus: {
type: String,
enum: ['pending', 'confirmed', 'cancelled', 'completed'],
default: 'pending'
},
paymentStatus: {
type: String,
enum: ['pending', 'partial', 'paid', 'refunded'],
default: 'pending'
},
totalAmount: { type: Number, default: 0 },
paidAmount: { type: Number, default: 0 },
bookingDate: { type: Date, default: Date.now },
confirmationCode: { type: String, unique: true },
adminNotes: { type: String, default: '' }
}
]
}
],
},
{timestamps: true}
);
// Add index for better query performance
activitySchema.index({name: 1});
activitySchema.index({isActive: 1, order: 1});
activitySchema.index({season: 1});
activitySchema.index({locations: 1});
module.exports = mongoose.model("Activity", activitySchema);