chore: save pending changes

This commit is contained in:
2026-09-12 19:59:10 +03:00
parent e6f58ef0ee
commit 8c074d85de
5 changed files with 46 additions and 0 deletions
@@ -0,0 +1 @@
ALTER TABLE "BankCard" ADD COLUMN "paymentSystem" TEXT CHECK ("paymentSystem" IN ('mir', 'visa', 'mastercard'));
+1
View File
@@ -47,6 +47,7 @@ model BankCard {
name String
bankName String?
lastFour String?
paymentSystem String?
openingBalanceKopecks BigInt
openingDate String
version Int @default(1)
+7
View File
@@ -25,6 +25,7 @@ import { MoneyDto } from '../common/money.dto';
const trim = ({ value }: { value: unknown }) =>
typeof value === 'string' ? value.trim() : value;
export const bankPaymentSystems = ['mir', 'visa', 'mastercard'] as const;
export const bankOperationKinds = [
'expense',
'topup',
@@ -57,6 +58,10 @@ export class CreateBankCardDto {
@IsOptional()
@Matches(/^[0-9]{4}$/)
lastFour?: string | null;
@ApiPropertyOptional({ enum: bankPaymentSystems, nullable: true })
@IsOptional()
@IsIn(bankPaymentSystems)
paymentSystem?: string | null;
@ApiProperty({ type: RubMoneyInputDto })
@IsDefined()
@ValidateNested()
@@ -180,6 +185,8 @@ export class BankCardDto {
@ApiProperty({ type: String }) name: string;
@ApiProperty({ type: String, nullable: true }) bankName: string | null;
@ApiProperty({ type: String, nullable: true }) lastFour: string | null;
@ApiProperty({ enum: bankPaymentSystems, nullable: true }) paymentSystem:
string | null;
@ApiProperty({ type: MoneyDto }) openingBalance: MoneyDto;
@ApiProperty({ type: String }) openingDate: string;
@ApiProperty({ type: MoneyDto }) balance: MoneyDto;
+13
View File
@@ -20,6 +20,7 @@ import {
moscowToday,
} from './bank-card.calculations';
import {
bankPaymentSystems,
BankCardDto,
BankOperationDto,
BankOperationsQueryDto,
@@ -84,7 +85,13 @@ function cardInput(dto: CreateBankCardDto) {
const bankName = dto.bankName?.trim() || null;
if (bankName && bankName.length > 100) fail();
if (dto.lastFour != null && !/^\d{4}$/.test(dto.lastFour)) fail();
if (
dto.paymentSystem != null &&
!bankPaymentSystems.some((system) => system === dto.paymentSystem)
)
fail();
return {
...(dto.paymentSystem == null ? {} : { paymentSystem: dto.paymentSystem }),
name: name(dto.name, 100),
bankName,
lastFour: dto.lastFour || null,
@@ -180,6 +187,7 @@ export class BankCardsService {
name: card.name,
bankName: card.bankName,
lastFour: card.lastFour,
paymentSystem: card.paymentSystem,
openingDate: card.openingDate,
openingBalance: rubMoney(card.openingBalanceKopecks),
balance: rubMoney(bankBalance(card.id, card.openingBalanceKopecks, rows)),
@@ -292,6 +300,10 @@ export class BankCardsService {
dto.lastFour === undefined
? (previous.lastFour ?? undefined)
: (dto.lastFour ?? undefined),
paymentSystem:
dto.paymentSystem === undefined
? previous.paymentSystem
: dto.paymentSystem,
openingBalance:
dto.openingBalance ?? rubMoney(previous.openingBalanceKopecks),
openingDate: dto.openingDate ?? previous.openingDate,
@@ -316,6 +328,7 @@ export class BankCardsService {
where: { id, userId, version: dto.version },
data: {
...input,
paymentSystem: input.paymentSystem ?? null,
version: { increment: 1 },
...(dto.archived === undefined
? {}
+24
View File
@@ -709,4 +709,28 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
}),
).rejects.toMatchObject({ code: 'P2002' });
});
it('persists payment systems, preserves omitted metadata and allows clearing', async () => {
const card = await createCard('1000', owner, { paymentSystem: 'mir' });
expect((await getCard(card.id)).paymentSystem).toBe('mir');
await auth('patch', '/' + card.id)
.send({ version: 1, name: 'Renamed' })
.expect(200);
expect((await getCard(card.id)).paymentSystem).toBe('mir');
await auth('patch', '/' + card.id)
.send({ version: 2, paymentSystem: 'visa' })
.expect(200);
expect((await getCard(card.id)).paymentSystem).toBe('visa');
await auth('patch', '/' + card.id)
.send({ version: 3, paymentSystem: 'unknown' })
.expect(400);
await auth('patch', '/' + card.id)
.send({ version: 3, paymentSystem: null })
.expect(200);
expect((await getCard(card.id)).paymentSystem).toBeNull();
expect((await createCard()).paymentSystem).toBeNull();
expect(
(await createCard('1000', owner, { paymentSystem: 'mastercard' }))
.paymentSystem,
).toBe('mastercard');
});
});