diff --git a/src/shared/reactive.ts b/src/shared/reactive.ts index e3a68a4..4ca6980 100644 --- a/src/shared/reactive.ts +++ b/src/shared/reactive.ts @@ -4,7 +4,7 @@ export const promisifyObservable = (f: (...args: TArgs) => Observable) => (...args: TArgs) => new Promise((_resolve, _reject) => { - let isCalled = false; + const isCalled = false; const resolve = (result: TOutput) => { if (isCalled) { console.log('observable emits more than once'); diff --git a/src/shared/rules.ts b/src/shared/rules.ts index 481e066..57426c9 100644 --- a/src/shared/rules.ts +++ b/src/shared/rules.ts @@ -6,6 +6,15 @@ export const getMinimumRuleOutput = async ( rules: ((input: T) => RuleResult | Promise)[], input: T, ) => { - const results = await Promise.all(rules.map((rule) => rule(input))); - return Math.min(..._.compact(results)); + const results = await Promise.all( + rules.map(async (rule) => { + const result = await rule(input); + if (result === undefined || result === false) { + return null; + } + + return { commission: result }; + }), + ); + return Math.min(..._.compact(results).map(({ commission }) => commission)); }; diff --git a/src/transaction/transaction.controller.spec.ts b/src/transaction/transaction.controller.spec.ts index 6849cb2..1cbfffc 100644 --- a/src/transaction/transaction.controller.spec.ts +++ b/src/transaction/transaction.controller.spec.ts @@ -72,6 +72,7 @@ describe('TransactionController Unit Tests', () => { it('calling applyRules method minimum result of applied rules should be got', async () => { { const result = await transactionController.applyRules({ + date: '2021-01-05', base_amount: 1000, client_id: 1, }); @@ -81,6 +82,7 @@ describe('TransactionController Unit Tests', () => { { const result = await transactionController.applyRules({ + date: '2021-01-05', base_amount: 1, client_id: 1, }); @@ -90,6 +92,37 @@ describe('TransactionController Unit Tests', () => { { const result = await transactionController.applyRules({ + date: '2021-01-01', + base_amount: 1, + client_id: 1, + }); + + expect(result).to.eql(0); + } + + { + const result = await transactionController.applyRules({ + date: '2021-01-05', + base_amount: 1000, + client_id: 20, + }); + + expect(result).to.eql(0.01); + } + + { + const result = await transactionController.applyRules({ + date: '2021-01-05', + base_amount: 1, + client_id: 20, + }); + + expect(result).to.eql(0.01); + } + + { + const result = await transactionController.applyRules({ + date: '2021-01-05', base_amount: 1000, client_id: 42, }); @@ -99,6 +132,7 @@ describe('TransactionController Unit Tests', () => { { const result = await transactionController.applyRules({ + date: '2021-01-05', base_amount: 1, client_id: 42, }); @@ -108,6 +142,7 @@ describe('TransactionController Unit Tests', () => { { const result = await transactionController.applyRules({ + date: '2021-01-05', base_amount: 1000, client_id: 99, }); @@ -117,6 +152,7 @@ describe('TransactionController Unit Tests', () => { { const result = await transactionController.applyRules({ + date: '2021-01-05', base_amount: 1, client_id: 99, }); diff --git a/src/transaction/transaction.controller.ts b/src/transaction/transaction.controller.ts index 959d914..e73bd27 100644 --- a/src/transaction/transaction.controller.ts +++ b/src/transaction/transaction.controller.ts @@ -1,5 +1,5 @@ import { Controller, Post, UsePipes, Body } from '@nestjs/common'; -import _ from 'lodash'; +import _, { endsWith } from 'lodash'; import { BodyValidationPipe } from '../pipes/body.validation.pipe'; import { ExchangeRateService } from '../exchange-rate/exchange-rate.service'; import { promisifyObservable } from '../shared/reactive'; @@ -9,14 +9,14 @@ import { transactionBodySchema } from './transaction.validation'; import { Currency, TransactionInput, - DiscountRuleForClientById, DefaultCommissionPercentage, DefaultCommissionAmount, HighTurnoverDiscount, + DISCOUNTED_COMMISSIONS, } from './transaction.dto'; import { Transaction } from './transaction.entity'; -type TransactionRuleData = Pick; +type TransactionRuleData = Pick; @Controller('transaction') export class TransactionController { @@ -38,11 +38,12 @@ export class TransactionController { getClientDeposit = async (transactionInput: TransactionRuleData) => { try { - const existingTransactions = await this.transactionService.findByClientIdWithinActualMonth( - transactionInput.client_id, - ); + const existingTransactions = + await this.transactionService.findByClientIdWithinActualMonth( + transactionInput.client_id, + ); - return _.sum(existingTransactions.map(t => t.base_amount)); + return _.sum(existingTransactions.map((t) => t.base_amount)); } catch (error) { console.log(error); return 0; @@ -61,8 +62,8 @@ export class TransactionController { }; discountRule(transactionInput: TransactionRuleData) { - return transactionInput.client_id === 42 - ? DiscountRuleForClientById.client_42 + return DISCOUNTED_COMMISSIONS.has(transactionInput.client_id) + ? DISCOUNTED_COMMISSIONS.get(transactionInput.client_id) : false; } @@ -75,14 +76,24 @@ export class TransactionController { : commissionAmount; } + firstDayOfMonthFreeRule(transactionInput: TransactionRuleData) { + if (transactionInput.date.endsWith('-01')) { + return 0; + } + + return undefined; + } + async applyRules(transactionInput: TransactionRuleData) { return getMinimumRuleOutput( - [this.turnoverRule, this.discountRule, this.defaultRule], + [this.turnoverRule, this.discountRule, this.firstDayOfMonthFreeRule, this.defaultRule], transactionInput, ); } - getExchangeRateResponse = promisifyObservable(this.exchangeRateService.convertCurrency.bind(this.exchangeRateService)); + getExchangeRateResponse = promisifyObservable( + this.exchangeRateService.convertCurrency.bind(this.exchangeRateService), + ); async getExchangeRateIfNeeded(transactionInput: TransactionInput) { if (transactionInput.currency === Currency.EUR) { diff --git a/src/transaction/transaction.dto.ts b/src/transaction/transaction.dto.ts index a73e9b8..7af7d5c 100644 --- a/src/transaction/transaction.dto.ts +++ b/src/transaction/transaction.dto.ts @@ -9,9 +9,11 @@ export enum Currency { EUR = 'EUR', } -export enum DiscountRuleForClientById { - client_42 = 0.05, -} +export const DISCOUNTED_COMMISSIONS = new Map([ + [42, 0.05], + [10, 0.02], + [20, 0.01] +]); export enum DefaultCommissionPercentage { percentage = 0.5,