diff --git a/package.json b/package.json index c22a29f..4a87ae7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "db:seed": "prisma db seed" }, "name": "myfin-api", - "version": "1.0.2", + "version": "1.1.0", "description": "NodeJS API for Myfin", "main": "src/server.js", "devDependencies": { diff --git a/src/controllers/investTransactionsController.ts b/src/controllers/investTransactionsController.ts index 8f17ff4..0633e36 100644 --- a/src/controllers/investTransactionsController.ts +++ b/src/controllers/investTransactionsController.ts @@ -1,106 +1,119 @@ -import { NextFunction, Request, Response } from "express"; +import {NextFunction, Request, Response} from "express"; import Logger from "../utils/Logger.js"; import APIError from "../errorHandling/apiError.js"; import CommonsController from "./commonsController.js"; import InvestTransactionsService from "../services/investTransactionsService.js"; import joi from "joi"; -import { MYFIN } from "../consts.js"; +import {MYFIN} from "../consts.js"; // CREATE const createTransactionSchema = joi.object({ - date_timestamp: joi.number().required(), - note: joi.string().allow('').optional(), - total_price: joi.number().required(), - units: joi.number().required(), - fees: joi.number().required(), - asset_id: joi.number().required(), - type: joi.string().allow(MYFIN.INVEST.TRX_TYPE.BUY, MYFIN.INVEST.TRX_TYPE.SELL).required(), + date_timestamp: joi.number().required(), + note: joi.string().allow('').optional(), + total_price: joi.number().required(), + units: joi.number().required(), + fees: joi.number().required(), + asset_id: joi.number().required(), + type: joi.string().allow(MYFIN.INVEST.TRX_TYPE.BUY, MYFIN.INVEST.TRX_TYPE.SELL).required(), + /* SPLIT TRX - FOR DEDUCTED FEES */ + is_split: joi.boolean().default(false), + split_total_price: joi.number().empty('').optional(), + split_units: joi.number().empty('').optional(), + split_note: joi.string().empty('').trim().optional(), + split_type: joi.string().allow(MYFIN.INVEST.TRX_TYPE.BUY, MYFIN.INVEST.TRX_TYPE.SELL, '').optional(), }); const createTransaction = async (req: Request, res: Response, next: NextFunction) => { - try { - const sessionData = await CommonsController.checkAuthSessionValidity(req); - const input = await createTransactionSchema.validateAsync(req.body); - await InvestTransactionsService.createTransaction( - sessionData.userId, - input.asset_id, - input.date_timestamp, - input.note, - input.total_price, - input.units, - input.fees, - input.type - ); - res.json(`Transaction successfully created!`); - } catch (err) { - Logger.addLog(err); - next(err || APIError.internalServerError()); - } + try { + const sessionData = await CommonsController.checkAuthSessionValidity(req); + const input = await createTransactionSchema.validateAsync(req.body); + await InvestTransactionsService.createTransaction( + sessionData.userId, + input.asset_id, + input.date_timestamp, + input.note, + input.total_price, + input.units, + input.fees, + input.type, + input.is_split, + { + totalPrice: input.split_total_price, + units: input.split_units, + type: input.split_type, + note: input.split_note + }, + ); + res.json(`Transaction successfully created!`); + } catch (err) { + Logger.addLog(err); + next(err || APIError.internalServerError()); + } }; // READ const getAllTransactionsForUser = async (req: Request, res: Response, next: NextFunction) => { - try { - const sessionData = await CommonsController.checkAuthSessionValidity(req); - const data = await InvestTransactionsService.getAllTransactionsForUser(sessionData.userId); - res.json(data); - } catch (err) { - Logger.addLog(err); - next(err || APIError.internalServerError()); - } + try { + const sessionData = await CommonsController.checkAuthSessionValidity(req); + const data = await InvestTransactionsService.getAllTransactionsForUser(sessionData.userId); + res.json(data); + } catch (err) { + Logger.addLog(err); + next(err || APIError.internalServerError()); + } }; // UPDATE const updateTransactionSchema = joi.object({ - date_timestamp: joi.number().required(), - note: joi.string().empty('').allow(''), - total_price: joi.number().required(), - units: joi.number().required(), - fees: joi.number().required(), - asset_id: joi.number().required(), - type: joi.string().allow(MYFIN.INVEST.TRX_TYPE.BUY, MYFIN.INVEST.TRX_TYPE.SELL).required(), + date_timestamp: joi.number().required(), + note: joi.string().empty('').allow(''), + total_price: joi.number().required(), + units: joi.number().required(), + fees: joi.number().required(), + asset_id: joi.number().required(), + type: joi.string().allow(MYFIN.INVEST.TRX_TYPE.BUY, MYFIN.INVEST.TRX_TYPE.SELL).required(), }); const updateTransaction = async (req: Request, res: Response, next: NextFunction) => { - try { - const sessionData = await CommonsController.checkAuthSessionValidity(req); - const input = await updateTransactionSchema.validateAsync(req.body); - const trxId = req.params.id; - await InvestTransactionsService.updateTransaction( - sessionData.userId, - BigInt(trxId), - input.asset_id, - input.date_timestamp, - input.note, - input.total_price, - input.units, - input.fees, - input.type - ); - res.json(`Transaction successfully updated!`); - } catch (err) { - Logger.addLog(err); - next(err || APIError.internalServerError()); - } + try { + const sessionData = await CommonsController.checkAuthSessionValidity(req); + const input = await updateTransactionSchema.validateAsync(req.body); + const trxId = req.params.id; + await InvestTransactionsService.updateTransaction( + sessionData.userId, + BigInt(trxId), + input.asset_id, + input.date_timestamp, + input.note, + input.total_price, + input.units, + input.fees, + input.type + ); + res.json(`Transaction successfully updated!`); + } catch (err) { + Logger.addLog(err); + next(err || APIError.internalServerError()); + } }; // DELETE const deleteTransaction = async (req: Request, res: Response, next: NextFunction) => { - try { - const sessionData = await CommonsController.checkAuthSessionValidity(req); - const trxId = req.params.id; - await InvestTransactionsService.deleteTransaction(sessionData.userId, BigInt(trxId)); - res.json(`Transaction successfully deleted!`); - } catch (err) { - Logger.addLog(err); - next(err || APIError.internalServerError()); - } + try { + const sessionData = await CommonsController.checkAuthSessionValidity(req); + const trxId = req.params.id; + await InvestTransactionsService.deleteTransaction(sessionData.userId, BigInt(trxId)); + res.json(`Transaction successfully deleted!`); + } catch (err) { + Logger.addLog(err); + next(err || APIError.internalServerError()); + } }; export default { - getAllTransactionsForUser, - updateTransaction, - createTransaction, - deleteTransaction, + getAllTransactionsForUser, + updateTransaction, + createTransaction, + deleteTransaction, }; diff --git a/src/services/investTransactionsService.ts b/src/services/investTransactionsService.ts index 0511151..0da0130 100644 --- a/src/services/investTransactionsService.ts +++ b/src/services/investTransactionsService.ts @@ -5,6 +5,7 @@ import DateTimeUtils from '../utils/DateTimeUtils.js'; import ConvertUtils from '../utils/convertUtils.js'; import { invest_transactions_type } from '@prisma/client'; import Logger from '../utils/Logger.js'; +import {date} from "joi"; const getAllTransactionsForUser = async (userId: bigint, dbClient = prisma) => dbClient.$queryRaw`SELECT transaction_id, date_timestamp, invest_transactions.type as 'trx_type', invest_assets.type as 'asset_type', note, (total_price/100) as 'total_price', invest_transactions.units, invest_assets_asset_id, name, ticker, broker, invest_assets.asset_id, (fees_taxes / 100) as 'fees_taxes' @@ -83,6 +84,8 @@ const createTransaction = async ( units: number, fees: number, type: invest_transactions_type, + isSplit: boolean, + splitData?: {totalPrice?: number, units?: number, type?: invest_transactions_type, note?: string}, dbClient = undefined ) => { await performDatabaseRequest(async (prismaTx) => { @@ -112,7 +115,7 @@ const createTransaction = async ( DateTimeUtils.getCurrentUnixTimestamp() + 1, prisma ); - Logger.addLog(`Latest snapshot: ${JSON.stringify(latestSnapshot)}`); + //Logger.addLog(`Latest snapshot: ${JSON.stringify(latestSnapshot)}`); await prisma.invest_assets.update({ where: { asset_id: assetId, @@ -121,6 +124,11 @@ const createTransaction = async ( units: latestSnapshot.units, }, }); + + // SPLIT HANDLING + if(isSplit){ + await createTransaction(userId, assetId, dateTimestamp, splitData.note, splitData.totalPrice, splitData.units, 0, splitData.type, false, null); + } }; const deleteTransaction = async (userId: bigint, trxId: bigint, dbClient = undefined) => { diff --git a/src/utils/demoDataManager.ts b/src/utils/demoDataManager.ts index c8d0708..051da9a 100644 --- a/src/utils/demoDataManager.ts +++ b/src/utils/demoDataManager.ts @@ -969,6 +969,8 @@ const createMockAssetTransactions = async (userId: bigint, dbClient = undefined) 1500, 0, invest_transactions_type.B, + false, + null, prismaTx ) ); @@ -983,6 +985,8 @@ const createMockAssetTransactions = async (userId: bigint, dbClient = undefined) 800, 0, invest_transactions_type.B, + false, + null, prismaTx ) ); @@ -997,6 +1001,8 @@ const createMockAssetTransactions = async (userId: bigint, dbClient = undefined) 0.5, 0, invest_transactions_type.B, + false, + null, prismaTx ) ); @@ -1011,6 +1017,8 @@ const createMockAssetTransactions = async (userId: bigint, dbClient = undefined) 2.3, 0, invest_transactions_type.B, + false, + null, prismaTx ) );