first commit
This commit is contained in:
434
prisma/schema.prisma
Normal file
434
prisma/schema.prisma
Normal file
@@ -0,0 +1,434 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String? @db.Text
|
||||
access_token String? @db.Text
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String? @db.Text
|
||||
session_state String?
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(cuid())
|
||||
sessionToken String @unique
|
||||
userId String
|
||||
expires DateTime
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
password String?
|
||||
role Role @default(CUSTOMER)
|
||||
referralCode String @unique @default(cuid())
|
||||
referrerId String?
|
||||
phone String?
|
||||
address String?
|
||||
joinedAt DateTime @default(now())
|
||||
isActive Boolean @default(true)
|
||||
currentRankId String?
|
||||
|
||||
// Partner-specific fields
|
||||
partnerTier String? // 'Diamond', 'Gold', 'Silver'
|
||||
minReferrals Int @default(3) // Minimum members a partner needs to add
|
||||
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
|
||||
// Referral relationships
|
||||
referrer User? @relation("UserReferrals", fields: [referrerId], references: [id])
|
||||
referrals User[] @relation("UserReferrals")
|
||||
|
||||
// Orders and transactions
|
||||
orders Order[]
|
||||
commissions Commission[] @relation("UserCommissions")
|
||||
commissionsFrom Commission[] @relation("UserCommissionsFrom")
|
||||
payouts Payout[]
|
||||
wallet Wallet?
|
||||
|
||||
// Address management
|
||||
addresses Address[]
|
||||
|
||||
// Rank system
|
||||
currentRank Rank? @relation(fields: [currentRankId], references: [id])
|
||||
rankAchievements RankAchievement[]
|
||||
|
||||
// Form responses
|
||||
formResponses FormResponse[]
|
||||
|
||||
// Reviews and feedback
|
||||
reviews Review[]
|
||||
reviewHelpfulVotes ReviewHelpfulVote[]
|
||||
reviewReports ReviewReport[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model VerificationToken {
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
|
||||
@@unique([identifier, token])
|
||||
}
|
||||
|
||||
model Category {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
description String?
|
||||
image String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
products Product[]
|
||||
|
||||
@@index([isActive])
|
||||
@@index([name])
|
||||
@@map("categories")
|
||||
}
|
||||
|
||||
model Product {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
description String?
|
||||
price Float
|
||||
discount Float @default(0)
|
||||
images String[]
|
||||
stock Int @default(0)
|
||||
manageStock Boolean @default(true)
|
||||
sku String @unique
|
||||
slug String @unique
|
||||
isActive Boolean @default(true)
|
||||
categoryId String
|
||||
brand String?
|
||||
origin String?
|
||||
weight String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
category Category @relation(fields: [categoryId], references: [id])
|
||||
orderItems OrderItem[]
|
||||
reviews Review[]
|
||||
|
||||
@@index([isActive])
|
||||
@@index([categoryId])
|
||||
@@index([createdAt])
|
||||
@@index([isActive, stock])
|
||||
@@index([categoryId, isActive])
|
||||
@@index([createdAt, isActive])
|
||||
@@index([isActive, createdAt(sort: Desc)])
|
||||
@@index([isActive, createdAt(sort: Desc), categoryId])
|
||||
@@map("products")
|
||||
}
|
||||
|
||||
model Order {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
total Float
|
||||
status OrderStatus @default(PENDING)
|
||||
razorpayOrderId String?
|
||||
razorpayPaymentId String?
|
||||
shippingAddressId String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
orderItems OrderItem[]
|
||||
shippingAddress Address? @relation(fields: [shippingAddressId], references: [id])
|
||||
|
||||
@@map("orders")
|
||||
}
|
||||
|
||||
model OrderItem {
|
||||
id String @id @default(cuid())
|
||||
orderId String
|
||||
productId String
|
||||
quantity Int
|
||||
price Float
|
||||
|
||||
order Order @relation(fields: [orderId], references: [id])
|
||||
product Product @relation(fields: [productId], references: [id])
|
||||
|
||||
@@map("order_items")
|
||||
}
|
||||
|
||||
model Commission {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
fromUserId String
|
||||
orderId String
|
||||
amount Float
|
||||
level Int
|
||||
type CommissionType @default(REFERRAL)
|
||||
status CommissionStatus @default(PENDING)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation("UserCommissions", fields: [userId], references: [id])
|
||||
fromUser User @relation("UserCommissionsFrom", fields: [fromUserId], references: [id])
|
||||
|
||||
@@map("commissions")
|
||||
}
|
||||
|
||||
model Wallet {
|
||||
id String @id @default(cuid())
|
||||
userId String @unique
|
||||
balance Float @default(0)
|
||||
totalEarnings Float @default(0)
|
||||
totalWithdrawn Float @default(0)
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@map("wallets")
|
||||
}
|
||||
|
||||
model Payout {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
amount Float
|
||||
status PayoutStatus @default(PENDING)
|
||||
bankDetails String?
|
||||
adminNotes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@map("payouts")
|
||||
}
|
||||
|
||||
model CommissionSettings {
|
||||
id String @id @default(cuid())
|
||||
level Int @unique
|
||||
percentage Float
|
||||
isActive Boolean @default(true)
|
||||
|
||||
@@map("commission_settings")
|
||||
}
|
||||
|
||||
model Address {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
firstName String
|
||||
lastName String
|
||||
company String?
|
||||
address1 String
|
||||
address2 String?
|
||||
city String
|
||||
state String
|
||||
zipCode String
|
||||
country String @default("India")
|
||||
phone String?
|
||||
isDefault Boolean @default(false)
|
||||
type AddressType @default(HOME)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
orders Order[]
|
||||
|
||||
@@map("addresses")
|
||||
}
|
||||
|
||||
model SystemSettings {
|
||||
id String @id @default(cuid())
|
||||
siteName String @default("Padmaaja Rasooi")
|
||||
siteDescription String @default("Premium quality rice products and grains. Experience the finest rice sourced directly from local farmers.")
|
||||
supportEmail String @default("info@padmajarice.com")
|
||||
minimumPayout Float @default(1000)
|
||||
enableReferrals Boolean @default(true)
|
||||
enableCommissions Boolean @default(true)
|
||||
maintenanceMode Boolean @default(false)
|
||||
allowRegistration Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("system_settings")
|
||||
}
|
||||
|
||||
model Rank {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
description String?
|
||||
minReferrals Int @default(0)
|
||||
minSalesVolume Float @default(0)
|
||||
minTeamVolume Float @default(0)
|
||||
commissionMultiplier Float @default(1.0)
|
||||
benefits String[]
|
||||
color String @default("#3B82F6")
|
||||
icon String @default("🏆")
|
||||
order Int @unique
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
users User[]
|
||||
achievements RankAchievement[]
|
||||
|
||||
@@map("ranks")
|
||||
}
|
||||
|
||||
model RankAchievement {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
rankId String
|
||||
achievedAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
rank Rank @relation(fields: [rankId], references: [id])
|
||||
|
||||
@@unique([userId, rankId])
|
||||
@@map("rank_achievements")
|
||||
}
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
MEMBER // For Partners
|
||||
WHOLESALER // For Wholesale customers
|
||||
PART_TIME // For those who want part-time job opportunities
|
||||
CUSTOMER // Regular customers
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
PENDING
|
||||
PAID
|
||||
SHIPPED
|
||||
DELIVERED
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
enum CommissionType {
|
||||
REFERRAL
|
||||
LEVEL
|
||||
BONUS
|
||||
}
|
||||
|
||||
enum CommissionStatus {
|
||||
PENDING
|
||||
APPROVED
|
||||
PAID
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
enum PayoutStatus {
|
||||
PENDING
|
||||
APPROVED
|
||||
REJECTED
|
||||
PAID
|
||||
}
|
||||
|
||||
enum AddressType {
|
||||
HOME
|
||||
WORK
|
||||
OTHER
|
||||
}
|
||||
|
||||
model FormResponse {
|
||||
id String @id @default(cuid())
|
||||
formId String // e.g., "contact", "partnership", "bulk_inquiry"
|
||||
data Json @db.JsonB // Actual form submission data
|
||||
status String @default("new")
|
||||
metadata Json? @db.JsonB // Additional metadata like IP, user agent
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
userId String? // Optional relation to user if logged in
|
||||
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([status])
|
||||
@@index([userId])
|
||||
@@index([formId])
|
||||
@@map("form_responses")
|
||||
}
|
||||
|
||||
model Review {
|
||||
id String @id @default(cuid())
|
||||
productId String
|
||||
userId String
|
||||
rating Int @default(5) // 1-5 stars
|
||||
title String?
|
||||
comment String?
|
||||
images String[] @default([])
|
||||
isVerified Boolean @default(false) // Verified purchase
|
||||
isApproved Boolean @default(false) // Admin approval
|
||||
helpfulVotes Int @default(0)
|
||||
reportCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Relations for helpful votes and reports
|
||||
helpfulVotedBy ReviewHelpfulVote[]
|
||||
reportedBy ReviewReport[]
|
||||
|
||||
@@unique([productId, userId]) // One review per user per product
|
||||
@@index([productId])
|
||||
@@index([userId])
|
||||
@@index([rating])
|
||||
@@index([isApproved])
|
||||
@@index([createdAt])
|
||||
@@index([productId, isApproved])
|
||||
@@index([createdAt, isApproved])
|
||||
@@index([isApproved, createdAt(sort: Desc)])
|
||||
@@index([isApproved, createdAt(sort: Desc), productId])
|
||||
@@map("reviews")
|
||||
}
|
||||
|
||||
model ReviewHelpfulVote {
|
||||
id String @id @default(cuid())
|
||||
reviewId String
|
||||
userId String
|
||||
|
||||
review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([reviewId, userId])
|
||||
@@map("review_helpful_votes")
|
||||
}
|
||||
|
||||
model ReviewReport {
|
||||
id String @id @default(cuid())
|
||||
reviewId String
|
||||
userId String
|
||||
reason ReportReason
|
||||
comment String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([reviewId, userId])
|
||||
@@map("review_reports")
|
||||
}
|
||||
|
||||
enum ReportReason {
|
||||
SPAM
|
||||
INAPPROPRIATE
|
||||
FAKE
|
||||
OFFENSIVE
|
||||
OTHER
|
||||
}
|
||||
410
prisma/seed-padmaaja.ts
Normal file
410
prisma/seed-padmaaja.ts
Normal file
@@ -0,0 +1,410 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
async function seedPadmaajaRasooi() {
|
||||
console.log('🌾 Seeding Padmaaja Rasooi database...')
|
||||
|
||||
// Create Categories for Food Products
|
||||
const flourCategory = await prisma.category.upsert({
|
||||
where: { name: 'Flour & Grains' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Flour & Grains',
|
||||
description: 'Premium quality flours and grain products for healthy cooking',
|
||||
image: '/images/categories/flour.jpg',
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
const riceCategory = await prisma.category.upsert({
|
||||
where: { name: 'Rice & Cereals' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Rice & Cereals',
|
||||
description: 'Authentic basmati and non-basmati rice varieties',
|
||||
image: '/images/categories/rice.jpg',
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
const spicesCategory = await prisma.category.upsert({
|
||||
where: { name: 'Spices & Seasonings' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Spices & Seasonings',
|
||||
description: 'Traditional spice blends and pure spices',
|
||||
image: '/images/categories/spices.jpg',
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
const pulsesCategory = await prisma.category.upsert({
|
||||
where: { name: 'Pulses & Legumes' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Pulses & Legumes',
|
||||
description: 'Organic dals and pulses rich in protein',
|
||||
image: '/images/categories/pulses.jpg',
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
console.log('📂 Categories created successfully')
|
||||
|
||||
// Create Food Products
|
||||
|
||||
// Flour Products
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-FLOUR-001' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'SHREE AAHAR Multigrain Flour',
|
||||
description: 'Premium multigrain flour made from wheat, jowar, bajra, ragi, and other nutritious grains. Perfect for making healthy rotis, parathas, and other Indian breads. Rich in fiber, protein, and essential nutrients for wholesome family nutrition.',
|
||||
price: 150.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1574323347407-f5e1ad6d020b?w=600&h=400&fit=crop&crop=center',
|
||||
'https://images.unsplash.com/photo-1509440159596-0249088772ff?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 500,
|
||||
sku: 'PD-FLOUR-001',
|
||||
slug: 'shree-aahar-multigrain-flour',
|
||||
isActive: true,
|
||||
categoryId: flourCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-FLOUR-002' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Premium Whole Wheat Flour',
|
||||
description: 'Pure whole wheat flour ground from carefully selected wheat grains. Stone-ground to preserve natural nutrients and fiber. Ideal for daily cooking and baking needs.',
|
||||
price: 80.00,
|
||||
discount: 5,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1594736797933-d0d6483cae4d?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 750,
|
||||
sku: 'PD-FLOUR-002',
|
||||
slug: 'premium-whole-wheat-flour',
|
||||
isActive: true,
|
||||
categoryId: flourCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
// Rice Products - Based on Rate List Rice 1121
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-1121-001' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Premium Basmati Rice 1121 - Extra Long Grain',
|
||||
description: 'Finest quality aged basmati rice 1121 variety with extra-long grains and distinctive aroma. Naturally aged for 12+ months for superior taste and texture. Perfect for biryanis, pulavs, and special occasions.',
|
||||
price: 250.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1586201375761-83865001e31c?w=600&h=400&fit=crop&crop=center',
|
||||
'https://images.unsplash.com/photo-1536304993881-ff6e9eefa2a6?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 300,
|
||||
sku: 'PD-RICE-1121-001',
|
||||
slug: 'premium-basmati-rice-1121-extra-long',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-1121-002' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Basmati Rice 1121 - Steam Processed',
|
||||
description: 'Steam processed basmati rice 1121 with enhanced shelf life and consistent quality. Perfect for daily cooking and commercial use. Maintains the authentic basmati aroma and taste.',
|
||||
price: 220.00,
|
||||
discount: 5,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1586201375761-83865001e31c?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 500,
|
||||
sku: 'PD-RICE-1121-002',
|
||||
slug: 'basmati-rice-1121-steam-processed',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-1121-003' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Basmati Rice 1121 - Sella (Parboiled)',
|
||||
description: 'Parboiled basmati rice 1121 with golden color and enhanced nutritional value. Partially boiled in the husk to retain nutrients. Excellent for biryanis and festive cooking.',
|
||||
price: 240.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1536304993881-ff6e9eefa2a6?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 400,
|
||||
sku: 'PD-RICE-1121-003',
|
||||
slug: 'basmati-rice-1121-sella-parboiled',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-1121-004' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Basmati Rice 1121 - White Sella',
|
||||
description: 'White sella basmati rice 1121 with creamy white appearance and excellent cooking properties. Ideal for premium restaurants and households seeking restaurant-quality rice.',
|
||||
price: 260.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1516684669134-de6f7c473a2a?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 350,
|
||||
sku: 'PD-RICE-1121-004',
|
||||
slug: 'basmati-rice-1121-white-sella',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-1121-005' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Basmati Rice 1121 - Golden Sella',
|
||||
description: 'Golden sella basmati rice 1121 with rich golden color and enhanced taste. Steam processing retains natural nutrients while ensuring longer shelf life.',
|
||||
price: 270.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1586201375761-83865001e31c?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 300,
|
||||
sku: 'PD-RICE-1121-005',
|
||||
slug: 'basmati-rice-1121-golden-sella',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-1121-006' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Basmati Rice 1121 - Broken (25% Broken)',
|
||||
description: 'Premium quality broken basmati rice 1121 (25% broken) ideal for daily consumption at economical rates. Maintains the basmati flavor at affordable pricing.',
|
||||
price: 180.00,
|
||||
discount: 10,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1516684669134-de6f7c473a2a?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 600,
|
||||
sku: 'PD-RICE-1121-006',
|
||||
slug: 'basmati-rice-1121-broken-25-percent',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-NON-BASMATI-001' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Non-Basmati Rice - IR64 Variety',
|
||||
description: 'High-quality IR64 non-basmati rice variety suitable for daily consumption. Good texture, taste, and cooking properties. Ideal for households and commercial use.',
|
||||
price: 85.00,
|
||||
discount: 10,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1516684669134-de6f7c473a2a?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 800,
|
||||
sku: 'PD-RICE-NON-BASMATI-001',
|
||||
slug: 'non-basmati-rice-ir64-variety',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-RICE-NON-BASMATI-002' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Non-Basmati Rice - Swarna Variety',
|
||||
description: 'Premium Swarna variety non-basmati rice with excellent cooking properties and nutritional value. Popular choice for daily meals across Indian households.',
|
||||
price: 90.00,
|
||||
discount: 5,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1516684669134-de6f7c473a2a?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 700,
|
||||
sku: 'PD-RICE-NON-BASMATI-002',
|
||||
slug: 'non-basmati-rice-swarna-variety',
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
// Spice Products
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-SPICE-001' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Traditional Garam Masala',
|
||||
description: 'Authentic garam masala blend prepared using traditional family recipes. Made from carefully selected and ground spices including cardamom, cinnamon, cloves, and black pepper for perfect aroma and taste.',
|
||||
price: 120.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1596040033229-a9821ebd058d?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 200,
|
||||
sku: 'PD-SPICE-001',
|
||||
slug: 'traditional-garam-masala',
|
||||
isActive: true,
|
||||
categoryId: spicesCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-SPICE-002' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Pure Turmeric Powder',
|
||||
description: 'Premium quality turmeric powder made from fresh turmeric roots. Rich in curcumin and natural antioxidants. Essential for Indian cooking and known for its health benefits.',
|
||||
price: 90.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1615485290382-441e4d049cb5?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 350,
|
||||
sku: 'PD-SPICE-002',
|
||||
slug: 'pure-turmeric-powder',
|
||||
isActive: true,
|
||||
categoryId: spicesCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
// Pulses Products
|
||||
await prisma.product.upsert({
|
||||
where: { sku: 'PD-PULSE-001' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Organic Toor Dal',
|
||||
description: 'Premium quality organic toor dal (pigeon peas) sourced directly from certified organic farms. Rich in protein and dietary fiber. Chemical-free and naturally grown without pesticides.',
|
||||
price: 140.00,
|
||||
discount: 0,
|
||||
images: [
|
||||
'https://images.unsplash.com/photo-1559181567-c3190ca9959b?w=600&h=400&fit=crop&crop=center'
|
||||
],
|
||||
stock: 250,
|
||||
sku: 'PD-PULSE-001',
|
||||
slug: 'organic-toor-dal',
|
||||
isActive: true,
|
||||
categoryId: pulsesCategory.id
|
||||
}
|
||||
})
|
||||
|
||||
console.log('🍚 Food products created successfully')
|
||||
|
||||
// Update System Settings for Padmaaja Rasooi
|
||||
await prisma.systemSettings.upsert({
|
||||
where: { id: 'padmaaja-system' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'padmaaja-system',
|
||||
siteName: 'Padmaaja Rasooi',
|
||||
siteDescription: 'Authentic Indian Food Products - Preserving Traditional Flavors with Modern Quality Standards',
|
||||
supportEmail: 'info@padmajarice.com',
|
||||
minimumPayout: 1000,
|
||||
enableReferrals: true,
|
||||
enableCommissions: true,
|
||||
maintenanceMode: false,
|
||||
allowRegistration: true
|
||||
}
|
||||
})
|
||||
|
||||
// Create Marketing Partnership Commission Settings
|
||||
const commissionLevels = [
|
||||
{ level: 1, percentage: 8.0 }, // Direct referral
|
||||
{ level: 2, percentage: 4.0 }, // Second level
|
||||
{ level: 3, percentage: 2.0 }, // Third level
|
||||
{ level: 4, percentage: 1.0 }, // Fourth level
|
||||
{ level: 5, percentage: 0.5 } // Fifth level
|
||||
]
|
||||
|
||||
for (const commission of commissionLevels) {
|
||||
await prisma.commissionSettings.upsert({
|
||||
where: { level: commission.level },
|
||||
update: {},
|
||||
create: {
|
||||
level: commission.level,
|
||||
percentage: commission.percentage,
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Create Marketing Partnership Ranks
|
||||
const partnershipRanks = [
|
||||
{
|
||||
name: 'Silver Partner',
|
||||
description: 'Entry level marketing partnership with basic benefits',
|
||||
minReferrals: 0,
|
||||
minSalesVolume: 5000,
|
||||
minTeamVolume: 15000,
|
||||
commissionMultiplier: 1.0,
|
||||
benefits: ['Standard commission rates', 'Basic marketing materials', 'Email support'],
|
||||
color: '#C0C0C0',
|
||||
icon: '🥈',
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
name: 'Gold Partner',
|
||||
description: 'Intermediate partnership level with enhanced benefits',
|
||||
minReferrals: 5,
|
||||
minSalesVolume: 15000,
|
||||
minTeamVolume: 50000,
|
||||
commissionMultiplier: 1.2,
|
||||
benefits: ['Enhanced commissions', 'Premium marketing materials', 'Priority support', 'Training access'],
|
||||
color: '#FFD700',
|
||||
icon: '🥇',
|
||||
order: 2
|
||||
},
|
||||
{
|
||||
name: 'Diamond Partner',
|
||||
description: 'Premium partnership level with maximum benefits',
|
||||
minReferrals: 15,
|
||||
minSalesVolume: 50000,
|
||||
minTeamVolume: 150000,
|
||||
commissionMultiplier: 1.5,
|
||||
benefits: ['Maximum commissions', 'Exclusive products', 'Dedicated support', 'Leadership bonuses', 'Custom branding'],
|
||||
color: '#B9F2FF',
|
||||
icon: '💎',
|
||||
order: 3
|
||||
}
|
||||
]
|
||||
|
||||
for (const rank of partnershipRanks) {
|
||||
await prisma.rank.upsert({
|
||||
where: { name: rank.name },
|
||||
update: {},
|
||||
create: rank
|
||||
})
|
||||
}
|
||||
|
||||
console.log('🏆 Marketing partnership ranks created successfully')
|
||||
console.log('✅ Padmaaja Rasooi database seeded successfully!')
|
||||
}
|
||||
|
||||
// Run the seed function
|
||||
seedPadmaajaRasooi()
|
||||
.catch((e) => {
|
||||
console.error('❌ Error seeding database:', e)
|
||||
process.exit(1)
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
202
prisma/seed-products.ts
Normal file
202
prisma/seed-products.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
async function seedProducts() {
|
||||
console.log('🌾 Seeding Kashmina products...')
|
||||
|
||||
try {
|
||||
// First, delete all existing products
|
||||
console.log('🗑️ Deleting existing products...')
|
||||
await prisma.orderItem.deleteMany({})
|
||||
await prisma.product.deleteMany({})
|
||||
|
||||
// Ensure rice category exists
|
||||
const riceCategory = await prisma.category.upsert({
|
||||
where: { name: 'Rice & Cereals' },
|
||||
update: {},
|
||||
create: {
|
||||
name: 'Rice & Cereals',
|
||||
description: 'Premium Basmati and specialty rice varieties sourced directly from Haryanai farmers',
|
||||
image: '/images/categories/rice.jpg',
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
console.log('📦 Creating rice products with weight variations...')
|
||||
|
||||
// Product data based on the attached price sheet with proper per-kg calculations
|
||||
const riceProducts = [
|
||||
// KASHMINA STEAM
|
||||
{
|
||||
baseName: 'Kashmina Steam Grade-1',
|
||||
description: 'Superior Grade-1 Kashmina Steam rice with perfect steam processing for enhanced aroma and taste.',
|
||||
marketRatePerKg: 116, // Updated rate
|
||||
companyRatePerKg: 116, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
{
|
||||
baseName: 'Kashmina Steam Dubar',
|
||||
description: 'High-quality Dubar grade Kashmina Steam rice perfect for everyday cooking needs.',
|
||||
marketRatePerKg: 68, // Updated rate
|
||||
companyRatePerKg: 68, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
{
|
||||
baseName: 'Kashmina Steam Tibar',
|
||||
description: 'Premium Tibar grade Kashmina Steam rice with excellent texture and cooking properties.',
|
||||
marketRatePerKg: 78, // Updated rate
|
||||
companyRatePerKg: 78, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
|
||||
// KASHMINA SELLA
|
||||
{
|
||||
baseName: 'Kashmina Sella Grade-1',
|
||||
description: 'Premium Grade-1 Kashmina Sella rice with perfect texture and aroma. Ideal for biryani and special occasions.',
|
||||
marketRatePerKg: 104, // Updated rate
|
||||
companyRatePerKg: 104, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
{
|
||||
baseName: 'Kashmina Sella Tibar',
|
||||
description: 'High-quality Tibar grade Kashmina Sella rice with excellent cooking properties and authentic taste.',
|
||||
marketRatePerKg: 72, // Updated rate
|
||||
companyRatePerKg: 72, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
{
|
||||
baseName: 'Kashmina Sella Dubar',
|
||||
description: 'Premium Dubar grade Kashmina Sella rice perfect for everyday cooking and special meals.',
|
||||
marketRatePerKg: 65, // Updated rate
|
||||
companyRatePerKg: 65, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
|
||||
// KASHMINA GOLDEN
|
||||
{
|
||||
baseName: 'Kashmina Golden Grade-1',
|
||||
description: 'Exquisite Grade-1 Kashmina Golden rice with rich golden color and superior quality. Perfect for special occasions.',
|
||||
marketRatePerKg: 109, // Updated rate
|
||||
companyRatePerKg: 109, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
{
|
||||
baseName: 'Kashmina Golden Tibar',
|
||||
description: 'Premium Tibar grade Kashmina Golden rice with authentic golden hue and exceptional flavor.',
|
||||
marketRatePerKg: 74, // Updated rate
|
||||
companyRatePerKg: 74, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
},
|
||||
{
|
||||
baseName: 'Kashmina Golden Dubar',
|
||||
description: 'High-quality Dubar grade Kashmina Golden rice ideal for daily cooking and family meals.',
|
||||
marketRatePerKg: 66, // Updated rate
|
||||
companyRatePerKg: 66, // Company rate same as market rate
|
||||
origin: 'Haryana, India',
|
||||
brand: 'Kashmina'
|
||||
}
|
||||
]
|
||||
|
||||
// Images for different weight variations
|
||||
const image5kg = 'https://4m5m4tx28rtva30c.public.blob.vercel-storage.com/media/2025-09-07/Kashmina%20Rice%205KG.png-1757220648279'
|
||||
const image30kg = 'https://4m5m4tx28rtva30c.public.blob.vercel-storage.com/media/2025-09-07/Kashmina%20Rice%2030KG.png-1757220559950'
|
||||
|
||||
// Create products with only 5kg and 30kg variations
|
||||
for (const product of riceProducts) {
|
||||
// Calculate prices for different weights
|
||||
const price5kg = product.companyRatePerKg * 5
|
||||
const price30kg = product.companyRatePerKg * 30
|
||||
|
||||
// Create 5kg variant
|
||||
const product5kg = await prisma.product.create({
|
||||
data: {
|
||||
name: `${product.baseName} - 5kg`,
|
||||
description: `${product.description} Available in convenient 5kg packaging for household use.`,
|
||||
price: price5kg,
|
||||
discount: 0, // No discount
|
||||
images: [image5kg],
|
||||
stock: 100,
|
||||
manageStock: false,
|
||||
sku: `${product.baseName.toLowerCase().replace(/[^a-z0-9]/g, '')}-5kg`,
|
||||
slug: `${product.baseName.toLowerCase().replace(/[^a-z0-9]/g, '-')}-5kg`,
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id,
|
||||
brand: product.brand,
|
||||
origin: product.origin,
|
||||
weight: '5kg'
|
||||
}
|
||||
})
|
||||
|
||||
// Create 30kg variant
|
||||
const product30kg = await prisma.product.create({
|
||||
data: {
|
||||
name: `${product.baseName} - 30kg`,
|
||||
description: `${product.description} Available in bulk 30kg packaging for restaurants, hotels, and wholesale buyers.`,
|
||||
price: price30kg,
|
||||
discount: 0, // No discount
|
||||
images: [image30kg],
|
||||
stock: 50,
|
||||
manageStock: false,
|
||||
sku: `${product.baseName.toLowerCase().replace(/[^a-z0-9]/g, '')}-30kg`,
|
||||
slug: `${product.baseName.toLowerCase().replace(/[^a-z0-9]/g, '-')}-30kg`,
|
||||
isActive: true,
|
||||
categoryId: riceCategory.id,
|
||||
brand: product.brand,
|
||||
origin: product.origin,
|
||||
weight: '30kg'
|
||||
}
|
||||
})
|
||||
|
||||
console.log(`✅ Created: ${product5kg.name} (₹${product5kg.price}) - Per kg: ₹${product.companyRatePerKg}`)
|
||||
console.log(`✅ Created: ${product30kg.name} (₹${product30kg.price}) - Per kg: ₹${product.companyRatePerKg}`)
|
||||
}
|
||||
|
||||
const productCount = await prisma.product.count()
|
||||
console.log(`🎉 Successfully created ${productCount} products!`)
|
||||
|
||||
// Display summary
|
||||
console.log('\n📊 Product Summary:')
|
||||
console.log('==================')
|
||||
|
||||
const productsByWeight = await prisma.product.groupBy({
|
||||
by: ['weight'],
|
||||
_count: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
|
||||
for (const group of productsByWeight) {
|
||||
console.log(`${group.weight}: ${group._count.id} products`)
|
||||
}
|
||||
|
||||
console.log('\n✨ Products seeding completed successfully!')
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error seeding products:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await seedProducts()
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
|
||||
export default seedProducts
|
||||
223
prisma/seed.ts
Normal file
223
prisma/seed.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import { faker } from '@faker-js/faker'
|
||||
import { rankSystem } from '@/lib/ranks'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
const categories = [
|
||||
{
|
||||
name: 'Health & Wellness',
|
||||
description: 'Premium health and wellness products for optimal living'
|
||||
},
|
||||
{
|
||||
name: 'Beauty & Skincare',
|
||||
description: 'Natural and organic beauty products for radiant skin'
|
||||
},
|
||||
{
|
||||
name: 'Nutrition & Supplements',
|
||||
description: 'High-quality nutritional supplements and vitamins'
|
||||
},
|
||||
{
|
||||
name: 'Fitness & Sports',
|
||||
description: 'Performance products for active lifestyles'
|
||||
},
|
||||
{
|
||||
name: 'Personal Care',
|
||||
description: 'Daily essentials for personal hygiene and care'
|
||||
},
|
||||
{
|
||||
name: 'Home & Lifestyle',
|
||||
description: 'Premium products for modern living'
|
||||
}
|
||||
]
|
||||
|
||||
const productTemplates = [
|
||||
// Health & Wellness
|
||||
{ namePrefix: 'Organic', nameSuffix: ['Detox Tea', 'Green Tea', 'Herbal Blend', 'Immune Booster'] },
|
||||
{ namePrefix: 'Natural', nameSuffix: ['Energy Drink', 'Wellness Tonic', 'Health Elixir', 'Vitality Boost'] },
|
||||
{ namePrefix: 'Premium', nameSuffix: ['Superfood Powder', 'Antioxidant Complex', 'Immunity Support', 'Daily Greens'] },
|
||||
|
||||
// Beauty & Skincare
|
||||
{ namePrefix: 'Radiant', nameSuffix: ['Face Serum', 'Night Cream', 'Eye Cream', 'Moisturizer'] },
|
||||
{ namePrefix: 'Glow', nameSuffix: ['Facial Cleanser', 'Toner', 'Face Mask', 'Exfoliator'] },
|
||||
{ namePrefix: 'Youth', nameSuffix: ['Anti-Aging Cream', 'Collagen Serum', 'Wrinkle Reducer', 'Firming Lotion'] },
|
||||
|
||||
// Nutrition & Supplements
|
||||
{ namePrefix: 'Power', nameSuffix: ['Protein Powder', 'Multivitamin', 'Omega-3', 'Probiotics'] },
|
||||
{ namePrefix: 'Elite', nameSuffix: ['Pre-Workout', 'BCAA Complex', 'Creatine Formula', 'Recovery Blend'] },
|
||||
{ namePrefix: 'Pure', nameSuffix: ['Vitamin D3', 'Magnesium', 'Zinc Complex', 'B-Complex'] },
|
||||
|
||||
// Fitness & Sports
|
||||
{ namePrefix: 'Athletic', nameSuffix: ['Performance Drink', 'Energy Bar', 'Recovery Shake', 'Endurance Formula'] },
|
||||
{ namePrefix: 'Sport', nameSuffix: ['Electrolyte Mix', 'Protein Bar', 'Hydration Pack', 'Energy Gel'] },
|
||||
|
||||
// Personal Care
|
||||
{ namePrefix: 'Fresh', nameSuffix: ['Body Wash', 'Shampoo', 'Conditioner', 'Deodorant'] },
|
||||
{ namePrefix: 'Pure', nameSuffix: ['Toothpaste', 'Mouthwash', 'Hand Sanitizer', 'Body Lotion'] },
|
||||
|
||||
// Home & Lifestyle
|
||||
{ namePrefix: 'Eco', nameSuffix: ['Cleaning Spray', 'Laundry Detergent', 'Dish Soap', 'Air Freshener'] },
|
||||
{ namePrefix: 'Smart', nameSuffix: ['Essential Oil', 'Diffuser Blend', 'Room Spray', 'Candle'] }
|
||||
]
|
||||
|
||||
const healthDescriptions = [
|
||||
'Boost your immune system naturally with this powerful blend of organic ingredients.',
|
||||
'Experience enhanced vitality and energy with our premium formulation.',
|
||||
'Support your wellness journey with this scientifically-backed supplement.',
|
||||
'Detoxify and rejuvenate your body with natural, plant-based ingredients.',
|
||||
'Maintain optimal health with this carefully crafted nutritional supplement.'
|
||||
]
|
||||
|
||||
const beautyDescriptions = [
|
||||
'Transform your skin with this luxurious, age-defying formula.',
|
||||
'Achieve radiant, youthful-looking skin with natural ingredients.',
|
||||
'Nourish and protect your skin with this premium skincare solution.',
|
||||
'Experience the power of nature in this scientifically-formulated product.',
|
||||
'Reveal your natural beauty with this gentle yet effective treatment.'
|
||||
]
|
||||
|
||||
const fitnessDescriptions = [
|
||||
'Fuel your workouts and achieve peak performance with this advanced formula.',
|
||||
'Support muscle recovery and growth with premium quality ingredients.',
|
||||
'Enhance your athletic performance and endurance naturally.',
|
||||
'Optimize your fitness journey with this scientifically-designed supplement.',
|
||||
'Power through your workouts with sustained energy and focus.'
|
||||
]
|
||||
|
||||
const getRandomDescription = (categoryName: string): string => {
|
||||
switch (categoryName.toLowerCase()) {
|
||||
case 'health & wellness':
|
||||
case 'nutrition & supplements':
|
||||
return faker.helpers.arrayElement(healthDescriptions)
|
||||
case 'beauty & skincare':
|
||||
case 'personal care':
|
||||
return faker.helpers.arrayElement(beautyDescriptions)
|
||||
case 'fitness & sports':
|
||||
return faker.helpers.arrayElement(fitnessDescriptions)
|
||||
default:
|
||||
return faker.commerce.productDescription()
|
||||
}
|
||||
}
|
||||
|
||||
const generateProductImages = (): string[] => {
|
||||
const imageCount = faker.number.int({ min: 1, max: 4 })
|
||||
const images: string[] = []
|
||||
|
||||
for (let i = 0; i < imageCount; i++) {
|
||||
images.push(`https://images.unsplash.com/photo-${faker.number.int({ min: 1500000000000, max: 1700000000000 })}?w=800&h=600&fit=crop`)
|
||||
}
|
||||
|
||||
return images
|
||||
}
|
||||
|
||||
const generateProductSlug = (name: string): string => {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\s-]/g, '') // Remove special characters
|
||||
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
||||
.replace(/-+/g, '-') // Replace multiple hyphens with single
|
||||
.trim()
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Starting database seeding...')
|
||||
|
||||
// Clear existing data
|
||||
console.log('🧹 Clearing existing data...')
|
||||
await prisma.product.deleteMany()
|
||||
await prisma.category.deleteMany()
|
||||
await prisma.commissionSettings.deleteMany()
|
||||
|
||||
// Create commission settings
|
||||
console.log('💰 Creating commission settings...')
|
||||
await prisma.commissionSettings.createMany({
|
||||
data: [
|
||||
{ level: 1, percentage: 10, isActive: true },
|
||||
{ level: 2, percentage: 5, isActive: true },
|
||||
{ level: 3, percentage: 3, isActive: true },
|
||||
{ level: 4, percentage: 2, isActive: true },
|
||||
{ level: 5, percentage: 1, isActive: true }
|
||||
]
|
||||
})
|
||||
|
||||
// Create categories
|
||||
console.log('📂 Creating categories...')
|
||||
const createdCategories = []
|
||||
for (const category of categories) {
|
||||
const createdCategory = await prisma.category.create({
|
||||
data: {
|
||||
name: category.name,
|
||||
description: category.description
|
||||
}
|
||||
})
|
||||
createdCategories.push(createdCategory)
|
||||
}
|
||||
|
||||
// Create products
|
||||
console.log('📦 Creating products...')
|
||||
const productsToCreate = 120 // 20 products per category
|
||||
|
||||
for (let i = 0; i < productsToCreate; i++) {
|
||||
const category = faker.helpers.arrayElement(createdCategories)
|
||||
const template = faker.helpers.arrayElement(productTemplates)
|
||||
const productName = `${template.namePrefix} ${faker.helpers.arrayElement(template.nameSuffix)}`
|
||||
|
||||
const basePrice = faker.number.float({ min: 19.99, max: 299.99, multipleOf: 0.01 })
|
||||
const discount = faker.number.int({ min: 0, max: 40 })
|
||||
|
||||
await prisma.product.create({
|
||||
data: {
|
||||
name: productName,
|
||||
description: getRandomDescription(category.name),
|
||||
price: basePrice,
|
||||
discount: discount,
|
||||
images: generateProductImages(),
|
||||
stock: faker.number.int({ min: 0, max: 500 }),
|
||||
sku: faker.string.alphanumeric({ length: 8, casing: 'upper' }),
|
||||
slug: generateProductSlug(productName) + '-' + faker.string.alphanumeric({ length: 4, casing: 'lower' }),
|
||||
categoryId: category.id,
|
||||
isActive: faker.datatype.boolean({ probability: 0.9 }), // 90% active products
|
||||
createdAt: faker.date.between({
|
||||
from: new Date('2023-01-01'),
|
||||
to: new Date()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if ((i + 1) % 20 === 0) {
|
||||
console.log(`✅ Created ${i + 1} products...`)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize rank system
|
||||
console.log('🏆 Initializing rank system...')
|
||||
await rankSystem.initializeDefaultRanks()
|
||||
|
||||
// Get final counts
|
||||
const categoryCount = await prisma.category.count()
|
||||
const productCount = await prisma.product.count()
|
||||
const commissionCount = await prisma.commissionSettings.count()
|
||||
|
||||
console.log('\n🎉 Seeding completed successfully!')
|
||||
console.log(`📂 Categories created: ${categoryCount}`)
|
||||
console.log(`📦 Products created: ${productCount}`)
|
||||
console.log(`💰 Commission levels created: ${commissionCount}`)
|
||||
|
||||
console.log('\n📊 Products per category:')
|
||||
|
||||
for (const category of createdCategories) {
|
||||
const count = await prisma.product.count({
|
||||
where: { categoryId: category.id }
|
||||
})
|
||||
console.log(` ${category.name}: ${count} products`)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('❌ Error during seeding:', e)
|
||||
process.exit(1)
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect()
|
||||
})
|
||||
Reference in New Issue
Block a user