diff --git a/CPM/ComboBox/LV_COMBOBOX.cs b/CPM/ComboBox/LV_COMBOBOX.cs
new file mode 100644
index 0000000..1478e52
--- /dev/null
+++ b/CPM/ComboBox/LV_COMBOBOX.cs
@@ -0,0 +1,242 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+
+namespace CPM
+{
+ ///
+ /// ComboBox customizado do sistema LevelOS.
+ /// Segue o mesmo padrão visual do LV_TEXTBOX1.
+ ///
+ public class LV_COMBOBOX : UserControl
+ {
+ // ── CAMPOS INTERNOS ───────────────────────────────────────────────────
+ private ComboBox _combo;
+ private bool _isFocused = false;
+
+ // ── PROPRIEDADES VISUAIS ──────────────────────────────────────────────
+ private Color _borderColor = Color.FromArgb(226, 232, 240);
+ private Color _borderFocusColor = Color.FromArgb(37, 99, 235);
+ private Color _arrowColor = Color.FromArgb(100, 116, 139);
+ private int _borderRadius = 6;
+ private int _borderSize = 1;
+
+ public Color BorderColor
+ {
+ get => _borderColor;
+ set { _borderColor = value; Invalidate(); }
+ }
+
+ public Color BorderFocusColor
+ {
+ get => _borderFocusColor;
+ set { _borderFocusColor = value; Invalidate(); }
+ }
+
+ public Color ArrowColor
+ {
+ get => _arrowColor;
+ set { _arrowColor = value; Invalidate(); }
+ }
+
+ public int BorderRadius
+ {
+ get => _borderRadius;
+ set { _borderRadius = value; Invalidate(); }
+ }
+
+ public int BorderSize
+ {
+ get => _borderSize;
+ set { _borderSize = value; Invalidate(); }
+ }
+
+ // ── PROPRIEDADES DO COMBOBOX ──────────────────────────────────────────
+ public ComboBoxStyle DropDownStyle
+ {
+ get => _combo.DropDownStyle;
+ set => _combo.DropDownStyle = value;
+ }
+
+ public System.Windows.Forms.ComboBox.ObjectCollection Items => _combo.Items;
+
+ public object? SelectedItem
+ {
+ get => _combo.SelectedItem;
+ set => _combo.SelectedItem = value;
+ }
+
+ public int SelectedIndex
+ {
+ get => _combo.SelectedIndex;
+ set => _combo.SelectedIndex = value;
+ }
+
+ public string Text
+ {
+ get => _combo.Text;
+ set => _combo.Text = value;
+ }
+
+ public override Font Font
+ {
+ get => base.Font;
+ set
+ {
+ base.Font = value;
+ _combo.Font = value;
+ AjustarAltura();
+ }
+ }
+
+ public new bool Enabled
+ {
+ get => base.Enabled;
+ set
+ {
+ base.Enabled = value;
+ _combo.Enabled = value;
+ BackColor = value ? Color.White : Color.FromArgb(241, 245, 249);
+ Invalidate();
+ }
+ }
+
+ // ── EVENTOS REPASSADOS ────────────────────────────────────────────────
+ public event EventHandler? SelectedIndexChanged
+ {
+ add => _combo.SelectedIndexChanged += value;
+ remove => _combo.SelectedIndexChanged -= value;
+ }
+
+ public new event EventHandler? TextChanged
+ {
+ add => _combo.TextChanged += value;
+ remove => _combo.TextChanged -= value;
+ }
+
+ // ── CONSTRUTOR ────────────────────────────────────────────────────────
+ public LV_COMBOBOX()
+ {
+ _combo = new ComboBox
+ {
+ DropDownStyle = ComboBoxStyle.DropDownList,
+ FlatStyle = FlatStyle.Flat,
+ Font = new Font("Segoe UI", 9f),
+ BackColor = Color.White,
+ ForeColor = Color.FromArgb(30, 41, 59),
+ Dock = DockStyle.None,
+ IntegralHeight = false
+ };
+
+ // Configura o controle pai
+ Padding = new Padding(8, 0, 30, 0); // espaço para seta customizada
+ BackColor = Color.White;
+ ForeColor = Color.FromArgb(30, 41, 59);
+ Font = new Font("Segoe UI", 9f);
+ Size = new Size(200, 36);
+ DoubleBuffered = true;
+
+ Controls.Add(_combo);
+ AjustarAltura();
+
+ // Eventos de foco
+ _combo.GotFocus += (s, e) => { _isFocused = true; Invalidate(); };
+ _combo.LostFocus += (s, e) => { _isFocused = false; Invalidate(); };
+
+ // Propaga clique na área do controle para o combo
+ this.Click += (s, e) => _combo.Focus();
+
+ _combo.DropDown += (s, e) => Invalidate();
+ _combo.DropDownClosed += (s, e) => Invalidate();
+ }
+
+ // ── AJUSTE DE ALTURA ──────────────────────────────────────────────────
+ private void AjustarAltura()
+ {
+ int altura = _combo.PreferredHeight;
+ this.Height = altura + 10;
+ _combo.Width = this.Width - 38; // reserva espaço para seta
+ _combo.Left = 8;
+ _combo.Top = (this.Height - _combo.Height) / 2;
+ }
+
+ // ── RESIZE ────────────────────────────────────────────────────────────
+ protected override void OnResize(EventArgs e)
+ {
+ base.OnResize(e);
+ _combo.Width = this.Width - 38;
+ _combo.Left = 8;
+ _combo.Top = (this.Height - _combo.Height) / 2;
+ Invalidate();
+ }
+
+ // ── PAINT ─────────────────────────────────────────────────────────────
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ base.OnPaint(e);
+
+ var g = e.Graphics;
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+
+ var cor = _isFocused ? _borderFocusColor : _borderColor;
+ var rect = new Rectangle(0, 0, Width - 1, Height - 1);
+ var bgRect = new Rectangle(1, 1, Width - 2, Height - 2);
+
+ // Fundo
+ using var bgBrush = new SolidBrush(Enabled ? BackColor : Color.FromArgb(241, 245, 249));
+ g.FillRoundedRectangle(bgBrush, bgRect, _borderRadius);
+
+ // Borda
+ using var pen = new Pen(cor, _borderSize);
+ g.DrawRoundedRectangle(pen, rect, _borderRadius);
+
+ // Seta customizada
+ DesenharSeta(g);
+ }
+
+ private void DesenharSeta(Graphics g)
+ {
+ int arrowX = Width - 22;
+ int arrowY = Height / 2;
+
+ using var brush = new SolidBrush(_isFocused ? _borderFocusColor : _arrowColor);
+ var pontos = new Point[]
+ {
+ new Point(arrowX - 5, arrowY - 3),
+ new Point(arrowX + 5, arrowY - 3),
+ new Point(arrowX, arrowY + 4)
+ };
+ g.FillPolygon(brush, pontos);
+ }
+ }
+
+ // ── EXTENSÕES DE GRAPHICS PARA ROUNDED RECT ───────────────────────────────
+ internal static class GraphicsExtensions
+ {
+ public static void FillRoundedRectangle(this Graphics g, Brush brush, Rectangle rect, int radius)
+ {
+ using var path = GetRoundedPath(rect, radius);
+ g.FillPath(brush, path);
+ }
+
+ public static void DrawRoundedRectangle(this Graphics g, Pen pen, Rectangle rect, int radius)
+ {
+ using var path = GetRoundedPath(rect, radius);
+ g.DrawPath(pen, path);
+ }
+
+ private static GraphicsPath GetRoundedPath(Rectangle rect, int radius)
+ {
+ int r = Math.Min(radius, Math.Min(rect.Width, rect.Height) / 2);
+ var d = r * 2;
+ var path = new GraphicsPath();
+ path.AddArc(rect.X, rect.Y, d, d, 180, 90);
+ path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);
+ path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);
+ path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);
+ path.CloseFigure();
+ return path;
+ }
+ }
+}
diff --git a/MLL/ModeloBoletos.cs b/MLL/ModeloBoletos.cs
index a912390..09aa30d 100644
--- a/MLL/ModeloBoletos.cs
+++ b/MLL/ModeloBoletos.cs
@@ -4,71 +4,122 @@ namespace MLL
{
public class ModeloBoletos
{
+ // ── CONSTRUTOR VAZIO ──────────────────────────────────────────────────
public ModeloBoletos()
{
- this.ID_BOLETO = 0;
- this.CODIGO = string.Empty;
- this.EMITIDO = string.Empty;
- this.VENCE = string.Empty;
- this.VALOR = string.Empty;
- this.NUMERO = string.Empty;
- this.PG = string.Empty;
- this.SACADO = string.Empty;
- this.CONTA = string.Empty;
- this.OBSERVACAO = string.Empty;
- this.COD_CONTA = string.Empty;
- this.NOSSO_NUMERO = string.Empty;
- this.ACEITE = string.Empty;
- this.IMPRESSO = string.Empty;
- this.IMPORTACAO = string.Empty;
- }
- public ModeloBoletos(int iD_BOLETO, string cODIGO, string eMITIDO, string vENCE, string vALOR, string nUMERO, string pG, string sACADO, string cONTA, string oBSERVACAO, string cOD_CONTA, string nOSSO_NUMERO, string aCEITE, string iMPRESSO, string iMPORTACAO)
- {
- ID_BOLETO = iD_BOLETO;
- CODIGO = cODIGO;
- EMITIDO = eMITIDO;
- VENCE = vENCE;
- VALOR = vALOR;
- NUMERO = nUMERO;
- PG = pG;
- SACADO = sACADO;
- CONTA = cONTA;
- OBSERVACAO = oBSERVACAO;
- COD_CONTA = cOD_CONTA;
- NOSSO_NUMERO = nOSSO_NUMERO;
- ACEITE = aCEITE;
- IMPRESSO = iMPRESSO;
- IMPORTACAO = iMPORTACAO;
+ ID_BOLETO = 0;
+ CODIGO = string.Empty;
+ NUMERO = string.Empty;
+ NOSSO_NUMERO = string.Empty;
+ CHAVE_BOLETO = string.Empty;
+ LINHA_DIGITAVEL = string.Empty;
+ EMITIDO = null;
+ VENCE = null;
+ DT_PAGAMENTO = null;
+ VALOR = 0m;
+ VL_PAGO = null;
+ VL_MULTA = null;
+ VL_DESCONTO = null;
+ STATUS = "ABERTO";
+ PG = false;
+ SACADO = string.Empty;
+ CONTA = string.Empty;
+ COD_CONTA = string.Empty;
+ ACEITE = false;
+ IMPRESSO = false;
+ IMPORTACAO = false;
+ ARQUIVO_NOME = string.Empty;
+ ARQUIVO_TIPO = string.Empty;
+ ARQUIVO_CAMINHO = string.Empty;
+ ARQUIVO_DADOS = null;
+ OBSERVACAO = string.Empty;
+ DT_CADASTRO = DateTime.Now;
+ DT_ALTERACAO = null;
+ ID_USUARIO = null;
}
+ // ── IDENTIFICAÇÃO ─────────────────────────────────────────────────────
public int ID_BOLETO { get; set; }
-
public string CODIGO { get; set; }
-
- public string EMITIDO { get; set; }
-
- public string VENCE { get; set; }
-
- public string VALOR { get; set; }
-
public string NUMERO { get; set; }
-
- public string PG { get; set; }
-
- public string SACADO { get; set; }
-
- public string CONTA { get; set; }
-
- public string OBSERVACAO { get; set; }
-
- public string COD_CONTA { get; set; }
-
public string NOSSO_NUMERO { get; set; }
- public string ACEITE { get; set; }
+ /// Chave única para baixa/integração bancária.
+ public string CHAVE_BOLETO { get; set; }
- public string IMPRESSO { get; set; }
+ /// Código de barras / linha digitável (47 ou 48 dígitos).
+ public string LINHA_DIGITAVEL { get; set; }
- public string IMPORTACAO { get; set; }
+ // ── DATAS ─────────────────────────────────────────────────────────────
+ public DateTime? EMITIDO { get; set; }
+ public DateTime? VENCE { get; set; }
+
+ /// Data efetiva em que o boleto foi pago.
+ public DateTime? DT_PAGAMENTO { get; set; }
+
+ // ── VALORES ───────────────────────────────────────────────────────────
+ public decimal VALOR { get; set; }
+
+ /// Valor efetivamente pago (pode diferir de VALOR por multa/desconto).
+ public decimal? VL_PAGO { get; set; }
+
+ /// Multa por atraso aplicada no pagamento.
+ public decimal? VL_MULTA { get; set; }
+
+ /// Desconto concedido no pagamento.
+ public decimal? VL_DESCONTO { get; set; }
+
+ // ── STATUS ────────────────────────────────────────────────────────────
+ ///
+ /// Status do boleto.
+ /// Valores: ABERTO | PAGO | VENCIDO | CANCELADO | BAIXADO
+ ///
+ public string STATUS { get; set; }
+
+ // ── FLAGS ─────────────────────────────────────────────────────────────
+ public bool PG { get; set; }
+ public bool ACEITE { get; set; }
+ public bool IMPRESSO { get; set; }
+ public bool IMPORTACAO { get; set; }
+
+ // ── SACADO E CONTA ────────────────────────────────────────────────────
+ public string SACADO { get; set; }
+ public string CONTA { get; set; }
+ public string COD_CONTA { get; set; }
+
+ // ── ARQUIVO (XML / PDF) ───────────────────────────────────────────────
+ /// Nome original do arquivo anexado.
+ public string ARQUIVO_NOME { get; set; }
+
+ /// Tipo do arquivo: "XML" ou "PDF".
+ public string ARQUIVO_TIPO { get; set; }
+
+ /// Caminho completo do arquivo em disco.
+ public string ARQUIVO_CAMINHO { get; set; }
+
+ /// Conteúdo binário do arquivo (para armazenamento no banco).
+ public byte[]? ARQUIVO_DADOS { get; set; }
+
+ // ── OBSERVAÇÃO ────────────────────────────────────────────────────────
+ public string OBSERVACAO { get; set; }
+
+ // ── RASTREABILIDADE ───────────────────────────────────────────────────
+ public DateTime DT_CADASTRO { get; set; }
+ public DateTime? DT_ALTERACAO { get; set; }
+ public int? ID_USUARIO { get; set; }
+
+ // ── HELPERS ───────────────────────────────────────────────────────────
+
+ /// Retorna true se o boleto está vencido e ainda não foi pago.
+ public bool EstaVencido =>
+ !PG && VENCE.HasValue && VENCE.Value.Date < DateTime.Today;
+
+ /// Retorna true se há arquivo anexado (caminho ou binário).
+ public bool TemArquivo =>
+ !string.IsNullOrEmpty(ARQUIVO_CAMINHO) || ARQUIVO_DADOS != null;
+
+ /// Valor com multa e desconto aplicados.
+ public decimal ValorFinal =>
+ VALOR + (VL_MULTA ?? 0m) - (VL_DESCONTO ?? 0m);
}
}
\ No newline at end of file
diff --git a/UI/ArquivosAuxiliares/BoletoTableNew.sql b/UI/ArquivosAuxiliares/BoletoTableNew.sql
new file mode 100644
index 0000000..5453093
--- /dev/null
+++ b/UI/ArquivosAuxiliares/BoletoTableNew.sql
@@ -0,0 +1,189 @@
+USE [Levelcode-LevelOS]
+GO
+
+-- ============================================================
+-- MIGRAÇÃO DA TABELA [dbo].[Boletos]
+-- Gerado em: 20/04/2026
+-- Descrição: Melhoria de tipos, rastreabilidade,
+-- suporte a arquivo (XML/PDF) e baixa bancária
+-- ============================================================
+
+-- ── PASSO 1: Corrigir tipos das colunas existentes ──────────
+
+-- Datas
+ALTER TABLE [dbo].[Boletos]
+ ALTER COLUMN [EMITIDO] DATE NULL;
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ALTER COLUMN [VENCE] DATE NULL;
+GO
+
+-- Valor
+ALTER TABLE [dbo].[Boletos]
+ ALTER COLUMN [VALOR] DECIMAL(10,2) NULL;
+GO
+
+-- Flags booleanas (S/N → BIT)
+-- Precisa converter os dados antes de mudar o tipo
+UPDATE [dbo].[Boletos] SET [PG] = CASE WHEN [PG] = 'S' THEN '1' ELSE '0' END;
+UPDATE [dbo].[Boletos] SET [ACEITE] = CASE WHEN [ACEITE] = 'S' THEN '1' ELSE '0' END;
+UPDATE [dbo].[Boletos] SET [IMPRESSO] = CASE WHEN [IMPRESSO] = 'S' THEN '1' ELSE '0' END;
+UPDATE [dbo].[Boletos] SET [IMPORTACAO]= CASE WHEN [IMPORTACAO]= 'S' THEN '1' ELSE '0' END;
+GO
+
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [PG] BIT NOT NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [ACEITE] BIT NOT NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [IMPRESSO] BIT NOT NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [IMPORTACAO] BIT NOT NULL;
+GO
+
+-- Campos de texto: limitar tamanho adequado
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [CODIGO] VARCHAR(50) NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [NUMERO] VARCHAR(50) NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [NOSSO_NUMERO] VARCHAR(50) NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [SACADO] VARCHAR(200) NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [CONTA] VARCHAR(100) NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [COD_CONTA] VARCHAR(30) NULL;
+ALTER TABLE [dbo].[Boletos] ALTER COLUMN [OBSERVACAO] VARCHAR(500) NULL;
+GO
+
+-- ── PASSO 2: Adicionar colunas novas ────────────────────────
+
+-- Baixa bancária / integração
+ALTER TABLE [dbo].[Boletos]
+ ADD [CHAVE_BOLETO] VARCHAR(100) NULL; -- Chave única para baixa/integração bancária
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [LINHA_DIGITAVEL] VARCHAR(60) NULL; -- Código de barras / linha digitável
+GO
+
+-- Pagamento
+ALTER TABLE [dbo].[Boletos]
+ ADD [DT_PAGAMENTO] DATE NULL; -- Data efetiva do pagamento
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [VL_PAGO] DECIMAL(10,2) NULL; -- Valor pago (pode ter multa/desconto)
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [VL_MULTA] DECIMAL(10,2) NULL; -- Multa por atraso
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [VL_DESCONTO] DECIMAL(10,2) NULL; -- Desconto concedido
+GO
+
+-- Arquivo (XML ou PDF) — caminho em disco
+ALTER TABLE [dbo].[Boletos]
+ ADD [ARQUIVO_NOME] VARCHAR(255) NULL; -- Nome original do arquivo
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [ARQUIVO_TIPO] VARCHAR(10) NULL; -- 'XML' ou 'PDF'
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [ARQUIVO_CAMINHO] VARCHAR(500) NULL; -- Caminho completo em disco
+GO
+
+-- Arquivo — binário no banco
+ALTER TABLE [dbo].[Boletos]
+ ADD [ARQUIVO_DADOS] VARBINARY(MAX) NULL; -- Conteúdo binário do arquivo
+GO
+
+-- Rastreabilidade
+ALTER TABLE [dbo].[Boletos]
+ ADD [DT_CADASTRO] DATETIME NOT NULL DEFAULT GETDATE(); -- Data de criação
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [DT_ALTERACAO] DATETIME NULL; -- Última alteração
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [ID_USUARIO] INT NULL; -- Usuário responsável
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD [STATUS] VARCHAR(20) NOT NULL DEFAULT 'ABERTO';
+ -- Valores possíveis: 'ABERTO', 'PAGO', 'VENCIDO', 'CANCELADO', 'BAIXADO'
+GO
+
+-- ── PASSO 3: Índices para performance ───────────────────────
+
+-- Busca por número do boleto
+CREATE NONCLUSTERED INDEX [IX_Boletos_Numero]
+ ON [dbo].[Boletos] ([NUMERO] ASC)
+ WHERE [NUMERO] IS NOT NULL;
+GO
+
+-- Busca por chave bancária
+CREATE NONCLUSTERED INDEX [IX_Boletos_Chave]
+ ON [dbo].[Boletos] ([CHAVE_BOLETO] ASC)
+ WHERE [CHAVE_BOLETO] IS NOT NULL;
+GO
+
+-- Busca por vencimento (relatórios de inadimplência)
+CREATE NONCLUSTERED INDEX [IX_Boletos_Vence]
+ ON [dbo].[Boletos] ([VENCE] ASC);
+GO
+
+-- Busca por status
+CREATE NONCLUSTERED INDEX [IX_Boletos_Status]
+ ON [dbo].[Boletos] ([STATUS] ASC);
+GO
+
+-- ── PASSO 4: Constraint de validação de status ──────────────
+
+ALTER TABLE [dbo].[Boletos]
+ ADD CONSTRAINT [CK_Boletos_Status]
+ CHECK ([STATUS] IN ('ABERTO', 'PAGO', 'VENCIDO', 'CANCELADO', 'BAIXADO'));
+GO
+
+ALTER TABLE [dbo].[Boletos]
+ ADD CONSTRAINT [CK_Boletos_ArquivoTipo]
+ CHECK ([ARQUIVO_TIPO] IN ('XML', 'PDF') OR [ARQUIVO_TIPO] IS NULL);
+GO
+
+-- ── PASSO 5: FK para usuário (se a tabela existir) ──────────
+-- Descomente quando a tabela de usuários estiver criada:
+-- ALTER TABLE [dbo].[Boletos]
+-- ADD CONSTRAINT [FK_Boletos_Usuario]
+-- FOREIGN KEY ([ID_USUARIO]) REFERENCES [dbo].[Usuarios]([ID_USUARIO]);
+-- GO
+
+-- ── RESULTADO FINAL ──────────────────────────────────────────
+-- Tabela com a estrutura completa após migração:
+--
+-- ID_BOLETO INT IDENTITY PK
+-- CODIGO VARCHAR(50)
+-- NUMERO VARCHAR(50)
+-- NOSSO_NUMERO VARCHAR(50)
+-- CHAVE_BOLETO VARCHAR(100) ← novo
+-- LINHA_DIGITAVEL VARCHAR(60) ← novo
+-- EMITIDO DATE ← tipo corrigido
+-- VENCE DATE ← tipo corrigido
+-- DT_PAGAMENTO DATE ← novo
+-- VALOR DECIMAL(10,2) ← tipo corrigido
+-- VL_PAGO DECIMAL(10,2) ← novo
+-- VL_MULTA DECIMAL(10,2) ← novo
+-- VL_DESCONTO DECIMAL(10,2) ← novo
+-- STATUS VARCHAR(20) ← novo
+-- PG BIT ← tipo corrigido
+-- SACADO VARCHAR(200) ← tipo corrigido
+-- CONTA VARCHAR(100) ← tipo corrigido
+-- COD_CONTA VARCHAR(30) ← tipo corrigido
+-- ACEITE BIT ← tipo corrigido
+-- IMPRESSO BIT ← tipo corrigido
+-- IMPORTACAO BIT ← tipo corrigido
+-- ARQUIVO_NOME VARCHAR(255) ← novo
+-- ARQUIVO_TIPO VARCHAR(10) ← novo
+-- ARQUIVO_CAMINHO VARCHAR(500) ← novo
+-- ARQUIVO_DADOS VARBINARY(MAX) ← novo
+-- OBSERVACAO VARCHAR(500) ← tipo corrigido
+-- DT_CADASTRO DATETIME ← novo
+-- DT_ALTERACAO DATETIME ← novo
+-- ID_USUARIO INT ← novo
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/BoletoCadastroPanel.cs b/UI/Dashboards/Cadastros/BoletoCadastroPanel.cs
new file mode 100644
index 0000000..ac7127a
--- /dev/null
+++ b/UI/Dashboards/Cadastros/BoletoCadastroPanel.cs
@@ -0,0 +1,741 @@
+using CPM;
+using DAL;
+using MLL;
+using System;
+using System.Drawing;
+using System.IO;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class BoletoCadastroPanel : FormularioModelo
+ {
+ // ── MODELO ────────────────────────────────────────────────────────────
+ private ModeloBoletos _modelo = new ModeloBoletos();
+
+ // ── SEÇÃO 1: Identificação ────────────────────────────────────────────
+ private LV_TEXTBOX1 txtCodigo = null!;
+ private LV_TEXTBOX1 txtNumero = null!;
+ private LV_TEXTBOX1 txtNossoNumero = null!;
+ private LV_TEXTBOX1 txtChaveBoleto = null!;
+ private LV_TEXTBOX1 txtLinhaDigitavel = null!;
+
+ // ── SEÇÃO 2: Datas e Valores ──────────────────────────────────────────
+ private DateTimePicker dtpEmitido = null!;
+ private DateTimePicker dtpVence = null!;
+ private DateTimePicker dtpPagamento = null!;
+ private LV_TEXTBOX1 txtValor = null!;
+ private LV_TEXTBOX1 txtVlPago = null!;
+ private LV_TEXTBOX1 txtVlMulta = null!;
+ private LV_TEXTBOX1 txtVlDesconto = null!;
+
+ // ── SEÇÃO 3: Sacado e Conta ───────────────────────────────────────────
+ private LV_TEXTBOX1 txtSacado = null!;
+ private LV_COMBOBOX cmbConta = null!;
+ private LV_COMBOBOX cmbCodConta = null!;
+
+ // ── SEÇÃO 4: Status e Flags ───────────────────────────────────────────
+ private LV_COMBOBOX cmbStatus = null!;
+ private CheckBox chkPago = null!;
+ private CheckBox chkAceite = null!;
+ private CheckBox chkImpresso = null!;
+ private CheckBox chkImportado = null!;
+
+ // ── SEÇÃO 5: Arquivo ──────────────────────────────────────────────────
+ private LV_TEXTBOX1 txtArquivoNome = null!;
+ private LV_TEXTBOX1 txtArquivoCaminho = null!;
+ private LV_COMBOBOX cmbArquivoTipo = null!;
+ private Button btnAnexar = null!;
+ private Button btnVisualizarArq = null!;
+ private Label lblArquivoInfo = null!;
+
+ // ── SEÇÃO 6: Observação ───────────────────────────────────────────────
+ private LV_TEXTBOX1 txtObservacao = null!;
+
+ // ── BOTÃO EXTRA DA TOOLBAR ────────────────────────────────────────────
+ private Button btnBaixar = null!;
+
+ // ── CONSTRUTOR ────────────────────────────────────────────────────────
+ public BoletoCadastroPanel()
+ {
+ Titulo = "Cadastro de Boletos";
+ BuildToolbarExtra();
+ BuildForm();
+ SetEstadoInicial();
+ }
+
+ // ── TOOLBAR EXTRA ─────────────────────────────────────────────────────
+ private void BuildToolbarExtra()
+ {
+ btnBaixar = CreateToolbarButton("Baixar", Color.FromArgb(99, 102, 241));
+ btnBaixar.Click += (s, e) => OnBaixarBoleto();
+ AddToolbarButton(btnBaixar);
+ }
+
+ // ── CONSTRUÇÃO DO FORMULÁRIO ──────────────────────────────────────────
+ private void BuildForm()
+ {
+ content.Height = 1050;
+
+ // ── SEÇÃO 1: Identificação ─────────────────────────────────────
+ content.Controls.Add(CreateSectionHeader("Identificação", 20));
+
+ txtCodigo = AddInput(content, "Código", 20, 55, 120, 32, readOnly: true);
+ txtNumero = AddInput(content, "Número do Boleto", 155, 55, 200, 32);
+ txtNossoNumero = AddInput(content, "Nosso Número", 370, 55, 200, 32);
+ txtChaveBoleto = AddInput(content, "Chave do Boleto", 585, 55, 235, 32);
+ txtLinhaDigitavel = AddInput(content, "Linha Digitável / Código de Barras", 20, 110, 800, 32);
+
+ // ── SEÇÃO 2: Datas e Valores ───────────────────────────────────
+ content.Controls.Add(CreateSectionHeader("Datas e Valores", 165));
+
+ dtpEmitido = BuildDatePicker("Data de Emissão", 20, 200);
+ dtpVence = BuildDatePicker("Data de Vencimento", 210, 200);
+ dtpPagamento = BuildDatePicker("Data de Pagamento", 400, 200);
+ dtpPagamento.Enabled = false;
+
+ txtValor = AddInput(content, "Valor (R$)", 600, 200, 140, 32);
+ txtVlPago = AddInput(content, "Valor Pago (R$)", 20, 260, 140, 32);
+ txtVlMulta = AddInput(content, "Multa (R$)", 175, 260, 140, 32);
+ txtVlDesconto = AddInput(content, "Desconto (R$)", 330, 260, 140, 32);
+
+ var lblVFLabel = new Label
+ {
+ Text = "Valor Final (R$)",
+ Location = new Point(490, 260),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = AccentBlue,
+ AutoSize = true
+ };
+ var lblVFValor = new Label
+ {
+ Name = "lblValorFinal",
+ Text = "R$ 0,00",
+ Location = new Point(490, 276),
+ Font = new Font("Segoe UI", 10f, FontStyle.Bold),
+ ForeColor = AccentBlue,
+ AutoSize = true
+ };
+ content.Controls.AddRange(new Control[] { lblVFLabel, lblVFValor });
+
+ txtValor.Leave += (s, e) => AtualizarValorFinal();
+ txtVlMulta.Leave += (s, e) => AtualizarValorFinal();
+ txtVlDesconto.Leave += (s, e) => AtualizarValorFinal();
+
+ // ── SEÇÃO 3: Sacado e Conta ────────────────────────────────────
+ content.Controls.Add(CreateSectionHeader("Sacado e Conta", 315));
+
+ txtSacado = AddInput(content, "Sacado", 20, 350, 430, 32);
+
+ content.Controls.Add(new Label
+ {
+ Text = "Conta",
+ Location = new Point(465, 350),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = TextDark,
+ AutoSize = true
+ });
+ cmbConta = new LV_COMBOBOX
+ {
+ Location = new Point(465, 366),
+ Size = new Size(200, 32),
+ Font = new Font("Segoe UI", 9f),
+ DropDownStyle = ComboBoxStyle.DropDownList,
+ BackColor = Color.White,
+ };
+
+ content.Controls.Add(new Label
+ {
+ Text = "Cód. Conta",
+ Location = new Point(680, 350),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = TextDark,
+ AutoSize = true
+ });
+ cmbCodConta = new LV_COMBOBOX
+ {
+ Location = new Point(680, 366),
+ Size = new Size(150, 32),
+ Font = new Font("Segoe UI", 9f),
+ DropDownStyle = ComboBoxStyle.DropDownList,
+ BackColor = Color.White,
+ };
+ content.Controls.AddRange(new Control[] { cmbConta, cmbCodConta });
+
+ // ── SEÇÃO 4: Status e Flags ────────────────────────────────────
+ content.Controls.Add(CreateSectionHeader("Status e Flags", 415));
+
+ content.Controls.Add(new Label
+ {
+ Text = "Status",
+ Location = new Point(20, 450),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = TextDark,
+ AutoSize = true
+ });
+ cmbStatus = new LV_COMBOBOX
+ {
+ Location = new Point(20, 466),
+ Size = new Size(160, 32),
+ Font = new Font("Segoe UI", 9f),
+ DropDownStyle = ComboBoxStyle.DropDownList,
+ BackColor = Color.White,
+ };
+ cmbStatus.Items.AddRange(new object[] { "ABERTO", "PAGO", "VENCIDO", "CANCELADO", "BAIXADO" });
+ cmbStatus.SelectedIndex = 0;
+ cmbStatus.SelectedIndexChanged += (s, e) => OnStatusChanged();
+ content.Controls.Add(cmbStatus);
+
+ chkPago = CreateCheckBox("Pago", 200, 470);
+ chkAceite = CreateCheckBox("Aceite", 300, 470);
+ chkImpresso = CreateCheckBox("Impresso", 400, 470);
+ chkImportado = CreateCheckBox("Importado", 510, 470);
+
+ chkPago.CheckedChanged += (s, e) =>
+ {
+ dtpPagamento.Enabled = chkPago.Checked;
+ if (chkPago.Checked && cmbStatus.SelectedItem?.ToString() != "PAGO")
+ cmbStatus.SelectedItem = "PAGO";
+ };
+
+ content.Controls.AddRange(new Control[]
+ { chkPago, chkAceite, chkImpresso, chkImportado });
+
+ // ── SEÇÃO 5: Arquivo ───────────────────────────────────────────
+ content.Controls.Add(CreateSectionHeader("Arquivo Anexo (XML / PDF)", 510));
+
+ content.Controls.Add(new Label
+ {
+ Text = "Tipo",
+ Location = new Point(20, 545),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = TextDark,
+ AutoSize = true
+ });
+ cmbArquivoTipo = new LV_COMBOBOX
+ {
+ Location = new Point(20, 561),
+ Size = new Size(80, 32),
+ Font = new Font("Segoe UI", 9f),
+ DropDownStyle = ComboBoxStyle.DropDownList,
+ BackColor = Color.White,
+ };
+ cmbArquivoTipo.Items.AddRange(new object[] { "", "XML", "PDF" });
+ cmbArquivoTipo.SelectedIndex = 0;
+ content.Controls.Add(cmbArquivoTipo);
+
+ txtArquivoNome = AddInput(content, "Nome do Arquivo", 115, 545, 220, 32, readOnly: true);
+ txtArquivoCaminho = AddInput(content, "Caminho em Disco", 350, 545, 340, 32, readOnly: true);
+
+ btnAnexar = new Button
+ {
+ Text = "📎 Anexar",
+ Location = new Point(705, 561),
+ Size = new Size(95, 32),
+ BackColor = Color.FromArgb(100, 116, 139),
+ ForeColor = Color.White,
+ Font = new Font("Segoe UI Semibold", 8.5f),
+ Cursor = Cursors.Hand,
+ };
+ btnAnexar.FlatAppearance.BorderSize = 0;
+ btnAnexar.Click += (s, e) => OnAnexarArquivo();
+
+ btnVisualizarArq = new Button
+ {
+ Text = "👁 Abrir",
+ Location = new Point(705, 599),
+ Size = new Size(95, 28),
+ BackColor = AccentBlue,
+ ForeColor = Color.White,
+ Font = new Font("Segoe UI Semibold", 8f),
+ Cursor = Cursors.Hand,
+ Enabled = false
+ };
+ btnVisualizarArq.FlatAppearance.BorderSize = 0;
+ btnVisualizarArq.Click += (s, e) => OnAbrirArquivo();
+
+ lblArquivoInfo = new Label
+ {
+ Text = "Nenhum arquivo anexado.",
+ Location = new Point(20, 603),
+ Font = new Font("Segoe UI", 8f, FontStyle.Italic),
+ ForeColor = Color.Gray,
+ AutoSize = true
+ };
+
+ content.Controls.AddRange(new Control[]
+ { btnAnexar, btnVisualizarArq, lblArquivoInfo });
+
+ // ── SEÇÃO 6: Observação ────────────────────────────────────────
+ content.Controls.Add(CreateSectionHeader("Observação", 640));
+
+ content.Controls.Add(new Label
+ {
+ Text = "Observação",
+ Location = new Point(20, 675),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = TextDark,
+ AutoSize = true
+ });
+ txtObservacao = new LV_TEXTBOX1
+ {
+ Location = new Point(20, 691),
+ Size = new Size(830, 80),
+ BorderColor = BorderColor,
+ BorderFocusColor = AccentBlue,
+ Multiline = true
+ };
+ content.Controls.Add(txtObservacao);
+ }
+
+ // ── HELPER: DateTimePicker padronizado ────────────────────────────────
+ private DateTimePicker BuildDatePicker(string label, int x, int y)
+ {
+ content.Controls.Add(new Label
+ {
+ Text = label,
+ Location = new Point(x, y),
+ Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
+ ForeColor = TextDark,
+ AutoSize = true
+ });
+
+ var dtp = new DateTimePicker
+ {
+ Location = new Point(x, y + 16),
+ Size = new Size(175, 32),
+ Format = DateTimePickerFormat.Short,
+ Font = new Font("Segoe UI", 9f)
+ };
+
+ content.Controls.Add(dtp);
+ return dtp;
+ }
+
+ // ── VALOR FINAL ───────────────────────────────────────────────────────
+ private void AtualizarValorFinal()
+ {
+ decimal valor = ParseDecimal(txtValor.Text);
+ decimal multa = ParseDecimal(txtVlMulta.Text);
+ decimal desconto = ParseDecimal(txtVlDesconto.Text);
+ decimal final = valor + multa - desconto;
+
+ var lbl = content.Controls["lblValorFinal"] as Label;
+ if (lbl != null)
+ {
+ lbl.Text = final.ToString("C2");
+ lbl.ForeColor = final < 0 ? Color.FromArgb(239, 68, 68) : AccentBlue;
+ }
+ }
+
+ private static decimal ParseDecimal(string text)
+ {
+ text = text.Replace("R$", "").Replace(".", "").Replace(",", ".").Trim();
+ return decimal.TryParse(text,
+ System.Globalization.NumberStyles.Any,
+ System.Globalization.CultureInfo.InvariantCulture,
+ out var v) ? v : 0m;
+ }
+
+ // ── STATUS CHANGED ────────────────────────────────────────────────────
+ private void OnStatusChanged()
+ {
+ var status = cmbStatus.SelectedItem?.ToString();
+ if (status == "PAGO" && !chkPago.Checked)
+ chkPago.Checked = true;
+ dtpPagamento.Enabled = status == "PAGO";
+ }
+
+ // ── ARQUIVO ───────────────────────────────────────────────────────────
+ private void OnAnexarArquivo()
+ {
+ using var dlg = new OpenFileDialog
+ {
+ Title = "Selecionar Arquivo do Boleto",
+ Filter = "Arquivos Suportados (*.xml;*.pdf)|*.xml;*.pdf|XML|*.xml|PDF|*.pdf"
+ };
+
+ if (dlg.ShowDialog() != DialogResult.OK) return;
+
+ var caminho = dlg.FileName;
+ var nome = Path.GetFileName(caminho);
+ var ext = Path.GetExtension(caminho).TrimStart('.').ToUpper();
+
+ txtArquivoNome.Text = nome;
+ txtArquivoCaminho.Text = caminho;
+ cmbArquivoTipo.Text = ext;
+ _modelo.ARQUIVO_DADOS = File.ReadAllBytes(caminho);
+
+ lblArquivoInfo.Text = $"✔ {nome} ({new FileInfo(caminho).Length / 1024} KB)";
+ lblArquivoInfo.ForeColor = Color.FromArgb(34, 197, 94);
+ btnVisualizarArq.Enabled = true;
+ }
+
+ private void OnAbrirArquivo()
+ {
+ var caminho = txtArquivoCaminho.Text;
+
+ if (!string.IsNullOrEmpty(caminho) && File.Exists(caminho))
+ {
+ System.Diagnostics.Process.Start(
+ new System.Diagnostics.ProcessStartInfo { FileName = caminho, UseShellExecute = true });
+ return;
+ }
+
+ // Sem caminho em disco — reconstrói do binário para temp
+ if (_modelo.ARQUIVO_DADOS != null && _modelo.ARQUIVO_DADOS.Length > 0)
+ {
+ var ext = string.IsNullOrEmpty(cmbArquivoTipo.Text) ? "tmp" : cmbArquivoTipo.Text.ToLower();
+ var temp = Path.Combine(Path.GetTempPath(), $"boleto_{_modelo.ID_BOLETO}.{ext}");
+ File.WriteAllBytes(temp, _modelo.ARQUIVO_DADOS);
+ System.Diagnostics.Process.Start(
+ new System.Diagnostics.ProcessStartInfo { FileName = temp, UseShellExecute = true });
+ }
+ else
+ {
+ MessageBox.Show("Nenhum arquivo disponível para visualização.",
+ "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ }
+ }
+
+ // ── BAIXAR BOLETO ─────────────────────────────────────────────────────
+ private void OnBaixarBoleto()
+ {
+ var chave = txtChaveBoleto.Text.Trim();
+ var linha = txtLinhaDigitavel.Text.Trim();
+ var numero = txtNumero.Text.Trim();
+
+ if (string.IsNullOrEmpty(chave) && string.IsNullOrEmpty(linha) && string.IsNullOrEmpty(numero))
+ {
+ MessageBox.Show(
+ "Informe a Chave do Boleto, a Linha Digitável ou o Número para realizar a baixa.",
+ "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ return;
+ }
+
+ // TODO: implementar integração bancária
+ // Fluxo sugerido:
+ // 1. BLLBoletos.BaixarBoleto(chave / linha / numero, _cx)
+ // 2. BLL aciona API do banco escolhido
+ // 3. Retorna status: BAIXADO | PAGO | ERRO
+ // 4. Atualiza _modelo e recarrega tela
+ MessageBox.Show(
+ $"Baixa bancária ainda não implementada.\n\n" +
+ $"Dados disponíveis:\n" +
+ $"• Chave: {chave}\n" +
+ $"• Linha Digitável: {linha}\n" +
+ $"• Número: {numero}",
+ "Baixar Boleto", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ // ── MÁQUINA DE ESTADOS ────────────────────────────────────────────────
+ private void SetEstadoInicial()
+ {
+ SetCamposEnabled(false);
+ btnSalvar.Enabled = false;
+ btnCancelar.Enabled = false;
+ btnAlterar.Enabled = false;
+ btnExcluir.Enabled = false;
+ btnBaixar.Enabled = false;
+ }
+
+ private void SetCamposEnabled(bool enabled)
+ {
+ txtNumero.ReadOnly = !enabled;
+ txtNossoNumero.ReadOnly = !enabled;
+ txtChaveBoleto.ReadOnly = !enabled;
+ txtLinhaDigitavel.ReadOnly = !enabled;
+ txtValor.ReadOnly = !enabled;
+ txtVlPago.ReadOnly = !enabled;
+ txtVlMulta.ReadOnly = !enabled;
+ txtVlDesconto.ReadOnly = !enabled;
+ txtSacado.ReadOnly = !enabled;
+ txtObservacao.ReadOnly = !enabled;
+ dtpEmitido.Enabled = enabled;
+ dtpVence.Enabled = enabled;
+ dtpPagamento.Enabled = enabled && chkPago.Checked;
+ cmbConta.Enabled = enabled;
+ cmbCodConta.Enabled = enabled;
+ cmbStatus.Enabled = enabled;
+ cmbArquivoTipo.Enabled = enabled;
+ chkPago.Enabled = enabled;
+ chkAceite.Enabled = enabled;
+ chkImpresso.Enabled = enabled;
+ chkImportado.Enabled = enabled;
+ btnAnexar.Enabled = enabled;
+ }
+
+ private void SetEstadoEdicao()
+ {
+ SetCamposEnabled(true);
+ btnSalvar.Enabled = true;
+ btnCancelar.Enabled = true;
+ btnNovo.Enabled = false;
+ btnAlterar.Enabled = false;
+ btnExcluir.Enabled = false;
+ btnLocalizar.Enabled = false;
+ btnBaixar.Enabled = false;
+ }
+
+ private void SetEstadoConsulta()
+ {
+ SetCamposEnabled(false);
+ btnSalvar.Enabled = false;
+ btnCancelar.Enabled = false;
+ btnNovo.Enabled = true;
+ btnAlterar.Enabled = true;
+ btnExcluir.Enabled = true;
+ btnLocalizar.Enabled = true;
+ btnBaixar.Enabled = _modelo.ID_BOLETO > 0;
+ }
+
+ // ── CARGA / LIMPEZA / COLETA ──────────────────────────────────────────
+ private void CarregarModelo()
+ {
+ txtCodigo.Text = _modelo.ID_BOLETO == 0 ? "" : _modelo.ID_BOLETO.ToString();
+ txtNumero.Text = _modelo.NUMERO;
+ txtNossoNumero.Text = _modelo.NOSSO_NUMERO;
+ txtChaveBoleto.Text = _modelo.CHAVE_BOLETO;
+ txtLinhaDigitavel.Text = _modelo.LINHA_DIGITAVEL;
+ txtSacado.Text = _modelo.SACADO;
+ txtValor.Text = _modelo.VALOR.ToString("N2");
+ txtVlPago.Text = _modelo.VL_PAGO?.ToString("N2") ?? "";
+ txtVlMulta.Text = _modelo.VL_MULTA?.ToString("N2") ?? "";
+ txtVlDesconto.Text = _modelo.VL_DESCONTO?.ToString("N2") ?? "";
+ txtObservacao.Text = _modelo.OBSERVACAO;
+
+ dtpEmitido.Value = _modelo.EMITIDO ?? DateTime.Today;
+ dtpVence.Value = _modelo.VENCE ?? DateTime.Today;
+ dtpPagamento.Value = _modelo.DT_PAGAMENTO ?? DateTime.Today;
+
+ cmbStatus.SelectedItem = _modelo.STATUS ?? "ABERTO";
+
+ chkPago.Checked = _modelo.PG;
+ chkAceite.Checked = _modelo.ACEITE;
+ chkImpresso.Checked = _modelo.IMPRESSO;
+ chkImportado.Checked = _modelo.IMPORTACAO;
+
+ if (!string.IsNullOrEmpty(_modelo.CONTA)) cmbConta.Text = _modelo.CONTA;
+ if (!string.IsNullOrEmpty(_modelo.COD_CONTA)) cmbCodConta.Text = _modelo.COD_CONTA;
+
+ txtArquivoNome.Text = _modelo.ARQUIVO_NOME;
+ txtArquivoCaminho.Text = _modelo.ARQUIVO_CAMINHO;
+ cmbArquivoTipo.Text = _modelo.ARQUIVO_TIPO;
+
+ bool temArquivo = _modelo.TemArquivo;
+ btnVisualizarArq.Enabled = temArquivo;
+ lblArquivoInfo.Text = temArquivo ? $"✔ {_modelo.ARQUIVO_NOME}" : "Nenhum arquivo anexado.";
+ lblArquivoInfo.ForeColor = temArquivo ? Color.FromArgb(34, 197, 94) : Color.Gray;
+
+ AtualizarValorFinal();
+ }
+
+ private void LimparCampos()
+ {
+ _modelo = new ModeloBoletos();
+
+ txtCodigo.Text = "";
+ txtNumero.Text = "";
+ txtNossoNumero.Text = "";
+ txtChaveBoleto.Text = "";
+ txtLinhaDigitavel.Text = "";
+ txtSacado.Text = "";
+ txtValor.Text = "";
+ txtVlPago.Text = "";
+ txtVlMulta.Text = "";
+ txtVlDesconto.Text = "";
+ txtObservacao.Text = "";
+ txtArquivoNome.Text = "";
+ txtArquivoCaminho.Text = "";
+
+ dtpEmitido.Value = DateTime.Today;
+ dtpVence.Value = DateTime.Today;
+ dtpPagamento.Value = DateTime.Today;
+
+ cmbStatus.SelectedIndex = 0;
+ cmbConta.SelectedIndex = -1;
+ cmbCodConta.SelectedIndex = -1;
+ cmbArquivoTipo.SelectedIndex = 0;
+
+ chkPago.Checked = false;
+ chkAceite.Checked = false;
+ chkImpresso.Checked = false;
+ chkImportado.Checked = false;
+
+ btnVisualizarArq.Enabled = false;
+ lblArquivoInfo.Text = "Nenhum arquivo anexado.";
+ lblArquivoInfo.ForeColor = Color.Gray;
+
+ AtualizarValorFinal();
+ }
+
+ private ModeloBoletos ColetarModelo() => new ModeloBoletos
+ {
+ ID_BOLETO = _modelo.ID_BOLETO,
+ NUMERO = txtNumero.Text.Trim(),
+ NOSSO_NUMERO = txtNossoNumero.Text.Trim(),
+ CHAVE_BOLETO = txtChaveBoleto.Text.Trim(),
+ LINHA_DIGITAVEL = txtLinhaDigitavel.Text.Trim(),
+ EMITIDO = dtpEmitido.Value.Date,
+ VENCE = dtpVence.Value.Date,
+ DT_PAGAMENTO = chkPago.Checked ? dtpPagamento.Value.Date : (DateTime?)null,
+ VALOR = ParseDecimal(txtValor.Text),
+ VL_PAGO = string.IsNullOrWhiteSpace(txtVlPago.Text) ? null : ParseDecimal(txtVlPago.Text),
+ VL_MULTA = string.IsNullOrWhiteSpace(txtVlMulta.Text) ? null : ParseDecimal(txtVlMulta.Text),
+ VL_DESCONTO = string.IsNullOrWhiteSpace(txtVlDesconto.Text) ? null : ParseDecimal(txtVlDesconto.Text),
+ STATUS = cmbStatus.SelectedItem?.ToString() ?? "ABERTO",
+ PG = chkPago.Checked,
+ ACEITE = chkAceite.Checked,
+ IMPRESSO = chkImpresso.Checked,
+ IMPORTACAO = chkImportado.Checked,
+ SACADO = txtSacado.Text.Trim(),
+ CONTA = cmbConta.Text,
+ COD_CONTA = cmbCodConta.Text,
+ ARQUIVO_NOME = txtArquivoNome.Text.Trim(),
+ ARQUIVO_TIPO = cmbArquivoTipo.Text,
+ ARQUIVO_CAMINHO = txtArquivoCaminho.Text.Trim(),
+ ARQUIVO_DADOS = _modelo.ARQUIVO_DADOS,
+ OBSERVACAO = txtObservacao.Text.Trim(),
+ DT_CADASTRO = _modelo.DT_CADASTRO == default ? DateTime.Now : _modelo.DT_CADASTRO,
+ DT_ALTERACAO = _modelo.ID_BOLETO > 0 ? DateTime.Now : (DateTime?)null,
+ ID_USUARIO = _modelo.ID_USUARIO
+ };
+
+ // ── EVENTOS ABSTRATOS ─────────────────────────────────────────────────
+ protected override void OnNovo()
+ {
+ LimparCampos();
+ SetEstadoEdicao();
+ txtNumero.Focus();
+ }
+
+ protected override void OnAlterar()
+ {
+ if (_modelo.ID_BOLETO == 0)
+ {
+ MessageBox.Show("Localize um boleto antes de alterar.",
+ "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ return;
+ }
+ SetEstadoEdicao();
+ txtNumero.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (_modelo.ID_BOLETO == 0)
+ {
+ MessageBox.Show("Localize um boleto antes de excluir.",
+ "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ return;
+ }
+
+ var confirm = MessageBox.Show(
+ $"Deseja excluir o boleto Nº {_modelo.NUMERO}?",
+ "Confirmar Exclusão", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
+
+ if (confirm == DialogResult.Yes)
+ {
+ // TODO: DALBoletos.Excluir(_modelo.ID_BOLETO, _cx);
+ LimparCampos();
+ SetEstadoInicial();
+ MessageBox.Show("Boleto excluído com sucesso.",
+ "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // TODO: abrir form de pesquisa
+ // var frm = new FormLocalizarBoleto();
+ // if (frm.ShowDialog() == DialogResult.OK)
+ // {
+ // _modelo = frm.ModeloSelecionado;
+ // CarregarModelo();
+ // SetEstadoConsulta();
+ // }
+ }
+
+ protected override void OnSalvar()
+ {
+ if (!Validar()) return;
+
+ var modelo = ColetarModelo();
+
+ try
+ {
+ if (modelo.ID_BOLETO == 0)
+ {
+ // TODO: DALBoletos.Inserir(modelo, _cx);
+ MessageBox.Show("Boleto cadastrado com sucesso.",
+ "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ else
+ {
+ // TODO: DALBoletos.Atualizar(modelo, _cx);
+ MessageBox.Show("Boleto atualizado com sucesso.",
+ "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ _modelo = modelo;
+ SetEstadoConsulta();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Erro ao salvar boleto:\n{ex.Message}",
+ "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ protected override void OnCancelar()
+ {
+ if (_modelo.ID_BOLETO == 0)
+ LimparCampos();
+ else
+ CarregarModelo();
+
+ SetEstadoConsulta();
+ }
+
+ // ── VALIDAÇÃO ─────────────────────────────────────────────────────────
+ private bool Validar()
+ {
+ if (string.IsNullOrWhiteSpace(txtNumero.Text))
+ {
+ MessageBox.Show("Informe o número do boleto.",
+ "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNumero.Focus(); return false;
+ }
+
+ if (ParseDecimal(txtValor.Text) <= 0)
+ {
+ MessageBox.Show("Informe um valor válido para o boleto.",
+ "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtValor.Focus(); return false;
+ }
+
+ if (dtpVence.Value.Date < dtpEmitido.Value.Date)
+ {
+ MessageBox.Show("A data de vencimento não pode ser anterior à data de emissão.",
+ "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ dtpVence.Focus(); return false;
+ }
+
+ if (string.IsNullOrWhiteSpace(txtSacado.Text))
+ {
+ MessageBox.Show("Informe o sacado.",
+ "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtSacado.Focus(); return false;
+ }
+
+ if (cmbConta.SelectedIndex < 0)
+ {
+ MessageBox.Show("Selecione a conta.",
+ "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ cmbConta.Focus(); return false;
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/BoletoCadastroPanel.resx b/UI/Dashboards/Cadastros/BoletoCadastroPanel.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/UI/Dashboards/Cadastros/BoletoCadastroPanel.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/ContratosCadastroPanel.cs b/UI/Dashboards/Cadastros/ContratosCadastroPanel.cs
new file mode 100644
index 0000000..083bb3c
--- /dev/null
+++ b/UI/Dashboards/Cadastros/ContratosCadastroPanel.cs
@@ -0,0 +1,176 @@
+using CPM;
+using MLL; // Namespace da sua model
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using UI; // Namespace do seu FormularioModelo
+
+namespace UI
+{
+ public partial class ContratosCadastroPanel : FormularioModelo
+ {
+ private ModeloContrato _contrato = new ModeloContrato();
+
+ // Controles específicos
+ private LV_TEXTBOX1 txtId, txtEmpresaId, txtClienteId, txtDescricao;
+ private LV_TEXTBOX1 txtValor, txtDataInicio, txtDataValidade, txtFranquia;
+ private LV_TEXTBOX1 txtObservacoes;
+ private CheckBox chkAtivo;
+ private LV_TEXTBOX1 txtNomeCliente; // Novo campo para o nome
+ private Button btnBuscaCliente; // Botão da lupa
+ public ContratosCadastroPanel()
+ {
+ this.Titulo = "Gestão de Contratos";
+ MontarInterface();
+ }
+
+ //private void MontarInterface()
+ //{
+ // // --- SEÇÃO 1: Vínculos e Descrição ---
+ // content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO CONTRATO", 20));
+
+ // txtId = AddInput(content, "ID", 20, 50, 80, 30, true);
+ // txtEmpresaId = AddInput(content, "ID EMPRESA", 110, 50, 100, 30);
+ // txtClienteId = AddInput(content, "ID CLIENTE", 220, 50, 100, 30);
+ // txtDescricao = AddInput(content, "DESCRIÇÃO DO CONTRATO", 330, 50, 550, 30);
+
+ // // --- SEÇÃO 2: Valores e Prazos ---
+ // content.Controls.Add(CreateSectionHeader("FINANCEIRO E VIGÊNCIA", 110));
+
+ // txtValor = AddInput(content, "VALOR MENSAL (R$)", 20, 140, 150, 30);
+ // txtDataInicio = AddInput(content, "DATA INÍCIO", 180, 140, 150, 30);
+ // txtDataValidade = AddInput(content, "VALIDADE/TÉRMINO", 340, 140, 150, 30);
+ // txtFranquia = AddInput(content, "FRANQUIA (HORAS/MIN)", 500, 140, 180, 30);
+
+ // chkAtivo = CreateCheckBox("CONTRATO ATIVO", 700, 158);
+ // content.Controls.Add(chkAtivo);
+
+ // // --- SEÇÃO 3: Observações ---
+ // content.Controls.Add(CreateSectionHeader("DETALHES E OBSERVAÇÕES", 200));
+
+ // txtObservacoes = AddInput(content, "OBSERVAÇÕES INTERNAS", 20, 230, 860, 80);
+
+ // // Ajuste para o campo de observações ser maior (se o seu LV_TEXTBOX1 permitir)
+ // txtObservacoes.Height = 80;
+ //}
+ private void MontarInterface()
+ {
+ // --- SEÇÃO 1: Identificação e Vínculos ---
+ content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO CONTRATO", 20));
+
+ // Linha 1: IDs e Busca
+ txtId = AddInput(content, "ID CONTRATO", 20, 50, 90, 30, true);
+ txtClienteId = AddInput(content, "ID CLIENTE", 120, 50, 80, 30);
+
+ // Botão Lupa
+ btnBuscaCliente = new Button
+ {
+ Text = "🔍",
+ Location = new Point(205, 66), // Alinhado ao topo do textbox (50 + 16)
+ Size = new Size(32, 30),
+ BackColor = AccentBlue,
+ ForeColor = Color.White,
+ FlatStyle = FlatStyle.Flat,
+ Cursor = Cursors.Hand
+ };
+ btnBuscaCliente.FlatAppearance.BorderSize = 0;
+ btnBuscaCliente.Click += (s, e) => OnLocalizarCliente();
+ content.Controls.Add(btnBuscaCliente);
+
+ txtNomeCliente = AddInput(content, "NOME DO CLIENTE / RAZÃO SOCIAL", 247, 50, 410, 30, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 667, 50, 80, 30);
+
+ // Linha 2: Descrição (abaixo dos IDs)
+ txtDescricao = AddInput(content, "DESCRIÇÃO DO CONTRATO", 20, 105, 727, 30);
+
+ // --- SEÇÃO 2: Valores e Prazos ---
+ // Aumentei o Y para 170 para dar espaço à descrição acima
+ content.Controls.Add(CreateSectionHeader("FINANCEIRO E VIGÊNCIA", 175));
+
+ txtValor = AddInput(content, "VALOR MENSAL (R$)", 20, 205, 150, 30);
+ txtDataInicio = AddInput(content, "DATA INÍCIO", 185, 205, 150, 30);
+ txtDataValidade = AddInput(content, "VALIDADE/TÉRMINO", 350, 205, 150, 30);
+ txtFranquia = AddInput(content, "FRANQUIA (HORAS/MIN)", 515, 205, 170, 30);
+
+ // Checkbox Alinhado com os inputs
+ chkAtivo = CreateCheckBox("CONTRATO ATIVO", 700, 223); // Y do input (205) + ~18px
+ content.Controls.Add(chkAtivo);
+
+ // --- SEÇÃO 3: Detalhes e Notas ---
+ content.Controls.Add(CreateSectionHeader("DETALHES E OBSERVAÇÕES", 275));
+
+ txtObservacoes = AddInput(content, "OBSERVAÇÕES INTERNAS", 20, 305, 860, 100);
+
+ // Forçar a altura maior para o campo de observações
+ txtObservacoes.Height = 100;
+ // Se o seu LV_TEXTBOX1 tiver a propriedade Multiline, ative-a aqui:
+ // txtObservacoes.Multiline = true;
+ }
+
+ // Método que você precisará implementar para a busca
+ private void OnLocalizarCliente()
+ {
+ //Logica para abrir o form de busca e retornar os dados
+ //Exemplo:
+ // var busca = new FormBuscaCliente();
+ //if (busca.ShowDialog() == DialogResult.OK)
+ //{
+ // txtClienteId.Text = busca.IdSelecionado;
+ // txtNomeCliente.Text = busca.NomeSelecionado;
+ //}
+ }
+
+ private void PreencherModel()
+ {
+ _contrato.Descricao = txtDescricao.Text;
+ _contrato.Observacoes = txtObservacoes.Text;
+ _contrato.Ativo = chkAtivo.Checked;
+
+ // Conversões seguras
+ if (decimal.TryParse(txtValor.Text, out decimal v)) _contrato.Valor = v;
+ if (int.TryParse(txtEmpresaId.Text, out int emp)) _contrato.EmpresaId = emp;
+ if (int.TryParse(txtClienteId.Text, out int cli)) _contrato.ClienteId = cli;
+ if (int.TryParse(txtFranquia.Text, out int fra)) _contrato.FranquiaTempo = fra;
+
+ if (DateTime.TryParse(txtDataInicio.Text, out DateTime dtIn)) _contrato.DataInicio = dtIn;
+ if (DateTime.TryParse(txtDataValidade.Text, out DateTime dtVal)) _contrato.DataValidade = dtVal;
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DA BASE ---
+
+ protected override void OnNovo()
+ {
+ _contrato = new ModeloContrato();
+ // Limpar campos...
+ txtDescricao.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ try
+ {
+ PreencherModel();
+ // Chamar BLL.Salvar(_contrato);
+ MessageBox.Show("Contrato processado com sucesso!", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Erro ao salvar contrato: " + ex.Message);
+ }
+ }
+
+ protected override void OnAlterar() { /* Implementar busca/edição */ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja rescindir/excluir este contrato?", "Confirmação", MessageBoxButtons.YesNo) == DialogResult.Yes)
+ {
+ // Lógica de exclusão
+ }
+ }
+
+ protected override void OnLocalizar() { /* Abrir grid de contratos */ }
+
+ protected override void OnCancelar() { OnNovo(); }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/EquipamentosCadastroPanel.cs b/UI/Dashboards/Cadastros/EquipamentosCadastroPanel.cs
new file mode 100644
index 0000000..a76dd0c
--- /dev/null
+++ b/UI/Dashboards/Cadastros/EquipamentosCadastroPanel.cs
@@ -0,0 +1,123 @@
+using CPM;
+using MLL; // Namespace da sua model
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using UI; // Namespace do seu FormularioModelo
+
+namespace UI
+{
+ public partial class EquipamentosCadastroPanel : FormularioModelo
+ {
+ // Instância da model para controle de dados
+ private ModeloEquipamentos _equipamento = new ModeloEquipamentos();
+
+ // Controles do formulário
+ private LV_TEXTBOX1 txtId, txtCodigo, txtDescricao, txtMarca, txtModelo;
+ private LV_TEXTBOX1 txtSerie, txtPatrimonio, txtDataCompra, txtRevenda;
+ private LV_TEXTBOX1 txtNF, txtCertificado, txtObservacoes;
+
+ public EquipamentosCadastroPanel()
+ {
+ this.Titulo = "Cadastro de Equipamentos";
+ MontarInterface();
+ LimparTela();
+ }
+
+ private void MontarInterface()
+ {
+ // --- SEÇÃO 1: Identificação ---
+ content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO E DESCRIÇÃO", 20));
+
+ txtId = AddInput(content, "ID", 20, 50, 80, 30, true); // Somente leitura
+ txtCodigo = AddInput(content, "CÓDIGO INTERNO", 110, 50, 150, 30);
+ txtDescricao = AddInput(content, "DESCRIÇÃO DO EQUIPAMENTO", 270, 50, 450, 30);
+
+ // --- SEÇÃO 2: Detalhes Técnicos ---
+ content.Controls.Add(CreateSectionHeader("ESPECIFICAÇÕES TÉCNICAS", 110));
+
+ txtMarca = AddInput(content, "MARCA", 20, 140, 240, 30);
+ txtModelo = AddInput(content, "MODELO", 270, 140, 240, 30);
+ txtSerie = AddInput(content, "Nº DE SÉRIE", 520, 140, 200, 30);
+ txtPatrimonio = AddInput(content, "PATRIMÔNIO (PAT)", 730, 140, 150, 30);
+
+ // --- SEÇÃO 3: Compra e Garantia ---
+ content.Controls.Add(CreateSectionHeader("DADOS DE AQUISIÇÃO E GARANTIA", 200));
+
+ txtDataCompra = AddInput(content, "DATA DA COMPRA", 20, 230, 150, 30);
+ txtRevenda = AddInput(content, "REVENDA / FORNECEDOR", 180, 230, 330, 30);
+ txtNF = AddInput(content, "NOTA FISCAL", 520, 230, 150, 30);
+ txtCertificado = AddInput(content, "Nº CERT. GARANTIA", 680, 230, 200, 30);
+
+ // --- SEÇÃO 4: Observações ---
+ content.Controls.Add(CreateSectionHeader("OBSERVAÇÕES ADICIONAIS", 290));
+
+ txtObservacoes = AddInput(content, "NOTAS GERAIS", 20, 320, 860, 60);
+ // Se o seu LV_TEXTBOX1 suportar Multiline, você pode ajustar aqui
+ }
+
+ private void LimparTela()
+ {
+ _equipamento = new ModeloEquipamentos();
+ // Lógica para limpar todos os campos txtId.Text = "", etc.
+ // Dica: Você pode criar um método auxiliar na base para limpar o 'content'
+ }
+
+ // --- IMPLEMENTAÇÃO DOS MÉTODOS DA BASE ---
+
+ protected override void OnNovo()
+ {
+ LimparTela();
+ txtCodigo.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ try
+ {
+ // Mapeia a tela para a model
+ _equipamento.CODIGO = txtCodigo.Text;
+ _equipamento.DESCRICAO = txtDescricao.Text;
+ _equipamento.MARCA = txtMarca.Text;
+ _equipamento.MODELO = txtModelo.Text;
+ _equipamento.SERIE = txtSerie.Text;
+ _equipamento.PAT = txtPatrimonio.Text;
+ _equipamento.DATA_COMPRA = txtDataCompra.Text;
+ _equipamento.REVENDA = txtRevenda.Text;
+ _equipamento.NUM_NF = txtNF.Text;
+ _equipamento.NUM_CERTGAR = txtCertificado.Text;
+ _equipamento.OBSERVACOES = txtObservacoes.Text;
+
+ // Aqui você chamaria sua BLL ou DAL passando o _equipamento
+ MessageBox.Show("Equipamento salvo com sucesso!", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Erro ao salvar: " + ex.Message);
+ }
+ }
+
+ protected override void OnAlterar()
+ {
+ // Lógica para habilitar campos ou mudar estado
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja excluir este equipamento?", "Confirmar", MessageBoxButtons.YesNo) == DialogResult.Yes)
+ {
+ // Lógica de exclusão
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aqui você abriria um formulário de busca
+ }
+
+ protected override void OnCancelar()
+ {
+ LimparTela();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/FornecedoresCadastroPanel.cs b/UI/Dashboards/Cadastros/FornecedoresCadastroPanel.cs
new file mode 100644
index 0000000..3fae31a
--- /dev/null
+++ b/UI/Dashboards/Cadastros/FornecedoresCadastroPanel.cs
@@ -0,0 +1,133 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using UI;
+
+namespace UI
+{
+ public partial class FornecedoresCadastroPanel : FormularioModelo
+ {
+ private ModeloFornecedores _fornecedor = new ModeloFornecedores();
+
+ // Controles - Identificação
+ private LV_TEXTBOX1 txtId, txtEmpresaId, txtNome, txtNomeFantasia, txtDocumento, txtIE, txtTipoPessoa;
+
+ // Controles - Localização
+ private LV_TEXTBOX1 txtCep, txtEndereco, txtNumero, txtBairro, txtCidade, txtUF, txtComplemento;
+
+ // Controles - Contato e Extras
+ private LV_TEXTBOX1 txtTelefone, txtCelular, txtWhatsapp, txtEmail, txtSite, txtObservacoes;
+ private CheckBox chkAtivo;
+
+ public FornecedoresCadastroPanel()
+ {
+ this.Titulo = "Cadastro de Fornecedores";
+ MontarInterface();
+ }
+
+ private void MontarInterface()
+ {
+ // --- SEÇÃO 1: Identificação ---
+ content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO FORNECEDOR", 20));
+
+ txtId = AddInput(content, "ID", 20, 50, 70, 30, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 100, 50, 80, 30);
+ txtTipoPessoa = AddInput(content, "TIPO (PF/PJ)", 190, 50, 100, 30);
+ txtDocumento = AddInput(content, "CPF / CNPJ", 300, 50, 180, 30);
+ txtIE = AddInput(content, "INSC. ESTADUAL", 490, 50, 180, 30);
+
+ txtNome = AddInput(content, "RAZÃO SOCIAL / NOME", 20, 105, 430, 30);
+ txtNomeFantasia = AddInput(content, "NOME FANTASIA", 460, 105, 420, 30);
+
+ // --- SEÇÃO 2: Localização ---
+ content.Controls.Add(CreateSectionHeader("ENDEREÇO E LOCALIZAÇÃO", 175));
+
+ txtCep = AddInput(content, "CEP", 20, 205, 100, 30);
+ txtEndereco = AddInput(content, "LOGRADOURO", 130, 205, 350, 30);
+ txtNumero = AddInput(content, "Nº", 490, 205, 70, 30);
+ txtBairro = AddInput(content, "BAIRRO", 570, 205, 190, 30);
+ txtUF = AddInput(content, "UF", 770, 205, 50, 30);
+
+ txtCidade = AddInput(content, "CIDADE", 20, 260, 300, 30);
+ txtComplemento = AddInput(content, "COMPLEMENTO", 330, 260, 550, 30);
+
+ // --- SEÇÃO 3: Contato e Comunicação ---
+ content.Controls.Add(CreateSectionHeader("CONTATOS E DIGITAL", 330));
+
+ txtTelefone = AddInput(content, "TELEFONE", 20, 360, 150, 30);
+ txtCelular = AddInput(content, "CELULAR", 180, 360, 150, 30);
+ txtWhatsapp = AddInput(content, "WHATSAPP", 340, 360, 150, 30);
+ txtEmail = AddInput(content, "E-MAIL", 500, 360, 380, 30);
+
+ txtSite = AddInput(content, "WEBSITE / PORTAL", 20, 415, 430, 30);
+
+ chkAtivo = CreateCheckBox("FORNECEDOR ATIVO", 460, 433);
+ content.Controls.Add(chkAtivo);
+
+ // --- SEÇÃO 4: Observações ---
+ content.Controls.Add(CreateSectionHeader("OBSERVAÇÕES GERAIS", 485));
+ txtObservacoes = AddInput(content, "NOTAS INTERNAS", 20, 515, 860, 100);
+ txtObservacoes.Height = 100;
+
+ // Ajuste automático da área de scroll para o conteúdo caber
+ content.Height = 650;
+ }
+
+ private void PreencherModel()
+ {
+ _fornecedor.Nome = txtNome.Text;
+ _fornecedor.NomeFantasia = txtNomeFantasia.Text;
+ _fornecedor.TipoPessoa = txtTipoPessoa.Text;
+ _fornecedor.Documento = txtDocumento.Text;
+ _fornecedor.InscricaoEstadual = txtIE.Text;
+
+ _fornecedor.Cep = txtCep.Text;
+ _fornecedor.Endereco = txtEndereco.Text;
+ _fornecedor.Bairro = txtBairro.Text;
+ _fornecedor.Cidade = txtCidade.Text;
+ _fornecedor.UF = txtUF.Text;
+ _fornecedor.Complemento = txtComplemento.Text;
+
+ if (int.TryParse(txtNumero.Text, out int n)) _fornecedor.Numero = n;
+ if (int.TryParse(txtEmpresaId.Text, out int emp)) _fornecedor.EmpresaId = emp;
+
+ _fornecedor.Telefone = txtTelefone.Text;
+ _fornecedor.Celular = txtCelular.Text;
+ _fornecedor.Whatsapp = txtWhatsapp.Text;
+ _fornecedor.Email = txtEmail.Text;
+ _fornecedor.Site = txtSite.Text;
+ _fornecedor.Observacoes = txtObservacoes.Text;
+ _fornecedor.Ativo = chkAtivo.Checked;
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS ---
+
+ protected override void OnNovo()
+ {
+ _fornecedor = new ModeloFornecedores();
+ // Implementar lógica de limpar campos se necessário
+ txtNome.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ try
+ {
+ PreencherModel();
+ // BLLFornecedor.Salvar(_fornecedor);
+ MessageBox.Show("Fornecedor salvo com sucesso!", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Erro ao salvar: " + ex.Message);
+ }
+ }
+
+ protected override void OnAlterar() { }
+ protected override void OnExcluir() { }
+ protected override void OnLocalizar() { }
+ protected override void OnCancelar() { OnNovo(); }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/ServicosCadastroPanel.cs b/UI/Dashboards/Cadastros/ServicosCadastroPanel.cs
new file mode 100644
index 0000000..d346bb9
--- /dev/null
+++ b/UI/Dashboards/Cadastros/ServicosCadastroPanel.cs
@@ -0,0 +1,104 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using UI;
+
+namespace UI
+{
+ public partial class ServicosCadastroPanel : FormularioModelo
+ {
+ private ModeloServicos _servico = new ModeloServicos();
+
+ // Controles - Identificação
+ private LV_TEXTBOX1 txtId, txtEmpresaId, txtNome, txtDescricao;
+
+ // Controles - Financeiro e Comissão
+ private LV_TEXTBOX1 txtValorVenda, txtCusto, txtTipoComissao, txtValorComissao;
+
+ // Controles - Operacional
+ private LV_TEXTBOX1 txtTempoEstimado;
+ private CheckBox chkAtivo;
+
+ public ServicosCadastroPanel()
+ {
+ this.Titulo = "Cadastro de Serviços";
+ MontarInterface();
+ }
+
+ private void MontarInterface()
+ {
+ // --- SEÇÃO 1: Definição do Serviço ---
+ content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO SERVIÇO", 20));
+
+ txtId = AddInput(content, "ID", 20, 50, 70, 30, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 100, 50, 80, 30);
+ txtNome = AddInput(content, "NOME DO SERVIÇO", 190, 50, 690, 30);
+
+ txtDescricao = AddInput(content, "DESCRIÇÃO DETALHADA / ESCOPO", 20, 105, 860, 50);
+ txtDescricao.Multiline = true;
+
+ // --- SEÇÃO 2: Financeiro e Precificação ---
+ content.Controls.Add(CreateSectionHeader("VALORES E CUSTOS", 175));
+
+ txtValorVenda = AddInput(content, "VALOR DE VENDA (R$)", 20, 205, 180, 30);
+ txtCusto = AddInput(content, "CUSTO ESTIMADO (R$)", 210, 205, 180, 30);
+
+ // --- SEÇÃO 3: Regras de Comissão e Tempo ---
+ content.Controls.Add(CreateSectionHeader("COMISSIONAMENTO E OPERAÇÃO", 270));
+
+ txtTipoComissao = AddInput(content, "TIPO COMISSÃO (FIXO/%)", 20, 300, 180, 30);
+ txtValorComissao = AddInput(content, "VALOR DA COMISSÃO", 210, 300, 180, 30);
+
+ txtTempoEstimado = AddInput(content, "TEMPO ESTIMADO (MIN)", 400, 300, 180, 30);
+
+ chkAtivo = CreateCheckBox("SERVIÇO ATIVO PARA VENDA", 600, 318);
+ content.Controls.Add(chkAtivo);
+
+ // Ajuste da altura do conteúdo (Serviços costumam ser telas mais curtas)
+ content.Height = 450;
+ }
+
+ private void PreencherModel()
+ {
+ _servico.Nome = txtNome.Text;
+ _servico.Descricao = txtDescricao.Text;
+ _servico.TipoComissao = txtTipoComissao.Text;
+ _servico.Ativo = chkAtivo.Checked;
+
+ // Conversões Numéricas
+ if (int.TryParse(txtEmpresaId.Text, out int emp)) _servico.EmpresaId = emp;
+ if (int.TryParse(txtTempoEstimado.Text, out int tempo)) _servico.TempoEstimado = tempo;
+
+ if (decimal.TryParse(txtValorVenda.Text, out decimal valor)) _servico.ValorPadrao = valor;
+ if (decimal.TryParse(txtCusto.Text, out decimal custo)) _servico.Custo = custo;
+ if (decimal.TryParse(txtValorComissao.Text, out decimal comissao)) _servico.ValorComissao = comissao;
+ }
+
+ protected override void OnNovo()
+ {
+ _servico = new ModeloServicos();
+ txtNome.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ try
+ {
+ PreencherModel();
+ // BLLServicos.Salvar(_servico);
+ MessageBox.Show("Serviço cadastrado com sucesso!", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Erro ao salvar serviço: " + ex.Message);
+ }
+ }
+
+ protected override void OnAlterar() { }
+ protected override void OnExcluir() { }
+ protected override void OnLocalizar() { }
+ protected override void OnCancelar() { OnNovo(); }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/ServicosCadastroPanel.resx b/UI/Dashboards/Cadastros/ServicosCadastroPanel.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/UI/Dashboards/Cadastros/ServicosCadastroPanel.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/TransportadorasCadastroPanel.cs b/UI/Dashboards/Cadastros/TransportadorasCadastroPanel.cs
new file mode 100644
index 0000000..7946b95
--- /dev/null
+++ b/UI/Dashboards/Cadastros/TransportadorasCadastroPanel.cs
@@ -0,0 +1,126 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using UI;
+
+namespace UI
+{
+ public partial class TransportadorasCadastroPanel : FormularioModelo
+ {
+ private ModeloTransportadoras _transportadora = new ModeloTransportadoras();
+
+ // Controles - Identificação
+ private LV_TEXTBOX1 txtId, txtEmpresaId, txtRazaoSocial, txtNomeFantasia, txtCNPJ;
+
+ // Controles - Localização
+ private LV_TEXTBOX1 txtCep, txtEndereco, txtNumero, txtBairro, txtCidade, txtUF, txtComplemento;
+
+ // Controles - Logística e Contato
+ private LV_TEXTBOX1 txtTelefone, txtEmail, txtTipoFrete, txtPrazo, txtValorFrete, txtObservacoes;
+ private CheckBox chkAtivo;
+
+ public TransportadorasCadastroPanel()
+ {
+ this.Titulo = "Cadastro de Transportadoras";
+ MontarInterface();
+ }
+
+ private void MontarInterface()
+ {
+ // --- SEÇÃO 1: Identificação ---
+ content.Controls.Add(CreateSectionHeader("DADOS DA TRANSPORTADORA", 20));
+
+ txtId = AddInput(content, "ID", 20, 50, 70, 30, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 100, 50, 80, 30);
+ txtCNPJ = AddInput(content, "CNPJ", 190, 50, 200, 30);
+
+ txtRazaoSocial = AddInput(content, "RAZÃO SOCIAL", 20, 105, 430, 30);
+ txtNomeFantasia = AddInput(content, "NOME FANTASIA", 460, 105, 420, 30);
+
+ // --- SEÇÃO 2: Localização ---
+ content.Controls.Add(CreateSectionHeader("ENDEREÇO SEDE", 175));
+
+ txtCep = AddInput(content, "CEP", 20, 205, 100, 30);
+ txtEndereco = AddInput(content, "LOGRADOURO", 130, 205, 350, 30);
+ txtNumero = AddInput(content, "Nº", 490, 205, 70, 30);
+ txtBairro = AddInput(content, "BAIRRO", 570, 205, 190, 30);
+ txtUF = AddInput(content, "UF", 770, 205, 50, 30);
+
+ txtCidade = AddInput(content, "CIDADE", 20, 260, 300, 30);
+ txtComplemento = AddInput(content, "COMPLEMENTO", 330, 260, 550, 30);
+
+ // --- SEÇÃO 3: Regras de Logística e Contato ---
+ content.Controls.Add(CreateSectionHeader("CONFIGURAÇÕES DE FRETE E CONTATO", 330));
+
+ txtTipoFrete = AddInput(content, "TIPO DE FRETE (CIF/FOB)", 20, 360, 180, 30);
+ txtPrazo = AddInput(content, "PRAZO MÉDIO (DIAS)", 210, 360, 150, 30);
+ txtValorFrete = AddInput(content, "VALOR PADRÃO (R$)", 370, 360, 150, 30);
+
+ chkAtivo = CreateCheckBox("TRANSPORTADORA ATIVA", 540, 378);
+ content.Controls.Add(chkAtivo);
+
+ txtTelefone = AddInput(content, "TELEFONE", 20, 415, 180, 30);
+ txtEmail = AddInput(content, "E-MAIL PARA COTAÇÃO", 210, 415, 670, 30);
+
+ // --- SEÇÃO 4: Observações ---
+ content.Controls.Add(CreateSectionHeader("OBSERVAÇÕES ADICIONAIS", 485));
+ txtObservacoes = AddInput(content, "NOTAS DE LOGÍSTICA", 20, 515, 860, 80);
+ txtObservacoes.Height = 80;
+
+ content.Height = 630;
+ }
+
+ private void PreencherModel()
+ {
+ _transportadora.RazaoSocial = txtRazaoSocial.Text;
+ _transportadora.NomeFantasia = txtNomeFantasia.Text;
+ _transportadora.CNPJ = txtCNPJ.Text;
+
+ _transportadora.Cep = txtCep.Text;
+ _transportadora.Endereco = txtEndereco.Text;
+ _transportadora.Bairro = txtBairro.Text;
+ _transportadora.Cidade = txtCidade.Text;
+ _transportadora.UF = txtUF.Text;
+ _transportadora.Complemento = txtComplemento.Text;
+
+ // Conversões numéricas
+ if (int.TryParse(txtNumero.Text, out int num)) _transportadora.Numero = num;
+ if (int.TryParse(txtEmpresaId.Text, out int emp)) _transportadora.EmpresaId = emp;
+ if (int.TryParse(txtPrazo.Text, out int prazo)) _transportadora.PrazoEntrega = prazo;
+ if (decimal.TryParse(txtValorFrete.Text, out decimal valor)) _transportadora.ValorFretePadrao = valor;
+
+ _transportadora.TipoFrete = txtTipoFrete.Text;
+ _transportadora.Telefone = txtTelefone.Text;
+ _transportadora.Email = txtEmail.Text;
+ _transportadora.Observacoes = txtObservacoes.Text;
+ _transportadora.Ativo = chkAtivo.Checked;
+ }
+
+ protected override void OnNovo()
+ {
+ _transportadora = new ModeloTransportadoras();
+ txtCNPJ.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ try
+ {
+ PreencherModel();
+ // BLLTransportadora.Salvar(_transportadora);
+ MessageBox.Show("Transportadora registrada com sucesso!", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show("Erro ao processar dados: " + ex.Message);
+ }
+ }
+
+ protected override void OnAlterar() { }
+ protected override void OnExcluir() { }
+ protected override void OnLocalizar() { }
+ protected override void OnCancelar() { OnNovo(); }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Dashmain/MainForm.cs b/UI/Dashboards/Dashmain/MainForm.cs
index 2f5d973..9dd8cc7 100644
--- a/UI/Dashboards/Dashmain/MainForm.cs
+++ b/UI/Dashboards/Dashmain/MainForm.cs
@@ -1,6 +1,7 @@
using CCH;
using CustomMessageBox;
using DAL;
+using LevelOS;
using System;
using System.Drawing;
using System.Windows.Forms;
@@ -18,6 +19,15 @@ namespace UI
private readonly AgendaCadastroPanel _pAgendaCadastro;
private readonly AgendaConsultaPanel _pAgendaConsulta;
private readonly FuncionariosCadastroPanel _pfuncionariosCadastro ;
+
+ private readonly EquipamentosCadastroPanel _pequipamentosCadastroPanel;
+ private readonly ContratosCadastroPanel _pcontratosCadastroPanel;
+ private readonly FornecedoresCadastroPanel _pfornecedoresCadastroPanel;
+ private readonly TransportadorasCadastroPanel _ptransportadorasCadastroPanel;
+ private readonly ServicosCadastroPanel _pservicosCadastroPanel;
+
+ //Painel financeiro
+ private readonly BoletoCadastroPanel _pboletoCadastroPanel;
private readonly Panel _pOrdens;
private readonly Panel _pProdutos;
private readonly Panel _pEstoque;
@@ -41,6 +51,12 @@ namespace UI
_pAgendaCadastro = new AgendaCadastroPanel { Dock = DockStyle.Fill, Visible = false };
_pAgendaConsulta = new AgendaConsultaPanel { Dock = DockStyle.Fill, Visible = false };
_pfuncionariosCadastro = new FuncionariosCadastroPanel { Dock = DockStyle.Fill, Visible = false };
+ _pboletoCadastroPanel = new BoletoCadastroPanel { Dock = DockStyle.Fill, Visible = false };
+ _pequipamentosCadastroPanel = new EquipamentosCadastroPanel { Dock = DockStyle.Fill, Visible = false };
+ _pcontratosCadastroPanel = new ContratosCadastroPanel { Dock = DockStyle.Fill, Visible = false };
+ _pfornecedoresCadastroPanel = new FornecedoresCadastroPanel { Dock = DockStyle.Fill, Visible = false };
+ _ptransportadorasCadastroPanel = new TransportadorasCadastroPanel { Dock = DockStyle.Fill, Visible = false };
+ _pservicosCadastroPanel = new ServicosCadastroPanel { Dock = DockStyle.Fill, Visible = false };
_pOrdens = PlaceholderPanel("Ordens de Serviço", Color.FromArgb(22, 163, 74));
_pProdutos = PlaceholderPanel("Catálogo de Produtos", Color.FromArgb(217, 119, 6));
_pEstoque = PlaceholderPanel("Controle de Estoque", Color.FromArgb(234, 88, 12));
@@ -50,6 +66,12 @@ namespace UI
mainContainer.Controls.Add(_pFinanceiro);
mainContainer.Controls.Add(_pAgendaCadastro);
mainContainer.Controls.Add(_pAgendaConsulta);
+ mainContainer.Controls.Add(_pboletoCadastroPanel);
+ mainContainer.Controls.Add(_pequipamentosCadastroPanel);
+ mainContainer.Controls.Add(_pcontratosCadastroPanel);
+ mainContainer.Controls.Add(_pfornecedoresCadastroPanel);
+ mainContainer.Controls.Add(_ptransportadorasCadastroPanel);
+ mainContainer.Controls.Add(_pservicosCadastroPanel);
mainContainer.Controls.Add(_pEstoque);
mainContainer.Controls.Add(_pProdutos);
mainContainer.Controls.Add(_pOrdens);
@@ -85,7 +107,12 @@ namespace UI
case 5: ShowPanel(_pEstoque); break;
case 9: ShowPanel(_pFinanceiro); break;
case 99: ShowPanel(_pClientes); break;
+ case 100: ShowPanel(_pequipamentosCadastroPanel); break;
+ case 101: ShowPanel(_pcontratosCadastroPanel); break;
+ case 102: ShowPanel(_pfornecedoresCadastroPanel); break;
case 103: ShowPanel(_pfuncionariosCadastro); break;
+ case 104: ShowPanel(_ptransportadorasCadastroPanel); break;
+ case 105: ShowPanel(_pservicosCadastroPanel); break;
case 106: ShowPanel(_pEmpresa); break;
@@ -94,6 +121,10 @@ namespace UI
case 301: ShowPanel(_pAgendaConsulta); break;
+
+ case 500: ShowPanel(_pboletoCadastroPanel); break;
+
+
}
}
@@ -110,7 +141,12 @@ namespace UI
_pAgendaCadastro.Visible = (panelToShow == _pAgendaCadastro);
_pAgendaConsulta.Visible = (panelToShow == _pAgendaConsulta);
_pfuncionariosCadastro.Visible = (panelToShow == _pfuncionariosCadastro);
-
+ _pboletoCadastroPanel.Visible = (panelToShow == _pboletoCadastroPanel);
+ _pequipamentosCadastroPanel.Visible = (panelToShow == _pequipamentosCadastroPanel);
+ _pcontratosCadastroPanel.Visible = (panelToShow == _pcontratosCadastroPanel);
+ _pfornecedoresCadastroPanel.Visible = (panelToShow == _pfornecedoresCadastroPanel);
+ _ptransportadorasCadastroPanel.Visible = (panelToShow == _ptransportadorasCadastroPanel);
+ _pservicosCadastroPanel.Visible = (panelToShow == _pservicosCadastroPanel);
if (panelToShow.Visible)
{
panelToShow.BringToFront();
diff --git a/UI/Dashboards/Dashmain/SidebarControl.cs b/UI/Dashboards/Dashmain/SidebarControl.cs
index 6b5fbd8..9bc837a 100644
--- a/UI/Dashboards/Dashmain/SidebarControl.cs
+++ b/UI/Dashboards/Dashmain/SidebarControl.cs
@@ -156,6 +156,7 @@ namespace UI
_subMenuFinanceiro.Items.Add("💳 Contas", null, (s, e) => { /* Lógica */ });
_subMenuFinanceiro.Items.Add("📈 Contas a receber", null, (s, e) => { /* Lógica */ });
_subMenuFinanceiro.Items.Add("📉 Contas a pagar", null, (s, e) => { /* Lógica */ });
+ _subMenuFinanceiro.Items.Add("📉 Boletos/Duplicatas", null, (s, e) => { NavItemClicked?.Invoke(this, 500); });
_subMenuFinanceiro.Items.Add(new ToolStripSeparator()); // Linha divisória
_subMenuFinanceiro.Items.Add("🛒 Compras", null, (s, e) => { /* Lógica */ });
_subMenuFinanceiro.Items.Add("💰 Vendas", null, (s, e) => { /* Lógica */ });
diff --git a/UI/ModeloPanel/Formulariomodelo.cs b/UI/ModeloPanel/Formulariomodelo.cs
index 7a1d784..43e5bb9 100644
--- a/UI/ModeloPanel/Formulariomodelo.cs
+++ b/UI/ModeloPanel/Formulariomodelo.cs
@@ -4,7 +4,7 @@ using System;
using System.Drawing;
using System.Windows.Forms;
-namespace LevelOS
+namespace UI
{
///
/// Modelo base para todos os formulários do sistema.
diff --git a/UI/ModeloPanel/Formulariomodelo.resx b/UI/ModeloPanel/Formulariomodelo.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/UI/ModeloPanel/Formulariomodelo.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file