Merge pull request #11 from JurunenseDesenvolvimento/homologacao
fix: adiciona variáveis globais do Jest no ESLint config
This commit is contained in:
2
.env
2
.env
@@ -31,7 +31,7 @@ THROTTLE_LIMIT=10
|
|||||||
|
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
|
||||||
ORACLE_CLIENT_LIB_DIR=C:\\instantclient_23_9
|
ORACLE_CLIENT_LIB_DIR=C:\\instantclient_23_0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ module.exports = [
|
|||||||
globals: {
|
globals: {
|
||||||
node: true,
|
node: true,
|
||||||
jest: true,
|
jest: true,
|
||||||
|
describe: 'readonly',
|
||||||
|
it: 'readonly',
|
||||||
|
test: 'readonly',
|
||||||
|
expect: 'readonly',
|
||||||
|
beforeEach: 'readonly',
|
||||||
|
afterEach: 'readonly',
|
||||||
|
beforeAll: 'readonly',
|
||||||
|
afterAll: 'readonly',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
@@ -33,6 +41,22 @@ module.exports = [
|
|||||||
'prettier/prettier': 'error',
|
'prettier/prettier': 'error',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.spec.ts', '**/__tests__/**/*.ts', '**/test/**/*.ts'],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
describe: 'readonly',
|
||||||
|
it: 'readonly',
|
||||||
|
test: 'readonly',
|
||||||
|
expect: 'readonly',
|
||||||
|
beforeEach: 'readonly',
|
||||||
|
afterEach: 'readonly',
|
||||||
|
beforeAll: 'readonly',
|
||||||
|
afterAll: 'readonly',
|
||||||
|
jest: 'readonly',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ignores: ['dist/**', 'node_modules/**', 'coverage/**'],
|
ignores: ['dist/**', 'node_modules/**', 'coverage/**'],
|
||||||
},
|
},
|
||||||
|
|||||||
553
package-lock.json
generated
553
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
export class CreateInvoiceDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do pedido',
|
|
||||||
example: 12345,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
orderId: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do usuário',
|
|
||||||
example: '001',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
userId: number;
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
export class CreatePaymentDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do pedido',
|
|
||||||
example: 12345,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
orderId: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Número do cartão',
|
|
||||||
example: '**** **** **** 1234',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
card: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Código de autorização',
|
|
||||||
example: 'A12345',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
auth: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'NSU da transação',
|
|
||||||
example: '123456789',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
nsu: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Número de parcelas',
|
|
||||||
example: 3,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
installments: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Valor do pagamento',
|
|
||||||
example: 1000.0,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
amount: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nome da bandeira',
|
|
||||||
example: 'VISA',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
flagName: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Tipo de pagamento',
|
|
||||||
example: 'CREDITO',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
paymentType: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do usuário',
|
|
||||||
example: '001',
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
userId: number;
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
export class OrderDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Data de criação do pedido',
|
|
||||||
example: '2024-04-02T10:00:00Z',
|
|
||||||
})
|
|
||||||
createDate: Date;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID da loja',
|
|
||||||
example: '001',
|
|
||||||
})
|
|
||||||
storeId: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do pedido',
|
|
||||||
example: 12345,
|
|
||||||
})
|
|
||||||
orderId: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do cliente',
|
|
||||||
example: '12345',
|
|
||||||
})
|
|
||||||
customerId: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nome do cliente',
|
|
||||||
example: 'João da Silva',
|
|
||||||
})
|
|
||||||
customerName: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do vendedor',
|
|
||||||
example: '001',
|
|
||||||
})
|
|
||||||
sellerId: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nome do vendedor',
|
|
||||||
example: 'Maria Santos',
|
|
||||||
})
|
|
||||||
sellerName: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID da forma de pagamento',
|
|
||||||
example: '001',
|
|
||||||
})
|
|
||||||
billingId: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nome da forma de pagamento',
|
|
||||||
example: 'Cartão de Crédito',
|
|
||||||
})
|
|
||||||
billingName: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do plano de pagamento',
|
|
||||||
example: '001',
|
|
||||||
})
|
|
||||||
planId: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nome do plano de pagamento',
|
|
||||||
example: '3x sem juros',
|
|
||||||
})
|
|
||||||
planName: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Valor total do pedido',
|
|
||||||
example: 1000.0,
|
|
||||||
})
|
|
||||||
amount: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Número de parcelas',
|
|
||||||
example: 3,
|
|
||||||
})
|
|
||||||
installments: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Valor total pago',
|
|
||||||
example: 1000.0,
|
|
||||||
})
|
|
||||||
amountPaid: number;
|
|
||||||
|
|
||||||
constructor(partial: Partial<OrderDto>) {
|
|
||||||
Object.assign(this, partial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
|
|
||||||
export class PaymentDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do pedido',
|
|
||||||
example: 12345,
|
|
||||||
})
|
|
||||||
orderId: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Data do pagamento',
|
|
||||||
example: '2024-04-02T10:00:00Z',
|
|
||||||
})
|
|
||||||
payDate: Date;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Número do cartão',
|
|
||||||
example: '**** **** **** 1234',
|
|
||||||
})
|
|
||||||
card: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Número de parcelas',
|
|
||||||
example: 3,
|
|
||||||
})
|
|
||||||
installments: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nome da bandeira',
|
|
||||||
example: 'VISA',
|
|
||||||
})
|
|
||||||
flagName: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Tipo de pagamento',
|
|
||||||
example: 'CREDITO',
|
|
||||||
})
|
|
||||||
type: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Valor do pagamento',
|
|
||||||
example: 1000.0,
|
|
||||||
})
|
|
||||||
amount: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'ID do usuário',
|
|
||||||
example: '001',
|
|
||||||
})
|
|
||||||
userId: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'NSU da transação',
|
|
||||||
example: '123456789',
|
|
||||||
})
|
|
||||||
nsu: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Código de autorização',
|
|
||||||
example: 'A12345',
|
|
||||||
})
|
|
||||||
auth: string;
|
|
||||||
|
|
||||||
constructor(partial: Partial<PaymentDto>) {
|
|
||||||
Object.assign(this, partial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common';
|
|
||||||
import {
|
|
||||||
ApiTags,
|
|
||||||
ApiOperation,
|
|
||||||
ApiParam,
|
|
||||||
ApiResponse,
|
|
||||||
ApiBearerAuth,
|
|
||||||
} from '@nestjs/swagger';
|
|
||||||
import { OrdersPaymentService } from './orders-payment.service';
|
|
||||||
import { OrderDto } from './dto/order.dto';
|
|
||||||
import { PaymentDto } from './dto/payment.dto';
|
|
||||||
import { CreatePaymentDto } from './dto/create-payment.dto';
|
|
||||||
import { CreateInvoiceDto } from './dto/create-invoice.dto';
|
|
||||||
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
|
|
||||||
|
|
||||||
@ApiTags('Orders Payment')
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@UseGuards(JwtAuthGuard)
|
|
||||||
@Controller('api/v1/orders-payment')
|
|
||||||
export class OrdersPaymentController {
|
|
||||||
constructor(private readonly orderPaymentService: OrdersPaymentService) {}
|
|
||||||
|
|
||||||
@Get('orders/:id')
|
|
||||||
@ApiOperation({ summary: 'Lista todos os pedidos de uma loja' })
|
|
||||||
@ApiParam({ name: 'id', description: 'ID da loja' })
|
|
||||||
@ApiResponse({
|
|
||||||
status: 200,
|
|
||||||
description: 'Lista de pedidos retornada com sucesso',
|
|
||||||
type: [OrderDto],
|
|
||||||
})
|
|
||||||
async findOrders(@Param('id') storeId: string): Promise<OrderDto[]> {
|
|
||||||
return this.orderPaymentService.findOrders(storeId, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('orders/:id/:orderId')
|
|
||||||
@ApiOperation({ summary: 'Busca um pedido específico' })
|
|
||||||
@ApiParam({ name: 'id', description: 'ID da loja' })
|
|
||||||
@ApiParam({ name: 'orderId', description: 'ID do pedido' })
|
|
||||||
@ApiResponse({
|
|
||||||
status: 200,
|
|
||||||
description: 'Pedido retornado com sucesso',
|
|
||||||
type: OrderDto,
|
|
||||||
})
|
|
||||||
async findOrder(
|
|
||||||
@Param('id') storeId: string,
|
|
||||||
@Param('orderId') orderId: number,
|
|
||||||
): Promise<OrderDto> {
|
|
||||||
const orders = await this.orderPaymentService.findOrders(storeId, orderId);
|
|
||||||
return orders[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('payments/:id')
|
|
||||||
@ApiOperation({ summary: 'Lista todos os pagamentos de um pedido' })
|
|
||||||
@ApiParam({ name: 'id', description: 'ID do pedido' })
|
|
||||||
@ApiResponse({
|
|
||||||
status: 200,
|
|
||||||
description: 'Lista de pagamentos retornada com sucesso',
|
|
||||||
type: [PaymentDto],
|
|
||||||
})
|
|
||||||
async findPayments(@Param('id') orderId: number): Promise<PaymentDto[]> {
|
|
||||||
return this.orderPaymentService.findPayments(orderId);
|
|
||||||
}
|
|
||||||
@Post('payments/create')
|
|
||||||
@ApiOperation({ summary: 'Cria um novo pagamento' })
|
|
||||||
@ApiResponse({
|
|
||||||
status: 201,
|
|
||||||
description: 'Pagamento criado com sucesso',
|
|
||||||
})
|
|
||||||
async createPayment(@Body() data: CreatePaymentDto): Promise<void> {
|
|
||||||
return this.orderPaymentService.createPayment(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post('invoice/create')
|
|
||||||
@ApiOperation({ summary: 'Cria uma nova fatura' })
|
|
||||||
@ApiResponse({
|
|
||||||
status: 201,
|
|
||||||
description: 'Fatura criada com sucesso',
|
|
||||||
})
|
|
||||||
async createInvoice(@Body() data: CreateInvoiceDto): Promise<void> {
|
|
||||||
return this.orderPaymentService.createInvoice(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable prettier/prettier */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
https://docs.nestjs.com/modules
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Module } from '@nestjs/common';
|
|
||||||
import { OrdersPaymentController } from './orders-payment.controller';
|
|
||||||
import { OrdersPaymentService } from './orders-payment.service';
|
|
||||||
import { DatabaseModule } from '../core/database/database.module';
|
|
||||||
import { ConfigModule } from '@nestjs/config';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [
|
|
||||||
ConfigModule,
|
|
||||||
DatabaseModule,
|
|
||||||
],
|
|
||||||
controllers: [OrdersPaymentController],
|
|
||||||
providers: [OrdersPaymentService],
|
|
||||||
exports: [OrdersPaymentService],
|
|
||||||
})
|
|
||||||
export class OrdersPaymentModule { }
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import { Injectable, Inject } from '@nestjs/common';
|
|
||||||
import { DataSource } from 'typeorm';
|
|
||||||
import { ConfigService } from '@nestjs/config';
|
|
||||||
import { DATA_SOURCE } from '../core/constants';
|
|
||||||
import { OrderDto } from './dto/order.dto';
|
|
||||||
import { PaymentDto } from './dto/payment.dto';
|
|
||||||
import { CreatePaymentDto } from './dto/create-payment.dto';
|
|
||||||
import { CreateInvoiceDto } from './dto/create-invoice.dto';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class OrdersPaymentService {
|
|
||||||
constructor(
|
|
||||||
private readonly configService: ConfigService,
|
|
||||||
@Inject(DATA_SOURCE) private readonly dataSource: DataSource,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async findOrders(storeId: string, orderId: number): Promise<OrderDto[]> {
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
try {
|
|
||||||
const sql = `SELECT PCPEDC.DATA as "createDate"
|
|
||||||
,PCPEDC.CODFILIAL as "storeId"
|
|
||||||
,PCPEDC.NUMPED as "orderId"
|
|
||||||
,PCPEDC.CODCLI as "customerId"
|
|
||||||
,PCCLIENT.CLIENTE as "customerName"
|
|
||||||
,PCPEDC.CODUSUR as "sellerId"
|
|
||||||
,PCUSUARI.NOME as "sellerName"
|
|
||||||
,PCPEDC.CODCOB as "billingId"
|
|
||||||
,PCCOB.COBRANCA as "billingName"
|
|
||||||
,PCPEDC.CODPLPAG as "planId"
|
|
||||||
,PCPLPAG.DESCRICAO as "planName"
|
|
||||||
,ROUND(PCPEDC.VLATEND,2) as "amount"
|
|
||||||
,NVL(PCPLPAG.NUMPARCELAS,1) as "installments"
|
|
||||||
,( SELECT SUM(ESTPAGAMENTO.VALOR) FROM ESTPAGAMENTO
|
|
||||||
WHERE ESTPAGAMENTO.NUMORCA = PCPEDC.NUMPED ) as "amountPaid"
|
|
||||||
FROM PCPEDC, PCCLIENT, PCUSUARI, PCCOB, PCPLPAG
|
|
||||||
WHERE PCPEDC.CODCLI = PCCLIENT.CODCLI
|
|
||||||
AND PCPEDC.CODUSUR = PCUSUARI.CODUSUR
|
|
||||||
AND PCPEDC.CODPLPAG = PCPLPAG.CODPLPAG
|
|
||||||
AND PCPEDC.CODCOB = PCCOB.CODCOB
|
|
||||||
AND PCPEDC.CONDVENDA = 7
|
|
||||||
AND PCPEDC.POSICAO IN ('L')
|
|
||||||
AND PCPEDC.DATA >= TRUNC(SYSDATE) - 5
|
|
||||||
AND PCPEDC.CODFILIAL = ${storeId} `;
|
|
||||||
let sqlWhere = '';
|
|
||||||
if (orderId > 0) {
|
|
||||||
sqlWhere += ` AND PCPEDC.NUMPED = ${orderId}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const orders = await queryRunner.manager.query(sql + sqlWhere);
|
|
||||||
return orders.map((order) => new OrderDto(order));
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async findPayments(orderId: number): Promise<PaymentDto[]> {
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
try {
|
|
||||||
const sql = `SELECT
|
|
||||||
ESTPAGAMENTO.NUMORCA as "orderId"
|
|
||||||
,ESTPAGAMENTO.DTPAGAMENTO as "payDate"
|
|
||||||
,ESTPAGAMENTO.CARTAO as "card"
|
|
||||||
,ESTPAGAMENTO.PARCELAS as "installments"
|
|
||||||
,ESTPAGAMENTO.NOMEBANDEIRA as "flagName"
|
|
||||||
,ESTPAGAMENTO.FORMAPAGTO as "type"
|
|
||||||
,ESTPAGAMENTO.VALOR as "amount"
|
|
||||||
,ESTPAGAMENTO.CODFUNC as "userId"
|
|
||||||
,ESTPAGAMENTO.NSU as "nsu"
|
|
||||||
,ESTPAGAMENTO.CODAUTORIZACAO as "auth"
|
|
||||||
FROM ESTPAGAMENTO
|
|
||||||
WHERE ESTPAGAMENTO.NUMORCA = ${orderId}`;
|
|
||||||
|
|
||||||
const payments = await queryRunner.manager.query(sql);
|
|
||||||
return payments.map((payment) => new PaymentDto(payment));
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async createPayment(payment: CreatePaymentDto): Promise<void> {
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
await queryRunner.startTransaction();
|
|
||||||
try {
|
|
||||||
const sql = `INSERT INTO ESTPAGAMENTO ( NUMORCA, DTPAGAMENTO, CARTAO, CODAUTORIZACAO, CODRESPOSTA, DTREQUISICAO, DTSERVIDOR, IDTRANSACAO,
|
|
||||||
NSU, PARCELAS, VALOR, NOMEBANDEIRA, FORMAPAGTO, DTPROCESSAMENTO, CODFUNC )
|
|
||||||
VALUES ( ${payment.orderId}, TRUNC(SYSDATE), '${payment.card}', '${payment.auth}', '00', SYSDATE, SYSDATE, NULL,
|
|
||||||
'${payment.nsu}', ${payment.installments}, ${payment.amount}, '${payment.flagName}',
|
|
||||||
'${payment.paymentType}', SYSDATE, ${payment.userId} ) `;
|
|
||||||
|
|
||||||
await queryRunner.manager.query(sql);
|
|
||||||
await queryRunner.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await queryRunner.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async createInvoice(data: CreateInvoiceDto): Promise<void> {
|
|
||||||
const queryRunner = this.dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
await queryRunner.startTransaction();
|
|
||||||
try {
|
|
||||||
const sql = `BEGIN
|
|
||||||
ESK_FATURAMENTO.FATURAMENTO_VENDA_ASSISTIDA(${data.orderId}, ${data.userId});
|
|
||||||
END;`;
|
|
||||||
await queryRunner.manager.query(sql);
|
|
||||||
await queryRunner.commitTransaction();
|
|
||||||
} catch (error) {
|
|
||||||
await queryRunner.rollbackTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user