jp-shared 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/configs/firebase-admin.js +24 -0
  2. package/configs/index.js +3 -0
  3. package/constants/configuration.js +6 -0
  4. package/constants/database.js +6 -0
  5. package/constants/index.js +6 -0
  6. package/constants/org.js +30 -0
  7. package/constants/time-constant.js +4 -0
  8. package/helpers/index.js +4 -0
  9. package/helpers/otp-helper.js +48 -0
  10. package/helpers/validateMongoId.js +13 -0
  11. package/index.js +15 -0
  12. package/models/admin-models/admin-model.js +62 -0
  13. package/models/admin-models/index.js +4 -0
  14. package/models/admin-models/token-model.js +20 -0
  15. package/models/candidate-models/candidateModel.js +375 -0
  16. package/models/candidate-models/index.js +8 -0
  17. package/models/candidate-models/mobileOTPModel.js +75 -0
  18. package/models/candidate-models/otpModel.js +75 -0
  19. package/models/candidate-models/requestModel.js +26 -0
  20. package/models/candidate-models/savedJobModel.js +20 -0
  21. package/models/candidate-models/searchAppearanceModel.js +50 -0
  22. package/models/candidate-models/tokenModel.js +20 -0
  23. package/models/common-models/course-model.js +20 -0
  24. package/models/common-models/downloadedResumeHistory-model.js +54 -0
  25. package/models/common-models/education-model.js +17 -0
  26. package/models/common-models/index.js +19 -0
  27. package/models/common-models/jobApplication-model.js +57 -0
  28. package/models/common-models/jobApproach-model.js +14 -0
  29. package/models/common-models/jobOffer-model.js +20 -0
  30. package/models/common-models/jobType-model.js +22 -0
  31. package/models/common-models/noticePeriod.js +14 -0
  32. package/models/common-models/paymentHistory-model.js +128 -0
  33. package/models/common-models/plan-model.js +144 -0
  34. package/models/common-models/role-model.js +22 -0
  35. package/models/common-models/searchAppearanceHistory-model.js +36 -0
  36. package/models/common-models/skill-model.js +21 -0
  37. package/models/common-models/sms-student-model.js +44 -0
  38. package/models/common-models/speakingLanguage.js +14 -0
  39. package/models/common-models/specialization-model.js +20 -0
  40. package/models/common-models/viewedProfileHistory-model.js +44 -0
  41. package/models/index.js +8 -0
  42. package/models/jobPost-models/active-model.js +71 -0
  43. package/models/jobPost-models/draft-model.js +42 -0
  44. package/models/jobPost-models/expired-model.js +46 -0
  45. package/models/jobPost-models/index.js +10 -0
  46. package/models/jobPost-models/invitation-model.js +72 -0
  47. package/models/jobPost-models/onHold-model.js +58 -0
  48. package/models/jobPost-models/pending-model.js +45 -0
  49. package/models/jobPost-models/rejected-model.js +51 -0
  50. package/models/jobPost-models/verification-model.js +50 -0
  51. package/models/organization-models/active-model.js +111 -0
  52. package/models/organization-models/index.js +4 -0
  53. package/models/organization-models/verification-model.js +52 -0
  54. package/models/recruiter-models/active-model.js +45 -0
  55. package/models/recruiter-models/basicDetail-model.js +113 -0
  56. package/models/recruiter-models/counter-model.js +13 -0
  57. package/models/recruiter-models/emailOTP-model.js +68 -0
  58. package/models/recruiter-models/index.js +10 -0
  59. package/models/recruiter-models/mobileOTP-model.js +88 -0
  60. package/models/recruiter-models/pending-model.js +44 -0
  61. package/models/recruiter-models/request-model.js +75 -0
  62. package/models/recruiter-models/token-model.js +15 -0
  63. package/models/recruiter-models/verification-model.js +63 -0
  64. package/package.json +28 -0
  65. package/schemes/address-schema.js +43 -0
  66. package/schemes/index.js +7 -0
  67. package/schemes/pendingJobPostStep1-schema.js +192 -0
  68. package/schemes/pendingJobPostStep2-scheme.js +117 -0
  69. package/schemes/pendingJobPostStep3-scheme.js +21 -0
  70. package/schemes/pendingJobPostStep4-scheme.js +22 -0
  71. package/utils/env-utils.js +12 -0
  72. package/utils/firebase-utils.js +220 -0
  73. package/utils/index.js +12 -0
  74. package/utils/invoiceTemplate.js +123 -0
  75. package/utils/otp-utils.js +23 -0
  76. package/utils/password-utils.js +49 -0
  77. package/utils/percentageWeights.js +106 -0
  78. package/utils/populate-utils.js +57 -0
  79. package/utils/sendEmail-utils.js +40 -0
  80. package/utils/sendInvoice-utils.js +139 -0
  81. package/utils/token-utils.js +18 -0
  82. package/utils/validate-utils.js +118 -0
@@ -0,0 +1,75 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+ const {
4
+ Schema,
5
+ Types: { ObjectId },
6
+ } = mongoose;
7
+
8
+ // Define the schema
9
+ const schema = new Schema(
10
+ {
11
+ candidateId: {
12
+ type: ObjectId,
13
+ required: [true, "Candidate ID is required"],
14
+ },
15
+ OTP: {
16
+ type: String,
17
+ required: [true, "OTP is required"],
18
+ maxlength: [6, "OTP must be 6 digits"],
19
+ },
20
+ requests: [
21
+ {
22
+ mobileNumber: {
23
+ type: String,
24
+ required: [true, "Mobile number is required"],
25
+ match: [/^\d{10}$/, "Mobile number must be exactly 10 digits"],
26
+ },
27
+ countryCode: {
28
+ type: String,
29
+ required: [true, "Country code is required"],
30
+ enum: ["+91"], // Consider expanding this if needed
31
+ },
32
+ createdAt: {
33
+ type: Date,
34
+ required: [true, "Request date is required"],
35
+ default: Date.now,
36
+ },
37
+ attempts: {
38
+ type: Number,
39
+ default: 0, // Initialize attempts with 0
40
+ min: [0, "Attempts cannot be negative"],
41
+ },
42
+ successful: {
43
+ type: Boolean,
44
+ default: false,
45
+ },
46
+ },
47
+ ],
48
+ deleteAt: {
49
+ type: Date,
50
+ required: [true, "DeleteAt date is required"],
51
+ validate: {
52
+ validator: function (v) {
53
+ return v > new Date(); // Ensure deleteAt is in the future
54
+ },
55
+ message: "DeleteAt must be a future date.",
56
+ },
57
+ },
58
+ },
59
+ { timestamps: { createdAt: true, updatedAt: true } }
60
+ );
61
+
62
+ // Ensure TTL index is created
63
+ // Ensure deleteAt index is created (for document expiry)
64
+ schema.index({ deleteAt: 1 }, { expireAfterSeconds: 0 });
65
+
66
+ // Consider adding indexes for frequently queried fields
67
+ schema.index({ candidateId: 1 });
68
+ schema.index({ mobileNumber: 1 });
69
+ schema.index({ countryCode: 1 });
70
+
71
+ const CandidateMobileOTPModel = mongoose.connection
72
+ .useDb(getDatabaseName())
73
+ .model("candidate-mobile-otp", schema);
74
+
75
+ module.exports = CandidateMobileOTPModel;
@@ -0,0 +1,75 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+ const {
4
+ Schema,
5
+ Types: { ObjectId },
6
+ } = mongoose;
7
+
8
+ const schema = new Schema(
9
+ {
10
+ candidateId: { type: ObjectId, required: true },
11
+ contactInfo: {
12
+ type: String,
13
+ required: [
14
+ true,
15
+ "Contact information (email or mobile number) is required",
16
+ ],
17
+ validate: {
18
+ validator: function (v) {
19
+ const emailRegex = /^\S+@\S+\.\S+$/;
20
+ const mobileRegex = /^\d{10}$/;
21
+ return emailRegex.test(v) || mobileRegex.test(v);
22
+ },
23
+ message:
24
+ "Invalid contact information. Must be a valid email address or a 10-digit mobile number.",
25
+ },
26
+ },
27
+ type: {
28
+ type: String,
29
+ enum: ["email", "mobile"],
30
+ required: [true, "OTP type (email or mobile) is required"],
31
+ },
32
+ purpose: {
33
+ type: String,
34
+ enum: ["creation", "change"],
35
+ required: [true, "Purpose (creation or change) is required"],
36
+ },
37
+ OTP: {
38
+ type: Number,
39
+ required: [true, "OTP is required"],
40
+ minlength: [4, "OTP must be at least 4 digits long"],
41
+ maxlength: [6, "OTP must be at most 6 digits long"],
42
+ match: [/^\d{4,6}$/, "OTP must be 4 to 6 digits long"],
43
+ },
44
+ expiryDate: {
45
+ type: Date,
46
+ required: [true, "Expiry date is required"],
47
+ },
48
+ attempts: {
49
+ type: Number,
50
+ default: 0,
51
+ required: [true, "Attempts count is required"],
52
+ min: [0, "Attempts count cannot be negative"],
53
+ },
54
+ deleteAt: {
55
+ type: Date,
56
+ required: [true, "Deletion time is required"], // TTL field for automatic deletion
57
+ validate: {
58
+ validator: function (v) {
59
+ return v > this.expiryDate;
60
+ },
61
+ message: "Deletion time must be after the expiry date.",
62
+ },
63
+ },
64
+ },
65
+ { timestamps: { createdAt: true, updatedAt: true } }
66
+ );
67
+
68
+ // Ensure TTL index is created
69
+ schema.index({ deleteAt: 1 }, { expireAfterSeconds: 0 });
70
+
71
+ const CandidateOTPModel = mongoose.connection
72
+ .useDb(getDatabaseName())
73
+ .model("recruiter-otp", schema);
74
+
75
+ module.exports = CandidateOTPModel;
@@ -0,0 +1,26 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ // Define the schema
5
+ const schema = new mongoose.Schema(
6
+ {
7
+ fullName: { type: String, required: true },
8
+ email: { type: String, required: true },
9
+ password: { type: String, required: true },
10
+ expireAt: {
11
+ type: Date,
12
+ default: () => new Date(+new Date() + 60 * 60 * 1000), // Set to expire after one hour
13
+ },
14
+ },
15
+ { timestamps: { createdAt: true, updatedAt: false } }
16
+ );
17
+
18
+ // Create the TTL index
19
+ schema.index({ expireAt: 1 }, { expireAfterSeconds: 0 });
20
+
21
+ const myDB = mongoose.connection.useDb(getDatabaseName());
22
+
23
+ // Create the model
24
+ const CandidateRequestModel = myDB.model("candidate-request", schema);
25
+
26
+ module.exports = CandidateRequestModel;
@@ -0,0 +1,20 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Types;
5
+
6
+ // Define the schema
7
+ const schema = new mongoose.Schema(
8
+ {
9
+ candidateId: { type: ObjectId, required: true },
10
+ jobPostId: { type: ObjectId, required: true },
11
+ },
12
+ { timestamps: { createdAt: true, updatedAt: true } }
13
+ );
14
+
15
+ const myDB = mongoose.connection.useDb(getDatabaseName());
16
+
17
+ // Create the model
18
+ const CandidateSavedJobModel = myDB.model("candidate-saved-job", schema);
19
+
20
+ module.exports = CandidateSavedJobModel;
@@ -0,0 +1,50 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+ const Schema = mongoose.Schema;
4
+
5
+ const SearchAppearanceSchema = new Schema(
6
+ {
7
+ recruiterId: {
8
+ type: mongoose.Schema.Types.ObjectId,
9
+ ref: "recruiter",
10
+ required: true,
11
+ },
12
+ candidateId: {
13
+ type: mongoose.Schema.Types.ObjectId,
14
+ ref: "candidate",
15
+ required: true,
16
+ },
17
+ appearanceCount: {
18
+ type: Number,
19
+ default: 1,
20
+ },
21
+ // Field to track expiration date
22
+ expiresAt: {
23
+ type: Date,
24
+ required: true,
25
+ default: () => {
26
+ // Set the default expiration time to 30 days from now
27
+ return new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
28
+ },
29
+ },
30
+ },
31
+ { timestamps: true } // Adds createdAt and updatedAt fields
32
+ );
33
+
34
+ // Add an index to improve performance of frequent searches
35
+ SearchAppearanceSchema.index(
36
+ { recruiterId: 1, candidateId: 1 },
37
+ { unique: true }
38
+ );
39
+
40
+ // Create a TTL index on the expiresAt field
41
+ SearchAppearanceSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
42
+
43
+ const myDB = mongoose.connection.useDb(getDatabaseName());
44
+
45
+ const SearchAppearanceModel = myDB.model(
46
+ "search-appearance-history",
47
+ SearchAppearanceSchema
48
+ );
49
+
50
+ module.exports = SearchAppearanceModel;
@@ -0,0 +1,20 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const schema = new mongoose.Schema(
5
+ {
6
+ candidateId: { type: mongoose.Schema.Types.ObjectId, required: true },
7
+ sessionId: { type: String, required: true },
8
+ },
9
+ {
10
+ timestamps: true, // Adds createdAt and updatedAt fields
11
+ }
12
+ );
13
+
14
+ const myDB = mongoose.connection.useDb("OA_Job_Portal_API");
15
+
16
+ schema.index({ candidateId: 1, sessionId: 1 });
17
+
18
+ const CandidateToken = myDB.model(getDatabaseName, schema);
19
+
20
+ module.exports = { CandidateToken };
@@ -0,0 +1,20 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Types;
5
+
6
+ // Define the schema
7
+ const schema = new mongoose.Schema(
8
+ {
9
+ educationId: { type: ObjectId, required: true },
10
+ label: { type: String, required: true },
11
+ },
12
+ { timestamps: { createdAt: true, updatedAt: true } }
13
+ );
14
+
15
+ const myDB = mongoose.connection.useDb(getDatabaseName());
16
+
17
+ // Create the model
18
+ const CourseModel = myDB.model("course", schema);
19
+
20
+ module.exports = CourseModel;
@@ -0,0 +1,54 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Types;
5
+
6
+ // Define the schema
7
+ const schema = new mongoose.Schema(
8
+ {
9
+ candidateId: {
10
+ type: ObjectId,
11
+ required: [true, "Candidate ID is required"],
12
+ validate: {
13
+ validator: (value) => mongoose.isValidObjectId(value),
14
+ message: "Invalid Candidate ID",
15
+ },
16
+ },
17
+ recruiterId: {
18
+ type: ObjectId,
19
+ required: [true, "Recruiter ID is required"],
20
+ validate: {
21
+ validator: (value) => mongoose.isValidObjectId(value),
22
+ message: "Invalid Recruiter ID",
23
+ },
24
+ },
25
+ organizationId: {
26
+ type: ObjectId,
27
+ required: [true, "Organization ID is required"],
28
+ validate: {
29
+ validator: (value) => mongoose.isValidObjectId(value),
30
+ message: "Invalid Organization ID",
31
+ },
32
+ },
33
+ createdAt: {
34
+ type: Date,
35
+ default: Date.now,
36
+ },
37
+ },
38
+ {
39
+ timestamps: true, // Automatically creates createdAt and updatedAt fields
40
+ }
41
+ );
42
+
43
+ // Define the TTL index for the createdAt field
44
+ schema.index({ createdAt: 1 }, { expireAfterSeconds: 2592000 }); // 30 days in seconds
45
+
46
+ const myDB = mongoose.connection.useDb(getDatabaseName());
47
+
48
+ // Create the model
49
+ const DownloadedResumeHistoryModel = myDB.model(
50
+ "downloaded-resume-history",
51
+ schema
52
+ );
53
+
54
+ module.exports = DownloadedResumeHistoryModel;
@@ -0,0 +1,17 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ // Define the schema
5
+ const schema = new mongoose.Schema(
6
+ {
7
+ label: { type: String, required: true },
8
+ },
9
+ { timestamps: { createdAt: true, updatedAt: true } }
10
+ );
11
+
12
+ const myDB = mongoose.connection.useDb(getDatabaseName());
13
+
14
+ // Create the model
15
+ const EducationModel = myDB.model("education", schema);
16
+
17
+ module.exports = EducationModel;
@@ -0,0 +1,19 @@
1
+ module.exports = {
2
+ EducationModel: require("./education-model"),
3
+ CourseModel: require("./course-model"),
4
+ JobApplicationModel: require("./jobApplication-model"),
5
+ JobApprochModel: require("./jobApproach-model"),
6
+ JobTypeModel: require("./jobType-model"),
7
+ NoticePeriodModel: require("./noticePeriod"),
8
+ RoleModel: require("./role-model"),
9
+ SkillModel: require("./skill-model"),
10
+ SearchAppearanceHistoryModel: require("./searchAppearanceHistory-model"),
11
+ AdmissionModel: require("./sms-student-model"),
12
+ ViewedProfileHistory: require("./viewedProfileHistory-model"),
13
+ SpecializationModel: require("./specialization-model"),
14
+ SpeakingLanguageModel: require("./speakingLanguage"),
15
+ JobOfferModel: require("./jobOffer-model"),
16
+ PlanModel: require("./plan-model"),
17
+ DownloadedResumeHistoryModel: require("./downloadedResumeHistory-model"),
18
+ PaymentHistoryModel: require("./paymentHistory-model"),
19
+ };
@@ -0,0 +1,57 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Types;
5
+
6
+ // Define the schema with status as an array of objects
7
+ const schema = new mongoose.Schema(
8
+ {
9
+ candidateId: {
10
+ type: ObjectId,
11
+ required: true,
12
+ validate: {
13
+ validator: mongoose.Types.ObjectId.isValid,
14
+ message: "Invalid candidate ID format.",
15
+ },
16
+ },
17
+ jobPostId: {
18
+ type: ObjectId,
19
+ required: true,
20
+ validate: {
21
+ validator: mongoose.Types.ObjectId.isValid,
22
+ message: "Invalid job post ID format.",
23
+ },
24
+ },
25
+ status: {
26
+ type: [
27
+ {
28
+ process: {
29
+ type: String,
30
+ required: true,
31
+ enum: ["sent", "viewed", "shortlisted"],
32
+ },
33
+ createdAt: {
34
+ type: Date,
35
+ required: true,
36
+ default: Date.now,
37
+ },
38
+ },
39
+ ],
40
+ default: [{ process: "sent", createdAt: Date.now() }],
41
+ validate: {
42
+ validator: function (value) {
43
+ return value.length <= 3;
44
+ },
45
+ message: "Status array can contain a maximum of 3 objects.",
46
+ },
47
+ },
48
+ },
49
+ { timestamps: { createdAt: true, updatedAt: true } }
50
+ );
51
+
52
+ const myDB = mongoose.connection.useDb(getDatabaseName());
53
+
54
+ // Create the model
55
+ const JobApplicationModel = myDB.model("job-application", schema);
56
+
57
+ module.exports = JobApplicationModel;
@@ -0,0 +1,14 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ // Define the schema
5
+ const schema = new mongoose.Schema({
6
+ jobApproach: { type: String, required: true },
7
+ });
8
+
9
+ const myDB = mongoose.connection.useDb(getDatabaseName());
10
+
11
+ // Create the model
12
+ const JobApprochModel = myDB.model("job-approach", schema);
13
+
14
+ module.exports = JobApprochModel;
@@ -0,0 +1,20 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Types;
5
+
6
+ // Define the schema
7
+ const schema = new mongoose.Schema(
8
+ {
9
+ candidateId: { type: ObjectId, required: true },
10
+ jobPostId: { type: ObjectId, required: true },
11
+ },
12
+ { timestamps: { createdAt: true, updatedAt: true } }
13
+ );
14
+
15
+ const myDB = mongoose.connection.useDb(getDatabaseName());
16
+
17
+ // Create the model
18
+ const JobOfferModel = myDB.model("job-offer", schema);
19
+
20
+ module.exports = JobOfferModel;
@@ -0,0 +1,22 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ // Define the schema
5
+ const schema = new mongoose.Schema({
6
+ jobType: { type: String, required: true },
7
+ });
8
+
9
+ // Modify the toJSON method to exclude __v
10
+ schema.set("toJSON", {
11
+ transform: (doc, ret) => {
12
+ delete ret.__v;
13
+ return ret;
14
+ },
15
+ });
16
+
17
+ const myDB = mongoose.connection.useDb(getDatabaseName());
18
+
19
+ // Create the model
20
+ const JobTypeModel = myDB.model("jobType", schema);
21
+
22
+ module.exports = JobTypeModel;
@@ -0,0 +1,14 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ // Define the schema
5
+ const schema = new mongoose.Schema({
6
+ noticePeriod: { type: String, required: true },
7
+ });
8
+
9
+ const myDB = mongoose.connection.useDb(getDatabaseName());
10
+
11
+ // Create the model
12
+ const NoticePeriodModel = myDB.model("notice-period", schema);
13
+
14
+ module.exports = NoticePeriodModel;
@@ -0,0 +1,128 @@
1
+ const mongoose = require("mongoose");
2
+ const { getDatabaseName } = require("../../constants");
3
+
4
+ const { ObjectId } = mongoose.Types;
5
+
6
+ // Define the schema
7
+ const paymentHistorySchema = new mongoose.Schema(
8
+ {
9
+ billNumber: {
10
+ type: String,
11
+ required: true,
12
+ trim: true,
13
+ unique: true, // Ensure bill numbers are unique
14
+ match: /^OAJP\d+$/, // Regular expression to match "OAJP" followed by digits
15
+ minlength: 5,
16
+ maxlength: 20, // Adjust this as per your requirements
17
+ },
18
+ jobPostId: {
19
+ type: ObjectId,
20
+ required: true,
21
+ },
22
+ recruiterId: {
23
+ type: ObjectId,
24
+ required: true,
25
+ },
26
+ organizationId: {
27
+ type: ObjectId,
28
+ required: true,
29
+ },
30
+ amount: {
31
+ type: Number,
32
+ required: true,
33
+ min: 0, // Ensure amount is non-negative
34
+ },
35
+ planName: {
36
+ type: String,
37
+ required: true,
38
+ trim: true,
39
+ maxlength: 100, // Limit the length of plan name
40
+ },
41
+ maxApplicant: {
42
+ type: Number,
43
+ required: true,
44
+ min: 0, // Ensure non-negative value
45
+ },
46
+ userAccessCount: {
47
+ type: Number,
48
+ required: true,
49
+ min: 0, // Ensure non-negative value
50
+ },
51
+ candidateLastActiveMonth: {
52
+ type: Number,
53
+ required: true,
54
+ min: 0, // Ensure non-negative value
55
+ },
56
+ maxResult: {
57
+ type: Number,
58
+ required: true,
59
+ min: 0, // Ensure non-negative value
60
+ },
61
+ maxProfileView: {
62
+ type: Number,
63
+ required: true,
64
+ min: 0, // Ensure non-negative value
65
+ },
66
+ isDownloadResume: {
67
+ type: Boolean,
68
+ default: false,
69
+ },
70
+ isFilter: {
71
+ type: Boolean,
72
+ default: false,
73
+ },
74
+ isTag: {
75
+ type: Boolean,
76
+ default: false,
77
+ },
78
+ minValidityDay: {
79
+ type: Number,
80
+ required: true,
81
+ min: 1, // Minimum validity should be at least 1 day
82
+ },
83
+ maxValidityDay: {
84
+ type: Number,
85
+ required: true,
86
+ min: 1, // Minimum validity should be at least 1 day
87
+ },
88
+ isFree: {
89
+ type: Boolean,
90
+ required: [true, "isFree field is required"],
91
+ default: false, // Assuming plans are paid by default
92
+ },
93
+ isJobOffer: {
94
+ type: Boolean,
95
+ required: [true, "Job offer status is required"],
96
+ },
97
+ jobOfferDiscountPercentage: {
98
+ type: Number,
99
+ required: function () {
100
+ return this.isJobOffer === true; // Only required if isJobOffer is true
101
+ },
102
+ min: [1, "Discount percentage must be greater than 1%"],
103
+ max: [99, "Discount percentage must be less than or equal to 99%"],
104
+ validate: {
105
+ validator: function (value) {
106
+ // Allow null when isJobOffer is false
107
+ return this.isJobOffer === true ? value !== null : true;
108
+ },
109
+ message: "Discount percentage is required when isJobOffer is true",
110
+ },
111
+ },
112
+ },
113
+ {
114
+ timestamps: true, // Automatically manage createdAt and updatedAt
115
+ }
116
+ );
117
+
118
+ // Indexing frequently queried fields for performance
119
+ paymentHistorySchema.index({ recruiterId: 1 });
120
+ paymentHistorySchema.index({ organizationId: 1 });
121
+
122
+ // Connect to the specific database
123
+ const myDB = mongoose.connection.useDb(getDatabaseName());
124
+
125
+ // Create the model
126
+ const PaymentHistoryModel = myDB.model("payment-history", paymentHistorySchema);
127
+
128
+ module.exports = PaymentHistoryModel;