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