Compare commits

...

1 Commits

  1. 2
      src/shared/reactive.ts
  2. 13
      src/shared/rules.ts
  3. 36
      src/transaction/transaction.controller.spec.ts
  4. 33
      src/transaction/transaction.controller.ts
  5. 8
      src/transaction/transaction.dto.ts

@ -4,7 +4,7 @@ export const promisifyObservable =
<TArgs extends any[], TOutput>(f: (...args: TArgs) => Observable<TOutput>) =>
(...args: TArgs) =>
new Promise<TOutput>((_resolve, _reject) => {
let isCalled = false;
const isCalled = false;
const resolve = (result: TOutput) => {
if (isCalled) {
console.log('observable emits more than once');

@ -6,6 +6,15 @@ export const getMinimumRuleOutput = async <T>(
rules: ((input: T) => RuleResult | Promise<RuleResult>)[],
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));
};

@ -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,
});

@ -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<Transaction, 'base_amount' | 'client_id'>;
type TransactionRuleData = Pick<Transaction, 'base_amount' | 'client_id' | 'date'>;
@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) {

@ -9,9 +9,11 @@ export enum Currency {
EUR = 'EUR',
}
export enum DiscountRuleForClientById {
client_42 = 0.05,
}
export const DISCOUNTED_COMMISSIONS = new Map<number, number>([
[42, 0.05],
[10, 0.02],
[20, 0.01]
]);
export enum DefaultCommissionPercentage {
percentage = 0.5,

Loading…
Cancel
Save