diff --git a/UI/ArquivosAuxiliares/Ferramentas/ScreenProfile.cs b/UI/ArquivosAuxiliares/Ferramentas/ScreenProfile.cs
new file mode 100644
index 0000000..e7bcb7f
--- /dev/null
+++ b/UI/ArquivosAuxiliares/Ferramentas/ScreenProfile.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ ///
+ /// Detecta automaticamente o perfil de tela (Monitor ou Notebook)
+ /// combinando resolução e DPI, e fornece fatores de escala para
+ /// dimensões e fontes de forma centralizada.
+ ///
+ /// Base de referência do layout: 1920x1080 a 96 DPI = Scale 1.0
+ /// O layout base foi desenhado compacto (sem escalação excessiva),
+ /// então Monitor FHD usa 1.0 e os demais perfis sobem/descem a partir daí.
+ ///
+ public static class ScreenProfile
+ {
+ // ─────────────────────────────────────────────
+ // Enum de perfil
+ // ─────────────────────────────────────────────
+
+ public enum ProfileType
+ {
+ NotebookHD, // ≤ 1366 x 768
+ NotebookHDPlus, // 1600 x 900
+ MonitorFHD, // 1920 x 1080 ← referência (Scale = 1.0)
+ MonitorQHD, // 2560 x 1440
+ MonitorUHD // 3840 x 2160 (4K)
+ }
+
+ // ─────────────────────────────────────────────
+ // Propriedades públicas
+ // ─────────────────────────────────────────────
+
+ /// Perfil detectado.
+ public static ProfileType Profile { get; private set; }
+
+ /// Fator de escala para dimensões e posições.
+ public static float Scale { get; private set; }
+
+ /// Fator de escala específico para fontes.
+ public static float FontScale { get; private set; }
+
+ /// DPI real da tela primária.
+ public static float Dpi { get; private set; }
+
+ /// Resolução da tela primária.
+ public static Size Resolution { get; private set; }
+
+ // ─────────────────────────────────────────────
+ // Inicialização estática
+ // ─────────────────────────────────────────────
+
+ static ScreenProfile() => Detect();
+
+ private static void Detect()
+ {
+ // 1. Resolução física
+ var screen = Screen.PrimaryScreen!;
+ int w = screen.Bounds.Width;
+ int h = screen.Bounds.Height;
+ Resolution = new Size(w, h);
+
+ // 2. DPI real (96 = 100%, 120 = 125%, 144 = 150%, 192 = 200%)
+ using var g = Graphics.FromHwnd(IntPtr.Zero);
+ Dpi = g.DpiX;
+
+ // 3. Correção: evita dupla escala quando Windows Scaling está ativo
+ float dpiCorrection = Dpi > 96f ? (96f / Dpi) : 1f;
+
+ // 4. Escala base por resolução
+ // Referência: Monitor FHD = 1.0 (layout desenhado para 1920x1080)
+ if (w >= 3840)
+ {
+ Profile = ProfileType.MonitorUHD;
+ Scale = 1.40f;
+ FontScale = 1.30f;
+ }
+ else if (w >= 2560)
+ {
+ Profile = ProfileType.MonitorQHD;
+ Scale = 1.20f;
+ FontScale = 1.15f;
+ }
+ else if (w >= 1920)
+ {
+ Profile = ProfileType.MonitorFHD;
+ Scale = 1.00f; // ← referência
+ FontScale = 1.00f;
+ }
+ else if (w >= 1600)
+ {
+ Profile = ProfileType.NotebookHDPlus;
+ Scale = 0.85f;
+ FontScale = 0.88f;
+ }
+ else
+ {
+ Profile = ProfileType.NotebookHD;
+ Scale = 0.72f;
+ FontScale = 0.76f;
+ }
+
+ // 5. Aplica correção de DPI
+ Scale *= dpiCorrection;
+ FontScale *= dpiCorrection;
+
+ // 6. Limita range seguro
+ Scale = Math.Clamp(Scale, 0.65f, 1.50f);
+ FontScale = Math.Clamp(FontScale, 0.70f, 1.40f);
+ }
+
+ // ─────────────────────────────────────────────
+ // Helpers de escala
+ // ─────────────────────────────────────────────
+
+ /// Escala um valor inteiro (dimensão ou posição).
+ public static int S(int value) => (int)Math.Round(value * Scale);
+
+ /// Escala um ponto.
+ public static Point P(int x, int y) => new(S(x), S(y));
+
+ /// Escala um tamanho.
+ public static Size Sz(int w, int h) => new(S(w), S(h));
+
+ /// Escala um retângulo.
+ public static Rectangle R(int x, int y, int w, int h)
+ => new(S(x), S(y), S(w), S(h));
+
+ /// Escala um tamanho de fonte.
+ public static float F(float pt) => (float)Math.Round(pt * FontScale, 1);
+
+ // ─────────────────────────────────────────────
+ // Diagnóstico
+ // ─────────────────────────────────────────────
+
+ public static string Diagnostico()
+ => $"Perfil: {Profile} | {Resolution.Width}x{Resolution.Height} | " +
+ $"DPI: {Dpi:F0} | Scale: {Scale:F2} | FontScale: {FontScale:F2}";
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/OSServicosPanel.cs b/UI/Dashboards/Cadastros/OSServicosPanel.cs
new file mode 100644
index 0000000..55f3ed6
--- /dev/null
+++ b/UI/Dashboards/Cadastros/OSServicosPanel.cs
@@ -0,0 +1,178 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class OSServicosPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todos os campos do ModeloOSServicos
+ private LV_TEXTBOX1 txtIdServico;
+ private LV_TEXTBOX1 txtCodigo;
+ private LV_TEXTBOX1 txtDescricao;
+ private LV_TEXTBOX1 txtTotal;
+ private LV_TEXTBOX1 txtInicio;
+ private LV_TEXTBOX1 txtFim;
+ private LV_TEXTBOX1 txtTecnico;
+ private LV_TEXTBOX1 txtTipo;
+ private LV_TEXTBOX1 txtOsNum;
+ private LV_TEXTBOX1 txtCodServ;
+ private LV_TEXTBOX1 txtQtd;
+ private LV_TEXTBOX1 txtVFrete;
+ private LV_TEXTBOX1 txtVSeguro;
+ private LV_TEXTBOX1 txtVOutros;
+ private LV_TEXTBOX1 txtNumNfPed;
+ private LV_TEXTBOX1 txtCusto;
+ private LV_TEXTBOX1 txtXPed;
+ private LV_TEXTBOX1 txtNItemPed;
+
+ public OSServicosPanel()
+ {
+ this.Titulo = "LANÇAMENTO DE SERVIÇOS E MÃO DE OBRA";
+ MontarInterfaceCompleta();
+ VincularEventosCalculo();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: VÍNCULO DA O.S. E IDENTIFICAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Identificação do Serviço", 20));
+
+ txtIdServico = AddInput(content, "ID REGISTRO", 20, 55, 100, 28, true);
+ txtOsNum = AddInput(content, "Nº DA O.S.", 130, 55, 120, 28, true);
+ txtCodServ = AddInput(content, "CÓD. SERVIÇO", 260, 55, 130, 28);
+ txtCodigo = AddInput(content, "CÓD. INTERNO", 400, 55, 130, 28);
+ txtTipo = AddInput(content, "TIPO SERVIÇO", 540, 55, 150, 28);
+
+ // --- SEÇÃO 2: DETALHES E APURAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Especificações e Execução", 115));
+
+ txtDescricao = AddInput(content, "DESCRIÇÃO DO SERVIÇO EXECUTADO", 20, 150, 650, 28);
+ txtTecnico = AddInput(content, "TÉCNICO RESPONSÁVEL", 680, 150, 300, 28);
+
+ txtInicio = AddInput(content, "DATA/HORA INÍCIO", 20, 210, 180, 28);
+ txtFim = AddInput(content, "DATA/HORA FIM", 210, 210, 180, 28);
+ txtQtd = AddInput(content, "QUANTIDADE", 400, 210, 100, 28);
+
+ // --- SEÇÃO 3: VALORES E FECHAMENTO ---
+ content.Controls.Add(CreateSectionHeader("Valores e Custos Comerciais", 275));
+
+ txtCusto = AddInput(content, "CUSTO UNITÁRIO (R$)", 20, 310, 150, 28);
+ txtVFrete = AddInput(content, "VALOR FRETE (R$)", 180, 310, 140, 28);
+ txtVSeguro = AddInput(content, "VALOR SEGURO (R$)", 330, 310, 140, 28);
+ txtVOutros = AddInput(content, "OUTRAS DESPESAS (R$)", 480, 310, 140, 28);
+ txtTotal = AddInput(content, "TOTAL GERAL (R$)", 630, 310, 180, 28, true); // Calculado automaticamente
+
+ // --- SEÇÃO 4: INTEGRAÇÃO FISCAL / FATURAMENTO ---
+ content.Controls.Add(CreateSectionHeader("Vínculos Fiscais e Pedidos (B2B)", 375));
+
+ txtNumNfPed = AddInput(content, "Nº NF / PEDIDO", 20, 410, 200, 28);
+ txtXPed = AddInput(content, "Nº PEDIDO COMPRA (XPED)", 230, 410, 220, 28);
+ txtNItemPed = AddInput(content, "ITEM DO PEDIDO (NITEMPED)", 460, 410, 180, 28);
+ }
+
+ private void VincularEventosCalculo()
+ {
+ // Dispara o cálculo automático sempre que alterar quantidade ou valores relevantes
+ txtQtd.TextChanged += (s, e) => CalcularTotalServico();
+ txtCusto.TextChanged += (s, e) => CalcularTotalServico();
+ txtVFrete.TextChanged += (s, e) => CalcularTotalServico();
+ txtVSeguro.TextChanged += (s, e) => CalcularTotalServico();
+ txtVOutros.TextChanged += (s, e) => CalcularTotalServico();
+ }
+
+ private void CalcularTotalServico()
+ {
+ decimal.TryParse(txtQtd.Text, out decimal qtd);
+ decimal.TryParse(txtCusto.Text, out decimal custoUnit);
+ decimal.TryParse(txtVFrete.Text, out decimal frete);
+ decimal.TryParse(txtVSeguro.Text, out decimal seguro);
+ decimal.TryParse(txtVOutros.Text, out decimal outros);
+
+ if (qtd == 0) qtd = 1; // Evita zerar se o usuário apagar o campo
+
+ // Regra básica de composição de preço do serviço
+ decimal totalGeral = (custoUnit * qtd) + frete + seguro + outros;
+
+ txtTotal.Text = totalGeral.ToString("N2");
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa todos os controles não-bloqueados contidos no painel content
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+ txtQtd.Text = "1";
+ txtCusto.Text = "0,00";
+ txtVFrete.Text = "0,00";
+ txtVSeguro.Text = "0,00";
+ txtVOutros.Text = "0,00";
+ txtTotal.Text = "0,00";
+
+ txtCodServ.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Mapeamento exato de todas as propriedades sem deixar nenhuma de fora
+ var servico = new ModeloOSServicos
+ {
+ ID_OS_SEVICOS = string.IsNullOrEmpty(txtIdServico.Text) ? 0 : Convert.ToInt32(txtIdServico.Text),
+ CODIGO = txtCodigo.Text,
+ DESCRICAO = txtDescricao.Text,
+ TOTAL = txtTotal.Text,
+ INICIO = txtInicio.Text,
+ FIM = txtFim.Text,
+ TECNICO = txtTecnico.Text,
+ TIPO = txtTipo.Text,
+ OS_NUM = txtOsNum.Text,
+ COD_SERV = txtCodServ.Text,
+ QTD = txtQtd.Text,
+ V_FRETE = txtVFrete.Text,
+ V_SEGURO = txtVSeguro.Text,
+ V_OUTROS = txtVOutros.Text,
+ NUM_NF_PED = txtNumNfPed.Text,
+ CUSTO = txtCusto.Text,
+ XPED = txtXPed.Text,
+ NITEMPED = txtNItemPed.Text
+ };
+
+ // Aqui sua lógica chamará a BLL/DAL passando o objeto 'servico'
+ MessageBox.Show("Lançamento de serviço salvo com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ // Lógica para destravar componentes ou carregar estado de edição
+ txtDescricao.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja realmente remover este serviço da O.S.?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Executar exclusão via BLL
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aqui você abre sua tela padrão de busca de serviços da OS
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/OrdensCadastroPanel.cs b/UI/Dashboards/Cadastros/OrdensCadastroPanel.cs
index ac43460..23d9c88 100644
--- a/UI/Dashboards/Cadastros/OrdensCadastroPanel.cs
+++ b/UI/Dashboards/Cadastros/OrdensCadastroPanel.cs
@@ -4,6 +4,9 @@ using System;
using System.Drawing;
using System.Windows.Forms;
+// Atalhos estáticos — eliminam o prefixo "ScreenProfile." em todo o arquivo
+using static UI.ScreenProfile;
+
namespace UI
{
public class OrdensCadastroPanel : FormularioModelo
@@ -24,9 +27,7 @@ namespace UI
private LV_TEXTBOX1 txtTelefones = null!;
private LV_TEXTBOX1 txtDocs = null!;
private LV_TEXTBOX1 txtEmail = null!;
-
private LV_TEXTBOX1 txtGarantia = null!;
-
private LV_TEXTBOX1 txtAdiantamento = null!;
private LV_TEXTBOX1 txtMaoObra = null!;
private LV_TEXTBOX1 txtPecas = null!;
@@ -44,18 +45,28 @@ namespace UI
private ComboBox cbTecnico = null!;
private ComboBox cbPrioridade = null!;
-
#endregion
+ // ══════════════════════════════════════════════════════════════
+ // Layout base: desenhado para 1920x1080 @ 96 DPI (Scale = 1.0)
+ // Tudo que está em pixels aqui é o valor ANTES da escala.
+ // Use sempre S(), P(), Sz(), R(), F() para aplicar o Scale.
+ // ══════════════════════════════════════════════════════════════
+
public OrdensCadastroPanel()
{
Titulo = "Ordem de Serviço";
- content.Width = 1200;
- content.Height = 960;
+ content.Width = S(1180);
+ content.Height = S(870);
content.BackColor = Color.FromArgb(245, 247, 250);
BuildInterface();
+
+#if DEBUG
+ if (ParentForm != null)
+ ParentForm.Text += $" [{ScreenProfile.Diagnostico()}]";
+#endif
}
#region Build
@@ -69,89 +80,121 @@ namespace UI
BuildTabs();
BuildRodape();
}
- private Panel CreateInternalCard(string title,Rectangle rect)
+
+ // Card interno (com borda simples, sem sombra)
+ private Panel CreateInternalCard(string title, Rectangle rect)
{
var pnl = new Panel
{
Location = rect.Location,
Size = rect.Size,
-
BackColor = Color.White,
-
BorderStyle = BorderStyle.FixedSingle
};
var lbl = new Label
{
Text = title,
-
- Font = new Font("Segoe UI", 9f, FontStyle.Bold),
-
+ Font = new Font("Segoe UI", F(8.5f), FontStyle.Bold),
ForeColor = AccentBlue,
-
- Location = new Point(10, 10),
-
+ Location = P(8, 6),
AutoSize = true
};
pnl.Controls.Add(lbl);
-
return pnl;
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // HEADER (y=10, h=60)
+ // ──────────────────────────────────────────────────────────────
#region Header
private void BuildHeader()
{
var header = new Panel
{
- Location = new Point(20, 20),
- Size = new Size(1130, 90),
+ Location = P(10, 10),
+ Size = Sz(1160, 60),
BackColor = Color.White
};
-
header.Paint += CardPaint;
lblNumeroOS = new Label
{
Text = "O.S. nº 1771",
- Font = new Font("Segoe UI", 25f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(20f), FontStyle.Bold),
ForeColor = Color.FromArgb(210, 38, 38),
- Location = new Point(15, 20),
+ Location = P(12, 8),
AutoSize = true
};
var lblSub = new Label
{
Text = "Cadastro e gerenciamento da ordem de serviço",
- Font = new Font("Segoe UI", 9f),
+ Font = new Font("Segoe UI", F(8f)),
ForeColor = Color.Gray,
- Location = new Point(24, 63),
+ Location = P(15, 42),
AutoSize = true
};
header.Controls.Add(lblNumeroOS);
header.Controls.Add(lblSub);
-
content.Controls.Add(header);
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // CLIENTE (y=80, h=160)
+ // ──────────────────────────────────────────────────────────────
#region Cliente
private void BuildCliente()
{
- cardCliente = CreateCard(new Rectangle(20, 130, 760, 220), "Dados do Cliente");
+ cardCliente = CreateCard(R(10, 80, 850, 170), "Dados do Cliente");
- txtCliente = AddModernInput(cardCliente, "Cliente", 20, 45, 700);
- txtEndereco = AddModernInput(cardCliente, "Endereço", 20, 95, 700);
+ // Calcula tudo em pixels JA ESCALADOS para evitar dupla escala
+ int m = S(12);
+ int iw = cardCliente.Width - m * 2;
+ int gap = S(8);
+ int col = (iw - gap * 2) / 3;
+ int h26 = S(26);
+ int h16 = S(16);
+ int y1 = S(35);
+ int y2 = S(80);
+ int y3 = S(125);
- txtTelefones = AddModernInput(cardCliente, "Telefones", 20, 145, 220);
- txtDocs = AddModernInput(cardCliente, "Documentos", 260, 145, 220);
- txtEmail = AddModernInput(cardCliente, "E-mail", 500, 145, 220);
+ // Helper local: coordenadas ja em pixels escalados
+ LV_TEXTBOX1 Inp(Control p, string lbl, int x, int y, int w)
+ {
+ p.Controls.Add(new Label
+ {
+ Text = lbl,
+ Font = new Font("Segoe UI", F(8f), FontStyle.Bold),
+ ForeColor = TextDark,
+ Location = new Point(x, y),
+ AutoSize = true
+ });
+ var tb = new LV_TEXTBOX1
+ {
+ Location = new Point(x, y + h16),
+ Size = new Size(w, h26),
+ BorderColor = BorderColor,
+ BorderFocusColor = AccentBlue,
+ BackColor = Color.White
+ };
+ p.Controls.Add(tb);
+ return tb;
+ }
+
+ txtCliente = Inp(cardCliente, "Cliente", m, y1, iw);
+ txtEndereco = Inp(cardCliente, "Endereço", m, y2, iw);
+ txtTelefones = Inp(cardCliente, "Telefones", m, y3, col);
+ txtDocs = Inp(cardCliente, "Documentos", m + col + gap, y3, col);
+ txtEmail = Inp(cardCliente, "E-mail", m + (col + gap) * 2, y3, iw - (col + gap) * 2);
content.Controls.Add(cardCliente);
txtCliente.Text = "Nicolas Felipe G. dos santos";
@@ -159,122 +202,102 @@ namespace UI
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // STATUS E DATAS (y=248, h=130)
+ // ──────────────────────────────────────────────────────────────
#region Datas
private void BuildDatasStatus()
{
- cardDatas = CreateCard(new Rectangle(20, 370, 760, 170), "Status e Datas");
+ cardDatas = CreateCard(R(10, 248, 850, 130), "Status e Datas");
- AddSmallLabel(cardDatas, "Entrada", 20, 45);
-
- dtpEntrada = CreatePicker(20, 65, 180);
+ // Linha 1
+ AddSmallLabel(cardDatas, "Entrada", 12, 35);
+ dtpEntrada = CreatePicker(12, 52, 175);
cardDatas.Controls.Add(dtpEntrada);
- AddSmallLabel(cardDatas, "Pronto", 20, 100);
-
- dtpPronto = CreatePicker(20, 120, 180);
- cardDatas.Controls.Add(dtpPronto);
-
- AddSmallLabel(cardDatas, "Saída", 220, 45);
-
- dtpSaida = CreatePicker(220, 65, 180);
+ AddSmallLabel(cardDatas, "Saída", 200, 35);
+ dtpSaida = CreatePicker(200, 52, 175);
cardDatas.Controls.Add(dtpSaida);
- cbSituacao = AddComboBox(cardDatas, "Situação da OS", 430, 45, 280);
+ cbSituacao = AddComboBox(cardDatas, "Situação da OS", 390, 35, 445);
- AddSmallLabel(cardDatas, "Garantia até", 220, 100);
- dtpGarantia = CreatePicker(220, 120, 180);
+ // Linha 2
+ AddSmallLabel(cardDatas, "Pronto", 12, 85);
+ dtpPronto = CreatePicker(12, 102, 175);
+ cardDatas.Controls.Add(dtpPronto);
+
+ AddSmallLabel(cardDatas, "Garantia até", 200, 85);
+ dtpGarantia = CreatePicker(200, 102, 175);
cardDatas.Controls.Add(dtpGarantia);
var btnHistorico = new Button
{
Text = "🕘 Histórico",
- Location = new Point(480, 120),
- Size = new Size(220, 36),
-
+ Location = P(390, 97),
+ Size = Sz(210, 28),
FlatStyle = FlatStyle.Flat,
BackColor = Color.White,
ForeColor = TextDark,
-
- Font = new Font("Segoe UI Semibold", 9f),
-
+ Font = new Font("Segoe UI Semibold", F(8.5f)),
Cursor = Cursors.Hand
};
-
btnHistorico.FlatAppearance.BorderColor = BorderColor;
- btnHistorico.FlatAppearance.MouseOverBackColor = Color.Blue;
-
- // Evento clique
+ btnHistorico.FlatAppearance.MouseOverBackColor = Color.FromArgb(235, 240, 255);
btnHistorico.Click += (s, e) =>
- {
- MessageBox.Show(
- "Abrir histórico da OS",
- "Histórico",
- MessageBoxButtons.OK,
- MessageBoxIcon.Information);
- };
+ MessageBox.Show("Abrir histórico da OS", "Histórico",
+ MessageBoxButtons.OK, MessageBoxIcon.Information);
- // Adiciona no painel
cardDatas.Controls.Add(btnHistorico);
-
- //txtGarantia = AddModernInput(cardDatas, "Garantia até", 250, 105, 180);
-
content.Controls.Add(cardDatas);
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // FINANCEIRO (x=870, y=80, w=300, h=298)
+ // — alinhado com Cliente + Datas somados
+ // ──────────────────────────────────────────────────────────────
#region Financeiro
private void BuildFinanceiro()
{
- cardFinanceiro = CreateCard(new Rectangle(800, 130, 350, 410), "Financeiro");
+ // altura = 160(cliente) + 8(gap) + 130(datas) = 298
+ cardFinanceiro = CreateCard(R(870, 80, 300, 298), "Financeiro");
- int y = 50;
+ int y = 35;
+ int step = 34; // espaço entre linhas — compacto
- txtAdiantamento = AddFinanceRow(cardFinanceiro, "Adiantamento", y);
- y += 42;
-
- txtMaoObra = AddFinanceRow(cardFinanceiro, "Mão-de-obra", y);
- y += 42;
-
- txtPecas = AddFinanceRow(cardFinanceiro, "Peças", y);
- y += 42;
-
- txtDeslocamento = AddFinanceRow(cardFinanceiro, "Deslocamento", y);
- y += 42;
-
- txtServicosTerceiros = AddFinanceRow(cardFinanceiro, "Serviços terceiros", y);
- y += 42;
-
- txtOutros = AddFinanceRow(cardFinanceiro, "Outros", y);
- y += 65;
+ txtAdiantamento = AddFinanceRow(cardFinanceiro, "Adiantamento", y); y += step;
+ txtMaoObra = AddFinanceRow(cardFinanceiro, "Mão-de-obra", y); y += step;
+ txtPecas = AddFinanceRow(cardFinanceiro, "Peças", y); y += step;
+ txtDeslocamento = AddFinanceRow(cardFinanceiro, "Deslocamento", y); y += step;
+ txtServicosTerceiros = AddFinanceRow(cardFinanceiro, "Serv. terceiros", y); y += step;
+ txtOutros = AddFinanceRow(cardFinanceiro, "Outros", y); y += step + 8;
var line = new Panel
{
BackColor = BorderColor,
- Location = new Point(20, y),
- Size = new Size(300, 1)
+ Location = P(10, y),
+ Size = Sz(278, 1)
};
-
cardFinanceiro.Controls.Add(line);
-
- y += 20;
+ y += 10;
var lblTotal = new Label
{
Text = "TOTAL",
- Font = new Font("Segoe UI", 12f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(10f), FontStyle.Bold),
ForeColor = Color.FromArgb(220, 38, 38),
- Location = new Point(20, y + 8),
+ Location = P(12, y + 6),
AutoSize = true
};
txtTotal = new LV_TEXTBOX1
{
- Location = new Point(140, y),
- Size = new Size(180, 38),
- Font = new Font("Segoe UI", 14f, FontStyle.Bold),
+ Location = P(110, y),
+ Size = Sz(168, 32),
+ Font = new Font("Segoe UI", F(12f), FontStyle.Bold),
TextAlign = HorizontalAlignment.Right,
BorderColor = Color.FromArgb(220, 38, 38),
BorderFocusColor = Color.FromArgb(220, 38, 38),
@@ -283,26 +306,27 @@ namespace UI
cardFinanceiro.Controls.Add(lblTotal);
cardFinanceiro.Controls.Add(txtTotal);
-
content.Controls.Add(cardFinanceiro);
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // TABS (y=386, h=420)
+ // ──────────────────────────────────────────────────────────────
#region Tabs
private void BuildTabs()
{
tabDetalhes = new TabControl
{
- Location = new Point(20, 560),
- Size = new Size(1130, 320),
- Font = new Font("Segoe UI", 9f),
+ Location = P(10, 386),
+ Size = Sz(1160, 430),
+ Font = new Font("Segoe UI", F(8.5f)),
DrawMode = TabDrawMode.OwnerDrawFixed,
SizeMode = TabSizeMode.Fixed,
- ItemSize = new Size(180, 35)
+ ItemSize = Sz(170, 30)
};
-
tabDetalhes.DrawItem += DrawTab;
BuildTabAparelho();
@@ -311,955 +335,384 @@ namespace UI
BuildTabLaudo();
BuildTabMiscelanea();
-
- //tabDetalhes.TabPages.Add(CreateSimpleTab("Peças utilizadas"));
- //tabDetalhes.TabPages.Add(CreateSimpleTab("Obs / Laudo técnico"));
- //tabDetalhes.TabPages.Add(CreateSimpleTab("Miscelânea"));
-
content.Controls.Add(tabDetalhes);
}
+ // ── Aparelho ─────────────────────────────────────────────────
private void BuildTabAparelho()
{
- var tab = new TabPage("Aparelho")
- {
- BackColor = Color.White
- };
+ var tab = new TabPage("Aparelho") { BackColor = Color.White };
- AddModernInput(tab, "Modelo", 20, 20, 500);
- AddModernInput(tab, "Marca", 550, 20, 500);
+ AddModernInput(tab, "Modelo", 12, 12, 490);
+ AddModernInput(tab, "Marca", 520, 12, 490);
+ AddModernInput(tab, "Operadora", 12, 70, 280);
+ AddModernInput(tab, "Serial", 310, 70, 280);
+ AddModernInput(tab, "Nº Patrimônio", 608, 70, 402);
- AddModernInput(tab, "Operadora", 20, 90, 300);
- AddModernInput(tab, "Serial", 350, 90, 300);
- AddModernInput(tab, "Nº Patrimônio", 680, 90, 370);
-
- var txtAcessorios = AddModernInput(tab, "Acessórios", 20, 160, 500, 90);
+ var txtAcessorios = AddModernInput(tab, "Acessórios", 12, 128, 490, 80);
txtAcessorios.Multiline = true;
- var txtDefeito = AddModernInput(tab, "Defeito / Reclamação", 550, 160, 500, 90);
+ var txtDefeito = AddModernInput(tab, "Defeito / Reclamação", 520, 128, 490, 80);
txtDefeito.Multiline = true;
tabDetalhes.TabPages.Add(tab);
- }//Aparelho
+ }
+
+ // ── Mão de obra / Serviços ───────────────────────────────────
private void BuildTabServicos()
{
- var tab = new TabPage("Mão de obra / Serviços")
- {
- BackColor = Color.White
- };
+ var tab = new TabPage("Mão de obra / Serviços") { BackColor = Color.White };
- // =====================================================
- // GRID DE SERVIÇOS
- // =====================================================
-
- var lblLista = new Label
+ tab.Controls.Add(new Label
{
- Text = "Lista de Serviços executados nesta OS",
- Font = new Font("Segoe UI", 9f, FontStyle.Bold),
+ Text = "Serviços executados nesta OS",
+ Font = new Font("Segoe UI", F(8.5f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(15, 15),
+ Location = P(12, 10),
AutoSize = true
- };
-
- tab.Controls.Add(lblLista);
-
- var gridServicos = new DataGridView
- {
- Location = new Point(15, 40),
- Size = new Size(900, 240),
-
- BackgroundColor = Color.White,
- BorderStyle = BorderStyle.FixedSingle,
-
- AllowUserToAddRows = false,
- AllowUserToDeleteRows = false,
- AllowUserToResizeRows = false,
-
- RowHeadersVisible = false,
-
- SelectionMode = DataGridViewSelectionMode.FullRowSelect,
- MultiSelect = false,
-
- AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None,
-
- EnableHeadersVisualStyles = false,
-
- Font = new Font("Segoe UI", 8.5f),
-
- GridColor = BorderColor
- };
-
- // =========================
- // HEADER STYLE
- // =========================
-
- gridServicos.ColumnHeadersDefaultCellStyle.BackColor =
- Color.FromArgb(245, 247, 250);
-
- gridServicos.ColumnHeadersDefaultCellStyle.ForeColor =
- TextDark;
-
- gridServicos.ColumnHeadersDefaultCellStyle.Font =
- new Font("Segoe UI", 8.5f, FontStyle.Bold);
-
- gridServicos.ColumnHeadersHeight = 30;
-
- // =========================
- // COLUNAS
- // =========================
-
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Descrição",
- Width = 320
});
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
+ var grid = CriarGrid(P(12, 30), Sz(940, 230));
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Descrição", Width = S(310) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Tipo", Width = S(80) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Início", Width = S(70) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Fim", Width = S(70) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Qtd", Width = S(55) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Valor", Width = S(90) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Técnico", Width = S(290) });
+ tab.Controls.Add(grid);
+
+ // menu lateral
+ var pnl = new Panel { Location = P(962, 30), Size = Sz(170, 230), BackColor = Color.White };
+
+ pnl.Controls.Add(BotaoLateral("Padrões", 0, AccentBlue, (s, e) =>
+ NT_MessageBox.Show("Testando evento click padrão", "Padrão",
+ MessageBoxButtons.OK, MessageBoxIcon.Information)));
+ pnl.Controls.Add(BotaoLateral("Avulsos", 44, Color.FromArgb(34, 197, 94)));
+ pnl.Controls.Add(BotaoLateral("Excluir", 88, Color.FromArgb(239, 68, 68)));
+
+ pnl.Controls.Add(new Label
{
- HeaderText = "Tipo",
- Width = 80
- });
-
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Início",
- Width = 70
- });
-
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Fim",
- Width = 70
- });
-
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Qtd",
- Width = 60
- });
-
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Valor",
- Width = 90
- });
-
- gridServicos.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Técnico",
- Width = 180
- });
-
- tab.Controls.Add(gridServicos);
-
- // =====================================================
- // MENU LATERAL
- // =====================================================
-
- var pnlLateral = new Panel
- {
- Location = new Point(930, 40),
- Size = new Size(170, 240),
- BackColor = Color.White
- };
-
- Button CriarBotao(string texto, int y, Color cor)
- {
- var btn = new Button
- {
- Text = texto,
- Location = new Point(10, y),
- Size = new Size(145, 38),
-
- FlatStyle = FlatStyle.Flat,
- BackColor = cor,
- ForeColor = Color.White,
-
- Font = new Font("Segoe UI Semibold", 8.5f),
-
- Cursor = Cursors.Hand
- };
-
- btn.FlatAppearance.BorderSize = 0;
-
- return btn;
- }
-
- var btnPadroes = CriarBotao(
- "Padrões",
- 0,
- AccentBlue);
-
- var btnAvulsos = CriarBotao(
- "Avulsos",
- 50,
- Color.FromArgb(34, 197, 94));
-
- var btnExcluir = CriarBotao(
- "Excluir",
- 100,
- Color.FromArgb(239, 68, 68));
-
- pnlLateral.Controls.Add(btnPadroes);
- pnlLateral.Controls.Add(btnAvulsos);
- pnlLateral.Controls.Add(btnExcluir);
-
- // =====================================================
- // TOTAL HORAS
- // =====================================================
-
- var lblHoras = new Label
- {
- Text = "Total de horas",
- Font = new Font("Segoe UI", 8.5f, FontStyle.Bold),
+ Text = "Total horas",
+ Font = new Font("Segoe UI", F(8f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(10, 170),
+ Location = P(8, 130),
AutoSize = true
- };
-
- pnlLateral.Controls.Add(lblHoras);
-
- var txtHoras = new LV_TEXTBOX1
+ });
+ pnl.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(10, 190),
- Size = new Size(145, 30),
-
+ Location = P(8, 146),
+ Size = Sz(148, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue,
-
- Font = new Font("Segoe UI", 10f, FontStyle.Bold)
- };
-
- pnlLateral.Controls.Add(txtHoras);
-
- // =====================================================
- // TOTAL
- // =====================================================
-
- var lblTotal = new Label
+ Font = new Font("Segoe UI", F(9f), FontStyle.Bold)
+ });
+ pnl.Controls.Add(new Label
{
Text = "Total",
- Font = new Font("Segoe UI", 9f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(8.5f), FontStyle.Bold),
ForeColor = Color.Red,
- Location = new Point(10, 230),
+ Location = P(8, 175),
AutoSize = true
- };
-
- pnlLateral.Controls.Add(lblTotal);
-
- var txtTotal = new LV_TEXTBOX1
+ });
+ pnl.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(10, 250),
- Size = new Size(145, 34),
-
+ Location = P(8, 193),
+ Size = Sz(148, 28),
BorderColor = Color.Red,
BorderFocusColor = Color.Red,
-
- Font = new Font("Segoe UI", 11f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(10f), FontStyle.Bold),
ForeColor = Color.Red
- };
+ });
- pnlLateral.Controls.Add(txtTotal);
+ tab.Controls.Add(pnl);
- tab.Controls.Add(pnlLateral);
-
- // =====================================================
- // OBSERVAÇÕES
- // =====================================================
-
- var lblObs = new Label
+ // observações
+ tab.Controls.Add(new Label
{
Text = "Observações internas",
- Font = new Font("Segoe UI", 8.5f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(8f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(15, 295),
+ Location = P(12, 272),
AutoSize = true
- };
-
- tab.Controls.Add(lblObs);
-
- var txtObs = new LV_TEXTBOX1
+ });
+ tab.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(15, 318),
- Size = new Size(900, 90),
-
+ Location = P(12, 288),
+ Size = Sz(940, 80),
Multiline = true,
-
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
+ });
- tab.Controls.Add(txtObs);
-
- // =====================================================
- // BOTÃO DESLOCAMENTO
- // =====================================================
-
- var btnDeslocamento = new Button
- {
- Text = "Deslocamentos",
-
- Location = new Point(930, 360),
- Size = new Size(145, 40),
-
- FlatStyle = FlatStyle.Flat,
-
- BackColor = AccentBlue,
- ForeColor = Color.White,
-
- Font = new Font("Segoe UI Semibold", 8.5f),
-
- Cursor = Cursors.Hand
- };
- //eventos clicks
- btnPadroes.Click += (s, e) =>
- {
- NT_MessageBox.Show(
- "Testando evento click padrão",
- "Padrão",
- MessageBoxButtons.OK,
- MessageBoxIcon.Information);
- };
-
- btnDeslocamento.FlatAppearance.BorderSize = 0;
-
- tab.Controls.Add(btnDeslocamento);
-
- // =====================================================
- // ADD TAB
- // =====================================================
+ tab.Controls.Add(BotaoLateral("Deslocamentos", 288, AccentBlue,
+ location: P(962, 288), size: Sz(148, 32)));
tabDetalhes.TabPages.Add(tab);
- }//Mão de obra e serviço
+ }
+
+ // ── Peças utilizadas ─────────────────────────────────────────
private void BuildTabPecas()
{
- var tab = new TabPage("Peças utilizadas")
- {
- BackColor = Color.White
- };
+ var tab = new TabPage("Peças utilizadas") { BackColor = Color.White };
- // =====================================================
- // TITULO
- // =====================================================
-
- var lblLista = new Label
+ tab.Controls.Add(new Label
{
- Text = "Lista de Peças utilizadas nesta OS",
- Font = new Font("Segoe UI", 9f, FontStyle.Bold),
+ Text = "Peças utilizadas nesta OS",
+ Font = new Font("Segoe UI", F(8.5f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(15, 15),
+ Location = P(12, 10),
AutoSize = true
- };
-
- tab.Controls.Add(lblLista);
-
- // =====================================================
- // GRID
- // =====================================================
-
- var gridPecas = new DataGridView
- {
- Location = new Point(15, 40),
- Size = new Size(900, 360),
-
- BackgroundColor = Color.White,
- BorderStyle = BorderStyle.FixedSingle,
-
- AllowUserToAddRows = false,
- AllowUserToDeleteRows = false,
- AllowUserToResizeRows = false,
-
- RowHeadersVisible = false,
-
- SelectionMode = DataGridViewSelectionMode.FullRowSelect,
- MultiSelect = false,
-
- AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None,
-
- EnableHeadersVisualStyles = false,
-
- Font = new Font("Segoe UI", 8.5f),
-
- GridColor = BorderColor
- };
-
- // =====================================================
- // HEADER STYLE
- // =====================================================
-
- gridPecas.ColumnHeadersDefaultCellStyle.BackColor =
- Color.FromArgb(245, 247, 250);
-
- gridPecas.ColumnHeadersDefaultCellStyle.ForeColor =
- TextDark;
-
- gridPecas.ColumnHeadersDefaultCellStyle.Font =
- new Font("Segoe UI", 8.5f, FontStyle.Bold);
-
- gridPecas.ColumnHeadersHeight = 30;
-
- // =====================================================
- // COLUNAS
- // =====================================================
-
- gridPecas.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Peça nº",
- Width = 120
});
- gridPecas.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Descrição",
- Width = 300
- });
+ var grid = CriarGrid(P(12, 30), Sz(940, 340));
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Peça nº", Width = S(115) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Descrição", Width = S(295) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Valor un", Width = S(105) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Qtd.", Width = S(75) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Valor Total", Width = S(115) });
+ grid.Columns.Add(new DataGridViewTextBoxColumn { HeaderText = "Técnico", Width = S(190) });
+ tab.Controls.Add(grid);
- gridPecas.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Valor un",
- Width = 110
- });
-
- gridPecas.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Qtd.",
- Width = 80
- });
-
- gridPecas.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Valor Total",
- Width = 120
- });
-
- gridPecas.Columns.Add(new DataGridViewTextBoxColumn
- {
- HeaderText = "Técnico",
- Width = 170
- });
-
- tab.Controls.Add(gridPecas);
-
- // =====================================================
- // MENU LATERAL
- // =====================================================
-
- var pnlLateral = new Panel
- {
- Location = new Point(930, 40),
- Size = new Size(170, 360),
- BackColor = Color.White
- };
-
- Button CriarBotao(
- string texto,
- int y,
- Color cor)
- {
- var btn = new Button
- {
- Text = texto,
-
- Location = new Point(10, y),
- Size = new Size(145, 40),
-
- FlatStyle = FlatStyle.Flat,
-
- BackColor = cor,
- ForeColor = Color.White,
-
- Font = new Font("Segoe UI Semibold", 8.5f),
-
- Cursor = Cursors.Hand
- };
-
- btn.FlatAppearance.BorderSize = 0;
-
- return btn;
- }
-
- // =====================================================
- // BOTÕES
- // =====================================================
-
- var btnEstoque = CriarBotao(
- "Peças do Estoque",
- 0,
- AccentBlue);
-
- var btnAvulsas = CriarBotao(
- "Peças avulsas",
- 50,
- Color.FromArgb(34, 197, 94));
-
- var btnKit = CriarBotao(
- "KIT Montado",
- 100,
- Color.FromArgb(245, 158, 11));
-
- var btnExcluir = CriarBotao(
- "Excluir",
- 150,
- Color.FromArgb(239, 68, 68));
-
- var btnOrcamento = CriarBotao(
- "Inserir orçamento",
- 210,
- Color.FromArgb(99, 102, 241));
-
- var btnRequisicao = CriarBotao(
- "Requisição",
- 260,
- Color.FromArgb(107, 114, 128));
-
- pnlLateral.Controls.Add(btnEstoque);
- pnlLateral.Controls.Add(btnAvulsas);
- pnlLateral.Controls.Add(btnKit);
- pnlLateral.Controls.Add(btnExcluir);
- pnlLateral.Controls.Add(btnOrcamento);
- pnlLateral.Controls.Add(btnRequisicao);
-
- tab.Controls.Add(pnlLateral);
-
- // =====================================================
- // ADD TAB
- // =====================================================
+ var pnl = new Panel { Location = P(962, 30), Size = Sz(170, 340), BackColor = Color.White };
+ pnl.Controls.Add(BotaoLateral("Peças do Estoque", 0, AccentBlue));
+ pnl.Controls.Add(BotaoLateral("Peças avulsas", 44, Color.FromArgb(34, 197, 94)));
+ pnl.Controls.Add(BotaoLateral("KIT Montado", 88, Color.FromArgb(245, 158, 11)));
+ pnl.Controls.Add(BotaoLateral("Excluir", 132, Color.FromArgb(239, 68, 68)));
+ pnl.Controls.Add(BotaoLateral("Inserir orçamento", 176, Color.FromArgb(99, 102, 241)));
+ pnl.Controls.Add(BotaoLateral("Requisição", 220, Color.FromArgb(107, 114, 128)));
+ tab.Controls.Add(pnl);
tabDetalhes.TabPages.Add(tab);
- }//Peças utilizadas
+ }
+
+ // ── Laudo técnico ────────────────────────────────────────────
private void BuildTabLaudo()
{
- var tab = new TabPage("Obs / Laudo técnico")
+ var tab = new TabPage("Obs / Laudo técnico") { BackColor = Color.White };
+
+ tab.Controls.Add(new Label
{
- BackColor = Color.White
- };
-
- // =====================================================
- // TITULO
- // =====================================================
-
- var lblInfo = new Label
- {
- Text = "Escreva no espaço abaixo o laudo técnico ou detalhes do conserto do equipamento",
-
- Font = new Font("Segoe UI", 9f, FontStyle.Bold),
-
+ Text = "Laudo técnico / detalhes do conserto",
+ Font = new Font("Segoe UI", F(8.5f), FontStyle.Bold),
ForeColor = TextDark,
-
- Location = new Point(15, 15),
-
+ Location = P(12, 10),
AutoSize = true
- };
-
- tab.Controls.Add(lblInfo);
-
- // =====================================================
- // AJUDA
- // =====================================================
-
- var lblAjuda = new Label
+ });
+ tab.Controls.Add(new Label
{
- Text = "(SHIFT + Enter para pular linha)",
-
- Font = new Font("Segoe UI", 8f),
-
+ Text = "(SHIFT + Enter para nova linha)",
+ Font = new Font("Segoe UI", F(7.5f)),
ForeColor = Color.Gray,
-
- Location = new Point(780, 18),
-
+ Location = P(820, 12),
AutoSize = true
- };
-
- tab.Controls.Add(lblAjuda);
-
- // =====================================================
- // CAMPO DO LAUDO
- // =====================================================
+ });
var txtLaudo = new LV_TEXTBOX1
{
- Location = new Point(15, 40),
-
- Size = new Size(1080, 300),
-
+ Location = P(12, 30),
+ Size = Sz(1118, 330),
Multiline = true,
-
BorderColor = BorderColor,
-
BorderFocusColor = AccentBlue,
-
- Font = new Font("Segoe UI", 9f),
-
+ Font = new Font("Segoe UI", F(9f)),
BackColor = Color.White
};
-
tab.Controls.Add(txtLaudo);
- // =====================================================
- // BOTÃO PREENCHER
- // =====================================================
-
var btnPreencher = new Button
{
Text = "📝 Preencher Laudo",
-
- Location = new Point(15, 355),
-
- Size = new Size(180, 38),
-
+ Location = P(12, 372),
+ Size = Sz(165, 32),
FlatStyle = FlatStyle.Flat,
-
BackColor = AccentBlue,
-
ForeColor = Color.White,
-
- Font = new Font("Segoe UI Semibold", 9f),
-
+ Font = new Font("Segoe UI Semibold", F(8.5f)),
Cursor = Cursors.Hand
};
-
btnPreencher.FlatAppearance.BorderSize = 0;
-
btnPreencher.Click += (s, e) =>
{
txtLaudo.Text =
- @"Equipamento analisado e testado em bancada.
-
-Foi identificado defeito no componente principal.
-
-Realizado:
-- limpeza interna
-- substituição de peças
-- testes finais
-
-Equipamento funcionando normalmente.";
+ "Equipamento analisado e testado em bancada.\r\n\r\n" +
+ "Foi identificado defeito no componente principal.\r\n\r\n" +
+ "Realizado:\r\n- limpeza interna\r\n- substituição de peças\r\n- testes finais\r\n\r\n" +
+ "Equipamento funcionando normalmente.";
};
-
tab.Controls.Add(btnPreencher);
- // =====================================================
- // ADD TAB
- // =====================================================
-
tabDetalhes.TabPages.Add(tab);
- }//Laudo tecnico
+ }
+
+ // ── Miscelânea ───────────────────────────────────────────────
private void BuildTabMiscelanea()
{
- var tab = new TabPage("Miscelânea")
- {
- BackColor = Color.White
- };
+ var tab = new TabPage("Miscelânea") { BackColor = Color.White };
- // =====================================================
- // CARD GARANTIA
- // =====================================================
-
- var cardGarantia = CreateInternalCard(
- "Garantia / Garantidor",
- new Rectangle(15, 15, 650, 280));
-
- // Garantidor
-
- var cbGarantidor = AddComboBox(
- cardGarantia,
- "Fábrica / Garantidor",
- 15,
- 20,
- 300);
-
- cbGarantidor.Items.AddRange(new object[]
- {
- "Nenhum",
- "Samsung",
- "LG",
- "Motorola",
- "Dell"
- });
+ // ── Card Garantia (x=10, y=10, w=640, h=260)
+ var cardGarantia = CreateInternalCard("Garantia / Garantidor", R(10, 10, 640, 260));
+ var cbGarantidor = AddComboBox(cardGarantia, "Fábrica / Garantidor", 10, 22, 290);
+ cbGarantidor.Items.AddRange(new object[] { "Nenhum", "Samsung", "LG", "Motorola", "Dell" });
cbGarantidor.SelectedIndex = 0;
- // Senha
-
- AddSmallLabel(
- cardGarantia,
- "Senha garantidor",
- 15,
- 75);
-
- var txtSenha = new LV_TEXTBOX1
+ AddSmallLabel(cardGarantia, "Senha garantidor", 10, 68);
+ cardGarantia.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(15, 95),
- Size = new Size(220, 30),
-
+ Location = P(10, 84),
+ Size = Sz(210, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
+ });
- cardGarantia.Controls.Add(txtSenha);
-
- // Aviso
-
- var lblAviso = new Label
+ cardGarantia.Controls.Add(new Label
{
- Text =
- "A fábrica/Garantidor é aquele que pagará pelo reparo do equipamento.",
-
- Font = new Font("Segoe UI", 8f),
-
+ Text = "A fábrica/Garantidor é aquele que pagará pelo reparo.",
+ Font = new Font("Segoe UI", F(7.5f)),
ForeColor = Color.FromArgb(120, 53, 15),
-
BackColor = Color.FromArgb(254, 249, 195),
-
- Location = new Point(250, 95),
-
- Size = new Size(360, 45),
-
+ Location = P(235, 84),
+ Size = Sz(385, 36),
TextAlign = ContentAlignment.MiddleCenter
- };
+ });
- cardGarantia.Controls.Add(lblAviso);
-
- // NF Venda
-
- AddSmallLabel(
- cardGarantia,
- "Nº NF de venda",
- 15,
- 150);
-
- var txtNFVenda = new LV_TEXTBOX1
+ AddSmallLabel(cardGarantia, "Nº NF de venda", 10, 126);
+ cardGarantia.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(15, 170),
- Size = new Size(180, 30),
-
+ Location = P(10, 142),
+ Size = Sz(170, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
+ });
- cardGarantia.Controls.Add(txtNFVenda);
-
- // Certificado
-
- AddSmallLabel(
- cardGarantia,
- "Nº certificado de garantia",
- 220,
- 150);
-
- var txtCertificado = new LV_TEXTBOX1
+ AddSmallLabel(cardGarantia, "Nº certificado de garantia", 198, 126);
+ cardGarantia.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(220, 170),
- Size = new Size(390, 30),
-
+ Location = P(198, 142),
+ Size = Sz(422, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
+ });
- cardGarantia.Controls.Add(txtCertificado);
-
- // Compra
-
- AddSmallLabel(
- cardGarantia,
- "Data da compra",
- 15,
- 215);
-
- var dtCompra = new DateTimePicker
+ AddSmallLabel(cardGarantia, "Data da compra", 10, 184);
+ cardGarantia.Controls.Add(new DateTimePicker
{
- Location = new Point(15, 235),
- Width = 180,
-
+ Location = P(10, 200),
+ Width = S(170),
Format = DateTimePickerFormat.Short,
+ Font = new Font("Segoe UI", F(8.5f))
+ });
- Font = new Font("Segoe UI", 8.5f)
- };
-
- cardGarantia.Controls.Add(dtCompra);
-
- // Revendedor
-
- AddSmallLabel(
- cardGarantia,
- "Revendedor",
- 220,
- 215);
-
- var txtRevendedor = new LV_TEXTBOX1
+ AddSmallLabel(cardGarantia, "Revendedor", 198, 184);
+ cardGarantia.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(220, 235),
- Size = new Size(390, 30),
-
+ Location = P(198, 200),
+ Size = Sz(422, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
-
- cardGarantia.Controls.Add(txtRevendedor);
+ });
tab.Controls.Add(cardGarantia);
- // =====================================================
- // CARD NF ENTRADA
- // =====================================================
+ // ── Card NF Entrada (x=660, y=10, w=480, h=120)
+ var cardNF = CreateInternalCard("Nota Fiscal Entrada / Remessa", R(660, 10, 490, 120));
- var cardNF = CreateInternalCard(
- "Nota Fiscal Entrada / Remessa",
- new Rectangle(685, 15, 420, 130));
-
- // Numero NF
-
- AddSmallLabel(
- cardNF,
- "Número da NF",
- 15,
- 20);
-
- var txtNumeroNF = new LV_TEXTBOX1
+ AddSmallLabel(cardNF, "Número da NF", 10, 22);
+ cardNF.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(15, 40),
- Size = new Size(140, 30),
-
+ Location = P(10, 38),
+ Size = Sz(145, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
+ });
- cardNF.Controls.Add(txtNumeroNF);
-
- // Valor NF
-
- AddSmallLabel(
- cardNF,
- "Valor da NF",
- 175,
- 20);
-
- var txtValorNF = new LV_TEXTBOX1
+ AddSmallLabel(cardNF, "Valor da NF", 168, 22);
+ cardNF.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(175, 40),
- Size = new Size(180, 30),
-
+ Location = P(168, 38),
+ Size = Sz(290, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
-
- cardNF.Controls.Add(txtValorNF);
-
- // Emissor
-
- var cbFornecedorNF = AddComboBox(
- cardNF,
- "Emissor (Fornecedor)",
- 15,
- 75,
- 340);
+ });
+ var cbFornecedorNF = AddComboBox(cardNF, "Emissor (Fornecedor)", 10, 72, 448);
cbFornecedorNF.Items.Add("Nenhum");
cbFornecedorNF.SelectedIndex = 0;
tab.Controls.Add(cardNF);
- // =====================================================
- // CARD TERCEIROS
- // =====================================================
+ // ── Card Terceiros (x=660, y=138, w=480, h=132)
+ var cardTerceiros = CreateInternalCard("OS de Terceiros / Parceiros", R(660, 138, 490, 132));
- var cardTerceiros = CreateInternalCard(
- "Ordem de serviço de Terceiros / Parceiros",
- new Rectangle(685, 160, 420, 135));
-
- // OS Terceiro
-
- AddSmallLabel(
- cardTerceiros,
- "Nº OS terceiros",
- 15,
- 20);
-
- var txtOSTerceiros = new LV_TEXTBOX1
+ AddSmallLabel(cardTerceiros, "Nº OS terceiros", 10, 22);
+ cardTerceiros.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(15, 40),
- Size = new Size(120, 30),
-
+ Location = P(10, 38),
+ Size = Sz(140, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
+ });
- cardTerceiros.Controls.Add(txtOSTerceiros);
-
- // OS Fabricante
-
- AddSmallLabel(
- cardTerceiros,
- "Nº OS Fabricante",
- 160,
- 20);
-
- var txtOSFabricante = new LV_TEXTBOX1
+ AddSmallLabel(cardTerceiros, "Nº OS Fabricante", 162, 22);
+ cardTerceiros.Controls.Add(new LV_TEXTBOX1
{
- Location = new Point(160, 40),
- Size = new Size(160, 30),
-
+ Location = P(162, 38),
+ Size = Sz(165, 26),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
- };
-
- cardTerceiros.Controls.Add(txtOSFabricante);
-
- // Fornecedor
-
- var cbFornecedor = AddComboBox(
- cardTerceiros,
- "Emissor (Fornecedor)",
- 15,
- 75,
- 340);
+ });
+ var cbFornecedor = AddComboBox(cardTerceiros, "Emissor (Fornecedor)", 10, 72, 448);
cbFornecedor.Items.Add("Nenhum");
cbFornecedor.SelectedIndex = 0;
tab.Controls.Add(cardTerceiros);
-
- // =====================================================
- // ADD TAB
- // =====================================================
-
tabDetalhes.TabPages.Add(tab);
- }//Miscelânea
+ }
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // RODAPÉ (y=824, h=56)
+ // ──────────────────────────────────────────────────────────────
#region Rodapé
private void BuildRodape()
{
- cardRodape = CreateCard(new Rectangle(20, 900, 1130, 70), "");
+ cardRodape = CreateCard(R(10, 824, 1160, 46), "");
- cbTecnico = AddComboBox(cardRodape, "Técnico Responsável", 20, 10, 350);
+ cbTecnico = AddComboBox(cardRodape, "Técnico Responsável", 12, 5, 320);
+ cbPrioridade = AddComboBox(cardRodape, "Prioridade", 348, 5, 160);
- cbPrioridade = AddComboBox(cardRodape, "Prioridade", 400, 10, 180);
- cbPrioridade.Items.AddRange(new object[]{"Baixa","Normal", "Alta", "Urgente" ,"Emergencial"});
+ cbPrioridade.Items.AddRange(new object[]
+ {
+ "Baixa", "Normal", "Alta", "Urgente", "Emergencial"
+ });
cbPrioridade.SelectedIndex = 1;
var btnFotos = new Button
{
Text = "Fotos / Docs",
- Location = new Point(930, 20),
- Size = new Size(160, 35),
+ Location = P(980, 8),
+ Size = Sz(155, 30),
FlatStyle = FlatStyle.Flat,
BackColor = AccentBlue,
ForeColor = Color.White,
- Font = new Font("Segoe UI Semibold", 9f),
+ Font = new Font("Segoe UI Semibold", F(8.5f)),
Cursor = Cursors.Hand
};
-
btnFotos.FlatAppearance.BorderSize = 0;
cardRodape.Controls.Add(btnFotos);
-
content.Controls.Add(cardRodape);
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // HELPERS
+ // ──────────────────────────────────────────────────────────────
#region Helpers
private Panel CreateCard(Rectangle rect, string title)
@@ -1270,30 +723,24 @@ Equipamento funcionando normalmente.";
Size = rect.Size,
BackColor = Color.White
};
-
pnl.Paint += CardPaint;
if (!string.IsNullOrWhiteSpace(title))
{
- var lbl = new Label
+ pnl.Controls.Add(new Label
{
Text = title,
- Font = new Font("Segoe UI", 10f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(9f), FontStyle.Bold),
ForeColor = AccentBlue,
- Location = new Point(18, 15),
+ Location = P(12, 10),
AutoSize = true
- };
-
- pnl.Controls.Add(lbl);
-
- var line = new Panel
+ });
+ pnl.Controls.Add(new Panel
{
BackColor = BorderColor,
- Location = new Point(18, 40),
- Size = new Size(rect.Width - 36, 1)
- };
-
- pnl.Controls.Add(line);
+ Location = P(12, 30),
+ Size = new Size(rect.Width - S(24), 1)
+ });
}
return pnl;
@@ -1302,58 +749,51 @@ Equipamento funcionando normalmente.";
private LV_TEXTBOX1 AddModernInput(
Control parent,
string label,
- int x,
- int y,
+ int x, int y,
int width,
- int height = 32)
+ int height = 26)
{
- var lbl = new Label
+ parent.Controls.Add(new Label
{
Text = label,
- Font = new Font("Segoe UI", 8.5f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(8f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(x, y),
+ Location = P(x, y),
AutoSize = true
- };
+ });
var txt = new LV_TEXTBOX1
{
- Location = new Point(x, y + 20),
- Size = new Size(width, height),
+ Location = P(x, y + 16),
+ Size = Sz(width, height),
BorderColor = BorderColor,
BorderFocusColor = AccentBlue,
BackColor = Color.White
};
-
- parent.Controls.Add(lbl);
parent.Controls.Add(txt);
-
return txt;
}
private LV_TEXTBOX1 AddFinanceRow(Control parent, string text, int y)
{
- var lbl = new Label
+ parent.Controls.Add(new Label
{
Text = text,
- Font = new Font("Segoe UI", 9f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(8f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(20, y + 7),
+ Location = P(10, y + 5),
AutoSize = true
- };
+ });
var txt = new LV_TEXTBOX1
{
- Location = new Point(140, y),
- Size = new Size(180, 32),
+ Location = P(118, y),
+ Size = Sz(164, 26),
TextAlign = HorizontalAlignment.Right,
BorderColor = BorderColor,
BorderFocusColor = AccentBlue
};
-
- parent.Controls.Add(lbl);
parent.Controls.Add(txt);
-
return txt;
}
@@ -1362,9 +802,9 @@ Equipamento funcionando normalmente.";
parent.Controls.Add(new Label
{
Text = text,
- Font = new Font("Segoe UI", 8.5f, FontStyle.Bold),
+ Font = new Font("Segoe UI", F(8f), FontStyle.Bold),
ForeColor = TextDark,
- Location = new Point(x, y),
+ Location = P(x, y),
AutoSize = true
});
}
@@ -1373,107 +813,144 @@ Equipamento funcionando normalmente.";
{
return new DateTimePicker
{
- Location = new Point(x, y),
- Width = width,
+ Location = P(x, y),
+ Width = S(width),
Format = DateTimePickerFormat.Custom,
CustomFormat = "dd/MM/yyyy HH:mm",
- Font = new Font("Segoe UI", 9f)
+ Font = new Font("Segoe UI", F(8.5f))
};
}
- private TabPage CreateSimpleTab(string title)
+ private ComboBox AddComboBox(Control parent, string label, int x, int y, int width)
{
- return new TabPage(title)
+ AddSmallLabel(parent, label, x, y);
+ var cb = new ComboBox
{
- BackColor = Color.White
+ Location = P(x, y + 16),
+ Size = Sz(width, 26),
+ Font = new Font("Segoe UI", F(8.5f)),
+ DropDownStyle = ComboBoxStyle.DropDownList
};
+ parent.Controls.Add(cb);
+ return cb;
+ }
+
+ // Grid padrão reutilizável
+ private DataGridView CriarGrid(Point location, Size size)
+ {
+ var grid = new DataGridView
+ {
+ Location = location,
+ Size = size,
+ BackgroundColor = Color.White,
+ BorderStyle = BorderStyle.FixedSingle,
+ AllowUserToAddRows = false,
+ AllowUserToDeleteRows = false,
+ AllowUserToResizeRows = false,
+ RowHeadersVisible = false,
+ SelectionMode = DataGridViewSelectionMode.FullRowSelect,
+ MultiSelect = false,
+ AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None,
+ EnableHeadersVisualStyles = false,
+ Font = new Font("Segoe UI", F(8f)),
+ GridColor = BorderColor,
+ ColumnHeadersHeight = S(26)
+ };
+ grid.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(245, 247, 250);
+ grid.ColumnHeadersDefaultCellStyle.ForeColor = TextDark;
+ grid.ColumnHeadersDefaultCellStyle.Font = new Font("Segoe UI", F(8f), FontStyle.Bold);
+ return grid;
+ }
+
+ // Botão lateral padronizado — overload simples
+ private Button BotaoLateral(string texto, int y, Color cor,
+ EventHandler? click = null)
+ {
+ var btn = new Button
+ {
+ Text = texto,
+ Location = P(8, y),
+ Size = Sz(148, 38),
+ FlatStyle = FlatStyle.Flat,
+ BackColor = cor,
+ ForeColor = Color.White,
+ Font = new Font("Segoe UI Semibold", F(8f)),
+ Cursor = Cursors.Hand
+ };
+ btn.FlatAppearance.BorderSize = 0;
+ if (click != null) btn.Click += click;
+ return btn;
+ }
+
+ // Botão lateral com posição e tamanho explícitos
+ private Button BotaoLateral(string texto, int y, Color cor,
+ Point location, Size size, EventHandler? click = null)
+ {
+ var btn = new Button
+ {
+ Text = texto,
+ Location = location,
+ Size = size,
+ FlatStyle = FlatStyle.Flat,
+ BackColor = cor,
+ ForeColor = Color.White,
+ Font = new Font("Segoe UI Semibold", F(8f)),
+ Cursor = Cursors.Hand
+ };
+ btn.FlatAppearance.BorderSize = 0;
+ if (click != null) btn.Click += click;
+ return btn;
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // EVENTOS VISUAIS
+ // ──────────────────────────────────────────────────────────────
#region Eventos Visuais
private void CardPaint(object? sender, PaintEventArgs e)
{
var pnl = sender as Panel;
-
using var pen = new Pen(BorderColor);
-
- e.Graphics.DrawRectangle(
- pen,
- 0,
- 0,
- pnl!.Width - 1,
- pnl.Height - 1);
+ e.Graphics.DrawRectangle(pen, 0, 0, pnl!.Width - 1, pnl.Height - 1);
}
private void DrawTab(object? sender, DrawItemEventArgs e)
{
var tab = tabDetalhes.TabPages[e.Index];
- var rect = e.Bounds;
-
bool selected = e.Index == tabDetalhes.SelectedIndex;
- using var back = new SolidBrush(
- selected
- ? AccentBlue
- : Color.FromArgb(230, 233, 238));
-
- using var text = new SolidBrush(
- selected
- ? Color.White
- : TextDark);
-
- e.Graphics.FillRectangle(back, rect);
-
- var sf = new StringFormat
- {
- Alignment = StringAlignment.Center,
- LineAlignment = StringAlignment.Center
- };
+ using var back = new SolidBrush(selected ? AccentBlue : Color.FromArgb(230, 233, 238));
+ using var fore = new SolidBrush(selected ? Color.White : TextDark);
+ e.Graphics.FillRectangle(back, e.Bounds);
e.Graphics.DrawString(
tab.Text,
- new Font("Segoe UI", 9f, FontStyle.Bold),
- text,
- rect,
- sf);
+ new Font("Segoe UI", F(8.5f), FontStyle.Bold),
+ fore,
+ e.Bounds,
+ new StringFormat
+ {
+ Alignment = StringAlignment.Center,
+ LineAlignment = StringAlignment.Center
+ });
}
#endregion
+ // ──────────────────────────────────────────────────────────────
+ // MÉTODOS ABSTRATOS
+ // ──────────────────────────────────────────────────────────────
#region Métodos Abstratos
- protected override void OnNovo()
- {
-
- }
-
- protected override void OnAlterar()
- {
-
- }
-
- protected override void OnExcluir()
- {
-
- }
-
- protected override void OnLocalizar()
- {
-
- }
-
- protected override void OnSalvar()
- {
-
- }
-
- protected override void OnCancelar()
- {
-
- }
+ protected override void OnNovo() { }
+ protected override void OnAlterar() { }
+ protected override void OnExcluir() { }
+ protected override void OnLocalizar() { }
+ protected override void OnSalvar() { }
+ protected override void OnCancelar() { }
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/UI/Dashboards/Cadastros/PedidosPanel.cs b/UI/Dashboards/Cadastros/PedidosPanel.cs
new file mode 100644
index 0000000..ff37fe0
--- /dev/null
+++ b/UI/Dashboards/Cadastros/PedidosPanel.cs
@@ -0,0 +1,185 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class PedidosPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todas as propriedades do ModeloPedidos
+ private LV_TEXTBOX1 txtIdPedidos;
+ private LV_TEXTBOX1 txtCodigo;
+ private LV_TEXTBOX1 txtTipo;
+ private LV_TEXTBOX1 txtDataPedido;
+ private LV_TEXTBOX1 txtFormaPgto;
+ private LV_TEXTBOX1 txtEntregaDia;
+ private LV_TEXTBOX1 txtEntregaContato;
+ private LV_TEXTBOX1 txtEntregaEndereco;
+ private LV_TEXTBOX1 txtEntregaCidade;
+ private LV_TEXTBOX1 txtEntregaUf;
+ private LV_TEXTBOX1 txtEntregaCep;
+ private LV_TEXTBOX1 txtEntregaTelefone;
+ private LV_TEXTBOX1 txtDataEnvio;
+ private LV_TEXTBOX1 txtObservacoes;
+ private LV_TEXTBOX1 txtFornecedor;
+ private LV_TEXTBOX1 txtTransportador;
+ private LV_TEXTBOX1 txtVendedor;
+ private LV_TEXTBOX1 txtValor;
+ private LV_TEXTBOX1 txtSituacao;
+ private LV_TEXTBOX1 txtDesconto;
+ private LV_TEXTBOX1 txtNumNfPed;
+ private LV_TEXTBOX1 txtVFrete;
+ private LV_TEXTBOX1 txtVSeguro;
+ private LV_TEXTBOX1 txtVOutros;
+ private LV_TEXTBOX1 txtPedPrazo;
+ private LV_TEXTBOX1 txtPedForma;
+ private LV_TEXTBOX1 txtPedObs;
+ private LV_TEXTBOX1 txtChaveNfeCompra;
+ private LV_TEXTBOX1 txtPagamentoPedido;
+ private LV_TEXTBOX1 txtPagamentoFrete;
+ private LV_TEXTBOX1 txtRastreioFrete;
+
+ public PedidosPanel()
+ {
+ this.Titulo = "CENTRAL DE COMPRAS E PEDIDOS";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: DADOS BÁSICOS E ENVOLVIDOS ---
+ content.Controls.Add(CreateSectionHeader("Identificação Básica e Fluxo", 15));
+
+ txtIdPedidos = AddInput(content, "ID PEDIDO", 20, 45, 100, 28, true);
+ txtCodigo = AddInput(content, "CÓDIGO INT.", 135, 45, 110, 28);
+ txtTipo = AddInput(content, "TIPO (COMPRA/VENDA)", 260, 45, 160, 28);
+ txtDataPedido = AddInput(content, "DATA PEDIDO", 435, 45, 130, 28);
+ txtSituacao = AddInput(content, "SITUAÇÃO/STATUS", 580, 45, 150, 28);
+
+ txtVendedor = AddInput(content, "VENDEDOR", 20, 100, 225, 28);
+ txtFornecedor = AddInput(content, "FORNECEDOR / PARCEIRO", 260, 100, 310, 28);
+ txtTransportador = AddInput(content, "TRANSPORTADORA", 585, 100, 280, 28);
+
+ // --- SEÇÃO 2: LOGÍSTICA E ENTREGA ---
+ content.Controls.Add(CreateSectionHeader("Logística e Local de Entrega", 155));
+
+ txtEntregaContato = AddInput(content, "CONTATO P/ ENTREGA", 20, 185, 225, 28);
+ txtEntregaTelefone = AddInput(content, "TEL. ENTREGA", 260, 185, 150, 28);
+ txtEntregaDia = AddInput(content, "DATA PROMETIDA", 425, 185, 140, 28);
+ txtDataEnvio = AddInput(content, "DATA DE ENVIO", 580, 185, 140, 28);
+ txtRastreioFrete = AddInput(content, "CÓD. RASTREIO FRETE", 735, 185, 220, 28);
+
+ txtEntregaEndereco = AddInput(content, "ENDEREÇO DE ENTREGA", 20, 240, 400, 28);
+ txtEntregaCidade = AddInput(content, "CIDADE", 435, 240, 200, 28);
+ txtEntregaUf = AddInput(content, "UF", 650, 240, 60, 28);
+ txtEntregaCep = AddInput(content, "CEP", 725, 240, 110, 28);
+
+ // --- SEÇÃO 3: VALORES E FINANCEIRO ---
+ content.Controls.Add(CreateSectionHeader("Valores, Custos e Condições Financeiras", 295));
+
+ txtValor = AddInput(content, "VALOR PRODUTOS (R$)", 20, 325, 150, 28);
+ txtDesconto = AddInput(content, "DESCONTO (R$)", 185, 325, 120, 28);
+ txtVFrete = AddInput(content, "VALOR FRETE (R$)", 320, 325, 120, 28);
+ txtVSeguro = AddInput(content, "VALOR SEGURO (R$)", 455, 325, 120, 28);
+ txtVOutros = AddInput(content, "OUTRAS DESPESAS (R$)", 590, 325, 140, 28);
+
+ txtFormaPgto = AddInput(content, "FORMA PGTO PRINCIPAL", 20, 380, 180, 28);
+ txtPedForma = AddInput(content, "FORMA DETALHADA", 215, 380, 180, 28);
+ txtPedPrazo = AddInput(content, "CONDIÇÃO DE PRAZO", 410, 380, 165, 28);
+ txtPagamentoPedido = AddInput(content, "STATUS PGTO PEDIDO", 590, 380, 160, 28);
+ txtPagamentoFrete = AddInput(content, "STATUS PGTO FRETE", 765, 380, 160, 28);
+
+ // --- SEÇÃO 4: DADOS FISCAIS E OBSERVAÇÕES ---
+ content.Controls.Add(CreateSectionHeader("Documentação Fiscal e Informações de Fechamento", 435));
+
+ txtNumNfPed = AddInput(content, "Nº NF-E / DOCUMENTO", 20, 465, 180, 28);
+ txtChaveNfeCompra = AddInput(content, "CHAVE DE ACESSO DA NF-E (44 DÍGITOS)", 215, 465, 415, 28);
+
+ txtObservacoes = AddInput(content, "OBSERVAÇÕES GERAIS", 20, 520, 465, 28);
+ txtPedObs = AddInput(content, "OBS. INTERNAS / FINANCEIRAS", 500, 520, 455, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa de forma segura todos os inputs dinâmicos do formulário
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+ txtCodigo.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Mapeamento cirúrgico e sem omissões de todas as 31 propriedades
+ var pedido = new ModeloPedidos
+ {
+ ID_PEDIDOS = string.IsNullOrEmpty(txtIdPedidos.Text) ? 0 : Convert.ToInt32(txtIdPedidos.Text),
+ CODIGO = txtCodigo.Text,
+ TIPO = txtTipo.Text,
+ DATA_PEDIDO = txtDataPedido.Text,
+ FORMA_PGTO = txtFormaPgto.Text,
+ ENTREGA_DIA = txtEntregaDia.Text,
+ ENTREGA_CONTATO = txtEntregaContato.Text,
+ ENTREGA_ENDERECO = txtEntregaEndereco.Text,
+ ENTREGA_CIDADE = txtEntregaCidade.Text,
+ ENTREGA_UF = txtEntregaUf.Text,
+ ENTREGA_CEP = txtEntregaCep.Text,
+ ENTREGA_TELEFONE = txtEntregaTelefone.Text,
+ DATA_ENVIO = txtDataEnvio.Text,
+ OBSERVACOES = txtObservacoes.Text,
+ FORNECEDOR = txtFornecedor.Text,
+ TRANSPORTADOR = txtTransportador.Text,
+ VENDEDOR = txtVendedor.Text,
+ VALOR = txtValor.Text,
+ SITUACAO = txtSituacao.Text,
+ DESCONTO = txtDesconto.Text,
+ NUM_NF_PED = txtNumNfPed.Text,
+ V_FRETE = txtVFrete.Text,
+ V_SEGURO = txtVSeguro.Text,
+ V_OUTROS = txtVOutros.Text,
+ PED_PRAZO = txtPedPrazo.Text,
+ PED_FORMA = txtPedForma.Text,
+ PED_OBS = txtPedObs.Text,
+ CHAVE_NFE_COMPRA = txtChaveNfeCompra.Text,
+ PAGAMENTO_PEDIDO = txtPagamentoPedido.Text,
+ PAGAMENTO_FRETE = txtPagamentoFrete.Text,
+ RASTREIO_FRETE = txtRastreioFrete.Text
+ };
+
+ // Comunicação direta com sua BLL/DAL para persistir no banco SQL Server
+ MessageBox.Show("Pedido registrado e integrado com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtSituacao.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Atenção! A exclusão deste pedido pode afetar o fluxo financeiro e o estoque. Confirmar?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Comando de deleção...
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aciona sua tela de consulta/Grid de pedidos
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/PerfilPanel.cs b/UI/Dashboards/Cadastros/PerfilPanel.cs
new file mode 100644
index 0000000..b95486a
--- /dev/null
+++ b/UI/Dashboards/Cadastros/PerfilPanel.cs
@@ -0,0 +1,115 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class PerfilPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todas as propriedades do ModeloPerfil
+ private LV_TEXTBOX1 txtId;
+ private LV_TEXTBOX1 txtEmpresaId;
+ private LV_TEXTBOX1 txtNome;
+ private LV_TEXTBOX1 txtDescricao;
+ private CheckBox chkAtivo;
+
+ public PerfilPanel()
+ {
+ this.Titulo = "CONTROLE DE PERFIS DE ACESSO";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO ÚNICA: ESTRUTURA DO PERFIL ---
+ content.Controls.Add(CreateSectionHeader("Configurações do Perfil de Usuário", 20));
+
+ // Linha 1: Chaves de Identificação e Vínculo Multi-Empresa
+ txtId = AddInput(content, "ID PERFIL", 20, 55, 110, 28, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 145, 55, 120, 28);
+
+ // Status Ativo/Inativo posicionado de forma alinhada na primeira linha
+ chkAtivo = new CheckBox
+ {
+ Text = "Perfil Liberado / Ativo",
+ Location = new Point(285, 71),
+ AutoSize = true,
+ Font = new Font("Segoe UI", 10F, FontStyle.Bold),
+ ForeColor = Color.FromArgb(64, 64, 64)
+ };
+ content.Controls.Add(chkAtivo);
+
+ // Linha 2: Nome do Grupo/Perfil
+ txtNome = AddInput(content, "NOME DO PERFIL (EX: ADMINISTRADOR, VENDEDOR)", 20, 115, 500, 28);
+
+ // Linha 3: Detalhamento das Permissões do Perfil
+ txtDescricao = AddInput(content, "DESCRIÇÃO DAS ATRIBUIÇÕES E PERMISSÕES DESTE NÍVEL", 20, 175, 500, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa os campos de texto editáveis
+ txtEmpresaId.Text = string.Empty;
+ txtNome.Text = string.Empty;
+ txtDescricao.Text = string.Empty;
+
+ // Estado padrão para novas inserções
+ txtId.Text = "0";
+ chkAtivo.Checked = true;
+
+ txtEmpresaId.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Validação simples antes de montar o objeto
+ if (string.IsNullOrWhiteSpace(txtNome.Text))
+ {
+ MessageBox.Show("O nome do perfil é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNome.Focus();
+ return;
+ }
+
+ // Mapeamento absoluto de todas as propriedades da classe
+ var perfil = new ModeloPerfil
+ {
+ Id = string.IsNullOrEmpty(txtId.Text) ? 0 : Convert.ToInt32(txtId.Text),
+ EmpresaId = string.IsNullOrEmpty(txtEmpresaId.Text) ? 0 : Convert.ToInt32(txtEmpresaId.Text),
+ Nome = txtNome.Text,
+ Descricao = txtDescricao.Text,
+ Ativo = chkAtivo.Checked // Atribuição booleana direta sem necessidade de conversão de string
+ };
+
+ // Envio do objeto limpo e populado para sua camada BLL / DAL do SQL Server
+ MessageBox.Show("Perfil de acesso salvo com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNome.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja realmente remover este perfil? Usuários vinculados a ele podem perder o acesso ao sistema.", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Executa exclusão física ou lógica...
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Abre sua Grid / Tela de pesquisa para buscar os perfis existentes
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/PermissaoPanel.cs b/UI/Dashboards/Cadastros/PermissaoPanel.cs
new file mode 100644
index 0000000..e42aa98
--- /dev/null
+++ b/UI/Dashboards/Cadastros/PermissaoPanel.cs
@@ -0,0 +1,97 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class PermissaoPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todas as propriedades do ModeloPermissao
+ private LV_TEXTBOX1 txtId;
+ private LV_TEXTBOX1 txtNome;
+ private LV_TEXTBOX1 txtDescricao;
+
+ public PermissaoPanel()
+ {
+ this.Titulo = "CADASTRO DE PERMISSÕES DO SISTEMA";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO ÚNICA: DADOS DA PERMISSÃO ---
+ content.Controls.Add(CreateSectionHeader("Identificação da Diretiva de Segurança", 20));
+
+ // Linha 1: ID de Registro (Desabilitado por padrão)
+ txtId = AddInput(content, "ID PERMISSÃO", 20, 55, 110, 28, true);
+
+ // Linha 2: Chave Identificadora da Permissao (ex: os_deletar_registro)
+ txtNome = AddInput(content, "CHAVE IDENTIFICADORA DA PERMISSÃO (SISTEMA_ACAO)", 20, 115, 500, 28);
+
+ // Linha 3: Detalhamento amigável para o usuário administrador entender o que ela faz
+ txtDescricao = AddInput(content, "DESCRIÇÃO DETALHADA DO RECURSO BLOQUEADO / LIBERADO", 20, 175, 650, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa os campos editáveis
+ txtNome.Text = string.Empty;
+ txtDescricao.Text = string.Empty;
+
+ // Define o ID padrão de inserção
+ txtId.Text = "0";
+
+ txtNome.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Validação mínima de consistência de dados
+ if (string.IsNullOrWhiteSpace(txtNome.Text))
+ {
+ MessageBox.Show("A chave identificadora da permissão é obrigatória.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNome.Focus();
+ return;
+ }
+
+ // Mapeamento absoluto de todas as propriedades do ModeloPermissao
+ var permissao = new ModeloPermissao
+ {
+ Id = string.IsNullOrEmpty(txtId.Text) ? 0 : Convert.ToInt32(txtId.Text),
+ Nome = txtNome.Text,
+ Descricao = txtDescricao.Text
+ };
+
+ // Processa o envio do objeto estruturado para as regras de persistência (BLL / DAL)
+ MessageBox.Show("Permissão gravada no dicionário de segurança!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNome.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Aviso! Remover esta permissão pode invalidar as checagens de segurança no código-fonte do sistema. Deseja continuar?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Processa a rotina de exclusão física do banco de dados...
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aciona o seu Grid de busca para selecionar as permissões instaladas
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/PlanoDeContasPanel.cs b/UI/Dashboards/Cadastros/PlanoDeContasPanel.cs
new file mode 100644
index 0000000..fb791e5
--- /dev/null
+++ b/UI/Dashboards/Cadastros/PlanoDeContasPanel.cs
@@ -0,0 +1,163 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class PlanoDeContasPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todas as propriedades do ModeloPlanoDeContas
+ private LV_TEXTBOX1 txtId;
+ private LV_TEXTBOX1 txtEmpresaId;
+ private LV_TEXTBOX1 txtContaPaiId;
+ private LV_TEXTBOX1 txtNome;
+ private LV_TEXTBOX1 txtCodigo;
+ private LV_TEXTBOX1 txtTipo;
+ private CheckBox chkAceitaLancamento;
+ private CheckBox chkAtivo;
+ private LV_TEXTBOX1 txtCriadoEm;
+ private LV_TEXTBOX1 txtAtualizadoEm;
+
+ public PlanoDeContasPanel()
+ {
+ this.Titulo = "ESTRUTURAÇÃO DO PLANO DE CONTAS FINACEIRO";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: HIERARQUIA E IDENTIFICAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Classificação e Hierarquia da Conta", 20));
+
+ txtId = AddInput(content, "ID REGISTRO", 20, 55, 100, 28, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 135, 55, 110, 28);
+ txtCodigo = AddInput(content, "CÓDIGO ESTRUTURAL (EX: 1.01.02)", 260, 55, 230, 28);
+ txtContaPaiId = AddInput(content, "ID CONTA PAI (NULO P/ GRUPO RAIZ)", 505, 55, 230, 28);
+
+ // --- SEÇÃO 2: DEFINIÇÃO COMERCIAL ---
+ content.Controls.Add(CreateSectionHeader("Dados de Identificação e Regras de Operação", 115));
+
+ txtNome = AddInput(content, "NOME DA CONTA (EX: ENERGIA ELÉTRICA, RECEITA DE VENDAS)", 20, 150, 470, 28);
+ txtTipo = AddInput(content, "TIPO (RECEITA / DESPESA / ATIVO)", 505, 150, 230, 28);
+
+ // Checkboxes de Regras de Negócio e Status alinhados lado a lado
+ chkAceitaLancamento = new CheckBox
+ {
+ Text = "Aceita Lançamento Direto (Conta Analítica)",
+ Location = new Point(20, 200),
+ AutoSize = true,
+ Font = new Font("Segoe UI", 9.5F, FontStyle.Bold),
+ ForeColor = Color.FromArgb(64, 64, 64)
+ };
+ content.Controls.Add(chkAceitaLancamento);
+
+ chkAtivo = new CheckBox
+ {
+ Text = "Conta Ativa no Sistema",
+ Location = new Point(350, 200),
+ AutoSize = true,
+ Font = new Font("Segoe UI", 9.5F, FontStyle.Bold),
+ ForeColor = Color.FromArgb(64, 64, 64)
+ };
+ content.Controls.Add(chkAtivo);
+
+ // --- SEÇÃO 3: AUDITORIA ---
+ content.Controls.Add(CreateSectionHeader("Datas de Auditoria e Controle de Registro", 245));
+
+ txtCriadoEm = AddInput(content, "DATA DE CRIAÇÃO", 20, 280, 220, 28, true);
+ txtAtualizadoEm = AddInput(content, "ÚLTIMA ATUALIZAÇÃO", 255, 280, 220, 28, true);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa os campos editáveis de texto
+ txtEmpresaId.Text = string.Empty;
+ txtCodigo.Text = string.Empty;
+ txtContaPaiId.Text = string.Empty;
+ txtNome.Text = string.Empty;
+ txtTipo.Text = string.Empty;
+
+ // Valores padrão para novos registros
+ txtId.Text = "0";
+ chkAceitaLancamento.Checked = true;
+ chkAtivo.Checked = true;
+ txtCriadoEm.Text = DateTime.Now.ToString("g");
+ txtAtualizadoEm.Text = DateTime.Now.ToString("g");
+
+ txtCodigo.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Validações básicas de negócio
+ if (string.IsNullOrWhiteSpace(txtCodigo.Text))
+ {
+ MessageBox.Show("O código estrutural da conta é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtCodigo.Focus();
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(txtNome.Text))
+ {
+ MessageBox.Show("O nome da conta é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNome.Focus();
+ return;
+ }
+
+ // Tratamento explícito para o tipo Nullable (int?) da ContaPaiId
+ int? contaPai = null;
+ if (!string.IsNullOrWhiteSpace(txtContaPaiId.Text) && int.TryParse(txtContaPaiId.Text, out int resultId))
+ {
+ contaPai = resultId;
+ }
+
+ // Mapeamento absoluto e tipado de todas as propriedades do ModeloPlanoDeContas
+ var conta = new ModeloPlanoDeContas
+ {
+ Id = string.IsNullOrEmpty(txtId.Text) ? 0 : Convert.ToInt32(txtId.Text),
+ EmpresaId = string.IsNullOrEmpty(txtEmpresaId.Text) ? 0 : Convert.ToInt32(txtEmpresaId.Text),
+ ContaPaiId = contaPai,
+ Codigo = txtCodigo.Text,
+ Nome = txtNome.Text,
+ Tipo = txtTipo.Text,
+ AceitaLancamento = chkAceitaLancamento.Checked,
+ Ativo = chkAtivo.Checked,
+
+ // Preserva ou trata as datas de auditoria
+ CriadoEm = string.IsNullOrEmpty(txtCriadoEm.Text) ? DateTime.Now : Convert.ToDateTime(txtCriadoEm.Text),
+ AtualizadoEm = DateTime.Now // Sempre grava a data do momento do save
+ };
+
+ // Envio do objeto limpo e preenchido para as camadas BLL / DAL do SQL Server
+ MessageBox.Show("Conta cadastrada com sucesso no plano de contas!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNome.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Atenção! Remover uma conta com lançamentos financeiros vinculados pode corromper os relatórios de DRE e fluxo de caixa. Confirmar exclusão?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Processa deleção...
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Abre sua Grid de pesquisa ou componente TreeView do plano de contas
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/ServicosPanel.cs b/UI/Dashboards/Cadastros/ServicosPanel.cs
new file mode 100644
index 0000000..ac3a331
--- /dev/null
+++ b/UI/Dashboards/Cadastros/ServicosPanel.cs
@@ -0,0 +1,166 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Cadastro
+{
+ public class ServicosPanel : FormularioModelo
+ {
+ // Controles marcados como anuláveis para sanar avisos do compilador modernos (NRT)
+ private LV_TEXTBOX1? txtId;
+ private LV_TEXTBOX1? txtEmpresaId;
+ private LV_TEXTBOX1? txtNome;
+ private LV_TEXTBOX1? txtDescricao;
+ private LV_TEXTBOX1? txtValorPadrao;
+ private LV_TEXTBOX1? txtCusto;
+ private LV_TEXTBOX1? txtTipoComissao;
+ private LV_TEXTBOX1? txtValorComissao;
+ private LV_TEXTBOX1? txtTempoEstimado;
+ private LV_TEXTBOX1? txtCriadoEm;
+ private LV_TEXTBOX1? txtAtualizadoEm;
+ private CheckBox? chkAtivo;
+
+ public ServicosPanel()
+ {
+ this.Titulo = "CADASTRO E CONFIGURAÇÃO DE SERVIÇOS";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: IDENTIFICAÇÃO E DADOS GERAIS ---
+ content.Controls.Add(CreateSectionHeader("Identificação do Serviço", 20));
+
+ txtId = AddInput(content, "ID SERVIÇO", 20, 55, 100, 28, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 135, 55, 100, 28);
+ txtNome = AddInput(content, "NOME DO SERVIÇO", 250, 55, 400, 28);
+
+ // CheckBox customizado ou nativo alinhado ao grid visual
+ chkAtivo = new CheckBox
+ {
+ Text = "Serviço Ativo",
+ Location = new Point(670, 58),
+ Size = new Size(120, 24),
+ Font = new Font("Segoe UI", 10f, FontStyle.Bold),
+ ForeColor = Color.FromArgb(45, 45, 45),
+ Checked = true
+ };
+ content.Controls.Add(chkAtivo);
+
+ txtDescricao = AddInput(content, "DESCRIÇÃO DETALHADA DO SERVIÇO", 20, 115, 630, 28);
+
+ // --- SEÇÃO 2: VALORES E PRECIFICAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Precificação, Custos e Regras de Comissão", 185));
+
+ txtValorPadrao = AddInput(content, "VALOR PADRÃO VENDA (R$)", 20, 220, 180, 28);
+ txtCusto = AddInput(content, "CUSTO DO SERVIÇO (R$)", 215, 220, 180, 28);
+ txtTipoComissao = AddInput(content, "TIPO COMISSÃO (EX: % OU FIXO)", 410, 220, 220, 28);
+ txtValorComissao = AddInput(content, "VALOR COMISSÃO", 645, 220, 145, 28);
+
+ // --- SEÇÃO 3: OPERAÇÃO E LOG DE AUDITORIA ---
+ content.Controls.Add(CreateSectionHeader("Tempo de Execução e Auditoria", 290));
+
+ txtTempoEstimado = AddInput(content, "TEMPO ESTIMADO (EM MINUTOS)", 20, 325, 220, 28); // Grafia corrigida aqui
+ txtCriadoEm = AddInput(content, "DATA DE CRIAÇÃO", 255, 325, 180, 28, true);
+ txtAtualizadoEm = AddInput(content, "ÚLTIMA ATUALIZAÇÃO", 445, 325, 180, 28, true);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Varre e limpa os inputs do painel
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+
+ if (txtId != null) txtId.Text = "0";
+ if (txtEmpresaId != null) txtEmpresaId.Text = "1"; // Default para a empresa ativa principal
+ if (txtValorPadrao != null) txtValorPadrao.Text = "0,00";
+ if (txtCusto != null) txtCusto.Text = "0,00";
+ if (txtValorComissao != null) txtValorComissao.Text = "0,00";
+ if (txtTempoEstimado != null) txtTempoEstimado.Text = "0";
+
+ if (txtCriadoEm != null) txtCriadoEm.Text = DateTime.Now.ToString("g");
+ if (txtAtualizadoEm != null) txtAtualizadoEm.Text = DateTime.Now.ToString("g");
+
+ if (chkAtivo != null) chkAtivo.Checked = true;
+
+ txtNome?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (string.IsNullOrWhiteSpace(txtNome?.Text))
+ {
+ MessageBox.Show("O nome do serviço é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNome?.Focus();
+ return;
+ }
+
+ // Conversões seguras extraídas dos componentes de texto de forma resiliente
+ int idServico = string.IsNullOrEmpty(txtId?.Text) ? 0 : Convert.ToInt32(txtId.Text);
+ int idEmpresa = string.IsNullOrEmpty(txtEmpresaId?.Text) ? 0 : Convert.ToInt32(txtEmpresaId.Text);
+
+ decimal.TryParse(txtValorPadrao?.Text, out decimal vPadrao);
+ decimal.TryParse(txtValorComissao?.Text, out decimal vComissao);
+
+ decimal? vCusto = null;
+ if (!string.IsNullOrWhiteSpace(txtCusto?.Text) && decimal.TryParse(txtCusto.Text, out decimal cParsed))
+ vCusto = cParsed;
+
+ int? tEstimado = null;
+ if (!string.IsNullOrWhiteSpace(txtTempoEstimado?.Text) && int.TryParse(txtTempoEstimado.Text, out int tParsed))
+ tEstimado = tParsed;
+
+ // Mapeamento cirúrgico de todas as 12 propriedades da classe ModeloServicos
+ var servico = new ModeloServicos
+ {
+ Id = idServico,
+ EmpresaId = idEmpresa,
+ Nome = txtNome.Text,
+ Descricao = txtDescricao?.Text ?? string.Empty,
+ ValorPadrao = vPadrao,
+ Custo = vCusto,
+ TipoComissao = txtTipoComissao?.Text ?? string.Empty,
+ ValorComissao = vComissao,
+ TempoEstimado = tEstimado,
+ Ativo = chkAtivo?.Checked ?? false,
+ CriadoEm = string.IsNullOrEmpty(txtCriadoEm?.Text) ? DateTime.Now : Convert.ToDateTime(txtCriadoEm.Text),
+ AtualizadoEm = DateTime.Now // Sempre carimba a hora do salvamento atual
+ };
+
+ // Aqui o objeto 'servico' está pronto para ser enviado para sua camada de persistência (BLL / DAL)
+ MessageBox.Show($"Serviço '{servico.Nome}' salvo com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNome?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja realmente remover este serviço do catálogo?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Vinculado à Grid de busca global de serviços
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/SituacoesOSPanel.cs b/UI/Dashboards/Cadastros/SituacoesOSPanel.cs
new file mode 100644
index 0000000..a97d8f6
--- /dev/null
+++ b/UI/Dashboards/Cadastros/SituacoesOSPanel.cs
@@ -0,0 +1,186 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Cadastro
+{
+ public class SituacoesOSPanel : FormularioModelo
+ {
+ // Controles marcados como anuláveis para sanar avisos do compilador modernos (NRT)
+ private LV_TEXTBOX1? txtId, txtEmpresaId, txtDescricao, txtTipo, txtCorFundo, txtCorFonte, txtPlanoContasId, txtOrdem, txtCriadoEm, txtAtualizadoEm;
+ private CheckBox? chkConsideraAberta, chkConsideraFechada, chkMarcaComoPronto, chkAtivo;
+
+ public SituacoesOSPanel()
+ {
+ this.Titulo = "SITUAÇÕES E STATUS DE ORDENS DE SERVIÇO (OS)";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: IDENTIFICAÇÃO E ESPECIFICAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Identificação do Status da OS", 20));
+
+ txtId = AddInput(content, "ID SITUAÇÃO", 20, 55, 100, 28, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA", 135, 55, 100, 28);
+ txtDescricao = AddInput(content, "DESCRIÇÃO DO STATUS (EX: EM ANDAMENTO)", 250, 55, 350, 28);
+ txtTipo = AddInput(content, "TIPO", 615, 55, 140, 28);
+
+ chkAtivo = new CheckBox
+ {
+ Text = "Status Ativo",
+ Location = new Point(770, 58),
+ Size = new Size(110, 24),
+ Font = new Font("Segoe UI", 10f, FontStyle.Bold),
+ ForeColor = Color.FromArgb(45, 45, 45),
+ Checked = true
+ };
+ content.Controls.Add(chkAtivo);
+
+ // --- SEÇÃO 2: REGRAS DE COMPORTAMENTO ---
+ content.Controls.Add(CreateSectionHeader("Comportamento e Regras de Negócio no Fluxo de OS", 115));
+
+ chkConsideraAberta = new CheckBox
+ {
+ Text = "Considerar OS Aberta (Pendente / Em Execução)",
+ Location = new Point(25, 150),
+ Size = new Size(350, 24),
+ Font = new Font("Segoe UI", 9.5f)
+ };
+
+ chkConsideraFechada = new CheckBox
+ {
+ Text = "Considerar OS Fechada (Finalizada / Encerrada)",
+ Location = new Point(400, 150),
+ Size = new Size(350, 24),
+ Font = new Font("Segoe UI", 9.5f)
+ };
+
+ chkMarcaComoPronto = new CheckBox
+ {
+ Text = "Marcar OS como Pronta (Aguardando Retirada / Entrega)",
+ Location = new Point(25, 185),
+ Size = new Size(450, 24),
+ Font = new Font("Segoe UI", 9.5f)
+ };
+
+ content.Controls.AddRange(new Control[] { chkConsideraAberta, chkConsideraFechada, chkMarcaComoPronto });
+
+ // --- SEÇÃO 3: INTEGRALIZAÇÃO, CORES E TRIAGEM ---
+ content.Controls.Add(CreateSectionHeader("Integração Financeira, Ordenação e Identidade Visual", 235));
+
+ txtPlanoContasId = AddInput(content, "ID PLANO DE CONTAS", 20, 270, 150, 28);
+ txtOrdem = AddInput(content, "ORDEM DE EXIBIÇÃO", 185, 270, 140, 28);
+ txtCorFundo = AddInput(content, "COR DO FUNDO (HEX)", 340, 270, 180, 28);
+ txtCorFonte = AddInput(content, "COR DA FONTE (HEX)", 535, 270, 180, 28);
+
+ // --- SEÇÃO 4: AUDITORIA ---
+ content.Controls.Add(CreateSectionHeader("Histórico do Registro", 335));
+
+ txtCriadoEm = AddInput(content, "DATA DE CRIAÇÃO", 20, 370, 180, 28, true);
+ txtAtualizadoEm = AddInput(content, "ÚLTIMA ATUALIZAÇÃO", 215, 370, 180, 28, true);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa caixas de texto editáveis
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+
+ // Reseta CheckBoxes
+ if (chkConsideraAberta != null) chkConsideraAberta.Checked = false;
+ if (chkConsideraFechada != null) chkConsideraFechada.Checked = false;
+ if (chkMarcaComoPronto != null) chkMarcaComoPronto.Checked = false;
+ if (chkAtivo != null) chkAtivo.Checked = true;
+
+ // Valores padrão iniciais
+ if (txtId != null) txtId.Text = "0";
+ if (txtEmpresaId != null) txtEmpresaId.Text = "1";
+ if (txtOrdem != null) txtOrdem.Text = "1";
+ if (txtCorFundo != null) txtCorFundo.Text = "#FFFFFF";
+ if (txtCorFonte != null) txtCorFonte.Text = "#000000";
+
+ if (txtCriadoEm != null) txtCriadoEm.Text = DateTime.Now.ToString("g");
+ if (txtAtualizadoEm != null) txtAtualizadoEm.Text = DateTime.Now.ToString("g");
+
+ txtDescricao?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (string.IsNullOrWhiteSpace(txtDescricao?.Text))
+ {
+ MessageBox.Show("A descrição do status da OS é obrigatória.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtDescricao?.Focus();
+ return;
+ }
+
+ // Tratamento resiliente de inteiros
+ int idStatus = string.IsNullOrEmpty(txtId?.Text) ? 0 : Convert.ToInt32(txtId.Text);
+ int idEmpresa = string.IsNullOrEmpty(txtEmpresaId?.Text) ? 0 : Convert.ToInt32(txtEmpresaId.Text);
+
+ // Tratamento seguro de inteiros anuláveis (int?)
+ int? planoContasId = null;
+ if (!string.IsNullOrWhiteSpace(txtPlanoContasId?.Text) && int.TryParse(txtPlanoContasId.Text, out int pcParsed))
+ planoContasId = pcParsed;
+
+ int? ordemExibicao = null;
+ if (!string.IsNullOrWhiteSpace(txtOrdem?.Text) && int.TryParse(txtOrdem.Text, out int ordParsed))
+ ordemExibicao = ordParsed;
+
+ // Mapeamento absoluto de todas as 14 propriedades da classe ModeloSituacoesOS
+ var situacaoOS = new ModeloSituacoesOS
+ {
+ Id = idStatus,
+ EmpresaId = idEmpresa,
+ Descricao = txtDescricao.Text,
+ Tipo = txtTipo?.Text ?? string.Empty,
+ ConsideraAberta = chkConsideraAberta?.Checked ?? false,
+ ConsideraFechada = chkConsideraFechada?.Checked ?? false,
+ MarcaComoPronto = chkMarcaComoPronto?.Checked ?? false,
+ CorFundo = txtCorFundo?.Text ?? string.Empty,
+ CorFonte = txtCorFonte?.Text ?? string.Empty,
+ PlanoContasId = planoContasId,
+ Ordem = ordemExibicao,
+ Ativo = chkAtivo?.Checked ?? false,
+ CriadoEm = string.IsNullOrEmpty(txtCriadoEm?.Text) ? DateTime.Now : Convert.ToDateTime(txtCriadoEm.Text),
+ AtualizadoEm = DateTime.Now // Atualiza o carimbo de data
+ };
+
+ // Envio do objeto estruturado para a persistência em banco de dados SQL Server via BLL/DAL
+ MessageBox.Show($"Status de OS '{situacaoOS.Descricao}' salvo com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtDescricao?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("A exclusão deste status pode invalidar o histórico de fluxo das ordens de serviço associadas. Deseja continuar?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aciona o grid interno para localização de status de OS existentes
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/SituacoesPanel.cs b/UI/Dashboards/Cadastros/SituacoesPanel.cs
new file mode 100644
index 0000000..ef05fb8
--- /dev/null
+++ b/UI/Dashboards/Cadastros/SituacoesPanel.cs
@@ -0,0 +1,135 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Cadastro
+{
+ public class SituacoesPanel : FormularioModelo
+ {
+ // Controles marcados como anuláveis para sanar avisos do compilador modernos (NRT)
+ private LV_TEXTBOX1? txtIdSituacoes;
+ private LV_TEXTBOX1? txtCodigo;
+ private LV_TEXTBOX1? txtNome;
+ private LV_TEXTBOX1? txtEtapa1;
+ private LV_TEXTBOX1? txtEtapa2;
+ private LV_TEXTBOX1? txtEtapa3;
+ private LV_TEXTBOX1? txtEtapa3Pg;
+ private LV_TEXTBOX1? txtPronto;
+ private LV_TEXTBOX1? txtSubgrupo;
+ private LV_TEXTBOX1? txtCorFonte;
+ private LV_TEXTBOX1? txtCorFundo;
+ private LV_TEXTBOX1? txtPlanoConta;
+
+ public SituacoesPanel()
+ {
+ this.Titulo = "CADASTRO E CONFIGURAÇÃO DE SITUAÇÕES / STATUS";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: IDENTIFICAÇÃO DO STATUS ---
+ content.Controls.Add(CreateSectionHeader("Identificação do Status", 20));
+
+ txtIdSituacoes = AddInput(content, "ID SITUAÇÃO", 20, 55, 110, 28, true);
+ txtCodigo = AddInput(content, "CÓDIGO INTERNO", 145, 55, 130, 28);
+ txtNome = AddInput(content, "NOME DA SITUAÇÃO / STATUS", 290, 55, 350, 28);
+ txtSubgrupo = AddInput(content, "SUBGRUPO", 655, 55, 150, 28);
+
+ // --- SEÇÃO 2: REGRAS E ETAPAS DO FLUXO ---
+ content.Controls.Add(CreateSectionHeader("Etapas e Regras do Fluxo de Trabalho", 115));
+
+ txtEtapa1 = AddInput(content, "ETAPA 1 (EX: TRIAGEM)", 20, 150, 185, 28);
+ txtEtapa2 = AddInput(content, "ETAPA 2 (EX: EM PROCESSO)", 220, 150, 185, 28);
+ txtEtapa3 = AddInput(content, "ETAPA 3 (EX: CONCLUÍDO)", 420, 150, 185, 28);
+ txtEtapa3Pg = AddInput(content, "ETAPA 3 PG (PAGO)", 620, 150, 185, 28);
+
+ txtPronto = AddInput(content, "INDICADOR PRONTO (S/N)", 20, 210, 185, 28);
+ txtPlanoConta = AddInput(content, "VÍNCULO PLANO DE CONTAS", 220, 210, 385, 28);
+
+ // --- SEÇÃO 3: ESTILIZAÇÃO VISUAL (GRID / KANBAN) ---
+ content.Controls.Add(CreateSectionHeader("Estilização Visual (Exibição em Telas e Grids)", 275));
+
+ txtCorFonte = AddInput(content, "COR DA FONTE (HEX: #FFFFFF)", 20, 310, 230, 28);
+ txtCorFundo = AddInput(content, "COR DO FUNDO (HEX: #007ACC)", 265, 310, 230, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Varre e limpa de forma segura todos os campos que não são somente leitura
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+
+ if (txtIdSituacoes != null) txtIdSituacoes.Text = "0";
+ if (txtPronto != null) txtPronto.Text = "N";
+ if (txtCorFonte != null) txtCorFonte.Text = "#000000";
+ if (txtCorFundo != null) txtCorFundo.Text = "#FFFFFF";
+
+ txtCodigo?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (string.IsNullOrWhiteSpace(txtNome?.Text))
+ {
+ MessageBox.Show("O nome da situação é obrigatório para mapear os fluxos.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNome?.Focus();
+ return;
+ }
+
+ int idSituacoes = string.IsNullOrEmpty(txtIdSituacoes?.Text) ? 0 : Convert.ToInt32(txtIdSituacoes.Text);
+
+ // Mapeamento absoluto, limpo e direto de todas as propriedades da classe
+ var situacao = new ModeloSituacoes
+ {
+ ID_SITUACOES = idSituacoes,
+ CODIGO = txtCodigo?.Text ?? string.Empty,
+ NOME = txtNome.Text,
+ ETAPA1 = txtEtapa1?.Text ?? string.Empty,
+ ETAPA2 = txtEtapa2?.Text ?? string.Empty,
+ ETAPA3 = txtEtapa3?.Text ?? string.Empty,
+ ETAPA3_PG = txtEtapa3Pg?.Text ?? string.Empty,
+ PRONTO = txtPronto?.Text ?? string.Empty,
+ SUBGRUPO = txtSubgrupo?.Text ?? string.Empty,
+ COR_FONTE = txtCorFonte?.Text ?? string.Empty,
+ COR_FUNDO = txtCorFundo?.Text ?? string.Empty,
+ PLANO_CONTA = txtPlanoConta?.Text ?? string.Empty
+ };
+
+ // Objeto preenchido pronto para ser enviado para sua BLL / DAL e persistido no SQL Server
+ MessageBox.Show($"Situação '{situacao.NOME}' configurada com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNome?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("A exclusão deste status pode afetar registros históricos vinculados a ele. Confirma?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Abre o grid de consulta para selecionar uma situação existente
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/UsuarioPerfisPanel.cs b/UI/Dashboards/Cadastros/UsuarioPerfisPanel.cs
new file mode 100644
index 0000000..e4a1182
--- /dev/null
+++ b/UI/Dashboards/Cadastros/UsuarioPerfisPanel.cs
@@ -0,0 +1,164 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Cadastro
+{
+ public class UsuarioPerfisPanel : FormularioModelo
+ {
+ // Controles marcados como anuláveis para sanar avisos do compilador modernos (NRT)
+ private LV_TEXTBOX1? txtId;
+ private ComboBox? cbUsuario;
+ private CheckedListBox? clbPerfis;
+
+ public UsuarioPerfisPanel()
+ {
+ this.Titulo = "VÍNCULO DE PERFIS DE ACESSO POR USUÁRIO";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: IDENTIFICAÇÃO E SELEÇÃO DO USUÁRIO ---
+ content.Controls.Add(CreateSectionHeader("Seleção do Operador / Usuário", 20));
+
+ txtId = AddInput(content, "ID VÍNCULO", 20, 55, 100, 28, true);
+
+ // Label para o ComboBox de Usuário
+ var lblUsuario = new Label
+ {
+ Text = "SELECIONE O USUÁRIO DO SISTEMA",
+ Location = new Point(135, 40),
+ AutoSize = true,
+ Font = new Font("Segoe UI", 8.25f, FontStyle.Bold),
+ ForeColor = Color.FromArgb(90, 90, 90)
+ };
+
+ cbUsuario = new ComboBox
+ {
+ Location = new Point(135, 57),
+ Size = new Size(500, 28),
+ DropDownStyle = ComboBoxStyle.DropDownList,
+ Font = new Font("Segoe UI", 10f)
+ };
+
+ content.Controls.AddRange(new Control[] { lblUsuario, cbUsuario });
+
+ // --- SEÇÃO 2: ATRIBUIÇÃO DOS PERFIS ---
+ content.Controls.Add(CreateSectionHeader("Perfis de Segurança e Permissões Disponíveis", 115));
+
+ // CheckedListBox para o operador marcar múltiplos perfis de forma nativa e intuitiva
+ clbPerfis = new CheckedListBox
+ {
+ Location = new Point(20, 150),
+ Size = new Size(615, 250),
+ Font = new Font("Segoe UI", 10f),
+ CheckOnClick = true,
+ BorderStyle = BorderStyle.FixedSingle
+ };
+ content.Controls.Add(clbPerfis);
+
+ CarregarDadosIniciais();
+ }
+
+ private void CarregarDadosIniciais()
+ {
+ // Simulação de preenchimento dos combos (Aqui você chamará suas BLLs correspondentes)
+ if (cbUsuario != null)
+ {
+ cbUsuario.Items.Add("Selecione um operador...");
+ cbUsuario.Items.Add("Nicolas - Administrador do Sistema");
+ cbUsuario.Items.Add("Davi - Operador de Caixa");
+ cbUsuario.SelectedIndex = 0;
+ }
+
+ if (clbPerfis != null)
+ {
+ clbPerfis.Items.Add("ADMINISTRADOR GLOBAL");
+ clbPerfis.Items.Add("FANCEIRO / CONTÁBIL");
+ clbPerfis.Items.Add("VENDEDOR / EMISSOR NFC-E");
+ clbPerfis.Items.Add("SUPORTE TÉCNICO (ORDEM DE SERVIÇO)");
+ }
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ if (txtId != null) txtId.Text = "0";
+
+ if (cbUsuario != null && cbUsuario.Items.Count > 0)
+ cbUsuario.SelectedIndex = 0;
+
+ if (clbPerfis != null)
+ {
+ for (int i = 0; i < clbPerfis.Items.Count; i++)
+ {
+ clbPerfis.SetItemChecked(i, false);
+ }
+ }
+
+ cbUsuario?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (cbUsuario == null || cbUsuario.SelectedIndex <= 0)
+ {
+ MessageBox.Show("Por favor, selecione um usuário válido para aplicar as permissões.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ cbUsuario?.Focus();
+ return;
+ }
+
+ if (clbPerfis == null || clbPerfis.CheckedItems.Count == 0)
+ {
+ MessageBox.Show("Selecione ao menos um perfil de acesso para este usuário.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ clbPerfis?.Focus();
+ return;
+ }
+
+ int idVinculo = string.IsNullOrEmpty(txtId?.Text) ? 0 : Convert.ToInt32(txtId.Text);
+
+ // Loop para ler os perfis checados e montar os objetos associativos
+ // Como é uma tabela NxN, você gerará um registro para cada Perfil Id associado àquele UsuarioId
+ foreach (var itemMarcado in clbPerfis.CheckedItems)
+ {
+ var usuarioPerfil = new ModeloUsuarioPerfis
+ {
+ Id = idVinculo,
+ UsuarioId = cbUsuario.SelectedIndex, // Mock simulando o ID recuperado do ValueMember
+ PerfilId = clbPerfis.Items.IndexOf(itemMarcado) + 1 // Mock simulando o ID do Perfil
+ };
+
+ // Aqui sua BLL/DAL processará cada vínculo (Inserindo ou deletando os antigos antes)
+ }
+
+ MessageBox.Show("Políticas e perfis de acesso atualizados com sucesso!", "LevelOS - Segurança", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ cbUsuario?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja revogar TODOS os perfis de acesso deste usuário? O operador perderá acesso às telas do sistema.", "LevelOS - Segurança", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Vinculado à busca global de associações de segurança
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Cadastros/UsuariosPanel.cs b/UI/Dashboards/Cadastros/UsuariosPanel.cs
new file mode 100644
index 0000000..ade92da
--- /dev/null
+++ b/UI/Dashboards/Cadastros/UsuariosPanel.cs
@@ -0,0 +1,167 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Cadastro
+{
+ public class UsuariosPanel : FormularioModelo
+ {
+ // Controles marcados como anuláveis para sanar avisos de compilação modernos (.NET 8 NRT)
+ private LV_TEXTBOX1? txtId;
+ private LV_TEXTBOX1? txtEmpresaId;
+ private LV_TEXTBOX1? txtNome;
+ private LV_TEXTBOX1? txtEmail;
+ private LV_TEXTBOX1? txtUsuario;
+ private LV_TEXTBOX1? txtSenhaHash;
+ private LV_TEXTBOX1? txtUltimoLogin;
+ private LV_TEXTBOX1? txtCriadoEm;
+ private LV_TEXTBOX1? txtAtualizadoEm;
+ private CheckBox? chkAtivo;
+
+ public UsuariosPanel()
+ {
+ this.Titulo = "GESTÃO E CONTROLE DE USUÁRIOS";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: IDENTIFICAÇÃO DO COLABORADOR ---
+ content.Controls.Add(CreateSectionHeader("Identificação do Operador", 20));
+
+ txtId = AddInput(content, "ID USUÁRIO", 20, 55, 100, 28, true);
+ txtEmpresaId = AddInput(content, "ID EMPRESA VÍNCULO", 135, 55, 130, 28);
+ txtNome = AddInput(content, "NOME COMPLETO", 280, 55, 370, 28);
+
+ chkAtivo = new CheckBox
+ {
+ Text = "Usuário Ativo",
+ Location = new Point(665, 58),
+ Size = new Size(120, 24),
+ Font = new Font("Segoe UI", 10f, FontStyle.Bold),
+ ForeColor = Color.FromArgb(45, 45, 45),
+ Checked = true
+ };
+ content.Controls.Add(chkAtivo);
+
+ txtEmail = AddInput(content, "E-MAIL DE CONTATO", 20, 115, 630, 28);
+
+ // --- SEÇÃO 2: CREDENCIAIS E AUTENTICAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Credenciais de Autenticação e Segurança", 185));
+
+ txtUsuario = AddInput(content, "NOME DE USUÁRIO / LOGIN", 20, 220, 250, 28);
+
+ // Campo de senha configurado nativamente para ocultar a digitação
+ txtSenhaHash = AddInput(content, "SENHA DE ACESSO", 285, 220, 250, 28);
+ if (txtSenhaHash != null)
+ {
+ txtSenhaHash.UseSystemPasswordChar = true;
+ }
+
+ // --- SEÇÃO 3: AUDITORIA E LOGS ---
+ content.Controls.Add(CreateSectionHeader("Histórico e Auditoria de Acessos", 290));
+
+ txtUltimoLogin = AddInput(content, "ÚLTIMO LOGIN", 20, 325, 200, 28, true);
+ txtCriadoEm = AddInput(content, "DATA DE CRIAÇÃO", 235, 325, 180, 28, true);
+ txtAtualizadoEm = AddInput(content, "ÚLTIMA ATUALIZAÇÃO", 430, 325, 180, 28, true);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa de forma iterativa todas as caixas de texto editáveis do painel
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+
+ if (txtId != null) txtId.Text = "0";
+ if (txtEmpresaId != null) txtEmpresaId.Text = "1";
+ if (txtUltimoLogin != null) txtUltimoLogin.Text = "Nunca Conectado";
+
+ // Tratamento como string para exibição visual imediata das datas padrões
+ if (txtCriadoEm != null) txtCriadoEm.Text = DateTime.Now.ToString("g");
+ if (txtAtualizadoEm != null) txtAtualizadoEm.Text = DateTime.Now.ToString("g");
+
+ if (chkAtivo != null) chkAtivo.Checked = true;
+
+ txtNome?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (string.IsNullOrWhiteSpace(txtNome?.Text))
+ {
+ MessageBox.Show("O nome completo do operador é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtNome?.Focus();
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(txtUsuario?.Text))
+ {
+ MessageBox.Show("O login do usuário é obrigatório para autenticação.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtUsuario?.Focus();
+ return;
+ }
+
+ int idUsuario = string.IsNullOrEmpty(txtId?.Text) ? 0 : Convert.ToInt32(txtId.Text);
+ int idEmpresa = string.IsNullOrEmpty(txtEmpresaId?.Text) ? 0 : Convert.ToInt32(txtEmpresaId.Text);
+
+ // Parsing resiliente de datas anuláveis (DateTime?) baseadas na interface
+ DateTime? ultimoLogin = null;
+ if (!string.IsNullOrEmpty(txtUltimoLogin?.Text) && DateTime.TryParse(txtUltimoLogin.Text, out DateTime ulParsed))
+ ultimoLogin = ulParsed;
+
+ DateTime? criadoEm = null;
+ if (!string.IsNullOrEmpty(txtCriadoEm?.Text) && DateTime.TryParse(txtCriadoEm.Text, out DateTime cParsed))
+ criadoEm = cParsed;
+
+ // Mapeamento absoluto das 10 propriedades da classe ModeloUsuarios
+ var usuario = new ModeloUsuarios
+ {
+ Id = idUsuario,
+ EmpresaId = idEmpresa,
+ Nome = txtNome.Text,
+ Email = txtEmail?.Text ?? string.Empty,
+ Usuario = txtUsuario.Text,
+ SenhaHash = txtSenhaHash?.Text ?? string.Empty, // Lembre-se de hashear (ex: SHA256/BCrypt) na sua BLL antes do banco
+ Ativo = chkAtivo?.Checked ?? false,
+ UltimoLogin = ultimoLogin,
+ CriadoEm = criadoEm,
+ AtualizadoEm = DateTime.Now // Carimba o momento exato da persistência
+ };
+
+ // Objeto completo pronto para ser passado à sua camada de regras de negócio (BLL)
+ MessageBox.Show($"Usuário '{usuario.Usuario}' salvo com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNome?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Confirma a exclusão deste operador? O acesso ao sistema será revogado imediatamente.", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aciona a Grid / Busca Geral de usuários cadastrados
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Configurações/ParametrosPanel.cs b/UI/Dashboards/Configurações/ParametrosPanel.cs
new file mode 100644
index 0000000..ff8085f
--- /dev/null
+++ b/UI/Dashboards/Configurações/ParametrosPanel.cs
@@ -0,0 +1,121 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class ParametrosPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todas as propriedades do ModeloParametros
+ private LV_TEXTBOX1 txtIdParametros;
+ private LV_TEXTBOX1 txtCodigo;
+ private LV_TEXTBOX1 txtNomePar;
+ private LV_TEXTBOX1 txtDescricao;
+ private LV_TEXTBOX1 txtPx;
+ private LV_TEXTBOX1 txtPy;
+ private LV_TEXTBOX1 txtCampo;
+ private CheckBox chkAtivo;
+
+ public ParametrosPanel()
+ {
+ this.Titulo = "CADASTRO E POSICIONAMENTO DE PARAMETROS";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: IDENTIFICAÇÃO E CHAVES ---
+ content.Controls.Add(CreateSectionHeader("Identificação do Parâmetro", 20));
+
+ txtIdParametros = AddInput(content, "ID REGISTRO", 20, 55, 100, 28, true);
+ txtCodigo = AddInput(content, "CÓDIGO INTERNO", 130, 55, 120, 28);
+ txtNomePar = AddInput(content, "NOME DO PARÂMETRO (CHAVE)", 260, 55, 300, 28);
+
+ // Status Ativo/Inativo usando o posicionamento padrão
+ chkAtivo = new CheckBox
+ {
+ Text = "Parâmetro Ativo no Sistema",
+ Location = new Point(580, 71),
+ AutoSize = true,
+ Font = new Font("Segoe UI", 10F, FontStyle.Bold),
+ ForeColor = Color.FromArgb(64, 64, 64),
+ Checked = true
+ };
+ content.Controls.Add(chkAtivo);
+
+ // --- SEÇÃO 2: MAPEAMENTO DE COORDENADAS E INTERFACE ---
+ content.Controls.Add(CreateSectionHeader("Posicionamento e Mapeamento de Tela / Relatório", 115));
+
+ txtCampo = AddInput(content, "CAMPO DA TABELA / CONTROLE ALVO", 20, 150, 350, 28);
+ txtPx = AddInput(content, "COORDENADA X (PIXELS / COLUNA)", 390, 150, 200, 28);
+ txtPy = AddInput(content, "COORDENADA Y (PIXELS / LINHA)", 600, 150, 200, 28);
+
+ // --- SEÇÃO 3: DETALHAMENTO ---
+ content.Controls.Add(CreateSectionHeader("Documentação e Regras", 210));
+
+ txtDescricao = AddInput(content, "DESCRIÇÃO DA FUNÇÃO DO PARÂMETRO", 20, 245, 780, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Limpa todos os controles de texto dentro do content
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+
+ chkAtivo.Checked = true;
+ txtCodigo.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Mapeamento absoluto e fiel de cada campo para o objeto MLL
+ var parametro = new ModeloParametros
+ {
+ ID_PARAMETROS = string.IsNullOrEmpty(txtIdParametros.Text) ? 0 : Convert.ToInt32(txtIdParametros.Text),
+ CODIGO = txtCodigo.Text,
+ NOME_PAR = txtNomePar.Text,
+ DESCRICAO = txtDescricao.Text,
+ PX = txtPx.Text,
+ PY = txtPy.Text,
+ CAMPO = txtCampo.Text,
+ ATIVO = chkAtivo.Checked ? "S" : "N" // Conversão limpa para persistência string do seu banco
+ };
+
+ // Envio direto do objeto populado para as suas camadas de persistência (BLL/DAL)
+ MessageBox.Show("Configuração de parâmetro salva com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtNomePar.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja realmente excluir este parâmetro? Isso pode afetar o layout de telas ou relatórios.", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Processa a exclusão...
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Vincula a abertura da sua Grid de pesquisa de parâmetros
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Financeiro/VendasPanel.cs b/UI/Dashboards/Financeiro/VendasPanel.cs
new file mode 100644
index 0000000..4ea12cd
--- /dev/null
+++ b/UI/Dashboards/Financeiro/VendasPanel.cs
@@ -0,0 +1,223 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Cadastro
+{
+ public class VendasPanel : FormularioModelo
+ {
+ // Container de abas para as 27 propriedades do modelo
+ private TabControl? tabVendas;
+
+ // --- ABA 1: RESUMO DO PEDIDO & CLIENTE ---
+ private LV_TEXTBOX1? txtIdVendas, txtCodigo, txtCliente, txtOperador, txtOperador2, txtDia, txtSituacaoV;
+
+ // --- ABA 2: FINANCEIRO E VALORES DE VENDA ---
+ private LV_TEXTBOX1? txtTotal, txtDesconto, txtTotalGeral, txtTotalServicos, txtTotalPecas, txtComissao, txtComissaoFixar;
+
+ // --- ABA 3: EXPEDIÇÃO, LOGÍSTICA & INTEGRAÇÃO ---
+ private LV_TEXTBOX1? txtTotalFrete, txtTransportadora, txtRastreio, txtGerouConta;
+
+ // --- ABA 4: FATURAMENTO FISCAL E OBSERVAÇÕES ---
+ private LV_TEXTBOX1? txtNfTipo, txtNfNumero, txtNfcNumero, txtNfsNumero, txtCupomNum, txtCancelada, txtObsVenda, txtObsVendaInterna;
+
+ public VendasPanel()
+ {
+ this.Titulo = "PDV - CENTRALIZADOR DE VENDAS E FATURAMENTO";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ tabVendas = new TabControl
+ {
+ Location = new Point(10, 10),
+ Size = new Size(1060, 520),
+ Font = new Font("Segoe UI", 9.5f)
+ };
+
+ var tpGeral = new TabPage("1. Cabeçalho da Venda");
+ var tpValores = new TabPage("2. Totais e Precificação");
+ var tpLogistica = new TabPage("3. Despacho e Logística");
+ var tpFiscal = new TabPage("4. Fiscal & Observações");
+
+ tabVendas.TabPages.AddRange([tpGeral, tpValores, tpLogistica, tpFiscal]);
+ content.Controls.Add(tabVendas);
+
+ ConfigurarAbaGeral(tpGeral);
+ ConfigurarAbaValores(tpValores);
+ ConfigurarAbaLogistica(tpLogistica);
+ ConfigurarAbaFiscal(tpFiscal);
+ }
+
+ private void ConfigurarAbaGeral(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Identificação Básica do Fluxo Comercial", 15));
+ txtIdVendas = AddInput(tp, "ID VENDA (SISTEMA)", 20, 50, 130, 28, true);
+ txtCodigo = AddInput(tp, "CÓDIGO PEDIDO / ORÇAMENTO", 165, 50, 180, 28);
+ txtDia = AddInput(tp, "DATA DA VENDA", 360, 50, 160, 28);
+ txtSituacaoV = AddInput(tp, "SITUAÇÃO / STATUS", 535, 50, 150, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Operadores e Cliente Vinculado", 115));
+ txtCliente = AddInput(tp, "CLIENTE (NOME / RAZÃO SOCIAL)", 20, 150, 665, 28);
+ txtOperador = AddInput(tp, "OPERADOR PRINCIPAL (CAIXA / VENDEDOR)", 20, 210, 325, 28);
+ txtOperador2 = AddInput(tp, "OPERADOR 2 (ASSISTENTE / GERENTE)", 360, 210, 325, 28);
+ }
+
+ private void ConfigurarAbaValores(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Divisão de Subtotais do Cupom / Pedido", 15));
+ txtTotalPecas = AddInput(tp, "TOTAL PRODUTOS / PEÇAS (+)", 20, 50, 210, 28);
+ txtTotalServicos = AddInput(tp, "TOTAL SERVIÇOS (+)", 245, 50, 210, 28);
+ txtDesconto = AddInput(tp, "DESCONTO APLICADO (-)", 470, 50, 215, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Fechamento Líquido e Comissionamento", 115));
+ txtTotal = AddInput(tp, "SUBTOTAL BRUTO (R$)", 20, 150, 210, 28);
+ txtTotalGeral = AddInput(tp, "TOTAL GERAL LÍQUIDO (R$)", 245, 150, 210, 28);
+
+ txtComissao = AddInput(tp, "COMISSÃO OPERADOR (R$ ou %)", 20, 210, 210, 28);
+ txtComissaoFixar = AddInput(tp, "VALOR COMISSÃO FIXA (R$)", 245, 210, 210, 28);
+ }
+
+ private void ConfigurarAbaLogistica(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Custos e Vinculações de Despacho", 15));
+ txtTotalFrete = AddInput(tp, "VALOR DO FRETE (R$)", 20, 50, 180, 28);
+ txtTransportadora = AddInput(tp, "TRANSPORTADORA PARCEIRA", 215, 50, 465, 28);
+ txtRastreio = AddInput(tp, "CÓDIGO DE RASTREAMENTO DO OBJETO", 20, 115, 660, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Status Financeiro no Contas a Receber", 185));
+ txtGerouConta = AddInput(tp, "GEROU CONTA FINANCEIRA? (S/N)", 20, 220, 250, 28);
+ }
+
+ private void ConfigurarAbaFiscal(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Documentação Fiscal Emitida (NF-e / NFC-e / NFS-e)", 15));
+ txtNfTipo = AddInput(tp, "TIPO DA NOTA (E/S)", 20, 50, 130, 28);
+ txtNfNumero = AddInput(tp, "NÚMERO NF-E", 165, 50, 160, 28);
+ txtNfcNumero = AddInput(tp, "NÚMERO NFC-E (CUPOM)", 340, 50, 160, 28);
+ txtNfsNumero = AddInput(tp, "NÚMERO NFS-E (SERVIÇO)", 515, 50, 160, 28);
+
+ txtCupomNum = AddInput(tp, "NÚMERO CONTROLE INTEGRAL / CUPOM", 20, 115, 225, 28);
+ txtCancelada = AddInput(tp, "VENDA CANCELADA? (S/N)", 260, 115, 215, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Observações do Pedido", 185));
+ txtObsVenda = AddInput(tp, "OBSERVAÇÕES PÚBLICAS (SAÍDA NA NOTA/IMPRESSÃO)", 20, 220, 660, 28);
+ txtObsVendaInterna = AddInput(tp, "OBSERVAÇÕES INTERNAS (RESTRITO AO SISTEMA)", 20, 280, 660, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ void LimparCamposFormulario(Control.ControlCollection controls)
+ {
+ foreach (Control c in controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly) txt.Text = string.Empty;
+ if (c.HasChildren) LimparCamposFormulario(c.Controls);
+ }
+ }
+
+ if (tabVendas != null)
+ {
+ LimparCamposFormulario(tabVendas.Controls);
+ tabVendas.SelectedIndex = 0;
+ }
+
+ if (txtIdVendas != null) txtIdVendas.Text = "0";
+ if (txtDia != null) txtDia.Text = DateTime.Today.ToString("dd/MM/yyyy");
+ if (txtSituacaoV != null) txtSituacaoV.Text = "ABERTA";
+ if (txtGerouConta != null) txtGerouConta.Text = "N";
+ if (txtCancelada != null) txtCancelada.Text = "N";
+
+ // Seta valores string como padrões limpos para evitar nulos visuais
+ if (txtTotal != null) txtTotal.Text = "0,00";
+ if (txtDesconto != null) txtDesconto.Text = "0,00";
+ if (txtTotalGeral != null) txtTotalGeral.Text = "0,00";
+ if (txtTotalServicos != null) txtTotalServicos.Text = "0,00";
+ if (txtTotalPecas != null) txtTotalPecas.Text = "0,00";
+ if (txtTotalFrete != null) txtTotalFrete.Text = "0,00";
+ if (txtComissao != null) txtComissao.Text = "0,00";
+ if (txtComissaoFixar != null) txtComissaoFixar.Text = "0,00";
+
+ txtCodigo?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (string.IsNullOrWhiteSpace(txtCliente?.Text))
+ {
+ MessageBox.Show("A definição do cliente é mandatória para faturar a venda.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ if (tabVendas != null) tabVendas.SelectedIndex = 0;
+ txtCliente?.Focus();
+ return;
+ }
+
+ int idVenda = string.IsNullOrEmpty(txtIdVendas?.Text) ? 0 : Convert.ToInt32(txtIdVendas.Text);
+
+ // Mapeamento absoluto de todas as 27 propriedades da classe ModeloVendas
+ // Como suas propriedades são todas string, passamos o fallback 'string.Empty' ou '0,00'
+ var venda = new ModeloVendas
+ {
+ ID_VENDAS = idVenda,
+ CODIGO = txtCodigo?.Text ?? string.Empty,
+ OPERADOR = txtOperador?.Text ?? string.Empty,
+ TOTAL = txtTotal?.Text ?? "0,00",
+ DIA = txtDia?.Text ?? string.Empty,
+ COMISSAO = txtComissao?.Text ?? "0,00",
+ CLIENTE = txtCliente.Text,
+ DESCONTO = txtDesconto?.Text ?? "0,00",
+ TOTAL_GERAL = txtTotalGeral?.Text ?? "0,00",
+ TOTAL_SERVICOS = txtTotalServicos?.Text ?? "0,00",
+ TOTAL_PECAS = txtTotalPecas?.Text ?? "0,00",
+ TOTAL_IMPOSTOS = "0,00", // Fallback padrão de tributos
+ TOTAL_FRETE = txtTotalFrete?.Text ?? "0,00",
+ TRANSPORTADORA = txtTransportadora?.Text ?? string.Empty,
+ NF_TIPO = txtNfTipo?.Text ?? string.Empty,
+ SITUACAO_V = txtSituacaoV?.Text ?? string.Empty,
+ NF_NUMERO = txtNfNumero?.Text ?? string.Empty,
+ OBS_VENDA = txtObsVenda?.Text ?? string.Empty,
+ GEROU_CONTA = txtGerouConta?.Text ?? "N",
+ CUPOM_NUM = txtCupomNum?.Text ?? string.Empty,
+ OPERADOR2 = txtOperador2?.Text ?? string.Empty,
+ COMISSAO_FIXA = txtComissaoFixar?.Text ?? "0,00",
+ RASTREIO = txtRastreio?.Text ?? string.Empty,
+ OBS_VENDA_INTERNA = txtObsVendaInterna?.Text ?? string.Empty,
+ CANCELADA = txtCancelada?.Text ?? "N",
+ NFC_NUMERO = txtNfcNumero?.Text ?? string.Empty,
+ NFS_NUMERO = txtNfsNumero?.Text ?? string.Empty
+ };
+
+ // Objeto completo pronto para a BLL gerenciar validações fiscais e dar o INSERT/UPDATE
+ MessageBox.Show($"Venda sob o código '{venda.CODIGO}' processada!", "LevelOS - PDV", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ if (tabVendas != null) tabVendas.SelectedIndex = 0;
+ txtCodigo?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Excluir uma venda pode comprometer a escrituração fiscal e os saldos de estoque. Deseja cancelar a venda em vez disso?", "LevelOS - Atenção", MessageBoxButtons.YesNo, MessageBoxIcon.Hand) == DialogResult.Yes)
+ {
+ if (txtCancelada != null) txtCancelada.Text = "S";
+ OnSalvar();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Aciona o grid de histórico geral de cupons e faturamentos
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Fiscal/SatFiscalConsumidorFormasPanel.cs b/UI/Dashboards/Fiscal/SatFiscalConsumidorFormasPanel.cs
new file mode 100644
index 0000000..79bedbb
--- /dev/null
+++ b/UI/Dashboards/Fiscal/SatFiscalConsumidorFormasPanel.cs
@@ -0,0 +1,126 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI
+{
+ public class SatFiscalConsumidorFormasPanel : FormularioModelo
+ {
+ // Mapeamento absoluto de todas as propriedades do ModeloSatFiscalConsumidorFormas
+ private LV_TEXTBOX1 txtIdSatFiscalConsFormas;
+ private LV_TEXTBOX1 txtCodigo;
+ private LV_TEXTBOX1 txtCodNfce;
+ private LV_TEXTBOX1 txtForma;
+ private LV_TEXTBOX1 txtValor;
+ private LV_TEXTBOX1 txtDataCadastro;
+ private LV_TEXTBOX1 txtCnpjOperadora;
+ private LV_TEXTBOX1 txtTBand;
+
+ public SatFiscalConsumidorFormasPanel()
+ {
+ this.Titulo = "DETALHAMENTO DE FORMAS DE PAGAMENTO (NFC-E / SAT)";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // --- SEÇÃO 1: VÍNCULOS DA OPERAÇÃO ---
+ content.Controls.Add(CreateSectionHeader("Vínculos Fiscais e Código da Transação", 20));
+
+ txtIdSatFiscalConsFormas = AddInput(content, "ID REGISTRO", 20, 55, 110, 28, true);
+ txtCodigo = AddInput(content, "CÓDIGO INTERNO", 145, 55, 140, 28);
+ txtCodNfce = AddInput(content, "CÓD. VÍNCULO NFC-E / SAT", 300, 55, 200, 28);
+ txtDataCadastro = AddInput(content, "DATA DO LANÇAMENTO", 515, 55, 180, 28, true);
+
+ // --- SEÇÃO 2: DETALHES DO PAGAMENTO ---
+ content.Controls.Add(CreateSectionHeader("Valores e Regras do Meio de Pagamento (SEFAZ)", 115));
+
+ txtForma = AddInput(content, "FORMA (EX: 01-DINHEIRO, 03-CARTÃO CRÉDITO)", 20, 150, 320, 28);
+ txtValor = AddInput(content, "VALOR INTEGRADO (R$)", 355, 150, 150, 28);
+
+ // --- SEÇÃO 3: DADOS DE CARTÃO / TEF ---
+ content.Controls.Add(CreateSectionHeader("Identificação de Operações com Cartão (Crédito/Débito)", 210));
+
+ txtCnpjOperadora = AddInput(content, "CNPJ DA OPERADORA DO CARTÃO (ADQUIRENTE)", 20, 245, 320, 28);
+ txtTBand = AddInput(content, "CÓDIGO BANDEIRA (TBAND: 01-VISA, 02-MASTER)", 355, 245, 340, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Varre e limpa os inputs de forma segura
+ foreach (Control c in content.Controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly)
+ {
+ txt.Text = string.Empty;
+ }
+ }
+
+ txtIdSatFiscalConsFormas.Text = "0";
+ txtDataCadastro.Text = DateTime.Now.ToString("g");
+ txtCodNfce.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Validações básicas de negócio para evitar faturamento incompleto
+ if (string.IsNullOrWhiteSpace(txtCodNfce.Text))
+ {
+ MessageBox.Show("O código de vínculo da NFC-e é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtCodNfce.Focus();
+ return;
+ }
+
+ if (string.IsNullOrWhiteSpace(txtForma.Text))
+ {
+ MessageBox.Show("A forma de pagamento é obrigatória.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ txtForma.Focus();
+ return;
+ }
+
+ // Mapeamento absoluto, limpo e direto de todas as propriedades da classe
+ var formaPagamento = new ModeloSatFiscalConsumidorFormas
+ {
+ ID_SAT_FISCAL_CONS_FORMAS = string.IsNullOrEmpty(txtIdSatFiscalConsFormas.Text) ? 0 : Convert.ToInt32(txtIdSatFiscalConsFormas.Text),
+ CODIGO = txtCodigo.Text,
+ COD_NFCE = txtCodNfce.Text,
+ FORMA = txtForma.Text,
+ VALOR = txtValor.Text,
+ DATA_CADASTRO = txtDataCadastro.Text,
+ CNPJ_OPERADORA = txtCnpjOperadora.Text,
+ TBand = txtTBand.Text
+ };
+
+ // Envio do objeto preenchido para sua BLL / DAL para inserção ou update no SQL Server
+ MessageBox.Show("Forma de pagamento registrada com sucesso para o cupom fiscal!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtForma.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Deseja remover esta forma de pagamento? Isso alterará o balanço de fechamento do cupom fiscal.", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ // Processa a exclusão física...
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Abre o Grid para consultar as formas cadastradas neste cupom
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Fiscal/SatFiscalConsumidorItensPanel.cs b/UI/Dashboards/Fiscal/SatFiscalConsumidorItensPanel.cs
new file mode 100644
index 0000000..1d78f5a
--- /dev/null
+++ b/UI/Dashboards/Fiscal/SatFiscalConsumidorItensPanel.cs
@@ -0,0 +1,290 @@
+using CPM;
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace UI.Dashboards.Fiscal
+{
+ public class SatFiscalConsumidorItensPanel : FormularioModelo
+ {
+ // Aplicação de (?) para sanar os avisos de campos não nulos ao sair do construtor (NRT net8.0)
+ private TabControl? tabItens;
+
+ // --- ABA 1: DADOS GERAIS DO PRODUTO ---
+ private LV_TEXTBOX1? txtIdSatFiscalConsItens, txtCodigo, txtCodNfce, txtItemTipo, txtItemCean, txtItemCprod, txtItemXprod, txtItemInfAdic, txtDataCadastro;
+
+ // --- ABA 2: QUANTIDADES, VALORES E COMERCIAL ---
+ private LV_TEXTBOX1? txtItemCfop, txtItemNcm, txtItemUncom, txtItemQcom, txtItemVprod, txtItemVoutro, txtItemVfrete, txtItemVseg, txtItemVdesc, txtItemVTotTrib, txtItemCest, txtCProdAnp, txtCBenef;
+
+ // --- ABA 3: ICMS (NORMAL E ST) ---
+ private LV_TEXTBOX1? txtItemOrigem, txtItemCst, txtItemIcmsModBc, txtItemIcmsPRedBc, txtItemIcmsVBc, txtItemIcmsPIcms, txtItemIcmsVIcms, txtItemIcmsVIcmsDeson, txtItemIcmsMotDesIcms, txtItemIcmsModBcSt, txtItemIcmsPMvast, txtItemIcmsPRedBcSt, txtItemIcmsVBcSt, txtItemIcmsPIcmsSt, txtItemIcmsVIcmsSt;
+
+ // --- ABA 4: FCP (FUNDO DE COMBATE À POBREZA) ---
+ private LV_TEXTBOX1? txtItemPFcp, txtItemVFcp, txtItemVBcFcp, txtItemVBcFcpSt, txtItemPFcpSt, txtItemVFcpSt, txtItemPSt, txtItemVBcFcpStRet, txtItemPFcpStRet, txtItemVFcpStRet;
+
+ // --- ABA 5: PIS, COFINS E EFETIVOS ---
+ private LV_TEXTBOX1? txtItemPisCst, txtItemPisVBc, txtItemPisPPis, txtItemPisVPis, txtItemCofinsCst, txtItemCofinsVBc, txtItemCofinsPCofins, txtItemCofinsVCofins, txtVIcmsSubstituto, txtPRedBcEfet, txtVBcEfet, txtPIcmsEfet, txtVIcmsEfet;
+
+ public SatFiscalConsumidorItensPanel()
+ {
+ this.Titulo = "DETALHAMENTO DE ITENS DO CUPOM FISCAL";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ tabItens = new TabControl
+ {
+ Location = new Point(10, 10),
+ Size = new Size(1060, 520),
+ Font = new Font("Segoe UI", 9.5f)
+ };
+
+ var tpGeral = new TabPage("Dados do Produto");
+ var tpComercial = new TabPage("Valores e Códigos");
+ var tpIcms = new TabPage("ICMS Normal / ST");
+ var tpFcp = new TabPage("FCP");
+ var tpPisCofins = new TabPage("PIS / COFINS / Efetivos");
+
+ // Simplificação da inicialização de coleção aceita pelo compilador moderno
+ tabItens.TabPages.AddRange([tpGeral, tpComercial, tpIcms, tpFcp, tpPisCofins]);
+ content.Controls.Add(tabItens);
+
+ ConfigurarAbaGeral(tpGeral);
+ ConfigurarAbaComercial(tpComercial);
+ ConfigurarAbaIcms(tpIcms);
+ ConfigurarAbaFcp(tpFcp);
+ ConfigurarAbaPisCofins(tpPisCofins);
+ }
+
+ private void ConfigurarAbaGeral(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Identificação e Chaves do Item", 15));
+ txtIdSatFiscalConsItens = AddInput(tp, "ID ITEM REG.", 20, 50, 100, 28, true);
+ txtCodigo = AddInput(tp, "CÓDIGO INT.", 135, 50, 110, 28);
+ txtCodNfce = AddInput(tp, "CÓD. VÍNCULO NFC-E", 260, 50, 150, 28);
+ txtItemTipo = AddInput(tp, "TIPO ITEM", 425, 50, 120, 28);
+ txtDataCadastro = AddInput(tp, "DATA CADASTRO", 560, 50, 180, 28, true);
+
+ tp.Controls.Add(CreateSectionHeader("Especificações do Produto", 120));
+ txtItemCprod = AddInput(tp, "CÓD. COMERCIAL DO PRODUTO", 20, 155, 200, 28);
+ txtItemCean = AddInput(tp, "CÓDIGO EAN (CÓD. BARRAS)", 235, 155, 220, 28);
+ txtItemXprod = AddInput(tp, "DESCRIÇÃO DO PRODUTO / SERVIÇO", 20, 215, 600, 28);
+ txtItemInfAdic = AddInput(tp, "INFORMAÇÕES ADICIONAIS DO ITEM", 20, 275, 600, 28);
+ }
+
+ private void ConfigurarAbaComercial(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Classificações Fiscais Obrigatórias", 15));
+ txtItemCfop = AddInput(tp, "CFOP", 20, 50, 90, 28);
+ txtItemNcm = AddInput(tp, "NCM", 125, 50, 120, 28);
+ txtItemCest = AddInput(tp, "CEST", 260, 50, 120, 28);
+ txtCProdAnp = AddInput(tp, "CÓD. ANP (COMBUSTÍVEIS)", 395, 50, 180, 28);
+ txtCBenef = AddInput(tp, "BENEFÍCIO FISCAL (CBENEF)", 590, 50, 180, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Valores Comerciais, Quantidades e Rateios", 120));
+ txtItemUncom = AddInput(tp, "UNIDADE MEDIDA", 20, 155, 100, 28);
+ txtItemQcom = AddInput(tp, "QUANTIDADE COMERCIAL", 135, 155, 140, 28);
+ txtItemVprod = AddInput(tp, "VALOR BRUTO PROD. (R$)", 290, 155, 150, 28);
+ txtItemVdesc = AddInput(tp, "VALOR DESCONTO (R$)", 455, 155, 140, 28);
+
+ txtItemVfrete = AddInput(tp, "RATEIO FRETE (R$)", 20, 215, 140, 28);
+ txtItemVseg = AddInput(tp, "RATEIO SEGURO (R$)", 175, 215, 140, 28);
+ txtItemVoutro = AddInput(tp, "OUTRAS DESPESAS (R$)", 330, 215, 150, 28);
+ txtItemVTotTrib = AddInput(tp, "VALOR APROX. TRIBUTOS", 495, 215, 160, 28);
+ }
+
+ private void ConfigurarAbaIcms(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("ICMS Regra Geral e Base de Cálculo", 15));
+ txtItemOrigem = AddInput(tp, "ORIGEM PROD.", 20, 50, 100, 28);
+ txtItemCst = AddInput(tp, "CST / CSOSN", 135, 50, 100, 28);
+ txtItemIcmsModBc = AddInput(tp, "MODALIDADE BC ICMS", 250, 50, 150, 28);
+ txtItemIcmsPRedBc = AddInput(tp, "% REDUÇÃO BC", 415, 50, 120, 28);
+ txtItemIcmsVBc = AddInput(tp, "VALOR BC ICMS", 550, 50, 130, 28);
+ txtItemIcmsPIcms = AddInput(tp, "ALÍQUOTA ICMS", 695, 50, 120, 28);
+ txtItemIcmsVIcms = AddInput(tp, "VALOR ICMS", 830, 50, 130, 28);
+
+ tp.Controls.Add(CreateSectionHeader("ICMS Desonerado e Regras de Substituição Tributária (ST)", 120));
+ txtItemIcmsVIcmsDeson = AddInput(tp, "VALOR ICMS DESON.", 20, 155, 150, 28);
+ txtItemIcmsMotDesIcms = AddInput(tp, "MOTIVO DESON.", 185, 155, 140, 28); // Corrigido a inconsistência de caixa alta/baixa
+ txtItemIcmsModBcSt = AddInput(tp, "MODALIDADE BC ST", 340, 155, 140, 28);
+ txtItemIcmsPMvast = AddInput(tp, "% MVA ST", 495, 155, 110, 28);
+ txtItemIcmsPRedBcSt = AddInput(tp, "% REDUÇÃO BC ST", 620, 155, 130, 28);
+
+ txtItemIcmsVBcSt = AddInput(tp, "VALOR BASE CÁLCULO ST", 20, 215, 170, 28);
+ txtItemIcmsPIcmsSt = AddInput(tp, "ALÍQUOTA ICMS ST", 205, 215, 140, 28);
+ txtItemIcmsVIcmsSt = AddInput(tp, "VALOR DO ICMS ST", 360, 215, 150, 28);
+ }
+
+ private void ConfigurarAbaFcp(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Fundo de Combate à Pobreza - ICMS Normal e ST", 15));
+ txtItemVBcFcp = AddInput(tp, "VALOR BC FCP", 20, 50, 130, 28);
+ txtItemPFcp = AddInput(tp, "% ALÍQUOTA FCP", 165, 50, 130, 28);
+ txtItemVFcp = AddInput(tp, "VALOR DO FCP", 310, 50, 130, 28);
+
+ txtItemVBcFcpSt = AddInput(tp, "VALOR BC FCP ST", 455, 50, 140, 28);
+ txtItemPFcpSt = AddInput(tp, "% ALÍQUOTA FCP ST", 610, 50, 140, 28);
+ txtItemVFcpSt = AddInput(tp, "VALOR DO FCP ST", 765, 50, 140, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Fundo de Combate à Pobreza Retido Anteriormente", 120));
+ txtItemPSt = AddInput(tp, "% ALÍQUOTA ICMS ST RET.", 20, 155, 180, 28);
+ txtItemVBcFcpStRet = AddInput(tp, "VALOR BC FCP ST RET.", 215, 155, 160, 28);
+ txtItemPFcpStRet = AddInput(tp, "% ALÍQUOTA FCP ST RET.", 390, 155, 170, 28);
+ txtItemVFcpStRet = AddInput(tp, "VALOR DO FCP ST RET.", 575, 155, 160, 28); // Corrigido nomenclatura para bater com a propriedade da classe
+ }
+
+ private void ConfigurarAbaPisCofins(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Contribuições para o PIS", 15));
+ txtItemPisCst = AddInput(tp, "CST PIS", 20, 50, 100, 28);
+ txtItemPisVBc = AddInput(tp, "VALOR BC PIS", 135, 50, 130, 28);
+ txtItemPisPPis = AddInput(tp, "% ALÍQUOTA PIS", 280, 50, 120, 28);
+ txtItemPisVPis = AddInput(tp, "VALOR DO PIS", 415, 50, 130, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Contribuições para a COFINS", 120));
+ txtItemCofinsCst = AddInput(tp, "CST COFINS", 20, 155, 100, 28);
+ txtItemCofinsVBc = AddInput(tp, "VALOR BC COFINS", 135, 155, 130, 28);
+ txtItemCofinsPCofins = AddInput(tp, "% ALÍQUOTA COFINS", 280, 155, 140, 28);
+ txtItemCofinsVCofins = AddInput(tp, "VALOR DO COFINS", 435, 155, 140, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Indicadores de Valores Fiscais Efetivos", 225));
+ txtVIcmsSubstituto = AddInput(tp, "VALOR ICMS SUBST.", 20, 260, 150, 28);
+ txtPRedBcEfet = AddInput(tp, "% REDUÇÃO BC EFET.", 185, 260, 150, 28);
+ txtVBcEfet = AddInput(tp, "VALOR BC EFETIVA", 350, 260, 140, 28);
+ txtPIcmsEfet = AddInput(tp, "% ALÍQUOTA ICMS EFET.", 505, 260, 160, 28);
+ txtVIcmsEfet = AddInput(tp, "VALOR ICMS EFETIVO", 680, 260, 150, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ // Substituição por função local (atende à sugestão do analisador C# moderno)
+ void LimparRecursivo(Control.ControlCollection controls)
+ {
+ foreach (Control c in controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly) txt.Text = string.Empty;
+ if (c.HasChildren) LimparRecursivo(c.Controls);
+ }
+ }
+
+ if (tabItens != null)
+ {
+ LimparRecursivo(tabItens.Controls);
+ tabItens.SelectedIndex = 0;
+ }
+
+ if (txtIdSatFiscalConsItens != null) txtIdSatFiscalConsItens.Text = "0";
+ if (txtDataCadastro != null) txtDataCadastro.Text = DateTime.Now.ToString("g");
+
+ txtItemCprod?.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ // Proteção nula com operador condicional para checagem segura
+ if (string.IsNullOrWhiteSpace(txtItemCprod?.Text))
+ {
+ MessageBox.Show("O código comercial do produto é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ if (tabItens != null) tabItens.SelectedIndex = 0;
+ txtItemCprod?.Focus();
+ return;
+ }
+
+ // Mapeamento usando Operador de Coalescência Nula (??) para garantir strings limpas
+ var item = new ModeloSatFiscalConsumidorItens
+ {
+ ID_SAT_FISCAL_CONS_ITENS = string.IsNullOrEmpty(txtIdSatFiscalConsItens?.Text) ? 0 : Convert.ToInt32(txtIdSatFiscalConsItens.Text),
+ CODIGO = txtCodigo?.Text ?? string.Empty,
+ COD_NFCE = txtCodNfce?.Text ?? string.Empty,
+ ITEM_TIPO = txtItemTipo?.Text ?? string.Empty,
+ ITEM_CEAN = txtItemCean?.Text ?? string.Empty,
+ ITEM_CPROD = txtItemCprod.Text,
+ ITEM_XPROD = txtItemXprod?.Text ?? string.Empty,
+ ITEM_INF_ADIC = txtItemInfAdic?.Text ?? string.Empty,
+ ITEM_CFOP = txtItemCfop?.Text ?? string.Empty,
+ ITEM_NCM = txtItemNcm?.Text ?? string.Empty,
+ ITEM_UNCOM = txtItemUncom?.Text ?? string.Empty,
+ ITEM_QCOM = txtItemQcom?.Text ?? string.Empty,
+ ITEM_VPROD = txtItemVprod?.Text ?? string.Empty,
+ ITEM_VOUTRO = txtItemVoutro?.Text ?? string.Empty,
+ ITEM_VFRETE = txtItemVfrete?.Text ?? string.Empty,
+ ITEM_VSEG = txtItemVseg?.Text ?? string.Empty,
+ ITEM_VDESC = txtItemVdesc?.Text ?? string.Empty,
+ ITEM_vTotTrib = txtItemVTotTrib?.Text ?? string.Empty,
+ ITEM_ORIGEM = txtItemOrigem?.Text ?? string.Empty,
+ ITEM_CST = txtItemCst?.Text ?? string.Empty,
+ DATA_CADASTRO = txtDataCadastro?.Text ?? string.Empty,
+ ITEM_ICMS_modBC = txtItemIcmsModBc?.Text ?? string.Empty,
+ ITEM_ICMS_pRedBC = txtItemIcmsPRedBc?.Text ?? string.Empty,
+ ITEM_ICMS_vBC = txtItemIcmsVBc?.Text ?? string.Empty,
+ ITEM_ICMS_pICMS = txtItemIcmsPIcms?.Text ?? string.Empty,
+ ITEM_ICMS_vICMS = txtItemIcmsVIcms?.Text ?? string.Empty,
+ ITEM_ICMS_vICMSDeson = txtItemIcmsVIcmsDeson?.Text ?? string.Empty,
+ ITEM_ICMS_motDesICMS = txtItemIcmsMotDesIcms?.Text ?? string.Empty,
+ ITEM_ICMS_modBCST = txtItemIcmsModBcSt?.Text ?? string.Empty,
+ ITEM_ICMS_pMVAST = txtItemIcmsPMvast?.Text ?? string.Empty,
+ ITEM_ICMS_pRedBCST = txtItemIcmsPRedBcSt?.Text ?? string.Empty,
+ ITEM_ICMS_vBCST = txtItemIcmsVBcSt?.Text ?? string.Empty,
+ ITEM_ICMS_pICMSST = txtItemIcmsPIcmsSt?.Text ?? string.Empty,
+ ITEM_ICMS_vICMSST = txtItemIcmsVIcmsSt?.Text ?? string.Empty,
+ ITEM_cProdANP = txtCProdAnp?.Text ?? string.Empty,
+ ITEM_CEST = txtItemCest?.Text ?? string.Empty,
+ CBenef = txtCBenef?.Text ?? string.Empty,
+ ITEM_pFCP = txtItemPFcp?.Text ?? string.Empty,
+ ITEM_vFCP = txtItemVFcp?.Text ?? string.Empty,
+ ITEM_vBCFCP = txtItemVBcFcp?.Text ?? string.Empty,
+ ITEM_vBCFCPST = txtItemVBcFcpSt?.Text ?? string.Empty,
+ ITEM_pFCPST = txtItemPFcpSt?.Text ?? string.Empty,
+ ITEM_vFCPST = txtItemVFcpSt?.Text ?? string.Empty,
+ ITEM_pST = txtItemPSt?.Text ?? string.Empty,
+ ITEM_vBCFCPSTRet = txtItemVBcFcpStRet?.Text ?? string.Empty,
+ ITEM_pFCPSTRet = txtItemPFcpStRet?.Text ?? string.Empty,
+ ITEM_vFCPSTRet = txtItemVFcpStRet?.Text ?? string.Empty,
+ ITEM_PIS_CST = txtItemPisCst?.Text ?? string.Empty,
+ ITEM_PIS_vBC = txtItemPisVBc?.Text ?? string.Empty,
+ ITEM_PIS_pPIS = txtItemPisPPis?.Text ?? string.Empty,
+ ITEM_PIS_vPIS = txtItemPisVPis?.Text ?? string.Empty,
+ ITEM_COFINS_CST = txtItemCofinsCst?.Text ?? string.Empty,
+ ITEM_COFINS_vBC = txtItemCofinsVBc?.Text ?? string.Empty,
+ ITEM_COFINS_pCOFINS = txtItemCofinsPCofins?.Text ?? string.Empty,
+ ITEM_COFINS_vCOFINS = txtItemCofinsVCofins?.Text ?? string.Empty,
+ VICMSSubstituto = txtVIcmsSubstituto?.Text ?? string.Empty,
+ PRedBCEfet = txtPRedBcEfet?.Text ?? string.Empty,
+ VBCEfet = txtVBcEfet?.Text ?? string.Empty,
+ PICMSEfet = txtPIcmsEfet?.Text ?? string.Empty,
+ VICMSEfet = txtVIcmsEfet?.Text ?? string.Empty
+ };
+
+ // Processa o objeto preenchido nas camadas inferiores
+ MessageBox.Show($"Item {item.ITEM_CPROD} gravado com sucesso!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtItemXprod?.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Confirma a exclusão deste item?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Vinculado à Grid de busca global
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file
diff --git a/UI/Dashboards/Fiscal/SatFiscalConsumidorPanel.cs b/UI/Dashboards/Fiscal/SatFiscalConsumidorPanel.cs
new file mode 100644
index 0000000..13ed0dd
--- /dev/null
+++ b/UI/Dashboards/Fiscal/SatFiscalConsumidorPanel.cs
@@ -0,0 +1,242 @@
+using MLL;
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using CPM;
+
+namespace UI
+{
+ public class SatFiscalConsumidorPanel : FormularioModelo
+ {
+ private TabControl tabFiscal;
+
+ // --- CAMPOS DA ABA 1: DADOS DA EMISSÃO ---
+ private LV_TEXTBOX1 txtIdSatFiscalConsu, txtCodigo, txtProducao, txtSerie, txtNatureza, txtEmissao, txtTerminal, txtSituacao, txtDataCadastro;
+
+ // --- CAMPOS DA ABA 2: DESTINATÁRIO / CLIENTE ---
+ private LV_TEXTBOX1 txtDestNome, txtDestEmail, txtDestCpfCnpj, txtDestIdEstrangeiro, txtDestLgr, txtDestCpl, txtDestNro, txtDestBairro, txtDestCMun, txtDestXMun, txtDestUf, txtDestCep, txtDestCPais, txtDestXPais, txtDestFone;
+
+ // --- CAMPOS DA ABA 3: TOTAIS E IMPOSTOS (SEFAZ) ---
+ private LV_TEXTBOX1 txtTotalVBc, txtTotalVIcms, txtTotalVBcSt, txtTotalVSt, txtTotalVProd, txtTotalVFrete, txtTotalVSeg, txtTotalVDesc, txtTotalVIi, txtTotalVIpi, txtTotalVPis, txtTotalVCofins, txtTotalVOutro, txtTotalVNf;
+
+ // --- CAMPOS DA ABA 4: LOGÍSTICA / PROTOCOLOS ---
+ private LV_TEXTBOX1 txtFreteModalidade, txtFreteXCnpjCpf, txtFreteXNome, txtNfcPronta, txtNfcInfCpl, txtChaveNfc, txtProtocolo, txtProtocoloCancela;
+
+ public SatFiscalConsumidorPanel()
+ {
+ this.Titulo = "GERENCIAMENTO DE EMISSÃO FISCAL (NFC-E / SAT)";
+ MontarInterfaceCompleta();
+ }
+
+ private void MontarInterfaceCompleta()
+ {
+ // Inicialização do TabControl adaptado ao content (1100px)
+ tabFiscal = new TabControl
+ {
+ Location = new Point(10, 10),
+ Size = new Size(1060, 520),
+ Font = new Font("Segoe UI", 9.5f)
+ };
+
+ var tpEmissao = new TabPage("Dados da Emissão");
+ var tpDestinatario = new TabPage("Destinatário / Cliente");
+ var tpTotais = new TabPage("Totais e Impostos");
+ var tpProtocolos = new TabPage("Logística e Protocolos");
+
+ tabFiscal.TabPages.AddRange(new[] { tpEmissao, tpDestinatario, tpTotais, tpProtocolos });
+ content.Controls.Add(tabFiscal);
+
+ ConfigurarAbaEmissao(tpEmissao);
+ ConfigurarAbaDestinatario(tpDestinatario);
+ ConfigurarAbaTotais(tpTotais);
+ ConfigurarAbaProtocolos(tpProtocolos);
+ }
+
+ private void ConfigurarAbaEmissao(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Identificação e Status do Cupom Fiscal", 15));
+ txtIdSatFiscalConsu = AddInput(tp, "ID FISCAL", 20, 50, 100, 28, true);
+ txtCodigo = AddInput(tp, "CÓDIGO INT.", 135, 50, 110, 28);
+ txtTerminal = AddInput(tp, "Nº TERMINAL", 260, 50, 110, 28);
+ txtSerie = AddInput(tp, "SÉRIE", 385, 50, 90, 28);
+ txtProducao = AddInput(tp, "AMBIENTE (1=PROD / 2=HOMOL)", 490, 50, 210, 28);
+ txtSituacao = AddInput(tp, "SITUAÇÃO XML", 715, 50, 150, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Datas e Natureza de Operação", 120));
+ txtNatureza = AddInput(tp, "NATUREZA DA OPERAÇÃO", 20, 155, 350, 28);
+ txtEmissao = AddInput(tp, "DATA/HORA EMISSÃO", 385, 155, 180, 28);
+ txtDataCadastro = AddInput(tp, "DATA CADASTRO NO SISTEMA", 580, 155, 200, 28, true);
+ }
+
+ private void ConfigurarAbaDestinatario(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Identificação do Consumidor", 15));
+ txtDestNome = AddInput(tp, "RAZÃO SOCIAL / NOME", 20, 50, 400, 28);
+ txtDestCpfCnpj = AddInput(tp, "CPF / CNPJ", 435, 50, 180, 28);
+ txtDestEmail = AddInput(tp, "E-MAIL DESTINATÁRIO", 630, 50, 250, 28);
+ txtDestFone = AddInput(tp, "TELEFONE", 20, 105, 150, 28);
+ txtDestIdEstrangeiro = AddInput(tp, "DOCUMENTO ESTRANGEIRO (PASSAPORTE)", 185, 105, 250, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Endereço do Destinatário", 165));
+ txtDestLgr = AddInput(tp, "LOGRADOURO (RUA, AV)", 20, 200, 350, 28);
+ txtDestNro = AddInput(tp, "NÚMERO", 385, 200, 80, 28);
+ txtDestCpl = AddInput(tp, "COMPLEMENTO", 480, 200, 200, 28);
+ txtDestBairro = AddInput(tp, "BAIRRO", 695, 200, 185, 28);
+
+ txtDestCep = AddInput(tp, "CEP", 20, 255, 110, 28);
+ txtDestCMun = AddInput(tp, "CÓD. MUNICÍPIO (IBGE)", 145, 255, 150, 28);
+ txtDestXMun = AddInput(tp, "MUNICÍPIO", 310, 255, 220, 28);
+ txtDestUf = AddInput(tp, "UF", 545, 255, 50, 28);
+ txtDestCPais = AddInput(tp, "CÓD. PAÍS", 610, 255, 80, 28);
+ txtDestXPais = AddInput(tp, "PAÍS", 700, 255, 180, 28);
+ }
+
+ private void ConfigurarAbaTotais(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Composição de Valores de Produtos e Frete", 15));
+ txtTotalVProd = AddInput(tp, "TOTAL PRODUTOS (R$)", 20, 50, 160, 28);
+ txtTotalVDesc = AddInput(tp, "TOTAL DESCONTO (R$)", 195, 50, 150, 28);
+ txtTotalVFrete = AddInput(tp, "VALOR FRETE (R$)", 360, 50, 140, 28);
+ txtTotalVSeg = AddInput(tp, "VALOR SEGURO (R$)", 515, 50, 140, 28);
+ txtTotalVOutro = AddInput(tp, "OUTRAS DESPESAS (R$)", 670, 50, 150, 28);
+ txtTotalVNf = AddInput(tp, "VALOR TOTAL DA NOTA (R$)", 835, 50, 190, 28, true);
+
+ tp.Controls.Add(CreateSectionHeader("Impostos e Retenções Fiscais", 115));
+ txtTotalVBc = AddInput(tp, "BASE CÁLCULO ICMS", 20, 150, 150, 28);
+ txtTotalVIcms = AddInput(tp, "VALOR DO ICMS", 185, 150, 140, 28);
+ txtTotalVBcSt = AddInput(tp, "BASE CÁLCULO ICMS ST", 340, 150, 160, 28);
+ txtTotalVSt = AddInput(tp, "VALOR ICMS ST", 515, 150, 140, 28);
+ txtTotalVIi = AddInput(tp, "VALOR IMP. IMPORTAÇÃO", 670, 150, 160, 28);
+
+ txtTotalVIpi = AddInput(tp, "VALOR TOTAL IPI", 20, 205, 150, 28);
+ txtTotalVPis = AddInput(tp, "VALOR TOTAL PIS", 185, 205, 140, 28);
+ txtTotalVCofins = AddInput(tp, "VALOR TOTAL COFINS", 340, 205, 160, 28);
+ }
+
+ private void ConfigurarAbaProtocolos(TabPage tp)
+ {
+ tp.Controls.Add(CreateSectionHeader("Informações do Transportador e Frete", 15));
+ txtFreteModalidade = AddInput(tp, "MODALIDADE FRETE", 20, 50, 160, 28);
+ txtFreteXCnpjCpf = AddInput(tp, "CNPJ / CPF TRANSP.", 195, 50, 180, 28);
+ txtFreteXNome = AddInput(tp, "RAZÃO SOCIAL TRANSPORTADORA", 390, 50, 420, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Protocolos de Validação SEFAZ", 115));
+ txtChaveNfc = AddInput(tp, "CHAVE DE ACESSO NFC-E / SAT (44 DÍGITOS)", 20, 150, 450, 28);
+ txtProtocolo = AddInput(tp, "Nº PROTOCOLO AUTORIZAÇÃO", 480, 150, 230, 28);
+ txtProtocoloCancela = AddInput(tp, "Nº PROTOCOLO CANCELAMENTO", 720, 150, 230, 28);
+
+ tp.Controls.Add(CreateSectionHeader("Parâmetros do Arquivo Fiscal XML", 215));
+ txtNfcPronta = AddInput(tp, "NFC PRONTA (S/N)", 20, 250, 140, 28);
+ txtNfcInfCpl = AddInput(tp, "INFORMAÇÕES COMPLEMENTARES AO CONTRIBUINTE", 175, 250, 635, 28);
+ }
+
+ // --- MÉTODOS OBRIGATÓRIOS DO FORMULÁRIO MODELO ---
+
+ protected override void OnNovo()
+ {
+ Action limparCampos = null;
+ limparCampos = (controls) =>
+ {
+ foreach (Control c in controls)
+ {
+ if (c is LV_TEXTBOX1 txt && !txt.ReadOnly) txt.Text = string.Empty;
+ if (c.HasChildren) limparCampos(c.Controls);
+ }
+ };
+
+ limparCampos(tabFiscal.Controls);
+ txtIdSatFiscalConsu.Text = "0";
+ txtDataCadastro.Text = DateTime.Now.ToString("g");
+ tabFiscal.SelectedIndex = 0;
+ txtCodigo.Focus();
+ }
+
+ protected override void OnSalvar()
+ {
+ if (string.IsNullOrWhiteSpace(txtCodigo.Text))
+ {
+ MessageBox.Show("O código interno da transação é obrigatório.", "Aviso", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ tabFiscal.SelectedIndex = 0;
+ txtCodigo.Focus();
+ return;
+ }
+
+ // Mapeamento absoluto, cirúrgico e fiel de todas as 46 propriedades
+ var fiscal = new ModeloSatFiscalConsumidor
+ {
+ ID_SAT_FISCAL_CONSU = string.IsNullOrEmpty(txtIdSatFiscalConsu.Text) ? 0 : Convert.ToInt32(txtIdSatFiscalConsu.Text),
+ CODIGO = txtCodigo.Text,
+ PRODUCAO = txtProducao.Text,
+ SERIE = txtSerie.Text,
+ NATUREZA = txtNatureza.Text,
+ EMISSAO = txtEmissao.Text,
+ DEST_NOME = txtDestNome.Text,
+ DEST_EMAIL = txtDestEmail.Text,
+ DEST_CPF_CNPJ = txtDestCpfCnpj.Text,
+ DEST_IDESTRANGEIRO = txtDestIdEstrangeiro.Text,
+ DEST_xLgr = txtDestLgr.Text,
+ DEST_CPL = txtDestCpl.Text,
+ DEST_nro = txtDestNro.Text,
+ DEST_xBairro = txtDestBairro.Text,
+ DEST_cMun = txtDestCMun.Text,
+ DEST_xMun = txtDestXMun.Text,
+ DEST_UF = txtDestUf.Text,
+ DEST_CEP = txtDestCep.Text,
+ DEST_cPais = txtDestCPais.Text,
+ DEST_xPais = txtDestXPais.Text,
+ DEST_fone = txtDestFone.Text,
+ FRETE_MODALIDADE = txtFreteModalidade.Text,
+ FRETE_xCNPJ_CPF = txtFreteXCnpjCpf.Text,
+ FRETE_xNome = txtFreteXNome.Text,
+ NFC_PRONTA = txtNfcPronta.Text,
+ NFC_infCpl = txtNfcInfCpl.Text,
+ TOTAL_vBC = txtTotalVBc.Text,
+ TOTAL_vICMS = txtTotalVIcms.Text,
+ TOTAL_vBCST = txtTotalVBcSt.Text,
+ TOTAL_vST = txtTotalVSt.Text,
+ TOTAL_vProd = txtTotalVProd.Text,
+ TOTAL_vFrete = txtTotalVFrete.Text,
+ TOTAL_vSeg = txtTotalVSeg.Text,
+ TOTAL_vDesc = txtTotalVDesc.Text,
+ TOTAL_vII = txtTotalVIi.Text,
+ TOTAL_vIPI = txtTotalVIpi.Text,
+ TOTAL_vPIS = txtTotalVPis.Text,
+ TOTAL_vCOFINS = txtTotalVCofins.Text,
+ TOTAL_vOutro = txtTotalVOutro.Text,
+ TOTAL_vNF = txtTotalVNf.Text,
+ TERMINAL = txtTerminal.Text,
+ CHAVE_NFC = txtChaveNfc.Text,
+ PROTOCOLO = txtProtocolo.Text,
+ PROTOCOLO_CANCELA = txtProtocoloCancela.Text,
+ SITUACAO = txtSituacao.Text,
+ DATA_CADASTRO = txtDataCadastro.Text
+ };
+
+ // Envio para repositórios DAL / BLL (LevelCode)
+ MessageBox.Show("Movimentação fiscal salva e estruturada para transmissão!", "LevelOS", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ protected override void OnAlterar()
+ {
+ txtSituacao.Focus();
+ }
+
+ protected override void OnExcluir()
+ {
+ if (MessageBox.Show("Atenção! A exclusão direta de um cupom fiscal no banco pode gerar quebras de sequência numérica na SEFAZ. Deseja prosseguir?", "LevelOS", MessageBoxButtons.YesNo, MessageBoxIcon.Stop) == DialogResult.Yes)
+ {
+ OnNovo();
+ }
+ }
+
+ protected override void OnLocalizar()
+ {
+ // Abre o Grid de cupons emitidos/pendentes
+ }
+
+ protected override void OnCancelar()
+ {
+ OnNovo();
+ }
+ }
+}
\ No newline at end of file