UNPKG

@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.

297 lines (289 loc) 7.05 kB
import mongoose from 'mongoose'; const equipmentSchema = new mongoose.Schema({ name: { type: String, required: true, trim: true }, description: { type: String, required: true }, price: { type: Number, required: true, min: 0 }, pricing: { baseRate: { type: Number, min: 0, default: function () { return this.price || 0; } }, rateType: { type: String, enum: ['hourly', 'daily', 'weekly', 'monthly', 'fixed'], default: 'daily' }, currency: { type: String, default: 'NGN' }, discounts: [{ type: { type: String, enum: ['percentage', 'fixed', 'bulk'] }, value: Number, minQuantity: Number, validFrom: Date, validUntil: Date, description: String }], seasonalPricing: [{ name: String, multiplier: Number, startDate: String, endDate: String, description: String }] }, category: { type: String, required: true, enum: [ 'cameras', 'lenses', 'tripods', 'lighting', 'audio', 'screens', 'accessories', 'stabilizers', 'filters', 'memory_cards', 'batteries', 'bags', 'monitors', 'computers', 'projectors', 'microphones', 'stands', 'cables', 'adapters', 'tools', 'cases', 'other' ] }, subcategory: { type: String, required: false // Make optional to match validation }, shortDescription: { type: String, maxlength: 200 }, type: { type: String, default: 'equipment_rental' }, images: [{ url: String, alt: String, isPrimary: { type: Boolean, default: false } }], isActive: { type: Boolean, default: true }, stock: { type: Number, default: 0, min: 0 }, // Additional fields expected by Admin system specifications: { type: Map, of: mongoose.Schema.Types.Mixed, default: {} }, features: [{ type: String, maxlength: 200 }], whatsIncluded: [{ type: String, maxlength: 200 }], requirements: [{ type: String, maxlength: 200 }], usageInstructions: { type: String, maxlength: 1000 }, tags: [String], sku: { type: String, unique: true, sparse: true }, barcode: String, isFeatured: { type: Boolean, default: false }, isDigital: { type: Boolean, default: false }, inventory: { totalUnits: { type: Number, min: 1, default: 1 }, availableUnits: { type: Number, min: 0, default: 1 }, condition: { type: String, enum: ['excellent', 'good', 'fair', 'needs_repair'], default: 'excellent' }, serialNumbers: [String] }, availabilityRules: { minRentalPeriod: { type: Number, default: 1 }, maxRentalPeriod: { type: Number, default: 168 }, advanceBookingRequired: { type: Number, default: 1 } }, analytics: { viewCount: { type: Number, default: 0 }, purchaseCount: { type: Number, default: 0 }, reviewCount: { type: Number, default: 0 }, revenue: { type: Number, default: 0 }, popularityScore: { type: Number, default: 0 }, rentalCount: { type: Number, default: 0 }, averageRating: { type: Number, default: 0 } }, relatedProducts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Equipment' }], createdBy: { type: mongoose.Schema.Types.ObjectId, ref: 'Admin' }, lastModifiedBy: { type: mongoose.Schema.Types.ObjectId, ref: 'Admin' }, discount: { type: { type: String, enum: ['percentage', 'fixed'], default: 'percentage' }, value: { type: Number, default: 0 }, isActive: { type: Boolean, default: false } }, maintenance: { serviceHistory: [{ date: Date, description: String, cost: Number, performedBy: String }] }, bundleProducts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Equipment' }], uuid: { type: String, unique: true, sparse: true }, metadata: { type: Map, of: mongoose.Schema.Types.Mixed }, createdAt: { type: Date, default: Date.now }, updatedAt: { type: Date, default: Date.now } }, { timestamps: true }); // Indexes for performance equipmentSchema.index({ category: 1, subcategory: 1 }); equipmentSchema.index({ isActive: 1 }); equipmentSchema.index({ name: 'text', description: 'text' }); // Virtual for primary image equipmentSchema.virtual('primaryImage').get(function () { const primary = this.images.find(img => img.isPrimary); return primary || this.images[0] || null; }); // Method to check if equipment is available equipmentSchema.methods.isAvailable = function () { return this.isActive && this.stock > 0; }; // Method to get display price equipmentSchema.methods.getDisplayPrice = function () { return `₦${this.price.toLocaleString()}`; }; equipmentSchema.pre('save', function (next) { // Sync legacy stock field with new inventory.availableUnits if (this.isModified('inventory.availableUnits') && !this.isModified('stock')) { this.stock = this.inventory.availableUnits; } else if (this.isModified('stock') && !this.isModified('inventory.availableUnits')) { this.inventory.availableUnits = this.stock; } next(); }); export default mongoose.model('Equipment', equipmentSchema);