340 lines
12 KiB
JavaScript
340 lines
12 KiB
JavaScript
import mongoose from "mongoose";
|
|
import User from "./models/User.js";
|
|
import Session from "./models/Session.js";
|
|
import Transaction from "./models/Transaction.js";
|
|
import dotenv from "dotenv";
|
|
|
|
dotenv.config();
|
|
|
|
const MONGODB_URI =
|
|
process.env.MONGODB_URI || "mongodb://localhost:27017/turbotrades";
|
|
|
|
// Transaction types and their properties
|
|
const transactionTypes = [
|
|
{
|
|
type: "deposit",
|
|
direction: "positive",
|
|
descriptions: [
|
|
"PayPal deposit",
|
|
"Stripe payment",
|
|
"Crypto deposit",
|
|
"Balance top-up",
|
|
],
|
|
},
|
|
{
|
|
type: "withdrawal",
|
|
direction: "negative",
|
|
descriptions: [
|
|
"PayPal withdrawal",
|
|
"Bank transfer",
|
|
"Crypto withdrawal",
|
|
"Cash out",
|
|
],
|
|
},
|
|
{
|
|
type: "purchase",
|
|
direction: "negative",
|
|
descriptions: [
|
|
{
|
|
name: "AWP | Dragon Lore",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpot621FAR17PLfYQJD_9W7m5a0mvLwOq7cqWdQ-sJ0teXI8oThxlawrRI9fSmtc9TCJgI2ZlyDq1jvxuq5g8W6v5SYwXU37yEl7S7em0TmiRhEZ-BxxavJZlnsNrA/360fx360f",
|
|
},
|
|
{
|
|
name: "Karambit | Fade",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpovbSsLQJf2PLacDBA5ciJlY20k_jkI7fUhFRc4cJ5ntbN9J7yjRrm-UBrNzykI9CcdwRtaV3R-lS8xOu-hpK1u8zPzCRmuiEj-z-DyIHVYeJG/360fx360f",
|
|
},
|
|
{
|
|
name: "M4A4 | Howl",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpou-6kejhz2v_Nfz5H_uO1gb-Gw_alIITSg3tu5Mx2gv2PqNnz3le1-Etr9zqrOoWVcFU3M16FqVG5kO_qhcW4v8_AynZ9-n51s35gZPo/360fx360f",
|
|
},
|
|
{
|
|
name: "Glock-18 | Fade",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgposbaqKAxf0Ob3djFN79eJkIGZqPv1IbfQmGpD6e11jOzA4YfwjAy3_0ttamv6INWVe1RvZ1vY-li9lbzqhp7vusvXiSw0I5LNEws/360fx360f",
|
|
},
|
|
{
|
|
name: "AK-47 | Fire Serpent",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpot7HxfDhjxszJemkV08-mkYGHqPv9NLPF2GpVvZIpi-yWo96l2AK3-kZvYjv6cYOWcQU-YlrQ-1C9xb--gZLutczMmHtivj5iuyiMF8f2Bg/360fx360f",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: "sale",
|
|
direction: "positive",
|
|
descriptions: [
|
|
{
|
|
name: "Sold AWP | Asiimov",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpot621FAR17PLfYQJD_9W7m5a0mvLwOq7c2GpTu8Ah2ezDpIqh3wO1rhFuNW2gIoPDcQU_YlyE-gW9k-_ugJO86czXiSw0jMXQfH8/360fx360f",
|
|
},
|
|
{
|
|
name: "Sold Butterfly Knife",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpovbSsLQJf0ebcZThQ6tCvq4GGqPD1I6vdk1Rd4cJ5nqeQpYmtjVHm_RJlNTiiLYGddABvNVqB-QXow-q5hZK46svAziFruSR3sHrVlgv330-LpY0XQg/360fx360f",
|
|
},
|
|
{
|
|
name: "Sold StatTrak™ AK-47",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpot7HxfDhjxszJemkV09-5lpKKqPrxN7LEmyVQ7MEpiLuSrYqnjQCx_0NvZGHxdoKWJ1RsYF_V_we-xui915bpv8zLznBg7z5iuyjH3ErYgA/360fx360f",
|
|
},
|
|
{
|
|
name: "Sold M9 Bayonet",
|
|
image:
|
|
"https://community.cloudflare.steamstatic.com/economy/image/-9a81dlWLwJ2UUGcVs_nsVtzdOEdtWwKGZZLQHTxDZ7I56KU0Zwwo4NUX4oFJZEHLbXH5ApeO4YmlhxYQknCRvCo04DEVlxkKgpovbSsLQJf3qr3czxb49KzgL-DjsjwN6vdk1Rd4cJ5nqfE842s2AewqBJpMTrzLIWWcFBsYgrT_FK6ku_uh5G96JXPzCQ37iF2sH6Plgv330_SkBhtxg/360fx360f",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
type: "bonus",
|
|
direction: "positive",
|
|
descriptions: [
|
|
"Welcome bonus",
|
|
"Referral bonus",
|
|
"Loyalty reward",
|
|
"Promotional credit",
|
|
],
|
|
},
|
|
{
|
|
type: "refund",
|
|
direction: "positive",
|
|
descriptions: [
|
|
"Purchase refund",
|
|
"Transaction reversal",
|
|
"Cancelled order refund",
|
|
],
|
|
},
|
|
];
|
|
|
|
const paymentMethods = ["stripe", "paypal", "crypto", "balance", "steam"];
|
|
const statuses = ["completed", "pending", "processing"];
|
|
|
|
// Generate random amount based on transaction type
|
|
function generateAmount(type) {
|
|
switch (type) {
|
|
case "deposit":
|
|
case "withdrawal":
|
|
return parseFloat((Math.random() * 200 + 10).toFixed(2)); // $10-$210
|
|
case "purchase":
|
|
case "sale":
|
|
return parseFloat((Math.random() * 500 + 5).toFixed(2)); // $5-$505
|
|
case "bonus":
|
|
return parseFloat((Math.random() * 50 + 5).toFixed(2)); // $5-$55
|
|
case "refund":
|
|
return parseFloat((Math.random() * 150 + 10).toFixed(2)); // $10-$160
|
|
default:
|
|
return parseFloat((Math.random() * 100 + 10).toFixed(2));
|
|
}
|
|
}
|
|
|
|
// Generate random date within last 30 days
|
|
function generateRandomDate() {
|
|
const now = new Date();
|
|
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
|
const randomTime =
|
|
thirtyDaysAgo.getTime() +
|
|
Math.random() * (now.getTime() - thirtyDaysAgo.getTime());
|
|
return new Date(randomTime);
|
|
}
|
|
|
|
// Select random item from array
|
|
function randomItem(array) {
|
|
return array[Math.floor(Math.random() * array.length)];
|
|
}
|
|
|
|
async function seedTransactions() {
|
|
try {
|
|
console.log("🔌 Connecting to MongoDB...");
|
|
await mongoose.connect(MONGODB_URI);
|
|
console.log("✅ Connected to MongoDB");
|
|
|
|
// Find a user (preferably with sessions)
|
|
console.log("👤 Finding user...");
|
|
|
|
// Check for command line argument for Steam ID
|
|
const targetSteamId = process.argv[2];
|
|
let user;
|
|
|
|
if (targetSteamId) {
|
|
console.log(` Looking for Steam ID: ${targetSteamId}`);
|
|
user = await User.findOne({ steamId: targetSteamId });
|
|
|
|
if (!user) {
|
|
console.error(`❌ User with Steam ID ${targetSteamId} not found!`);
|
|
console.error("💡 Make sure you're logged in with this Steam account.");
|
|
process.exit(1);
|
|
}
|
|
} else {
|
|
// Default: find most recent user
|
|
user = await User.findOne().sort({ createdAt: -1 });
|
|
|
|
if (!user) {
|
|
console.error(
|
|
"❌ No users found. Please create a user first by logging in via Steam."
|
|
);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
console.log(`✅ Found user: ${user.username} (${user.steamId})`);
|
|
|
|
// Get existing sessions for this user
|
|
console.log("🔐 Finding sessions...");
|
|
let sessions = await Session.find({ userId: user._id, isActive: true });
|
|
|
|
if (sessions.length === 0) {
|
|
console.error("❌ No active sessions found!");
|
|
console.error(
|
|
"💡 Please log in via Steam first to create a real session."
|
|
);
|
|
console.error(" Then run this script again.");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`✅ Found ${sessions.length} active sessions`);
|
|
sessions.forEach((session) => {
|
|
console.log(
|
|
` - ${session.browser || "Unknown"} on ${
|
|
session.os || "Unknown"
|
|
} (...${session._id.toString().slice(-6)})`
|
|
);
|
|
});
|
|
|
|
// Generate 20-30 fake transactions
|
|
const transactionCount = Math.floor(Math.random() * 11) + 20;
|
|
console.log(`\n💰 Generating ${transactionCount} fake transactions...`);
|
|
|
|
let currentBalance = user.balance || 1000; // Start with current balance or $1000
|
|
const createdTransactions = [];
|
|
|
|
for (let i = 0; i < transactionCount; i++) {
|
|
// Pick random transaction type
|
|
const txTypeObj = randomItem(transactionTypes);
|
|
const amount = generateAmount(txTypeObj.type);
|
|
const descriptionItem = randomItem(txTypeObj.descriptions);
|
|
const description =
|
|
typeof descriptionItem === "string"
|
|
? descriptionItem
|
|
: descriptionItem.name;
|
|
const itemImage =
|
|
typeof descriptionItem === "object" ? descriptionItem.image : null;
|
|
|
|
// Calculate balance
|
|
const balanceBefore = currentBalance;
|
|
let balanceAfter;
|
|
|
|
if (txTypeObj.direction === "positive") {
|
|
balanceAfter = balanceBefore + amount;
|
|
} else {
|
|
balanceAfter = balanceBefore - amount;
|
|
}
|
|
|
|
currentBalance = balanceAfter;
|
|
|
|
// Pick random session
|
|
const session = randomItem(sessions);
|
|
|
|
// Pick random status (mostly completed)
|
|
const status = Math.random() < 0.85 ? "completed" : randomItem(statuses);
|
|
|
|
// Create transaction data
|
|
const transactionData = {
|
|
userId: user._id,
|
|
steamId: user.steamId,
|
|
type: txTypeObj.type,
|
|
status: status,
|
|
amount: amount,
|
|
currency: "USD",
|
|
balanceBefore: balanceBefore,
|
|
balanceAfter: balanceAfter,
|
|
sessionId: session._id,
|
|
description: description,
|
|
fee:
|
|
txTypeObj.type === "withdrawal"
|
|
? parseFloat((amount * 0.02).toFixed(2))
|
|
: 0,
|
|
feePercentage: txTypeObj.type === "withdrawal" ? 2 : 0,
|
|
};
|
|
|
|
// Add payment method for deposits/withdrawals
|
|
if (txTypeObj.type === "deposit" || txTypeObj.type === "withdrawal") {
|
|
transactionData.paymentMethod = randomItem(paymentMethods);
|
|
}
|
|
|
|
// Add item name and image for purchases/sales
|
|
if (txTypeObj.type === "purchase" || txTypeObj.type === "sale") {
|
|
transactionData.itemName = description;
|
|
if (itemImage) {
|
|
transactionData.itemImage = itemImage;
|
|
}
|
|
}
|
|
|
|
// Set completed date if status is completed
|
|
if (status === "completed") {
|
|
transactionData.completedAt = generateRandomDate();
|
|
}
|
|
|
|
const transaction = await Transaction.createTransaction(transactionData);
|
|
|
|
// Update createdAt to be in the past (for realistic history)
|
|
transaction.createdAt = generateRandomDate();
|
|
await transaction.save();
|
|
|
|
createdTransactions.push(transaction);
|
|
|
|
// Log progress
|
|
const sessionShort = session._id.toString().slice(-6).toUpperCase();
|
|
console.log(
|
|
` ✅ [${i + 1}/${transactionCount}] ${txTypeObj.type
|
|
.toUpperCase()
|
|
.padEnd(12)} $${amount
|
|
.toFixed(2)
|
|
.padStart(8)} - Session: ${sessionShort} - ${description}`
|
|
);
|
|
}
|
|
|
|
// Sort by date
|
|
createdTransactions.sort((a, b) => b.createdAt - a.createdAt);
|
|
|
|
console.log("\n📊 Transaction Summary:");
|
|
console.log(` Total created: ${createdTransactions.length}`);
|
|
|
|
const typeCounts = {};
|
|
const sessionCounts = {};
|
|
|
|
createdTransactions.forEach((tx) => {
|
|
typeCounts[tx.type] = (typeCounts[tx.type] || 0) + 1;
|
|
const sessionShort = tx.sessionIdShort || "SYSTEM";
|
|
sessionCounts[sessionShort] = (sessionCounts[sessionShort] || 0) + 1;
|
|
});
|
|
|
|
console.log("\n By Type:");
|
|
Object.entries(typeCounts).forEach(([type, count]) => {
|
|
console.log(` ${type.padEnd(12)}: ${count}`);
|
|
});
|
|
|
|
console.log("\n By Session:");
|
|
Object.entries(sessionCounts).forEach(([sessionShort, count]) => {
|
|
console.log(` ${sessionShort}: ${count} transactions`);
|
|
});
|
|
|
|
console.log("\n✅ Seeding completed successfully!");
|
|
console.log(
|
|
`\n💡 You can now view these transactions at: http://localhost:5173/transactions`
|
|
);
|
|
} catch (error) {
|
|
console.error("❌ Error seeding transactions:", error);
|
|
process.exit(1);
|
|
} finally {
|
|
await mongoose.disconnect();
|
|
console.log("\n🔌 Disconnected from MongoDB");
|
|
process.exit(0);
|
|
}
|
|
}
|
|
|
|
// Run the seed
|
|
seedTransactions();
|