saksh-easy-wallet
Version:
A simple and easy-to-use wallet management system for handling user balances and transactions.
169 lines (127 loc) • 5.98 kB
JavaScript
const mongoose = require('mongoose');
const { Schema } = mongoose;
const EventEmitter = require('events');
// Define the schema for wallet users
const walletUserSchema = new Schema({
email: { type: String, required: true, unique: true },
balance: { type: Map, of: Number, default: {} }
});
// Define the schema for wallet transactions
const walletTransactionSchema = new Schema({
email: { type: String, required: true },
type: { type: String, required: true },
amount: { type: Number, required: true },
currency: { type: String, required: true },
referenceId: { type: String, required: true },
description: { type: String, required: true },
transactionFee: { type: Number, default: 0 },
date: { type: Date, default: Date.now }
});
const logSchema = new mongoose.Schema({
level: { type: String, required: true },
message: { type: String, required: true },
timestamp: { type: Date, default: Date.now },
meta: { type: mongoose.Schema.Types.Mixed }
});
const Log = mongoose.model('Log', logSchema);
// Create the models
const WalletUserModel = mongoose.model('WalletUser', walletUserSchema);
const WalletTransactionModel = mongoose.model('WalletTransaction', walletTransactionSchema);
class SakshWallet extends EventEmitter {
constructor() {
super();
this.adminEmail = process.env.ADMIN_EMAIL || 'walletadmin@sakshwallet.com';
}
async log(level, message, meta = {}) {
const logEntry = new Log({ level, message, meta });
await logEntry.save();
}
setAdmin(adminEmail) {
this.adminEmail = adminEmail || 'walletadmin@sakshwallet.com';
}
async sakshGetBalance(email, currency) {
let userAccount = await WalletUserModel.findOne({ email });
if (!userAccount) {
userAccount = new WalletUserModel({ email });
await userAccount.save();
}
const balance = userAccount.balance.get(currency) || 0;
return { email, currency, balance };
}
async sakshGetBalanceSummary(email) {
let userAccount = await WalletUserModel.findOne({ email });
if (!userAccount) {
userAccount = new WalletUserModel({ email });
await userAccount.save();
}
return { email, balance: userAccount.balance };
}
async updateBalance(email, amount, currency, type, referenceId, description, transactionFee = 0) {
let userAccount = await WalletUserModel.findOne({ email });
if (!userAccount) {
userAccount = new WalletUserModel({ email });
await userAccount.save();
}
const currentBalance = userAccount.balance.get(currency) || 0;
const totalAmount = amount + transactionFee;
const newBalance = type === 'debit' ? currentBalance - totalAmount : currentBalance + amount;
if (type === 'debit' && totalAmount > currentBalance) {
return { message: 'Insufficient funds' };
}
userAccount.balance.set(currency, newBalance);
await userAccount.save();
const transaction = new WalletTransactionModel({
email,
type,
amount,
currency,
referenceId,
description,
transactionFee
});
await transaction.save();
if (transactionFee > 0) {
await this.sakshCredit(this.adminEmail, transactionFee, currency, referenceId, `Transaction fee for ${description}`);
}
this.emit(type, { email, amount, currency, newBalance, referenceId, description, transactionFee });
return { message: `${type === 'debit' ? 'Debited' : 'Credited'} ${amount} ${currency}.`, balance: newBalance, transaction };
}
async sakshDebit(email, amount, currency, referenceId, description, transactionFee = 0) {
return this.updateBalance(email, amount, currency, 'debit', referenceId, description, transactionFee);
}
async sakshCredit(email, amount, currency, referenceId, description, transactionFee = 0) {
await this.log('info', 'Initiating escrow', { email, email, amount, currency, description });
return this.updateBalance(email, amount, currency, 'credit', referenceId, description, transactionFee);
}
async sakshFundTransfer(senderEmail, receiverEmail, amount, currency, referenceId, description, transactionFee = 0) {
// Debit from sender
const debitResult = await this.sakshDebit(senderEmail, amount, currency, referenceId, `Transfer to ${receiverEmail}: ${description}`, transactionFee);
if (debitResult.message === 'Insufficient funds') {
throw new Error('Insufficient funds in sender\'s account');
}
// Credit to receiver
const creditResult = await this.sakshCredit(receiverEmail, amount, currency, referenceId, `Transfer from ${senderEmail}: ${description}`);
return {
message: `Transferred ${amount} ${currency} from ${senderEmail} to ${receiverEmail}.`,
senderBalance: debitResult.balance,
receiverBalance: creditResult.balance,
transaction: {
senderTransaction: debitResult.transaction,
receiverTransaction: creditResult.transaction
}
};
}
async sakshTransactionReport(email) {
const transactions = await WalletTransactionModel.find({ email }).sort({ date: -1 });
return transactions.map(tx => ({
type: tx.type,
amount: tx.amount,
currency: tx.currency,
referenceId: tx.referenceId,
description: tx.description,
transactionFee: tx.transactionFee,
date: tx.date
}));
}
}
module.exports = SakshWallet;