diff --git a/DAL/DAL.csproj b/DAL/DAL.csproj index 7321d5a..86f8a32 100644 --- a/DAL/DAL.csproj +++ b/DAL/DAL.csproj @@ -14,4 +14,8 @@ + + + + diff --git a/DAL/DALItensLotes.cs b/DAL/DALItensLotes.cs index 8b03669..1c8dcc9 100644 --- a/DAL/DALItensLotes.cs +++ b/DAL/DALItensLotes.cs @@ -1384,206 +1384,577 @@ namespace DAL }//QuantidadeProdutosComMaisDeUmLote #endregion - #region Relatórios - Reports + #region Relatórios- Reports public DataTable ListarTodos() { - DataTable tabela = new DataTable(); + DataTable tabela = new(); - using (SqlConnection conexao = new SqlConnection(DadosDaConexao.ObjetoStringConexao)) - { - conexao.Open(); + using SqlConnection conexao = new(connectionString); - SqlDataAdapter da = new SqlDataAdapter(@" - SELECT * - FROM Itens_Lotes - ORDER BY COD_ITEM, DATA_VALIDADE", conexao); + conexao.Open(); - da.Fill(tabela); - } + SqlDataAdapter da = new(@" + SELECT * + FROM Itens_Lotes + ORDER BY COD_ITEM, DATA_VALIDADE", conexao); + + da.Fill(tabela); return tabela; }//ListarTodos - public DataTable ListarPorProduto(string codItem) + public DataTable RelatorioPorProduto(string codItem) { - DataTable tabela = new DataTable(); + DataTable tabela = new(); - using (SqlConnection conexao = new SqlConnection(connectionString)) - { - conexao.Open(); + using SqlConnection conexao = new(connectionString); - SqlDataAdapter da = new SqlDataAdapter(@" - SELECT * - FROM Itens_Lotes - WHERE COD_ITEM=@COD_ITEM - ORDER BY DATA_VALIDADE", conexao); + conexao.Open(); - da.SelectCommand.Parameters.AddWithValue("@COD_ITEM", codItem); + SqlDataAdapter da = new(@" + SELECT * + FROM Itens_Lotes + WHERE COD_ITEM=@COD_ITEM + ORDER BY DATA_VALIDADE", conexao); - da.Fill(tabela); - } + da.SelectCommand.Parameters.AddWithValue( + "@COD_ITEM", codItem); + + da.Fill(tabela); return tabela; - } - - public DataTable ListarPorFornecedor(string fornecedor) + }//RelatorioPorProduto + public DataTable RelatorioPorFornecedor(string fornecedor) { - DataTable tabela = new DataTable(); + DataTable tabela = new(); - using (SqlConnection conexao = new SqlConnection(DadosDaConexao.StringDeConexao)) - { - conexao.Open(); + using SqlConnection conexao = new(connectionString); - SqlDataAdapter da = new SqlDataAdapter(@" - SELECT * - FROM Itens_Lotes - WHERE FORNECEDOR=@FORNECEDOR - ORDER BY COD_ITEM", conexao); + conexao.Open(); - da.SelectCommand.Parameters.AddWithValue("@FORNECEDOR", fornecedor); + SqlDataAdapter da = new(@" + SELECT * + FROM Itens_Lotes + WHERE FORNECEDOR=@FORNECEDOR + ORDER BY COD_ITEM", conexao); - da.Fill(tabela); - } + da.SelectCommand.Parameters.AddWithValue( + "@FORNECEDOR", fornecedor); + + da.Fill(tabela); return tabela; - } - - public DataTable ListarVencidos() + }//RelatorioPorFornecedor + public DataTable RelatorioVencidos() { - DataTable tabela = new DataTable(); + DataTable tabela = new(); - using (SqlConnection conexao = new SqlConnection(DadosDaConexao.StringDeConexao)) - { - conexao.Open(); + using SqlConnection conexao = new(connectionString); - SqlDataAdapter da = new SqlDataAdapter(@" - SELECT * - FROM Itens_Lotes - WHERE DATA_VALIDADE 0 + ORDER BY COD_ITEM", conexao); + + da.Fill(tabela); + + return tabela; + }//RelatorioComReserva + public DataTable RelatorioSemSaldo() + { + DataTable tabela = new(); + + using SqlConnection conexao = new(connectionString); + + conexao.Open(); + + SqlDataAdapter da = new(@" + SELECT * + FROM Itens_Lotes + WHERE QUANTIDADE = 0 + ORDER BY COD_ITEM", conexao); + + da.Fill(tabela); + + return tabela; + }//RelatorioSemSaldo + public DataTable RelatorioDisponiveis() + { + DataTable tabela = new(); + + using SqlConnection conexao = new(connectionString); + + conexao.Open(); + + SqlDataAdapter da = new(@" + SELECT * + FROM Itens_Lotes + WHERE QUANTIDADE_DISPONIVEL > 0 + ORDER BY COD_ITEM, + DATA_VALIDADE", conexao); + + da.Fill(tabela); + + return tabela; + }//RelatorioDisponiveis + + #endregion + #region Integração - Integration + public bool AtualizarSaldoItem(string codigoItem) + { + decimal saldo = SaldoProduto(codigoItem); + + using SqlConnection conn = new(connectionString); + + string sql = @" + UPDATE Itens + SET ESTOQUE_DISP = @ESTOQUE + WHERE CODIGO = @CODIGO"; + + using SqlCommand cmd = new(sql, conn); + + cmd.Parameters.AddWithValue("@ESTOQUE", saldo.ToString()); + cmd.Parameters.AddWithValue("@CODIGO", codigoItem); + + conn.Open(); + + return cmd.ExecuteNonQuery() > 0; + }//AtualizarSaldoItem + public bool AtualizarUltimaCompra(string codigoItem,DateTime dataCompra) + { + using SqlConnection conn = new(connectionString); + + string sql = @" + UPDATE Itens + SET ULTIMA_COMPRA = @DATA + WHERE CODIGO = @CODIGO"; + + using SqlCommand cmd = new(sql, conn); + + cmd.Parameters.AddWithValue( + "@DATA", + dataCompra.ToString("dd/MM/yyyy")); + + cmd.Parameters.AddWithValue( + "@CODIGO", + codigoItem); + + conn.Open(); + + return cmd.ExecuteNonQuery() > 0; + }//AtualizarUltimaCompra + public bool AtualizarFornecedorPrincipal(string codigoItem) + { + using SqlConnection conn = new(connectionString); + + string sqlFornecedor = @" + SELECT TOP 1 FORNECEDOR + FROM Itens_Lotes + WHERE COD_ITEM=@COD_ITEM + GROUP BY FORNECEDOR + ORDER BY COUNT(*) DESC"; + + using SqlCommand cmd = new(sqlFornecedor, conn); + + cmd.Parameters.AddWithValue( + "@COD_ITEM", + codigoItem); + + conn.Open(); + + string fornecedor = + Convert.ToString(cmd.ExecuteScalar()) ?? + string.Empty; + + conn.Close(); + + sqlFornecedor = @" + UPDATE Itens + SET FORNECEDOR=@FORNECEDOR + WHERE CODIGO=@CODIGO"; + + cmd.CommandText = sqlFornecedor; + + cmd.Parameters.Clear(); + + cmd.Parameters.AddWithValue( + "@FORNECEDOR", + fornecedor); + + cmd.Parameters.AddWithValue( + "@CODIGO", + codigoItem); + + conn.Open(); + + return cmd.ExecuteNonQuery() > 0; + }//AtualizarFornecedorPrincipal + public bool AtualizarValidadeProduto(string codigoItem) + { + DateTime? validade = + PrimeiroVencimento(codigoItem); + + if (!validade.HasValue) + return false; + + using SqlConnection conn = new(connectionString); + + string sql = @" + UPDATE Itens + SET VALIDADE=@VALIDADE + WHERE CODIGO=@CODIGO"; + + using SqlCommand cmd = new(sql, conn); + + cmd.Parameters.AddWithValue( + "@VALIDADE", + validade.Value.ToString("dd/MM/yyyy")); + + cmd.Parameters.AddWithValue( + "@CODIGO", + codigoItem); + + conn.Open(); + + return cmd.ExecuteNonQuery() > 0; + }//AtualizarValidadeProduto + public void RecalcularEstoqueProduto(string codigoItem) + { + AtualizarSaldoItem(codigoItem); + + AtualizarFornecedorPrincipal( + codigoItem); + + AtualizarValidadeProduto( + codigoItem); + }//RecalcularEstoqueProduto + + #endregion + #region Inteligencia de Negócios - Business Intelligence + public ModeloItensLotes? MelhorLoteVenda(string codigoProduto) + { + // Hoje utiliza FEFO. + // Futuramente poderá ler da configuração da empresa. + + return ObterFEFO(codigoProduto); + }//MelhorLoteVenda + public bool SugestaoReposicao(string codigoProduto) + { + decimal saldo = SaldoProduto( + codigoProduto); + + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT ESTOQUE_MIN + FROM Itens + WHERE CODIGO=@CODIGO"; + + using SqlCommand cmd = + new(sql, conn); + + cmd.Parameters.AddWithValue( + "@CODIGO", + codigoProduto); + + conn.Open(); + + decimal minimo = + Convert.ToDecimal( + cmd.ExecuteScalar() ?? 0); + + return saldo <= minimo; + }//SugestaoReposicao + public decimal CapitalParado() + { + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT ISNULL( + SUM( + TRY_CONVERT(decimal(18,2), + QUANTIDADE) + ),0) + FROM Itens_Lotes + WHERE QUANTIDADE > 0"; + + using SqlCommand cmd = + new(sql, conn); + + conn.Open(); + + return Convert.ToDecimal( + cmd.ExecuteScalar()); + }//CapitalParado + public decimal CapitalVencido() + { + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT ISNULL( + SUM(QUANTIDADE),0) + FROM Itens_Lotes + WHERE DATA_VALIDADE < + GETDATE()"; + + using SqlCommand cmd = + new(sql, conn); + + conn.Open(); + + return Convert.ToDecimal( + cmd.ExecuteScalar()); + }//CapitalVencido + public decimal CapitalAVencer(int dias) + { + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT ISNULL( + SUM(QUANTIDADE),0) + FROM Itens_Lotes + WHERE DATA_VALIDADE + BETWEEN GETDATE() + AND DATEADD( + DAY, + @DIAS, + GETDATE())"; + + using SqlCommand cmd = + new(sql, conn); + + cmd.Parameters.AddWithValue( + "@DIAS", + dias); + + conn.Open(); + + return Convert.ToDecimal( + cmd.ExecuteScalar()); + }//CapitalAVencer + public List ProdutosCriticos() + { + List lista = []; + + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT DISTINCT COD_ITEM + FROM Itens_Lotes + WHERE DATA_VALIDADE < + DATEADD( + DAY, + 15, + GETDATE())"; + + using SqlCommand cmd = + new(sql, conn); + + conn.Open(); + + using SqlDataReader dr = + cmd.ExecuteReader(); + + while (dr.Read()) + { + lista.Add( + dr["COD_ITEM"] + .ToString()!); + } + + return lista; + }//ProdutosCriticos + public ListLotesPrioritarios() + { + return Listar(validadeFinal:DateTime.Today.AddDays(15)); + }//LotesPrioritarios + public bool ExisteRiscoPerda(string codigoProduto) + { + return ExisteLoteAVencer( + codigoProduto, + 15); + }//ExisteRiscoPerda + public decimal SugestaoCompra(string codigoProduto) + { + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT ESTOQUE_IDEAL + FROM Itens + WHERE CODIGO=@CODIGO"; + + using SqlCommand cmd = + new(sql, conn); + + cmd.Parameters.AddWithValue( + "@CODIGO", + codigoProduto); + + conn.Open(); + + decimal ideal = + Convert.ToDecimal( + cmd.ExecuteScalar() ?? 0); + + decimal atual = + SaldoProduto( + codigoProduto); + + if (ideal <= atual) + return 0; + + return ideal - atual; + }//SugestaoCompra + public bool PossuiLotes(string codigoProduto) + { + using SqlConnection conn = + new(connectionString); + + string sql = @" + SELECT COUNT(*) + FROM Itens_Lotes + WHERE COD_ITEM=@COD_ITEM"; + + using SqlCommand cmd = + new(sql, conn); + + cmd.Parameters.AddWithValue( + "@COD_ITEM", + codigoProduto); + + conn.Open(); + + return Convert.ToInt32( + cmd.ExecuteScalar()) > 0; + }//PossuiLotes #endregion + //Concluida em 2026-07-20 + //Versão 1.0.2 - - //Parte 8.1 -> Concluida - //Parte 8.2 -> Concluida - //Parte 8.3 -> Concluida - //Parte 8.4 -> Concluida - //Parte 8.5 -> Concluida - //Parte 8.6 -> Concluida - //Parte 8.7 -> Concluida - //Parte 8.8 - //Parte 8.9 - //Parte 8.10 } } diff --git a/DAL/Docs/DALITENSLOTES_DESCRICAO.md b/DAL/Docs/DALITENSLOTES_DESCRICAO.md new file mode 100644 index 0000000..a534421 --- /dev/null +++ b/DAL/Docs/DALITENSLOTES_DESCRICAO.md @@ -0,0 +1,199 @@ +//Parte 8.1 -> Concluída +// CRUD (Create, Read, Update e Delete) +// +// Responsável pelas operações básicas da tabela Itens_Lotes. +// Implementa inserção, alteração, exclusão, carregamento, +// verificação de existência e preenchimento do modelo. +// +// Métodos: +// - Inserir() +// - Alterar() +// - Excluir() +// - Carregar() +// - CarregarPorCodigo() +// - CarregarPorLote() +// - ExisteCodigo() +// - ExisteLote() +// - PreencherModelo() +// - PreencherParametros() + +//Parte 8.2 -> Concluída +// Pesquisas e Filtros +// +// Responsável pelas consultas avançadas do módulo, +// permitindo localizar lotes por diversos critérios. +// +// Métodos: +// - Listar() +// - ListarPorProduto() +// - ListarPorFornecedor() +// - ListarPorNF() +// - ListarPorLote() +// - ListarAtivos() +// - ListarInativos() +// - ListarVencidos() +// - ListarAVencer() +// - ListarPorPeriodoValidade() +// - ListarPorPeriodoFabricacao() + +//Parte 8.3 -> Concluída +// Controle de Estoque +// +// Responsável pelas movimentações de estoque dos lotes, +// incluindo entradas, saídas, transferências e ajustes. +// +// Métodos: +// - Entrada() +// - Saida() +// - SomarQuantidade() +// - BaixarQuantidade() +// - AjustarQuantidade() +// - TransferirQuantidade() +// - SaldoLote() +// - SaldoProduto() +// - ExisteSaldo() +// - ZerarLote() + +//Parte 8.4 -> Concluída +// Controle de Validade +// +// Responsável pela gestão das datas de validade dos lotes, +// identificação de produtos vencidos e monitoramento de risco. +// +// Métodos: +// - LotesVencidos() +// - LotesAVencer() +// - LotesValidos() +// - LotesSemValidade() +// - DiasParaVencer() +// - DiasVencido() +// - PrimeiroVencimento() +// - UltimoVencimento() +// - ExisteLoteVencido() +// - ExisteLoteAVencer() +// - QuantidadeVencida() +// - QuantidadeAVencer() +// - QuantidadeValida() + +//Parte 8.5 -> Concluída +// FEFO / FIFO +// +// Responsável pela seleção automática do melhor lote para +// venda e reserva de estoque. +// +// Métodos: +// - ObterFEFO() +// - ObterFIFO() +// - ReservarLote() +// - LiberarLote() +// - ConsumirReserva() +// - MelhorLote() +// - QuantidadeDisponivel() +// - QuantidadeReservada() +// - PodeAtenderVenda() + +//Parte 8.6 -> Concluída +// Dashboard +// +// Responsável pelos indicadores e métricas utilizadas em +// dashboards, telas gerenciais e painéis do sistema. +// +// Indicadores: +// - QuantidadeLotes() +// - QuantidadeProdutos() +// - QuantidadeLotesAtivos() +// - QuantidadeLotesInativos() +// - QuantidadeVencidos() +// - QuantidadeAVencer() +// - QuantidadeSemValidade() +// - QuantidadeTotalEstoque() +// - QuantidadeDisponivelEstoque() +// - QuantidadeReservadaEstoque() +// - MaiorQuantidade() +// - MenorQuantidade() +// - QuantidadeMedia() +// - PercentualReservado() +// - PercentualDisponivel() + +//Parte 8.7 -> Concluída +// Estatísticas +// +// Responsável pela geração de estatísticas avançadas para +// análise de comportamento dos lotes. +// +// Estatísticas: +// - ProdutoComMaisLotes() +// - ProdutoComMenosLotes() +// - FornecedorComMaisLotes() +// - FornecedorComMenosLotes() +// - MediaQuantidadeLote() +// - MediaDiasValidade() +// - ProdutosSemLote() +// - LotesSemMovimento() +// - LotesComEstoqueZero() +// - LotesComEstoquePositivo() +// - QuantidadeMediaPorProduto() +// - QuantidadeProdutosComMaisDeUmLote() + +//Parte 8.8 -> Concluída +// Relatórios +// +// Responsável pela geração de DataTables para impressão, +// exportação e visualização em grids. +// +// Relatórios: +// - ListarTodos() +// - RelatorioPorProduto() +// - RelatorioPorFornecedor() +// - RelatorioVencidos() +// - RelatorioAVencer() +// - RelatorioSemValidade() +// - RelatorioEstoqueZero() +// - RelatorioAtivos() +// - RelatorioInativos() +// - RelatorioComReserva() +// - RelatorioSemSaldo() +// - RelatorioDisponiveis() + +//Parte 8.9 -> Concluída +// Integração +// +// Responsável pela sincronização do módulo de lotes com +// os demais módulos do ERP. +// +// Integrações: +// - AtualizarSaldoItem() +// - AtualizarUltimaCompra() +// - AtualizarFornecedorPrincipal() +// - AtualizarValidadeProduto() +// - RecalcularEstoqueProduto() +// +// Módulos Integrados: +// - Itens +// - Compras +// - Vendas +// - Estoque +// - Movimentações + +//Parte 8.10 -> Concluída +// Inteligência +// +// Responsável pela camada de inteligência do módulo, +// oferecendo sugestões, análises e automações. +// +// Recursos: +// - MelhorLoteVenda() +// - SugestaoReposicao() +// - CapitalParado() +// - CapitalVencido() +// - CapitalAVencer() +// - ProdutosCriticos() +// - LotesPrioritarios() +// - ExisteRiscoPerda() +// - SugestaoCompra() +// - PossuiLotes() +// +// Esta camada utiliza todas as demais partes da DAL para +// fornecer recursos avançados de tomada de decisão, +// tornando o módulo Itens_Lotes comparável aos controles +// de rastreabilidade presentes em ERPs de médio e grande porte.