chore: save pending changes
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "BankCard" ADD COLUMN "paymentSystem" TEXT CHECK ("paymentSystem" IN ('mir', 'visa', 'mastercard'));
|
||||||
@@ -47,6 +47,7 @@ model BankCard {
|
|||||||
name String
|
name String
|
||||||
bankName String?
|
bankName String?
|
||||||
lastFour String?
|
lastFour String?
|
||||||
|
paymentSystem String?
|
||||||
openingBalanceKopecks BigInt
|
openingBalanceKopecks BigInt
|
||||||
openingDate String
|
openingDate String
|
||||||
version Int @default(1)
|
version Int @default(1)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { MoneyDto } from '../common/money.dto';
|
|||||||
|
|
||||||
const trim = ({ value }: { value: unknown }) =>
|
const trim = ({ value }: { value: unknown }) =>
|
||||||
typeof value === 'string' ? value.trim() : value;
|
typeof value === 'string' ? value.trim() : value;
|
||||||
|
export const bankPaymentSystems = ['mir', 'visa', 'mastercard'] as const;
|
||||||
export const bankOperationKinds = [
|
export const bankOperationKinds = [
|
||||||
'expense',
|
'expense',
|
||||||
'topup',
|
'topup',
|
||||||
@@ -57,6 +58,10 @@ export class CreateBankCardDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Matches(/^[0-9]{4}$/)
|
@Matches(/^[0-9]{4}$/)
|
||||||
lastFour?: string | null;
|
lastFour?: string | null;
|
||||||
|
@ApiPropertyOptional({ enum: bankPaymentSystems, nullable: true })
|
||||||
|
@IsOptional()
|
||||||
|
@IsIn(bankPaymentSystems)
|
||||||
|
paymentSystem?: string | null;
|
||||||
@ApiProperty({ type: RubMoneyInputDto })
|
@ApiProperty({ type: RubMoneyInputDto })
|
||||||
@IsDefined()
|
@IsDefined()
|
||||||
@ValidateNested()
|
@ValidateNested()
|
||||||
@@ -180,6 +185,8 @@ export class BankCardDto {
|
|||||||
@ApiProperty({ type: String }) name: string;
|
@ApiProperty({ type: String }) name: string;
|
||||||
@ApiProperty({ type: String, nullable: true }) bankName: string | null;
|
@ApiProperty({ type: String, nullable: true }) bankName: string | null;
|
||||||
@ApiProperty({ type: String, nullable: true }) lastFour: 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: MoneyDto }) openingBalance: MoneyDto;
|
||||||
@ApiProperty({ type: String }) openingDate: string;
|
@ApiProperty({ type: String }) openingDate: string;
|
||||||
@ApiProperty({ type: MoneyDto }) balance: MoneyDto;
|
@ApiProperty({ type: MoneyDto }) balance: MoneyDto;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
moscowToday,
|
moscowToday,
|
||||||
} from './bank-card.calculations';
|
} from './bank-card.calculations';
|
||||||
import {
|
import {
|
||||||
|
bankPaymentSystems,
|
||||||
BankCardDto,
|
BankCardDto,
|
||||||
BankOperationDto,
|
BankOperationDto,
|
||||||
BankOperationsQueryDto,
|
BankOperationsQueryDto,
|
||||||
@@ -84,7 +85,13 @@ function cardInput(dto: CreateBankCardDto) {
|
|||||||
const bankName = dto.bankName?.trim() || null;
|
const bankName = dto.bankName?.trim() || null;
|
||||||
if (bankName && bankName.length > 100) fail();
|
if (bankName && bankName.length > 100) fail();
|
||||||
if (dto.lastFour != null && !/^\d{4}$/.test(dto.lastFour)) fail();
|
if (dto.lastFour != null && !/^\d{4}$/.test(dto.lastFour)) fail();
|
||||||
|
if (
|
||||||
|
dto.paymentSystem != null &&
|
||||||
|
!bankPaymentSystems.some((system) => system === dto.paymentSystem)
|
||||||
|
)
|
||||||
|
fail();
|
||||||
return {
|
return {
|
||||||
|
...(dto.paymentSystem == null ? {} : { paymentSystem: dto.paymentSystem }),
|
||||||
name: name(dto.name, 100),
|
name: name(dto.name, 100),
|
||||||
bankName,
|
bankName,
|
||||||
lastFour: dto.lastFour || null,
|
lastFour: dto.lastFour || null,
|
||||||
@@ -180,6 +187,7 @@ export class BankCardsService {
|
|||||||
name: card.name,
|
name: card.name,
|
||||||
bankName: card.bankName,
|
bankName: card.bankName,
|
||||||
lastFour: card.lastFour,
|
lastFour: card.lastFour,
|
||||||
|
paymentSystem: card.paymentSystem,
|
||||||
openingDate: card.openingDate,
|
openingDate: card.openingDate,
|
||||||
openingBalance: rubMoney(card.openingBalanceKopecks),
|
openingBalance: rubMoney(card.openingBalanceKopecks),
|
||||||
balance: rubMoney(bankBalance(card.id, card.openingBalanceKopecks, rows)),
|
balance: rubMoney(bankBalance(card.id, card.openingBalanceKopecks, rows)),
|
||||||
@@ -292,6 +300,10 @@ export class BankCardsService {
|
|||||||
dto.lastFour === undefined
|
dto.lastFour === undefined
|
||||||
? (previous.lastFour ?? undefined)
|
? (previous.lastFour ?? undefined)
|
||||||
: (dto.lastFour ?? undefined),
|
: (dto.lastFour ?? undefined),
|
||||||
|
paymentSystem:
|
||||||
|
dto.paymentSystem === undefined
|
||||||
|
? previous.paymentSystem
|
||||||
|
: dto.paymentSystem,
|
||||||
openingBalance:
|
openingBalance:
|
||||||
dto.openingBalance ?? rubMoney(previous.openingBalanceKopecks),
|
dto.openingBalance ?? rubMoney(previous.openingBalanceKopecks),
|
||||||
openingDate: dto.openingDate ?? previous.openingDate,
|
openingDate: dto.openingDate ?? previous.openingDate,
|
||||||
@@ -316,6 +328,7 @@ export class BankCardsService {
|
|||||||
where: { id, userId, version: dto.version },
|
where: { id, userId, version: dto.version },
|
||||||
data: {
|
data: {
|
||||||
...input,
|
...input,
|
||||||
|
paymentSystem: input.paymentSystem ?? null,
|
||||||
version: { increment: 1 },
|
version: { increment: 1 },
|
||||||
...(dto.archived === undefined
|
...(dto.archived === undefined
|
||||||
? {}
|
? {}
|
||||||
|
|||||||
@@ -709,4 +709,28 @@ describe('Manual bank cards configured HTTP and real SQLite', () => {
|
|||||||
}),
|
}),
|
||||||
).rejects.toMatchObject({ code: 'P2002' });
|
).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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user