chore: organize project and update service
This commit is contained in:
parent
66adb39b9b
commit
fc2045da89
|
|
@ -2,13 +2,15 @@ import { Module } from '@nestjs/common';
|
|||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { PrinterController } from './controller/printer.controller';
|
||||
import { PedidoSevenController } from './controller/pedido-seven.controller';
|
||||
import { PrinterService } from './services/printer.service';
|
||||
import { PrinterProcessor } from './services/printer.processor';
|
||||
import { InfrastructureModule } from './infrastructure/infrastructure.module';
|
||||
import { PedidoSevenService } from './services/pedido-seven.service';
|
||||
|
||||
@Module({
|
||||
imports: [InfrastructureModule],
|
||||
controllers: [AppController, PrinterController],
|
||||
providers: [AppService, PrinterService, PrinterProcessor],
|
||||
controllers: [AppController, PrinterController, PedidoSevenController],
|
||||
providers: [AppService, PrinterService, PrinterProcessor, PedidoSevenService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ export function createTypeOrmOptions(
|
|||
): TypeOrmModuleOptions {
|
||||
const baseOptions: DataSourceOptions = {
|
||||
type: 'oracle',
|
||||
username: configService.get<string>('DB_USERNAME') || 'teste',
|
||||
password: configService.get<string>('DB_PASSWORD') || 'teste',
|
||||
username: configService.get<string>('DB_USERNAME') || 'SEVEN',
|
||||
password: configService.get<string>('DB_PASSWORD') || 'USR54SEV',
|
||||
connectString:
|
||||
configService.get<string>('DB_CONNECT_STRING') ||
|
||||
'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.241)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=BDTESTE)))',
|
||||
'(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=10.1.1.241)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=WINT)))',
|
||||
synchronize: false,
|
||||
logging: true,
|
||||
entities: [__dirname + '/../**/*.{entity,view}.{js,ts}'],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
|
||||
import {
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
ApiServiceUnavailableResponse,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { PedidoSevenService } from '../services/pedido-seven.service';
|
||||
import { PedidoCondVenda7RowDto } from '../dto/pedido-condvenda7-row.dto';
|
||||
|
||||
@ApiTags('Pedidos')
|
||||
@Controller('pedidos')
|
||||
export class PedidoSevenController {
|
||||
constructor(private readonly pedidoSevenService: PedidoSevenService) {}
|
||||
|
||||
@Get('condvenda-7/:numped7')
|
||||
@ApiOperation({
|
||||
summary: 'Consulta pedido (CONDVENDA=7) por NUMPEDENTFUT',
|
||||
})
|
||||
@ApiParam({
|
||||
name: 'numped7',
|
||||
example: 123456,
|
||||
description: 'Valor para PCPEDC.NUMPEDENTFUT',
|
||||
})
|
||||
@ApiOkResponse({
|
||||
description: 'Linhas retornadas pela consulta (pedido x itens)',
|
||||
type: [PedidoCondVenda7RowDto],
|
||||
})
|
||||
@ApiNotFoundResponse({
|
||||
description: 'Pedido nao encontrado para o NUMPEDENTFUT informado',
|
||||
})
|
||||
@ApiServiceUnavailableResponse({
|
||||
description: 'Banco de dados indisponivel (DataSource nao inicializado)',
|
||||
})
|
||||
async consultar(@Param('numped7', ParseIntPipe) numped7: number) {
|
||||
return this.pedidoSevenService.consultarPorNumped7(numped7);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class PedidoCondVenda7RowDto {
|
||||
@ApiProperty({ example: 123456 })
|
||||
numped!: number;
|
||||
|
||||
@ApiProperty({ example: '12345678000199' })
|
||||
cgc!: string;
|
||||
|
||||
@ApiProperty({ example: 'MINHA EMPRESA LTDA' })
|
||||
razaosocial!: string;
|
||||
|
||||
@ApiProperty({ description: 'SYSDATE', type: String, format: 'date-time' })
|
||||
dtemissao!: Date;
|
||||
|
||||
@ApiProperty({ example: 1 })
|
||||
codfilial!: number;
|
||||
|
||||
@ApiProperty({ example: 'FILIAL CENTRO' })
|
||||
filialvenda!: string;
|
||||
|
||||
@ApiProperty({ example: 2 })
|
||||
codfilialretira!: number;
|
||||
|
||||
@ApiProperty({ example: 'FILIAL RETIRA' })
|
||||
filialretira!: string;
|
||||
|
||||
@ApiProperty({ type: String, format: 'date-time' })
|
||||
data!: Date;
|
||||
|
||||
@ApiProperty({ example: 999 })
|
||||
numcar!: number;
|
||||
|
||||
@ApiProperty({ example: 123 })
|
||||
codcli!: number;
|
||||
|
||||
@ApiProperty({ example: 'CLIENTE TESTE' })
|
||||
cliente!: string;
|
||||
|
||||
@ApiProperty({ example: 10 })
|
||||
codusur!: number;
|
||||
|
||||
@ApiProperty({ example: 'VENDEDOR' })
|
||||
vendedor!: string;
|
||||
|
||||
@ApiProperty({ example: 25.5 })
|
||||
vlfrete!: number;
|
||||
|
||||
@ApiProperty({ example: 199.9 })
|
||||
valor!: number;
|
||||
|
||||
@ApiProperty({ example: 'ENTREGA' })
|
||||
tipoentrega!: string;
|
||||
|
||||
@ApiProperty({
|
||||
type: String,
|
||||
format: 'date-time',
|
||||
required: false,
|
||||
nullable: true,
|
||||
})
|
||||
dtentrega!: Date | null;
|
||||
|
||||
@ApiProperty({ example: 98765 })
|
||||
codprod!: number;
|
||||
|
||||
@ApiProperty({ example: 'PRODUTO X' })
|
||||
descricao!: string;
|
||||
|
||||
@ApiProperty({ example: 2 })
|
||||
qt!: number;
|
||||
|
||||
@ApiProperty({ example: 'e10adc3949ba59abbe56e057f20f883e' })
|
||||
hash!: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
import {
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
NotFoundException,
|
||||
Optional,
|
||||
ServiceUnavailableException,
|
||||
} from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { PedidoCondVenda7RowDto } from '../dto/pedido-condvenda7-row.dto';
|
||||
|
||||
@Injectable()
|
||||
export class PedidoSevenService {
|
||||
constructor(@Optional() private readonly dataSource?: DataSource) {}
|
||||
|
||||
private static toNumber(value: unknown, field: string): number {
|
||||
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
const n = Number(value);
|
||||
if (Number.isFinite(n)) return n;
|
||||
}
|
||||
throw new InternalServerErrorException(`Campo ${field} invalido`);
|
||||
}
|
||||
|
||||
private static asString(value: unknown, field: string): string {
|
||||
if (typeof value === 'string') return value;
|
||||
if (value == null) return '';
|
||||
if (typeof value === 'number' || typeof value === 'boolean') {
|
||||
return String(value);
|
||||
}
|
||||
throw new InternalServerErrorException(`Campo ${field} invalido`);
|
||||
}
|
||||
|
||||
private static toDate(value: unknown, field: string): Date {
|
||||
if (value instanceof Date && !Number.isNaN(value.getTime())) return value;
|
||||
if (typeof value === 'string' || typeof value === 'number') {
|
||||
const d = new Date(value);
|
||||
if (!Number.isNaN(d.getTime())) return d;
|
||||
}
|
||||
throw new InternalServerErrorException(`Campo ${field} invalido`);
|
||||
}
|
||||
|
||||
private static toNullableDate(value: unknown): Date | null {
|
||||
if (value == null) return null;
|
||||
if (value instanceof Date && !Number.isNaN(value.getTime())) return value;
|
||||
if (typeof value === 'string' || typeof value === 'number') {
|
||||
const d = new Date(value);
|
||||
if (!Number.isNaN(d.getTime())) return d;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static pick(row: Record<string, unknown>, key: string): unknown {
|
||||
return (
|
||||
row[key] ??
|
||||
row[key.toUpperCase()] ??
|
||||
row[key.toLowerCase()] ??
|
||||
row[key.replace(/_/g, '')] ??
|
||||
row[key.toUpperCase().replace(/_/g, '')]
|
||||
);
|
||||
}
|
||||
|
||||
private static mapRow(row: Record<string, unknown>): PedidoCondVenda7RowDto {
|
||||
const dto = new PedidoCondVenda7RowDto();
|
||||
|
||||
dto.numped = this.toNumber(this.pick(row, 'NUMPED'), 'NUMPED');
|
||||
dto.cgc = this.asString(this.pick(row, 'CGC'), 'CGC');
|
||||
dto.razaosocial = this.asString(
|
||||
this.pick(row, 'RAZAOSOCIAL'),
|
||||
'RAZAOSOCIAL',
|
||||
);
|
||||
dto.dtemissao = this.toDate(this.pick(row, 'DTEMISSAO'), 'DTEMISSAO');
|
||||
|
||||
dto.codfilial = this.toNumber(this.pick(row, 'CODFILIAL'), 'CODFILIAL');
|
||||
dto.filialvenda = this.asString(
|
||||
this.pick(row, 'FILIALVENDA'),
|
||||
'FILIALVENDA',
|
||||
);
|
||||
|
||||
dto.codfilialretira = this.toNumber(
|
||||
this.pick(row, 'CODFILIALRETIRA'),
|
||||
'CODFILIALRETIRA',
|
||||
);
|
||||
dto.filialretira = this.asString(
|
||||
this.pick(row, 'FILIALRETIRA'),
|
||||
'FILIALRETIRA',
|
||||
);
|
||||
|
||||
dto.data = this.toDate(this.pick(row, 'DATA'), 'DATA');
|
||||
dto.numcar = this.toNumber(this.pick(row, 'NUMCAR'), 'NUMCAR');
|
||||
dto.codcli = this.toNumber(this.pick(row, 'CODCLI'), 'CODCLI');
|
||||
dto.cliente = this.asString(this.pick(row, 'CLIENTE'), 'CLIENTE');
|
||||
dto.codusur = this.toNumber(this.pick(row, 'CODUSUR'), 'CODUSUR');
|
||||
dto.vendedor = this.asString(this.pick(row, 'VENDEDOR'), 'VENDEDOR');
|
||||
dto.vlfrete = this.toNumber(this.pick(row, 'VLFRETE'), 'VLFRETE');
|
||||
dto.valor = this.toNumber(this.pick(row, 'VALOR'), 'VALOR');
|
||||
dto.tipoentrega = this.asString(
|
||||
this.pick(row, 'TIPOENTREGA'),
|
||||
'TIPOENTREGA',
|
||||
);
|
||||
dto.dtentrega = this.toNullableDate(this.pick(row, 'DTENTREGA'));
|
||||
dto.codprod = this.toNumber(this.pick(row, 'CODPROD'), 'CODPROD');
|
||||
dto.descricao = this.asString(this.pick(row, 'DESCRICAO'), 'DESCRICAO');
|
||||
dto.qt = this.toNumber(this.pick(row, 'QT'), 'QT');
|
||||
dto.hash = this.asString(this.pick(row, 'HASH'), 'HASH');
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
async consultarPorNumped7(
|
||||
numped7: number,
|
||||
): Promise<PedidoCondVenda7RowDto[]> {
|
||||
if (!this.dataSource) {
|
||||
throw new ServiceUnavailableException('DataSource nao disponivel');
|
||||
}
|
||||
|
||||
if (!this.dataSource.isInitialized) {
|
||||
throw new ServiceUnavailableException(
|
||||
'Banco de dados indisponivel (DataSource nao inicializado)',
|
||||
);
|
||||
}
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
PCPEDC.NUMPED,
|
||||
PCFILIAL.CGC,
|
||||
PCFILIAL.RAZAOSOCIAL,
|
||||
SYSDATE DTEMISSAO,
|
||||
PCPEDC.CODFILIAL,
|
||||
PCFILIAL.FANTASIA FILIALVENDA,
|
||||
PCPEDI.CODFILIALRETIRA,
|
||||
RETIRA.FANTASIA FILIALRETIRA,
|
||||
PCPEDC.DATA,
|
||||
PCPEDC.NUMCAR,
|
||||
PCPEDC.CODCLI,
|
||||
PCCLIENT.CLIENTE CLIENTE,
|
||||
PCNFSAID.CODUSUR,
|
||||
PCUSUARI.NOME VENDEDOR,
|
||||
PCPEDC.VLFRETE,
|
||||
DECODE(PCNFSAID.VLTOTGER, 0, PCNFSAID.VLTOTAL, PCNFSAID.VLTOTAL) VALOR,
|
||||
DECODE(
|
||||
PCPEDI.TIPOENTREGA,
|
||||
'EN', 'ENTREGA',
|
||||
'EF', 'ENCOMENDA',
|
||||
'RP', 'RETIRA POSTERIOR',
|
||||
'RI', 'RETIRA IMEDIATA',
|
||||
'RETIRA IMEDIATA'
|
||||
) TIPOENTREGA,
|
||||
PCPEDC.DTENTREGA,
|
||||
PCPEDI.CODPROD,
|
||||
PCPRODUT.DESCRICAO,
|
||||
PCPEDI.QT,
|
||||
MD5(PCNFSAID.NUMPED || '@Juru2025$') HASH
|
||||
FROM
|
||||
PCPEDC,
|
||||
PCPEDI,
|
||||
PCNFSAID,
|
||||
PCCLIENT,
|
||||
PCUSUARI,
|
||||
PCPRODUT,
|
||||
PCFILIAL,
|
||||
PCFILIAL RETIRA
|
||||
WHERE
|
||||
PCNFSAID.NUMPED = PCPEDC.NUMPEDENTFUT
|
||||
AND PCPEDC.CODFILIAL = PCFILIAL.CODIGO
|
||||
AND PCPEDI.CODFILIALRETIRA = RETIRA.CODIGO
|
||||
AND PCPEDI.CODPROD = PCPRODUT.CODPROD
|
||||
AND PCPEDC.CODCLI = PCCLIENT.CODCLI
|
||||
AND PCNFSAID.CODUSUR = PCUSUARI.CODUSUR
|
||||
AND PCPEDC.NUMPED = PCPEDI.NUMPED
|
||||
AND PCNFSAID.DTCANCEL IS NULL
|
||||
AND PCNFSAID.CONDVENDA = 7
|
||||
AND PCPEDC.NUMPEDENTFUT = :1
|
||||
`;
|
||||
|
||||
try {
|
||||
const rows = (await this.dataSource.query(sql, [numped7])) as unknown;
|
||||
if (!Array.isArray(rows)) {
|
||||
throw new InternalServerErrorException('Resposta invalida do banco');
|
||||
}
|
||||
|
||||
if (rows.length === 0) {
|
||||
throw new NotFoundException(
|
||||
`Pedido nao encontrado para NUMPEDENTFUT=${numped7}`,
|
||||
);
|
||||
}
|
||||
|
||||
return rows.map((r) => {
|
||||
if (r && typeof r === 'object' && !Array.isArray(r)) {
|
||||
return PedidoSevenService.mapRow(r as Record<string, unknown>);
|
||||
}
|
||||
throw new InternalServerErrorException(
|
||||
'Linha invalida retornada pelo banco',
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
throw new InternalServerErrorException(
|
||||
`Erro ao executar a consulta: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue