feat(server): add payment type
This commit is contained in:
parent
457f4bbed2
commit
3fba931281
@ -71,6 +71,7 @@ export default [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -46,17 +46,19 @@ model ExpenseList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model ExpenseItem {
|
model ExpenseItem {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
expenseList ExpenseList @relation(fields: [expenseListId], references: [id], onDelete: Cascade)
|
expenseList ExpenseList @relation(fields: [expenseListId], references: [id], onDelete: Cascade)
|
||||||
expenseListId String
|
expenseListId String
|
||||||
title String
|
title String
|
||||||
description String?
|
description String?
|
||||||
date DateTime
|
date DateTime
|
||||||
amount Float
|
amount Float
|
||||||
currency String @default("RUB")
|
currency String @default("RUB")
|
||||||
count Float @default(1)
|
count Float @default(1)
|
||||||
createdAt DateTime @default(now()) @map("created_at")
|
paymentType ExpenseItemFromType? @map("payment_type")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
paymentSourceId String? @map("payment_source_id")
|
||||||
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
|
|
||||||
@@map("expenses_items")
|
@@map("expenses_items")
|
||||||
}
|
}
|
||||||
@ -123,3 +125,10 @@ model Cash {
|
|||||||
|
|
||||||
@@map("cash")
|
@@map("cash")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ExpenseItemFromType {
|
||||||
|
BANK_CARD
|
||||||
|
CASH
|
||||||
|
|
||||||
|
@@map("expense_item_from_types")
|
||||||
|
}
|
||||||
|
|||||||
@ -9,5 +9,6 @@ import { BankCardService } from './bank-card.service';
|
|||||||
controllers: [BankCardController],
|
controllers: [BankCardController],
|
||||||
providers: [BankCardService],
|
providers: [BankCardService],
|
||||||
imports: [BankAccountModule],
|
imports: [BankAccountModule],
|
||||||
|
exports: [BankCardService],
|
||||||
})
|
})
|
||||||
export class BankCardModule {}
|
export class BankCardModule {}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export class BankCardService {
|
|||||||
private readonly bankAccountService: BankAccountService,
|
private readonly bankAccountService: BankAccountService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createBankCard(userId: User['id'], dto: CreateBankCardDto): Promise<BankCardDto> {
|
public async createBankCard(userId: User['id'], dto: CreateBankCardDto): Promise<BankCardDto> {
|
||||||
const { name, balance } = dto;
|
const { name, balance } = dto;
|
||||||
|
|
||||||
const bankAccount = await this.bankAccountService.createBankAccount({
|
const bankAccount = await this.bankAccountService.createBankAccount({
|
||||||
@ -36,20 +36,13 @@ export class BankCardService {
|
|||||||
return this.toDto(card);
|
return this.toDto(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBankCardById(userId: User['id'], bankCardId: BankCard['id']): Promise<BankCardDto> {
|
public async getBankCardById(userId: User['id'], bankCardId: BankCard['id']): Promise<BankCardDto> {
|
||||||
const card = await this.prismaService.bankCard.findUnique({
|
const card = await this.findCardById(userId, bankCardId);
|
||||||
where: { id: bankCardId },
|
|
||||||
include: { bankAccount: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (card?.userId !== userId) {
|
|
||||||
throw new NotFoundException('Карта не найдена');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.toDto(card);
|
return this.toDto(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBankCardsByUserId(userId: User['id']): Promise<BankCardDto[]> {
|
public async getBankCardsByUserId(userId: User['id']): Promise<BankCardDto[]> {
|
||||||
const cards = await this.prismaService.bankCard.findMany({
|
const cards = await this.prismaService.bankCard.findMany({
|
||||||
where: { userId },
|
where: { userId },
|
||||||
include: { bankAccount: true },
|
include: { bankAccount: true },
|
||||||
@ -59,7 +52,7 @@ export class BankCardService {
|
|||||||
return cards.map((card) => this.toDto(card));
|
return cards.map((card) => this.toDto(card));
|
||||||
}
|
}
|
||||||
|
|
||||||
async editBankCard(userId: User['id'], bankCardId: BankCard['id'], dto: EditBankCardDto): Promise<BankCardDto> {
|
public async editBankCard(userId: User['id'], bankCardId: BankCard['id'], dto: EditBankCardDto): Promise<BankCardDto> {
|
||||||
const { name, balance } = dto;
|
const { name, balance } = dto;
|
||||||
const card = await this.getBankCardById(userId, bankCardId);
|
const card = await this.getBankCardById(userId, bankCardId);
|
||||||
|
|
||||||
@ -79,7 +72,7 @@ export class BankCardService {
|
|||||||
return this.toDto(updatedCard);
|
return this.toDto(updatedCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteBankCard(userId: User['id'], bankCardId: BankCard['id']): Promise<BankCardDto> {
|
public async deleteBankCard(userId: User['id'], bankCardId: BankCard['id']): Promise<BankCardDto> {
|
||||||
const card = await this.getBankCardById(userId, bankCardId);
|
const card = await this.getBankCardById(userId, bankCardId);
|
||||||
|
|
||||||
const deletedCard = await this.prismaService.bankCard.delete({
|
const deletedCard = await this.prismaService.bankCard.delete({
|
||||||
@ -90,7 +83,25 @@ export class BankCardService {
|
|||||||
return this.toDto(deletedCard);
|
return this.toDto(deletedCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
toDto(card: BankCard & { bankAccount: BankAccount }): BankCardDto {
|
public async addExpense(userId: User['id'], bankCardId: BankCard['id'], amount: number) {
|
||||||
|
const card = await this.findCardById(userId, bankCardId);
|
||||||
|
await this.bankAccountService.changeBalance(card.bankAccount.id, card.bankAccount.balance - amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findCardById(userId: User['id'], bankCardId: BankCard['id']) {
|
||||||
|
const card = await this.prismaService.bankCard.findUnique({
|
||||||
|
where: { id: bankCardId },
|
||||||
|
include: { bankAccount: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (card?.userId !== userId) {
|
||||||
|
throw new NotFoundException('Карта не найдена');
|
||||||
|
}
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
private toDto(card: BankCard & { bankAccount: BankAccount }): BankCardDto {
|
||||||
return {
|
return {
|
||||||
id: card.id,
|
id: card.id,
|
||||||
name: card.name,
|
name: card.name,
|
||||||
|
|||||||
@ -6,5 +6,6 @@ import { CashService } from './cash.service';
|
|||||||
@Module({
|
@Module({
|
||||||
controllers: [CashController],
|
controllers: [CashController],
|
||||||
providers: [CashService],
|
providers: [CashService],
|
||||||
|
exports: [CashService],
|
||||||
})
|
})
|
||||||
export class CashModule {}
|
export class CashModule {}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { Cash, User } from '@prisma/client';
|
import { BankCard, Cash, User } from '@prisma/client';
|
||||||
|
|
||||||
import { PrismaService } from '@/modules/prisma/prisma.service';
|
import { PrismaService } from '@/modules/prisma/prisma.service';
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ import { CashDto, CreateCashDto, EditCashDto } from './dto';
|
|||||||
export class CashService {
|
export class CashService {
|
||||||
constructor(private readonly prismaService: PrismaService) {}
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
async createCash(userId: User['id'], dto: CreateCashDto): Promise<CashDto> {
|
public async createCash(userId: User['id'], dto: CreateCashDto): Promise<CashDto> {
|
||||||
const { balance, name } = dto;
|
const { balance, name } = dto;
|
||||||
|
|
||||||
return this.prismaService.cash.create({
|
return this.prismaService.cash.create({
|
||||||
@ -23,7 +23,7 @@ export class CashService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCashById(userId: User['id'], cashId: Cash['id']): Promise<CashDto> {
|
public async getCashById(userId: User['id'], cashId: Cash['id']): Promise<CashDto> {
|
||||||
const cash = await this.prismaService.cash.findUnique({
|
const cash = await this.prismaService.cash.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: cashId,
|
id: cashId,
|
||||||
@ -38,14 +38,14 @@ export class CashService {
|
|||||||
return cash;
|
return cash;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllCashByUserId(userId: User['id']): Promise<CashDto[]> {
|
public async getAllCashByUserId(userId: User['id']): Promise<CashDto[]> {
|
||||||
return this.prismaService.cash.findMany({
|
return this.prismaService.cash.findMany({
|
||||||
where: { userId },
|
where: { userId },
|
||||||
orderBy: { createdAt: 'asc' },
|
orderBy: { createdAt: 'asc' },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async editCash(userId: User['id'], cashId: Cash['id'], dto: EditCashDto): Promise<CashDto> {
|
public async editCash(userId: User['id'], cashId: Cash['id'], dto: EditCashDto): Promise<CashDto> {
|
||||||
const { balance, name } = dto;
|
const { balance, name } = dto;
|
||||||
|
|
||||||
const cash = await this.getCashById(userId, cashId);
|
const cash = await this.getCashById(userId, cashId);
|
||||||
@ -59,11 +59,16 @@ export class CashService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteCash(userId: User['id'], cashId: Cash['id']): Promise<CashDto> {
|
public async deleteCash(userId: User['id'], cashId: Cash['id']): Promise<CashDto> {
|
||||||
const cash = await this.getCashById(userId, cashId);
|
const cash = await this.getCashById(userId, cashId);
|
||||||
|
|
||||||
return this.prismaService.cash.delete({
|
return this.prismaService.cash.delete({
|
||||||
where: { id: cash.id },
|
where: { id: cash.id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async addExpense(userId: User['id'], cashId: BankCard['id'], amount: number) {
|
||||||
|
const cash = await this.getCashById(userId, cashId);
|
||||||
|
await this.editCash(userId, cash.id, { balance: cash.balance - amount });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,38 @@
|
|||||||
|
// eslint-disable-next-line max-classes-per-file
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { ExpenseItemFromType } from '@prisma/client';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
|
IsEnum,
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString, ValidateNested,
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
|
||||||
import { IsISODateTimeString } from '../../../../shared/validators';
|
import { IsISODateTimeString } from '../../../../shared/validators';
|
||||||
|
|
||||||
|
class ExpensePaymentDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Способ оплаты',
|
||||||
|
example: 'CASH',
|
||||||
|
enum: ExpenseItemFromType,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty({ message: 'Способ оплаты обязателен к заполнению' })
|
||||||
|
@IsEnum(ExpenseItemFromType)
|
||||||
|
type: ExpenseItemFromType;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'ID карты или наличных ',
|
||||||
|
example: '123',
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty({ message: 'ID источника оплаты обязателен к заполнению' })
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class CreateExpenseListItemDto {
|
export class CreateExpenseListItemDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'Заголовок расхода',
|
description: 'Заголовок расхода',
|
||||||
@ -67,4 +92,14 @@ export class CreateExpenseListItemDto {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNumber({ allowInfinity: false, allowNaN: false, maxDecimalPlaces: 2 }, { message: 'Количество должно быть числом.' })
|
@IsNumber({ allowInfinity: false, allowNaN: false, maxDecimalPlaces: 2 }, { message: 'Количество должно быть числом.' })
|
||||||
count?: number;
|
count?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Оплата',
|
||||||
|
type: ExpensePaymentDto,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
@IsOptional()
|
||||||
|
@ValidateNested()
|
||||||
|
@Type(() => ExpensePaymentDto)
|
||||||
|
payment?: ExpensePaymentDto;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,25 @@
|
|||||||
|
// eslint-disable-next-line max-classes-per-file
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { ExpenseItem, ExpenseList } from '@prisma/client';
|
import { ExpenseItem, ExpenseItemFromType, ExpenseList } from '@prisma/client';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
class ExpensePaymentDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Способ оплаты',
|
||||||
|
example: 'CASH',
|
||||||
|
enum: ExpenseItemFromType,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
type: ExpenseItemFromType | null;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'ID карты или наличных ',
|
||||||
|
example: '123',
|
||||||
|
type: String,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
id: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export class ExpenseListItemDto {
|
export class ExpenseListItemDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
@ -61,6 +81,14 @@ export class ExpenseListItemDto {
|
|||||||
})
|
})
|
||||||
count: ExpenseItem['count'];
|
count: ExpenseItem['count'];
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Оплата',
|
||||||
|
type: ExpensePaymentDto,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
@Type(() => ExpensePaymentDto)
|
||||||
|
payment?: ExpensePaymentDto;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'Дата создания',
|
description: 'Дата создания',
|
||||||
type: Date,
|
type: Date,
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { BankCardModule } from '@/modules/bank-card/bank-card.module';
|
||||||
|
import { CashModule } from '@/modules/cash/cash.module';
|
||||||
|
|
||||||
import { ExpensesController } from './expenses.controller';
|
import { ExpensesController } from './expenses.controller';
|
||||||
import { ExpensesService } from './expenses.service';
|
import { ExpensesService } from './expenses.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [
|
||||||
|
BankCardModule,
|
||||||
|
CashModule,
|
||||||
|
],
|
||||||
controllers: [ExpensesController],
|
controllers: [ExpensesController],
|
||||||
providers: [ExpensesService],
|
providers: [ExpensesService],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { ExpenseItem, ExpenseList, User } from '@prisma/client';
|
import {
|
||||||
|
ExpenseItem, ExpenseItemFromType, ExpenseList, User,
|
||||||
|
} from '@prisma/client';
|
||||||
|
|
||||||
|
import { BankCardService } from '@/modules/bank-card/bank-card.service';
|
||||||
|
import { CashService } from '@/modules/cash/cash.service';
|
||||||
|
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
|
||||||
@ -17,6 +22,8 @@ import {
|
|||||||
export class ExpensesService {
|
export class ExpensesService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly prismaService: PrismaService,
|
private readonly prismaService: PrismaService,
|
||||||
|
private readonly bankCardService: BankCardService,
|
||||||
|
private readonly cashService: CashService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createList(dto: CreateExpenseListDto, userId: User['id']): Promise<ExpenseListDto> {
|
async createList(dto: CreateExpenseListDto, userId: User['id']): Promise<ExpenseListDto> {
|
||||||
@ -88,10 +95,26 @@ export class ExpensesService {
|
|||||||
amount,
|
amount,
|
||||||
currency,
|
currency,
|
||||||
count,
|
count,
|
||||||
|
payment,
|
||||||
} = dto;
|
} = dto;
|
||||||
const list = await this.findList(listId, userId);
|
const list = await this.findList(listId, userId);
|
||||||
|
|
||||||
return this.prismaService.expenseItem.create({
|
switch (payment?.type) {
|
||||||
|
case ExpenseItemFromType.BANK_CARD:
|
||||||
|
await this.bankCardService.addExpense(userId, payment.id, amount * (count || 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExpenseItemFromType.CASH:
|
||||||
|
await this.cashService.addExpense(userId, payment.id, amount * (count || 1));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undefined
|
||||||
|
case undefined:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const item = await this.prismaService.expenseItem.create({
|
||||||
data: {
|
data: {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@ -99,11 +122,15 @@ export class ExpensesService {
|
|||||||
amount,
|
amount,
|
||||||
currency,
|
currency,
|
||||||
count,
|
count,
|
||||||
|
paymentType: payment?.type,
|
||||||
|
paymentSourceId: payment?.id,
|
||||||
expenseList: {
|
expenseList: {
|
||||||
connect: { id: list.id },
|
connect: { id: list.id },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.toDto(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async findListItemById(id: ExpenseItem['id'], listId: ExpenseList['id'], userId: User['id']) {
|
async findListItemById(id: ExpenseItem['id'], listId: ExpenseList['id'], userId: User['id']) {
|
||||||
@ -128,7 +155,7 @@ export class ExpensesService {
|
|||||||
count = item.count,
|
count = item.count,
|
||||||
} = dto;
|
} = dto;
|
||||||
|
|
||||||
return this.prismaService.expenseItem.update({
|
const updatedItem = await this.prismaService.expenseItem.update({
|
||||||
where: { id: item.id },
|
where: { id: item.id },
|
||||||
data: {
|
data: {
|
||||||
title,
|
title,
|
||||||
@ -139,6 +166,8 @@ export class ExpensesService {
|
|||||||
count,
|
count,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.toDto(updatedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteListItem(
|
async deleteListItem(
|
||||||
@ -148,9 +177,11 @@ export class ExpensesService {
|
|||||||
): Promise<ExpenseListItemDto> {
|
): Promise<ExpenseListItemDto> {
|
||||||
const item = await this.findListItem(itemId, listId, userId);
|
const item = await this.findListItem(itemId, listId, userId);
|
||||||
|
|
||||||
return this.prismaService.expenseItem.delete({
|
const deletedItem = await this.prismaService.expenseItem.delete({
|
||||||
where: { id: item.id },
|
where: { id: item.id },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return this.toDto(deletedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async findList(id: ExpenseList['id'], userId: User['id']) {
|
private async findList(id: ExpenseList['id'], userId: User['id']) {
|
||||||
@ -163,6 +194,9 @@ export class ExpensesService {
|
|||||||
throw new NotFoundException('Лист расходов не найден');
|
throw new NotFoundException('Лист расходов не найден');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo нужно преобразовать paymentSourceId и paymentType в объект payment
|
||||||
|
// for (let i = 0; i<= existingList.items.length)
|
||||||
|
|
||||||
return existingList;
|
return existingList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,4 +210,23 @@ export class ExpensesService {
|
|||||||
|
|
||||||
return existingItem;
|
return existingItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private toDto(item: ExpenseItem): ExpenseListItemDto {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
title: item.title,
|
||||||
|
description: item.description,
|
||||||
|
date: item.date,
|
||||||
|
amount: item.amount,
|
||||||
|
currency: item.currency,
|
||||||
|
count: item.count,
|
||||||
|
createdAt: item.createdAt,
|
||||||
|
updatedAt: item.updatedAt,
|
||||||
|
expenseListId: item.expenseListId,
|
||||||
|
payment: {
|
||||||
|
type: item.paymentType,
|
||||||
|
id: item.paymentSourceId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user