Skip to content

Commit 35466aa

Browse files
authored
Merge pull request #265 from sumitd94/develop
Track the stocks purchased by users
2 parents 9595a0a + 6310a35 commit 35466aa

File tree

7 files changed

+180
-21
lines changed

7 files changed

+180
-21
lines changed

controllers/stocks.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,36 @@ const fetchStocks = async (req, res) => {
2929
try {
3030
const allStock = await stocks.fetchStocks()
3131
return res.json({
32-
message: 'Stocks returned successfully!',
32+
message: allStock.length > 0 ? 'Stocks returned successfully!' : 'No stocks found',
3333
stock: allStock.length > 0 ? allStock : []
3434
})
3535
} catch (err) {
3636
logger.error(`Error while fetching stocks ${err}`)
3737
return res.boom.badImplementation('An internal server error occurred')
3838
}
3939
}
40+
/**
41+
* Fetches all the stocks of the user
42+
*
43+
* @param req {Object} - Express request object
44+
* @param res {Object} - Express response object
45+
*/
46+
const getSelfStocks = async (req, res) => {
47+
try {
48+
const { id: userId } = req.userData
49+
const userStocks = await stocks.fetchUserStocks(userId)
50+
return res.json({
51+
message: userStocks.length > 0 ? 'User stocks returned successfully!' : 'No stocks found',
52+
userStocks
53+
})
54+
} catch (err) {
55+
logger.error(`Error while getting user stocks ${err}`)
56+
return res.boom.badImplementation('An internal server error occurred')
57+
}
58+
}
4059

4160
module.exports = {
4261
addNewStock,
43-
fetchStocks
62+
fetchStocks,
63+
getSelfStocks
4464
}

controllers/trading.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const tradeModel = require('../models/trading')
1+
const tradeService = require('../services/tradingService')
22
/**
33
* New Trading Request
44
*
@@ -13,15 +13,15 @@ const trade = async (req, res) => {
1313
username,
1414
userId
1515
}
16-
const { canUserTrade, errorMessage, userBalance } = await tradeModel.trade(tradeStockData)
16+
const { canUserTrade, errorMessage, userBalance } = await tradeService.trade(tradeStockData)
1717

1818
if (!canUserTrade) {
1919
return res.boom.forbidden(errorMessage)
2020
}
2121

2222
return res.json({ userBalance })
2323
} catch (err) {
24-
logger.error(`Error while updating task: ${err}`)
24+
logger.error(`Error during trading: ${err}`)
2525
return res.boom.badImplementation('An internal server error occurred')
2626
}
2727
}

docs/swaggerDefinition.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,29 @@ const swaggerOptions = {
524524
}
525525
}
526526
},
527+
userStocks: {
528+
type: 'object',
529+
properties: {
530+
userId: {
531+
type: 'string'
532+
},
533+
stockId: {
534+
type: 'string'
535+
},
536+
stockName: {
537+
type: 'string'
538+
},
539+
quantity: {
540+
type: 'number'
541+
},
542+
orderValue: {
543+
type: 'number'
544+
},
545+
initialStockValue: {
546+
type: 'number'
547+
}
548+
}
549+
},
527550
auctions: {
528551
type: 'object',
529552
properties: {

models/stocks.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
const firestore = require('../utils/firestore')
22
const stocksModel = firestore.collection('stocks')
3+
const userStocksModel = firestore.collection('user-stocks')
4+
35
/**
46
* Adds Stocks
57
*
@@ -38,7 +40,65 @@ const fetchStocks = async () => {
3840
}
3941
}
4042

43+
/**
44+
* Fetches the user stocks
45+
* @return {Promise<userStocks|object>}
46+
*/
47+
const fetchUserStocks = async (userId, stockId = null) => {
48+
try {
49+
let userStocksRef = ''
50+
const query = userStocksModel.where('userId', '==', userId)
51+
if (stockId) {
52+
userStocksRef = await query.where('stockId', '==', stockId).get()
53+
const [userStocks] = userStocksRef.docs
54+
if (userStocks) {
55+
return { id: userStocks.id, ...userStocks.data() }
56+
}
57+
return {}
58+
}
59+
60+
userStocksRef = await query.get()
61+
const userStocks = []
62+
userStocksRef.forEach((stock) => {
63+
userStocks.push({
64+
id: stock.id,
65+
...stock.data()
66+
})
67+
})
68+
return userStocks
69+
} catch (err) {
70+
logger.error('Error retrieving user stocks', err)
71+
throw err
72+
}
73+
}
74+
75+
/**
76+
* Update Users Stocks
77+
* @return {Promise<userStocks|object>}
78+
*/
79+
const updateUserStocks = async (userId, stockData) => {
80+
try {
81+
const userStocks = await fetchUserStocks(userId, stockData.stockId)
82+
if (!userStocks.id) {
83+
await userStocksModel.add({
84+
userId,
85+
...stockData
86+
})
87+
return true
88+
}
89+
90+
const userStocksRef = userStocksModel.doc(userStocks.id)
91+
const res = await userStocksRef.update(stockData)
92+
return !!res
93+
} catch (err) {
94+
logger.error('Error updating users stocks', err)
95+
throw err
96+
}
97+
}
98+
4199
module.exports = {
42100
addStock,
43-
fetchStocks
101+
fetchStocks,
102+
fetchUserStocks,
103+
updateUserStocks
44104
}

public/apiSchema.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

routes/stocks.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const express = require('express')
22
const router = express.Router()
33
const authenticate = require('../middlewares/authenticate')
44
const authorization = require('../middlewares/authorization')
5-
const { addNewStock, fetchStocks } = require('../controllers/stocks')
5+
const { addNewStock, fetchStocks, getSelfStocks } = require('../controllers/stocks')
66
const { createStock } = require('../middlewares/validators/stocks')
77

88
/**
@@ -64,4 +64,34 @@ router.get('/', fetchStocks)
6464
*/
6565
router.post('/', authenticate, authorization, createStock, addNewStock)
6666

67+
/**
68+
* @swagger
69+
* /stocks/user/self:
70+
* get:
71+
* summary: Used to get all the stocks of the user
72+
* tags:
73+
* - User Stocks
74+
* responses:
75+
* 200:
76+
* description: returns stocks of the user
77+
* content:
78+
* application/json:
79+
* schema:
80+
* $ref: '#/components/schemas/userStocks'
81+
* 401:
82+
* description: unAuthorized
83+
* content:
84+
* application/json:
85+
* schema:
86+
* $ref: '#/components/schemas/errors/unAuthorized'
87+
* 500:
88+
* description: badImplementation
89+
* content:
90+
* application/json:
91+
* schema:
92+
* $ref: '#/components/schemas/errors/badImplementation'
93+
*/
94+
95+
router.get('/user/self', authenticate, getSelfStocks)
96+
6797
module.exports = router

models/trading.js renamed to services/tradingService.js

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ const stocksModel = firestore.collection('stocks')
33
const transactionsModel = firestore.collection('transactions')
44
const tradeLogsModel = firestore.collection('trade-logs')
55
const { fetchWallet, updateWallet } = require('../models/wallets')
6+
const { fetchUserStocks, updateUserStocks } = require('../models/stocks')
7+
const { DINERO } = require('../constants/wallets')
68

79
const INSUFFICIENT_FUNDS = 'Trade was not successful due to insufficient funds'
10+
const INSUFFICIENT_QUANTITIES = 'Trade was not successful because you do not have enough quantity'
811

912
/**
1013
* Updates the stock Price
@@ -26,16 +29,17 @@ const getUpdatedPrice = (stockPrice) => {
2629
const trade = async (tradeData) => {
2730
// ! TODO - update as per curreny type, currently only using dinero
2831
try {
29-
const { stockId, quantity, tradeType, totalPrice, userId } = tradeData
32+
const { stockId, stockName, quantity, tradeType, totalPrice, userId } = tradeData
3033
const stockCollection = await stocksModel.doc(stockId).get()
3134
const stockData = stockCollection.data()
3235
let userBalance = 0
3336
let quantityToUpdate = 0
34-
let stockPriceToBeUpdated = stockData.price
35-
let orderValue = 0
36-
let qtyUserCanPurchase = 0
37+
let qtyUserCanPurchase = quantity
38+
let userStocksQty = 0
39+
let initialStockValue = stockData.price
3740

3841
const { currencies } = await fetchWallet(userId)
42+
const userStocks = await fetchUserStocks(userId, stockId)
3943
const updatedCurrencyData = {}
4044

4145
if (!currencies) {
@@ -44,35 +48,57 @@ const trade = async (tradeData) => {
4448

4549
switch (tradeType) {
4650
case 'SELL': {
51+
if (!userStocks.id || userStocks.quantity < quantity) {
52+
return { canUserTrade: false, errorMessage: INSUFFICIENT_QUANTITIES }
53+
}
54+
4755
quantityToUpdate = quantity + stockData.quantity
48-
userBalance = quantity * stockData.price
49-
updatedCurrencyData.dinero = userBalance + currencies.dinero
50-
stockPriceToBeUpdated = getUpdatedPrice(stockData.price)
56+
userBalance = (quantity * stockData.price) + currencies[`${DINERO}`]
57+
userStocksQty = userStocks.quantity - quantity
5158
break
5259
}
5360
case 'BUY': {
5461
qtyUserCanPurchase = Math.floor(totalPrice / stockData.price)
55-
if (qtyUserCanPurchase <= 0 || totalPrice > currencies.dinero) {
62+
if (qtyUserCanPurchase <= 0 || totalPrice > currencies[`${DINERO}`]) {
5663
return { canUserTrade: false, errorMessage: INSUFFICIENT_FUNDS }
5764
}
58-
orderValue = qtyUserCanPurchase * stockData.price
5965
quantityToUpdate = stockData.quantity - qtyUserCanPurchase
60-
userBalance = currencies.dinero - orderValue
61-
updatedCurrencyData.dinero = userBalance
62-
stockPriceToBeUpdated = getUpdatedPrice(stockData.price)
66+
userBalance = currencies[`${DINERO}`] - (qtyUserCanPurchase * stockData.price)
67+
userStocksQty = qtyUserCanPurchase
68+
69+
initialStockValue = stockData.price
70+
71+
if (userStocks.id) {
72+
userStocksQty = userStocks.quantity + qtyUserCanPurchase
73+
initialStockValue = userStocks.initialStockValue
74+
}
6375
break
6476
}
6577
default: {
6678
return { canUserTrade: false, errorMessage: 'Invalid trade type' }
6779
}
6880
}
6981

82+
const orderValue = qtyUserCanPurchase * stockData.price
83+
const stockPriceToBeUpdated = getUpdatedPrice(stockData.price)
84+
updatedCurrencyData[`${DINERO}`] = userBalance
85+
7086
const updatedStockData = {
7187
...stockData,
7288
quantity: quantityToUpdate,
7389
price: stockPriceToBeUpdated
7490
}
7591

92+
// Update user stocks
93+
94+
await updateUserStocks(userId, {
95+
stockId,
96+
stockName,
97+
quantity: userStocksQty,
98+
orderValue: userStocksQty * stockData.price,
99+
initialStockValue
100+
})
101+
76102
// Transaction Log
77103

78104
const { id } = await tradeLogsModel.add({
@@ -94,7 +120,7 @@ const trade = async (tradeData) => {
94120

95121
// update user wallet
96122

97-
updateWallet(userId, {
123+
await updateWallet(userId, {
98124
...currencies,
99125
...updatedCurrencyData
100126
})

0 commit comments

Comments
 (0)