refactor: centralize domain values and enforce numeric lint

This commit is contained in:
2026-09-13 14:37:39 +03:00
parent 8ba005346d
commit 8637ad2f34
44 changed files with 543 additions and 174 deletions
@@ -1,3 +1,7 @@
import {
MAX_CARD_NAME_LENGTH,
MAX_OPERATION_DESCRIPTION_LENGTH,
} from '../domain/bank-card-limits';
import {
BadRequestException,
ConflictException,
@@ -13,7 +17,26 @@ import {
import { isCalendarDate, moscowToday } from '../domain/bank-card.calculations';
import { parseRubMoney } from '../domain/rub-money';
export function fail(code = 'BANK_INVALID_INPUT'): never {
export const BankErrorCode = {
InvalidInput: 'BANK_INVALID_INPUT',
VersionConflict: 'BANK_VERSION_CONFLICT',
NotFound: 'BANK_NOT_FOUND',
InvalidMoney: 'BANK_INVALID_MONEY',
InvalidDate: 'BANK_INVALID_DATE',
ImmutableOperation: 'BANK_IMMUTABLE_OPERATION',
InvalidRefund: 'BANK_INVALID_REFUND',
RefundLimit: 'BANK_REFUND_LIMIT',
DependentRefunds: 'BANK_DEPENDENT_REFUNDS',
IntentConflict: 'BANK_INTENT_CONFLICT',
OperationDeleted: 'BANK_OPERATION_DELETED',
CardArchived: 'BANK_CARD_ARCHIVED',
OpeningDateConflict: 'BANK_OPENING_DATE_CONFLICT',
WriteConflict: 'BANK_WRITE_CONFLICT',
DuplicateCategory: 'BANK_DUPLICATE_CATEGORY',
} as const;
export type BankErrorCode = (typeof BankErrorCode)[keyof typeof BankErrorCode];
export function fail(code: BankErrorCode = BankErrorCode.InvalidInput): never {
throw new BadRequestException({ code });
}
export function periodBounds(query: BankPeriodQueryDto) {
@@ -35,11 +58,13 @@ export function periodBounds(query: BankPeriodQueryDto) {
return fail();
return { from: query.from, to: query.to };
}
export function conflict(code = 'BANK_VERSION_CONFLICT'): never {
export function conflict(
code: BankErrorCode = BankErrorCode.VersionConflict,
): never {
throw new ConflictException({ code });
}
export function missing(): never {
throw new NotFoundException({ code: 'BANK_NOT_FOUND' });
throw new NotFoundException({ code: BankErrorCode.NotFound });
}
export const fingerprint = (value: unknown) =>
createHash('sha256')
@@ -56,16 +81,16 @@ export function amount(
try {
return parseRubMoney(value, positive);
} catch {
return fail('BANK_INVALID_MONEY');
return fail(BankErrorCode.InvalidMoney);
}
}
export function calendar(value: string) {
if (!isCalendarDate(value)) fail('BANK_INVALID_DATE');
if (!isCalendarDate(value)) fail(BankErrorCode.InvalidDate);
return value;
}
export function currentDate(value: string) {
calendar(value);
if (value > moscowToday()) fail('BANK_INVALID_DATE');
if (value > moscowToday()) fail(BankErrorCode.InvalidDate);
}
export function name(value: string, max: number) {
if (typeof value !== 'string' || !value.trim() || value.trim().length > max)
@@ -74,7 +99,7 @@ export function name(value: string, max: number) {
}
export function cardInput(dto: CreateBankCardDto) {
const bankName = dto.bankName?.trim() || null;
if (bankName && bankName.length > 100) fail();
if (bankName && bankName.length > MAX_CARD_NAME_LENGTH) fail();
if (dto.lastFour != null && !/^\d{4}$/.test(dto.lastFour)) fail();
if (
dto.paymentSystem != null &&
@@ -83,7 +108,7 @@ export function cardInput(dto: CreateBankCardDto) {
fail();
return {
...(dto.paymentSystem == null ? {} : { paymentSystem: dto.paymentSystem }),
name: name(dto.name, 100),
name: name(dto.name, MAX_CARD_NAME_LENGTH),
bankName,
lastFour: dto.lastFour || null,
openingBalanceKopecks: amount(dto.openingBalance),
@@ -93,7 +118,8 @@ export function cardInput(dto: CreateBankCardDto) {
export function operationInput(dto: CreateBankOperationDto) {
if (
dto.description != null &&
(typeof dto.description !== 'string' || dto.description.length > 500)
(typeof dto.description !== 'string' ||
dto.description.length > MAX_OPERATION_DESCRIPTION_LENGTH)
)
fail();
return {