refactor: centralize domain values and enforce numeric lint
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export const MAX_CARD_NAME_LENGTH = 100;
|
||||
export const MAX_CATEGORY_NAME_LENGTH = 80;
|
||||
export const MAX_OPERATION_DESCRIPTION_LENGTH = 500;
|
||||
@@ -1,3 +1,6 @@
|
||||
import { BankOperationKind } from './bank-operation-kind';
|
||||
|
||||
const ISO_MONTH_LENGTH = 7;
|
||||
export function moscowToday(now = new Date()): string {
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Europe/Moscow',
|
||||
@@ -30,12 +33,21 @@ export function bankBalance(
|
||||
let balance = opening;
|
||||
for (const operation of operations) {
|
||||
if (operation.cardId === cardId) {
|
||||
if (operation.kind === 'expense' || operation.kind === 'transfer')
|
||||
if (
|
||||
operation.kind === BankOperationKind.Expense ||
|
||||
operation.kind === BankOperationKind.Transfer
|
||||
)
|
||||
balance -= operation.amountKopecks;
|
||||
else if (operation.kind === 'topup' || operation.kind === 'refund')
|
||||
else if (
|
||||
operation.kind === BankOperationKind.Topup ||
|
||||
operation.kind === BankOperationKind.Refund
|
||||
)
|
||||
balance += operation.amountKopecks;
|
||||
}
|
||||
if (operation.kind === 'transfer' && operation.targetCardId === cardId)
|
||||
if (
|
||||
operation.kind === BankOperationKind.Transfer &&
|
||||
operation.targetCardId === cardId
|
||||
)
|
||||
balance += operation.amountKopecks;
|
||||
}
|
||||
return balance;
|
||||
@@ -60,13 +72,23 @@ export function bankSummary(
|
||||
for (const operation of operations) {
|
||||
if (
|
||||
typeof period === 'string'
|
||||
? operation.date.slice(0, 7) !== period
|
||||
? operation.date.slice(0, ISO_MONTH_LENGTH) !== period
|
||||
: operation.date < period.from || operation.date > period.to
|
||||
)
|
||||
continue;
|
||||
if (operation.kind !== 'expense' && operation.kind !== 'refund') continue;
|
||||
const expense = operation.kind === 'expense' ? operation.amountKopecks : 0n;
|
||||
const refund = operation.kind === 'refund' ? operation.amountKopecks : 0n;
|
||||
if (
|
||||
operation.kind !== BankOperationKind.Expense &&
|
||||
operation.kind !== BankOperationKind.Refund
|
||||
)
|
||||
continue;
|
||||
const expense =
|
||||
operation.kind === BankOperationKind.Expense
|
||||
? operation.amountKopecks
|
||||
: 0n;
|
||||
const refund =
|
||||
operation.kind === BankOperationKind.Refund
|
||||
? operation.amountKopecks
|
||||
: 0n;
|
||||
expenses += expense;
|
||||
refunds += refund;
|
||||
if (operation.categoryId !== null) {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
export const BankOperationKind = {
|
||||
Expense: 'expense',
|
||||
Topup: 'topup',
|
||||
Transfer: 'transfer',
|
||||
Refund: 'refund',
|
||||
} as const;
|
||||
export type BankOperationKind =
|
||||
(typeof BankOperationKind)[keyof typeof BankOperationKind];
|
||||
@@ -1,6 +1,9 @@
|
||||
import { decimalFromString, formatDecimal } from '../../../../common/decimal';
|
||||
import type { Money } from '../../../../common/money.types';
|
||||
|
||||
const MIN_KOPECKS = -9_223_372_036_854_775_808n;
|
||||
const MAX_KOPECKS = 9_223_372_036_854_775_807n;
|
||||
|
||||
export function parseRubMoney(money: Money, positive = false): bigint {
|
||||
if (
|
||||
money?.currency !== 'RUB' ||
|
||||
@@ -12,7 +15,7 @@ export function parseRubMoney(money: Money, positive = false): bigint {
|
||||
if (amount.scale > 2)
|
||||
throw new RangeError('RUB money supports at most two decimal places');
|
||||
const kopecks = amount.value * 10n ** BigInt(2 - amount.scale);
|
||||
if (kopecks < -(2n ** 63n) || kopecks > 2n ** 63n - 1n)
|
||||
if (kopecks < MIN_KOPECKS || kopecks > MAX_KOPECKS)
|
||||
throw new RangeError('RUB money is outside the signed 64-bit range');
|
||||
if (positive && kopecks <= 0n)
|
||||
throw new RangeError('Operation amount must be positive');
|
||||
|
||||
Reference in New Issue
Block a user