flykup_model_production 1.0.14 → 1.0.16

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.
@@ -21,7 +21,11 @@ const notificationSchema = new mongoose.Schema(
21
21
  'seller_broadcast',
22
22
  'live_stream_start',
23
23
  'seller_order_update',
24
- 'new_show_scheduled'
24
+ 'new_show_scheduled',
25
+ 'cohost_invite',
26
+ 'cohost_accepted',
27
+ 'cohost_rejected',
28
+ 'cohost_join_live'
25
29
  ],
26
30
  required: true,
27
31
  },
@@ -101,14 +105,18 @@ const notificationSchema = new mongoose.Schema(
101
105
  type: String,
102
106
  },
103
107
  },
108
+ // metadata: {
109
+ // status: String,
110
+ // reason: String,
111
+ // orderId: mongoose.Schema.Types.ObjectId,
112
+ // requestId: mongoose.Schema.Types.ObjectId,
113
+ // customerName: String,
114
+ // sellerName: String,
115
+ // customerProfileURL: String,
116
+ // },
104
117
  metadata: {
105
- status: String,
106
- reason: String,
107
- orderId: mongoose.Schema.Types.ObjectId,
108
- requestId: mongoose.Schema.Types.ObjectId,
109
- customerName: String,
110
- sellerName: String,
111
- customerProfileURL: String,
118
+ type: mongoose.Schema.Types.Mixed, // This allows any JSON object
119
+ default: {} // Default to empty object
112
120
  },
113
121
  },
114
122
  {
@@ -252,7 +252,7 @@ const orderSchema = new mongoose.Schema(
252
252
  },
253
253
  sourceType: {
254
254
  type: String,
255
- enum: ['static', 'shoppable_video', 'livestream', 'auction', 'flash_sale', 'giveaway'],
255
+ enum: ['static', 'shoppable_video', 'livestream', 'auction', 'flash_sale', 'giveaway','bundle_sale','bundle_flash_sale'],
256
256
  required: true
257
257
  },
258
258
  sourceRefId: String,
@@ -351,6 +351,10 @@ cancelSource: {
351
351
  flashPrice: Number,
352
352
  originalPrice: Number
353
353
  }],
354
+ labelPrinted: {
355
+ type: Boolean,
356
+ default: false
357
+ },
354
358
  payment: {
355
359
  type: mongoose.Schema.Types.ObjectId,
356
360
  ref: 'orderPayment'
@@ -61,7 +61,9 @@ const paymentSchema = new mongoose.Schema({
61
61
  },
62
62
  paymentMethod: String,
63
63
  transactionTime: Date,
64
- sellerPayments: [{
64
+
65
+ // ✅ SELLER PAYMENTS FIELD - Now matching package model
66
+ sellerPayments: [{
65
67
  sellerId: {
66
68
  type: mongoose.Schema.Types.ObjectId,
67
69
  ref: 'users',
@@ -94,12 +96,124 @@ const paymentSchema = new mongoose.Schema({
94
96
 
95
97
  // Create indexes for better performance
96
98
  paymentSchema.index({ razorpayOrderId: 1 });
97
- // paymentSchema.index({ cfOrderId: 1 });
98
99
  paymentSchema.index({ orderId: 1 });
99
100
 
100
- // ❌ The pre-save middleware is no longer needed and should be removed.
101
-
102
101
  const OrderPayment =
103
102
  mongoose.models.OrderPayment || mongoose.model('orderPayment', paymentSchema);
104
103
 
105
- export default OrderPayment;
104
+ export default OrderPayment;
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+ // import mongoose from 'mongoose';
116
+
117
+ // const paymentSchema = new mongoose.Schema({
118
+ // orderId: {
119
+ // type: mongoose.Schema.Types.ObjectId,
120
+ // ref: 'Order',
121
+ // required: true
122
+ // },
123
+ // userId: {
124
+ // type: mongoose.Schema.Types.ObjectId,
125
+ // ref: 'users',
126
+ // required: true
127
+ // },
128
+ // paymentGateway: {
129
+ // type: String,
130
+ // enum: ['RAZORPAY', 'CASHFREE'],
131
+ // required: true
132
+ // },
133
+
134
+ // // Razorpay-specific fields
135
+ // razorpayOrderId: {
136
+ // type: String,
137
+ // // ✅ This field is now required only if the gateway is RAZORPAY
138
+ // required: function() {
139
+ // return this.paymentGateway === 'RAZORPAY';
140
+ // }
141
+ // },
142
+ // razorpayPaymentId: {
143
+ // type: String,
144
+ // default: null
145
+ // },
146
+
147
+ // // Cashfree-specific fields
148
+ // cfPaymentSessionId: {
149
+ // type: String,
150
+ // // ✅ This field is now required only if the gateway is CASHFREE
151
+ // required: function() {
152
+ // return this.paymentGateway === 'CASHFREE';
153
+ // }
154
+ // },
155
+ // cfOrderId: {
156
+ // type: String,
157
+ // // ✅ This field is now required only if the gateway is CASHFREE
158
+ // required: function() {
159
+ // return this.paymentGateway === 'CASHFREE';
160
+ // }
161
+ // },
162
+
163
+ // amount: {
164
+ // type: Number,
165
+ // required: true
166
+ // },
167
+ // currency: {
168
+ // type: String,
169
+ // default: 'INR'
170
+ // },
171
+ // status: {
172
+ // type: String,
173
+ // enum: ['PENDING', 'SUCCESS', 'FAILED', 'REFUNDED'],
174
+ // default: 'PENDING'
175
+ // },
176
+ // paymentMethod: String,
177
+ // transactionTime: Date,
178
+ // sellerPayments: [{
179
+ // sellerId: {
180
+ // type: mongoose.Schema.Types.ObjectId,
181
+ // ref: 'users',
182
+ // required: true
183
+ // },
184
+ // payableAmount: { // Amount for products only
185
+ // type: Number,
186
+ // required: true,
187
+ // default: 0
188
+ // },
189
+ // deliveryCharge: { // Delivery fee for this seller's shipment
190
+ // type: Number,
191
+ // required: true,
192
+ // default: 0
193
+ // },
194
+ // totalAmount: { // The sum of payableAmount + deliveryCharge
195
+ // type: Number,
196
+ // required: true,
197
+ // default: 0
198
+ // },
199
+ // settlementStatus: {
200
+ // type: String,
201
+ // enum: ['PENDING', 'SETTLED', 'FAILED'],
202
+ // default: 'PENDING'
203
+ // }
204
+ // }]
205
+ // }, {
206
+ // timestamps: true
207
+ // });
208
+
209
+ // // Create indexes for better performance
210
+ // paymentSchema.index({ razorpayOrderId: 1 });
211
+ // // paymentSchema.index({ cfOrderId: 1 });
212
+ // paymentSchema.index({ orderId: 1 });
213
+
214
+ // // ❌ The pre-save middleware is no longer needed and should be removed.
215
+
216
+ // const OrderPayment =
217
+ // mongoose.models.OrderPayment || mongoose.model('orderPayment', paymentSchema);
218
+
219
+ // export default OrderPayment;
@@ -1,26 +1,25 @@
1
-
2
-
3
-
4
-
5
- // backend/models/ProductListing.js (or similar path)
6
1
  import mongoose from "mongoose";
7
2
  const { Schema } = mongoose;
8
3
 
9
4
  const ProductListingSchema = new Schema(
10
5
  {
11
6
  sellerId: { type: Schema.Types.ObjectId, ref: "sellers" },
12
- stockId: { type: Schema.Types.ObjectId, ref: "stocks" },
7
+ stockId: { type: Schema.Types.ObjectId, ref: "stocks" }, // ✅ KEEP THIS - for main inventory management
13
8
  title: String,
14
9
  description: String,
15
- flashSale: {
16
- isActive: { type: Boolean, default: false },
17
- flashSaleId: { type: mongoose.Schema.Types.ObjectId, ref: 'FlashSale' },
18
- flashPrice: { type: Number, default: 0 },
19
- flashStock: { type: Number, default: 0 },
20
- originalPrice: { type: Number, default: 0 },
21
- endsAt: { type: Date, default: null },
22
- startsAt: { type: Date, default: null }
23
- },
10
+ flashSale: {
11
+ isActive: { type: Boolean, default: false },
12
+ flashSaleId: { type: mongoose.Schema.Types.ObjectId, ref: 'FlashSale' },
13
+ flashPrice: { type: Number, default: 0 },
14
+ // REMOVED: flashStock field - now using main quantity
15
+ originalPrice: { type: Number, default: 0 },
16
+ endsAt: { type: Date, default: null },
17
+ startsAt: { type: Date, default: null }
18
+ },
19
+ reserveForLive: {
20
+ type: Boolean,
21
+ default: false
22
+ },
24
23
  sku: {
25
24
  type: String,
26
25
  required: true,
@@ -54,7 +53,7 @@ const ProductListingSchema = new Schema(
54
53
  min: 0,
55
54
  default: null,
56
55
  },
57
- logisticsType: {
56
+ logisticsType: {
58
57
  type: String,
59
58
  enum: ["flykupLogistics", "selfShipment"],
60
59
  default: null,
@@ -65,47 +64,45 @@ const ProductListingSchema = new Schema(
65
64
  default: null,
66
65
  },
67
66
  estimatedDeliveryDate: {
68
- type: Number, // Change from Date to Number
67
+ type: Number,
69
68
  min: 0,
70
69
  default: null,
71
70
  },
72
-
73
- // --- ADDED/UPDATED FIELDS FROM FRONTEND ---
74
- brand: { type: String, default: null }, // ADDED
71
+ brand: { type: String, default: null },
75
72
  manufacturer: String,
76
- manufacturerAddress: String, // ADDED in frontend, already exists here
73
+ manufacturerAddress: String,
77
74
  countryOfOrigin: String,
78
- netQuantity: { type: String, default: null }, // ADDED (String to accommodate units like '500g')
79
- packagingType: { type: String, default: null }, // ADDED
80
- weight: { // For shipping calculations
75
+ netQuantity: { type: String, default: null },
76
+ packagingType: { type: String, default: null },
77
+ weight: {
81
78
  value: { type: Number, default: null },
82
79
  unit: { type: String, default: null },
83
80
  },
84
- dimensions: { // For shipping calculations
81
+ dimensions: {
85
82
  length: { type: Number, default: null },
86
83
  width: { type: Number, default: null },
87
84
  height: { type: Number, default: null },
88
85
  },
89
- expiryDate: { type: Date, default: null }, // ADDED in frontend, already exists here (changed to allow null)
90
- shelfLife: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
91
- batchNumber: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
92
- gstRate: { type: Number, default: null }, // Changed to allow null if needed
86
+ expiryDate: { type: Date, default: null },
87
+ shelfLife: { type: String, default: null },
88
+ batchNumber: { type: String, default: null },
89
+ gstRate: { type: Number, default: null },
93
90
  sellerName: String,
94
- sellerContact: { type: String, default: null }, // ADDED
95
- sellerGSTIN: { type: String, default: null }, // ADDED
91
+ sellerContact: { type: String, default: null },
92
+ sellerGSTIN: { type: String, default: null },
96
93
  returnPolicy: [String],
97
94
  warranty: {
98
- hasWarranty: { type: Boolean, default: false }, // Default added
99
- duration: { type: String, default: null }, // Default added
95
+ hasWarranty: { type: Boolean, default: false },
96
+ duration: { type: String, default: null },
100
97
  },
101
- fssaiLicenseNo: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
102
- bisCertification: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
103
- importerName: { type: String, default: null }, // Default added
104
- importerAddress: { type: String, default: null }, // Default added
105
- importerGSTIN: { type: String, default: null }, // Default added
106
- eWasteCompliance: { type: Boolean, default: false }, // Default added
107
- recyclablePackaging: { type: Boolean, default: false }, // Default added
108
- hazardousMaterials: { type: String, default: null }, // Default added
98
+ fssaiLicenseNo: { type: String, default: null },
99
+ bisCertification: { type: String, default: null },
100
+ importerName: { type: String, default: null },
101
+ importerAddress: { type: String, default: null },
102
+ importerGSTIN: { type: String, default: null },
103
+ eWasteCompliance: { type: Boolean, default: false },
104
+ recyclablePackaging: { type: Boolean, default: false },
105
+ hazardousMaterials: { type: String, default: null },
109
106
  allowDropshipping: {
110
107
  type: Boolean,
111
108
  default: false,
@@ -114,65 +111,51 @@ const ProductListingSchema = new Schema(
114
111
  commissionRate: {
115
112
  type: Number,
116
113
  min: [0, 'Commission rate cannot be negative.'],
117
- // max: [100, 'Commission rate cannot exceed 100%.'], // Max was 25, changed to 100 based on frontend
118
114
  max: [100, 'Commission rate cannot exceed 100%.'],
119
115
  default: null,
120
- // Removed Mongoose-level required validation dependent on allowDropshipping
121
- // Let application logic handle this if needed, or adjust validator
122
- // required: [
123
- // function () { return this.allowDropshipping === true; },
124
- // 'Commission rate is required when allowing dropshipping.'
125
- // ],
126
- // validate: { ... } // Keep or remove validation as needed
127
116
  },
128
117
  hasReturn: {
129
- type: Boolean,
130
- default: false
131
- },
132
- returnDays: {
133
- type: Number,
134
- min: 0,
135
- default: null
136
- },
137
- size: {
138
- type: String,
139
- default: null
140
- },
118
+ type: Boolean,
119
+ default: false
120
+ },
121
+ returnDays: {
122
+ type: Number,
123
+ min: 0,
124
+ default: null
125
+ },
126
+ size: {
127
+ type: String,
128
+ default: null
129
+ },
141
130
  isActive: {
142
131
  type: Boolean,
143
132
  default: true,
144
- },ratingSummary: {
145
- averageRating: { type: Number, default: 0 },
146
- totalRatings: { type: Number, default: 0 },
147
- ratingDistribution: {
148
- 1: { type: Number, default: 0 },
149
- 2: { type: Number, default: 0 },
150
- 3: { type: Number, default: 0 },
151
- 4: { type: Number, default: 0 },
152
- 5: { type: Number, default: 0 }
153
- }
133
+ },
134
+ shopifySynced: {
135
+ type: Boolean,
136
+ default: false,
154
137
  },
155
- totalReviews: { type: Number, default: 0 }
138
+ ratingSummary: {
139
+ averageRating: { type: Number, default: 0 },
140
+ totalRatings: { type: Number, default: 0 },
141
+ ratingDistribution: {
142
+ 1: { type: Number, default: 0 },
143
+ 2: { type: Number, default: 0 },
144
+ 3: { type: Number, default: 0 },
145
+ 4: { type: Number, default: 0 },
146
+ 5: { type: Number, default: 0 }
147
+ }
148
+ },
149
+ totalReviews: { type: Number, default: 0 }
156
150
  },
157
151
  { timestamps: true }
158
152
  );
159
- ProductListingSchema.index({ title: 'text', description: 'text', category: 'text' });
160
153
 
154
+ ProductListingSchema.index({ title: 'text', description: 'text', category: 'text' });
161
155
 
162
- // Safe export to prevent OverwriteModelError
163
156
  const ProductListing = mongoose.models.productlistings || mongoose.model("productlistings", ProductListingSchema);
164
157
  export default ProductListing;
165
158
 
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
159
  // // backend/models/ProductListing.js (or similar path)
177
160
  // import mongoose from "mongoose";
178
161
  // const { Schema } = mongoose;
@@ -192,25 +175,11 @@ export default ProductListing;
192
175
  // endsAt: { type: Date, default: null },
193
176
  // startsAt: { type: Date, default: null }
194
177
  // },
195
-
196
- // //new fields added
197
-
198
- // returnPolicy: {
199
- // hasReturn: { type: Boolean, default: false },
200
- // returnType: {
201
- // type: [String],
202
- // enum: ['refund', 'replacement'],
203
- // default: []
204
- // },
205
- // returnDays: { type: Number, min: 0, default: null },
206
- // terms: [String] // Keep existing terms for backward compatibility
207
- // },
208
178
  // sku: {
209
179
  // type: String,
210
180
  // required: true,
211
- // match: [/^[A-Za-z0-9-]{6,}$/, 'SKU must be at least 6 alphanumeric characters']
181
+ // index: true
212
182
  // },
213
- // // ----------end of new fields added
214
183
  // images: [
215
184
  // {
216
185
  // key: { type: String, maxLength: 255, default: null },
@@ -239,7 +208,22 @@ export default ProductListing;
239
208
  // min: 0,
240
209
  // default: null,
241
210
  // },
242
-
211
+ // logisticsType: {
212
+ // type: String,
213
+ // enum: ["flykupLogistics", "selfShipment"],
214
+ // default: null,
215
+ // },
216
+ // deliveryCharge: {
217
+ // type: Number,
218
+ // min: 0,
219
+ // default: null,
220
+ // },
221
+ // estimatedDeliveryDate: {
222
+ // type: Number, // Change from Date to Number
223
+ // min: 0,
224
+ // default: null,
225
+ // },
226
+
243
227
  // // --- ADDED/UPDATED FIELDS FROM FRONTEND ---
244
228
  // brand: { type: String, default: null }, // ADDED
245
229
  // manufacturer: String,
@@ -324,13 +308,10 @@ export default ProductListing;
324
308
  // },
325
309
  // totalReviews: { type: Number, default: 0 }
326
310
  // },
327
-
328
-
329
-
330
311
  // { timestamps: true }
331
312
  // );
332
313
  // ProductListingSchema.index({ title: 'text', description: 'text', category: 'text' });
333
- // ProductListingSchema.index({ sellerId: 1, sku: 1 }, { unique: true });
314
+
334
315
 
335
316
  // // Safe export to prevent OverwriteModelError
336
317
  // const ProductListing = mongoose.models.productlistings || mongoose.model("productlistings", ProductListingSchema);
@@ -339,4 +320,3 @@ export default ProductListing;
339
320
 
340
321
 
341
322
 
342
-
@@ -0,0 +1,4 @@
1
+ Seller Name,Owner Name,Email,Mobile,Total Amount,Total Orders,Total Products,Account Number,IFSC Code,Bank Name
2
+ "HARISH A","HARISH A","thebrandspot@gmail.com","THEBRANDSPOT","1270","38","38","","",""
3
+ "Shanthi","Shanthi","shanthiaravindan81@gmail.com","+919500060775","450","1","1","","",""
4
+ "Gokul Krishnan","Gokul Krishnan","gkgokul1817@gmail.com","gokul_krishnan","55","1","1","","",""
@@ -0,0 +1,4 @@
1
+ Seller Name,Owner Name,Email,Mobile,Total Amount,Total Orders,Total Products,Account Number,IFSC Code,Bank Name
2
+ "HARISH A","HARISH A","thebrandspot@gmail.com","THEBRANDSPOT","1270","38","38","","",""
3
+ "Shanthi","Shanthi","shanthiaravindan81@gmail.com","+919500060775","450","1","1","","",""
4
+ "Gokul Krishnan","Gokul Krishnan","gkgokul1817@gmail.com","gokul_krishnan","55","1","1","","",""
@@ -6,43 +6,113 @@ const giveawayProductSchema = new Schema({
6
6
  productId: { type: Schema.Types.ObjectId, ref: "productlistings", required: true },
7
7
  productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
8
8
  productTitle: { type: String },
9
-
10
- // BGA Integration Fields
11
9
  giveawayObjectId: { type: Schema.Types.ObjectId, required: true, index: true },
12
10
  giveawayStatus: {
13
11
  type: String,
14
12
  enum: ['preparing', 'ready', 'active', 'ended', 'failed'],
15
13
  default: 'preparing'
16
14
  },
17
- requireAutoFollow: {
15
+ requireAutoFollow: {
18
16
  type: Boolean,
19
17
  default: false
20
18
  },
21
-
22
19
  activatedAt: { type: Date, default: null },
23
20
  createdAt: { type: Date, default: Date.now }
24
21
  });
25
22
 
26
- // Show Schema
23
+ const liveFlashSaleSchema = new Schema({
24
+ _id: false,
25
+ productId: {
26
+ type: Schema.Types.ObjectId,
27
+ ref: "productlistings",
28
+ required: true
29
+ },
30
+ stockId: {
31
+ type: Schema.Types.ObjectId,
32
+ ref: "stocks",
33
+ required: true
34
+ },
35
+ flashPrice: {
36
+ type: Number,
37
+ required: true,
38
+ min: 1
39
+ },
40
+ duration: {
41
+ type: Number,
42
+ required: true,
43
+ enum: [10, 20, 30, 40, 50, 60, 240]
44
+ },
45
+ initialStock: {
46
+ type: Number,
47
+ required: true,
48
+ min: 1
49
+ },
50
+ currentStock: {
51
+ type: Number,
52
+ required: true,
53
+ min: 0
54
+ },
55
+ sold: {
56
+ type: Number,
57
+ default: 0
58
+ },
59
+ status: {
60
+ type: String,
61
+ enum: ['scheduled', 'active', 'ended', 'cancelled'],
62
+ default: 'scheduled'
63
+ },
64
+ startTime: Date,
65
+ endTime: Date,
66
+ flashSaleId: {
67
+ type: Schema.Types.ObjectId,
68
+ ref: 'FlashSale'
69
+ },
70
+ createdAt: {
71
+ type: Date,
72
+ default: Date.now
73
+ }
74
+ });
75
+ const bundleSaleSchema = new Schema({
76
+ _id: false,
77
+ bundleSaleId: {
78
+ type: Schema.Types.ObjectId,
79
+ ref: "bundlesales",
80
+ required: true
81
+ },
82
+ bundleOwnerSellerId: {
83
+ type: Schema.Types.ObjectId,
84
+ ref: 'sellers',
85
+ required: function() {
86
+ return this.bundleSaleId != null;
87
+ }
88
+ },
89
+ bundleTitle: { type: String }, // Quick reference title
90
+ bundleMRP: { type: Number, min: 0, default: null }, // Original MRP
91
+ sellingPrice: { type: Number, min: 0, default: null }, // Actual selling price
92
+ bundleImage: { // Bundle thumbnail image
93
+ key: { type: String, default: null },
94
+ url: { type: String, default: null }
95
+ },
96
+ createdAt: { type: Date, default: Date.now }
97
+ });
98
+
99
+ // Show Schema with FIXED validation
27
100
  const showSchema = new Schema(
28
101
  {
29
-
30
- sellerId: { // <--- REMOVE or comment out this line
31
- type: mongoose.Schema.Types.ObjectId,
32
- ref: "sellers",
33
- },
34
- // === Host Information ===
35
- host: { // Host (Seller or Dropshipper)
102
+ sellerId: {
103
+ type: mongoose.Schema.Types.ObjectId,
104
+ ref: "sellers",
105
+ },
106
+ host: {
36
107
  type: mongoose.Schema.Types.ObjectId,
37
108
  required: true,
38
- refPath: 'hostModel' // Dynamic reference
109
+ refPath: 'hostModel'
39
110
  },
40
- hostModel: { // Type of host
111
+ hostModel: {
41
112
  type: String,
42
113
  required: true,
43
- enum: ['sellers', 'dropshippers'] // Allowed host types
114
+ enum: ['sellers', 'dropshippers']
44
115
  },
45
-
46
116
  title: {
47
117
  type: String,
48
118
  required: true,
@@ -55,7 +125,7 @@ const showSchema = new Schema(
55
125
  },
56
126
  scheduledAt: {
57
127
  type: Date,
58
- index: true // Add index for better query performance
128
+ index: true
59
129
  },
60
130
  category: {
61
131
  type: String,
@@ -73,13 +143,12 @@ const showSchema = new Schema(
73
143
  type: [String],
74
144
  default: [],
75
145
  },
76
-
77
146
  thumbnailImage: {
78
- type: String, // URL or file path
147
+ type: String,
79
148
  default: null,
80
149
  },
81
150
  previewVideo: {
82
- type: String, // URL or file path
151
+ type: String,
83
152
  default: null,
84
153
  },
85
154
  language: {
@@ -90,14 +159,30 @@ const showSchema = new Schema(
90
159
  default: false,
91
160
  },
92
161
  streamUrl: {
93
- type: String, // URL for the live stream
162
+ type: String,
94
163
  default: null,
95
164
  },
165
+ orientation: {
166
+ type: String,
167
+ enum: ['horizontal', 'vertical'],
168
+ default: 'horizontal'
169
+ },
170
+ layout: {
171
+ type: String,
172
+ enum: ['side-by-side', 'top-bottom'],
173
+ default: 'side-by-side'
174
+ },
96
175
  showStatus: {
97
176
  type: String,
98
177
  enum: ['created', 'live', 'cancelled', 'ended'],
99
178
  default: 'created'
100
179
  },
180
+ viewerCount: {
181
+ type: Number,
182
+ default: 0,
183
+ min: 0
184
+ },
185
+
101
186
  likes: {
102
187
  type: Number,
103
188
  default: 0,
@@ -108,27 +193,60 @@ const showSchema = new Schema(
108
193
  default: [],
109
194
  },
110
195
 
196
+ // ✅ FIXED: Better validation for buyNowProducts
111
197
  buyNowProducts: {
112
198
  type: [
113
199
  {
114
200
  _id: false,
115
201
  productId: { type: Schema.Types.ObjectId, ref: "productlistings" },
116
- productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
117
- productPrice: { type: Number, min: 0, default: null }, // Price set by host for this show
202
+ productOwnerSellerId: {
203
+ type: Schema.Types.ObjectId,
204
+ ref: 'sellers',
205
+ required: function() {
206
+ // Only require if productId exists
207
+ return this.productId != null;
208
+ }
209
+ },
210
+ productPrice: { type: Number, min: 0, default: null },
118
211
  },
119
212
  ],
120
213
  default: [],
214
+ validate: {
215
+ validator: function(products) {
216
+ // Custom validation to ensure productOwnerSellerId exists when productId exists
217
+ return products.every(product =>
218
+ !product.productId || (product.productId && product.productOwnerSellerId)
219
+ );
220
+ },
221
+ message: 'productOwnerSellerId is required when productId is provided'
222
+ }
121
223
  },
224
+ bundleSales: {
225
+ type: [bundleSaleSchema],
226
+ default: []
227
+ },
228
+
122
229
  auctionProducts: {
123
230
  type: [
124
231
  {
125
232
  _id: false,
126
233
  productId: { type: Schema.Types.ObjectId, ref: "productlistings" },
127
- productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
234
+ productOwnerSellerId: {
235
+ type: Schema.Types.ObjectId,
236
+ ref: 'sellers',
237
+ required: function() {
238
+ return this.productId != null;
239
+ }
240
+ },
128
241
  startingPrice: { type: Number, min: 0, default: null },
129
242
  reservedPrice: { type: Number, min: 0, default: null },
130
243
  auctionNumber: {
131
244
  type: Number,
245
+ },
246
+ auctionObjectId: {
247
+ type: Schema.Types.ObjectId,
248
+ required: true,
249
+ index: true
132
250
  }
133
251
  },
134
252
  ],
@@ -140,6 +258,16 @@ const showSchema = new Schema(
140
258
  default: []
141
259
  },
142
260
 
261
+ liveFlashSales: {
262
+ type: [liveFlashSaleSchema],
263
+ default: []
264
+ },
265
+ currentFlashSale: {
266
+ type: Schema.Types.ObjectId,
267
+ ref: 'FlashSale',
268
+ default: null
269
+ },
270
+
143
271
  enabledProductTypes: {
144
272
  buyNow: { type: Boolean, default: false },
145
273
  auction: { type: Boolean, default: false },
@@ -153,9 +281,39 @@ const showSchema = new Schema(
153
281
  { timestamps: true }
154
282
  );
155
283
 
156
- showSchema.pre('save', function (next) {
284
+ // ADD THIS PRE-SAVE MIDDLEWARE TO CLEAN INVALID DATA
285
+ showSchema.pre('save', function(next) {
157
286
  const doc = this;
158
287
 
288
+ // Clean up buyNowProducts - remove items without required fields
289
+ if (doc.buyNowProducts && Array.isArray(doc.buyNowProducts)) {
290
+ doc.buyNowProducts = doc.buyNowProducts.filter(product =>
291
+ product &&
292
+ product.productId &&
293
+ product.productOwnerSellerId
294
+ );
295
+ }
296
+
297
+ // Clean up auctionProducts
298
+ if (doc.auctionProducts && Array.isArray(doc.auctionProducts)) {
299
+ doc.auctionProducts = doc.auctionProducts.filter(product =>
300
+ product &&
301
+ product.productId &&
302
+ product.productOwnerSellerId &&
303
+ product.auctionObjectId
304
+ );
305
+ }
306
+
307
+ // Clean up giveawayProducts
308
+ if (doc.giveawayProducts && Array.isArray(doc.giveawayProducts)) {
309
+ doc.giveawayProducts = doc.giveawayProducts.filter(product =>
310
+ product &&
311
+ product.productId &&
312
+ product.productOwnerSellerId &&
313
+ product.giveawayObjectId
314
+ );
315
+ }
316
+
159
317
  // Set liveDrop based on product types
160
318
  const hasBuyNow = doc.buyNowProducts && doc.buyNowProducts.length > 0;
161
319
  const hasAuction = doc.auctionProducts && doc.auctionProducts.length > 0;
@@ -170,6 +328,276 @@ showSchema.pre('save', function (next) {
170
328
  next();
171
329
  });
172
330
 
173
- const Show = mongoose.model("shows", showSchema);
331
+ // ADD THIS PRE-VALIDATION MIDDLEWARE FOR EXTRA SAFETY
332
+ showSchema.pre('validate', function(next) {
333
+ // Ensure all arrays exist (prevent undefined errors)
334
+ if (!this.buyNowProducts) this.buyNowProducts = [];
335
+ if (!this.auctionProducts) this.auctionProducts = [];
336
+ if (!this.giveawayProducts) this.giveawayProducts = [];
337
+ if (!this.liveFlashSales) this.liveFlashSales = [];
338
+
339
+ next();
340
+ });
341
+
342
+ const Show = mongoose.models.shows || mongoose.model("shows", showSchema);
343
+ export default Show;
344
+
345
+
346
+
347
+ // import mongoose from "mongoose";
348
+ // const { Schema } = mongoose;
349
+
350
+ // const giveawayProductSchema = new Schema({
351
+ // _id: false,
352
+ // productId: { type: Schema.Types.ObjectId, ref: "productlistings", required: true },
353
+ // productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
354
+ // productTitle: { type: String },
355
+ // giveawayObjectId: { type: Schema.Types.ObjectId, required: true, index: true },
356
+ // giveawayStatus: {
357
+ // type: String,
358
+ // enum: ['preparing', 'ready', 'active', 'ended', 'failed'],
359
+ // default: 'preparing'
360
+ // },
361
+ // requireAutoFollow: {
362
+ // type: Boolean,
363
+ // default: false
364
+ // },
365
+ // activatedAt: { type: Date, default: null },
366
+ // createdAt: { type: Date, default: Date.now }
367
+ // });
368
+
369
+ // // Live Flash Sale Schema
370
+ // const liveFlashSaleSchema = new Schema({
371
+ // _id: false,
372
+ // productId: {
373
+ // type: Schema.Types.ObjectId,
374
+ // ref: "productlistings",
375
+ // required: true
376
+ // },
377
+ // stockId: {
378
+ // type: Schema.Types.ObjectId,
379
+ // ref: "stocks",
380
+ // required: true
381
+ // },
382
+ // flashPrice: {
383
+ // type: Number,
384
+ // required: true,
385
+ // min: 1
386
+ // },
387
+ // duration: {
388
+ // type: Number,
389
+ // required: true,
390
+ // enum: [10, 20, 30, 40, 50, 60,240]
391
+ // },
392
+ // initialStock: {
393
+ // type: Number,
394
+ // required: true,
395
+ // min: 1
396
+ // },
397
+ // currentStock: {
398
+ // type: Number,
399
+ // required: true,
400
+ // min: 0
401
+ // },
402
+ // sold: {
403
+ // type: Number,
404
+ // default: 0
405
+ // },
406
+ // status: {
407
+ // type: String,
408
+ // enum: ['scheduled', 'active', 'ended', 'cancelled'],
409
+ // default: 'scheduled'
410
+ // },
411
+ // startTime: Date,
412
+ // endTime: Date,
413
+ // flashSaleId: {
414
+ // type: Schema.Types.ObjectId,
415
+ // ref: 'FlashSale'
416
+ // },
417
+ // createdAt: {
418
+ // type: Date,
419
+ // default: Date.now
420
+ // }
421
+ // });
422
+ // // Show Schema
423
+ // const showSchema = new Schema(
424
+ // {
425
+ // sellerId: {
426
+ // type: mongoose.Schema.Types.ObjectId,
427
+ // ref: "sellers",
428
+ // },
429
+ // // === Host Information ===
430
+ // host: {
431
+ // type: mongoose.Schema.Types.ObjectId,
432
+ // required: true,
433
+ // refPath: 'hostModel'
434
+ // },
435
+ // hostModel: {
436
+ // type: String,
437
+ // required: true,
438
+ // enum: ['sellers', 'dropshippers']
439
+ // },
440
+
441
+ // title: {
442
+ // type: String,
443
+ // required: true,
444
+ // },
445
+ // date: {
446
+ // type: Date,
447
+ // },
448
+ // time: {
449
+ // type: String,
450
+ // },
451
+ // scheduledAt: {
452
+ // type: Date,
453
+ // index: true
454
+ // },
455
+ // category: {
456
+ // type: String,
457
+ // },
458
+ // subCategory: {
459
+ // type: String,
460
+ // default: '',
461
+ // },
462
+ // liveStreamId: { type: String, default: null },
463
+ // streamName: {
464
+ // type: String,
465
+ // default: ''
466
+ // },
467
+ // tags: {
468
+ // type: [String],
469
+ // default: [],
470
+ // },
471
+
472
+ // thumbnailImage: {
473
+ // type: String,
474
+ // default: null,
475
+ // },
476
+ // previewVideo: {
477
+ // type: String,
478
+ // default: null,
479
+ // },
480
+ // language: {
481
+ // type: String,
482
+ // },
483
+ // isLive: {
484
+ // type: Boolean,
485
+ // default: false,
486
+ // },
487
+ // streamUrl: {
488
+ // type: String,
489
+ // default: null,
490
+ // },
491
+
492
+ // // === Stream Layout Configuration ===
493
+ // orientation: {
494
+ // type: String,
495
+ // enum: ['horizontal', 'vertical'],
496
+ // default: 'horizontal'
497
+ // },
498
+ // layout: {
499
+ // type: String,
500
+ // enum: ['side-by-side', 'top-bottom'],
501
+ // default: 'side-by-side'
502
+ // },
503
+
504
+ // showStatus: {
505
+ // type: String,
506
+ // enum: ['created', 'live', 'cancelled', 'ended'],
507
+ // default: 'created'
508
+ // },
509
+ // likes: {
510
+ // type: Number,
511
+ // default: 0,
512
+ // },
513
+ // likedBy: {
514
+ // type: [mongoose.Schema.Types.ObjectId],
515
+ // ref: 'users',
516
+ // default: [],
517
+ // },
518
+
519
+ // buyNowProducts: {
520
+ // type: [
521
+ // {
522
+ // _id: false,
523
+ // productId: { type: Schema.Types.ObjectId, ref: "productlistings" },
524
+ // productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
525
+ // productPrice: { type: Number, min: 0, default: null },
526
+ // },
527
+ // ],
528
+ // default: [],
529
+ // },
530
+ // auctionProducts: {
531
+ // type: [
532
+ // {
533
+ // _id: false,
534
+ // productId: { type: Schema.Types.ObjectId, ref: "productlistings" },
535
+ // productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
536
+ // startingPrice: { type: Number, min: 0, default: null },
537
+ // reservedPrice: { type: Number, min: 0, default: null },
538
+ // auctionNumber: {
539
+ // type: Number,
540
+ // },
541
+ // // BGA Integration - Reference to BGA auction document
542
+ // auctionObjectId: {
543
+ // type: Schema.Types.ObjectId,
544
+ // required: true,
545
+ // index: true
546
+ // }
547
+ // },
548
+ // ],
549
+ // default: [],
550
+ // },
551
+
552
+ // giveawayProducts: {
553
+ // type: [giveawayProductSchema],
554
+ // default: []
555
+ // },
556
+
557
+ // // === LIVE FLASH SALE FIELDS (ADD THESE) ===
558
+ // liveFlashSales: {
559
+ // type: [liveFlashSaleSchema],
560
+ // default: [] // This ensures it's always an array
561
+ // },
562
+ // currentFlashSale: {
563
+ // type: Schema.Types.ObjectId,
564
+ // ref: 'FlashSale',
565
+ // default: null
566
+ // },
567
+
568
+ // enabledProductTypes: {
569
+ // buyNow: { type: Boolean, default: false },
570
+ // auction: { type: Boolean, default: false },
571
+ // giveaway: { type: Boolean, default: false }
572
+ // },
573
+ // notes: {
574
+ // type: String,
575
+ // default: ''
576
+ // },
577
+ // },
578
+ // { timestamps: true }
579
+ // );
580
+
581
+ // showSchema.pre('save', function (next) {
582
+ // const doc = this;
583
+
584
+ // // Set liveDrop based on product types
585
+ // const hasBuyNow = doc.buyNowProducts && doc.buyNowProducts.length > 0;
586
+ // const hasAuction = doc.auctionProducts && doc.auctionProducts.length > 0;
587
+ // const hasGiveaway = doc.giveawayProducts && doc.giveawayProducts.length > 0;
588
+ // doc.liveDrop = hasBuyNow && hasAuction && hasGiveaway;
589
+
590
+ // // Ensure coHost is null if hasCoHost is false
591
+ // if (!doc.hasCoHost) {
592
+ // doc.coHost = null;
593
+ // }
594
+
595
+ // next();
596
+ // });
597
+
598
+ // const Show = mongoose.model("shows", showSchema);
599
+
600
+ // export default Show;
601
+
602
+
174
603
 
175
- export default Show;
@@ -1,19 +1,8 @@
1
-
2
- // models/Stock.js
1
+ // models/Stock.js - Simplified
3
2
  import mongoose from "mongoose";
4
3
  const { Schema } = mongoose;
5
4
 
6
- // Sub-schema for manual stock updates
7
- const StockUpdateHistorySchema = new Schema({
8
- change: { type: Number, required: true }, // e.g., +50 or -10
9
- previousQuantity: { type: Number, required: true },
10
- newQuantity: { type: Number, required: true },
11
- reason: { type: String, default: "Manual update by seller" },
12
- updatedAt: { type: Date, default: Date.now }
13
- });
14
-
15
-
16
- const StockSchema = new Schema(
5
+ const stockSchema = new mongoose.Schema(
17
6
  {
18
7
  sellerId: {
19
8
  type: Schema.Types.ObjectId,
@@ -22,64 +11,95 @@ const StockSchema = new Schema(
22
11
  productListingId: {
23
12
  type: Schema.Types.ObjectId,
24
13
  ref: "productlistings",
14
+ required: true,
15
+ unique: true
16
+ },
17
+ quantity: {
18
+ type: Number,
19
+ default: 0,
20
+ min: 0
25
21
  },
26
22
  title: String,
27
23
  images: [{
28
24
  key: String,
29
25
  url: String
30
26
  }],
31
- quantity: {
27
+ // ❌ REMOVED: totalReserved, flashSaleReservations
28
+ lowStockThreshold: {
32
29
  type: Number,
33
- min: 0,
34
- default: 0,
30
+ default: 10
35
31
  },
36
- // History for manual stock adjustments
37
- stockUpdateHistory: [StockUpdateHistorySchema],
38
-
39
- // Track reservations for flash sales
40
- flashSaleReservations: [{
41
- flashSaleId: {
42
- type: Schema.Types.ObjectId,
43
- ref: "FlashSale",
44
- required: true
45
- },
46
- quantity: { type: Number, min: 0, default: 0 },
47
- status: {
48
- type: String,
49
- enum: ['reserved', 'active', 'released', 'sold', 'partially_sold'],
50
- default: 'reserved'
51
- },
52
- reservedAt: { type: Date, default: Date.now },
53
- releasedAt: Date,
54
- soldQuantity: { type: Number, default: 0 }
55
- }],
56
- totalReserved: {
32
+ reorderQuantity: {
57
33
  type: Number,
58
- min: 0,
59
- default: 0
60
- }
34
+ default: 50
35
+ },
36
+ isInStock: {
37
+ type: Boolean,
38
+ default: true
39
+ },
40
+ lastRestocked: {
41
+ type: Date,
42
+ default: null
43
+ },
44
+ stockUpdateHistory: [{
45
+ change: Number,
46
+ previousQuantity: Number,
47
+ newQuantity: Number,
48
+ reason: String,
49
+ updatedAt: { type: Date, default: Date.now }
50
+ }]
61
51
  },
62
52
  { timestamps: true }
63
53
  );
64
54
 
65
- // Pre-save hook to calculate totalReserved
66
- StockSchema.pre('save', function(next) {
67
- if (this.isModified('flashSaleReservations')) {
68
- this.totalReserved = this.flashSaleReservations.reduce((total, reservation) => {
69
- return total + (['reserved', 'active'].includes(reservation.status) ? reservation.quantity : 0);
70
- }, 0);
71
- }
72
- next();
73
- });
55
+ const Stock = mongoose.models.stocks || mongoose.model("stocks", stockSchema);
56
+ export default Stock;
57
+
58
+
59
+ // // models/Stock.js - Simplified version without flash sale reservations
60
+ // import mongoose from "mongoose";
61
+ // const { Schema } = mongoose;
62
+
63
+ // const stockSchema = new mongoose.Schema(
64
+ // {
65
+ // productListingId: {
66
+ // type: Schema.Types.ObjectId,
67
+ // ref: "productlistings",
68
+ // required: true,
69
+ // unique: true
70
+ // },
71
+ // quantity: {
72
+ // type: Number,
73
+ // default: 0,
74
+ // min: 0
75
+ // },
76
+ // // REMOVED: totalReserved field since we don't need reservations
77
+ // // REMOVED: flashSaleReservations array completely
78
+ // lowStockThreshold: {
79
+ // type: Number,
80
+ // default: 10
81
+ // },
82
+ // reorderQuantity: {
83
+ // type: Number,
84
+ // default: 50
85
+ // },
86
+ // isInStock: {
87
+ // type: Boolean,
88
+ // default: true
89
+ // },
90
+ // lastRestocked: {
91
+ // type: Date,
92
+ // default: null
93
+ // }
94
+ // },
95
+ // { timestamps: true }
96
+ // );
74
97
 
75
- // Virtual for available quantity
76
- StockSchema.virtual('availableQuantity').get(function() {
77
- return Math.max(0, this.quantity - this.totalReserved);
78
- });
98
+ // // Indexes
99
+ // stockSchema.index({ productListingId: 1 });
100
+ // stockSchema.index({ isInStock: 1 });
101
+ // stockSchema.index({ quantity: 1 });
79
102
 
80
- // Ensure virtuals are included in JSON output
81
- StockSchema.set('toJSON', { virtuals: true });
82
- StockSchema.set('toObject', { virtuals: true });
103
+ // const Stock = mongoose.models.stocks || mongoose.model("stocks", stockSchema);
104
+ // export default Stock;
83
105
 
84
- const Stock = mongoose.models.stocks || mongoose.model("stocks", StockSchema);
85
- export default Stock;
@@ -7,20 +7,22 @@ import Seller from "./seller.model.js";
7
7
  const UserSchema = new mongoose.Schema(
8
8
  {
9
9
  devices: [
10
- {
11
- deviceId: { type: String, required: true },
12
- fcmToken: { type: String, required: true },
13
- platform: {
14
- type: String,
15
- enum: ["web", "android", "ios", "mobile-web"],
16
- required: true,
17
- },
18
- lastLogin: { type: Date, default: Date.now },
19
- lastLogout: { type: Date },
20
- isActive: { type: Boolean, default: true },
21
- _id: false,
22
- },
23
- ],
10
+ {
11
+ deviceId: { type: String, required: true },
12
+ fcmToken: { type: String, required: true },
13
+ snsEndpointArn: { type: String, default: null }, // New field for SNS
14
+ platform: {
15
+ type: String,
16
+ enum: ["web", "android", "ios", "mobile-web"],
17
+ required: true,
18
+ },
19
+ lastLogin: { type: Date, default: Date.now },
20
+ lastLogout: { type: Date },
21
+ isActive: { type: Boolean, default: true },
22
+ _id: false,
23
+ },
24
+ ],
25
+
24
26
  sellerInfo: { type: mongoose.Schema.Types.ObjectId, ref: "sellers" },
25
27
  dropshipperInfo: { type: mongoose.Schema.Types.ObjectId, ref: "dropshippers" },
26
28
  categories: { type: [String], default: [], maxLength: 100 },
@@ -42,6 +44,7 @@ const UserSchema = new mongoose.Schema(
42
44
  maxLength: 60,
43
45
  index: true,
44
46
  },
47
+ isMandate: { type: Boolean, default: false },
45
48
  password: {
46
49
  type: String,
47
50
  required: function () {
@@ -49,7 +52,6 @@ const UserSchema = new mongoose.Schema(
49
52
  },
50
53
  maxLength: 120,
51
54
  },
52
- mobile: { type: String, trim: true, maxLength: 15 },
53
55
  isEmailVerified: { type: Boolean, default: false },
54
56
  role: {
55
57
  type: String,
@@ -59,6 +61,12 @@ const UserSchema = new mongoose.Schema(
59
61
  },
60
62
  default: null,
61
63
  },
64
+ gender: {
65
+ type: String,
66
+ enum: ["male", "female", "other", "prefer-not-to-say"],
67
+ lowercase: true,
68
+ default: null
69
+ },
62
70
  accessAllowed: { type: Boolean, default: true },
63
71
  oAuth: {
64
72
  type: String,
@@ -120,6 +128,13 @@ const UserSchema = new mongoose.Schema(
120
128
  isAddressSelected: { type: Boolean, default: false },
121
129
  addressSelectedDate: { type: Date },
122
130
 
131
+ //Mobile Verification
132
+ mobile: { type: String, trim: true, maxLength: 15, unique: true, sparse: true }, // Make it unique but allow nulls
133
+ isMobileVerified: { type: Boolean, default: false },
134
+ mobileVerificationOTP: { type: String, select: false }, // 'select: false' hides it from default queries
135
+ mobileVerificationOTPExpiry: { type: Date, select: false },
136
+
137
+
123
138
  // Payment Mandate Setup (Auto-Payment)
124
139
  payuMandate: {
125
140
  mandateToken: { type: String, default: null },
@@ -144,7 +159,11 @@ const UserSchema = new mongoose.Schema(
144
159
  },
145
160
  isAutoPaymentEnabled: { type: Boolean, default: false },
146
161
  autoPaymentSetupDate: { type: Date },
147
-
162
+ onboardingStatus: {
163
+ type: String,
164
+ enum: ["pending","profile_setup", "completed"],
165
+ default: "completed" // Default to completed for existing users
166
+ },
148
167
  deviceInfo: {
149
168
  deviceId: { type: String, default: null },
150
169
  appPlatform: { type: String, enum: ["android", "ios", "web"], default: "web" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flykup_model_production",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "private": false,