Introduces per-class payout configuration (percentage or hourly rate, plus an optional per-session expense allowance), pure calculation utilities for professor payout/net profit/receivables, and a new financial-reports API surface with per-class, per-session, and date-range/monthly reports. Also adds full CRUD for institutional expenses used in the range report, and wires up the new permissions and roles. Fixes a pre-existing ReferenceError (missing parseImportDate import) in paymentService that blocked creating payments with dated transactions.
130 lines
2.4 KiB
JavaScript
130 lines
2.4 KiB
JavaScript
// /components/classes/classModel.js
|
|
'use strict';
|
|
|
|
const mongoose = require('mongoose');
|
|
const uniqueCodePlugin = require('../../utils/mongooseUniqueCodePlugin');
|
|
|
|
const classSchema = new mongoose.Schema({
|
|
name: {
|
|
type: String,
|
|
required: true,
|
|
trim: true
|
|
},
|
|
course: {
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
ref: 'Course',
|
|
required: true
|
|
},
|
|
professor: {
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
ref: 'Professor'
|
|
},
|
|
students: [{
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
ref: 'User'
|
|
}],
|
|
capacity: {
|
|
type: Number,
|
|
default: 30
|
|
},
|
|
tuitionFee: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
hasDiscount: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
discount: {
|
|
type: Number,
|
|
default: 0,
|
|
min: 0
|
|
},
|
|
freeSpots: {
|
|
type: Number,
|
|
min: 0,
|
|
default: null
|
|
},
|
|
showOnFrontend: {
|
|
type: Boolean,
|
|
default: true,
|
|
index: true
|
|
},
|
|
startDate: {
|
|
type: Date
|
|
},
|
|
endDate: {
|
|
type: Date
|
|
},
|
|
days: {
|
|
type: [{
|
|
type: Number,
|
|
min: 0,
|
|
max: 6
|
|
}],
|
|
default: []
|
|
},
|
|
startTime: {
|
|
type: String,
|
|
trim: true,
|
|
default: ''
|
|
},
|
|
endTime: {
|
|
type: String,
|
|
trim: true,
|
|
default: ''
|
|
},
|
|
numberOfSessions: {
|
|
type: Number,
|
|
min: 1,
|
|
default: null
|
|
},
|
|
/** Professor compensation model for this class */
|
|
payoutType: {
|
|
type: String,
|
|
enum: ['percentage', 'hourly'],
|
|
default: 'percentage'
|
|
},
|
|
/** Used when payoutType === 'percentage' — professor's share of class revenue (0-100) */
|
|
payoutPercentage: {
|
|
type: Number,
|
|
default: 0,
|
|
min: 0,
|
|
max: 100
|
|
},
|
|
/** Used when payoutType === 'hourly' — professor's rate per teaching hour (Toman) */
|
|
payoutHourlyRate: {
|
|
type: Number,
|
|
default: 0,
|
|
min: 0
|
|
},
|
|
/** Optional flat allowance (travel/catering/etc.) paid per session held, regardless of payout model */
|
|
extraExpensePerSession: {
|
|
type: Number,
|
|
default: 0,
|
|
min: 0
|
|
},
|
|
isActive: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
adminNotes: {
|
|
type: [String],
|
|
default: []
|
|
}
|
|
}, {
|
|
timestamps: true,
|
|
toJSON: { virtuals: true },
|
|
toObject: { virtuals: true }
|
|
});
|
|
|
|
classSchema.plugin(uniqueCodePlugin);
|
|
|
|
classSchema.virtual('finalTuitionFee').get(function () {
|
|
const tuition = this.tuitionFee || 0;
|
|
if (!this.hasDiscount) return tuition;
|
|
return Math.max(0, tuition - (this.discount || 0));
|
|
});
|
|
|
|
module.exports = mongoose.model('Class', classSchema);
|