@mac777/project-pinecone-models 1.1.11 → 1.1.12

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.
package/src/Order.ts CHANGED
@@ -1,252 +1,201 @@
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 ---------- */
1
+ import mongoose from 'mongoose';
196
2
 
197
- ipAddress: String,
198
- userAgent: String
199
- },
200
- {
201
- timestamps: true,
202
- strict: true
3
+ // Order Ticket Schema
4
+ const orderTicketSchema = new mongoose.Schema({
5
+ ticketVariantId: {
6
+ type: mongoose.Schema.Types.ObjectId,
7
+ required: true
8
+ },
9
+ variantName: {
10
+ type: String,
11
+ required: true
12
+ },
13
+ quantity: {
14
+ type: Number,
15
+ required: true,
16
+ min: 1
17
+ },
18
+ pricePerTicket: {
19
+ type: Number,
20
+ required: true,
21
+ min: 0
22
+ },
23
+ subtotal: {
24
+ type: Number,
25
+ required: true,
26
+ min: 0
203
27
  }
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
- });
28
+ }, { _id: false });
29
+
30
+ // Pricing Schema
31
+ const pricingSchema = new mongoose.Schema({
32
+ subtotal: {
33
+ type: Number,
34
+ required: true,
35
+ min: 0
36
+ },
37
+ platformFee: {
38
+ type: Number,
39
+ required: true,
40
+ min: 0
41
+ },
42
+ paymentFee: {
43
+ type: Number,
44
+ required: true,
45
+ min: 0
46
+ },
47
+ total: {
48
+ type: Number,
49
+ required: true,
50
+ min: 0
51
+ },
52
+ currency: {
53
+ type: String,
54
+ required: true,
55
+ default: 'BDT'
56
+ },
57
+ hostPayout: {
58
+ type: Number,
59
+ required: true,
60
+ min: 0
61
+ }
62
+ }, { _id: false });
63
+
64
+ // Refund Schema
65
+ const refundSchema = new mongoose.Schema({
66
+ reason: {
67
+ type: String,
68
+ required: true,
69
+ enum: ['event_cancelled', 'user_request', 'fraud']
70
+ },
71
+ amount: {
72
+ type: Number,
73
+ required: true,
74
+ min: 0
75
+ },
76
+ refundedAt: {
77
+ type: Date,
78
+ default: Date.now
79
+ },
80
+ stripeRefundId: String
81
+ }, { _id: false });
82
+
83
+ // Main Order Schema
84
+ const orderSchema = new mongoose.Schema({
85
+ orderNumber: {
86
+ type: String,
87
+ required: true,
88
+ unique: true,
89
+ },
90
+
91
+ // WHO
92
+ userId: {
93
+ type: mongoose.Schema.Types.ObjectId,
94
+ required: true,
95
+ },
217
96
 
218
- /* ----------------------------------
219
- * Hooks
220
- * ---------------------------------- */
97
+ // WHAT
98
+ eventId: {
99
+ type: mongoose.Schema.Types.ObjectId,
100
+ required: true,
101
+ },
221
102
 
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();
103
+ paymentId: {
104
+ type: String,
105
+ required: false,
106
+ },
107
+
108
+ tickets: [orderTicketSchema],
109
+
110
+ // MONEY
111
+ pricing: pricingSchema,
112
+
113
+ // STATUS
114
+ status: {
115
+ type: String,
116
+ required: true,
117
+ enum: ['pending', 'confirmed', 'cancelled', 'refunded'],
118
+ default: 'pending'
119
+ },
120
+
121
+ requiresManualReview: {
122
+ type: Boolean,
123
+ default: false
124
+ },
125
+
126
+ manualReviewReason: {
127
+ type: String,
128
+ default: null
129
+ },
130
+
131
+ paymentMethod: {
132
+ type: String,
133
+ required: true,
134
+ enum: ['card', 'bkash', 'bank_transfer', 'free']
135
+ },
136
+ paymentStatus: {
137
+ type: String,
138
+ required: true,
139
+ enum: ['pending', 'succeeded', 'failed'],
140
+ default: 'pending'
141
+ },
142
+ paidAt: Date,
143
+
144
+ // TICKETS ISSUED
145
+ ticketIds: [{
146
+ type: mongoose.Schema.Types.ObjectId,
147
+ ref: 'Ticket'
148
+ }],
149
+
150
+ // LIFECYCLE
151
+ createdAt: {
152
+ type: Date,
153
+ default: Date.now,
154
+ index: true
155
+ },
156
+ expiresAt: {
157
+ type: Date,
158
+ required: true
159
+ },
160
+ confirmedAt: Date,
161
+ cancelledAt: Date,
162
+ refundedAt: Date,
163
+ reminderSentAt: Date,
164
+
165
+ // CONTACT
166
+ buyerEmail: {
167
+ type: String,
168
+ required: true
169
+ },
170
+ buyerPhone: String,
171
+
172
+ // AUDIT
173
+ ipAddress: String,
174
+ userAgent: String,
175
+
176
+ // REFUND (if applicable)
177
+ refund: refundSchema
230
178
  });
231
179
 
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);
180
+ // Indexes for performance
181
+ orderSchema.index({ userId: 1, createdAt: -1 });
182
+ orderSchema.index({ eventId: 1, status: 1 });
183
+ orderSchema.index({ status: 1, expiresAt: 1 });
184
+
185
+ // Auto-generate order number
186
+ orderSchema.pre('save', function(next) {
187
+ if (this.isNew && !this.orderNumber) {
188
+ const timestamp = Date.now().toString().slice(-6);
189
+ const random = Math.random().toString(36).substring(2, 8).toUpperCase();
190
+ this.orderNumber = `ORD-${timestamp}-${random}`;
236
191
  }
237
192
  next();
238
193
  });
239
194
 
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
- }
195
+ // Update updatedAt on save
196
+ orderSchema.pre('save', function(next) {
197
+ // Note: We don't have updatedAt field, but could add if needed
245
198
  next();
246
199
  });
247
200
 
248
- /* ----------------------------------
249
- * Export
250
- * ---------------------------------- */
251
-
252
- export default mongoose.model("Order", orderSchema);
201
+ export default orderSchema;
@@ -0,0 +1,253 @@
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 mongoose.model("Order", orderSchema);
253
+