@mac777/project-pinecone-models 1.1.11 → 1.1.13

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.
@@ -0,0 +1,252 @@
1
+ import mongoose from "mongoose";
2
+
3
+ /* ----------------------------------
4
+ * Embedded Schemas
5
+ * ---------------------------------- */
6
+
7
+ const orderTicketSchema = new mongoose.Schema(
8
+ {
9
+ ticketVariantId: {
10
+ type: mongoose.Schema.Types.ObjectId,
11
+ required: true,
12
+ ref: "TicketVariant"
13
+ },
14
+ variantName: {
15
+ type: String,
16
+ required: true,
17
+ trim: true
18
+ },
19
+ quantity: {
20
+ type: Number,
21
+ required: true,
22
+ min: 1
23
+ },
24
+ pricePerTicket: {
25
+ type: Number,
26
+ required: true,
27
+ min: 0
28
+ },
29
+ subtotal: {
30
+ type: Number,
31
+ required: true,
32
+ min: 0
33
+ }
34
+ },
35
+ { _id: false }
36
+ );
37
+
38
+ const pricingSchema = new mongoose.Schema(
39
+ {
40
+ subtotal: { type: Number, required: true, min: 0 },
41
+ platformFee: { type: Number, required: true, min: 0 },
42
+ paymentFee: { type: Number, required: true, min: 0 },
43
+ total: { type: Number, required: true, min: 0 },
44
+ currency: { type: String, default: "BDT" },
45
+ hostPayout: { type: Number, required: true, min: 0 }
46
+ },
47
+ { _id: false }
48
+ );
49
+
50
+ const refundSchema = new mongoose.Schema(
51
+ {
52
+ reason: {
53
+ type: String,
54
+ enum: ["event_cancelled", "user_request", "fraud"],
55
+ required: true
56
+ },
57
+ amount: {
58
+ type: Number,
59
+ required: true,
60
+ min: 0
61
+ },
62
+ refundedAt: {
63
+ type: Date,
64
+ default: Date.now
65
+ },
66
+ stripeRefundId: String
67
+ },
68
+ { _id: false }
69
+ );
70
+
71
+ /* ----------------------------------
72
+ * Main Order Schema
73
+ * ---------------------------------- */
74
+
75
+ const orderSchema = new mongoose.Schema(
76
+ {
77
+ /* ---------- Identity ---------- */
78
+
79
+ orderNumber: {
80
+ type: String,
81
+ unique: true,
82
+ index: true
83
+ },
84
+
85
+ userId: {
86
+ type: mongoose.Schema.Types.ObjectId,
87
+ ref: "User",
88
+ required: true,
89
+ index: true
90
+ },
91
+
92
+ eventId: {
93
+ type: mongoose.Schema.Types.ObjectId,
94
+ ref: "Event",
95
+ required: true,
96
+ index: true
97
+ },
98
+
99
+ /* ---------- Tickets ---------- */
100
+
101
+ tickets: {
102
+ type: [orderTicketSchema],
103
+ validate: (v: any) => v.length > 0
104
+ },
105
+
106
+ ticketCount: {
107
+ type: Number,
108
+ required: true,
109
+ min: 1
110
+ },
111
+
112
+ ticketIds: [{
113
+ type: mongoose.Schema.Types.ObjectId,
114
+ ref: "Ticket"
115
+ }],
116
+
117
+ /* ---------- Pricing ---------- */
118
+
119
+ pricing: {
120
+ type: pricingSchema,
121
+ required: true
122
+ },
123
+
124
+ /* ---------- Payment ---------- */
125
+
126
+ paymentId: String,
127
+
128
+ paymentMethod: {
129
+ type: String,
130
+ enum: ["card", "bkash", "bank_transfer", "free"],
131
+ required: true
132
+ },
133
+
134
+ paymentStatus: {
135
+ type: String,
136
+ enum: ["pending", "succeeded", "failed"],
137
+ default: "pending",
138
+ index: true
139
+ },
140
+
141
+ paidAt: Date,
142
+
143
+ /* ---------- Order Lifecycle ---------- */
144
+
145
+ status: {
146
+ type: String,
147
+ enum: ["pending", "confirmed", "cancelled", "refunded"],
148
+ default: "pending",
149
+ index: true
150
+ },
151
+
152
+ requiresManualReview: {
153
+ type: Boolean,
154
+ default: false
155
+ },
156
+
157
+ manualReviewReason: String,
158
+
159
+ confirmedAt: Date,
160
+ cancelledAt: Date,
161
+ refundedAt: Date,
162
+
163
+ expiresAt: {
164
+ type: Date,
165
+ required: true,
166
+ index: true
167
+ },
168
+
169
+ reminderSentAt: Date,
170
+
171
+ /* ---------- Buyer ---------- */
172
+
173
+ buyerEmail: {
174
+ type: String,
175
+ required: true,
176
+ lowercase: true,
177
+ trim: true,
178
+ index: true
179
+ },
180
+
181
+ buyerPhone: String,
182
+
183
+ /* ---------- Refund ---------- */
184
+
185
+ refund: {
186
+ type: refundSchema,
187
+ validate: {
188
+ validator(refund: any) {
189
+ return !refund || refund.amount <= this.pricing.total;
190
+ },
191
+ message: "Refund amount exceeds order total"
192
+ }
193
+ },
194
+
195
+ /* ---------- Audit ---------- */
196
+
197
+ ipAddress: String,
198
+ userAgent: String
199
+ },
200
+ {
201
+ timestamps: true,
202
+ strict: true
203
+ }
204
+ );
205
+
206
+ /* ----------------------------------
207
+ * Indexes
208
+ * ---------------------------------- */
209
+
210
+ orderSchema.index({ status: 1, createdAt: -1 });
211
+ orderSchema.index({ eventId: 1, status: 1, createdAt: -1 });
212
+ orderSchema.index({ paymentStatus: 1, createdAt: -1 });
213
+ orderSchema.index({ expiresAt: 1 }, {
214
+ expireAfterSeconds: 0,
215
+ partialFilterExpression: { status: "pending" }
216
+ });
217
+
218
+ /* ----------------------------------
219
+ * Hooks
220
+ * ---------------------------------- */
221
+
222
+ // Generate order number
223
+ orderSchema.pre("save", function (next) {
224
+ if (this.isNew && !this.orderNumber) {
225
+ const ts = Date.now().toString().slice(-6);
226
+ const rand = Math.random().toString(36).substring(2, 8).toUpperCase();
227
+ this.orderNumber = `ORD-${ts}-${rand}`;
228
+ }
229
+ next();
230
+ });
231
+
232
+ // Compute ticket count
233
+ orderSchema.pre("validate", function (next) {
234
+ if (this.tickets?.length) {
235
+ this.ticketCount = this.tickets.reduce((sum, t) => sum + t.quantity, 0);
236
+ }
237
+ next();
238
+ });
239
+
240
+ // Pricing immutability after confirmation
241
+ orderSchema.pre("save", function (next) {
242
+ if (!this.isNew && this.isModified("pricing") && this.status !== "pending") {
243
+ return next(new Error("Pricing cannot be modified after confirmation"));
244
+ }
245
+ next();
246
+ });
247
+
248
+ /* ----------------------------------
249
+ * Export
250
+ * ---------------------------------- */
251
+
252
+ export default orderSchema;
package/src/Payment.ts CHANGED
@@ -3,8 +3,8 @@ import mongoose from 'mongoose';
3
3
  // Payment schema for transaction logging
4
4
  const paymentSchema = new mongoose.Schema({
5
5
  // LINKS
6
- orderId: { type: mongoose.Schema.Types.ObjectId, required: true, index: true }, // Which order
7
- userId: { type: mongoose.Schema.Types.ObjectId, required: true, index: true }, // Who paid
6
+ orderId: { type: mongoose.Schema.Types.ObjectId, ref: 'Order', required: true, index: true }, // Which order
7
+ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true, index: true }, // Who paid
8
8
 
9
9
  paymentId: { type: String, required: true, unique: true, index: true }, // Stripe PI (unique)
10
10
 
package/src/Payout.ts CHANGED
@@ -9,10 +9,12 @@ const payoutSchema = new mongoose.Schema({
9
9
  // Ownership
10
10
  hostId: {
11
11
  type: mongoose.Schema.Types.ObjectId,
12
+ ref: 'User',
12
13
  required: true
13
14
  },
14
15
  eventId: {
15
16
  type: mongoose.Schema.Types.ObjectId,
17
+ ref: 'Event',
16
18
  required: true
17
19
  },
18
20
 
@@ -61,12 +63,14 @@ const payoutSchema = new mongoose.Schema({
61
63
  // Admin Actions
62
64
  approvedBy: {
63
65
  type: mongoose.Schema.Types.ObjectId,
66
+ ref: 'User',
64
67
  }, // Admin who approved
65
68
  approvedAt: {
66
69
  type: Date,
67
70
  },
68
71
  rejectedBy: {
69
72
  type: mongoose.Schema.Types.ObjectId,
73
+ ref: 'User',
70
74
  },
71
75
  rejectedAt: {
72
76
  type: Date,
package/src/Ticket.ts CHANGED
@@ -5,9 +5,9 @@ const ticketSchema = new mongoose.Schema({
5
5
  ticketNumber: { type: String, required: true, unique: true, index: true }, // Human-readable: "TKT-EVT123-A3K9-01"
6
6
 
7
7
  // BELONGS TO
8
- orderId: { type: mongoose.Schema.Types.ObjectId, required: true, index: true }, // Parent order
9
- eventId: { type: mongoose.Schema.Types.ObjectId, required: true, index: true }, // Which event
10
- userId: { type: mongoose.Schema.Types.ObjectId, required: true, index: true }, // Owner
8
+ orderId: { type: mongoose.Schema.Types.ObjectId, ref: 'Order', required: true, index: true }, // Parent order
9
+ eventId: { type: mongoose.Schema.Types.ObjectId, ref: 'Event', required: true, index: true }, // Which event
10
+ userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true, index: true }, // Owner
11
11
  ticketVariantId: { type: mongoose.Schema.Types.ObjectId, required: true }, // Which type (VIP, GA, etc)
12
12
 
13
13
  // DETAILS (denormalized for speed)
@@ -38,10 +38,10 @@ const ticketSchema = new mongoose.Schema({
38
38
  default: 'not_checked_in'
39
39
  },
40
40
  checkedInAt: Date,
41
- checkedInBy: mongoose.Schema.Types.ObjectId, // Staff/scanner user ID
41
+ checkedInBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, // Staff/scanner user ID
42
42
 
43
43
  // TRANSFER (if user transfers ticket to friend)
44
- transferredTo: mongoose.Schema.Types.ObjectId, // New owner user ID
44
+ transferredTo: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, // New owner user ID
45
45
  transferredAt: Date,
46
46
 
47
47
  // LIFECYCLE
package/src/User.v2.ts ADDED
@@ -0,0 +1,187 @@
1
+ import mongoose from "mongoose";
2
+
3
+ /* ----------------------------------
4
+ * Subschemas
5
+ * ---------------------------------- */
6
+
7
+ const contactSchema = new mongoose.Schema(
8
+ {
9
+ email: {
10
+ type: String,
11
+ required: true,
12
+ lowercase: true,
13
+ trim: true,
14
+ index: true
15
+ },
16
+ emailVerified: {
17
+ type: Boolean,
18
+ default: false
19
+ },
20
+ emailVerification: {
21
+ token: String,
22
+ expiresAt: Date
23
+ },
24
+
25
+ phone: {
26
+ type: String
27
+ },
28
+ phoneVerified: {
29
+ type: Boolean,
30
+ default: false
31
+ },
32
+ phoneVerification: {
33
+ token: String,
34
+ expiresAt: Date
35
+ }
36
+ },
37
+ { _id: false }
38
+ );
39
+
40
+ const identitySchema = new mongoose.Schema(
41
+ {
42
+ nidNumber: String,
43
+ nidVerified: {
44
+ type: Boolean,
45
+ default: false
46
+ },
47
+ verifiedAt: Date
48
+ },
49
+ { _id: false }
50
+ );
51
+
52
+ const payoutSchema = new mongoose.Schema(
53
+ {
54
+ method: {
55
+ type: String,
56
+ enum: ["bkash", "bank_transfer"],
57
+ default: "bkash"
58
+ },
59
+
60
+ bkash: {
61
+ number: String
62
+ },
63
+
64
+ bank: {
65
+ bankName: String,
66
+ accountName: String,
67
+ accountNumber: String,
68
+ branchName: String,
69
+ routingNumber: String
70
+ },
71
+
72
+ verified: {
73
+ type: Boolean,
74
+ default: false
75
+ },
76
+ verifiedAt: Date
77
+ },
78
+ { _id: false }
79
+ );
80
+
81
+ const profileSchema = new mongoose.Schema(
82
+ {
83
+ firstName: {
84
+ type: String,
85
+ required: true,
86
+ trim: true
87
+ },
88
+ lastName: {
89
+ type: String,
90
+ required: true,
91
+ trim: true
92
+ },
93
+ organization: String,
94
+
95
+ avatar: {
96
+ url: String,
97
+ publicId: String // S3 / Cloudinary
98
+ }
99
+ },
100
+ { _id: false }
101
+ );
102
+
103
+ const authSchema = new mongoose.Schema(
104
+ {
105
+ provider: {
106
+ type: String,
107
+ enum: ["local", "google"],
108
+ default: "local"
109
+ },
110
+
111
+ password: {
112
+ type: String,
113
+ select: false
114
+ },
115
+
116
+ googleId: {
117
+ type: String,
118
+ index: true
119
+ },
120
+
121
+ refreshToken: {
122
+ type: String,
123
+ select: false
124
+ }
125
+ },
126
+ { _id: false }
127
+ );
128
+
129
+ /* ----------------------------------
130
+ * Main User Schema
131
+ * ---------------------------------- */
132
+
133
+ const userSchema = new mongoose.Schema(
134
+ {
135
+ profile: profileSchema,
136
+
137
+ contact: contactSchema,
138
+
139
+ identity: identitySchema,
140
+
141
+ payout: payoutSchema,
142
+
143
+ auth: authSchema,
144
+
145
+ role: {
146
+ type: String,
147
+ enum: ["user", "host", "admin"],
148
+ default: "user",
149
+ index: true
150
+ },
151
+
152
+ status: {
153
+ type: String,
154
+ enum: ["active", "suspended", "deleted"],
155
+ default: "active",
156
+ index: true
157
+ },
158
+
159
+ lastLoginAt: Date
160
+ },
161
+ {
162
+ timestamps: true,
163
+ strict: true
164
+ }
165
+ );
166
+
167
+ /* ----------------------------------
168
+ * Indexes
169
+ * ---------------------------------- */
170
+
171
+ userSchema.index({ "contact.email": 1 }, { unique: true });
172
+ userSchema.index({ "auth.googleId": 1 }, { sparse: true });
173
+ userSchema.index({ role: 1, status: 1 });
174
+
175
+ /* ----------------------------------
176
+ * Virtuals
177
+ * ---------------------------------- */
178
+
179
+ userSchema.virtual("fullName").get(function () {
180
+ return `${this.profile?.firstName || ""} ${this.profile?.lastName || ""}`;
181
+ });
182
+
183
+ /* ----------------------------------
184
+ * Export
185
+ * ---------------------------------- */
186
+
187
+ export default userSchema;