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.