Skip to content

Commit

Permalink
Merge pull request #265 from sumitd94/develop
Browse files Browse the repository at this point in the history
Track the stocks purchased by users
  • Loading branch information
swarajpure committed May 13, 2021
2 parents 9595a0a + 6310a35 commit 35466aa
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 21 deletions.
24 changes: 22 additions & 2 deletions controllers/stocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,36 @@ const fetchStocks = async (req, res) => {
try {
const allStock = await stocks.fetchStocks()
return res.json({
message: 'Stocks returned successfully!',
message: allStock.length > 0 ? 'Stocks returned successfully!' : 'No stocks found',
stock: allStock.length > 0 ? allStock : []
})
} catch (err) {
logger.error(`Error while fetching stocks ${err}`)
return res.boom.badImplementation('An internal server error occurred')
}
}
/**
* Fetches all the stocks of the user
*
* @param req {Object} - Express request object
* @param res {Object} - Express response object
*/
const getSelfStocks = async (req, res) => {
try {
const { id: userId } = req.userData
const userStocks = await stocks.fetchUserStocks(userId)
return res.json({
message: userStocks.length > 0 ? 'User stocks returned successfully!' : 'No stocks found',
userStocks
})
} catch (err) {
logger.error(`Error while getting user stocks ${err}`)
return res.boom.badImplementation('An internal server error occurred')
}
}

module.exports = {
addNewStock,
fetchStocks
fetchStocks,
getSelfStocks
}
6 changes: 3 additions & 3 deletions controllers/trading.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const tradeModel = require('../models/trading')
const tradeService = require('../services/tradingService')
/**
* New Trading Request
*
Expand All @@ -13,15 +13,15 @@ const trade = async (req, res) => {
username,
userId
}
const { canUserTrade, errorMessage, userBalance } = await tradeModel.trade(tradeStockData)
const { canUserTrade, errorMessage, userBalance } = await tradeService.trade(tradeStockData)

if (!canUserTrade) {
return res.boom.forbidden(errorMessage)
}

return res.json({ userBalance })
} catch (err) {
logger.error(`Error while updating task: ${err}`)
logger.error(`Error during trading: ${err}`)
return res.boom.badImplementation('An internal server error occurred')
}
}
Expand Down
23 changes: 23 additions & 0 deletions docs/swaggerDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,29 @@ const swaggerOptions = {
}
}
},
userStocks: {
type: 'object',
properties: {
userId: {
type: 'string'
},
stockId: {
type: 'string'
},
stockName: {
type: 'string'
},
quantity: {
type: 'number'
},
orderValue: {
type: 'number'
},
initialStockValue: {
type: 'number'
}
}
},
auctions: {
type: 'object',
properties: {
Expand Down
62 changes: 61 additions & 1 deletion models/stocks.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const firestore = require('../utils/firestore')
const stocksModel = firestore.collection('stocks')
const userStocksModel = firestore.collection('user-stocks')

/**
* Adds Stocks
*
Expand Down Expand Up @@ -38,7 +40,65 @@ const fetchStocks = async () => {
}
}

/**
* Fetches the user stocks
* @return {Promise<userStocks|object>}
*/
const fetchUserStocks = async (userId, stockId = null) => {
try {
let userStocksRef = ''
const query = userStocksModel.where('userId', '==', userId)
if (stockId) {
userStocksRef = await query.where('stockId', '==', stockId).get()
const [userStocks] = userStocksRef.docs
if (userStocks) {
return { id: userStocks.id, ...userStocks.data() }
}
return {}
}

userStocksRef = await query.get()
const userStocks = []
userStocksRef.forEach((stock) => {
userStocks.push({
id: stock.id,
...stock.data()
})
})
return userStocks
} catch (err) {
logger.error('Error retrieving user stocks', err)
throw err
}
}

/**
* Update Users Stocks
* @return {Promise<userStocks|object>}
*/
const updateUserStocks = async (userId, stockData) => {
try {
const userStocks = await fetchUserStocks(userId, stockData.stockId)
if (!userStocks.id) {
await userStocksModel.add({
userId,
...stockData
})
return true
}

const userStocksRef = userStocksModel.doc(userStocks.id)
const res = await userStocksRef.update(stockData)
return !!res
} catch (err) {
logger.error('Error updating users stocks', err)
throw err
}
}

module.exports = {
addStock,
fetchStocks
fetchStocks,
fetchUserStocks,
updateUserStocks
}
2 changes: 1 addition & 1 deletion public/apiSchema.json

Large diffs are not rendered by default.

32 changes: 31 additions & 1 deletion routes/stocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const express = require('express')
const router = express.Router()
const authenticate = require('../middlewares/authenticate')
const authorization = require('../middlewares/authorization')
const { addNewStock, fetchStocks } = require('../controllers/stocks')
const { addNewStock, fetchStocks, getSelfStocks } = require('../controllers/stocks')
const { createStock } = require('../middlewares/validators/stocks')

/**
Expand Down Expand Up @@ -64,4 +64,34 @@ router.get('/', fetchStocks)
*/
router.post('/', authenticate, authorization, createStock, addNewStock)

/**
* @swagger
* /stocks/user/self:
* get:
* summary: Used to get all the stocks of the user
* tags:
* - User Stocks
* responses:
* 200:
* description: returns stocks of the user
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/userStocks'
* 401:
* description: unAuthorized
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/errors/unAuthorized'
* 500:
* description: badImplementation
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/errors/badImplementation'
*/

router.get('/user/self', authenticate, getSelfStocks)

module.exports = router
52 changes: 39 additions & 13 deletions models/trading.js → services/tradingService.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ const stocksModel = firestore.collection('stocks')
const transactionsModel = firestore.collection('transactions')
const tradeLogsModel = firestore.collection('trade-logs')
const { fetchWallet, updateWallet } = require('../models/wallets')
const { fetchUserStocks, updateUserStocks } = require('../models/stocks')
const { DINERO } = require('../constants/wallets')

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

/**
* Updates the stock Price
Expand All @@ -26,16 +29,17 @@ const getUpdatedPrice = (stockPrice) => {
const trade = async (tradeData) => {
// ! TODO - update as per curreny type, currently only using dinero
try {
const { stockId, quantity, tradeType, totalPrice, userId } = tradeData
const { stockId, stockName, quantity, tradeType, totalPrice, userId } = tradeData
const stockCollection = await stocksModel.doc(stockId).get()
const stockData = stockCollection.data()
let userBalance = 0
let quantityToUpdate = 0
let stockPriceToBeUpdated = stockData.price
let orderValue = 0
let qtyUserCanPurchase = 0
let qtyUserCanPurchase = quantity
let userStocksQty = 0
let initialStockValue = stockData.price

const { currencies } = await fetchWallet(userId)
const userStocks = await fetchUserStocks(userId, stockId)
const updatedCurrencyData = {}

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

switch (tradeType) {
case 'SELL': {
if (!userStocks.id || userStocks.quantity < quantity) {
return { canUserTrade: false, errorMessage: INSUFFICIENT_QUANTITIES }
}

quantityToUpdate = quantity + stockData.quantity
userBalance = quantity * stockData.price
updatedCurrencyData.dinero = userBalance + currencies.dinero
stockPriceToBeUpdated = getUpdatedPrice(stockData.price)
userBalance = (quantity * stockData.price) + currencies[`${DINERO}`]
userStocksQty = userStocks.quantity - quantity
break
}
case 'BUY': {
qtyUserCanPurchase = Math.floor(totalPrice / stockData.price)
if (qtyUserCanPurchase <= 0 || totalPrice > currencies.dinero) {
if (qtyUserCanPurchase <= 0 || totalPrice > currencies[`${DINERO}`]) {
return { canUserTrade: false, errorMessage: INSUFFICIENT_FUNDS }
}
orderValue = qtyUserCanPurchase * stockData.price
quantityToUpdate = stockData.quantity - qtyUserCanPurchase
userBalance = currencies.dinero - orderValue
updatedCurrencyData.dinero = userBalance
stockPriceToBeUpdated = getUpdatedPrice(stockData.price)
userBalance = currencies[`${DINERO}`] - (qtyUserCanPurchase * stockData.price)
userStocksQty = qtyUserCanPurchase

initialStockValue = stockData.price

if (userStocks.id) {
userStocksQty = userStocks.quantity + qtyUserCanPurchase
initialStockValue = userStocks.initialStockValue
}
break
}
default: {
return { canUserTrade: false, errorMessage: 'Invalid trade type' }
}
}

const orderValue = qtyUserCanPurchase * stockData.price
const stockPriceToBeUpdated = getUpdatedPrice(stockData.price)
updatedCurrencyData[`${DINERO}`] = userBalance

const updatedStockData = {
...stockData,
quantity: quantityToUpdate,
price: stockPriceToBeUpdated
}

// Update user stocks

await updateUserStocks(userId, {
stockId,
stockName,
quantity: userStocksQty,
orderValue: userStocksQty * stockData.price,
initialStockValue
})

// Transaction Log

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

// update user wallet

updateWallet(userId, {
await updateWallet(userId, {
...currencies,
...updatedCurrencyData
})
Expand Down

0 comments on commit 35466aa

Please sign in to comment.