implementação do logger
This commit is contained in:
10930
package-lock.json
generated
10930
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -20,23 +20,27 @@
|
|||||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/axios": "^3.1.3",
|
"@nestjs/axios": "^4.0.0",
|
||||||
"@nestjs/common": "^11.0.12",
|
"@nestjs/common": "^11.0.12",
|
||||||
|
"@nestjs/config": "^4.0.2",
|
||||||
"@nestjs/core": "^11.0.12",
|
"@nestjs/core": "^11.0.12",
|
||||||
"@nestjs/jwt": "^10.2.0",
|
"@nestjs/jwt": "^11.0.0",
|
||||||
|
"@nestjs/mapped-types": "^1.0.0",
|
||||||
"@nestjs/microservices": "^11.0.12",
|
"@nestjs/microservices": "^11.0.12",
|
||||||
"@nestjs/passport": "^10.0.3",
|
"@nestjs/passport": "^11.0.0",
|
||||||
"@nestjs/platform-express": "^11.0.12",
|
"@nestjs/platform-express": "^11.0.12",
|
||||||
|
"@nestjs/schematics": "^8.0.0",
|
||||||
"@nestjs/swagger": "^7.4.2",
|
"@nestjs/swagger": "^7.4.2",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@nestjs/websockets": "^11.0.12",
|
"@nestjs/websockets": "^11.0.12",
|
||||||
"@types/eslint": "^9.6.1",
|
"@types/eslint": "^9.6.1",
|
||||||
"@types/estree": "^1.0.7",
|
"@types/estree": "^1.0.7",
|
||||||
"aws-sdk": "^2.1692.0",
|
"aws-sdk": "^2.1692.0",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.8.4",
|
||||||
"fs": "0.0.1-security",
|
"fs": "0.0.1-security",
|
||||||
"guid-typescript": "^1.0.9",
|
"guid-typescript": "^1.0.9",
|
||||||
"https": "^1.0.0",
|
"https": "^1.0.0",
|
||||||
|
"ioredis": "^5.6.0",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"md5-typescript": "^1.0.5",
|
"md5-typescript": "^1.0.5",
|
||||||
"multer": "^1.4.5-lts.2",
|
"multer": "^1.4.5-lts.2",
|
||||||
@@ -55,7 +59,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "^11.0.5",
|
"@nestjs/cli": "^11.0.5",
|
||||||
"@nestjs/schematics": "^7.1.3",
|
"@nestjs/schematics": "^8.0.0",
|
||||||
"@nestjs/testing": "^11.0.12",
|
"@nestjs/testing": "^11.0.12",
|
||||||
"@types/express": "^4.17.8",
|
"@types/express": "^4.17.8",
|
||||||
"@types/jest": "^26.0.15",
|
"@types/jest": "^26.0.15",
|
||||||
|
|||||||
6
src/Log/ILogger.ts
Normal file
6
src/Log/ILogger.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface ILogger {
|
||||||
|
log(message: string): void;
|
||||||
|
warn(message: string): void;
|
||||||
|
error(message: string, trace?: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
26
src/Log/NestLoggerAdapter.ts
Normal file
26
src/Log/NestLoggerAdapter.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Logger } from '@nestjs/common';
|
||||||
|
import { ILogger } from './ILogger';
|
||||||
|
|
||||||
|
export class NestLoggerAdapter implements ILogger {
|
||||||
|
private readonly logger: Logger;
|
||||||
|
|
||||||
|
constructor(private readonly context: string) {
|
||||||
|
this.logger = new Logger(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(message: string, meta?: Record<string, any>): void {
|
||||||
|
this.logger.log(this.formatMessage(message, meta));
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(message: string, meta?: Record<string, any>): void {
|
||||||
|
this.logger.warn(this.formatMessage(message, meta));
|
||||||
|
}
|
||||||
|
|
||||||
|
error(message: string, trace?: string, meta?: Record<string, any>): void {
|
||||||
|
this.logger.error(this.formatMessage(message, meta), trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
private formatMessage(message: string, meta?: Record<string, any>): string {
|
||||||
|
return meta ? `${message} | ${JSON.stringify(meta)}` : message;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/Log/logger.decorator.ts
Normal file
22
src/Log/logger.decorator.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { ILogger } from './ILogger';
|
||||||
|
|
||||||
|
export function LogExecution(label?: string) {
|
||||||
|
return function (
|
||||||
|
target: any,
|
||||||
|
propertyKey: string,
|
||||||
|
descriptor: PropertyDescriptor
|
||||||
|
) {
|
||||||
|
const original = descriptor.value;
|
||||||
|
descriptor.value = async function (...args: any[]) {
|
||||||
|
const logger: ILogger = this.logger;
|
||||||
|
const context = label || `${target.constructor.name}.${propertyKey}`;
|
||||||
|
const start = Date.now();
|
||||||
|
logger.log(`Iniciando: ${context} | ${JSON.stringify({ args })}`);
|
||||||
|
const result = await original.apply(this, args);
|
||||||
|
const duration = Date.now() - start;
|
||||||
|
logger.log(`Finalizado: ${context} em ${duration}ms`);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
return descriptor;
|
||||||
|
};
|
||||||
|
}
|
||||||
14
src/Log/logger.module.ts
Normal file
14
src/Log/logger.module.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { NestLoggerAdapter } from './NestLoggerAdapter';
|
||||||
|
import { ILogger } from './ILogger';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: 'LoggerService',
|
||||||
|
useFactory: () => new NestLoggerAdapter('DataConsultService'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
exports: ['LoggerService'],
|
||||||
|
})
|
||||||
|
export class LoggerModule {}
|
||||||
@@ -18,7 +18,9 @@ import { ReasonTableModule } from './crm/reason-table/reason-table.module';
|
|||||||
import { NegotiationsModule } from './crm/negotiations/negotiations.module';
|
import { NegotiationsModule } from './crm/negotiations/negotiations.module';
|
||||||
import { HttpModule } from '@nestjs/axios';
|
import { HttpModule } from '@nestjs/axios';
|
||||||
import { LogisticController } from './logistic/logistic.controller';
|
import { LogisticController } from './logistic/logistic.controller';
|
||||||
|
import { CacheModule } from './core/configs/cache/redis.module';
|
||||||
import { LogisticService } from './logistic/logistic.service';
|
import { LogisticService } from './logistic/logistic.service';
|
||||||
|
import { LoggerModule } from './Log/logger.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -29,12 +31,15 @@ import { LogisticService } from './logistic/logistic.service';
|
|||||||
NegotiationsModule,
|
NegotiationsModule,
|
||||||
OccurrencesModule,
|
OccurrencesModule,
|
||||||
ReasonTableModule,
|
ReasonTableModule,
|
||||||
|
LoggerModule,
|
||||||
DataConsultModule,
|
DataConsultModule,
|
||||||
ProductsModule,
|
ProductsModule,
|
||||||
AuthModule,
|
AuthModule,
|
||||||
OrdersModule,
|
OrdersModule,
|
||||||
TypeOrmModule.forRoot(typeOrmConfig),
|
TypeOrmModule.forRoot(typeOrmConfig),
|
||||||
TypeOrmModule.forRoot(typeOrmPgConfig),
|
TypeOrmModule.forRoot(typeOrmPgConfig),
|
||||||
|
CacheModule,
|
||||||
|
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
OcorrencesController, LogisticController,],
|
OcorrencesController, LogisticController,],
|
||||||
|
|||||||
6
src/core/configs/cache/IRedisClient.ts
vendored
Normal file
6
src/core/configs/cache/IRedisClient.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export interface IRedisClient {
|
||||||
|
get<T>(key: string): Promise<T | null>;
|
||||||
|
set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
|
||||||
|
del(key: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
8
src/core/configs/cache/redis-client.adapter.provider.ts
vendored
Normal file
8
src/core/configs/cache/redis-client.adapter.provider.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
import { RedisClientAdapter } from './redis-client.adapter';
|
||||||
|
export const RedisClientToken = 'RedisClientInterface';
|
||||||
|
|
||||||
|
export const RedisClientAdapterProvider = {
|
||||||
|
provide: RedisClientToken,
|
||||||
|
useClass: RedisClientAdapter,
|
||||||
|
};
|
||||||
24
src/core/configs/cache/redis-client.adapter.ts
vendored
Normal file
24
src/core/configs/cache/redis-client.adapter.ts
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Redis } from 'ioredis';
|
||||||
|
import { IRedisClient } from './IRedisClient';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RedisClientAdapter implements IRedisClient {
|
||||||
|
constructor(
|
||||||
|
@Inject('REDIS_CLIENT')
|
||||||
|
private readonly redis: Redis
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async get<T>(key: string): Promise<T | null> {
|
||||||
|
const data = await this.redis.get(key);
|
||||||
|
return data ? JSON.parse(data) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async set<T>(key: string, value: T, ttlSeconds = 300): Promise<void> {
|
||||||
|
await this.redis.set(key, JSON.stringify(value), 'EX', ttlSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
async del(key: string): Promise<void> {
|
||||||
|
await this.redis.del(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/core/configs/cache/redis.module.ts
vendored
Normal file
12
src/core/configs/cache/redis.module.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Module, Global } from '@nestjs/common';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { RedisProvider } from './redis.provider';
|
||||||
|
import { RedisClientAdapterProvider } from './redis-client.adapter.provider';
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
providers: [RedisProvider, RedisClientAdapterProvider],
|
||||||
|
exports: [RedisProvider, RedisClientAdapterProvider],
|
||||||
|
})
|
||||||
|
export class CacheModule {}
|
||||||
21
src/core/configs/cache/redis.provider.ts
vendored
Normal file
21
src/core/configs/cache/redis.provider.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Provider } from '@nestjs/common';
|
||||||
|
import Redis from 'ioredis';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
export const RedisProvider: Provider = {
|
||||||
|
provide: 'REDIS_CLIENT',
|
||||||
|
useFactory: (configService: ConfigService) => {
|
||||||
|
const redis = new Redis({
|
||||||
|
host: configService.get<string>('REDIS_HOST', '10.1.1.109'),
|
||||||
|
port: configService.get<number>('REDIS_PORT', 6379),
|
||||||
|
// password: configService.get<string>('REDIS_PASSWORD', ''),
|
||||||
|
});
|
||||||
|
|
||||||
|
redis.on('error', (err) => {
|
||||||
|
console.error('Erro ao conectar ao Redis:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
return redis;
|
||||||
|
},
|
||||||
|
inject: [ConfigService],
|
||||||
|
};
|
||||||
@@ -1,44 +1,43 @@
|
|||||||
/* eslint-disable prettier/prettier */
|
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
https://docs.nestjs.com/controllers#controllers
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Controller, Get, Param } from '@nestjs/common';
|
import { Controller, Get, Param } from '@nestjs/common';
|
||||||
|
import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger';
|
||||||
import { DataConsultService } from './data-consult.service';
|
import { DataConsultService } from './data-consult.service';
|
||||||
|
|
||||||
|
@ApiTags('DataConsult')
|
||||||
@Controller('api/v1/data-consult')
|
@Controller('api/v1/data-consult')
|
||||||
export class DataConsultController {
|
export class DataConsultController {
|
||||||
|
|
||||||
constructor(private readonly dataConsultService: DataConsultService) {}
|
constructor(private readonly dataConsultService: DataConsultService) {}
|
||||||
|
|
||||||
|
@Get('stores')
|
||||||
|
@ApiOperation({ summary: 'Lista todas as lojas' })
|
||||||
|
async stores() {
|
||||||
|
return this.dataConsultService.stores();
|
||||||
|
}
|
||||||
|
|
||||||
@Get('stores')
|
@Get('sellers')
|
||||||
async stores() {
|
@ApiOperation({ summary: 'Lista todos os vendedores' })
|
||||||
return this.dataConsultService.stores();
|
async sellers() {
|
||||||
}
|
return this.dataConsultService.sellers();
|
||||||
|
}
|
||||||
|
|
||||||
@Get('sellers')
|
@Get('billings')
|
||||||
async sellers() {
|
@ApiOperation({ summary: 'Retorna informações de faturamento' })
|
||||||
return this.dataConsultService.sellers();
|
async billings() {
|
||||||
}
|
return this.dataConsultService.billings();
|
||||||
|
}
|
||||||
|
|
||||||
@Get('billings')
|
@Get('customers/:filter')
|
||||||
async billings() {
|
@ApiOperation({ summary: 'Filtra clientes pelo parâmetro fornecido' })
|
||||||
return this.dataConsultService.billings();
|
@ApiParam({ name: 'filter', description: 'Filtro de busca para clientes' })
|
||||||
}
|
async customer(@Param('filter') filter: string) {
|
||||||
|
return this.dataConsultService.customers(filter);
|
||||||
@Get('customers/:filter')
|
}
|
||||||
async customer(@Param('filter') filter: string) {
|
|
||||||
return this.dataConsultService.customers(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get('products/:filter')
|
|
||||||
async products(@Param('filter') filter: string) {
|
|
||||||
return this.dataConsultService.products(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Get('products/:filter')
|
||||||
|
@ApiOperation({ summary: 'Filtra produtos pelo parâmetro fornecido' })
|
||||||
|
@ApiParam({ name: 'filter', description: 'Filtro de busca para produtos' })
|
||||||
|
async products(@Param('filter') filter: string) {
|
||||||
|
return this.dataConsultService.products(filter);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
/* eslint-disable prettier/prettier */
|
import { Module } from '@nestjs/common';
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
import { DataConsultService } from './data-consult.service';
|
import { DataConsultService } from './data-consult.service';
|
||||||
import { DataConsultController } from './data-consult.controller';
|
import { DataConsultController } from './data-consult.controller';
|
||||||
|
import { DataConsultRepository } from './data-consult.repository';
|
||||||
/*
|
import { CacheModule } from '../core/configs/cache/redis.module';
|
||||||
https://docs.nestjs.com/modules
|
import { LoggerModule } from 'src/Log/logger.module';
|
||||||
*/
|
|
||||||
|
|
||||||
import { Module } from '@nestjs/common';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [],
|
imports: [CacheModule,LoggerModule],
|
||||||
controllers: [
|
controllers: [DataConsultController],
|
||||||
DataConsultController,],
|
providers: [
|
||||||
providers: [
|
DataConsultService,
|
||||||
DataConsultService,],
|
DataConsultRepository,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class DataConsultModule { }
|
export class DataConsultModule {}
|
||||||
|
|||||||
158
src/data-consult/data-consult.repository.ts
Normal file
158
src/data-consult/data-consult.repository.ts
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { DataSource } from 'typeorm';
|
||||||
|
import { typeOrmConfig } from '../core/configs/typeorm.config';
|
||||||
|
import { StoreDto } from './dto/store.dto';
|
||||||
|
import { SellerDto } from './dto/seller.dto';
|
||||||
|
import { BillingDto } from './dto/billing.dto';
|
||||||
|
import { CustomerDto } from './dto/customer.dto';
|
||||||
|
import { ProductDto } from './dto/product.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DataConsultRepository {
|
||||||
|
private readonly dataSource: DataSource;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.dataSource = new DataSource(typeOrmConfig);
|
||||||
|
this.dataSource.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async executeQuery<T>(sql: string, params: any[] = []): Promise<T> {
|
||||||
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
|
await queryRunner.connect();
|
||||||
|
try {
|
||||||
|
const result = await queryRunner.query(sql, params);
|
||||||
|
return result as T;
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async findStores(): Promise<StoreDto[]> {
|
||||||
|
const sql = `
|
||||||
|
SELECT PCFILIAL.CODIGO as "id",
|
||||||
|
PCFILIAL.RAZAOSOCIAL as "name",
|
||||||
|
PCFILIAL.CODIGO || ' - ' || PCFILIAL.FANTASIA as "store"
|
||||||
|
FROM PCFILIAL
|
||||||
|
WHERE PCFILIAL.CODIGO NOT IN ('99', '69')
|
||||||
|
ORDER BY TO_NUMBER(PCFILIAL.CODIGO)
|
||||||
|
`;
|
||||||
|
return this.executeQuery<StoreDto[]>(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findSellers(): Promise<SellerDto[]> {
|
||||||
|
const sql = `
|
||||||
|
SELECT PCUSUARI.CODUSUR as "id",
|
||||||
|
PCUSUARI.NOME as "name"
|
||||||
|
FROM PCUSUARI
|
||||||
|
WHERE PCUSUARI.DTTERMINO IS NULL
|
||||||
|
AND PCUSUARI.TIPOVEND NOT IN ('P')
|
||||||
|
ORDER BY PCUSUARI.NOME
|
||||||
|
`;
|
||||||
|
return this.executeQuery<SellerDto[]>(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findBillings(): Promise<BillingDto[]> {
|
||||||
|
const sql = `
|
||||||
|
SELECT PCCOB.CODCOB as "id",
|
||||||
|
PCCOB.CODCOB || ' - ' || PCCOB.COBRANCA as "description"
|
||||||
|
FROM PCCOB
|
||||||
|
WHERE PCCOB.CODCOB NOT IN ('DEVP', 'DEVT', 'DESD')
|
||||||
|
ORDER BY PCCOB.COBRANCA
|
||||||
|
`;
|
||||||
|
return this.executeQuery<BillingDto[]>(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findCustomers(filter: string): Promise<CustomerDto[]> {
|
||||||
|
const queries = [
|
||||||
|
{
|
||||||
|
sql: `
|
||||||
|
SELECT PCCLIENT.CODCLI as "id",
|
||||||
|
PCCLIENT.CODCLI || ' - ' || PCCLIENT.CLIENTE ||
|
||||||
|
' ( ' || REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') || ' )' as "name"
|
||||||
|
FROM PCCLIENT
|
||||||
|
WHERE PCCLIENT.CODCLI = REGEXP_REPLACE(?, '[^0-9]', '')
|
||||||
|
ORDER BY PCCLIENT.CLIENTE
|
||||||
|
`,
|
||||||
|
params: [filter],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: `
|
||||||
|
SELECT PCCLIENT.CODCLI as "id",
|
||||||
|
PCCLIENT.CODCLI || ' - ' || PCCLIENT.CLIENTE ||
|
||||||
|
' ( ' || REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') || ' )' as "name"
|
||||||
|
FROM PCCLIENT
|
||||||
|
WHERE REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE(?, '[^0-9]', '')
|
||||||
|
ORDER BY PCCLIENT.CLIENTE
|
||||||
|
`,
|
||||||
|
params: [filter],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: `
|
||||||
|
SELECT PCCLIENT.CODCLI as "id",
|
||||||
|
PCCLIENT.CODCLI || ' - ' || PCCLIENT.CLIENTE ||
|
||||||
|
' ( ' || REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') || ' )' as "name"
|
||||||
|
FROM PCCLIENT
|
||||||
|
WHERE PCCLIENT.CLIENTE LIKE ?
|
||||||
|
ORDER BY PCCLIENT.CLIENTE
|
||||||
|
`,
|
||||||
|
params: [filter.toUpperCase().replace('@', '%') + '%'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { sql, params } of queries) {
|
||||||
|
const result = await this.executeQuery<CustomerDto[]>(sql, params);
|
||||||
|
if (result.length > 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async findProducts(filter: string): Promise<ProductDto[]> {
|
||||||
|
const queries = [
|
||||||
|
{
|
||||||
|
sql: `
|
||||||
|
SELECT PCPRODUT.CODPROD as "id",
|
||||||
|
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
|
||||||
|
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
|
||||||
|
FROM PCPRODUT
|
||||||
|
WHERE PCPRODUT.CODPROD = REGEXP_REPLACE(?, '[^0-9]', '')
|
||||||
|
ORDER BY PCPRODUT.DESCRICAO
|
||||||
|
`,
|
||||||
|
params: [filter],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: `
|
||||||
|
SELECT PCPRODUT.CODPROD as "id",
|
||||||
|
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
|
||||||
|
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
|
||||||
|
FROM PCPRODUT
|
||||||
|
WHERE PCPRODUT.CODAUXILIAR = REGEXP_REPLACE(?, '[^0-9]', '')
|
||||||
|
ORDER BY PCPRODUT.DESCRICAO
|
||||||
|
`,
|
||||||
|
params: [filter],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: `
|
||||||
|
SELECT PCPRODUT.CODPROD as "id",
|
||||||
|
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
|
||||||
|
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
|
||||||
|
FROM PCPRODUT
|
||||||
|
WHERE PCPRODUT.DESCRICAO LIKE ?
|
||||||
|
ORDER BY PCPRODUT.DESCRICAO
|
||||||
|
`,
|
||||||
|
params: [filter + '%'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const { sql, params } of queries) {
|
||||||
|
const result = await this.executeQuery<ProductDto[]>(sql, params);
|
||||||
|
if (result.length > 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,170 +1,127 @@
|
|||||||
/* eslint-disable prettier/prettier */
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
import { IRedisClient } from '../core/configs/cache/IRedisClient';
|
||||||
/*
|
import { RedisClientToken } from '../core/configs/cache/redis-client.adapter.provider';
|
||||||
|
import { DataConsultRepository } from './data-consult.repository';
|
||||||
|
import { StoreDto } from './dto/store.dto';
|
||||||
|
import { SellerDto } from './dto/seller.dto';
|
||||||
|
import { BillingDto } from './dto/billing.dto';
|
||||||
|
import { CustomerDto } from './dto/customer.dto';
|
||||||
|
import { ProductDto } from './dto/product.dto';
|
||||||
|
import { ILogger } from '../Log/ILogger';
|
||||||
|
|
||||||
https://docs.nestjs.com/providers#services
|
const DEFAULT_CACHE_TTL = 100;
|
||||||
*/
|
|
||||||
|
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { typeOrmConfig } from '../core/configs/typeorm.config';
|
|
||||||
import { DataSource } from 'typeorm';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DataConsultService {
|
export class DataConsultService {
|
||||||
|
constructor(
|
||||||
|
private readonly repository: DataConsultRepository,
|
||||||
|
@Inject(RedisClientToken)
|
||||||
|
private readonly redisClient: IRedisClient,
|
||||||
|
@Inject('LoggerService')
|
||||||
|
private readonly logger: ILogger
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Método genérico para lidar com lógica de cache
|
||||||
|
* @param cacheKey - A chave a ser usada para cache
|
||||||
|
* @param fetchFn - Função para buscar dados se não estiverem no cache
|
||||||
|
* @param ttl - Tempo de vida em segundos para o cache
|
||||||
|
* @returns Os dados em cache ou recentemente buscados
|
||||||
|
*/
|
||||||
|
private async getCachedData<T>(
|
||||||
|
cacheKey: string,
|
||||||
|
fetchFn: () => Promise<T>,
|
||||||
|
ttl: number = DEFAULT_CACHE_TTL
|
||||||
|
): Promise<T> {
|
||||||
|
try {
|
||||||
|
this.logger.log(`Tentando obter dados em cache para a chave: ${cacheKey}`);
|
||||||
|
const cached = await this.redisClient.get<T>(cacheKey);
|
||||||
|
|
||||||
async stores() {
|
if (cached) {
|
||||||
const dataSource = new DataSource(typeOrmConfig);
|
this.logger.log(`Cache encontrado para a chave: ${cacheKey}`);
|
||||||
await dataSource.initialize();
|
return cached;
|
||||||
const queryRunner = dataSource.createQueryRunner();
|
}
|
||||||
await queryRunner.connect();
|
|
||||||
try {
|
|
||||||
const sql = `SELECT PCFILIAL.CODIGO as "id"
|
|
||||||
,PCFILIAL.RAZAOSOCIAL as "name"
|
|
||||||
,PCFILIAL.CODIGO || ' - ' || PCFILIAL.FANTASIA as "store"
|
|
||||||
FROM PCFILIAL
|
|
||||||
WHERE PCFILIAL.CODIGO NOT IN ('99', '69')
|
|
||||||
ORDER BY TO_NUMBER(PCFILIAL.CODIGO)`;
|
|
||||||
|
|
||||||
|
this.logger.log(`Cache não encontrado para a chave: ${cacheKey}, buscando na origem`);
|
||||||
|
const result = await fetchFn();
|
||||||
|
|
||||||
const stores = await queryRunner.manager.query(sql);
|
try {
|
||||||
|
await this.redisClient.set<T>(cacheKey, result, ttl);
|
||||||
|
this.logger.log(`Dados armazenados em cache com sucesso para a chave: ${cacheKey}`);
|
||||||
|
} catch (cacheError) {
|
||||||
|
this.logger.warn(`Falha ao armazenar dados em cache para a chave: ${cacheKey}`);
|
||||||
|
this.logger.error('Detalhes do erro de cache:', cacheError instanceof Error ? cacheError.stack : '');
|
||||||
|
}
|
||||||
|
|
||||||
return stores;
|
return result;
|
||||||
} finally {
|
} catch (error) {
|
||||||
await queryRunner.release();
|
this.logger.error(
|
||||||
await dataSource.destroy();
|
`Erro no método getCachedData para a chave ${cacheKey}:`,
|
||||||
}
|
error instanceof Error ? error.stack : ''
|
||||||
|
);
|
||||||
|
return fetchFn();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter todas as lojas com cache
|
||||||
|
* @returns Array de StoreDto
|
||||||
|
*/
|
||||||
|
async stores(): Promise<StoreDto[]> {
|
||||||
|
this.logger.log('Buscando todas as lojas');
|
||||||
|
return this.getCachedData<StoreDto[]>(
|
||||||
|
'data-consult:stores',
|
||||||
|
() => this.repository.findStores()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async sellers() {
|
/**
|
||||||
const dataSource = new DataSource(typeOrmConfig);
|
* Obter todos os vendedores com cache
|
||||||
await dataSource.initialize();
|
* @returns Array de SellerDto
|
||||||
const queryRunner = dataSource.createQueryRunner();
|
*/
|
||||||
await queryRunner.connect();
|
async sellers(): Promise<SellerDto[]> {
|
||||||
try {
|
this.logger.log('Buscando todos os vendedores');
|
||||||
const sql = `SELECT PCUSUARI.CODUSUR as "id"
|
return this.getCachedData<SellerDto[]>(
|
||||||
,PCUSUARI.NOME as "name"
|
'data-consult:sellers',
|
||||||
FROM PCUSUARI
|
() => this.repository.findSellers()
|
||||||
WHERE PCUSUARI.DTTERMINO IS NULL
|
);
|
||||||
AND PCUSUARI.TIPOVEND NOT IN ('P')
|
}
|
||||||
ORDER BY PCUSUARI.NOME`;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter todos os faturamentos com cache
|
||||||
|
* @returns Array de BillingDto
|
||||||
|
*/
|
||||||
|
async billings(): Promise<BillingDto[]> {
|
||||||
|
this.logger.log('Buscando todos os faturamentos');
|
||||||
|
return this.getCachedData<BillingDto[]>(
|
||||||
|
'data-consult:billings',
|
||||||
|
() => this.repository.findBillings()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const sellers = await queryRunner.manager.query(sql);
|
/**
|
||||||
|
* Obter clientes filtrados por termo de pesquisa com cache
|
||||||
return sellers;
|
* @param filter - Termo de pesquisa para filtrar clientes
|
||||||
} finally {
|
* @returns Array de CustomerDto
|
||||||
await queryRunner.release();
|
*/
|
||||||
await dataSource.destroy();
|
async customers(filter: string): Promise<CustomerDto[]> {
|
||||||
}
|
this.logger.log(`Buscando clientes com filtro: ${filter}`);
|
||||||
}
|
return this.getCachedData<CustomerDto[]>(
|
||||||
|
`data-consult:customers:${filter}`,
|
||||||
async billings() {
|
() => this.repository.findCustomers(filter)
|
||||||
const dataSource = new DataSource(typeOrmConfig);
|
);
|
||||||
await dataSource.initialize();
|
}
|
||||||
const queryRunner = dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
try {
|
|
||||||
const sql = `SELECT PCCOB.CODCOB as "id"
|
|
||||||
,PCCOB.CODCOB||' - '||PCCOB.COBRANCA as "description"
|
|
||||||
FROM PCCOB
|
|
||||||
WHERE PCCOB.CODCOB NOT IN ('DEVP', 'DEVT', 'DESD')
|
|
||||||
ORDER BY PCCOB.COBRANCA`;
|
|
||||||
|
|
||||||
|
|
||||||
const sellers = await queryRunner.manager.query(sql);
|
|
||||||
|
|
||||||
return sellers;
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
await dataSource.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async customers(filter: string) {
|
|
||||||
const dataSource = new DataSource(typeOrmConfig);
|
|
||||||
await dataSource.initialize();
|
|
||||||
const queryRunner = dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
try {
|
|
||||||
let sql = `SELECT PCCLIENT.CODCLI as "id"
|
|
||||||
,PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE||
|
|
||||||
' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name"
|
|
||||||
FROM PCCLIENT
|
|
||||||
WHERE PCCLIENT.CODCLI = REGEXP_REPLACE('${filter}', '[^0-9]', '')
|
|
||||||
ORDER BY PCCLIENT.CLIENTE`;
|
|
||||||
let customers = await queryRunner.manager.query(sql);
|
|
||||||
|
|
||||||
if (customers.length == 0) {
|
|
||||||
sql = `SELECT PCCLIENT.CODCLI as "id"
|
|
||||||
,PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE||
|
|
||||||
' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name"
|
|
||||||
FROM PCCLIENT
|
|
||||||
WHERE REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '') = REGEXP_REPLACE('${filter}', '[^0-9]', '')
|
|
||||||
ORDER BY PCCLIENT.CLIENTE`;
|
|
||||||
customers = await queryRunner.manager.query(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customers.length == 0) {
|
|
||||||
sql = `SELECT PCCLIENT.CODCLI as "id"
|
|
||||||
,PCCLIENT.CODCLI || ' - '|| PCCLIENT.CLIENTE||
|
|
||||||
' ( '||REGEXP_REPLACE(PCCLIENT.CGCENT, '[^0-9]', '')||' )' as "name"
|
|
||||||
FROM PCCLIENT
|
|
||||||
WHERE PCCLIENT.CLIENTE LIKE '${filter.toUpperCase().replace('@', '%')}%'
|
|
||||||
ORDER BY PCCLIENT.CLIENTE`;
|
|
||||||
customers = await queryRunner.manager.query(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
return customers;
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
await dataSource.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async products(filter: string) {
|
|
||||||
const dataSource = new DataSource(typeOrmConfig);
|
|
||||||
await dataSource.initialize();
|
|
||||||
const queryRunner = dataSource.createQueryRunner();
|
|
||||||
await queryRunner.connect();
|
|
||||||
try {
|
|
||||||
let sql = `SELECT PCPRODUT.CODPROD as "id"
|
|
||||||
,PCPRODUT.CODPROD || ' - '|| PCPRODUT.DESCRICAO||
|
|
||||||
' ( '||REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '')||' )' as "description"
|
|
||||||
FROM PCPRODUT
|
|
||||||
WHERE PCPRODUT.CODPROD = REGEXP_REPLACE('${filter}', '[^0-9]', '')
|
|
||||||
ORDER BY PCPRODUT.DESCRICAO`;
|
|
||||||
let products = await queryRunner.manager.query(sql);
|
|
||||||
|
|
||||||
if (products.length == 0) {
|
|
||||||
sql = `SELECT PCPRODUT.CODPROD as "id"
|
|
||||||
,PCPRODUT.CODPROD || ' - '|| PCPRODUT.DESCRICAO||
|
|
||||||
' ( '||REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '')||' )' as "description"
|
|
||||||
FROM PCPRODUT
|
|
||||||
WHERE PCPRODUT.CODAUXILIAR = REGEXP_REPLACE('${filter}', '[^0-9]', '')
|
|
||||||
ORDER BY PCPRODUT.DESCRICAO`;
|
|
||||||
products = await queryRunner.manager.query(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (products.length == 0) {
|
|
||||||
sql = `SELECT PCPRODUT.CODPROD as "id"
|
|
||||||
,PCPRODUT.CODPROD || ' - '|| PCPRODUT.DESCRICAO||
|
|
||||||
' ( '||REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '')||' )' as "description"
|
|
||||||
FROM PCPRODUT
|
|
||||||
WHERE PCPRODUT.DESCRICAO LIKE '${filter}%'
|
|
||||||
ORDER BY PCPRODUT.DESCRICAO`;
|
|
||||||
products = await queryRunner.manager.query(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
return products;
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release();
|
|
||||||
await dataSource.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter produtos filtrados por termo de pesquisa com cache
|
||||||
|
* @param filter - Termo de pesquisa para filtrar produtos
|
||||||
|
* @returns Array de ProductDto
|
||||||
|
*/
|
||||||
|
async products(filter: string): Promise<ProductDto[]> {
|
||||||
|
this.logger.log(`Buscando produtos com filtro: ${filter}`);
|
||||||
|
return this.getCachedData<ProductDto[]>(
|
||||||
|
`data-consult:products:${filter}`,
|
||||||
|
() => this.repository.findProducts(filter)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
90
src/data-consult/data-consult.spec.ts
Normal file
90
src/data-consult/data-consult.spec.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { DataConsultService } from './data-consult.service';
|
||||||
|
import { DataConsultRepository } from './data-consult.repository';
|
||||||
|
|
||||||
|
describe('DataConsultService', () => {
|
||||||
|
let service: DataConsultService;
|
||||||
|
let repository: DataConsultRepository;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
DataConsultService,
|
||||||
|
{
|
||||||
|
provide: DataConsultRepository,
|
||||||
|
useValue: {
|
||||||
|
findStores: jest.fn(),
|
||||||
|
findSellers: jest.fn(),
|
||||||
|
findBillings: jest.fn(),
|
||||||
|
findCustomers: jest.fn(),
|
||||||
|
findProducts: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<DataConsultService>(DataConsultService);
|
||||||
|
repository = module.get<DataConsultRepository>(DataConsultRepository);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('deve estar definido', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('stores', () => {
|
||||||
|
it('deve retornar uma lista de lojas', async () => {
|
||||||
|
const mockStores = [{ id: '1', name: 'Loja 1', store: '1 - Loja 1' }];
|
||||||
|
jest.spyOn(repository, 'findStores').mockResolvedValue(mockStores);
|
||||||
|
|
||||||
|
const result = await service.stores();
|
||||||
|
expect(result).toEqual(mockStores);
|
||||||
|
expect(repository.findStores).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sellers', () => {
|
||||||
|
it('deve retornar uma lista de vendedores', async () => {
|
||||||
|
const mockSellers = [{ id: '1', name: 'Vendedor 1' }];
|
||||||
|
jest.spyOn(repository, 'findSellers').mockResolvedValue(mockSellers);
|
||||||
|
|
||||||
|
const result = await service.sellers();
|
||||||
|
expect(result).toEqual(mockSellers);
|
||||||
|
expect(repository.findSellers).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('billings', () => {
|
||||||
|
it('deve retornar informações de faturamento', async () => {
|
||||||
|
const mockBillings = [{ id: '1', description: 'Faturamento 1' }];
|
||||||
|
jest.spyOn(repository, 'findBillings').mockResolvedValue(mockBillings);
|
||||||
|
|
||||||
|
const result = await service.billings();
|
||||||
|
expect(result).toEqual(mockBillings);
|
||||||
|
expect(repository.findBillings).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('customers', () => {
|
||||||
|
it('deve retornar clientes de acordo com o filtro fornecido', async () => {
|
||||||
|
const filter = '123';
|
||||||
|
const mockCustomers = [{ id: '123', name: 'Cliente 123' }];
|
||||||
|
jest.spyOn(repository, 'findCustomers').mockResolvedValue(mockCustomers);
|
||||||
|
|
||||||
|
const result = await service.customers(filter);
|
||||||
|
expect(result).toEqual(mockCustomers);
|
||||||
|
expect(repository.findCustomers).toHaveBeenCalledWith(filter);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('products', () => {
|
||||||
|
it('deve retornar produtos de acordo com o filtro fornecido', async () => {
|
||||||
|
const filter = '456';
|
||||||
|
const mockProducts = [{ id: '456', description: 'Produto 456' }];
|
||||||
|
jest.spyOn(repository, 'findProducts').mockResolvedValue(mockProducts);
|
||||||
|
|
||||||
|
const result = await service.products(filter);
|
||||||
|
expect(result).toEqual(mockProducts);
|
||||||
|
expect(repository.findProducts).toHaveBeenCalledWith(filter);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
9
src/data-consult/dto/billing.dto.ts
Normal file
9
src/data-consult/dto/billing.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class BillingDto {
|
||||||
|
@ApiProperty({ description: 'Identificador do faturamento' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Descrição do faturamento' })
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
9
src/data-consult/dto/customer.dto.ts
Normal file
9
src/data-consult/dto/customer.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class CustomerDto {
|
||||||
|
@ApiProperty({ description: 'Identificador do cliente' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Nome e identificação do cliente' })
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
9
src/data-consult/dto/product.dto.ts
Normal file
9
src/data-consult/dto/product.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class ProductDto {
|
||||||
|
@ApiProperty({ description: 'Identificador do produto' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Descrição do produto' })
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
9
src/data-consult/dto/seller.dto.ts
Normal file
9
src/data-consult/dto/seller.dto.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class SellerDto {
|
||||||
|
@ApiProperty({ description: 'Identificador do vendedor' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Nome do vendedor' })
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
12
src/data-consult/dto/store.dto.ts
Normal file
12
src/data-consult/dto/store.dto.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class StoreDto {
|
||||||
|
@ApiProperty({ description: 'Identificador da loja' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Nome da loja' })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Representação da loja (código e fantasia)' })
|
||||||
|
store: string;
|
||||||
|
}
|
||||||
@@ -23,6 +23,6 @@ async function bootstrap() {
|
|||||||
const document = SwaggerModule.createDocument(app, config);
|
const document = SwaggerModule.createDocument(app, config);
|
||||||
SwaggerModule.setup('docs', app, document);
|
SwaggerModule.setup('docs', app, document);
|
||||||
|
|
||||||
await app.listen(9000);
|
await app.listen(9002);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user