import { Injectable, HttpException, HttpStatus, Inject, Logger, } from '@nestjs/common'; 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 { RegionDto } from './dto/region.dto'; import { CarrierDto, FindCarriersDto } from './dto/carrier.dto'; import { RedisClientToken } from '../core/configs/cache/redis-client.adapter.provider'; import { IRedisClient } from '../core/configs/cache/IRedisClient'; import { getOrSetCache } from '../shared/cache.util'; import { DataSource } from 'typeorm'; import { DATA_SOURCE } from '../core/constants'; @Injectable() export class DataConsultService { private readonly logger = new Logger(DataConsultService.name); private readonly SELLERS_CACHE_KEY = 'data-consult:sellers'; private readonly SELLERS_TTL = 3600; 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; private readonly CUSTOMERS_TTL = 3600; private readonly CARRIERS_CACHE_KEY = 'data-consult:carriers:all'; private readonly CARRIERS_TTL = 3600; private readonly REGIONS_CACHE_KEY = 'data-consult:regions'; private readonly REGIONS_TTL = 7200; constructor( private readonly repository: DataConsultRepository, @Inject(RedisClientToken) private readonly redisClient: IRedisClient, @Inject(DATA_SOURCE) private readonly dataSource: DataSource, ) {} async stores(): Promise { this.logger.log('Buscando todas as lojas'); try { const stores = await this.repository.findStores(); if (stores === null || stores === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const storesArray = Array.isArray(stores) ? stores : [stores]; return storesArray .filter((store) => { if (!store || typeof store !== 'object') { return false; } const hasId = store.id !== undefined && store.id !== null && store.id !== ''; const hasName = store.name !== undefined && store.name !== null && store.name !== ''; const hasStore = store.store !== undefined && store.store !== null && store.store !== ''; return hasId && hasName && hasStore; }) .map((store) => new StoreDto(store)); } catch (error) { this.logger.error('Erro ao buscar lojas', error); throw new HttpException( 'Erro ao buscar lojas', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async sellers(): Promise { this.logger.log('Buscando vendedores com cache Redis...'); try { return await getOrSetCache( this.redisClient, this.SELLERS_CACHE_KEY, this.SELLERS_TTL, async () => { try { const sellers = await this.repository.findSellers(); if (sellers === null || sellers === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const sellersArray = Array.isArray(sellers) ? sellers : [sellers]; return sellersArray .filter((seller) => { if (!seller || typeof seller !== 'object') { return false; } const hasId = seller.id !== undefined && seller.id !== null && seller.id !== ''; const hasName = seller.name !== undefined && seller.name !== null && seller.name !== ''; return hasId && hasName; }) .map((seller) => new SellerDto(seller)); } catch (error) { this.logger.error('Erro ao buscar vendedores', error); throw error; } }, ); } catch (error) { this.logger.error('Erro ao buscar vendedores', error); throw new HttpException( 'Erro ao buscar vendedores', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async billings(): Promise { this.logger.log('Buscando informações de faturamento'); try { const billings = await this.repository.findBillings(); if (billings === null || billings === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const billingsArray = Array.isArray(billings) ? billings : [billings]; return billingsArray .filter((billing) => { if (!billing || typeof billing !== 'object') { return false; } const hasId = billing.id !== undefined && billing.id !== null && billing.id !== ''; const hasDate = billing.date !== undefined && billing.date !== null; const hasTotal = billing.total !== undefined && billing.total !== null; return hasId && hasDate && hasTotal; }) .map((billing) => new BillingDto(billing)); } catch (error) { this.logger.error('Erro ao buscar faturamento', error); throw new HttpException( 'Erro ao buscar faturamento', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async customers(filter: string): Promise { this.logger.log(`Buscando clientes com filtro: ${filter}`); try { if (!filter || typeof filter !== 'string') { throw new HttpException('Filtro inválido', HttpStatus.BAD_REQUEST); } const customers = await this.repository.findCustomers(filter); if (customers === null || customers === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const customersArray = Array.isArray(customers) ? customers : [customers]; return customersArray .filter((customer) => { if (!customer || typeof customer !== 'object') { return false; } const hasId = customer.id !== undefined && customer.id !== null && customer.id !== ''; const hasName = customer.name !== undefined && customer.name !== null && customer.name !== ''; const hasDocument = customer.document !== undefined && customer.document !== null && customer.document !== ''; return hasId && hasName && hasDocument; }) .map((customer) => new CustomerDto(customer)); } catch (error) { this.logger.error('Erro ao buscar clientes', error); throw new HttpException( 'Erro ao buscar clientes', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async products(filter: string): Promise { this.logger.log(`Buscando produtos com filtro: ${filter}`); try { if (!filter || typeof filter !== 'string') { throw new HttpException('Filtro inválido', HttpStatus.BAD_REQUEST); } const products = await this.repository.findProducts(filter); return products.map((product) => new ProductDto(product)); } catch (error) { this.logger.error('Erro ao buscar produtos', error); throw new HttpException( 'Erro ao buscar produtos', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async productsByCodauxiliar(codauxiliar: string): Promise { this.logger.log(`Buscando produtos por codauxiliar: ${codauxiliar}`); try { if (!codauxiliar || typeof codauxiliar !== 'string') { throw new HttpException( 'Código auxiliar inválido', HttpStatus.BAD_REQUEST, ); } const products = await this.repository.findProductsByCodauxiliar( codauxiliar, ); return products.map((product) => new ProductDto(product)); } catch (error) { this.logger.error('Erro ao buscar produtos por codauxiliar', error); throw new HttpException( 'Erro ao buscar produtos por codauxiliar', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async getAllProducts(): Promise { this.logger.log('Buscando todos os produtos'); try { return await getOrSetCache( this.redisClient, this.ALL_PRODUCTS_CACHE_KEY, this.ALL_PRODUCTS_TTL, async () => { try { const products = await this.repository.findAllProducts(); if (products === null || products === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const productsArray = Array.isArray(products) ? products : [products]; return productsArray .filter((product) => { if (!product || typeof product !== 'object') { return false; } const hasId = product.id !== undefined && product.id !== null && product.id !== ''; const hasName = product.name !== undefined && product.name !== null && product.name !== ''; const hasManufacturerCode = product.manufacturerCode !== undefined && product.manufacturerCode !== null && product.manufacturerCode !== ''; return hasId && hasName && hasManufacturerCode; }) .map((product) => new ProductDto(product)); } catch (error) { this.logger.error('Erro ao buscar todos os produtos', error); throw error; } }, ); } catch (error) { this.logger.error('Erro ao buscar todos os produtos', error); throw new HttpException( 'Erro ao buscar produtos', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async getAllCarriers(): Promise { this.logger.log('Buscando todas as transportadoras'); try { return await getOrSetCache( this.redisClient, this.CARRIERS_CACHE_KEY, this.CARRIERS_TTL, async () => { try { const carriers = await this.repository.findAllCarriers(); if (carriers === null || carriers === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const carriersArray = Array.isArray(carriers) ? carriers : [carriers]; return carriersArray .filter((carrier) => { if (!carrier || typeof carrier !== 'object') { return false; } const hasCarrierId = carrier.carrierId !== undefined && carrier.carrierId !== null && carrier.carrierId !== ''; const hasCarrierName = carrier.carrierName !== undefined && carrier.carrierName !== null && carrier.carrierName !== ''; const hasCarrierDescription = carrier.carrierDescription !== undefined && carrier.carrierDescription !== null && carrier.carrierDescription !== ''; return hasCarrierId && hasCarrierName && hasCarrierDescription; }) .map((carrier) => ({ carrierId: carrier.carrierId?.toString() || '', carrierName: carrier.carrierName || '', carrierDescription: carrier.carrierDescription || '', })); } catch (error) { this.logger.error('Erro ao buscar transportadoras', error); throw error; } }, ); } catch (error) { this.logger.error('Erro ao buscar transportadoras', error); throw new HttpException( 'Erro ao buscar transportadoras', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async getCarriersByDate(query: FindCarriersDto): Promise { this.logger.log( `Buscando transportadoras por período: ${JSON.stringify(query)}`, ); try { const carriers = await this.repository.findCarriersByDate(query); return carriers.map((carrier) => ({ carrierId: carrier.carrierId?.toString() || '', carrierName: carrier.carrierName || '', carrierDescription: carrier.carrierDescription || '', ordersCount: carrier.ordersCount ? Number(carrier.ordersCount) : 0, })); } catch (error) { this.logger.error('Erro ao buscar transportadoras por período', error); throw new HttpException( 'Erro ao buscar transportadoras', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async getOrderCarriers(orderId: number): Promise { this.logger.log(`Buscando transportadoras do pedido: ${orderId}`); try { const carriers = await this.repository.findOrderCarriers(orderId); return carriers.map((carrier) => ({ carrierId: carrier.carrierId?.toString() || '', carrierName: carrier.carrierName || '', carrierDescription: carrier.carrierDescription || '', })); } catch (error) { this.logger.error('Erro ao buscar transportadoras do pedido', error); throw new HttpException( 'Erro ao buscar transportadoras do pedido', HttpStatus.INTERNAL_SERVER_ERROR, ); } } async getRegions(): Promise { this.logger.log('Buscando todas as regiões'); try { return await getOrSetCache( this.redisClient, this.REGIONS_CACHE_KEY, this.REGIONS_TTL, async () => { try { const regions = await this.repository.findRegions(); if (regions === null || regions === undefined) { throw new HttpException( 'Resultado inválido do repositório', HttpStatus.INTERNAL_SERVER_ERROR, ); } const regionsArray = Array.isArray(regions) ? regions : [regions]; return regionsArray .filter((region) => { if (!region || typeof region !== 'object') { return false; } const hasNumregiao = region.numregiao !== undefined && region.numregiao !== null; const hasRegiao = region.regiao !== undefined && region.regiao !== null && region.regiao !== ''; return hasNumregiao && hasRegiao; }) .map((region) => new RegionDto(region)); } catch (error) { this.logger.error('Erro ao buscar regiões', error); throw error; } }, ); } catch (error) { this.logger.error('Erro ao buscar regiões', error); throw new HttpException( 'Erro ao buscar regiões', HttpStatus.INTERNAL_SERVER_ERROR, ); } } }