impl redis cloud

This commit is contained in:
JurTI-BR
2025-04-01 16:42:05 -03:00
parent f8bea4114f
commit 28a1cee876
14 changed files with 819 additions and 6 deletions

View File

@@ -6,9 +6,10 @@
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', ''),
host: configService.get<string>('REDIS_HOST', 'redis-17317.crce181.sa-east-1-2.ec2.redns.redis-cloud.com'),
port: configService.get<number>('REDIS_PORT', 17317),
username: configService.get<string>('REDIS_USERNAME', 'default' ),
password: configService.get<string>('REDIS_PASSWORD', 'd8sVttpJdNxrWjYRK43QGAKzEt3I8HVc'),
});
redis.on('error', (err) => {

View File

@@ -2,6 +2,7 @@ import { Controller, Get, Param,UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiParam, ApiBearerAuth } from '@nestjs/swagger';
import { DataConsultService } from './data-consult.service';
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'
import { ProductDto } from './dto/product.dto';
@ApiTags('DataConsult')
@Controller('api/v1/data-consult')
@@ -48,4 +49,11 @@ export class DataConsultController {
async products(@Param('filter') filter: string) {
return this.dataConsultService.products(filter);
}
@Get('Buscar 500 produtos')
@ApiOperation({ summary: 'VIEW DE 500 PRODUTOS' })
async getAllProducts(): Promise<ProductDto[]> {
return this.dataConsultService.getAllProducts();
}
}

View File

@@ -129,7 +129,7 @@ export class DataConsultRepository {
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
FROM PCPRODUT
WHERE PCPRODUT.CODPROD = ?
WHERE PCPRODUT.CODPROD = :1
ORDER BY PCPRODUT.DESCRICAO
`,
params: [cleanedFilter],
@@ -140,7 +140,7 @@ export class DataConsultRepository {
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
FROM PCPRODUT
WHERE PCPRODUT.CODAUXILIAR = ?
WHERE PCPRODUT.CODAUXILIAR = :1
ORDER BY PCPRODUT.DESCRICAO
`,
params: [cleanedFilter],
@@ -151,7 +151,7 @@ export class DataConsultRepository {
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
FROM PCPRODUT
WHERE PCPRODUT.DESCRICAO LIKE ?
WHERE PCPRODUT.DESCRICAO LIKE :1
ORDER BY PCPRODUT.DESCRICAO
`,
params: [likeFilter],
@@ -167,4 +167,16 @@ export class DataConsultRepository {
return [];
}
async findAllProducts(): Promise<ProductDto[]> {
const sql = `
SELECT PCPRODUT.CODPROD as "id",
PCPRODUT.CODPROD || ' - ' || PCPRODUT.DESCRICAO ||
' ( ' || REGEXP_REPLACE(PCPRODUT.CODAUXILIAR, '[^0-9]', '') || ' )' as "description"
FROM PCPRODUT
WHERE ROWNUM <= 1000
ORDER BY PCPRODUT.DESCRICAO
`;
return this.executeQuery<ProductDto[]>(sql);
}
}

View File

@@ -17,6 +17,10 @@ export class DataConsultService {
private readonly SELLERS_CACHE_KEY = 'data-consult:sellers';
private readonly SELLERS_TTL = 3600; // 1 hora
private readonly STORES_TTL = 3600;
private readonly BILLINGS_TTL = 3600;
private readonly ALL_PRODUCTS_CACHE_KEY = 'data-consult:products:all';
private readonly ALL_PRODUCTS_TTL = 600; // 10 minutos (ajustável)
constructor(
@@ -59,8 +63,11 @@ export class DataConsultService {
async billings(): Promise<BillingDto[]> {
this.logger.log('Buscando todos os faturamentos');
return this.repository.findBillings();
}
/**
* Obter clientes filtrados por termo de pesquisa
* @param filter - Termo de pesquisa para filtrar clientes
@@ -95,4 +102,17 @@ export class DataConsultService {
);
}
}
async getAllProducts(): Promise<ProductDto[]> {
this.logger.log('Buscando produtos com cache Redis...');
return getOrSetCache<ProductDto[]>(
this.redisClient,
this.ALL_PRODUCTS_CACHE_KEY,
this.ALL_PRODUCTS_TTL,
async () => {
this.logger.log('Cache de produtos vazio. Buscando no banco...');
return this.repository.findAllProducts();
}
);
}
}

View File

@@ -0,0 +1,140 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.DataConsultController = void 0;
var common_1 = require("@nestjs/common");
var swagger_1 = require("@nestjs/swagger");
var jwt_auth_guard_1 = require("src/auth/guards/jwt-auth.guard");
var DataConsultController = /** @class */ (function () {
function DataConsultController(dataConsultService) {
this.dataConsultService = dataConsultService;
}
DataConsultController.prototype.stores = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.dataConsultService.stores()];
});
});
};
DataConsultController.prototype.sellers = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.dataConsultService.sellers()];
});
});
};
DataConsultController.prototype.billings = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.dataConsultService.billings()];
});
});
};
DataConsultController.prototype.customer = function (filter) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.dataConsultService.customers(filter)];
});
});
};
DataConsultController.prototype.products = function (filter) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.dataConsultService.products(filter)];
});
});
};
DataConsultController.prototype.getAllProducts = function () {
return __awaiter(this, void 0, Promise, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.dataConsultService.getAllProducts()];
});
});
};
__decorate([
common_1.UseGuards(jwt_auth_guard_1.JwtAuthGuard),
swagger_1.ApiBearerAuth(),
common_1.Get('stores'),
swagger_1.ApiOperation({ summary: 'Lista todas as lojas' })
], DataConsultController.prototype, "stores");
__decorate([
common_1.UseGuards(jwt_auth_guard_1.JwtAuthGuard),
swagger_1.ApiBearerAuth(),
common_1.Get('sellers'),
swagger_1.ApiOperation({ summary: 'Lista todos os vendedores' })
], DataConsultController.prototype, "sellers");
__decorate([
common_1.UseGuards(jwt_auth_guard_1.JwtAuthGuard),
swagger_1.ApiBearerAuth(),
common_1.Get('billings'),
swagger_1.ApiOperation({ summary: 'Retorna informações de faturamento' })
], DataConsultController.prototype, "billings");
__decorate([
common_1.UseGuards(jwt_auth_guard_1.JwtAuthGuard),
swagger_1.ApiBearerAuth(),
common_1.Get('customers/:filter'),
swagger_1.ApiOperation({ summary: 'Filtra clientes pelo parâmetro fornecido' }),
swagger_1.ApiParam({ name: 'filter', description: 'Filtro de busca para clientes' }),
__param(0, common_1.Param('filter'))
], DataConsultController.prototype, "customer");
__decorate([
common_1.Get('products/:filter'),
swagger_1.ApiOperation({ summary: 'Busca produtos filtrados' }),
swagger_1.ApiParam({ name: 'filter', description: 'Filtro de busca' }),
__param(0, common_1.Param('filter'))
], DataConsultController.prototype, "products");
__decorate([
common_1.Get('Buscar 500 produtos'),
swagger_1.ApiOperation({ summary: 'VIEW DE 500 PRODUTOS' })
], DataConsultController.prototype, "getAllProducts");
DataConsultController = __decorate([
swagger_1.ApiTags('DataConsult'),
common_1.Controller('api/v1/data-consult')
], DataConsultController);
return DataConsultController;
}());
exports.DataConsultController = DataConsultController;

View File

@@ -0,0 +1,208 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
exports.OrdersService = void 0;
var common_1 = require("@nestjs/common");
var redis_client_adapter_provider_1 = require("src/core/configs/cache/redis-client.adapter.provider");
var cache_util_1 = require("src/shared/cache.util");
var crypto_1 = require("crypto");
var OrdersService = /** @class */ (function () {
function OrdersService(ordersRepository, redisClient) {
this.ordersRepository = ordersRepository;
this.redisClient = redisClient;
this.TTL_ORDERS = 60 * 10; // 10 minutos
this.TTL_INVOICE = 60 * 60; // 1 hora
this.TTL_ITENS = 60 * 10; // 10 minutos
}
/**
* Buscar pedidos com cache baseado nos filtros
*/
OrdersService.prototype.findOrders = function (query) {
return __awaiter(this, void 0, void 0, function () {
var key;
var _this = this;
return __generator(this, function (_a) {
key = "orders:query:" + this.hashObject(query);
return [2 /*return*/, cache_util_1.getOrSetCache(this.redisClient, key, this.TTL_ORDERS, function () { return _this.ordersRepository.findOrders(query); })];
});
});
};
/**
* Buscar nota fiscal por chave NFe com cache
*/
OrdersService.prototype.findInvoice = function (chavenfe) {
return __awaiter(this, void 0, Promise, function () {
var key;
var _this = this;
return __generator(this, function (_a) {
key = "orders:invoice:" + chavenfe;
return [2 /*return*/, cache_util_1.getOrSetCache(this.redisClient, key, this.TTL_INVOICE, function () { return __awaiter(_this, void 0, void 0, function () {
var invoiceData, invoice;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ordersRepository.findInvoice(chavenfe)];
case 1:
invoiceData = _a.sent();
invoice = {
storeId: invoiceData.storeId,
invoiceDate: new Date(invoiceData.invoiceDate),
orderId: invoiceData.orderId,
invoiceId: invoiceData.invoiceId,
transactionId: invoiceData.transactionId,
customerId: invoiceData.customerId,
customer: invoiceData.customer,
sellerId: invoiceData.sellerId,
sellerName: invoiceData.sellerName,
itensQt: invoiceData.itensQt,
itens: invoiceData.itens
};
return [2 /*return*/, invoice];
}
});
}); })];
});
});
};
/**
* Buscar itens de pedido com cache
*/
OrdersService.prototype.getItens = function (orderId) {
return __awaiter(this, void 0, Promise, function () {
var key;
var _this = this;
return __generator(this, function (_a) {
key = "orders:itens:" + orderId;
return [2 /*return*/, cache_util_1.getOrSetCache(this.redisClient, key, this.TTL_ITENS, function () { return __awaiter(_this, void 0, void 0, function () {
var itens;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ordersRepository.getItens(orderId)];
case 1:
itens = _a.sent();
return [2 /*return*/, itens.map(function (item) { return ({
productId: Number(item.productId),
description: item.description,
pacth: item.pacth,
color: item.color,
stockId: Number(item.stockId),
quantity: Number(item.quantity),
salePrice: Number(item.salePrice),
deliveryType: item.deliveryType,
total: Number(item.total),
weight: Number(item.weight),
department: item.department,
brand: item.brand
}); })];
}
});
}); })];
});
});
};
OrdersService.prototype.getCutItens = function (orderId) {
return __awaiter(this, void 0, Promise, function () {
var itens;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.ordersRepository.getCutItens(orderId)];
case 1:
itens = _a.sent();
return [2 /*return*/, itens.map(function (item) { return ({
productId: Number(item.productId),
description: item.description,
pacth: item.pacth,
stockId: Number(item.stockId),
saleQuantity: Number(item.saleQuantity),
cutQuantity: Number(item.cutQuantity),
separedQuantity: Number(item.separedQuantity)
}); })];
}
});
});
};
OrdersService.prototype.getOrderDelivery = function (orderId) {
return __awaiter(this, void 0, Promise, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.ordersRepository.getOrderDelivery(orderId)];
});
});
};
OrdersService.prototype.getTransfer = function (orderId) {
return __awaiter(this, void 0, Promise, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.ordersRepository.getTransfer(orderId)];
});
});
};
OrdersService.prototype.getStatusOrder = function (orderId) {
return __awaiter(this, void 0, Promise, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.ordersRepository.getStatusOrder(orderId)];
});
});
};
/**
* Utilitário para gerar hash MD5 de objetos
*/
OrdersService.prototype.hashObject = function (obj) {
var str = JSON.stringify(obj, Object.keys(obj).sort());
return crypto_1.createHash('md5').update(str).digest('hex');
};
OrdersService.prototype.createInvoiceCheck = function (invoice) {
return __awaiter(this, void 0, Promise, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.ordersRepository.createInvoiceCheck(invoice)];
});
});
};
OrdersService = __decorate([
common_1.Injectable(),
__param(1, common_1.Inject(redis_client_adapter_provider_1.RedisClientToken))
], OrdersService);
return OrdersService;
}());
exports.OrdersService = OrdersService;

View File

@@ -8,6 +8,12 @@ import { IRedisClient } from 'src/core/configs/cache/IRedisClient';
import { RedisClientToken } from 'src/core/configs/cache/redis-client.adapter.provider';
import { getOrSetCache } from 'src/shared/cache.util';
import { createHash } from 'crypto';
import { OrderDeliveryDto } from '../dto/OrderDeliveryDto';
import { OrderTransferDto } from '../dto/OrderTransferDto';
import { OrderStatusDto } from '../dto/OrderStatusDto';
import { InvoiceCheckDto } from '../dto/invoice-check.dto';
@Injectable()
export class OrdersService {
@@ -101,7 +107,17 @@ export class OrdersService {
}));
}
async getOrderDelivery(orderId: string): Promise<OrderDeliveryDto> {
return this.ordersRepository.getOrderDelivery(orderId);
}
async getTransfer(orderId: number): Promise<OrderTransferDto[] | null> {
return this.ordersRepository.getTransfer(orderId);
}
async getStatusOrder(orderId: number): Promise<OrderStatusDto[] | null> {
return this.ordersRepository.getStatusOrder(orderId);
}
/**
* Utilitário para gerar hash MD5 de objetos
*/
@@ -110,4 +126,9 @@ export class OrdersService {
return createHash('md5').update(str).digest('hex');
}
async createInvoiceCheck(invoice: InvoiceCheckDto): Promise<{ message: string }> {
return this.ordersRepository.createInvoiceCheck(invoice);
}
}

View File

@@ -1,6 +1,8 @@
import {
Controller,
Get,
Post,
Body,
Param,
Query,
UsePipes,
@@ -18,6 +20,13 @@ import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { InvoiceDto } from '../dto/find-invoice.dto';
import { OrderItemDto } from "../dto/OrderItemDto";
import { CutItemDto } from '../dto/CutItemDto';
import { OrderDeliveryDto } from '../dto/OrderDeliveryDto';
import { OrderTransferDto } from '../dto/OrderTransferDto';
import { OrderStatusDto } from '../dto/OrderStatusDto';
import { InvoiceCheckDto } from '../dto/invoice-check.dto';
@ApiTags('Orders')
@@ -73,4 +82,60 @@ export class OrdersController {
);
}
}
@Get('delivery/:orderId')
@ApiOperation({ summary: 'Busca dados de entrega do pedido' })
@UsePipes(new ValidationPipe({ transform: true }))
async getOrderDelivery(@Param('orderId') orderId: string): Promise<OrderDeliveryDto | null> {
try {
return await this.ordersService.getOrderDelivery(orderId);
} catch (error) {
throw new HttpException(
error.message || 'Erro ao buscar dados de entrega',
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
@Get('transfer/:orderId')
@ApiOperation({ summary: 'Consulta pedidos de transferência' })
@UsePipes(new ValidationPipe({ transform: true }))
async getTransfer(@Param('orderId') orderId: number): Promise<OrderTransferDto[] | null> {
try {
return await this.ordersService.getTransfer(orderId);
} catch (error) {
throw new HttpException(
error.message || 'Erro ao buscar transferências do pedido',
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
@Get('status/:orderId')
@ApiOperation({ summary: 'Consulta status do pedido' })
@UsePipes(new ValidationPipe({ transform: true }))
async getStatusOrder(@Param('orderId') orderId: number): Promise<OrderStatusDto[] | null> {
try {
return await this.ordersService.getStatusOrder(orderId);
} catch (error) {
throw new HttpException(
error.message || 'Erro ao buscar status do pedido',
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
@Post('invoice/check')
@ApiOperation({ summary: 'Cria conferência de nota fiscal' })
@UsePipes(new ValidationPipe({ transform: true }))
async createInvoiceCheck(@Body() invoice: InvoiceCheckDto): Promise<{ message: string }> {
try {
return await this.ordersService.createInvoiceCheck(invoice);
} catch (error) {
throw new HttpException(
error.message || 'Erro ao salvar conferência',
error.status || HttpStatus.INTERNAL_SERVER_ERROR
);
}
}
}

View File

@@ -0,0 +1,28 @@
export class OrderDeliveryDto {
placeId: number;
placeName: string;
street: string;
addressNumber: string;
bairro: string;
city: string;
state: string;
addressComplement: string;
cep: string;
commentOrder1: string;
commentOrder2: string;
commentDelivery1: string;
commentDelivery2: string;
commentDelivery3: string;
commentDelivery4: string;
shippimentId: number;
shippimentDate: Date;
shippimentComment: string;
place: string;
driver: string;
car: string;
closeDate: Date;
separatorName: string;
confName: string;
releaseDate: Date;
}

View File

@@ -0,0 +1,8 @@
export class OrderStatusDto {
orderId: number;
status: string;
statusDate: Date;
userName: string;
comments: string | null;
}

View File

@@ -0,0 +1,13 @@
export class OrderTransferDto {
orderId: number;
transferDate: Date;
invoiceId: number;
transactionId: number;
oldShipment: number;
newShipment: number;
transferText: string;
cause: string;
userName: string;
program: string;
}

View File

@@ -0,0 +1,7 @@
export class InvoiceCheckItemDto {
productId: number;
seq: number;
qt: number;
confDate: string;
}

View File

@@ -0,0 +1,11 @@
import { InvoiceCheckItemDto } from './invoice-check-item.dto';
export class InvoiceCheckDto {
transactionId: number;
storeId: number;
invoiceId: number;
startDate: string;
endDate: string;
userId: number;
itens: InvoiceCheckItemDto[];
}

View File

@@ -4,6 +4,11 @@ import { InjectDataSource } from "@nestjs/typeorm";
import { FindOrdersDto } from "../dto/find-orders.dto";
import { OrderItemDto } from "../dto/OrderItemDto";
import { CutItemDto } from '../dto/CutItemDto';
import { OrderDeliveryDto } from '../dto/OrderDeliveryDto';
import { OrderTransferDto } from '../dto/OrderTransferDto';
import { OrderStatusDto } from '../dto/OrderStatusDto';
import { InvoiceCheckDto } from '../dto/invoice-check.dto';
@@ -365,4 +370,270 @@ export class OrdersRepository {
await queryRunner.release();
}
}
async getOrderDelivery(orderId: string): Promise<OrderDeliveryDto | null> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
const sql = `
SELECT PCPRACA.CODPRACA as "placeId",
PCPRACA.PRACA as "placeName",
NVL(ENDENT.ENDERENT, PCCLIENT.ENDERENT) as "street",
NVL(ENDENT.NUMEROENT, PCCLIENT.NUMEROENT) as "addressNumber",
NVL(ENDENT.BAIRROENT, PCCLIENT.BAIRROENT) as "bairro",
NVL(ENDENT.MUNICENT, PCCLIENT.MUNICENT) as "city",
NVL(ENDENT.ESTENT, PCCLIENT.ESTENT) as "state",
NVL(ENDENT.COMPLEMENTOENT, PCCLIENT.COMPLEMENTOENT) as "addressComplement",
NVL(ENDENT.CEPENT, PCCLIENT.CEPENT) as "cep",
PCPEDC.OBS1 as "commentOrder1",
PCPEDC.OBS2 as "commentOrder2",
PCPEDC.OBSENTREGA1 as "commentDelivery1",
PCPEDC.OBSENTREGA2 as "commentDelivery2",
PCPEDC.OBSENTREGA3 as "commentDelivery3",
PCPEDC.OBSENTREGA4 as "commentDelivery4",
PCPEDC.NUMCAR as "shippimentId",
PCCARREG.DTSAIDA as "shippimentDate",
PCCARREG.DESTINO as "shippimentComment",
PCROTAEXP.DESCRICAO as "place",
PCEMPR.MATRICULA||'-'||PCEMPR.NOME as "driver",
PCVEICUL.PLACA||' - '||PCVEICUL.DESCRICAO as "car",
CASE WHEN PCCARREG.DTFECHA < PCCARREG.DTSAIDA THEN NULL ELSE PCCARREG.DTFECHA END as "closeDate",
SEPARADOR.NOME as "separatorName",
CONFERENTE.NOME as "confName",
PCPEDC.DTLIBERA as "releaseDate"
FROM PCPEDC, PCCLIENT, PCPRACA, PCCLIENTENDENT ENDENT, PCCARREG, PCVEICUL, PCEMPR, PCROTAEXP,
PCEMPR SEPARADOR, PCEMPR CONFERENTE
WHERE NVL(ENDENT.CODPRACAENT, PCPEDC.CODPRACA) = PCPRACA.CODPRACA
AND PCPEDC.CODCLI = PCCLIENT.CODCLI
AND PCPEDC.CODENDENTCLI = ENDENT.CODENDENTCLI (+)
AND PCPEDC.CODCLI = ENDENT.CODCLI (+)
AND PCPEDC.NUMCAR = PCCARREG.NUMCAR (+)
AND PCCARREG.CODMOTORISTA = PCEMPR.MATRICULA (+)
AND PCCARREG.CODVEICULO = PCVEICUL.CODVEICULO (+)
AND PCCARREG.CODROTAPRINC = PCROTAEXP.CODROTA (+)
AND PCPEDC.CODFUNCSEP = SEPARADOR.MATRICULA (+)
AND PCPEDC.CODFUNCCONF = CONFERENTE.MATRICULA (+)
AND PCPEDC.NUMPED = ${orderId}
`;
const result = await queryRunner.manager.query(sql);
return result.length > 0 ? result[0] : null;
} finally {
await queryRunner.release();
}
}
async getTransfer(orderId: number): Promise<OrderTransferDto[] | null> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
const sql = `
SELECT
L.NUMPED as "orderId",
L.DTTRANSF as "transferDate",
L.NUMNOTA as "invoiceId",
L.NUMTRANSVENDA as "transactionId",
L.NUMCARANTERIOR as "oldShipment",
L.NUMCARATUAL as "newShipment",
L.MOTIVOTRANSF as "transferText",
L.codmotivo || '-' || PCTABDEV.MOTIVO as "cause",
L.codfunctransf || '-' || PCEMPR.NOME as "userName",
L.rotinatransf as "program"
FROM PCLOGTRANSFNFCARREG L
LEFT JOIN PCTABDEV ON L.CODMOTIVO = PCTABDEV.coddevol
LEFT JOIN PCEMPR ON L.CODFUNCTRANSF = PCEMPR.MATRICULA
WHERE L.NUMTRANSVENDA IN (
SELECT NUMTRANSVENDA FROM PCPEDC WHERE PCPEDC.NUMPED = ${orderId}
)
`;
const result = await queryRunner.manager.query(sql);
return result.length > 0 ? result : null;
} finally {
await queryRunner.release();
}
}
async getStatusOrder(orderId: number): Promise<OrderStatusDto[] | null> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
const sql = `SELECT pcpedc.numped AS "orderId",
'Digitação pedido' AS "status",
TO_DATE (TO_CHAR(pcpedc.data, 'DD/MM/YYYY') || ' ' || pcpedc.hora || ':' || pcpedc.minuto,
'DD/MM/YYYY HH24:MI')
AS "statusDate",
pcpedc.codemitente || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr
WHERE pcpedc.numped = ${orderId} AND pcpedc.codemitente = pcempr.matricula(+)
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Montagem de carga' AS "status",
TO_DATE (
TO_CHAR(pccarreg.datamon, 'DD/MM/YYYY')
|| ' '
|| pccarreg.horamon
|| ':'
|| pccarreg.minutomon,
'DD/MM/YYYY HH24:MI')
AS "statusDate",
pccarreg.codfuncmon || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr, pccarreg
WHERE pcpedc.numped = ${orderId}
AND pccarreg.codfuncmon = pcempr.matricula(+)
AND pcpedc.numcar = pccarreg.numcar
AND pcpedc.numcar > 0
AND pccarreg.datamon is not null
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Emissão do mapa' AS "status",
CASE WHEN PCPEDC.DTEMISSAOMAPA IS NOT NULL THEN
TO_DATE (
TO_CHAR(pcpedc.dtemissaomapa, 'DD/MM/YYYY')
|| ' '
|| NVL(pcpedc.horaemissaomapa, '00')
|| ':'
|| nvl(pcpedc.minutoemissaomapa, '01'),
'DD/MM/YYYY HH24:MI') ELSE NULL END
AS "statusDate",
pcpedc.codfuncemissaomapa || '-' || pcempr.nome AS "userName"
,NULL as "comments"
FROM pcpedc, pcempr
WHERE pcpedc.numped = ${orderId}
AND pcpedc.codfuncemissaomapa = pcempr.matricula(+)
AND PCPEDC.DTEMISSAOMAPA IS NOT NULL
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Inicio de Separação' AS "status",
pcpedc.dtinicialsep as "statusDate",
pcpedc.codfuncsep || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr
WHERE pcpedc.numped = ${orderId}
AND pcpedc.codfuncsep = pcempr.matricula(+)
AND PCPEDC.dtinicialsep IS NOT NULL
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Fim de Separação' AS "status",
pcpedc.dtfinalsep as "statusDate",
pcpedc.codfuncsep || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr
WHERE pcpedc.numped = ${orderId} AND pcpedc.codfuncsep = pcempr.matricula(+)
and pcpedc.dtfinalsep is not null
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Inicio conferência' AS "status",
pcpedc.dtinicialcheckout AS "statusDate",
pcpedc.codfuncconf || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr
WHERE pcpedc.numped = ${orderId}
AND pcpedc.codfuncconf = pcempr.matricula(+)
AND pcpedc.dtinicialcheckout IS NOT NULL
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Fim conferência' AS "status",
pcpedc.dtfinalcheckout AS "statusDate",
pcpedc.codfuncconf || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr
WHERE pcpedc.numped = ${orderId}
AND pcpedc.codfuncconf = pcempr.matricula(+)
AND pcpedc.dtfinalcheckout IS NOT NULL
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Faturamento' AS "status",
TO_DATE (
TO_CHAR(pcpedc.dtfat, 'DD/MM/YYYY') || ' ' || pcpedc.horafat || ':' || pcpedc.minutofat,
'DD/MM/YYYY HH24:MI')
AS "statusDate",
pcempr.matricula || '-' || pcempr.nome "userName"
,NULL as "comments"
FROM pcpedc, pcempr, pccarreg, pcnfsaid
WHERE pcpedc.numped = ${orderId}
AND pcpedc.numcar = pccarreg.numcar
and pcpedc.numtransvenda = pcnfsaid.numtransvenda
AND nvl(pcnfsaid.codemitente, decode(pcpedc.numcar,0,-1,pccarreg.codfuncfat)) = pcempr.matricula(+)
AND pcpedc.dtfat IS NOT NULL
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Entrega' AS "status",
pcnfsaid.dtcanhoto AS "statusDate",
CASE WHEN PCNFSAID.NUMCAR > 0 THEN
pcnfsaid.codfunccanhoto || '-' || pcempr.nome
ELSE '' END "userName"
,NULL as "comments"
FROM pcpedc, pcnfsaid, pcempr, pccarreg
WHERE pcpedc.numped = ${orderId}
AND pcpedc.numtransvenda = pcnfsaid.numtransvenda
AND pcnfsaid.numcar = pccarreg.numcar (+)
AND pcnfsaid.codfunccanhoto = pcempr.matricula(+)
AND pcnfsaid.dtcanhoto IS NOT NULL
UNION ALL
SELECT pcpedc.numped AS "orderId",
'Transf entre carregamento' AS "status",
pclogtransfnfcarreg.dttransf AS "statusDate",
pclogtransfnfcarreg.codfunctransf || '-' || pcempr.nome "userName",
'ORIG: '||pclogtransfnfcarreg.numcaranterior || ' ->
DEST.: ' ||pclogtransfnfcarreg.numcaratual as "comments"
FROM pclogtransfnfcarreg, pcpedc, pcempr
WHERE pclogtransfnfcarreg.numnota = pcpedc.numnota (+)
AND pcpedc.numped = ${orderId}
AND pclogtransfnfcarreg.codfunctransf = pcempr.matricula(+)
ORDER BY 3`;
const result = await queryRunner.manager.query(sql);
return result.length > 0 ? result : null;
} finally {
await queryRunner.release();
}
}
async createInvoiceCheck(invoice: InvoiceCheckDto): Promise<{ message: string }> {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const sequenceSql = 'SELECT ESSCONFERENCIANF.NEXTVAL as "id" FROM DUAL';
const result = await queryRunner.manager.query(sequenceSql);
const checkId = result[0].id;
const sqlMain = `
INSERT INTO ESTCONFERENCIANF (
ID, NUMTRANSVENDA, CODFILIAL, NUMNOTA, DTINICIO, DTFIM, CODFUNCCONF
) VALUES (
${checkId}, ${invoice.transactionId}, ${invoice.storeId}, ${invoice.invoiceId},
TO_DATE(SUBSTR(REPLACE(REPLACE('${invoice.startDate}', 'T', ' '), 'Z', ''),1,18), 'YYYY-MM-DD HH24:MI:SS'),
TO_DATE(SUBSTR(REPLACE(REPLACE('${invoice.endDate}', 'T', ' '), 'Z', ''),1,18), 'YYYY-MM-DD HH24:MI:SS'),
${invoice.userId}
)
`;
await queryRunner.manager.query(sqlMain);
for (const item of invoice.itens) {
const sqlItem = `
INSERT INTO ESTCONFERENCIANFITENS (
IDCONF, NUMTRANSVENDA, CODPROD, NUMSEQ, QT, DTCONF
) VALUES (
${checkId}, ${invoice.transactionId}, ${item.productId}, ${item.seq}, ${item.qt},
TO_DATE(SUBSTR(REPLACE(REPLACE('${item.confDate}', 'T', ' '), 'Z', ''),1,18), 'YYYY-MM-DD HH24:MI:SS')
)
`;
await queryRunner.manager.query(sqlItem);
}
await queryRunner.commitTransaction();
return { message: 'Conferência salva com sucesso!' };
} catch (error) {
await queryRunner.rollbackTransaction();
throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
} finally {
await queryRunner.release();
}
}
}