Skip to content

Commit

Permalink
currency (dollars, euro)
Browse files Browse the repository at this point in the history
  • Loading branch information
qertis committed Oct 21, 2017
1 parent f51a18b commit 3f8ecf0
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 78 deletions.
14 changes: 7 additions & 7 deletions src/events/count.event.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
const dbEntries = require('../database/bot.database');
const sessions = require('../services/session.service');
const bot = require('./../config/bot.config');
const {getMoney, TYPES} = require('../services/calc.service');
const {getMoney, getFormatMoney, TYPES} = require('../services/calc.service');
const {decodeRows} = require('./../services/format.service');
/**
* @param startTime {String}
* @param endTime {String}
* @param money {String}
* @param money {Object}
* @return {string}
*/
const formatResponse = ({startTime, endTime, money}) => {
return ${startTime} по ${endTime}:\n*${money}*`;
const formatMoney = getFormatMoney(money);
return ${startTime} по ${endTime}:\n` +
`*${formatMoney.rub}*\n` +
`*${formatMoney.eur}*\n` +
`*${formatMoney.usd}*`;
};
/***
* @example /count - -> выведет сколько всего потрачено
Expand All @@ -29,12 +33,10 @@ const onCount = async ({chat, from}, match) => {
const getAllSpentMoney = () => getMoney({
texts: entries,
type: TYPES.allSpent,
local,
});
const getReceivedMoney = () => getMoney({
texts: entries,
type: TYPES.allReceived,
local,
});
const getResult = async (data, params) => {
switch (data) {
Expand All @@ -60,8 +62,6 @@ const onCount = async ({chat, from}, match) => {
await bot.sendMessage(chatId, 'No data');
return;
}
// TODO: на будущее дать выбор формату финансов (рубли, евро, доллары)
const local = 'RUB';
const entries = objRows.map(row => row.entry);
const startTime = objRows[0].date.toLocaleDateString();
const endTime = objRows[objRows.length - 1].date.toLocaleDateString();
Expand Down
172 changes: 124 additions & 48 deletions src/services/calc.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,56 +9,81 @@ const regExpMonthNumber = /^\d+ (?=Января|Февраля|Марта|Апр
const regExpYear = /\d+ (?=Понедельник|Вторник|Среда|Четверг|Пятница|Суббота|Воскресенье)/gi;
const regExpWeight = /вес.\d+(,|\.).+/gim;
const regExpNumbers = /^.+ ?(\d+)/gim;
const regExpRubles = /р|руб|₽| р| ₽| руб| рублей/im;
const regExpMyZP = /(зп|зарплата|получил|получено|заработано|заработал)(\s?)+\d/gim;
const regExpMyZP = /(зп|зарплата|получил|получено|заработано|заработал)(\s?)+\d|\$|€/gim;

const onlyNumberString = 'A-Za-z0-9_.,';
const rublesString = ' рублей|рублей|рублей | руб|руб|руб | р|р|р | ₽|₽|₽ | rub|rub|rub ';
const regExpRubles = new RegExp(rublesString);
const euroString = ' евро|евро| €|€|€ ';
const regExpEuro = new RegExp(euroString);
const usdString = ' долларов|долларов|долларов | доллар|доллар|доллар | dollars|dollars|dollars |\\$';
const regExpUsd = new RegExp(usdString);

const [EUR, RUB, USD] = ['eur', 'rub', 'usd',];
const defaultOut = Object.freeze({[EUR]: 0, [RUB]: 0, [USD]: 0,});
/**
* @param text {String}
* @return {Array}
*/
const splitText = text => (typeof text === 'string' ? text.split('\n') : []);
/**
* Локализуем
* @param money {Object}
* @returns {String}
*/
const getFormatMoney = (money) => {
const CURRENCY = 'currency';
return {
[EUR]: new Intl
.NumberFormat('de-DE', {
'style': CURRENCY,
'currency': 'EUR',
'minimumFractionDigits': 2,
'maximumFractionDigits': 2,
})
.format(money[EUR]),
[RUB]: new Intl
.NumberFormat('ru-RU', {
'style': CURRENCY,
'currency': 'RUB',
'minimumFractionDigits': 2,
'maximumFractionDigits': 2,
})
.format(money[RUB]),
[USD]: new Intl
.NumberFormat('en-US', {
'style': CURRENCY,
'currency': 'USD',
'minimumFractionDigits': 2,
'maximumFractionDigits': 2,
})
.format(money[USD]),
};
};
/**
* @param texts {Array}
* @param local {String}
* @param type {Number}
* @return {String}
* @return {Object}
*/
const getMoney = ({texts, type, local}) => {
const getMoney = ({texts, type,}) => {
if (!Array.isArray(texts)) {
throw 'Not valid argument';
}
/**
* @return {Number}
*/
const allSpentMoney = (() => {
if (texts.length) {
return texts.reduce((acc, raw) => acc.concat(...splitText(raw)), [])
.map(text => formatType(text, type))
.map(text => calcMoney(text))
.reduce((acc, money) => acc + money);
} else {
return 0;
}
})();
switch (local) {
case 'RUB': {
return getSumRub(allSpentMoney);
}
default: {
return allSpentMoney;
}
if (texts.length) {
return texts
.reduce((acc, raw) => acc.concat(...splitText(raw)), [])
.map(text => formatType(text, type))
.map(text => calcMoney(text))
.reduce((acc, money) => {
acc[EUR] += money.eur;
acc[RUB] += money.rub;
acc[USD] += money.usd;
return acc;
}, Object.assign({}, defaultOut));
} else {
return defaultOut;
}
};
/**
* Локализуем сумму в рублях
* @param money {Number}
* @returns {String}
*/
const getSumRub = money => {
const options = {style: 'currency', currency: 'RUB'};
const numberFormat = new Intl.NumberFormat('ru-RU', options);
return numberFormat.format(money);
};
/**
* @param str {String}
* @param type {Number}
Expand Down Expand Up @@ -98,47 +123,98 @@ const formatType = (str, type) => {
};
/**
* @param str {String}
* @returns {number}
* @returns {Object}
*/
const calcMoney = (str) => {
if (str.length <= 1) {
return 0;
return defaultOut;
}
// TODO: ничего не находит в случае когда str === '$100'
// явно объявляю доллары
str = str.replace(/\$.+/, (str) => {
return str.substr(1) + 'долларов';
});

const numbers = str.match(str.match(regExpNumbers));
if (!(numbers && numbers.length)) {
return 0;
return defaultOut;
}
return splitText(numbers.input)
.reduce((acc, text) => (acc += getAllSum(text)), 0);
.reduce((acc, text) => {
const money = getAllSum(text);
acc[RUB] += money.rub;
acc[EUR] += money.eur;
acc[USD] += money.usd;
return acc;
}, Object.assign({}, defaultOut));
};
/**
* @param str {String}
* @return {number}
*/
const cleanDirtyNumberString = (str) => {
const [val] = str
.replace(regExpEuro, '')
.replace(regExpUsd, '')
.replace(regExpRubles, '')
.replace(/\.$/, '')
.match(/\d+$|\d+\.\d+/, '') || [0];
return Number.parseFloat(val);
};
/**
* @param numbers {String}
* @returns {number}
* @returns {Object}
*/
const getAllSum = (numbers) => {
let out = numbers.replace(/^\D+/, '');
out = out.replace(regExpRubles, '');
out = out.replace(/к/i, () => '000');
// TODO: не обрабатывается случай `Игра престолов 1серия` => добавляется 1
// Отсеивание int+float значений
if (out.match(/^\d\.?(\d\d)?/) > '0') {
const outArray = out.replace(/[^A-Za-z0-9_.,]/gi, ',').split(',');
const res = outArray
const regexp = new RegExp(
'[^' + onlyNumberString + rublesString + euroString + usdString + ']', 'gim'
);
const outArray = out
.replace(regexp, ',')
// числа без знаков становятся рублями
.replace(/\d+\.?(\d\d)?(\s|$)/, (str, arg2, arg3, index, all) => {
const start = index + str.length;
const end = index + 6 + str.length;
const nextStr = all.substr(start, end);
if (regExpUsd.test(nextStr)) {
return str.trimRight() + 'долларов ';
} else if(regExpEuro.test(nextStr)) {
return str.trimRight() + 'евро ';
} else {
return str.trimRight() + 'рублей ';
}
})
.replace(/\s/g, ',')
.split(',');
return outArray
.filter(temp => {
if (!temp.length || Number.isNaN(Number(temp))) {
if (!temp.length || !(/\d/.test(temp)) /*|| Number.isNaN(Number(temp))*/) {
return false;
}
return true;
})
.reduce((acc, str) => (acc += Number.parseFloat(str)), 0)
.toFixed(2);
return Number(res);
.reduce((acc, str) => {
if (regExpUsd.test(str)) {
acc[USD] += cleanDirtyNumberString(str);
} else if(regExpEuro.test(str)) {
acc[EUR] += cleanDirtyNumberString(str);
} else {
acc[RUB] += cleanDirtyNumberString(str);
}
return acc;
}, Object.assign({}, defaultOut));
} else {
return 0;
return defaultOut;
}
};

module.exports = {
getMoney,
getFormatMoney,
TYPES,
};
89 changes: 66 additions & 23 deletions tests/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,53 +114,96 @@ test('session', t => {
});

test('money', t => {
const {getMoney, TYPES} = require('../src/services/calc.service');
const {getMoney, getFormatMoney, TYPES} = require('../src/services/calc.service');

// Spent
// TODO: getFormatMoney
{
t.is(getMoney({
}
// getMoney
{
t.deepEqual(getMoney({
texts: [1, 2, '0', 'sdlfjsdlfjsldkfj'],
type: TYPES.allSpent,
}), 0);
t.is(getMoney({
}), {
eur: 0,
rub: 0,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['Поел 300 рыбу', '+ ЗП 1 \n\nsad', 'nuff said'],
type: TYPES.allSpent,
}), 300);
t.is(getMoney({
}), {
eur: 0,
rub: 300,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['Поел мясо 100р', 'Магаз 100.20₽', 'Магаз 100р.', '20.11р магазин'],
type: TYPES.allSpent,
}), 320.31);
t.is(getMoney({
}), {
eur: 0,
rub: 320.31,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['Поел 0.1р', 'some 0.1₽', 'some x 0.112', 'еще 0.1 \n и еще 0.1'],
type: TYPES.allSpent,
}), 0.51);
t.is(getMoney({
}), {
eur: 0,
rub: 0.512,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['Поел 300', 'Магазин 100', 'Зп 999'],
type: TYPES.allSpent,
}), 400);
t.is(getMoney({
}), {
eur: 0,
rub: 400,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['+ ЗП 300', 'что-то еще'],
type: TYPES.allSpent,
}), 0);
t.is(getMoney({
}), {
eur: 0,
rub: 0,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['что-то отправил 300рублей ', 'Поел джаганнат за 200', 'получил 100р'],
type: TYPES.allSpent,
}), 500);
t.is(getMoney({
}), {
eur: 0,
rub: 500,
usd: 0,
});
t.deepEqual(getMoney({
texts: ['поел 300 100р 100'],
type: TYPES.allSpent,
}), 500);
}), {
eur: 0,
rub: 500,
usd: 0,
});
}
// received
{
t.is(getMoney({
texts: ['ЗП 300рублей ', 'зп 200 рублей', 'зарплата 100руб', 'получил 100', 'Водка 50'],
t.deepEqual(getMoney({
texts: ['ЗП 300рублей ', 'зп 10 евро', 'зарплата $10', 'зп 200 рублей', 'зарплата 100руб', 'получил 100', 'Водка 50'],
type: TYPES.allReceived,
}), 700);
t.is(getMoney({
}), {
eur: 10,
rub: 700,
usd: 10,
});
t.deepEqual(getMoney({
texts: ['ЗП 5\n ЗП 5'],
type: TYPES.allReceived,
}), 10);
}), {
eur: 0,
rub: 10,
usd: 0,
});
}
});

Expand Down

0 comments on commit 3f8ecf0

Please sign in to comment.