122 lines
2.9 KiB
TypeScript
122 lines
2.9 KiB
TypeScript
import mongoose, { Document, Model } from 'mongoose'
|
|
import { z } from 'zod'
|
|
|
|
// Zod schema for validation
|
|
export const TransactionSchema = z.object({
|
|
transactionId: z.string().min(1, 'Transaction ID is required'),
|
|
userId: z.string().min(1, 'User ID is required'),
|
|
email: z.string().email('Invalid email format'),
|
|
type: z.enum(['debit', 'credit']),
|
|
amount: z.number().positive('Amount must be positive'),
|
|
service: z.string().min(1, 'Service name is required'),
|
|
serviceId: z.string().optional(),
|
|
description: z.string().optional(),
|
|
status: z.enum(['pending', 'completed', 'failed']).default('completed'),
|
|
previousBalance: z.number().min(0, 'Previous balance cannot be negative'),
|
|
newBalance: z.number().min(0, 'New balance cannot be negative'),
|
|
metadata: z.record(z.string(), z.any()).optional(),
|
|
})
|
|
|
|
export type TransactionType = z.infer<typeof TransactionSchema>
|
|
|
|
// Mongoose interface
|
|
export interface ITransaction extends Document {
|
|
transactionId: string
|
|
userId: string
|
|
email: string
|
|
type: 'debit' | 'credit'
|
|
amount: number
|
|
service: string
|
|
serviceId?: string
|
|
description?: string
|
|
status: 'pending' | 'completed' | 'failed'
|
|
previousBalance: number
|
|
newBalance: number
|
|
metadata?: Record<string, any>
|
|
createdAt: Date
|
|
updatedAt: Date
|
|
}
|
|
|
|
// Mongoose schema
|
|
const transactionSchema = new mongoose.Schema<ITransaction>(
|
|
{
|
|
transactionId: {
|
|
type: String,
|
|
required: true,
|
|
unique: true,
|
|
index: true,
|
|
},
|
|
userId: {
|
|
type: String,
|
|
required: true,
|
|
index: true,
|
|
},
|
|
email: {
|
|
type: String,
|
|
required: true,
|
|
lowercase: true,
|
|
trim: true,
|
|
index: true,
|
|
},
|
|
type: {
|
|
type: String,
|
|
enum: ['debit', 'credit'],
|
|
required: true,
|
|
},
|
|
amount: {
|
|
type: Number,
|
|
required: true,
|
|
min: 0,
|
|
},
|
|
service: {
|
|
type: String,
|
|
required: true,
|
|
trim: true,
|
|
},
|
|
serviceId: {
|
|
type: String,
|
|
trim: true,
|
|
},
|
|
description: {
|
|
type: String,
|
|
trim: true,
|
|
},
|
|
status: {
|
|
type: String,
|
|
enum: ['pending', 'completed', 'failed'],
|
|
default: 'completed',
|
|
},
|
|
previousBalance: {
|
|
type: Number,
|
|
required: true,
|
|
min: 0,
|
|
},
|
|
newBalance: {
|
|
type: Number,
|
|
required: true,
|
|
min: 0,
|
|
},
|
|
metadata: {
|
|
type: mongoose.Schema.Types.Mixed,
|
|
},
|
|
},
|
|
{
|
|
timestamps: true,
|
|
}
|
|
)
|
|
|
|
// Indexes for performance
|
|
transactionSchema.index({ userId: 1, createdAt: -1 })
|
|
transactionSchema.index({ email: 1, createdAt: -1 })
|
|
transactionSchema.index({ service: 1, createdAt: -1 })
|
|
transactionSchema.index({ type: 1, createdAt: -1 })
|
|
|
|
// Transform method to format response
|
|
transactionSchema.methods.toJSON = function () {
|
|
const transaction = this.toObject()
|
|
return transaction
|
|
}
|
|
|
|
export const Transaction: Model<ITransaction> =
|
|
mongoose.models.Transaction || mongoose.model<ITransaction>('Transaction', transactionSchema)
|