diff --git a/package-lock.json b/package-lock.json index 87dee56..af569e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "axios": "0.26.1", "chai-as-promised": "^7.1.1", "joi": "17.6.0", + "lodash": "^4.17.21", "reflect-metadata": "0.1.13", "rimraf": "3.0.2", "rxjs": "7.5.5", @@ -29,6 +30,7 @@ "@types/express": "4.17.13", "@types/jest": "27.4.1", "@types/joi": "17.2.3", + "@types/lodash": "^4.14.202", "@types/node": "16.0.0", "@types/supertest": "2.0.11", "@typescript-eslint/eslint-plugin": "5.0.0", @@ -2157,6 +2159,12 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -7032,8 +7040,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -12381,6 +12388,12 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -16120,8 +16133,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.merge": { "version": "4.6.2", diff --git a/package.json b/package.json index 9817c1e..255b4d7 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "axios": "0.26.1", "chai-as-promised": "^7.1.1", "joi": "17.6.0", + "lodash": "^4.17.21", "reflect-metadata": "0.1.13", "rimraf": "3.0.2", "rxjs": "7.5.5", @@ -42,6 +43,7 @@ "@types/express": "4.17.13", "@types/jest": "27.4.1", "@types/joi": "17.2.3", + "@types/lodash": "^4.14.202", "@types/node": "16.0.0", "@types/supertest": "2.0.11", "@typescript-eslint/eslint-plugin": "5.0.0", diff --git a/src/transaction/transaction.controller.spec.ts b/src/transaction/transaction.controller.spec.ts index a8bf324..3fb3aa1 100644 --- a/src/transaction/transaction.controller.spec.ts +++ b/src/transaction/transaction.controller.spec.ts @@ -20,7 +20,7 @@ describe('TransactionController Unit Tests', () => { Promise.reject(new Error('DatabaseNotReachable')), ), findByClientIdWithinActualMonth: jest.fn((clientId) => { - if (clientId === 42) { + if (clientId === 42 || clientId === 99) { return [{ base_amount: 1500 }]; } return []; @@ -70,19 +70,95 @@ describe('TransactionController Unit Tests', () => { }); it('calling applyRules method minimum result of applied rules should be got', async () => { - const mockTransactionInput = { - date: '2021-01-05', - base_amount: 1000.0, - currency: 'EUR', - client_id: 1, - }; + { + const result = await transactionController.applyRules( + [ + transactionController.discountRule, + transactionController.turnoverRule, + ], + { + base_amount: 1000, + client_id: 1, + }, + ); - const result = await transactionController.applyRules( - [transactionController.discountRule, transactionController.turnoverRule], - mockTransactionInput, - ); + expect(result).to.eql(5); + } + + { + const result = await transactionController.applyRules( + [ + transactionController.discountRule, + transactionController.turnoverRule, + ], + { + base_amount: 1, + client_id: 1, + }, + ); + + expect(result).to.eql(0.05); + } + + { + const result = await transactionController.applyRules( + [ + transactionController.discountRule, + transactionController.turnoverRule, + ], + { + base_amount: 1000, + client_id: 42, + }, + ); + + expect(result).to.eql(0.03); + } + + { + const result = await transactionController.applyRules( + [ + transactionController.discountRule, + transactionController.turnoverRule, + ], + { + base_amount: 1, + client_id: 42, + }, + ); + + expect(result).to.eql(0.03); + } + + { + const result = await transactionController.applyRules( + [ + transactionController.discountRule, + transactionController.turnoverRule, + ], + { + base_amount: 1000, + client_id: 99, + }, + ); + + expect(result).to.eql(0.03); + } + + { + const result = await transactionController.applyRules( + [ + transactionController.discountRule, + transactionController.turnoverRule, + ], + { + base_amount: 1, + client_id: 99, + }, + ); - expect(result).to.eql(5); + expect(result).to.eql(0.03); + } }); it('calling commission method correct commission should be got', async () => { diff --git a/src/transaction/transaction.controller.ts b/src/transaction/transaction.controller.ts index 740794d..0a8c5ca 100644 --- a/src/transaction/transaction.controller.ts +++ b/src/transaction/transaction.controller.ts @@ -1,5 +1,9 @@ import { Controller, Post, UsePipes, Body } from '@nestjs/common'; -import { ExchangeRateInput, ExchangeRateResponse } from 'src/exchange-rate/exchange-rate.dto'; +import _ from 'lodash'; +import { + ExchangeRateInput, + ExchangeRateResponse, +} from 'src/exchange-rate/exchange-rate.dto'; import { ExchangeRateService } from 'src/exchange-rate/exchange-rate.service'; import { TransactionService } from './transaction.service'; import { transactionBodySchema } from './transaction.validation'; @@ -31,12 +35,8 @@ export class TransactionController { return JSON.stringify({ amount: transactionInput.currency !== Currency.EUR - ? parseFloat( - await this.getAmountWithExchange(transactionInput), - ).toFixed(2) - : parseFloat( - await this.getAmountWithoutExchange(transactionInput), - ).toFixed(2), + ? (await this.getAmountWithExchange(transactionInput)).toFixed(2) + : (await this.getAmountWithoutExchange(transactionInput)).toFixed(2), currency: Currency.EUR, }); } @@ -96,19 +96,10 @@ export class TransactionController { ) => number | false | undefined | Promise)[], transactionInput: TransactionRuleData, ) { - let commissionAmount; - for (let i = 0; i < rules.length; i++) { - const ruleResult = await rules[i](transactionInput); - if (ruleResult) { - commissionAmount = ruleResult; - break; - } else { - continue; - } - } - return commissionAmount - ? commissionAmount - : this.defaultRule(transactionInput); + const commissions = await Promise.all( + [...rules, this.defaultRule].map((rule) => rule(transactionInput)), + ); + return Math.min(..._.compact(commissions)); } getExchangeRate(exchangeRateInput: ExchangeRateInput) {