@ideal-photography/shared
Version:
Shared MongoDB and utility logic for Ideal Photography PWAs: users, products, services, bookings, orders/cart, galleries, reviews, notifications, campaigns, settings, audit logs, minimart items/orders, and push notification subscriptions.
204 lines (192 loc) • 5.34 kB
JavaScript
import mongoose from 'mongoose';
const bookingSchema = new mongoose.Schema({
bookingNumber: {
type: String,
required: true,
unique: true
},
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
orderId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Order',
required: true
},
// Service details
serviceType: {
type: String,
required: true,
enum: ['makeover', 'studio', 'service']
},
serviceName: {
type: String,
required: true
},
// Booking schedule
preferredDate: {
type: Date,
required: true
},
preferredTime: {
type: String,
required: true
},
duration: {
type: Number, // in hours
required: true
},
// Location details
location: {
type: String,
required: true
},
address: {
street: String,
city: String,
state: String,
zipCode: String,
country: { type: String, default: 'Nigeria' }
},
// Special requirements
specialInstructions: String,
requirements: [String],
// Booking status
status: {
type: String,
enum: ['pending', 'confirmed', 'in_progress', 'completed', 'cancelled', 'rescheduled', 'overdue', 'auto_completed'],
default: 'pending'
},
// Metadata for automated transitions
metadata: {
autoTransitioned: { type: Boolean, default: false },
autoTransitionedAt: Date
},
// Confirmation details
confirmedDate: Date,
confirmedTime: String,
confirmedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
// Completion details
completedAt: Date,
completedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
// Cancellation details
cancelledAt: Date,
cancelledBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
cancellationReason: String,
// Rescheduling details
rescheduledFrom: {
date: Date,
time: String
},
rescheduledAt: Date,
rescheduledBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
rescheduleReason: String,
// Notes and feedback
notes: String,
customerFeedback: String,
staffNotes: String,
// Timestamps
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
}, {
timestamps: true
});
// Indexes (bookingNumber already has unique index from schema definition)
bookingSchema.index({ userId: 1 });
bookingSchema.index({ orderId: 1 });
bookingSchema.index({ status: 1 });
bookingSchema.index({ preferredDate: 1 });
bookingSchema.index({ serviceType: 1 });
// Method to generate booking number
bookingSchema.statics.generateBookingNumber = function () {
const timestamp = Date.now().toString(36);
const random = Math.random().toString(36).substr(2, 5);
return `BK-${timestamp}-${random}`.toUpperCase();
};
// Method to confirm booking
bookingSchema.methods.confirm = function (confirmedBy, confirmedDate = null, confirmedTime = null) {
this.status = 'confirmed';
this.confirmedBy = confirmedBy;
this.confirmedDate = confirmedDate || this.preferredDate;
this.confirmedTime = confirmedTime || this.preferredTime;
this.updatedAt = new Date();
return this;
};
// Method to start booking
bookingSchema.methods.start = function (startedBy) {
this.status = 'in_progress';
this.updatedAt = new Date();
return this;
};
// Method to complete booking
bookingSchema.methods.complete = function (completedBy, notes = null) {
this.status = 'completed';
this.completedAt = new Date();
this.completedBy = completedBy;
if (notes) {
this.staffNotes = notes;
}
this.updatedAt = new Date();
return this;
};
// Method to cancel booking
bookingSchema.methods.cancel = function (cancelledBy, reason = null) {
this.status = 'cancelled';
this.cancelledAt = new Date();
this.cancelledBy = cancelledBy;
if (reason) {
this.cancellationReason = reason;
}
this.updatedAt = new Date();
return this;
};
// Method to reschedule booking
bookingSchema.methods.reschedule = function (newDate, newTime, rescheduledBy, reason = null) {
this.rescheduledFrom = {
date: this.preferredDate,
time: this.preferredTime
};
this.preferredDate = newDate;
this.preferredTime = newTime;
this.status = 'rescheduled';
this.rescheduledAt = new Date();
this.rescheduledBy = rescheduledBy;
if (reason) {
this.rescheduleReason = reason;
}
this.updatedAt = new Date();
return this;
};
// Method to check if booking is active
bookingSchema.methods.isActive = function () {
return ['pending', 'confirmed', 'in_progress'].includes(this.status);
};
// Method to check if booking is completed
bookingSchema.methods.isCompleted = function () {
return this.status === 'completed';
};
// Method to check if booking is cancelled
bookingSchema.methods.isCancelled = function () {
return this.status === 'cancelled';
};
export default mongoose.model('Booking', bookingSchema);