@@ -1,4 +1,3 @@
|
||||
console.log('Running Something')
|
||||
require('dotenv').config({ path: './config/.env' })
|
||||
const express = require('express')
|
||||
const databaseConnection = require('./setup/databaseConnection.js')
|
||||
|
||||
@@ -18,6 +18,10 @@ const belongingSchema = new mongoose.Schema(
|
||||
type: ObjectID,
|
||||
ref: 'Category',
|
||||
},
|
||||
unit: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: String,
|
||||
relatedProjects: [String],
|
||||
location: {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
const catchAsync = require('../../globalErrorHandler/catchAsync')
|
||||
const transactionService = require('./transactionService')
|
||||
|
||||
exports.createTransaction = catchAsync(async (req, res, next) => {
|
||||
const transactions = await transactionService.createTransaction(req.body)
|
||||
|
||||
res.status(201).json({
|
||||
status: 'success',
|
||||
results: transactions.length,
|
||||
data: transactions,
|
||||
})
|
||||
})
|
||||
|
||||
exports.getUserTransaction = catchAsync(async (req, res, next) => {
|
||||
const transactions = await transactionService.getUserTransaction(req.user._id)
|
||||
|
||||
res.status(200).json({
|
||||
status: 'success',
|
||||
results: transactions.length,
|
||||
data: transactions,
|
||||
})
|
||||
})
|
||||
|
||||
exports.getBelongingInventory = catchAsync(async (req, res, next) => {
|
||||
const result = await transactionService.getBelongingInventory(req.params.belongingId)
|
||||
|
||||
res.status(200).json({
|
||||
status: 'success',
|
||||
data: result,
|
||||
})
|
||||
})
|
||||
|
||||
exports.updateTransaction = catchAsync(async (req, res, next) => {
|
||||
const transaction = await transactionService.updateTransaction(req.params.transactionId, req.body)
|
||||
|
||||
res.status(200).json({
|
||||
status: 'success',
|
||||
data: transaction,
|
||||
})
|
||||
})
|
||||
|
||||
exports.deleteTransaction = catchAsync(async (req, res, next) => {
|
||||
await transactionService.deleteTransaction(req.params.transactionId)
|
||||
|
||||
res.status(204).json({
|
||||
status: 'success',
|
||||
data: null,
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,55 @@
|
||||
const mongoose = require('mongoose')
|
||||
const ObjectID = mongoose.Schema.Types.ObjectId
|
||||
|
||||
const transactionSchema = new mongoose.Schema(
|
||||
{
|
||||
type: {
|
||||
type: String,
|
||||
enum: ['withdraw', 'deposit'],
|
||||
required: true,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['failed', 'pending', 'finished'],
|
||||
required: true,
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
enum: ['normal'],
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
date: {
|
||||
type: Date,
|
||||
default: Date.now(),
|
||||
},
|
||||
description: String,
|
||||
userId: {
|
||||
type: ObjectID,
|
||||
ref: 'User',
|
||||
},
|
||||
belongingId: {
|
||||
type: ObjectID,
|
||||
ref: 'Belonging',
|
||||
},
|
||||
},
|
||||
{
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true },
|
||||
timestamps: true,
|
||||
}
|
||||
)
|
||||
|
||||
// Add individual indexes for frequently queried fields
|
||||
transactionSchema.index({ type: 1 })
|
||||
transactionSchema.index({ status: 1 })
|
||||
transactionSchema.index({ value: 1 })
|
||||
|
||||
// Add compound indexes for common query patterns in aggregation
|
||||
transactionSchema.index({ belongingId: 1, status: 1 })
|
||||
transactionSchema.index({ belongingId: 1, type: 1, status: 1 })
|
||||
|
||||
const Transaction = mongoose.model('Transaction', transactionSchema)
|
||||
module.exports = Transaction
|
||||
@@ -0,0 +1,40 @@
|
||||
const express = require('express')
|
||||
const transactionController = require('./transactionController')
|
||||
// const perm = require('../../middlewares/permissionMiddleware')
|
||||
const loginCheck = require('../../middlewares/loginCheck')
|
||||
|
||||
const router = new express.Router()
|
||||
|
||||
router.use(loginCheck.loginProtect)
|
||||
|
||||
router.get(
|
||||
'/admin/self',
|
||||
// perm.requires('getallbelongings'),
|
||||
transactionController.getUserTransaction
|
||||
)
|
||||
|
||||
router.post(
|
||||
'/admin/create',
|
||||
// perm.requires('getallbelongings'),
|
||||
transactionController.createTransaction
|
||||
)
|
||||
|
||||
router.get(
|
||||
'/admin/belonging/:belongingId/inventory',
|
||||
// perm.requires('getallbelongings'),
|
||||
transactionController.getBelongingInventory
|
||||
)
|
||||
|
||||
router.patch(
|
||||
'/admin/update/:transactionId',
|
||||
// perm.requires('getallbelongings'),
|
||||
transactionController.updateTransaction
|
||||
)
|
||||
|
||||
router.delete(
|
||||
'/admin/delete/:transactionId',
|
||||
// perm.requires('getallbelongings'),
|
||||
transactionController.deleteTransaction
|
||||
)
|
||||
|
||||
module.exports = router
|
||||
@@ -0,0 +1,150 @@
|
||||
const Transaction = require('./transactionModel')
|
||||
const Belonging = require('../belonging/belongingModel')
|
||||
const AppError = require('../../globalErrorHandler/AppError')
|
||||
const mongoose = require('mongoose')
|
||||
const ObjectID = mongoose.Schema.Types.ObjectId
|
||||
const { client } = require('../../setup/typesense')
|
||||
const TsApiFeatures = require('../../utils/TsApiFeatures')
|
||||
|
||||
const filterObj = (obj, ...allowedFields) => {
|
||||
const newObj = {}
|
||||
Object.keys(obj).forEach((el) => {
|
||||
if (allowedFields.includes(el)) newObj[el] = obj[el]
|
||||
})
|
||||
|
||||
return newObj
|
||||
}
|
||||
|
||||
const createTransaction = async (data) => {
|
||||
if (data.type == 'withdraw') {
|
||||
// Aggregate transactions to calculate inventory
|
||||
const result = await Transaction.aggregate([
|
||||
{
|
||||
$match: {
|
||||
belongingId: ObjectID,
|
||||
status: 'finished',
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: '$belongingId',
|
||||
totalInventory: {
|
||||
$sum: '$value',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
if (result[0].totalInventory <= 0) throw new AppError('Invalid Transaction', 404, {})
|
||||
}
|
||||
|
||||
return Transaction.create({
|
||||
type: data.type,
|
||||
status: data.status,
|
||||
source: data.source,
|
||||
value: data.type === 'withdraw' ? data.value * -1 : data.value,
|
||||
date: data.Date,
|
||||
description: data.description,
|
||||
userId: data.userId,
|
||||
belongingId: data.belongingId,
|
||||
})
|
||||
}
|
||||
|
||||
const getUserTransaction = async (userId) => {
|
||||
return Transaction.find({ userId }, null, null)
|
||||
}
|
||||
|
||||
const getBelongingInventory = async (belongingId) => {
|
||||
const belonging = await Belonging.findById(belongingId, null, null)
|
||||
|
||||
if (!belonging) {
|
||||
throw new AppError('NoBelongingFound', 404, {})
|
||||
}
|
||||
|
||||
// Simplified aggregation to calculate inventory metrics
|
||||
const result = await Transaction.aggregate([
|
||||
{
|
||||
$match: {
|
||||
belongingId: ObjectID,
|
||||
$or: [{ status: 'finished' }, { status: 'pending' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
$facet: {
|
||||
// Calculate total inventory from finished transactions
|
||||
finishedInventory: [
|
||||
{ $match: { status: 'finished' } },
|
||||
{
|
||||
$group: {
|
||||
_id: null,
|
||||
total: { $sum: '$value' },
|
||||
},
|
||||
},
|
||||
],
|
||||
// Calculate pending deposits
|
||||
pendingDepositsInventory: [
|
||||
{
|
||||
$match: {
|
||||
status: 'pending',
|
||||
type: 'deposit',
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: null,
|
||||
total: { $sum: '$value' },
|
||||
},
|
||||
},
|
||||
],
|
||||
// Calculate pending withdrawals
|
||||
pendingWithdrawsInventory: [
|
||||
{
|
||||
$match: {
|
||||
status: 'pending',
|
||||
type: 'withdraw',
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: null,
|
||||
total: { $sum: '$value' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
// Restructure the output to get only the values
|
||||
$project: {
|
||||
finishedInventory: { $ifNull: [{ $arrayElemAt: ['$finishedInventory.total', 0] }, 0] },
|
||||
pendingDepositsInventory: { $ifNull: [{ $arrayElemAt: ['$pendingDepositsInventory.total', 0] }, 0] },
|
||||
pendingWithdrawsInventory: { $ifNull: [{ $arrayElemAt: ['$pendingWithdrawsInventory.total', 0] }, 0] },
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
return { belongingCode: belonging.belongingCode, ...result[0] }
|
||||
}
|
||||
|
||||
const updateTransaction = async (transactionId, data) => {
|
||||
const filteredBody = filterObj(data, 'status')
|
||||
const transaction = await Transaction.findOneAndUpdate({ _id: transactionId }, filteredBody, { new: true })
|
||||
|
||||
if (!transaction) {
|
||||
throw new AppError('NoTransactionFound', 404, {})
|
||||
}
|
||||
|
||||
return transaction
|
||||
}
|
||||
|
||||
const deleteTransaction = async (transactionId) => {
|
||||
const transaction = await Transaction.findOneAndDelete({ _id: transactionId })
|
||||
|
||||
if (!transaction) {
|
||||
throw AppError('NoTransactionFound', 404, {})
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
module.exports = { createTransaction, getUserTransaction, getBelongingInventory, updateTransaction, deleteTransaction }
|
||||
@@ -5,8 +5,8 @@ const loginCheck = require('../../middlewares/loginCheck')
|
||||
|
||||
const router = new express.Router()
|
||||
|
||||
router.post('/user/signup-email', userController.signup)
|
||||
router.post('/user/login-email', userController.loginUser)
|
||||
router.post('/signup-email', userController.signup)
|
||||
router.post('/login-email', userController.loginUser)
|
||||
router.post('/logout', userController.logoutUser)
|
||||
|
||||
router.use(loginCheck.loginProtect)
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
MONGODB_URL=mongodb://root:DBKvf305VCc0csA5@services.irn9.chabokan.net:20690/marbm?authSource=admin
|
||||
MONGODB_URL=mongodb://root:yBi0FXMb1rWNhFxu@services.irn12.chabokan.net:58178/my-app?authSource=admin
|
||||
NODE_ENV=development
|
||||
PORT=3000
|
||||
JWT_SECRET=Y@RJ$WT!@K0NS@MPL!
|
||||
REDIS_URL= redis://:JrKdaxaQQGTwpxgm@services.irn9.chabokan.net:6322
|
||||
REDIS_URL= redis://:GFis6zU4DXW9Q7NQ@services.irn12.chabokan.net:19794/0
|
||||
LOGIN_ATTEMPT_LIMIT=900
|
||||
SUPER_ADMIN_ROLE_ID=66a2da5b9b989a8909948848
|
||||
TYPE_SENSE_URL=services.irn9.chabokan.net
|
||||
|
||||
+10
-10
@@ -1,13 +1,13 @@
|
||||
services:
|
||||
# api-server:
|
||||
# build: ./
|
||||
# ports:
|
||||
# - 3000:3000
|
||||
# environment:
|
||||
# - MONGODB_URL=mongodb://admin:*135792468*@mongo:27017/marbm?authSource=admin
|
||||
# - NODE_ENV=development
|
||||
# - PORT=3000
|
||||
# - REDIS_URL=redis://:135792468@redis:6379/0
|
||||
# api-server:
|
||||
# build: ./
|
||||
# ports:
|
||||
# - 3000:4000
|
||||
# environment:
|
||||
# - MONGODB_URL=mongodb://admin:*135792468*@bm_mongo:27017/marbm?authSource=admin
|
||||
# - NODE_ENV=development
|
||||
# - PORT=3000
|
||||
# - REDIS_URL=redis://:135792468@bm_redis:6379/0
|
||||
bm_minio:
|
||||
image: minio/minio
|
||||
ports:
|
||||
@@ -42,7 +42,7 @@ services:
|
||||
image: typesense/typesense:27.1
|
||||
command: ./typesense-server
|
||||
ports:
|
||||
- "8108:8108"
|
||||
- '8108:8108'
|
||||
environment:
|
||||
TYPESENSE_API_KEY: vYQq7pTgl6ACoRy
|
||||
TYPESENSE_DATA_DIR: /data
|
||||
|
||||
Generated
+1815
-1815
File diff suppressed because it is too large
Load Diff
+32
-32
@@ -1,36 +1,36 @@
|
||||
{
|
||||
"name": "belonging-manager",
|
||||
"version": "1.0.0",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"seed": "node ./seeder/seed.js",
|
||||
"start": "node app.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.20.3",
|
||||
"chalk": "^4.1.2",
|
||||
"compression": "^1.7.5",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.21.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"minio": "^8.0.3",
|
||||
"name": "belonging-manager",
|
||||
"version": "1.0.0",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"seed": "node ./seeder/seed.js",
|
||||
"start": "nodemon app.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"body-parser": "^1.20.3",
|
||||
"chalk": "^4.1.2",
|
||||
"compression": "^1.7.5",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.21.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"minio": "^8.0.3",
|
||||
"mongoose": "^8.9.0",
|
||||
"mongoose-sequence": "^6.0.1",
|
||||
"mongoose-sequence": "^6.0.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"redis": "^4.7.0",
|
||||
"typesense": "^1.8.2",
|
||||
"validator": "^13.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.9"
|
||||
}
|
||||
"redis": "^4.7.0",
|
||||
"typesense": "^1.8.2",
|
||||
"validator": "^13.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^3.1.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@ const roleRoutes = require('../components/role/roleRoutes')
|
||||
const permissionRoutes = require('../components/permission/permissionRoutes')
|
||||
const belongingRoutes = require('../components/belonging/belongingRoutes')
|
||||
const categoryRoutes = require('../components/category/categoryRoutes')
|
||||
const transactionRoutes = require('../components/transaction/transactionRoutes')
|
||||
// const codeRoutes = require('../components/code/codeRoutes')
|
||||
// const CRMRoutes = require('../components/pages/crmRoutes')
|
||||
// const LoginRoute = require('../components/pages/loginRoutes')
|
||||
|
||||
const fileRoutes = require('../components/file/fileRoutes')
|
||||
const featureRoutes = require('../components/feature/featureRoutes')
|
||||
const routerEndpoints = new express.Router()
|
||||
@@ -13,6 +18,8 @@ routerEndpoints.use('/permissions', permissionRoutes)
|
||||
routerEndpoints.use('/belongings', belongingRoutes)
|
||||
routerEndpoints.use('/roles', roleRoutes)
|
||||
routerEndpoints.use('/categories', categoryRoutes)
|
||||
routerEndpoints.use('/transactions', transactionRoutes)
|
||||
|
||||
routerEndpoints.use('/files', fileRoutes)
|
||||
routerEndpoints.use('/features', featureRoutes)
|
||||
module.exports = routerEndpoints
|
||||
|
||||
Reference in New Issue
Block a user