From a2e294584ce89835d581c2163984e49893e6c000 Mon Sep 17 00:00:00 2001 From: cavdy Date: Fri, 26 Apr 2019 11:18:15 +0100 Subject: [PATCH] bug(credit transaction accept negative value):credit transaction accept negative value credit transaction is accepting negative value and that is not good [Starts #165623064] --- server/v1/services/auth.js | 408 ++++++++++---------- server/v1/services/transaction.js | 361 +++++++++--------- server/v1/test/transactions.js | 598 ++++++++++++++++-------------- 3 files changed, 706 insertions(+), 661 deletions(-) diff --git a/server/v1/services/auth.js b/server/v1/services/auth.js index 0783121..9af66d8 100644 --- a/server/v1/services/auth.js +++ b/server/v1/services/auth.js @@ -1,192 +1,216 @@ -import bcrypt from 'bcryptjs'; -import dbConnection from '../config/database'; -import UserModel from '../model/users'; -import registrationHelper from '../helper/registrationHelper'; - -const AuthService = { - /** - * Login user - * @constructor - * @param {*} userData - user form data. - * @param {*} token - user's token - */ - async loginUser(userData, token) { - /* eslint max-len: ["error", { "ignoreRegExpLiterals": true }] */ - const emailRegex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,10})$/; - const passwordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // Check if email and password is valid - if (emailRegex.test(userData.email) - && passwordRegex.test(userData.password)) { - // check if email, if it exist get the user data - const emailresponse = await dbConnection - .dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); - if (emailresponse.rows.length > 0) { - // Load hash from your password DB. - const passwordUnhash = bcrypt - .compareSync(userData.password, emailresponse.rows[0].password); - if (passwordUnhash) { - // return users details - const user = new UserModel(); - user.id = emailresponse.rows[0].id; - user.firstName = emailresponse.rows[0].firstname; - user.lastName = emailresponse.rows[0].lastname; - user.email = emailresponse.rows[0].email; - user.token = token; - returnStatus = 201; - returnSuccess = user; - } else { - // else echo incorrect password - returnStatus = 422; - returnError = 'incorrect password'; - } - } else { - returnStatus = 404; - returnError = 'email does not exist'; - } - } else { - const error = []; - if (!emailRegex.test(userData.email)) { - returnStatus = 422; - error.push('invalid email address'); - } - - if (!passwordRegex.test(userData.password)) { - returnStatus = 422; - error - .push('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - } - returnError = error; - } - - - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - /** - * Register user - * @constructor - * @param {*} userData - user form data. - * @param {*} token - user's token - */ - async registerUser(userData, token) { - const returnData = await registrationHelper.registrationHelper(userData); - let returnStatus; let returnSuccess = ''; let returnError = ''; - - if (returnData[0] === true - && returnData[1] === true - && returnData[2] === true - && returnData[3] === true) { - const salt = bcrypt.genSaltSync(10); - const hash = bcrypt.hashSync(userData.password, salt); - userData.type = 'client'; - userData.isAdmin = false; - // checks if email exist - const emailresponse = await dbConnection - .dbConnect('SELECT email FROM users WHERE email=$1', - [userData.email]); - if (emailresponse.rows.length >= 1) { - returnStatus = 409; - returnError = 'email already exist'; - } else { - // email does not exist... you can insert data - const response = await dbConnection - .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', - [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); - if (response.command === 'INSERT') { - const userDbData = await dbConnection - .dbConnect('SELECT * FROM users WHERE email=$1', - [userData.email]); - const user = new UserModel(); - user.id = userDbData.rows[0].id; - user.firstName = userDbData.rows[0].firstname; - user.lastName = userDbData.rows[0].lastname; - user.email = userDbData.rows[0].email; - user.token = token; - returnStatus = 201; - returnSuccess = user; - } - } - } else { - returnStatus = 422; - // eslint-disable-next-line prefer-destructuring - returnError = returnData[4]; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - /** - * Create staffs - * @constructor - * @param {*} userData - user form data. - * @param {*} token - user's token - * @param {*} admin - admin's token - */ - async createStaffs(userData, token, admin) { - const returnData = await registrationHelper.registrationHelper(userData); - let returnStatus; let returnSuccess = ''; let returnError = ''; - - const userDetails = await dbConnection - .dbConnect('SELECT isadmin FROM users WHERE email=$1', [admin.email]); - const { isadmin } = userDetails.rows[0]; - - if (isadmin === true) { - if (returnData[0] === true - && returnData[1] === true - && returnData[2] === true - && returnData[3] === true) { - const salt = bcrypt.genSaltSync(10); - const hash = bcrypt.hashSync(userData.password, salt); - // checks if email exist - const emailresponse = await dbConnection - .dbConnect('SELECT email FROM users WHERE email=$1', - [userData.email]); - if (emailresponse.rows.length >= 1) { - returnStatus = 409; - returnError = 'email already exist'; - } else { - // email does not exist... you can insert data - const response = await dbConnection - .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', - [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); - if (response.command === 'INSERT') { - const userDbData = await dbConnection - .dbConnect('SELECT * FROM users WHERE email=$1', - [userData.email]); - const user = new UserModel(); - user.id = userDbData.rows[0].id; - user.firstName = userDbData.rows[0].firstname; - user.lastName = userDbData.rows[0].lastname; - user.email = userDbData.rows[0].email; - user.token = token; - returnStatus = 201; - returnSuccess = user; - } - } - } else { - returnStatus = 422; - // eslint-disable-next-line prefer-destructuring - returnError = returnData[4]; - } - } else { - returnStatus = 401; - returnError = 'you must be an admin to create staffs'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default AuthService; +import bcrypt from 'bcryptjs'; +import dbConnection from '../config/database'; +import UserModel from '../model/users'; +import registrationHelper from '../helper/registrationHelper'; + +const AuthService = { + /** + * Login user + * @constructor + * @param {*} userData - user form data. + * @param {*} token - user's token + */ + async loginUser(userData, token) { + /* eslint max-len: ["error", { "ignoreRegExpLiterals": true }] */ + const emailRegex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,10})$/; + const passwordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // Check if email and password is valid + if (emailRegex.test(userData.email) + && passwordRegex.test(userData.password)) { + // check if email, if it exist get the user data + const emailresponse = await dbConnection + .dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); + if (emailresponse.rows.length > 0) { + // Load hash from your password DB. + const passwordUnhash = bcrypt + .compareSync(userData.password, emailresponse.rows[0].password); + if (passwordUnhash) { + // return users details + const user = new UserModel(); + user.id = emailresponse.rows[0].id; + user.firstName = emailresponse.rows[0].firstname; + user.lastName = emailresponse.rows[0].lastname; + user.email = emailresponse.rows[0].email; + user.token = token; + returnStatus = 201; + returnSuccess = user; + } else { + // else echo incorrect password + returnStatus = 422; + returnError = 'incorrect password'; + } + } else { + returnStatus = 404; + returnError = 'email does not exist'; + } + } else { + const error = []; + if (!emailRegex.test(userData.email)) { + returnStatus = 422; + error.push('invalid email address'); + } + + if (!passwordRegex.test(userData.password)) { + returnStatus = 422; + error + .push('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + } + returnError = error; + } + + + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Register user + * @constructor + * @param {*} userData - user form data. + * @param {*} token - user's token + */ + async registerUser(userData, token) { + const returnData = await registrationHelper.registrationHelper(userData); + let returnStatus; let returnSuccess = ''; let returnError = ''; + const whiteSpaces = /\s/g; + + let email; + let fname; + let lname; + let password; + + // strip spaces + if (typeof userData.email !== 'undefined') { + email = userData.email.replace(whiteSpaces, ''); + email = userData.email.trim(); + } + + if (typeof userData.firstName !== 'undefined') { + fname = userData.firstName.replace(whiteSpaces, ''); + fname = userData.firstName.trim(); + } + + if (typeof userData.lastName !== 'undefined') { + lname = userData.lastName.replace(whiteSpaces, ''); + lname = userData.lastName.trim(); + } + + if (typeof userData.password !== 'undefined') { + password = userData.password.replace(whiteSpaces, ''); + password = userData.password.trim(); + } + + if (returnData[0] === true + && returnData[1] === true + && returnData[2] === true + && returnData[3] === true) { + const salt = bcrypt.genSaltSync(10); + const hash = bcrypt.hashSync(password, salt); + userData.type = 'client'; + userData.isAdmin = false; + // checks if email exist + const emailresponse = await dbConnection + .dbConnect('SELECT email FROM users WHERE email=$1', + [email]); + if (emailresponse.rows.length >= 1) { + returnStatus = 409; + returnError = 'email already exist'; + } else { + // email does not exist... you can insert data + const response = await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6) RETURNING id, email, firstname, lastname, password, type, isadmin', + [email, fname, lname, hash, userData.type, userData.isAdmin]); + if (response.command === 'INSERT') { + const user = new UserModel(); + user.id = response.rows[0].id; + user.firstName = response.rows[0].firstname; + user.lastName = response.rows[0].lastname; + user.email = response.rows[0].email; + user.token = token; + returnStatus = 201; + returnSuccess = user; + } + } + } else { + returnStatus = 422; + // eslint-disable-next-line prefer-destructuring + returnError = returnData[4]; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Create staffs + * @constructor + * @param {*} userData - user form data. + * @param {*} token - user's token + * @param {*} admin - admin's token + */ + async createStaffs(userData, token, admin) { + const returnData = await registrationHelper.registrationHelper(userData); + let returnStatus; let returnSuccess = ''; let returnError = ''; + + const userDetails = await dbConnection + .dbConnect('SELECT isadmin FROM users WHERE email=$1', [admin.email]); + const { isadmin } = userDetails.rows[0]; + + if (isadmin === true) { + if (returnData[0] === true + && returnData[1] === true + && returnData[2] === true + && returnData[3] === true) { + const salt = bcrypt.genSaltSync(10); + const hash = bcrypt.hashSync(userData.password, salt); + // checks if email exist + const emailresponse = await dbConnection + .dbConnect('SELECT email FROM users WHERE email=$1', + [userData.email]); + if (emailresponse.rows.length >= 1) { + returnStatus = 409; + returnError = 'email already exist'; + } else { + // email does not exist... you can insert data + const response = await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); + if (response.command === 'INSERT') { + const userDbData = await dbConnection + .dbConnect('SELECT * FROM users WHERE email=$1', + [userData.email]); + const user = new UserModel(); + user.id = userDbData.rows[0].id; + user.firstName = userDbData.rows[0].firstname; + user.lastName = userDbData.rows[0].lastname; + user.email = userDbData.rows[0].email; + user.token = token; + returnStatus = 201; + returnSuccess = user; + } + } + } else { + returnStatus = 422; + // eslint-disable-next-line prefer-destructuring + returnError = returnData[4]; + } + } else { + returnStatus = 401; + returnError = 'you must be an admin to create staffs'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, +}; + +export default AuthService; diff --git a/server/v1/services/transaction.js b/server/v1/services/transaction.js index b82101d..b7d055e 100644 --- a/server/v1/services/transaction.js +++ b/server/v1/services/transaction.js @@ -1,182 +1,179 @@ -/* eslint-disable no-param-reassign */ -import dbConnection from '../config/database'; -import TransactionModel from '../model/Transaction'; - -const TransactionService = { - - /** - * Debit Transaction - * @constructor - * @param {*} accountNumber - account number. - * @param {*} loggedInUser - logged in user - * @param {*} transactionData - transaction data - */ - async debitTransaction(accountNumber, loggedInUser, transactionData) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // check the users table - const userDetails = await dbConnection - .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', - [loggedInUser.email]); - const { id, type, isadmin } = userDetails.rows[0]; - - // checks if logged in user is an admin or staff - if (type === 'staff' || isadmin === true) { - const date = new Date(); - const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; - - // pull accountnumber details from database - const accountDbData = await dbConnection - .dbConnect( - 'SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', - [accountNumber] - ); - const { accountnumber, balance } = accountDbData.rows[0]; - - // check if a string - const checkForDigit = /^-?\d+\.?\d*$/; - if (checkForDigit.test(transactionData.amount)) { - // substract the passed in amount from the current balance - const newBalance = balance - transactionData.amount; - - // check if account balance is zero - if (newBalance < 0) { - returnStatus = 422; - returnError = 'Sorry this account is very low and can\'t be debited'; - } else { - const transactionDbData = await dbConnection - .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7)', - [createdOn, 'debit', accountnumber, id, transactionData.amount, balance, newBalance]); - if (transactionDbData.command === 'INSERT') { - // get the data from transaction - const accountData = await dbConnection - .dbConnect('SELECT * FROM transactions WHERE accountnumber=$1', - [accountNumber]); - // update the account table - const acBalance = await dbConnection - .dbConnect( - 'UPDATE accounts SET balance=$1 WHERE accountnumber=$2 RETURNING balance', - [newBalance, accountNumber] - ); - const transaction = new TransactionModel(); - transaction.transactionId = accountData.rows[0].id; - transaction.accountNumber = accountData.rows[0].accountnumber; - transaction.amount = accountData.rows[0].amount; - transaction.cashier = accountData.rows[0].cashier; - transaction.transactionType = accountData.rows[0].type; - transaction.accountBalance = acBalance.rows[0].balance; - returnStatus = 201; - returnSuccess = transaction; - } - } - } else { - returnStatus = 422; - returnError = 'please numbers only'; - } - } else { - returnStatus = 401; - returnError = 'You must be a staff or admin to perform this transaction'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - /** - * Get specific transaction - * @constructor - * @param {*} transactionId - transaction id. - */ - async getSpecificTransaction(transactionId) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - const userTransaction = await dbConnection - .dbConnect('SELECT * from transactions WHERE id=$1', [transactionId]); - if (userTransaction.rows.length > 0) { - returnStatus = 200; - returnSuccess = userTransaction.rows; - } else { - returnStatus = 404; - returnError = 'no transaction found'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - /** - * Credit Transaction - * @constructor - * @param {*} accountNumber - account number. - * @param {*} loggedInUser - logged in user - * @param {*} transactionData - transaction data - */ - async creditTransaction(accountNumber, loggedInUser, transactionData) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // check the users table - const userDetails = await dbConnection - .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', - [loggedInUser.email]); - const { id, type, isadmin } = userDetails.rows[0]; - - // checks if logged in user is an admin or staff - if (type === 'staff' || isadmin === true) { - const date = new Date(); - const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; - - // pull accountnumber details from database - const accountDbData = await dbConnection - .dbConnect( - 'SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', - [accountNumber] - ); - const { accountnumber, balance } = accountDbData.rows[0]; - - // check if a string - const checkForDigit = /^-?\d+\.?\d*$/; - if (checkForDigit.test(transactionData.amount)) { - // add the passed in amount from the current balance - const newBalance = balance + transactionData.amount; - const transactionDbData = await dbConnection - .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7)', - [createdOn, 'credit', accountnumber, id, transactionData.amount, balance, newBalance]); - if (transactionDbData.command === 'INSERT') { - // get the data from transaction - const accountData = await dbConnection - .dbConnect('SELECT * FROM transactions WHERE accountnumber=$1', - [accountNumber]); - // update the account table - const acBalance = await dbConnection - .dbConnect('UPDATE accounts SET balance=$1 WHERE accountnumber=$2 RETURNING balance', - [newBalance, accountNumber]); - const transaction = new TransactionModel(); - transaction.transactionId = accountData.rows[0].id; - transaction.accountNumber = accountData.rows[0].accountnumber; - transaction.amount = accountData.rows[0].amount; - transaction.cashier = accountData.rows[0].cashier; - transaction.transactionType = accountData.rows[0].type; - transaction.accountBalance = acBalance.rows[0].balance; - returnStatus = 201; - returnSuccess = transaction; - } - } else { - returnStatus = 422; - returnError = 'please numbers only'; - } - } else { - returnStatus = 401; - returnError = 'You must be a staff or admin to perform this transaction'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default TransactionService; +/* eslint-disable no-param-reassign */ +import dbConnection from '../config/database'; +import TransactionModel from '../model/Transaction'; + +const TransactionService = { + + /** + * Debit Transaction + * @constructor + * @param {*} accountNumber - account number. + * @param {*} loggedInUser - logged in user + * @param {*} transactionData - transaction data + */ + async debitTransaction(accountNumber, loggedInUser, transactionData) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // check the users table + const userDetails = await dbConnection + .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', + [loggedInUser.email]); + const { id, type, isadmin } = userDetails.rows[0]; + + // checks if logged in user is an admin or staff + if (type === 'staff' || isadmin === true) { + const date = new Date(); + const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; + + // pull accountnumber details from database + const accountDbData = await dbConnection + .dbConnect( + 'SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', + [accountNumber] + ); + const { accountnumber, balance } = accountDbData.rows[0]; + + // check if a string + const checkForDigit = /^-?\d+\.?\d*$/; + if (checkForDigit.test(transactionData.amount)) { + // substract the passed in amount from the current balance + const newBalance = balance - transactionData.amount; + + // check if account balance is zero + if (newBalance < 0) { + returnStatus = 422; + returnError = 'Sorry this account is very low and can\'t be debited'; + } else { + const transactionDbData = await dbConnection + .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7) RETURNING id, accountnumber, amount, cashier, type', + [createdOn, 'debit', accountnumber, id, transactionData.amount, balance, newBalance]); + if (transactionDbData.command === 'INSERT') { + // update the account table + const acBalance = await dbConnection + .dbConnect( + 'UPDATE accounts SET balance=$1 WHERE accountnumber=$2 RETURNING balance', + [newBalance, accountNumber] + ); + const transaction = new TransactionModel(); + transaction.transactionId = transactionDbData.rows[0].id; + transaction.accountNumber = transactionDbData.rows[0].accountnumber; + transaction.amount = transactionDbData.rows[0].amount; + transaction.cashier = transactionDbData.rows[0].cashier; + transaction.transactionType = transactionDbData.rows[0].type; + transaction.accountBalance = acBalance.rows[0].balance; + returnStatus = 201; + returnSuccess = transaction; + } + } + } else { + returnStatus = 422; + returnError = 'please numbers only'; + } + } else { + returnStatus = 401; + returnError = 'You must be a staff or admin to perform this transaction'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Get specific transaction + * @constructor + * @param {*} transactionId - transaction id. + */ + async getSpecificTransaction(transactionId) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + const userTransaction = await dbConnection + .dbConnect('SELECT * from transactions WHERE id=$1', [transactionId]); + if (userTransaction.rows.length > 0) { + returnStatus = 200; + returnSuccess = userTransaction.rows; + } else { + returnStatus = 404; + returnError = 'no transaction found'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Credit Transaction + * @constructor + * @param {*} accountNumber - account number. + * @param {*} loggedInUser - logged in user + * @param {*} transactionData - transaction data + */ + async creditTransaction(accountNumber, loggedInUser, transactionData) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // check the users table + const userDetails = await dbConnection + .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', + [loggedInUser.email]); + const { id, type, isadmin } = userDetails.rows[0]; + + // checks if logged in user is an admin or staff + if (type === 'staff' || isadmin === true) { + const date = new Date(); + const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; + + // pull accountnumber details from database + const accountDbData = await dbConnection + .dbConnect( + 'SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', + [accountNumber] + ); + const { accountnumber, balance } = accountDbData.rows[0]; + + // check if a string + const checkForDigit = /^-?\d+\.?\d*$/; + if (checkForDigit.test(transactionData.amount)) { + if (transactionData.amount <= 0) { + returnStatus = 422; + returnError = 'please credit an account with positive value'; + } else { + // add the passed in amount from the current balance + const newBalance = balance + transactionData.amount; + const transactionDbData = await dbConnection + .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7) RETURNING id, accountnumber, amount, cashier, type', + [createdOn, 'credit', accountnumber, id, transactionData.amount, balance, newBalance]); + if (transactionDbData.command === 'INSERT') { + // update the account table + const acBalance = await dbConnection + .dbConnect('UPDATE accounts SET balance=$1 WHERE accountnumber=$2 RETURNING balance', + [newBalance, accountNumber]); + const transaction = new TransactionModel(); + transaction.transactionId = transactionDbData.rows[0].id; + transaction.accountNumber = transactionDbData.rows[0].accountnumber; + transaction.amount = transactionDbData.rows[0].amount; + transaction.cashier = transactionDbData.rows[0].cashier; + transaction.transactionType = transactionDbData.rows[0].type; + transaction.accountBalance = acBalance.rows[0].balance; + returnStatus = 201; + returnSuccess = transaction; + } + } + } else { + returnStatus = 422; + returnError = 'please numbers only'; + } + } else { + returnStatus = 401; + returnError = 'You must be a staff or admin to perform this transaction'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, +}; + +export default TransactionService; diff --git a/server/v1/test/transactions.js b/server/v1/test/transactions.js index 95cb59f..18318cc 100644 --- a/server/v1/test/transactions.js +++ b/server/v1/test/transactions.js @@ -1,287 +1,311 @@ -import chaiHttp from 'chai-http'; -import chai, { expect } from 'chai'; - -import app from '../app'; - -chai.use(chaiHttp); - -describe('Testing Transactions Controller', () => { - describe('Testing transactions controller', () => { - it( - 'transactions should have all required propertise', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/credit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(201); - expect(res.body.data).to.have.property('transactionId'); - expect(res.body.data).to.have.property('accountNumber'); - expect(res.body.data).to.have.property('cashier'); - expect(res.body.data).to.have.property('amount'); - expect(res.body.data).to.have.property('transactionType'); - expect(res.body.data).to.have.property('accountBalance'); - }, - ); - - it( - 'only admin and staffs should perform debit transaction', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/credit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 1000, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(401); - expect(res.body.data) - .to.equal('You must be a staff or admin to perform this transaction'); - }, - ); - - it( - 'should not perform debit transaction when on zero balance', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3404704124/debit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(422); - expect(res.body.data) - .to.equal('Sorry this account is very low and can\'t be debited'); - }, - ); - - it( - 'admin and staff can debit account', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/debit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(201); - expect(res.body.data).to.have.property('transactionId'); - expect(res.body.data).to.have.property('accountNumber'); - expect(res.body.data).to.have.property('amount'); - expect(res.body.data).to.have.property('cashier'); - expect(res.body.data).to.have.property('transactionType'); - expect(res.body.data).to.have.property('accountBalance'); - }, - ); - - it( - 'transaction should have these propertise', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/transactions/4') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(200); - expect(res.body.data[0]).to.have.property('id'); - expect(res.body.data[0]).to.have.property('createdon'); - expect(res.body.data[0]).to.have.property('type'); - expect(res.body.data[0]).to.have.property('accountnumber'); - expect(res.body.data[0]).to.have.property('cashier'); - expect(res.body.data[0]).to.have.property('amount'); - expect(res.body.data[0]).to.have.property('oldbalance'); - expect(res.body.data[0]).to.have.property('newbalance'); - }, - ); - - it( - 'only admin and staffs should perform credit transaction', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/credit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(401); - expect(res.body.data) - .to.equal('You must be a staff or admin to perform this transaction'); - }, - ); - - it( - 'only admin and staffs should perform debit transaction', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/debit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(401); - expect(res.body.data) - .to.equal('You must be a staff or admin to perform this transaction'); - }, - ); - - it( - 'should not debit when not number', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/debit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 'fffff', - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(422); - expect(res.body.data) - .to.equal('please numbers only'); - }, - ); - - it( - 'should not credit when not number', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/credit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 'fffff', - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(422); - expect(res.body.data) - .to.equal('please numbers only'); - }, - ); - - it( - 'admin and staffs can perform credit transaction', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/credit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(201); - expect(res.body.data).to.have.property('transactionId'); - expect(res.body.data).to.have.property('accountNumber'); - expect(res.body.data).to.have.property('amount'); - expect(res.body.data).to.have.property('cashier'); - expect(res.body.data).to.have.property('transactionType'); - expect(res.body.data).to.have.property('accountBalance'); - }, - ); - - it( - 'check if transaction id exist', - async () => { - const signinUrl = '/api/v1/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/transactions/6000') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(404); - expect(res.body.data).to.equal('no transaction found'); - }, - ); - }); -}); +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing Transactions Controller', () => { + describe('Testing transactions controller', () => { + it( + 'transactions should have all required propertise', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('transactionId'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('cashier'); + expect(res.body.data).to.have.property('amount'); + expect(res.body.data).to.have.property('transactionType'); + expect(res.body.data).to.have.property('accountBalance'); + }, + ); + + it( + 'only admin and staffs should perform debit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 1000, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You must be a staff or admin to perform this transaction'); + }, + ); + + it( + 'should not perform debit transaction when on zero balance', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3404704124/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('Sorry this account is very low and can\'t be debited'); + }, + ); + + it( + 'admin and staff can debit account', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('transactionId'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('amount'); + expect(res.body.data).to.have.property('cashier'); + expect(res.body.data).to.have.property('transactionType'); + expect(res.body.data).to.have.property('accountBalance'); + }, + ); + + it( + 'transaction should have these propertise', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/transactions/4') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('cashier'); + expect(res.body.data[0]).to.have.property('amount'); + expect(res.body.data[0]).to.have.property('oldbalance'); + expect(res.body.data[0]).to.have.property('newbalance'); + }, + ); + + it( + 'only admin and staffs should perform credit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You must be a staff or admin to perform this transaction'); + }, + ); + + it( + 'only admin and staffs should perform debit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You must be a staff or admin to perform this transaction'); + }, + ); + + it( + 'should not debit when not number', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 'fffff', + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('please numbers only'); + }, + ); + + it( + 'should not credit when not number', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 'fffff', + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('please numbers only'); + }, + ); + + it( + 'should not credit when negative number', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: -500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('please credit an account with positive value'); + }, + ); + + it( + 'admin and staffs can perform credit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('transactionId'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('amount'); + expect(res.body.data).to.have.property('cashier'); + expect(res.body.data).to.have.property('transactionType'); + expect(res.body.data).to.have.property('accountBalance'); + }, + ); + + it( + 'check if transaction id exist', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/transactions/6000') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no transaction found'); + }, + ); + }); +});