flykup_model_production 1.0.10 → 1.0.11

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/index.js CHANGED
@@ -33,6 +33,7 @@ import SellerDraft from './models/sellerDraft.model.js';
33
33
  import AadhaarVerification from './models/AadhaarVerification.js';
34
34
  import BankVerification from './models/BankVerification.js';
35
35
  import GSTVerification from './models/GSTVerification.js';
36
+ import OrderPayment from './models/orderPayment.model.js';
36
37
  let initialized = false;
37
38
 
38
39
  export async function initializeSharedModels({ token, dbUri }) {
@@ -97,7 +98,7 @@ export const SellerDraftModel = createModelProxy(SellerDraft);
97
98
  export const AadhaarVerificationModel = createModelProxy(AadhaarVerification);
98
99
  export const BankVerificationModel = createModelProxy(BankVerification);
99
100
  export const GSTVerificationModel = createModelProxy(GSTVerification);
100
-
101
+ export const OrderPaymentModel = createModelProxy(OrderPayment)
101
102
 
102
103
  export {
103
104
  AdminModel as Admin,
@@ -134,5 +135,6 @@ export {
134
135
  SellerDraftModel as SellerDraft,
135
136
  AadhaarVerificationModel as AadhaarVerification,
136
137
  BankVerificationModel as BankVerification,
137
- GSTVerificationModel as GSTVerification
138
+ GSTVerificationModel as GSTVerification,
139
+ OrderPaymentModel as OrderPayment
138
140
  };
@@ -8,6 +8,16 @@ const bankVerificationSchema = new mongoose.Schema({
8
8
  required: true,
9
9
  unique: true, // Ensures only one bank verification per user
10
10
  index: true
11
+ },
12
+ sellerId: {
13
+ type: mongoose.Schema.Types.ObjectId,
14
+ ref: 'sellers',
15
+
16
+ },
17
+ role: {
18
+ type: String,
19
+ enum: ['user', 'seller', 'admin'],
20
+
11
21
  },
12
22
  accountNumber: {
13
23
  type: String,
@@ -69,6 +69,15 @@ const liveStreamInteractionSchema = new mongoose.Schema({
69
69
  type: mongoose.Schema.Types.ObjectId,
70
70
  ref: 'productlistings'
71
71
  }],
72
+ auctionBids: [{
73
+ productId: { type: mongoose.Schema.Types.ObjectId, ref: 'productlistings' },
74
+ bidAmount: { type: Number, required: true },
75
+ bidTime: { type: Date, default: Date.now }
76
+ }],
77
+ giveawayEntries: [{
78
+ productId: { type: mongoose.Schema.Types.ObjectId, ref: 'productlistings' },
79
+ entryTime: { type: Date, default: Date.now }
80
+ }]
72
81
  }, {
73
82
  timestamps: true
74
83
  });
@@ -1,34 +1,53 @@
1
1
  import mongoose, { Schema, model } from 'mongoose';
2
2
 
3
3
  const productInteractionSchema = new mongoose.Schema({
4
- product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
5
- user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
6
- seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
7
- location: {
8
- city: String,
9
- region: String,
10
- country: String
11
- },
12
- // --- NEW FIELD ---
13
- platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
14
- device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
15
- browser: String,
16
- os: String,
17
- ip: { type: String, required: true },
18
- isIndianRegion: { type: Boolean, default: false },
19
- rating: {
20
- type: Number,
21
- min: 1,
22
- max: 5,
23
- validate: {
24
- validator: Number.isInteger,
25
- message: '{VALUE} is not an integer value'
26
- }
27
- },
28
- review: {
29
- type: String,
30
- maxlength: 500
4
+ product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
5
+ user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
6
+ seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
7
+ location: {
8
+ city: String,
9
+ region: String,
10
+ country: String
11
+ },
12
+ platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
13
+ device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
14
+ browser: String,
15
+ os: String,
16
+ ip: { type: String, required: true },
17
+ isIndianRegion: { type: Boolean, default: false },
18
+ rating: {
19
+ type: Number,
20
+ min: 1,
21
+ max: 5,
22
+ validate: {
23
+ validator: Number.isInteger,
24
+ message: '{VALUE} is not an integer value'
31
25
  }
26
+ },
27
+ review: {
28
+ type: String,
29
+ maxlength: 500
30
+ },
31
+ viewCount: { type: Number, default: 1 },
32
+ // NEW: Trust signals tracking
33
+ trustSignals: {
34
+ reviewViews: { type: Number, default: 0 }, // How many times user viewed reviews
35
+ reviewViewDuration: { type: Number, default: 0 }, // Total time spent on reviews (seconds)
36
+ comparisonViews: { type: Number, default: 0 }, // How many times user compared with other products
37
+ priceCheckCount: { type: Number, default: 0 }, // How many times user checked pricing
38
+ lastTrustSignalAt: { type: Date } // When the last trust signal was recorded
39
+ },
40
+ // NEW: Engagement status for sellers
41
+ engagementStatus: {
42
+ type: String,
43
+ enum: ['new', 'interested', 'hesitant', 'contacted', 'converted'],
44
+ default: 'new'
45
+ },
46
+ sellerNotes: [{
47
+ note: String,
48
+ createdAt: { type: Date, default: Date.now },
49
+ updatedAt: { type: Date, default: Date.now }
50
+ }]
32
51
  }, { timestamps: true });
33
52
 
34
53
  // Ensures a user's view is counted only once per product
@@ -40,3 +59,50 @@ productInteractionSchema.index({ createdAt: -1 });
40
59
  // Safe export to prevent OverwriteModelError
41
60
  const ProductInteraction = mongoose.models.ProductInteraction || mongoose.model('ProductInteraction', productInteractionSchema);
42
61
  export default ProductInteraction;
62
+
63
+
64
+
65
+
66
+ // import mongoose, { Schema, model } from 'mongoose';
67
+
68
+ // const productInteractionSchema = new mongoose.Schema({
69
+ // product: { type: mongoose.Schema.Types.ObjectId, ref: 'Product', required: true },
70
+ // user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
71
+ // seller: { type: mongoose.Schema.Types.ObjectId, ref: 'Seller', required: true },
72
+ // location: {
73
+ // city: String,
74
+ // region: String,
75
+ // country: String
76
+ // },
77
+ // // --- NEW FIELD ---
78
+ // platform: { type: String, enum: ['web', 'mobile', 'unknown'], default: 'mobile' },
79
+ // device: { type: String, enum: ['mobile', 'desktop', 'tablet', 'other'] },
80
+ // browser: String,
81
+ // os: String,
82
+ // ip: { type: String, required: true },
83
+ // isIndianRegion: { type: Boolean, default: false },
84
+ // rating: {
85
+ // type: Number,
86
+ // min: 1,
87
+ // max: 5,
88
+ // validate: {
89
+ // validator: Number.isInteger,
90
+ // message: '{VALUE} is not an integer value'
91
+ // }
92
+ // },
93
+ // review: {
94
+ // type: String,
95
+ // maxlength: 500
96
+ // },
97
+ // viewCount: { type: Number, default: 1 }
98
+ // }, { timestamps: true });
99
+
100
+ // // Ensures a user's view is counted only once per product
101
+ // productInteractionSchema.index({ product: 1, user: 1 }, { unique: true, partialFilterExpression: { user: { $exists: true } } });
102
+
103
+ // // Additional indexes for performance
104
+ // productInteractionSchema.index({ createdAt: -1 });
105
+
106
+ // // Safe export to prevent OverwriteModelError
107
+ // const ProductInteraction = mongoose.models.ProductInteraction || mongoose.model('ProductInteraction', productInteractionSchema);
108
+ // export default ProductInteraction;
@@ -61,7 +61,22 @@ const shoppableVideoInteractionSchema = new mongoose.Schema({
61
61
  productsClicked: [{ // Unique list of products clicked by this user for this video
62
62
  type: mongoose.Schema.Types.ObjectId,
63
63
  ref: 'productlistings'
64
- }]
64
+ }],
65
+ maxSecondReached: {
66
+ type: Number,
67
+ default: 0
68
+ },
69
+ rewatchCount: {
70
+ type: Number,
71
+ default: 0
72
+ },
73
+ watchSessions: [{
74
+ startedAt: Date,
75
+ endedAt: Date,
76
+ duration: Number,
77
+ completionPercentage: Number,
78
+ maxSecond: Number
79
+ }],
65
80
  }, {
66
81
  timestamps: true
67
82
  });
@@ -71,6 +86,9 @@ shoppableVideoInteractionSchema.index({ video: 1, user: 1 }, {
71
86
  unique: true,
72
87
  partialFilterExpression: { user: { $exists: true } }
73
88
  });
89
+ shoppableVideoInteractionSchema.index({ video: 1, maxSecondReached: 1 });
90
+ shoppableVideoInteractionSchema.index({ video: 1, rewatchCount: 1 });
91
+ shoppableVideoInteractionSchema.index({ host: 1, user: 1 });
74
92
 
75
93
  // Ensures a unique interaction record per anonymous session per video.
76
94
  shoppableVideoInteractionSchema.index({ video: 1, sessionIdentifier: 1 }, {
@@ -191,6 +191,13 @@ const ChatMessageSchema = new mongoose.Schema({
191
191
  required: true
192
192
  },
193
193
 
194
+ source: {
195
+ type: String,
196
+ enum: ['chat', 'product', 'shoppable', 'liveVideo'],
197
+ default: 'chat'
198
+ },
199
+
200
+
194
201
  // Message content
195
202
  messageType: {
196
203
  type: String,
@@ -17,6 +17,10 @@ const notificationSchema = new mongoose.Schema(
17
17
  "return_status",
18
18
  'new_video',
19
19
  "new_product",
20
+ 'admin_broadcast',
21
+ 'seller_broadcast',
22
+ 'live_stream_start',
23
+ 'seller_order_update'
20
24
  ],
21
25
  required: true,
22
26
  },
@@ -1,5 +1,6 @@
1
+
1
2
  // order.modal.js
2
- import mongoose, { Schema, model } from 'mongoose';
3
+ import mongoose from 'mongoose';
3
4
  import { nanoid } from 'nanoid';
4
5
 
5
6
  const orderSchema = new mongoose.Schema(
@@ -8,7 +9,7 @@ const orderSchema = new mongoose.Schema(
8
9
  type: String,
9
10
  required: true,
10
11
  unique: true,
11
- default: () => `ORD-${nanoid(8)}`
12
+ default: () => `FLY-ORD-${nanoid(8)}`
12
13
  },
13
14
  userId: {
14
15
  type: mongoose.Schema.Types.ObjectId,
@@ -48,7 +49,15 @@ const orderSchema = new mongoose.Schema(
48
49
  type: String,
49
50
  enum: ['CGST+SGST', 'IGST',"NON-GST"],
50
51
  required: true
51
- }
52
+ },
53
+ isFlashSale: {
54
+ type: Boolean,
55
+ default: false
56
+ },
57
+ flashPrice: {
58
+ type: Number,
59
+ default: null // Store the specific flash price used for this item
60
+ }
52
61
  }],
53
62
  totalBaseAmount: {
54
63
  type: Number,
@@ -100,6 +109,77 @@ const orderSchema = new mongoose.Schema(
100
109
  default: null
101
110
  }
102
111
  },
112
+ logisticsDetails: {
113
+ shipmentMethod: {
114
+ type: String,
115
+ enum: ['self_shipment', 'flykup_logistics'],
116
+ default: 'flykup_logistics'
117
+ },
118
+ awbNumber: String,
119
+ carrier: String,
120
+ carrierId: String,
121
+ trackingNumber: String,
122
+ trackingUrl: String,
123
+ expectedDeliveryDate: Date,
124
+ shipmentBookedAt: Date,
125
+ logisticsResponse: mongoose.Schema.Types.Mixed,
126
+ shipmentBookingStatus: {
127
+ type: String,
128
+ enum: ['pending', 'booked', 'failed', 'cancelled', 'cancellation_failed'], // Add the new value here
129
+ default: 'pending'
130
+ },
131
+ shipmentBookingError: String,
132
+ multipleSellers: {
133
+ type: Boolean,
134
+ default: false
135
+ },
136
+ selectedCourier: {
137
+ courierId: String,
138
+ courierName: String,
139
+ deliveryCharges: Number,
140
+ estimatedDays: Number,
141
+ deliveryDate: String
142
+ },
143
+ cancellationAttemptedAt: Date,
144
+ cancellationResult: {
145
+ success: Boolean,
146
+ message: String,
147
+ error: String,
148
+ responseData: mongoose.Schema.Types.Mixed
149
+ },
150
+ cancellationEligibility: {
151
+ eligible: Boolean,
152
+ reason: String
153
+ },
154
+ tracking: {
155
+ lastSyncedAt: Date,
156
+ currentStatus: String,
157
+ statusCode: String,
158
+ progressPercentage: Number,
159
+ currentLocation: String,
160
+ estimatedDelivery: Date,
161
+ trackingTimeline: [{
162
+ date: Date,
163
+ status: String,
164
+ location: String,
165
+ icon: String
166
+ }]
167
+ },
168
+ },
169
+ packageDetails: {
170
+ totalWeight: Number,
171
+ weightUnit: {
172
+ type: String,
173
+ default: 'grams'
174
+ },
175
+ dimensions: {
176
+ length: Number,
177
+ width: Number,
178
+ height: Number
179
+ },
180
+
181
+ volumetricWeight: Number
182
+ },
103
183
  pickupAddresses: [{
104
184
  sellerUserId: {
105
185
  type: mongoose.Schema.Types.ObjectId,
@@ -136,7 +216,7 @@ const orderSchema = new mongoose.Schema(
136
216
  }],
137
217
  paymentMethod: {
138
218
  type: String,
139
- enum: ['CARD', 'UPI', 'NETBANKING', 'WALLET', 'COD', "PENDING_PAYMENT", "CASHFREE", "Online"],
219
+ enum: ['CARD', 'UPI', 'NETBANKING', 'WALLET', 'COD', "PENDING_PAYMENT", "CASHFREE","RAZORPAY", "Online"],
140
220
  required: true
141
221
  },
142
222
  paymentStatus: {
@@ -168,7 +248,7 @@ const orderSchema = new mongoose.Schema(
168
248
  },
169
249
  sourceType: {
170
250
  type: String,
171
- enum: ['static', 'shoppable_video', 'livestream', 'auction'],
251
+ enum: ['static', 'shoppable_video', 'livestream', 'auction', 'flash_sale', 'giveaway'],
172
252
  required: true
173
253
  },
174
254
  sourceRefId: String,
@@ -254,6 +334,19 @@ cancelSource: {
254
334
  enum: ['user', 'seller', 'system'],
255
335
  default: 'user'
256
336
  },
337
+ flashSaleItems: [{
338
+ productId: {
339
+ type: mongoose.Schema.Types.ObjectId,
340
+ ref: 'productlistings'
341
+ },
342
+ flashSaleId: {
343
+ type: mongoose.Schema.Types.ObjectId,
344
+ ref: 'FlashSale'
345
+ },
346
+ quantity: Number,
347
+ flashPrice: Number,
348
+ originalPrice: Number
349
+ }],
257
350
  payment: {
258
351
  type: mongoose.Schema.Types.ObjectId,
259
352
  ref: 'orderPayment'
@@ -273,10 +366,12 @@ payment: {
273
366
  },
274
367
  invoiceError: String
275
368
  },
369
+
276
370
  { timestamps: true }
277
371
  );
278
372
 
279
373
 
280
374
 
375
+
281
376
  const Order = mongoose.models.Order || mongoose.model('Order', orderSchema);
282
377
  export default Order;
@@ -0,0 +1,91 @@
1
+ import mongoose from 'mongoose';
2
+
3
+ const paymentSchema = new mongoose.Schema({
4
+ orderId: {
5
+ type: mongoose.Schema.Types.ObjectId,
6
+ ref: 'Order',
7
+ required: true
8
+ },
9
+ userId: {
10
+ type: mongoose.Schema.Types.ObjectId,
11
+ ref: 'users',
12
+ required: true
13
+ },
14
+ paymentGateway: {
15
+ type: String,
16
+ enum: ['RAZORPAY', 'CASHFREE'],
17
+ required: true
18
+ },
19
+
20
+ // Razorpay-specific fields
21
+ razorpayOrderId: {
22
+ type: String,
23
+ // ✅ This field is now required only if the gateway is RAZORPAY
24
+ required: function() {
25
+ return this.paymentGateway === 'RAZORPAY';
26
+ }
27
+ },
28
+ razorpayPaymentId: {
29
+ type: String,
30
+ default: null
31
+ },
32
+
33
+ // Cashfree-specific fields
34
+ cfPaymentSessionId: {
35
+ type: String,
36
+ // ✅ This field is now required only if the gateway is CASHFREE
37
+ required: function() {
38
+ return this.paymentGateway === 'CASHFREE';
39
+ }
40
+ },
41
+ cfOrderId: {
42
+ type: String,
43
+ // ✅ This field is now required only if the gateway is CASHFREE
44
+ required: function() {
45
+ return this.paymentGateway === 'CASHFREE';
46
+ }
47
+ },
48
+
49
+ amount: {
50
+ type: Number,
51
+ required: true
52
+ },
53
+ currency: {
54
+ type: String,
55
+ default: 'INR'
56
+ },
57
+ status: {
58
+ type: String,
59
+ enum: ['PENDING', 'SUCCESS', 'FAILED', 'REFUNDED'],
60
+ default: 'PENDING'
61
+ },
62
+ paymentMethod: String,
63
+ transactionTime: Date,
64
+ sellerPayments: [{
65
+ sellerId: {
66
+ type: mongoose.Schema.Types.ObjectId,
67
+ ref: 'users',
68
+ required: true
69
+ },
70
+ amount: Number,
71
+ settlementStatus: {
72
+ type: String,
73
+ enum: ['PENDING', 'SETTLED','FAILED'],
74
+ default: 'PENDING'
75
+ }
76
+ }]
77
+ }, {
78
+ timestamps: true
79
+ });
80
+
81
+ // Create indexes for better performance
82
+ paymentSchema.index({ razorpayOrderId: 1 });
83
+ paymentSchema.index({ cfOrderId: 1 });
84
+ paymentSchema.index({ orderId: 1 });
85
+
86
+ // ❌ The pre-save middleware is no longer needed and should be removed.
87
+
88
+ const OrderPayment =
89
+ mongoose.models.OrderPayment || mongoose.model('orderPayment', paymentSchema);
90
+
91
+ export default OrderPayment;
@@ -1,3 +1,7 @@
1
+
2
+
3
+
4
+
1
5
  // backend/models/ProductListing.js (or similar path)
2
6
  import mongoose from "mongoose";
3
7
  const { Schema } = mongoose;
@@ -8,6 +12,20 @@ const ProductListingSchema = new Schema(
8
12
  stockId: { type: Schema.Types.ObjectId, ref: "stocks" },
9
13
  title: String,
10
14
  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
+ },
24
+ sku: {
25
+ type: String,
26
+ required: true,
27
+ index: true
28
+ },
11
29
  images: [
12
30
  {
13
31
  key: { type: String, maxLength: 255, default: null },
@@ -36,7 +54,22 @@ const ProductListingSchema = new Schema(
36
54
  min: 0,
37
55
  default: null,
38
56
  },
39
-
57
+ logisticsType: {
58
+ type: String,
59
+ enum: ["flykupLogistics", "selfShipment"],
60
+ default: null,
61
+ },
62
+ deliveryCharge: {
63
+ type: Number,
64
+ min: 0,
65
+ default: null,
66
+ },
67
+ estimatedDeliveryDate: {
68
+ type: Number, // Change from Date to Number
69
+ min: 0,
70
+ default: null,
71
+ },
72
+
40
73
  // --- ADDED/UPDATED FIELDS FROM FRONTEND ---
41
74
  brand: { type: String, default: null }, // ADDED
42
75
  manufacturer: String,
@@ -123,10 +156,187 @@ totalReviews: { type: Number, default: 0 }
123
156
  },
124
157
  { timestamps: true }
125
158
  );
159
+ ProductListingSchema.index({ title: 'text', description: 'text', category: 'text' });
126
160
 
127
- // Optional: Ensure strict mode is not preventing fields if you intended flexibility (default is true)
128
- // ProductListingSchema.set('strict', false); // Use with caution
129
161
 
130
162
  // Safe export to prevent OverwriteModelError
131
163
  const ProductListing = mongoose.models.productlistings || mongoose.model("productlistings", ProductListingSchema);
132
164
  export default ProductListing;
165
+
166
+
167
+
168
+
169
+
170
+
171
+
172
+
173
+
174
+
175
+
176
+ // // backend/models/ProductListing.js (or similar path)
177
+ // import mongoose from "mongoose";
178
+ // const { Schema } = mongoose;
179
+
180
+ // const ProductListingSchema = new Schema(
181
+ // {
182
+ // sellerId: { type: Schema.Types.ObjectId, ref: "sellers" },
183
+ // stockId: { type: Schema.Types.ObjectId, ref: "stocks" },
184
+ // title: String,
185
+ // description: String,
186
+ // flashSale: {
187
+ // isActive: { type: Boolean, default: false },
188
+ // flashSaleId: { type: mongoose.Schema.Types.ObjectId, ref: 'FlashSale' },
189
+ // flashPrice: { type: Number, default: 0 },
190
+ // flashStock: { type: Number, default: 0 },
191
+ // originalPrice: { type: Number, default: 0 },
192
+ // endsAt: { type: Date, default: null },
193
+ // startsAt: { type: Date, default: null }
194
+ // },
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
+ // sku: {
209
+ // type: String,
210
+ // required: true,
211
+ // match: [/^[A-Za-z0-9-]{6,}$/, 'SKU must be at least 6 alphanumeric characters']
212
+ // },
213
+ // // ----------end of new fields added
214
+ // images: [
215
+ // {
216
+ // key: { type: String, maxLength: 255, default: null },
217
+ // }
218
+ // ],
219
+ // category: String,
220
+ // subcategory: String,
221
+ // hsnNo: String,
222
+ // MRP: {
223
+ // type: Number,
224
+ // min: 0,
225
+ // default: null,
226
+ // },
227
+ // productPrice: {
228
+ // type: Number,
229
+ // min: 0,
230
+ // default: null,
231
+ // },
232
+ // startingPrice: {
233
+ // type: Number,
234
+ // min: 0,
235
+ // default: null,
236
+ // },
237
+ // reservedPrice: {
238
+ // type: Number,
239
+ // min: 0,
240
+ // default: null,
241
+ // },
242
+
243
+ // // --- ADDED/UPDATED FIELDS FROM FRONTEND ---
244
+ // brand: { type: String, default: null }, // ADDED
245
+ // manufacturer: String,
246
+ // manufacturerAddress: String, // ADDED in frontend, already exists here
247
+ // countryOfOrigin: String,
248
+ // netQuantity: { type: String, default: null }, // ADDED (String to accommodate units like '500g')
249
+ // packagingType: { type: String, default: null }, // ADDED
250
+ // weight: { // For shipping calculations
251
+ // value: { type: Number, default: null },
252
+ // unit: { type: String, default: null },
253
+ // },
254
+ // dimensions: { // For shipping calculations
255
+ // length: { type: Number, default: null },
256
+ // width: { type: Number, default: null },
257
+ // height: { type: Number, default: null },
258
+ // },
259
+ // expiryDate: { type: Date, default: null }, // ADDED in frontend, already exists here (changed to allow null)
260
+ // shelfLife: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
261
+ // batchNumber: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
262
+ // gstRate: { type: Number, default: null }, // Changed to allow null if needed
263
+ // sellerName: String,
264
+ // sellerContact: { type: String, default: null }, // ADDED
265
+ // sellerGSTIN: { type: String, default: null }, // ADDED
266
+ // returnPolicy: [String],
267
+ // warranty: {
268
+ // hasWarranty: { type: Boolean, default: false }, // Default added
269
+ // duration: { type: String, default: null }, // Default added
270
+ // },
271
+ // fssaiLicenseNo: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
272
+ // bisCertification: { type: String, default: null }, // ADDED in frontend, already exists here (changed to allow null)
273
+ // importerName: { type: String, default: null }, // Default added
274
+ // importerAddress: { type: String, default: null }, // Default added
275
+ // importerGSTIN: { type: String, default: null }, // Default added
276
+ // eWasteCompliance: { type: Boolean, default: false }, // Default added
277
+ // recyclablePackaging: { type: Boolean, default: false }, // Default added
278
+ // hazardousMaterials: { type: String, default: null }, // Default added
279
+ // allowDropshipping: {
280
+ // type: Boolean,
281
+ // default: false,
282
+ // index: true,
283
+ // },
284
+ // commissionRate: {
285
+ // type: Number,
286
+ // min: [0, 'Commission rate cannot be negative.'],
287
+ // // max: [100, 'Commission rate cannot exceed 100%.'], // Max was 25, changed to 100 based on frontend
288
+ // max: [100, 'Commission rate cannot exceed 100%.'],
289
+ // default: null,
290
+ // // Removed Mongoose-level required validation dependent on allowDropshipping
291
+ // // Let application logic handle this if needed, or adjust validator
292
+ // // required: [
293
+ // // function () { return this.allowDropshipping === true; },
294
+ // // 'Commission rate is required when allowing dropshipping.'
295
+ // // ],
296
+ // // validate: { ... } // Keep or remove validation as needed
297
+ // },
298
+ // hasReturn: {
299
+ // type: Boolean,
300
+ // default: false
301
+ // },
302
+ // returnDays: {
303
+ // type: Number,
304
+ // min: 0,
305
+ // default: null
306
+ // },
307
+ // size: {
308
+ // type: String,
309
+ // default: null
310
+ // },
311
+ // isActive: {
312
+ // type: Boolean,
313
+ // default: true,
314
+ // },ratingSummary: {
315
+ // averageRating: { type: Number, default: 0 },
316
+ // totalRatings: { type: Number, default: 0 },
317
+ // ratingDistribution: {
318
+ // 1: { type: Number, default: 0 },
319
+ // 2: { type: Number, default: 0 },
320
+ // 3: { type: Number, default: 0 },
321
+ // 4: { type: Number, default: 0 },
322
+ // 5: { type: Number, default: 0 }
323
+ // }
324
+ // },
325
+ // totalReviews: { type: Number, default: 0 }
326
+ // },
327
+
328
+
329
+
330
+ // { timestamps: true }
331
+ // );
332
+ // ProductListingSchema.index({ title: 'text', description: 'text', category: 'text' });
333
+ // ProductListingSchema.index({ sellerId: 1, sku: 1 }, { unique: true });
334
+
335
+ // // Safe export to prevent OverwriteModelError
336
+ // const ProductListing = mongoose.models.productlistings || mongoose.model("productlistings", ProductListingSchema);
337
+ // export default ProductListing;
338
+
339
+
340
+
341
+
342
+
@@ -113,6 +113,8 @@ const SellerSchema = new mongoose.Schema(
113
113
  fssaiCertificateFileName: {
114
114
  type: String
115
115
  },
116
+ bisCertificateFileName: { type: String, default: null }, // New BIS certificate
117
+ qualityCertificateFileName: { type: String, default: null }, // New Quality certificate
116
118
  productCatalog: {
117
119
  link: { type: String },
118
120
  file: { type: String }, // for old sellers
@@ -289,7 +291,8 @@ const SellerSchema = new mongoose.Schema(
289
291
  start: { type: String, default: '09:00' },
290
292
  end: { type: String, default: '18:00' }
291
293
  }
292
- }
294
+ },
295
+
293
296
  },
294
297
  { timestamps: true, strict: true }
295
298
  );
@@ -308,5 +311,6 @@ SellerSchema.index({
308
311
  },
309
312
  name: "seller_text_index"
310
313
  });
314
+
311
315
  const Seller = mongoose.models.sellers || mongoose.model("sellers", SellerSchema);
312
316
  export default Seller;
@@ -37,8 +37,8 @@ const ShoppableVideoSchema = new Schema(
37
37
  required: false,
38
38
  trim: true,
39
39
  },
40
- category: { type: String, required: true, trim: true },
41
- subcategory: { type: String, required: true, trim: true },
40
+ category: { type: String, required: false, trim: false},
41
+ subcategory: { type: String, required: false, trim: false },
42
42
  // thumbnailURL might be set initially or updated by the processing service
43
43
  isThumbnailEnabled: {
44
44
  type: Boolean,
@@ -48,7 +48,7 @@ const ShoppableVideoSchema = new Schema(
48
48
  type: String,
49
49
  default: null
50
50
  },
51
- isProductsAvailable : { type : Boolean, required : true, default : true },
51
+ isProductsAvailable : { type : Boolean, required : true, default : false },
52
52
  productsListed: {
53
53
  type: [
54
54
  {
@@ -167,11 +167,31 @@ const ShoppableVideoSchema = new Schema(
167
167
  type: Number,
168
168
  default: 0
169
169
  },
170
- isEligibleToPlay : {
171
- type: Boolean,
172
- default: false, // Default to true, can be set to false if video is not eligible for playback
173
- index: true // Index for quick lookups
174
- }
170
+ // Admin blocking fields
171
+ isBlocked: {
172
+ type: Boolean,
173
+ default: false,
174
+ index: true // For efficient queries of blocked videos
175
+ },
176
+ blockedBy: {
177
+ type: Schema.Types.ObjectId,
178
+ ref: 'Admin',
179
+ default: null
180
+ },
181
+ blockReason: {
182
+ type: String,
183
+ default: null,
184
+ trim: true
185
+ },
186
+ blockedAt: {
187
+ type: Date,
188
+ default: null
189
+ },
190
+ isEligibleToPlay: {
191
+ type: Boolean,
192
+ default: false, // Default to true, can be set to false if video is not eligible for playback
193
+ index: true // Index for quick lookups
194
+ }
175
195
  },
176
196
  { timestamps: true }
177
197
  );
@@ -1,99 +1,6 @@
1
1
  import mongoose from "mongoose";
2
2
  const { Schema } = mongoose;
3
3
 
4
-
5
- // Comment Schema
6
- const commentSchema = new Schema({
7
- user: {
8
- type: mongoose.Schema.Types.ObjectId,
9
- ref: "users", // Reference to the User model
10
- },
11
- text: {
12
- type: String,
13
- },
14
- timeStamp: {
15
- type: Date,
16
- default: Date.now,
17
- },
18
- createdAt: {
19
- type: Date,
20
- default: Date.now,
21
- },
22
- });
23
-
24
- const bidSchema = new mongoose.Schema({
25
- user: {
26
- type: mongoose.Schema.Types.ObjectId,
27
- ref: "users", // Reference to the User model
28
- required: true,
29
- },
30
- amount: {
31
- type: Number,
32
- required: true,
33
- },
34
- createdAt: {
35
- type: Date,
36
- default: Date.now,
37
- },
38
- });
39
-
40
- // Auction Schema
41
- const auctionSchema = new mongoose.Schema(
42
- {
43
- streamId: {
44
- type: String,
45
- required: true,
46
- },
47
- product: {
48
- type: String,
49
- },
50
- auctionType: {
51
- type: String, // 'default' or other types
52
- },
53
- startingBid: {
54
- type: Number,
55
- },
56
- increment: {
57
- type: Number,
58
- default: 500,
59
- },
60
- currentHighestBid: {
61
- type: Number,
62
- default: 0,
63
- },
64
- nextBid1: {
65
- type: Number,
66
- default: 0,
67
- },
68
- nextBid2: {
69
- type: Number,
70
- default: 0,
71
- },
72
- highestBidder: {
73
- type: mongoose.Schema.Types.ObjectId,
74
- ref: "users", // Store reference to the highest bidder
75
- default: null,
76
- },
77
- bidderWon: {
78
- type: mongoose.Schema.Types.ObjectId,
79
- ref: "users", // Store reference to the highest bidder
80
- default: null,
81
- },
82
- bids: [bidSchema], // Array of bids
83
- endsAt: {
84
- type: Date,
85
- },
86
- isActive: {
87
- type: Boolean,
88
- default: true,
89
- },
90
- uniqueStreamId: {
91
- type: String,
92
- },
93
- },
94
- { timestamps: true }
95
- );
96
-
97
4
  const giveawayProductSchema = new Schema({
98
5
  _id: false,
99
6
  productId: { type: Schema.Types.ObjectId, ref: "productlistings", required: true },
@@ -119,22 +26,22 @@ const giveawayProductSchema = new Schema({
119
26
  // Show Schema
120
27
  const showSchema = new Schema(
121
28
  {
122
- // === MODIFIED START: Host Information ===
123
- sellerId: { // <--- REMOVE or comment out this line
124
- type: mongoose.Schema.Types.ObjectId,
125
- ref: "sellers",
126
- },
127
- host: { // New field for the host (Seller or Dropshipper)
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)
128
36
  type: mongoose.Schema.Types.ObjectId,
129
37
  required: true,
130
38
  refPath: 'hostModel' // Dynamic reference
131
39
  },
132
- hostModel: { // New field to define the type of host
40
+ hostModel: { // Type of host
133
41
  type: String,
134
42
  required: true,
135
43
  enum: ['sellers', 'dropshippers'] // Allowed host types
136
44
  },
137
- // === MODIFIED END: Host Information ===
138
45
 
139
46
  title: {
140
47
  type: String,
@@ -191,7 +98,6 @@ const showSchema = new Schema(
191
98
  enum: ['created', 'live', 'cancelled', 'ended'],
192
99
  default: 'created'
193
100
  },
194
- comments: [commentSchema], // Array of comments
195
101
  likes: {
196
102
  type: Number,
197
103
  default: 0,
@@ -201,14 +107,12 @@ const showSchema = new Schema(
201
107
  ref: 'users',
202
108
  default: [],
203
109
  },
204
- // auctions: [auctionSchema], // Array of auctions
205
- currentAuction: auctionSchema,
110
+
206
111
  buyNowProducts: {
207
112
  type: [
208
113
  {
209
114
  _id: false,
210
115
  productId: { type: Schema.Types.ObjectId, ref: "productlistings" },
211
- // --- ADDED productOwnerSellerId ---
212
116
  productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
213
117
  productPrice: { type: Number, min: 0, default: null }, // Price set by host for this show
214
118
  },
@@ -220,64 +124,10 @@ const showSchema = new Schema(
220
124
  {
221
125
  _id: false,
222
126
  productId: { type: Schema.Types.ObjectId, ref: "productlistings" },
223
- // --- ADDED productOwnerSellerId ---
224
127
  productOwnerSellerId: { type: Schema.Types.ObjectId, ref: 'sellers', required: true },
225
128
  startingPrice: { type: Number, min: 0, default: null },
226
129
  reservedPrice: { type: Number, min: 0, default: null },
227
- isAuctionEnded: {
228
- type: Boolean,
229
- default: false
230
- },
231
- streamId: {
232
- type: String,
233
- },
234
- // product: {
235
- // type: String,
236
- // },
237
- auctionType: {
238
- type: String, // 'default' or other types
239
- },
240
- startingBid: {
241
- type: Number,
242
- },
243
- increment: {
244
- type: Number,
245
- default: 5,
246
- },
247
- currentHighestBid: {
248
- type: Number,
249
- default: 0,
250
- },
251
- nextBid1: {
252
- type: Number,
253
- default: 0,
254
- },
255
- nextBid2: {
256
- type: Number,
257
- default: 0,
258
- },
259
- highestBidder: {
260
- type: mongoose.Schema.Types.ObjectId,
261
- ref: "users", // Store reference to the highest bidder
262
- default: null,
263
- },
264
- bidderWon: {
265
- type: mongoose.Schema.Types.ObjectId,
266
- ref: "users", // Store reference to the highest bidder
267
- default: null,
268
- },
269
- bids: [bidSchema], // Array of bids
270
- endsAt: {
271
- type: Date,
272
- },
273
- isActive: {
274
- type: Boolean,
275
- default: true,
276
- },
277
- uniqueStreamId: {
278
- type: String,
279
- },
280
- auctionNumber: { // <-- New field in auctionProducts sub-schema
130
+ auctionNumber: {
281
131
  type: Number,
282
132
  }
283
133
  },
@@ -291,16 +141,14 @@ const showSchema = new Schema(
291
141
  },
292
142
 
293
143
  enabledProductTypes: {
294
- buyNow: { type: Boolean, default: false },
295
- auction: { type: Boolean, default: false },
296
- giveaway: { type: Boolean, default: false }
297
- }
298
- ,
144
+ buyNow: { type: Boolean, default: false },
145
+ auction: { type: Boolean, default: false },
146
+ giveaway: { type: Boolean, default: false }
147
+ },
299
148
  notes: {
300
149
  type: String,
301
150
  default: ''
302
151
  },
303
- // giveaways: [giveawaySchema], // Array of giveaways
304
152
  },
305
153
  { timestamps: true }
306
154
  );
@@ -1,126 +1,85 @@
1
+
2
+ // models/Stock.js
1
3
  import mongoose from "mongoose";
2
- const { Schema, model } = mongoose;
4
+ const { Schema } = mongoose;
5
+
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
+
3
15
 
4
16
  const StockSchema = new Schema(
5
- {
6
- sellerId: {
7
- type: Schema.Types.ObjectId,
8
- ref: "sellers",
9
- },
10
- productListingId: {
11
- type: Schema.Types.ObjectId,
12
- ref: "productlistings",
13
- },
14
- title: String,
15
- quantity: {
16
- type: Number,
17
- min: 0,
18
- default: null,
19
- },
20
- images: [
21
- {
22
- key: { type: String, maxLength: 255, default: null },
23
- blobName: { type: String, maxLength: 255, default: null },
24
- azureUrl: { type: String, maxLength: 1024, default: null },
25
- },
26
- ],
27
- mfgDate: {
28
- type: String,
29
- default: null,
30
- },
31
- expDate: {
32
- type: String,
33
- default: null,
34
- },
17
+ {
18
+ sellerId: {
19
+ type: Schema.Types.ObjectId,
20
+ ref: "sellers",
35
21
  },
36
- { timestamps: true }
22
+ productListingId: {
23
+ type: Schema.Types.ObjectId,
24
+ ref: "productlistings",
25
+ },
26
+ title: String,
27
+ images: [{
28
+ key: String,
29
+ url: String
30
+ }],
31
+ quantity: {
32
+ type: Number,
33
+ min: 0,
34
+ default: 0,
35
+ },
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: {
57
+ type: Number,
58
+ min: 0,
59
+ default: 0
60
+ }
61
+ },
62
+ { timestamps: true }
37
63
  );
38
64
 
39
- const Stock = mongoose.models.stocks || mongoose.model("stocks", StockSchema);
40
- export default Stock;
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
+ });
41
74
 
75
+ // Virtual for available quantity
76
+ StockSchema.virtual('availableQuantity').get(function() {
77
+ return Math.max(0, this.quantity - this.totalReserved);
78
+ });
42
79
 
43
- // models/Stock.js
44
- // // models/Stock.js
45
- // import mongoose from "mongoose";
46
- // const { Schema, model } = mongoose;
47
-
48
- // const StockSchema = new Schema(
49
- // {
50
- // sellerId: {
51
- // type: Schema.Types.ObjectId,
52
- // ref: "sellers",
53
- // },
54
- // productListingId: {
55
- // type: Schema.Types.ObjectId,
56
- // ref: "productlistings",
57
- // },
58
- // title: String,
59
- // quantity: {
60
- // type: Number,
61
- // min: 0,
62
- // default: 0,
63
- // },
64
- // // Track reservations for current and upcoming flash sales
65
- // flashSaleReservations: [{
66
- // flashSaleId: {
67
- // type: Schema.Types.ObjectId,
68
- // ref: "FlashSale",
69
- // required: true
70
- // },
71
- // productId: {
72
- // type: Schema.Types.ObjectId,
73
- // ref: "productlistings",
74
- // required: true
75
- // },
76
- // quantity: {
77
- // type: Number,
78
- // min: 0,
79
- // default: 0
80
- // },
81
- // status: {
82
- // type: String,
83
- // enum: ['reserved', 'active', 'released', 'sold', 'partially_sold'],
84
- // default: 'reserved'
85
- // },
86
- // reservedAt: {
87
- // type: Date,
88
- // default: Date.now
89
- // },
90
- // releasedAt: Date,
91
- // soldQuantity: {
92
- // type: Number,
93
- // default: 0
94
- // }
95
- // }],
96
- // // Total reserved quantity (calculated field)
97
- // totalReserved: {
98
- // type: Number,
99
- // min: 0,
100
- // default: 0
101
- // }
102
- // },
103
- // { timestamps: true }
104
- // );
105
-
106
- // // Update totalReserved when flashSaleReservations change
107
- // StockSchema.pre('save', function(next) {
108
- // if (this.isModified('flashSaleReservations')) {
109
- // this.totalReserved = this.flashSaleReservations.reduce((total, reservation) => {
110
- // return total + (reservation.status === 'reserved' || reservation.status === 'active' ? reservation.quantity : 0);
111
- // }, 0);
112
- // }
113
- // next();
114
- // });
80
+ // Ensure virtuals are included in JSON output
81
+ StockSchema.set('toJSON', { virtuals: true });
82
+ StockSchema.set('toObject', { virtuals: true });
115
83
 
116
- // // Virtual for available quantity (total - reserved)
117
- // StockSchema.virtual('availableQuantity').get(function() {
118
- // return Math.max(0, this.quantity - this.totalReserved);
119
- // });
120
-
121
- // // Ensure virtuals are included in toJSON output
122
- // StockSchema.set('toJSON', { virtuals: true });
123
- // StockSchema.set('toObject', { virtuals: true });
124
-
125
- // const Stock = mongoose.models.stocks || mongoose.model("stocks", StockSchema);
126
- // export default Stock;
84
+ const Stock = mongoose.models.stocks || mongoose.model("stocks", StockSchema);
85
+ export default Stock;
@@ -93,7 +93,6 @@ const UserSchema = new mongoose.Schema(
93
93
  },
94
94
  ],
95
95
  filledNewSellerForm: { type: Boolean, default: false },
96
-
97
96
  // --- Verification Flow Fields ---
98
97
  verificationFlowStatus: {
99
98
  type: String,
@@ -181,7 +180,6 @@ UserSchema.index({
181
180
  name: "user_text_index"
182
181
  });
183
182
 
184
-
185
183
  UserSchema.methods.comparePassword = async function (loginPassword) {
186
184
  if (!this.password) return false;
187
185
  return bcrypt.compare(loginPassword, this.password);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flykup_model_production",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "main": "index.js",
5
5
  "type": "module",
6
6
  "private": false,