diff --git a/.gitignore b/.gitignore index 0735242..c5277d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vs/ +<<<<<<< HEAD **/.vs/ bin/ obj/ @@ -7,4 +8,11 @@ obj/ *.pdb *.cache *.user -*.suo \ No newline at end of file +*.suo +======= +bin/ +obj/ +*.user +*.suo +*.cache +>>>>>>> 577e97245b8945b1bfd71ca7bb3971042d27d2a9 diff --git a/ArquivosAuxiliares/DadosAuxiliaresTabelaPermissoes.sql b/ArquivosAuxiliares/DadosAuxiliaresTabelaPermissoes.sql new file mode 100644 index 0000000..715188e --- /dev/null +++ b/ArquivosAuxiliares/DadosAuxiliaresTabelaPermissoes.sql @@ -0,0 +1,108 @@ +INSERT INTO Permissoes (Nome, Descricao) +VALUES + +-- ======================== +-- EMPRESA +-- ======================== +('EMPRESA_VER', 'Visualizar dados da empresa'), +('EMPRESA_EDITAR', 'Editar dados da empresa'), + +-- ======================== +-- CLIENTES +-- ======================== +('CLIENTE_VER', 'Visualizar clientes'), +('CLIENTE_CADASTRAR', 'Cadastrar clientes'), +('CLIENTE_EDITAR', 'Editar clientes'), +('CLIENTE_EXCLUIR', 'Excluir clientes'), + +-- ======================== +-- FORNECEDORES +-- ======================== +('FORNECEDOR_VER', 'Visualizar fornecedores'), +('FORNECEDOR_CADASTRAR', 'Cadastrar fornecedores'), +('FORNECEDOR_EDITAR', 'Editar fornecedores'), +('FORNECEDOR_EXCLUIR', 'Excluir fornecedores'), + +-- ======================== +-- FUNCIONARIOS +-- ======================== +('FUNCIONARIO_VER', 'Visualizar funcionrios'), +('FUNCIONARIO_CADASTRAR', 'Cadastrar funcionrios'), +('FUNCIONARIO_EDITAR', 'Editar funcionrios'), +('FUNCIONARIO_EXCLUIR', 'Excluir funcionrios'), + +-- ======================== +-- USUARIOS / SEGURANA +-- ======================== +('USUARIO_VER', 'Visualizar usurios'), +('USUARIO_CADASTRAR', 'Cadastrar usurios'), +('USUARIO_EDITAR', 'Editar usurios'), +('USUARIO_EXCLUIR', 'Excluir usurios'), +('PERMISSAO_GERENCIAR', 'Gerenciar permisses'), + +-- ======================== +-- SERVIOS +-- ======================== +('SERVICO_VER', 'Visualizar servios'), +('SERVICO_CADASTRAR', 'Cadastrar servios'), +('SERVICO_EDITAR', 'Editar servios'), +('SERVICO_EXCLUIR', 'Excluir servios'), + +-- ======================== +-- CONTRATOS +-- ======================== +('CONTRATO_VER', 'Visualizar contratos'), +('CONTRATO_CADASTRAR', 'Cadastrar contratos'), +('CONTRATO_EDITAR', 'Editar contratos'), +('CONTRATO_EXCLUIR', 'Excluir contratos'), + +-- ======================== +-- FINANCEIRO - RECEBER +-- ======================== +('RECEBER_VER', 'Visualizar contas a receber'), +('RECEBER_CADASTRAR', 'Cadastrar contas a receber'), +('RECEBER_EDITAR', 'Editar contas a receber'), +('RECEBER_BAIXAR', 'Dar baixa em contas a receber'), + +-- ======================== +-- FINANCEIRO - PAGAR +-- ======================== +('PAGAR_VER', 'Visualizar contas a pagar'), +('PAGAR_CADASTRAR', 'Cadastrar contas a pagar'), +('PAGAR_EDITAR', 'Editar contas a pagar'), +('PAGAR_BAIXAR', 'Dar baixa em contas a pagar'), + +-- ======================== +-- PLANO DE CONTAS +-- ======================== +('PLANO_CONTAS_VER', 'Visualizar plano de contas'), +('PLANO_CONTAS_CADASTRAR', 'Cadastrar plano de contas'), +('PLANO_CONTAS_EDITAR', 'Editar plano de contas'), +('PLANO_CONTAS_EXCLUIR', 'Excluir plano de contas'), + +-- ======================== +-- TRANSPORTADORAS +-- ======================== +('TRANSPORTADORA_VER', 'Visualizar transportadoras'), +('TRANSPORTADORA_CADASTRAR', 'Cadastrar transportadoras'), +('TRANSPORTADORA_EDITAR', 'Editar transportadoras'), +('TRANSPORTADORA_EXCLUIR', 'Excluir transportadoras'), + +-- ======================== +-- RELATORIOS +-- ======================== +('RELATORIO_FINANCEIRO', 'Acessar relatrios financeiros'), +('RELATORIO_CLIENTES', 'Acessar relatrios de clientes'), +('RELATORIO_GERAL', 'Acessar relatrios gerais'), + +-- ======================== +-- SISTEMA +-- ======================== +('SISTEMA_CONFIG', 'Alterar configuraes do sistema'), +('SISTEMA_LOGS', 'Visualizar logs do sistema'); + +INSERT INTO Permissoes (Nome, Descricao) +SELECT 'CLIENTE_VER', 'Visualizar clientes' +WHERE NOT EXISTS ( + SELECT 1 FROM Permissoes WHERE Nome = 'CLIENTE_VER' +); \ No newline at end of file diff --git a/ArquivosAuxiliares/DadosSistema.sql b/ArquivosAuxiliares/DadosSistema.sql new file mode 100644 index 0000000..eeab4ec --- /dev/null +++ b/ArquivosAuxiliares/DadosSistema.sql @@ -0,0 +1,74 @@ +-- ========================= +-- PEGAR EMPRESA +-- ========================= +DECLARE @EmpresaId INT; +SELECT TOP 1 @EmpresaId = Id FROM Empresa; + +-- ========================= +-- CRIAR USUARIO ADMIN +-- ========================= +IF NOT EXISTS (SELECT 1 FROM Usuarios WHERE Usuario = 'admin' AND EmpresaId = @EmpresaId) +BEGIN + INSERT INTO Usuarios ( + EmpresaId, Nome, Email, Usuario, SenhaHash, Ativo, CriadoEm + ) + VALUES ( + @EmpresaId, + 'Administrador do Sistema', + 'admin@levelcode.com.br', + 'admin', + CONVERT(VARCHAR(255), HASHBYTES('SHA2_256', 'Nad310311*##'), 2), + 1, + GETDATE() + ); +END + +-- ========================= +-- CRIAR PERFIL ADMIN +-- ========================= +IF NOT EXISTS (SELECT 1 FROM Perfis WHERE Nome = 'Administrador' AND EmpresaId = @EmpresaId) +BEGIN + INSERT INTO Perfis ( + EmpresaId, Nome, Descricao, Ativo + ) + VALUES ( + @EmpresaId, + 'Administrador', + 'Acesso total ao sistema', + 1 + ); +END + +-- ========================= +-- PEGAR IDS +-- ========================= +DECLARE @UsuarioId INT; +DECLARE @PerfilId INT; + +SELECT @UsuarioId = Id FROM Usuarios WHERE Usuario = 'admin' AND EmpresaId = @EmpresaId; +SELECT @PerfilId = Id FROM Perfis WHERE Nome = 'Administrador' AND EmpresaId = @EmpresaId; + +-- ========================= +-- VINCULAR USUARIO AO PERFIL +-- ========================= +IF NOT EXISTS ( + SELECT 1 FROM UsuarioPerfis + WHERE UsuarioId = @UsuarioId AND PerfilId = @PerfilId +) +BEGIN + INSERT INTO UsuarioPerfis (UsuarioId, PerfilId) + VALUES (@UsuarioId, @PerfilId); +END + +-- ========================= +-- DAR TODAS PERMISSES +-- ========================= +INSERT INTO PerfilPermissoes (PerfilId, PermissaoId) +SELECT + @PerfilId, + Id +FROM Permissoes +WHERE NOT EXISTS ( + SELECT 1 FROM PerfilPermissoes + WHERE PerfilId = @PerfilId AND PermissaoId = Permissoes.Id +); diff --git a/ArquivosAuxiliares/Database.sql b/ArquivosAuxiliares/Database.sql new file mode 100644 index 0000000..27e3c15 --- /dev/null +++ b/ArquivosAuxiliares/Database.sql @@ -0,0 +1,674 @@ +-- ================================ +-- CRIAR DATABASE +-- ================================ +IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'LevelOS') +BEGIN + CREATE DATABASE LevelOS; +END +GO + +USE LevelOS; +GO + +-- ================================ +-- TABELA EMPRESA +-- ================================ +CREATE TABLE Empresa ( + Id INT IDENTITY(1,1) PRIMARY KEY, + + -- Dados bsicos + Nome VARCHAR(255) NOT NULL, + CNPJ VARCHAR(20) NOT NULL UNIQUE, + TipoEmpresa VARCHAR(20) NOT NULL, + RegimeTributario VARCHAR(30) NOT NULL, + CNAE VARCHAR(20) NOT NULL, + + -- Endereo + Cep VARCHAR(15) NOT NULL, + Endereco VARCHAR(255) NOT NULL, + Numero INT NOT NULL, + Complemento VARCHAR(255), + Bairro VARCHAR(255) NOT NULL, + Cidade VARCHAR(255) NOT NULL, + UF CHAR(2) NOT NULL, + Pais VARCHAR(50), + + -- Contatos + Telefone1 VARCHAR(20), + Telefone2 VARCHAR(20), + Celular VARCHAR(20), + Whatsapp VARCHAR(20), + Email VARCHAR(150) NOT NULL, + Site VARCHAR(255), + + -- Fiscal + InscricaoEstadual VARCHAR(20) UNIQUE, + InscricaoMunicipal VARCHAR(20) UNIQUE, + + -- Contador + CNPJCPF_Contador VARCHAR(20), + Nome_Contador VARCHAR(255), + + -- Sistema + TextoParaRecibo VARCHAR(MAX), + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE() +); +GO + +-- ================================ +-- CONFIGURAES +-- ================================ +CREATE TABLE Empresa_config ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Aparncia + NomeSistema VARCHAR(255), + CorPrimaria VARCHAR(20), + CorSecundaria VARCHAR(20), + Logo VARCHAR(255), + Favicon VARCHAR(255), + + -- OS + ExibirCPFCliente BIT DEFAULT 1, + ExibirTelefoneCliente BIT DEFAULT 1, + ExibirGarantia BIT DEFAULT 1, + DiasGarantiaPadrao INT DEFAULT 90, + + -- Financeiro + GerarReciboAutomatico BIT DEFAULT 1, + ExibirValoresOS BIT DEFAULT 1, + + -- Comunicao + EnviarEmailAutomatico BIT DEFAULT 0, + EnviarWhatsappAutomatico BIT DEFAULT 0, + + -- Sistema + ModoEscuro BIT DEFAULT 0, + PermitirEdicaoOSFinalizada BIT DEFAULT 0, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + CONSTRAINT FK_ConfigEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + CONSTRAINT UQ_ConfigEmpresa UNIQUE (EmpresaId) +); +GO + +-- ================================ +-- FUNCIONRIOS +-- ================================ +CREATE TABLE Funcionarios ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Dados pessoais + Nome VARCHAR(255) NOT NULL, + CPF VARCHAR(14), + DataNascimento DATE, + + -- Contato + Telefone VARCHAR(20), + Celular VARCHAR(20), + Email VARCHAR(150) NOT NULL, + + -- Login + Usuario VARCHAR(50) NOT NULL, + SenhaHash VARCHAR(255) NOT NULL, + + -- Permisso + TipoConta VARCHAR(20) NOT NULL DEFAULT 'Atendente', + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + UltimoLogin DATETIME, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Constraints + CONSTRAINT FK_FuncionarioEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + CONSTRAINT UQ_LoginEmpresa UNIQUE (EmpresaId, Usuario) +); +GO +-- ================================ +-- FORNECEDORES +-- ================================ + +CREATE TABLE Fornecedores ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Dados bsicos + Nome VARCHAR(255) NOT NULL, + TipoPessoa VARCHAR(2) NOT NULL, -- PF ou PJ + Documento VARCHAR(20) NOT NULL, -- CPF ou CNPJ + + -- Contato + Telefone VARCHAR(20), + Celular VARCHAR(20), + Whatsapp VARCHAR(20), + Email VARCHAR(150), + + -- Endereo + Cep VARCHAR(15), + Endereco VARCHAR(255), + Numero INT, + Complemento VARCHAR(255), + Bairro VARCHAR(255), + Cidade VARCHAR(255), + UF CHAR(2), + + -- Dados adicionais + NomeFantasia VARCHAR(255), + InscricaoEstadual VARCHAR(20), + Site VARCHAR(255), + Observacoes VARCHAR(MAX), + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamento + CONSTRAINT FK_FornecedorEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + -- Evita duplicidade por empresa + CONSTRAINT UQ_Fornecedor_Doc UNIQUE (EmpresaId, Documento) +); +GO + +-- ================================ +-- TRANSPORTADORAS +-- ================================ +CREATE TABLE Transportadoras ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Dados bsicos + RazaoSocial VARCHAR(255) NOT NULL, + NomeFantasia VARCHAR(255), + CNPJ VARCHAR(20) NOT NULL, + + -- Contato + Telefone VARCHAR(20), + Celular VARCHAR(20), + Whatsapp VARCHAR(20), + Email VARCHAR(150), + + -- Endereo + Cep VARCHAR(15), + Endereco VARCHAR(255), + Numero INT, + Complemento VARCHAR(255), + Bairro VARCHAR(255), + Cidade VARCHAR(255), + UF CHAR(2), + + -- Dados de transporte + TipoFrete VARCHAR(20), -- CIF / FOB / etc + PrazoEntrega INT, -- em dias + ValorFretePadrao DECIMAL(10,2), + + -- Sistema + Observacoes VARCHAR(MAX), + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamento + CONSTRAINT FK_TransportadoraEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + -- Evita duplicidade + CONSTRAINT UQ_Transportadora_CNPJ UNIQUE (EmpresaId, CNPJ) +); +GO +-- ================================ +-- CLIENTES +-- ================================ +CREATE TABLE Clientes ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Dados principais + Nome VARCHAR(255) NOT NULL, + NomeFantasia VARCHAR(255), + TipoPessoa VARCHAR(2) NOT NULL, -- PF / PJ + Documento VARCHAR(20) NOT NULL, -- CPF/CNPJ + RG VARCHAR(20), + InscricaoMunicipal VARCHAR(20), + DataNascimento DATE, + + -- Contato + Contato VARCHAR(255), + Telefone1 VARCHAR(20), + Telefone2 VARCHAR(20), + Celular VARCHAR(20), + Whatsapp VARCHAR(20), + Email VARCHAR(150), + EmailNFe VARCHAR(150), + Site VARCHAR(255), + + -- Classificao + Grupo VARCHAR(100), + + -- Endereo + Cep VARCHAR(15), + Endereco VARCHAR(255), + Numero INT, + Complemento VARCHAR(255), + Bairro VARCHAR(255), + Cidade VARCHAR(255), + UF CHAR(2), + Pais VARCHAR(50), + + -- Financeiro + LimiteCredito DECIMAL(10,2) DEFAULT 0, + Bloqueado BIT DEFAULT 0, + ObservacoesCobranca VARCHAR(MAX), + + -- Vendas / OS + VendedorPadraoId INT NULL, + TipoConsumidor VARCHAR(50), -- Consumidor final, revenda etc + + -- Sistema + Observacoes VARCHAR(MAX), + + -- Extras (campos custom) + CampoExtra1 VARCHAR(255), + CampoExtra2 VARCHAR(255), + CampoExtra3 VARCHAR(255), + + -- Carteiras virtuais + Bitcoin VARCHAR(255), + Ethereum VARCHAR(255), + Litecoin VARCHAR(255), + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + UltimaCompra DATETIME, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamento + CONSTRAINT FK_ClienteEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + -- Evita duplicidade + CONSTRAINT UQ_Cliente_Doc UNIQUE (EmpresaId, Documento) +); +GO + +-- ================================ +-- SERVIOS +-- ================================ +CREATE TABLE Servicos ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Dados bsicos + Nome VARCHAR(255) NOT NULL, + Descricao VARCHAR(MAX), + + -- Valores + ValorPadrao DECIMAL(10,2) NOT NULL, + Custo DECIMAL(10,2), + + -- Comisso + TipoComissao VARCHAR(10) NOT NULL DEFAULT 'Percentual', -- Percentual ou Fixo + ValorComissao DECIMAL(10,2) NOT NULL DEFAULT 0, + + -- Tempo + TempoEstimado INT, -- em minutos + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamento + CONSTRAINT FK_ServicoEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE +); +GO +-- ================================ +-- Situao OS +-- ================================ +CREATE TABLE SituacoesOS ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Identificao + Descricao VARCHAR(255) NOT NULL, + + -- Classificao (os 3 grupos da tela) + Tipo VARCHAR(20) NOT NULL, + -- Entrada | Oficina | Saida + + -- Regras da OS + ConsideraAberta BIT NOT NULL DEFAULT 1, + ConsideraFechada BIT NOT NULL DEFAULT 0, + MarcaComoPronto BIT NOT NULL DEFAULT 0, + + -- Aparncia (igual na tela) + CorFundo VARCHAR(20), + CorFonte VARCHAR(20), + + -- Financeiro (opcional) + PlanoContasId INT NULL, + + -- Controle + Ordem INT DEFAULT 0, -- ordem de exibio + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamento + CONSTRAINT FK_SituacaoEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE +); +GO +-- ================================ +-- CONTRATOS +-- ================================ +CREATE TABLE Contratos ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + ClienteId INT NOT NULL, + + -- Dados principais + Descricao VARCHAR(255), + Observacoes VARCHAR(MAX), + + Valor DECIMAL(10,2) NOT NULL, + DataInicio DATE, + DataValidade DATE, + + -- Controle de franquia (ex: horas inclusas) + FranquiaTempo INT, -- minutos ou horas (voc define padro) + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamentos + CONSTRAINT FK_ContratoEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + CONSTRAINT FK_ContratoCliente + FOREIGN KEY (ClienteId) REFERENCES Clientes(Id) +); +GO +-- ================================ +-- CONTRATOS - EQUIPAMENTOS +-- ================================ +CREATE TABLE ContratoEquipamentos ( + Id INT IDENTITY(1,1) PRIMARY KEY, + ContratoId INT NOT NULL, + + -- Dados do equipamento + Modelo VARCHAR(255), + Marca VARCHAR(255), + Operadora VARCHAR(100), + Serial VARCHAR(100), + NumeroPatrimonio VARCHAR(100), + + Observacoes VARCHAR(MAX), + + -- Relacionamento + CONSTRAINT FK_ContratoEquipamento + FOREIGN KEY (ContratoId) REFERENCES Contratos(Id) ON DELETE CASCADE +); +GO +-- ================================ +-- PLANO DE CONTAS +-- ================================ +CREATE TABLE PlanoDeContas ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + -- Hierarquia + ContaPaiId INT NULL, + + -- Identificao + Nome VARCHAR(255) NOT NULL, + Codigo VARCHAR(50), -- Ex: 1.01.02 + Tipo VARCHAR(20) NOT NULL, -- Receita / Despesa + + -- Controle + AceitaLancamento BIT NOT NULL DEFAULT 1, -- se pode lanar direto + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamentos + CONSTRAINT FK_PlanoContaEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + CONSTRAINT FK_PlanoContaPai + FOREIGN KEY (ContaPaiId) REFERENCES PlanoDeContas(Id) +); +GO +-- ================================ +-- CONTAS A PAGAR +-- ================================ +CREATE TABLE ContasReceber ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + ClienteId INT NOT NULL, + + -- Classificao + PlanoContaId INT NOT NULL, + + -- Origem (contrato, venda futura, etc) + ContratoId INT NULL, + + -- Dados financeiros + Descricao VARCHAR(255), + Valor DECIMAL(10,2) NOT NULL, + DataEmissao DATE, + DataVencimento DATE NOT NULL, + DataPagamento DATE, + + -- Controle + Status VARCHAR(20) NOT NULL DEFAULT 'Pendente', + -- Pendente / Pago / Cancelado / Atrasado + + ValorPago DECIMAL(10,2), + Juros DECIMAL(10,2) DEFAULT 0, + Multa DECIMAL(10,2) DEFAULT 0, + Desconto DECIMAL(10,2) DEFAULT 0, + + -- Observaes + Observacoes VARCHAR(MAX), + + -- Controle sistema + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamentos + CONSTRAINT FK_ReceberEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + CONSTRAINT FK_ReceberCliente + FOREIGN KEY (ClienteId) REFERENCES Clientes(Id), + + CONSTRAINT FK_ReceberPlano + FOREIGN KEY (PlanoContaId) REFERENCES PlanoDeContas(Id), + + CONSTRAINT FK_ReceberContrato + FOREIGN KEY (ContratoId) REFERENCES Contratos(Id) +); +GO +-- ================================ +-- CONTAS A PAGAR +-- ================================ +CREATE TABLE ContasPagar ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + FornecedorId INT NOT NULL, + + -- Classificao + PlanoContaId INT NOT NULL, + + -- Dados financeiros + Descricao VARCHAR(255), + Valor DECIMAL(10,2) NOT NULL, + DataEmissao DATE, + DataVencimento DATE NOT NULL, + DataPagamento DATE, + + -- Controle + Status VARCHAR(20) NOT NULL DEFAULT 'Pendente', + + ValorPago DECIMAL(10,2), + Juros DECIMAL(10,2) DEFAULT 0, + Multa DECIMAL(10,2) DEFAULT 0, + Desconto DECIMAL(10,2) DEFAULT 0, + + -- Observaes + Observacoes VARCHAR(MAX), + + -- Controle sistema + Ativo BIT NOT NULL DEFAULT 1, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamentos + CONSTRAINT FK_PagarEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + CONSTRAINT FK_PagarFornecedor + FOREIGN KEY (FornecedorId) REFERENCES Fornecedores(Id), + + CONSTRAINT FK_PagarPlano + FOREIGN KEY (PlanoContaId) REFERENCES PlanoDeContas(Id) +); +GO + +-- ================================ +-- USURIOS DO SISTEMA +-- ================================ +CREATE TABLE Usuarios ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + Nome VARCHAR(255) NOT NULL, + Email VARCHAR(150) NOT NULL, + Usuario VARCHAR(50) NOT NULL, + SenhaHash VARCHAR(255) NOT NULL, + + -- Controle + Ativo BIT NOT NULL DEFAULT 1, + UltimoLogin DATETIME, + + -- Auditoria + CriadoEm DATETIME DEFAULT GETDATE(), + AtualizadoEm DATETIME DEFAULT GETDATE(), + + -- Relacionamento + CONSTRAINT FK_UsuarioEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE, + + -- Evita login duplicado por empresa + CONSTRAINT UQ_Usuario_Login UNIQUE (EmpresaId, Usuario) +); +GO +-- ================================ +-- PERFIS DE USURIO +-- ================================ +CREATE TABLE Perfis ( + Id INT IDENTITY(1,1) PRIMARY KEY, + EmpresaId INT NOT NULL, + + Nome VARCHAR(100) NOT NULL, -- Admin, Tcnico, etc + Descricao VARCHAR(255), + + Ativo BIT NOT NULL DEFAULT 1, + + CONSTRAINT FK_PerfilEmpresa + FOREIGN KEY (EmpresaId) REFERENCES Empresa(Id) ON DELETE CASCADE +); +GO +-- ================================ +-- PERMISSES DE USURIO +-- ================================ +CREATE TABLE Permissoes ( + Id INT IDENTITY(1,1) PRIMARY KEY, + + Nome VARCHAR(100) NOT NULL, -- Ex: CLIENTE_CADASTRAR + Descricao VARCHAR(255) +); +GO +-- ================================ +-- PERFIL - PERMISSES +-- ================================ +CREATE TABLE PerfilPermissoes ( + Id INT IDENTITY(1,1) PRIMARY KEY, + PerfilId INT NOT NULL, + PermissaoId INT NOT NULL, + + CONSTRAINT FK_PerfilPermissao_Perfil + FOREIGN KEY (PerfilId) REFERENCES Perfis(Id) ON DELETE CASCADE, + + CONSTRAINT FK_PerfilPermissao_Permissao + FOREIGN KEY (PermissaoId) REFERENCES Permissoes(Id) ON DELETE CASCADE, + + CONSTRAINT UQ_PerfilPermissao UNIQUE (PerfilId, PermissaoId) +); +GO +-- ================================ +-- USURIO - PERFIL +-- ================================ +CREATE TABLE UsuarioPerfis ( + Id INT IDENTITY(1,1) PRIMARY KEY, + UsuarioId INT NOT NULL, + PerfilId INT NOT NULL, + + CONSTRAINT FK_UsuarioPerfil_Usuario + FOREIGN KEY (UsuarioId) + REFERENCES Usuarios(Id) + ON DELETE CASCADE, + + CONSTRAINT FK_UsuarioPerfil_Perfil + FOREIGN KEY (PerfilId) + REFERENCES Perfis(Id) + ON DELETE NO ACTION, + + CONSTRAINT UQ_UsuarioPerfil UNIQUE (UsuarioId, PerfilId) +); +GO \ No newline at end of file diff --git a/ArquivosAuxiliares/ExemploUSO.txt b/ArquivosAuxiliares/ExemploUSO.txt new file mode 100644 index 0000000..4adeae9 --- /dev/null +++ b/ArquivosAuxiliares/ExemploUSO.txt @@ -0,0 +1,95 @@ +using DALL; +using System.Data; + +// ============================================= +// Configuração da connection string +// ============================================= +var connectionString = "Server=206.42.13.180;Database=Levelcode-LevelOS;User Id=sa;Password=suasenha;TrustServerCertificate=True;"; + +var backupService = new DALLBackupService(connectionString); + +// ============================================= +// Backup FULL +// ============================================= +var resultadoFull = backupService.ExecutarBackupFull(); + +if (resultadoFull.Sucesso) + Console.WriteLine($"✅ Backup FULL concluído em {resultadoFull.Duracao.TotalSeconds:F1}s"); +else + Console.WriteLine($"❌ Erro no Backup FULL: {resultadoFull.Erro}"); + +// ============================================= +// Backup DIFERENCIAL +// ============================================= +var resultadoDiff = backupService.ExecutarBackupDiferencial(); + +if (resultadoDiff.Sucesso) + Console.WriteLine($"✅ Backup DIFERENCIAL concluído em {resultadoDiff.Duracao.TotalSeconds:F1}s"); +else + Console.WriteLine($"❌ Erro no Backup DIFERENCIAL: {resultadoDiff.Erro}"); + +// ============================================= +// Limpeza de backups antigos +// ============================================= +var resultadoLimpeza = backupService.ExecutarLimpeza(); + +if (resultadoLimpeza.Sucesso) + Console.WriteLine($"✅ Limpeza concluída em {resultadoLimpeza.Duracao.TotalSeconds:F1}s"); +else + Console.WriteLine($"❌ Erro na Limpeza: {resultadoLimpeza.Erro}"); + +// ============================================= +// Listar histórico de backups +// ============================================= +var historico = backupService.ListarHistoricoBackups(); + +Console.WriteLine("\n📋 Histórico de Backups:"); +Console.WriteLine($"{"Tipo",-15} {"TamanhoMB",-12} {"Inicio",-22} {"Arquivo"}"); +Console.WriteLine(new string('-', 90)); + +foreach (DataRow row in historico.Rows) +{ + Console.WriteLine($"{row["Tipo"],-15} {row["TamanhoMB"],-12} {row["Inicio"],-22} {row["Arquivo"]}"); +} + +// ============================================= +// Restauração FULL + DIFERENCIAL +// ============================================= + +// Pega o arquivo mais recente do histórico automaticamente +string arquivoFull = ""; +string arquivoDiff = ""; + +foreach (DataRow row in historico.Rows) +{ + if (row["Tipo"].ToString() == "FULL" && string.IsNullOrEmpty(arquivoFull)) + arquivoFull = row["Arquivo"].ToString()!; + + if (row["Tipo"].ToString() == "DIFERENCIAL" && string.IsNullOrEmpty(arquivoDiff)) + arquivoDiff = row["Arquivo"].ToString()!; + + if (!string.IsNullOrEmpty(arquivoFull) && !string.IsNullOrEmpty(arquivoDiff)) + break; +} + +// Restaura FULL +Console.WriteLine($"\n🔁 Restaurando FULL: {arquivoFull}"); +var r1 = backupService.RestaurarBackup(arquivoFull, TipoRestauracao.Full); + +if (r1.Sucesso) +{ + Console.WriteLine($"✅ FULL restaurado em {r1.Duracao.TotalSeconds:F1}s"); + + // Aplica DIFERENCIAL após o FULL + Console.WriteLine($"🔁 Aplicando DIFERENCIAL: {arquivoDiff}"); + var r2 = backupService.RestaurarBackup(arquivoDiff, TipoRestauracao.Diferencial); + + if (r2.Sucesso) + Console.WriteLine($"✅ DIFERENCIAL aplicado em {r2.Duracao.TotalSeconds:F1}s — Banco online!"); + else + Console.WriteLine($"❌ Erro no DIFERENCIAL: {r2.Erro}"); +} +else +{ + Console.WriteLine($"❌ Erro no FULL: {r1.Erro}"); +} \ No newline at end of file diff --git a/ArquivosAuxiliares/InsertsLotes.sql b/ArquivosAuxiliares/InsertsLotes.sql new file mode 100644 index 0000000..3dac05e --- /dev/null +++ b/ArquivosAuxiliares/InsertsLotes.sql @@ -0,0 +1,157 @@ +INSERT INTO Bancos (NUMERO, NOME) VALUES +(1,'Banco do Brasil S/A'), +(2,'Banco Central do Brasil'), +(3,'Banco da Amazonia S/A'), +(4,'Banco do Nordeste do Brasil S/A'), +(8,'Banco Santander Meridional S/A'), +(21,'BANESTES S/A - Banco Est.Esp.Santo'), +(22,'CREDIREAL'), +(24,'Banco de Pernambuco S/A - BANDEPE'), +(25,'Banco Alfa S/A'), +(27,'Banco Estado Santa Catarina S/A'), +(28,'BANEB'), +(29,'Banco BANERJ S/A'), +(30,'PARAIBAN - Banco da Paraiba S/A'), +(31,'Banco BEG S/A'), +(33,'SANTANDER'), +(34,'Banco BEA S/A'), +(35,'Banco do Estado do Ceara S/A - BEC'), +(36,'Banco do Estado do Maranhao S/A'), +(37,'Banco do Estado do Para S/A'), +(38,'Banco BANESTADO S/A'), +(39,'Banco do Estado do Piaui S/A'), +(40,'Banco Cargill S/A'), +(41,'Banco Est. Rio Grande do Sul S/A'), +(44,'Banco BVA S/A'), +(45,'Banco OPPORTUNITY S/A'), +(47,'Banco Est. de Sergipe S/A'), +(48,'Banco BENGE S/A'), +(63,'IBIBANK S/A - Banco Multiplo'), +(65,'LEMON BANK Banco Multiplo S/A'), +(66,'Banco MORGAN S. D. Witter S/A'), +(67,'Banco BANEB S/A'), +(68,'Banco BEA S/A'), +(70,'BRB-Banco de Brasilia S/A'), +(89,'CREDISAN'), +(104,'Caixa Economica Federal'), +(106,'Banco Itabanco S/A'), +(107,'Banco BBM S/A'), +(109,'CREDIBANCO S/A'), +(116,'Banco BNL do Brasil S/A'), +(148,'Bank Of America Brasil S/A'), +(151,'Banco Nossa Caixa S/A'), +(175,'Banco Finasa S/A'), +(184,'Banco BBA Creditanstalt S/A'), +(204,'BCO Inter American Express S/A'), +(208,'Banco Pactual S/A'), +(210,'DRESDNER Bank Lateinamerika A.'), +(212,'Banco Matone S/A'), +(213,'Banco ARBI S/A'), +(214,'Banco DIBENS S/A'), +(215,'Banco Com e Invest Sudameris'), +(216,'Banco Regional MALCON S/A'), +(217,'Banco JOHN DEERE S/A'), +(218,'Banco Bonsucesso S/A'), +(219,'Banco ZOGBI S/A'), +(222,'BCO Credit Lyonnais Brasil S/A'), +(224,'Banco Fibra S/A'), +(225,'Banco Brascan S/A'), +(229,'Banco Cruzeiro do Sul S/A'), +(230,'Banco Bandeirantes S/A'), +(231,'Banco Boavista interatlantico S/A'), +(233,'Banco GE Capital S/A'), +(237,'Banco Bradesco S/A'), +(240,'Banco de Credito Real de M.G. S/A'), +(241,'Banco Classico S/A'), +(243,'Banco STOCK Maxima S/A'), +(244,'Banco Cidade S/A'), +(246,'Banco ABC-Brasil S/A'), +(247,'UBS WARBURG S/A'), +(249,'Banco Investcred UNIBANCO S/A'), +(250,'Banco SCHAHIN S/A'), +(252,'Banco FININVEST S/A'), +(254,'PARANA Banco S/A'), +(263,'Banco CACIQUE S/A'), +(265,'Banco Fator S/A'), +(266,'Banco Cedula S/A'), +(275,'Banco ABN AMRO Real S/A'), +(291,'Banco de Cred. Nacional S/A'), +(294,'BCR'), +(300,'Banco de LA Nacion Argentina'), +(318,'Banco BMG S/A'), +(320,'Banco Ind. e Com. S/A'), +(341,'Banco Itau S/A'), +(346,'Banco BFB'), +(347,'Banco Sudameris Brasil S/A'), +(351,'Banco Bozano Simonsen S/A'), +(353,'Banco Santander S/A'), +(356,'Banco ABN AMRO S/A'), +(366,'Banco Societe Generale Bras. S/A'), +(370,'Banco Westlb do Brasil S/A'), +(376,'Banco CHASE Manhattan S/A'), +(389,'Banco Mercantil do Brasil S/A'), +(392,'Banco Mercantil de Sao Paulo S/A'), +(394,'Banco BMC S/A'), +(399,'HSBC Bank Brasil S/A'), +(409,'Unibanco Uniao de Bancos Bras. S/A'), +(412,'Banco Capital S/A'), +(422,'Banco Safra S/A'), +(424,'Banco Santander Nordeste S/A'), +(453,'Banco Rural S/A'), +(456,'Banco de Tokio Mitsubishi BR S/A'), +(464,'Banco Sumitomo Mitsui Bras. S/A'), +(472,'LLOYDS Bank PLC'), +(473,'Banco Financial Portugues S/A'), +(477,'Banco Citibank N/A'), +(479,'Bankboston Banco Multiplo S/A'), +(487,'Deutsche Bank S/A'), +(488,'Morgan G. Trust Company of NY'), +(492,'ING Bank N.V.'), +(493,'Banco Union - Brasil S/A'), +(494,'Banco de La Rep. Or.Del Uruguai'), +(495,'Banco de La Provinc.Buenos Aires'), +(496,'Banco Uno-E Brasil S/A'), +(505,'Banco Credit S. F. Boston S/A'), +(600,'Banco Luso Brasileiro S/A'), +(604,'Banco Industrial Brasileiro S/A'), +(610,'Banco VR S/A'), +(611,'Banco Paulista S/A'), +(612,'Banco Guanabara S/A'), +(613,'Banco Pecunia S/A'), +(623,'Banco Panamericano S/A'), +(626,'Banco FICSA S/A'), +(630,'Banco Intercap S/A'), +(633,'Banco Rendimento S/A'), +(634,'Banco Triangulo S/A'), +(637,'Banco SOFISA S/A'), +(638,'Banco Prosper S/A'), +(641,'Banco Bilbao Vizcaya Argentaria Brasil S/A'), +(643,'Banco Pine S/A'), +(650,'Banco PEBB S/A'), +(652,'Banco Frances e Brasileiro S/A'), +(653,'Banco Indusval S/A'), +(654,'Banco A. J. RENNER S/A'), +(655,'Banco Votorantim S/A'), +(702,'Banco Santos S/A'), +(707,'Banco Daycoval S/A'), +(719,'Banco Banif Primus S/A'), +(721,'Banco Credibel S/A'), +(733,'Banco das Nacoes S/A'), +(734,'Banco Gerdau S/A'), +(735,'Banco Pottencial S/A'), +(738,'Banco Morada S/A'), +(739,'Banco BGN S/A'), +(740,'Banco BARCLAYS S/A'), +(741,'Banco Ribeirao Preto S/A'), +(743,'Banco Emblema S/A'), +(744,'Bankboston N.A.'), +(745,'Banco Citibank S/A'), +(746,'Banco Modal S/A'), +(747,'Banco Rabobank INT Brasil S/A'), +(748,'Banco Coop. Sic. S/A BANSICREDI'), +(749,'BR Banco Mercantil S/A'), +(751,'DRESDNER Bank Brasil S/A'), +(752,'Banco BNP Paribas Brasil S/A'), +(753,'Banco Comercial Uruguai S/A'), +(756,'Banco Cooperativo do Brasil S/A'), +(757,'Banco KEB do Brasil S/A'); \ No newline at end of file diff --git a/ArquivosAuxiliares/ProcedureBKP-DIFF_AUTO.sql b/ArquivosAuxiliares/ProcedureBKP-DIFF_AUTO.sql new file mode 100644 index 0000000..ad63822 --- /dev/null +++ b/ArquivosAuxiliares/ProcedureBKP-DIFF_AUTO.sql @@ -0,0 +1,44 @@ +USE [msdb] +GO + +-- ============================================= +-- Job: Backup DIFERENCIAL - a cada 6 horas +-- ============================================= +EXEC sp_add_job @job_name = N'Backup DIFERENCIAL - Levelcode-LevelOS'; + +EXEC sp_add_jobstep + @job_name = N'Backup DIFERENCIAL - Levelcode-LevelOS', + @step_name = N'Executar Backup DIFERENCIAL', + @command = N'EXEC [Levelcode-LevelOS].[dbo].[sp_BackupDiferencial]', + @database_name = N'Levelcode-LevelOS'; + +EXEC sp_add_schedule + @schedule_name = N'A cada 6 horas', + @freq_type = 4, -- diário + @freq_interval = 1, + @freq_subday_type = 8, -- a cada X horas + @freq_subday_interval = 6, -- 6 horas + @active_start_time = 080000; -- começa às 08:00 + +EXEC sp_attach_schedule + @job_name = N'Backup DIFERENCIAL - Levelcode-LevelOS', + @schedule_name = N'A cada 6 horas'; + +EXEC sp_add_jobserver + @job_name = N'Backup DIFERENCIAL - Levelcode-LevelOS'; +GO + +-- Confirma os jobs criados +SELECT + j.name AS Job, + s.name AS Schedule, + s.active_start_time, + CASE s.freq_subday_type + WHEN 8 THEN CAST(s.freq_subday_interval AS VARCHAR) + 'h em ' + CAST(s.freq_subday_interval AS VARCHAR) + 'h' + ELSE 'Diário fixo' + END AS Frequencia +FROM msdb.dbo.sysjobs j +JOIN msdb.dbo.sysjobschedules js ON j.job_id = js.job_id +JOIN msdb.dbo.sysschedules s ON js.schedule_id = s.schedule_id +WHERE j.name LIKE '%Levelcode%' +ORDER BY j.name; \ No newline at end of file diff --git a/ArquivosAuxiliares/ProcedureBKP-FULL_AUTO.sql b/ArquivosAuxiliares/ProcedureBKP-FULL_AUTO.sql new file mode 100644 index 0000000..01251e3 --- /dev/null +++ b/ArquivosAuxiliares/ProcedureBKP-FULL_AUTO.sql @@ -0,0 +1,25 @@ +USE [msdb] +GO + +-- Job: Backup FULL - toda madrugada às 02:00 +EXEC sp_add_job @job_name = N'Backup FULL - Levelcode-LevelOS'; + +EXEC sp_add_jobstep + @job_name = N'Backup FULL - Levelcode-LevelOS', + @step_name = N'Executar Backup FULL', + @command = N'EXEC [Levelcode-LevelOS].[dbo].[sp_BackupFull]', + @database_name = N'Levelcode-LevelOS'; + +EXEC sp_add_schedule + @schedule_name = N'Diario 02:00', + @freq_type = 4, -- diário + @freq_interval = 1, + @active_start_time = 020000; -- 02:00:00 + +EXEC sp_attach_schedule + @job_name = N'Backup FULL - Levelcode-LevelOS', + @schedule_name = N'Diario 02:00'; + +EXEC sp_add_jobserver + @job_name = N'Backup FULL - Levelcode-LevelOS'; +GO \ No newline at end of file diff --git a/ArquivosAuxiliares/ProcedureBackups.sql b/ArquivosAuxiliares/ProcedureBackups.sql new file mode 100644 index 0000000..5214bd6 --- /dev/null +++ b/ArquivosAuxiliares/ProcedureBackups.sql @@ -0,0 +1,61 @@ +USE [Levelcode-LevelOS] +GO + +DROP PROCEDURE IF EXISTS [dbo].[sp_BackupFull] +GO + +CREATE PROCEDURE [dbo].[sp_BackupFull] +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @Caminho NVARCHAR(500); + + SET @Caminho = '/var/opt/mssql/backups/Levelcode-LevelOS_FULL_' + + FORMAT(GETDATE(), 'yyyyMMdd_HHmmss') + '.bak'; + + BACKUP DATABASE [Levelcode-LevelOS] + TO DISK = @Caminho + WITH FORMAT, + INIT, + NAME = 'Backup FULL - Levelcode-LevelOS', + STATS = 10; +END +GO + +-- Confirma criação +SELECT name, create_date, modify_date +FROM sys.procedures +WHERE name = 'sp_BackupFull'; + + +USE [Levelcode-LevelOS] +GO + +DROP PROCEDURE IF EXISTS [dbo].[sp_BackupDiferencial] +GO + +CREATE PROCEDURE [dbo].[sp_BackupDiferencial] +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @Caminho NVARCHAR(500); + + SET @Caminho = '/var/opt/mssql/backups/Levelcode-LevelOS_DIFF_' + + FORMAT(GETDATE(), 'yyyyMMdd_HHmmss') + '.bak'; + + BACKUP DATABASE [Levelcode-LevelOS] + TO DISK = @Caminho + WITH DIFFERENTIAL, + INIT, + NAME = 'Backup DIFERENCIAL - Levelcode-LevelOS', + STATS = 10; +END +GO + +-- Confirma ambas criadas +SELECT name, create_date, modify_date +FROM sys.procedures +WHERE name IN ('sp_BackupFull', 'sp_BackupDiferencial') +ORDER BY name; \ No newline at end of file diff --git a/ArquivosAuxiliares/ProcedureRestaurarBanco.sql b/ArquivosAuxiliares/ProcedureRestaurarBanco.sql new file mode 100644 index 0000000..cbd51ec --- /dev/null +++ b/ArquivosAuxiliares/ProcedureRestaurarBanco.sql @@ -0,0 +1,128 @@ +USE [master] +GO + +DROP PROCEDURE IF EXISTS [dbo].[sp_RestaurarBackup] +GO + +CREATE PROCEDURE [dbo].[sp_RestaurarBackup] + @Arquivo NVARCHAR(500) = NULL, + @Tipo CHAR(1) = 'F' -- 'F' = FULL | 'D' = DIFERENCIAL +AS +BEGIN + SET NOCOUNT ON; + + -- ============================================= + -- Se não informar arquivo, lista os disponíveis + -- ============================================= + IF @Arquivo IS NULL + BEGIN + PRINT '>>> Backups disponíveis no histórico:'; + + SELECT + ROW_NUMBER() OVER (ORDER BY bs.backup_finish_date DESC) AS N, + CASE bs.type + WHEN 'D' THEN 'FULL' + WHEN 'I' THEN 'DIFERENCIAL' + END AS Tipo, + bmf.physical_device_name AS Arquivo, + bs.backup_start_date AS Inicio, + bs.backup_finish_date AS Fim, + CAST(bs.backup_size / 1024.0 / 1024.0 AS DECIMAL(10,2)) AS TamanhoMB + FROM msdb.dbo.backupset bs + JOIN msdb.dbo.backupmediafamily bmf + ON bs.media_set_id = bmf.media_set_id + WHERE bs.database_name = 'Levelcode-LevelOS' + ORDER BY bs.backup_finish_date DESC; + + PRINT '>>> Copie o caminho do arquivo desejado e execute:'; + PRINT '>>> EXEC sp_RestaurarBackup @Arquivo = ''caminho_aqui'', @Tipo = ''F'''; + RETURN; + END + + -- ============================================= + -- Verifica o arquivo com RESTORE HEADERONLY + -- ============================================= + BEGIN TRY + RESTORE HEADERONLY FROM DISK = @Arquivo; + END TRY + BEGIN CATCH + RAISERROR('Arquivo não encontrado ou inválido: %s', 16, 1, @Arquivo); + RETURN; + END CATCH + + -- ============================================= + -- Coloca o banco em SINGLE_USER + -- ============================================= + PRINT '>>> Preparando banco para restauração...'; + + BEGIN TRY + ALTER DATABASE [Levelcode-LevelOS] + SET SINGLE_USER WITH ROLLBACK IMMEDIATE; + END TRY + BEGIN CATCH + PRINT '>>> Aviso: ' + ERROR_MESSAGE(); + END CATCH + + -- ============================================= + -- Restauração FULL + -- ============================================= + IF @Tipo = 'F' + BEGIN + PRINT '>>> Restaurando FULL: ' + @Arquivo; + + RESTORE DATABASE [Levelcode-LevelOS] + FROM DISK = @Arquivo + WITH REPLACE, + NORECOVERY, + STATS = 10; + + ALTER DATABASE [Levelcode-LevelOS] SET MULTI_USER; + + PRINT '>>> FULL restaurado com sucesso!'; + PRINT '>>> Se tiver diferencial execute: EXEC sp_RestaurarBackup @Arquivo = ''caminho_diff'', @Tipo = ''D'''; + PRINT '>>> Se não tiver diferencial execute: RESTORE DATABASE [Levelcode-LevelOS] WITH RECOVERY;'; + END + + -- ============================================= + -- Restauração DIFERENCIAL + -- ============================================= + IF @Tipo = 'D' + BEGIN + PRINT '>>> Aplicando DIFERENCIAL: ' + @Arquivo; + + RESTORE DATABASE [Levelcode-LevelOS] + FROM DISK = @Arquivo + WITH RECOVERY, + STATS = 10; + + ALTER DATABASE [Levelcode-LevelOS] SET MULTI_USER; + + PRINT '>>> Banco restaurado e online!'; + END +END +GO + +--Como usar -- +-- 1. Lista os backups disponíveis +EXEC [master].[dbo].[sp_RestaurarBackup]; + +-- 2. Restaura apenas o FULL (sem diferencial) +EXEC [master].[dbo].[sp_RestaurarBackup] + @Arquivo = '/var/opt/mssql/backups/Levelcode-LevelOS_FULL_20260413_020000.bak', + @Tipo = 'F'; + +-- Finaliza o banco após o FULL sem diferencial +RESTORE DATABASE [Levelcode-LevelOS] WITH RECOVERY; + +-- 3. Restaura FULL + DIFERENCIAL (sequência completa) +EXEC [master].[dbo].[sp_RestaurarBackup] + @Arquivo = '/var/opt/mssql/backups/Levelcode-LevelOS_FULL_20260413_020000.bak', + @Tipo = 'F'; + +EXEC [master].[dbo].[sp_RestaurarBackup] + @Arquivo = '/var/opt/mssql/backups/Levelcode-LevelOS_DIFF_20260413_080000.bak', + @Tipo = 'D'; + +EXEC [master].[dbo].[sp_RestaurarBackup] + @Arquivo = '/var/opt/mssql/backups/Levelcode-LevelOS_FULL_20260413_072013.bak', + @Tipo = 'F'; \ No newline at end of file diff --git a/ArquivosAuxiliares/Procedure_LIMPEZA15DIAS.sql b/ArquivosAuxiliares/Procedure_LIMPEZA15DIAS.sql new file mode 100644 index 0000000..437ff4d --- /dev/null +++ b/ArquivosAuxiliares/Procedure_LIMPEZA15DIAS.sql @@ -0,0 +1,77 @@ +USE [Levelcode-LevelOS] +GO + +-- ============================================= +-- Procedure: Limpeza de backups antigos (+15 dias) +-- ============================================= +DROP PROCEDURE IF EXISTS [dbo].[sp_LimpezaBackups] +GO + +CREATE PROCEDURE [dbo].[sp_LimpezaBackups] +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @DataCorte DATETIME = DATEADD(DAY, -15, GETDATE()); + DECLARE @Comando NVARCHAR(500); + DECLARE @Arquivo NVARCHAR(500); + + -- Cursor nos backups com mais de 15 dias + DECLARE cur CURSOR FOR + SELECT DISTINCT bmf.physical_device_name + FROM msdb.dbo.backupset bs + JOIN msdb.dbo.backupmediafamily bmf + ON bs.media_set_id = bmf.media_set_id + WHERE bs.database_name = 'Levelcode-LevelOS' + AND bs.backup_finish_date < @DataCorte + AND bmf.physical_device_name LIKE '/var/opt/mssql/backups/%'; + + OPEN cur; + FETCH NEXT FROM cur INTO @Arquivo; + + WHILE @@FETCH_STATUS = 0 + BEGIN + -- Deleta o arquivo físico no Linux + SET @Comando = 'rm -f ' + @Arquivo; + EXEC xp_cmdshell @Comando; + + -- Remove o histórico do msdb + PRINT 'Removido: ' + @Arquivo; + + FETCH NEXT FROM cur INTO @Arquivo; + END + + CLOSE cur; + DEALLOCATE cur; + + -- Limpa o histórico do msdb também + EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = @DataCorte; + + PRINT 'Limpeza concluída. Backups anteriores a ' + + CONVERT(NVARCHAR(20), @DataCorte, 120) + ' removidos.'; +END +GO +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +USE [Levelcode-LevelOS] +GO + +-- ============================================= +-- Procedure: Limpeza do HISTÓRICO (msdb) +15 dias +-- ============================================= +DROP PROCEDURE IF EXISTS [dbo].[sp_LimpezaBackups] +GO + +CREATE PROCEDURE [dbo].[sp_LimpezaBackups] +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @DataCorte DATETIME = DATEADD(DAY, -15, GETDATE()); + + -- Limpa apenas o histórico do msdb (não precisa de xp_cmdshell) + EXEC msdb.dbo.sp_delete_backuphistory @oldest_date = @DataCorte; + + PRINT 'Histórico de backups anteriores a ' + + CONVERT(NVARCHAR(20), @DataCorte, 120) + ' removido do msdb.'; +END +GO \ No newline at end of file diff --git a/ArquivosAuxiliares/ScriptLimpezaServidor.sh b/ArquivosAuxiliares/ScriptLimpezaServidor.sh new file mode 100644 index 0000000..1af4c44 --- /dev/null +++ b/ArquivosAuxiliares/ScriptLimpezaServidor.sh @@ -0,0 +1,32 @@ +# Cria o script de limpeza +cat > /var/opt/mssql/backups/limpar_backups.sh << 'EOF' +#!/bin/bash +# Deleta arquivos .bak com mais de 15 dias +find /var/opt/mssql/backups/ -name "*.bak" -mtime +15 -delete +echo "[$(date)] Limpeza concluída." >> /var/opt/mssql/backups/limpeza.log +EOF + +# Dá permissão de execução +chmod +x /var/opt/mssql/backups/limpar_backups.sh + +# Agenda no cron todo domingo às 03:00 +(crontab -l 2>/dev/null; echo "0 3 * * 0 /var/opt/mssql/backups/limpar_backups.sh") | crontab - + +# Confirma o cron +crontab -l + +#------------------------------------------------------------------------------------------------- +cat > /var/opt/mssql/backups/limpar_backups.sh << 'EOF' +#!/bin/bash +find /var/opt/mssql/backups/ -name "*.bak" -mtime +15 -delete +echo "[$(date)] Limpeza concluída." >> /var/opt/mssql/backups/limpeza.log +EOF + +#Dar permissão +chmod +x /var/opt/mssql/backups/limpar_backups.sh +# Executar script +/var/opt/mssql/backups/limpar_backups.sh && cat /var/opt/mssql/backups/limpeza.log +# Agendar JOB +(crontab -l 2>/dev/null; echo "0 3 * * 0 /var/opt/mssql/backups/limpar_backups.sh") | crontab - +# confirmar agendamento +crontab -l \ No newline at end of file diff --git a/ArquivosAuxiliares/TriggerFuncionarios.sql b/ArquivosAuxiliares/TriggerFuncionarios.sql new file mode 100644 index 0000000..bb68135 --- /dev/null +++ b/ArquivosAuxiliares/TriggerFuncionarios.sql @@ -0,0 +1,14 @@ +--Gatilhos para a tabela funcionarios-- +CREATE OR ALTER TRIGGER TR_Funcionarios_GerarCodigo +ON Funcionarios +AFTER INSERT +AS +BEGIN + SET NOCOUNT ON; + + UPDATE F + SET CODIGO = CAST(100 + ((F.ID_FUNCIONARIO - 1) * 100) AS VARCHAR) + FROM Funcionarios F + INNER JOIN inserted I ON F.ID_FUNCIONARIO = I.ID_FUNCIONARIO; +END +GO \ No newline at end of file diff --git a/ArquivosAuxiliares/Trigger_AgendaCodigoAuto.sql b/ArquivosAuxiliares/Trigger_AgendaCodigoAuto.sql new file mode 100644 index 0000000..1778b25 --- /dev/null +++ b/ArquivosAuxiliares/Trigger_AgendaCodigoAuto.sql @@ -0,0 +1,13 @@ +CREATE OR ALTER TRIGGER TR_Agenda_GerarCodigo +ON Agenda +AFTER INSERT +AS +BEGIN + SET NOCOUNT ON; + + UPDATE A + SET CODIGO = 'AG' + RIGHT('0000' + CAST(A.ID_AGENDA AS VARCHAR), 4) + FROM Agenda A + INNER JOIN inserted I ON A.ID_AGENDA = I.ID_AGENDA; +END +GO \ No newline at end of file diff --git a/ControlesCustom.cs b/ControlesCustom.cs new file mode 100644 index 0000000..de894d4 --- /dev/null +++ b/ControlesCustom.cs @@ -0,0 +1,151 @@ +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace UI +{ + public class RoundTextBox : UserControl + { + private TextBox _textBox = null!; + public int Radius { get; set; } = 4; + public Color BorderColor { get; set; } = Color.LightGray; + public Color FocusColor { get; set; } = Color.Blue; + private bool _focused; + + public bool ReadOnly + { + get => _textBox.ReadOnly; + set => _textBox.ReadOnly = value; + } + public char PasswordChar + { + get => _textBox.PasswordChar; + set => _textBox.PasswordChar = value; + } + + // ── Adiciona isso aqui ── + public int SelectionStart + { + get => _textBox.SelectionStart; + set => _textBox.SelectionStart = value; + } + public new event KeyEventHandler? KeyDown + { + add => _textBox.KeyDown += value; + remove => _textBox.KeyDown -= value; + } + + public bool Multiline + { + get => _textBox.Multiline; + set + { + _textBox.Multiline = value; + _textBox.ScrollBars = value ? ScrollBars.Vertical : ScrollBars.None; + AjustarTextBox(); + } + } + + public override string Text + { + get => _textBox.Text; + set => _textBox.Text = value; + } + + public new Color BackColor + { + get => base.BackColor; + set { base.BackColor = value; if (_textBox != null) _textBox.BackColor = value; } + } + + //public RoundTextBox() + //{ + // DoubleBuffered = true; + // base.BackColor = Color.White; + // _textBox = new TextBox + // { + // BorderStyle = BorderStyle.None, + // Font = new Font("Segoe UI", 9f), + // Location = new Point(6, 6), + // Width = Width - 12, + // Height = Height - 12, + // BackColor = Color.White + // }; + // _textBox.GotFocus += (s, e) => { _focused = true; Invalidate(); }; + // _textBox.LostFocus += (s, e) => { _focused = false; Invalidate(); }; + // Controls.Add(_textBox); + // SizeChanged += (s, e) => AjustarTextBox(); + //} + public RoundTextBox() + { + DoubleBuffered = true; + base.BackColor = Color.White; + _textBox = new TextBox + { + BorderStyle = BorderStyle.None, + Font = new Font("Segoe UI", 9f), + Location = new Point(6, 6), + Width = Width - 12, + Height = Height - 12, + BackColor = Color.White + }; + + _textBox.GotFocus += (s, e) => { _focused = true; Invalidate(); }; + _textBox.LostFocus += (s, e) => { _focused = false; Invalidate(); }; + _textBox.TextChanged += (s, e) => OnTextChanged(e); // ← adiciona essa + _textBox.Leave += (s, e) => OnLeave(e); // ← e essa + + Controls.Add(_textBox); + SizeChanged += (s, e) => AjustarTextBox(); + } + + // Ajusta largura e altura do TextBox interno conforme Multiline + private void AjustarTextBox() + { + _textBox.Width = Width - 12; + _textBox.Height = _textBox.Multiline ? Height - 12 : _textBox.PreferredHeight; + // Recentraliza verticalmente quando não é multiline + if (!_textBox.Multiline) + _textBox.Location = new Point(6, (Height - _textBox.PreferredHeight) / 2); + else + _textBox.Location = new Point(6, 6); + } + + protected override void OnPaint(PaintEventArgs e) + { + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + using var path = GetPath(new Rectangle(0, 0, Width - 1, Height - 1), Radius); + using var brush = new SolidBrush(BackColor); + e.Graphics.FillPath(brush, path); + using var pen = new Pen(_focused ? FocusColor : BorderColor, _focused ? 1.5f : 1f); + e.Graphics.DrawPath(pen, path); + } + + private static GraphicsPath GetPath(Rectangle r, int rad) + { + var path = new GraphicsPath(); + int d = rad * 2; + path.AddArc(r.X, r.Y, d, d, 180, 90); + path.AddArc(r.Right - d, r.Y, d, d, 270, 90); + path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90); + path.AddArc(r.X, r.Bottom - d, d, d, 90, 90); + path.CloseFigure(); + return path; + } + } + + public class RoundButton : Button + { + [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")] + private static extern IntPtr CreateRoundRectRgn(int nL, int nT, int nR, int nB, int nW, int nH); + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + Region = Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 8, 8)); + FlatStyle = FlatStyle.Flat; + FlatAppearance.BorderSize = 0; + } + } +} \ No newline at end of file diff --git a/ControlesCustom.resx b/ControlesCustom.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/ControlesCustom.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Cadastros/AgendaCadastroPanel.cs b/Dashboards/Cadastros/AgendaCadastroPanel.cs new file mode 100644 index 0000000..d884975 --- /dev/null +++ b/Dashboards/Cadastros/AgendaCadastroPanel.cs @@ -0,0 +1,887 @@ +using BLL; +using CustomMessageBox; +using DAL; +using MLL; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace UI +{ + public class AgendaCadastroPanel : UserControl + { + string _cx = DadosDaConexao.ObterConexao(); + // ── CORES ───────────────────────────────────────────────────────────── + private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private readonly Color TextDark = Color.FromArgb(30, 41, 59); + private readonly Color BorderColor = Color.FromArgb(226, 232, 240); + private readonly Color GreenColor = Color.FromArgb(34, 197, 94); + private readonly Color AmberColor = Color.FromArgb(245, 158, 11); + private readonly Color RedColor = Color.FromArgb(239, 68, 68); + private readonly Color MutedGray = Color.FromArgb(148, 163, 184); + private readonly Color SurfaceColor = Color.FromArgb(248, 250, 252); + private readonly Color DisabledBack = Color.FromArgb(241, 245, 249); + + // ── LAYOUT ──────────────────────────────────────────────────────────── + private Panel pnlToolbar = null!; + private Panel pnlLeft = null!; + private Panel pnlRight = null!; + private Panel pnlEventList = null!; + private Panel pnlSplit = null!; + private Panel pnlDias = null!; + + // ── TOOLBAR ─────────────────────────────────────────────────────────── + private RoundButton btnNovo = null!; + private RoundButton btnAlterar = null!; + private RoundButton btnExcluir = null!; + private RoundButton btnLocalizar = null!; + private RoundButton btnSalvar = null!; + private RoundButton btnCancelar = null!; + + // ── CAMPOS DO FORMULÁRIO ────────────────────────────────────────────── + private RoundTextBox txtId = null!; + private RoundTextBox txtCodigo = null!; + private RoundTextBox txtCompromisso = null!; + private RoundTextBox txtData = null!; + private RoundTextBox txtDia = null!; + private RoundTextBox txtHora = null!; + private RoundTextBox txtFunc = null!; + private RoundTextBox txtAvisar = null!; + private RoundTextBox txtOsVinc = null!; + private CheckBox chkRealizado = null!; + + // ── INFO (readonly) ─────────────────────────────────────────────────── + private RoundTextBox txtCriadoEm = null!; + private RoundTextBox txtAtualizadoEm = null!; + + // ── CALENDÁRIO ──────────────────────────────────────────────────────── + private Label lblMesAno = null!; + private Button btnPrev = null!; + private Button btnNext = null!; + + // ── ESTADO ──────────────────────────────────────────────────────────── + private DateTime _currentMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); + private DateTime? _selectedDate = null; + private List _eventos = new(); + private int _nextId = 1; + + // ── CONSTRUTOR ──────────────────────────────────────────────────────── + public AgendaCadastroPanel() + { + Dock = DockStyle.Fill; + BackColor = Color.White; + DoubleBuffered = true; + + InitializeLayout(); + SetCampos(false); + //CarregarDadosFake(); + CarregarDadosDoBanco(); + RenderCalendario(); + RenderListaEventos(); + } + + // ══════════════════════════════════════════════════════════════════════ + // LAYOUT + // ══════════════════════════════════════════════════════════════════════ + private void InitializeLayout() + { + Controls.Clear(); + + // ── TOOLBAR ─────────────────────────────────────────────────────── + pnlToolbar = new Panel + { + Dock = DockStyle.Top, + Height = 55, + BackColor = SurfaceColor + }; + + var flow = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(12, 10, 0, 0), + BackColor = Color.Transparent + }; + + btnNovo = CreateToolbarButton("Novo", GreenColor); + btnAlterar = CreateToolbarButton("Alterar", AmberColor); + btnExcluir = CreateToolbarButton("Excluir", RedColor); + btnLocalizar = CreateToolbarButton("Localizar", AccentBlue); + btnSalvar = CreateToolbarButton("Salvar", AccentBlue); + btnCancelar = CreateToolbarButton("Cancelar", MutedGray); + + btnNovo.Click += (_, _) => BtnNovo_Click(); + btnAlterar.Click += (_, _) => BtnAlterar_Click(); + btnExcluir.Click += (_, _) => BtnExcluir_Click(); + btnLocalizar.Click += (_, _) => BtnLocalizar_Click(); + btnSalvar.Click += (_, _) => BtnSalvar_Click(); + btnCancelar.Click += (_, _) => BtnCancelar_Click(); + + flow.Controls.AddRange(new Control[] + { btnNovo, btnAlterar, btnExcluir, btnLocalizar, btnSalvar, btnCancelar }); + + pnlToolbar.Controls.Add(flow); + Controls.Add(pnlToolbar); + + // ── SPLIT ───────────────────────────────────────────────────────── + pnlSplit = new Panel { Dock = DockStyle.Fill, BackColor = Color.White }; + Controls.Add(pnlSplit); + pnlSplit.BringToFront(); + + // RIGHT ─ calendário + lista + pnlRight = new Panel + { + Dock = DockStyle.Right, + Width = 340, + BackColor = Color.White, + Padding = new Padding(10, 10, 10, 10) + }; + pnlSplit.Controls.Add(pnlRight); + BuildCalendario(); // preenche pnlRight + + // Divider + var divider = new Panel + { + Dock = DockStyle.Right, + Width = 1, + BackColor = BorderColor + }; + pnlSplit.Controls.Add(divider); + + // LEFT ─ formulário + pnlLeft = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = Color.White + }; + pnlSplit.Controls.Add(pnlLeft); + BuildFormulario(); + } + + // ── FORMULÁRIO ──────────────────────────────────────────────────────── + private void BuildFormulario() + { + var content = new Panel { Width = 800, BackColor = Color.White }; + pnlLeft.Controls.Add(content); + + const int rowH = 52; + const int secH = 28; + const int secGap = 10; + const int inputH = 28; + int y = 10; + + // IDENTIFICAÇÃO + content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO", y)); + y += secH + 4; + + txtId = AddInput(content, "ID", 20, y, 60, inputH, readOnly: true); + txtCodigo = AddInput(content, "Código", 90, y, 120, inputH); + txtCompromisso = AddInput(content, "Compromisso", 220, y, 520, inputH); + y += rowH; + + // DATA E HORA + y += secGap; + content.Controls.Add(CreateSectionHeader("DATA E HORA", y)); + y += secH + 4; + + txtData = AddInput(content, "Data", 20, y, 130, inputH, readOnly: true); + txtDia = AddInput(content, "Dia", 160, y, 150, inputH, readOnly: true); + txtHora = AddInput(content, "Hora", 320, y, 100, inputH); + y += rowH; + + // RESPONSÁVEL E AVISO + y += secGap; + content.Controls.Add(CreateSectionHeader("RESPONSÁVEL E AVISO", y)); + y += secH + 4; + + txtFunc = AddInput(content, "Funcionário", 20, y, 280, inputH); + txtAvisar = AddInput(content, "Avisar", 310, y, 180, inputH); + txtOsVinc = AddInput(content, "OS Vinculada", 500, y, 140, inputH); + y += rowH; + + // SITUAÇÃO + y += secGap; + content.Controls.Add(CreateSectionHeader("SITUAÇÃO", y)); + y += secH + 4; + + chkRealizado = new CheckBox + { + Text = "Realizado", + Location = new Point(20, y + 4), + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + content.Controls.Add(chkRealizado); + y += rowH; + + // INFORMAÇÕES DO REGISTRO + y += secGap; + content.Controls.Add(CreateSectionHeader("INFORMAÇÕES DO REGISTRO", y)); + y += secH + 4; + + txtCriadoEm = AddInput(content, "Criado Em", 20, y, 175, inputH, readOnly: true); + txtAtualizadoEm = AddInput(content, "Atualizado Em", 205, y, 175, inputH, readOnly: true); + y += rowH; + + content.Height = y + 10; + } + + // ── CALENDÁRIO ──────────────────────────────────────────────────────── + // ATENÇÃO: No WinForms, DockStyle.Fill deve ser adicionado ANTES dos + // DockStyle.Top — a ordem de inserção em Controls é invertida visualmente. + private void BuildCalendario() + { + // 1º — Lista de eventos (Fill) → adicionada PRIMEIRO + pnlEventList = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = Color.White, + Padding = new Padding(0, 4, 0, 0) + }; + pnlRight.Controls.Add(pnlEventList); // ← PRIMEIRO + + // 2º — Grid dos dias (Top) → adicionado DEPOIS do Fill + pnlDias = new Panel + { + Dock = DockStyle.Top, + Height = 215, + BackColor = Color.White + }; + pnlRight.Controls.Add(pnlDias); // ← SEGUNDO + + // 3º — Cabeçalho mês/ano (Top) → adicionado POR ÚLTIMO (aparece no topo) + var pnlCalHeader = new Panel + { + Dock = DockStyle.Top, + Height = 38, + BackColor = Color.White + }; + + btnPrev = new Button + { + Text = "‹", + Size = new Size(28, 26), + Location = new Point(0, 6), + FlatStyle = FlatStyle.Flat, + Font = new Font("Segoe UI", 13f), + ForeColor = AccentBlue, + BackColor = Color.White, + Cursor = Cursors.Hand + }; + btnPrev.FlatAppearance.BorderColor = BorderColor; + btnPrev.Click += (_, _) => + { + _currentMonth = _currentMonth.AddMonths(-1); + RenderCalendario(); + RenderListaEventos(); + }; + + btnNext = new Button + { + Text = "›", + Size = new Size(28, 26), + Location = new Point(290, 6), + FlatStyle = FlatStyle.Flat, + Font = new Font("Segoe UI", 13f), + ForeColor = AccentBlue, + BackColor = Color.White, + Cursor = Cursors.Hand + }; + btnNext.FlatAppearance.BorderColor = BorderColor; + btnNext.Click += (_, _) => + { + _currentMonth = _currentMonth.AddMonths(1); + RenderCalendario(); + RenderListaEventos(); + }; + + lblMesAno = new Label + { + AutoSize = false, + TextAlign = ContentAlignment.MiddleCenter, + Font = new Font("Segoe UI", 10f, FontStyle.Bold), + ForeColor = TextDark, + Size = new Size(256, 26), + Location = new Point(32, 6) + }; + + pnlCalHeader.Controls.AddRange(new Control[] { btnPrev, lblMesAno, btnNext }); + pnlRight.Controls.Add(pnlCalHeader); // ← ÚLTIMO (fica no topo visualmente) + } + + // ══════════════════════════════════════════════════════════════════════ + // RENDER CALENDÁRIO + // ══════════════════════════════════════════════════════════════════════ + private void RenderCalendario() + { + pnlDias.Controls.Clear(); + + lblMesAno.Text = _currentMonth.ToString("MMMM yyyy", + new System.Globalization.CultureInfo("pt-BR")).ToUpper(); + + string[] dowLabels = { "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb" }; + int cellW = 44; + int cellH = 26; + int startX = 2; + + // Cabeçalho dias da semana + for (int i = 0; i < 7; i++) + { + pnlDias.Controls.Add(new Label + { + Text = dowLabels[i], + Size = new Size(cellW, 18), + Location = new Point(startX + i * cellW, 0), + TextAlign = ContentAlignment.MiddleCenter, + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = MutedGray + }); + } + + int firstDow = (int)new DateTime(_currentMonth.Year, _currentMonth.Month, 1).DayOfWeek; + int daysInMonth = DateTime.DaysInMonth(_currentMonth.Year, _currentMonth.Month); + var datesWithEvts = GetDatesWithEvents(); + DateTime today = DateTime.Today; + int col = firstDow, row = 0; + + for (int d = 1; d <= daysInMonth; d++) + { + var date = new DateTime(_currentMonth.Year, _currentMonth.Month, d); + bool isToday = date == today; + bool isSelected = _selectedDate.HasValue && date == _selectedDate.Value; + bool hasEvent = datesWithEvts.Contains(date.Date); + + var btn = new Button + { + Text = hasEvent ? $"{d} •" : d.ToString(), + Size = new Size(cellW - 2, cellH), + Location = new Point(startX + col * cellW, 22 + row * (cellH + 2)), + FlatStyle = FlatStyle.Flat, + Font = new Font("Segoe UI", 8f, + isToday || isSelected ? FontStyle.Bold : FontStyle.Regular), + Cursor = Cursors.Hand, + Tag = date + }; + + if (isSelected) + { + btn.BackColor = AccentBlue; + btn.ForeColor = Color.White; + btn.FlatAppearance.BorderColor = AccentBlue; + } + else if (isToday) + { + btn.BackColor = Color.White; + btn.ForeColor = AccentBlue; + btn.FlatAppearance.BorderColor = AccentBlue; + } + else + { + btn.BackColor = Color.White; + btn.ForeColor = TextDark; + btn.FlatAppearance.BorderColor = BorderColor; + } + + btn.Click += (s, _) => + { + if (s is Button b && b.Tag is DateTime dt) + { + _selectedDate = dt; + if (txtData.Enabled) + { + txtData.Text = dt.ToString("dd/MM/yyyy"); + txtDia.Text = new System.Globalization.CultureInfo("pt-BR") + .DateTimeFormat.GetDayName(dt.DayOfWeek); + } + RenderCalendario(); + RenderListaEventos(); + } + }; + + pnlDias.Controls.Add(btn); + + col++; + if (col == 7) { col = 0; row++; } + } + } + + // ══════════════════════════════════════════════════════════════════════ + // RENDER LISTA DE EVENTOS + // ══════════════════════════════════════════════════════════════════════ + private void RenderListaEventos() + { + pnlEventList.Controls.Clear(); + + var filtrados = _selectedDate.HasValue + ? _eventos.Where(e => ParseData(e.dDATA).Date == _selectedDate.Value.Date).ToList() + : _eventos.Where(e => ParseData(e.dDATA).Month == _currentMonth.Month + && ParseData(e.dDATA).Year == _currentMonth.Year).ToList(); + + filtrados = filtrados.OrderBy(e => e.HORA).ToList(); + + // Largura real do painel (com fallback para evitar 0) + int listW = pnlEventList.ClientSize.Width > 0 + ? pnlEventList.ClientSize.Width + : pnlRight.Width - pnlRight.Padding.Horizontal - 20; + + int y = 0; + + // ── Título ──────────────────────────────────────────────────────── + string titulo = _selectedDate.HasValue + ? $"COMPROMISSOS — {_selectedDate.Value:dd/MM/yyyy}" + : $"COMPROMISSOS — {_currentMonth.ToString("MMMM/yyyy", new System.Globalization.CultureInfo("pt-BR")).ToUpper()}"; + + pnlEventList.Controls.Add(new Label + { + Text = titulo, + AutoSize = false, + Width = listW, + Height = 18, + Location = new Point(0, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = MutedGray + }); + y += 6; + + // Linha separadora + pnlEventList.Controls.Add(new Panel + { + Location = new Point(0, y + 14), + Size = new Size(listW, 1), + BackColor = BorderColor + }); + y += 22; + + // ── Vazio ───────────────────────────────────────────────────────── + if (!filtrados.Any()) + { + pnlEventList.Controls.Add(new Label + { + Text = "Nenhum compromisso encontrado.", + Location = new Point(0, y + 8), + AutoSize = true, + Font = new Font("Segoe UI", 8.5f), + ForeColor = MutedGray + }); + return; + } + + // ── Cards ───────────────────────────────────────────────────────── + foreach (var ev in filtrados) + { + bool realizado = ev.REALIZADO?.ToUpper() == "S"; + + var card = new Panel + { + Location = new Point(0, y), + Width = listW, + Height = 72, + BackColor = Color.White, + BorderStyle = BorderStyle.None, + Cursor = Cursors.Hand, + Tag = ev + }; + + // Borda esquerda colorida + card.Controls.Add(new Panel + { + Location = new Point(0, 0), + Size = new Size(3, 72), + BackColor = realizado ? GreenColor : AmberColor + }); + + card.Controls.Add(new Label + { + Text = $"{ev.HORA} — {ev.dDATA}", + Location = new Point(10, 5), + AutoSize = true, + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = AccentBlue + }); + card.Controls.Add(new Label + { + Text = ev.COMPROMISSO, + Location = new Point(10, 21), + AutoSize = true, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = TextDark + }); + card.Controls.Add(new Label + { + Text = string.IsNullOrWhiteSpace(ev.FUNC) ? "—" : ev.FUNC, + Location = new Point(10, 39), + AutoSize = true, + Font = new Font("Segoe UI", 8f), + ForeColor = MutedGray + }); + card.Controls.Add(new Label + { + Text = realizado ? "✔ Realizado" : "⏳ Pendente", + Location = new Point(10, 55), + AutoSize = true, + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = realizado + ? Color.FromArgb(22, 101, 52) + : Color.FromArgb(146, 64, 14) + }); + + // Borda do card via Paint + card.Paint += (_, pe) => + { + using var pen = new Pen(BorderColor); + pe.Graphics.DrawRectangle(pen, 0, 0, card.Width - 1, card.Height - 1); + }; + + // Clique em qualquer parte do card (inclusive labels filhos) + var evLocal = ev; + EventHandler clickHandler = (_, _) => CarregarEvento(evLocal); + card.Click += clickHandler; + foreach (Control child in card.Controls) + child.Click += clickHandler; + + pnlEventList.Controls.Add(card); + y += 78; + } + } + + // ══════════════════════════════════════════════════════════════════════ + // EVENTOS DOS BOTÕES + // ══════════════════════════════════════════════════════════════════════ + private void BtnNovo_Click() + { + + LimparCampos(); + SetCampos(true); + txtCriadoEm.Text = DateTime.Now.ToString("dd/MM/yyyy"); + + + } + + private void BtnAlterar_Click() + { + if (string.IsNullOrWhiteSpace(txtId.Text)) + { + MessageBox.Show("Nenhum registro selecionado para alterar.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + SetCampos(true); + } + + private void BtnExcluir_Click() + { + BLLAgenda _agendaBLL = new BLLAgenda(this._cx); + if (string.IsNullOrWhiteSpace(txtId.Text)) + { + NT_MessageBox.Show("Nenhum registro selecionado para excluir.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + var confirm = NT_MessageBox.Show("Confirma a exclusão deste registro?", + "Confirmar Exclusão", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + + if (confirm == DialogResult.Yes) + { + int id = int.Parse(txtId.Text); + + bool sucesso = _agendaBLL.Excluir(id); + + if (!sucesso) + { + NT_MessageBox.Show("Erro ao excluir o registro.", + "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + // 🔹 Atualiza lista do banco + _eventos.Clear(); + _eventos.AddRange(_agendaBLL.Listar()); + + LimparCampos(); + SetCampos(false); + RenderCalendario(); + RenderListaEventos(); + + NT_MessageBox.Show("Registro excluído com sucesso!", + "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + }//Excluir registro selecionado + + private void BtnLocalizar_Click() + { + FormHelper.Show("Agenda de Compromissos"); + } + + private void BtnSalvar_Click() + { + //if (string.IsNullOrWhiteSpace(txtData.Text) || + // string.IsNullOrWhiteSpace(txtCompromisso.Text)) + //{ + // MessageBox.Show("Preencha ao menos Data e Compromisso.", + // "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + // return; + //} + + //bool isNew = string.IsNullOrWhiteSpace(txtId.Text); + //int id = isNew ? _nextId++ : int.Parse(txtId.Text); + + //var agenda = new MLL.ModeloAgenda( + // iD_AGENDA: id, + // cODIGO: txtCodigo.Text, + // cOMPROMISSO: txtCompromisso.Text, + // dDATA: txtData.Text, + // aVISAR: txtAvisar.Text, + // fUNC: txtFunc.Text, + // dIA: txtDia.Text, + // hORA: txtHora.Text, + // rEALIZADO: chkRealizado.Checked ? "S" : "N", + // oS_VINC: txtOsVinc.Text + //); + + //if (isNew) + //{ + // _eventos.Add(agenda); + // txtId.Text = id.ToString(); + //} + //else + //{ + // int idx = _eventos.FindIndex(e => e.ID_AGENDA == id); + // if (idx >= 0) _eventos[idx] = agenda; + //} + + //txtAtualizadoEm.Text = DateTime.Now.ToString("dd/MM/yyyy"); + //SetCampos(false); + //RenderCalendario(); + //RenderListaEventos(); + + //MessageBox.Show("Registro salvo com sucesso!", "Sucesso", + // MessageBoxButtons.OK, MessageBoxIcon.Information); + BLLAgenda _agendaBLL = new BLLAgenda(_cx); + if (string.IsNullOrWhiteSpace(txtData.Text) || + string.IsNullOrWhiteSpace(txtCompromisso.Text)) + { + MessageBox.Show("Preencha ao menos Data e Compromisso.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + bool isNew = string.IsNullOrWhiteSpace(txtId.Text); + + var agenda = new MLL.ModeloAgenda( + iD_AGENDA: isNew ? 0 : int.Parse(txtId.Text), + cODIGO: txtCodigo.Text, + cOMPROMISSO: txtCompromisso.Text, + dDATA: txtData.Text, + aVISAR: txtAvisar.Text, + fUNC: txtFunc.Text, + dIA: txtDia.Text, + hORA: txtHora.Text, + rEALIZADO: chkRealizado.Checked ? "S" : "N", + oS_VINC: txtOsVinc.Text + ); + + bool sucesso; + + if (isNew) + { + sucesso = _agendaBLL.Inserir(agenda); + } + else + { + sucesso = _agendaBLL.Alterar(agenda); + } + + if (!sucesso) + { + MessageBox.Show("Erro ao salvar no banco de dados.", + "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + // 🔹 Recarrega dados do banco + _eventos = _agendaBLL.Listar(); + + // 🔹 Atualiza UI + txtAtualizadoEm.Text = DateTime.Now.ToString("dd/MM/yyyy"); + SetCampos(false); + RenderCalendario(); + RenderListaEventos(); + + MessageBox.Show("Registro salvo com sucesso!", "Sucesso", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void BtnCancelar_Click() + { + LimparCampos(); + SetCampos(false); + } + + // ══════════════════════════════════════════════════════════════════════ + // HELPERS + // ══════════════════════════════════════════════════════════════════════ + private void SetCampos(bool enabled) + { + var campos = new[] { txtCodigo, txtCompromisso, txtHora, txtFunc, txtAvisar, txtOsVinc }; + foreach (var c in campos) + { + c.Enabled = enabled; + c.BackColor = enabled ? Color.White : DisabledBack; + } + chkRealizado.Enabled = enabled; + txtData.BackColor = enabled ? Color.FromArgb(239, 246, 255) : DisabledBack; + } + + private void LimparCampos() + { + txtId.Text = txtCodigo.Text = txtCompromisso.Text = string.Empty; + txtData.Text = txtDia.Text = txtHora.Text = string.Empty; + txtFunc.Text = txtAvisar.Text = txtOsVinc.Text = string.Empty; + txtCriadoEm.Text = txtAtualizadoEm.Text = string.Empty; + chkRealizado.Checked = false; + _selectedDate = null; + } + + private void CarregarEvento(MLL.ModeloAgenda ev) + { + txtId.Text = ev.ID_AGENDA.ToString(); + txtCodigo.Text = ev.CODIGO; + txtCompromisso.Text = ev.COMPROMISSO; + txtData.Text = ev.dDATA; + txtDia.Text = ev.DIA; + txtHora.Text = ev.HORA; + txtFunc.Text = ev.FUNC; + txtAvisar.Text = ev.AVISAR; + txtOsVinc.Text = ev.OS_VINC; + txtCriadoEm.Text = ev.dDATA; + txtAtualizadoEm.Text = DateTime.Now.ToString("dd/MM/yyyy"); + chkRealizado.Checked = ev.REALIZADO?.ToUpper() == "S"; + + var dt = ParseData(ev.dDATA); + if (dt != DateTime.MinValue) + { + _selectedDate = dt; + _currentMonth = new DateTime(dt.Year, dt.Month, 1); + } + + SetCampos(false); + RenderCalendario(); + RenderListaEventos(); + } + + private HashSet GetDatesWithEvents() + { + var set = new HashSet(); + foreach (var ev in _eventos) + { + var dt = ParseData(ev.dDATA); + if (dt != DateTime.MinValue) set.Add(dt.Date); + } + return set; + } + + private static DateTime ParseData(string? value) + { + if (string.IsNullOrWhiteSpace(value)) return DateTime.MinValue; + if (DateTime.TryParseExact(value, "dd/MM/yyyy", + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.None, out var dt)) + return dt; + if (DateTime.TryParse(value, out dt)) return dt; + return DateTime.MinValue; + } + + private void CarregarDadosFake() + { + var hoje = DateTime.Today; + _eventos.AddRange(new[] + { + new MLL.ModeloAgenda(1, "AG001", "Reunião com cliente", + hoje.ToString("dd/MM/yyyy"), "30 minutos antes", + "Carlos Silva", DiaSemana(hoje), "09:00", "S", "OS-1042"), + + new MLL.ModeloAgenda(2, "AG002", "Visita técnica", + hoje.ToString("dd/MM/yyyy"), "1 hora antes", + "Ana Souza", DiaSemana(hoje), "14:00", "N", "OS-1055"), + + new MLL.ModeloAgenda(3, "AG003", "Entrega de equipamento", + hoje.AddDays(4).ToString("dd/MM/yyyy"), "1 dia antes", + "Pedro Lima", DiaSemana(hoje.AddDays(4)), "10:30", "N", ""), + }); + _nextId = 4; + }//Carregar dados fake (Não usa mais) + private void CarregarDadosDoBanco() + { + BLLAgenda _agendaBLL = new BLLAgenda(_cx); + _eventos.Clear(); + _eventos.AddRange(_agendaBLL.Listar()); + }// Método auxiliar para obter os dados da agenda no banco de dados e preencher a lista de eventos. + + private static string DiaSemana(DateTime d) => + new System.Globalization.CultureInfo("pt-BR").DateTimeFormat.GetDayName(d.DayOfWeek); + + // ── UI HELPERS ──────────────────────────────────────────────────────── + private Panel CreateSectionHeader(string title, int y) + { + var pnl = new Panel { Location = new Point(20, y), Width = 760, Height = 26 }; + pnl.Controls.Add(new Label + { + Text = title, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = AccentBlue, + AutoSize = true, + Location = new Point(0, 0) + }); + pnl.Controls.Add(new Panel + { + BackColor = BorderColor, + Height = 1, + Width = 740, + Location = new Point(0, 20) + }); + return pnl; + } + + private RoundTextBox AddInput(Control parent, string label, + int x, int y, int width, int height, + bool readOnly = false) + { + parent.Controls.Add(new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = readOnly ? Color.Gray : TextDark, + AutoSize = true + }); + var txt = new RoundTextBox + { + Location = new Point(x, y + 16), + Size = new Size(width, height), + Radius = 4, + BorderColor = readOnly ? Color.FromArgb(203, 213, 225) : BorderColor, + FocusColor = AccentBlue, + ReadOnly = readOnly, + BackColor = readOnly ? DisabledBack : Color.White + }; + parent.Controls.Add(txt); + return txt; + } + + private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton + { + Text = text, + Size = new Size(95, 32), + BackColor = color, + ForeColor = Color.White, + Font = new Font("Segoe UI Semibold", 8.5f), + Margin = new Padding(0, 0, 6, 0), + Cursor = Cursors.Hand + }; + } +} \ No newline at end of file diff --git a/Dashboards/Cadastros/AgendaCadastroPanel.resx b/Dashboards/Cadastros/AgendaCadastroPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Cadastros/AgendaCadastroPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Cadastros/ClienteCadastroPanel.cs b/Dashboards/Cadastros/ClienteCadastroPanel.cs new file mode 100644 index 0000000..baab19b --- /dev/null +++ b/Dashboards/Cadastros/ClienteCadastroPanel.cs @@ -0,0 +1,530 @@ +using BLL; +using CustomMessageBox; +using DAL; +using System.Drawing; +using System.Windows.Forms; + +namespace UI +{ + public class ClienteCadastroPanel : UserControl + { + private string _connectionString = DadosDaConexao.ObterConexao(); + private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private readonly Color TextDark = Color.FromArgb(30, 41, 59); + private readonly Color BorderColor = Color.FromArgb(226, 232, 240); + + private Panel pnlToolbar = null!; + private Panel mainScroll = null!; + private Panel content = null!; + + // Identificação + private RoundTextBox txtId = null!, txtEmpresaId = null!, txtNome = null!, txtNomeFantasia = null!; + private RoundTextBox txtTipoPessoa = null!, txtDocumento = null!, txtRG = null!; + private RoundTextBox txtInscricaoMunicipal = null!, txtDataNascimento = null!; + private RoundTextBox txtGrupo = null!, txtTipoConsumidor = null!; + + // Contatos + private RoundTextBox txtContato = null!, txtTelefone1 = null!, txtTelefone2 = null!; + private RoundTextBox txtCelular = null!, txtWhatsapp = null!, txtEmail = null!, txtEmailNFe = null!, txtSite = null!; + + // Endereço + private RoundTextBox txtCep = null!, txtEndereco = null!, txtNumero = null!, txtComplemento = null!; + private RoundTextBox txtBairro = null!, txtCidade = null!, txtUF = null!, txtPais = null!; + + // Financeiro + private RoundTextBox txtLimiteCredito = null!, txtVendedorPadraoId = null!, txtObservacoesCobranca = null!; + private CheckBox chkBloqueado = null!, chkAtivo = null!; + + // Carteiras + private RoundTextBox txtBitcoin = null!, txtEthereum = null!, txtLitecoin = null!; + + // Extras + private RoundTextBox txtObservacoes = null!; + private RoundTextBox txtCampoExtra1 = null!, txtCampoExtra2 = null!, txtCampoExtra3 = null!; + + // Info (readonly) + private RoundTextBox txtUltimaCompra = null!, txtCriadoEm = null!, txtAtualizadoEm = null!; + + //Funções Auxiliares + private void CarregarConfiguracoesSistema() + { + BLLEmpresaConfig empresaConfig = new BLLEmpresaConfig(_connectionString); + int codEmpresa = empresaConfig.ObterEmpresaAtivaId(); + + this.txtEmpresaId.Text = codEmpresa.ToString(); + } + private DateTime? ConverterData(string texto) + { + if (string.IsNullOrWhiteSpace(texto)) + return null; + + if (DateTime.TryParse(texto, out DateTime data)) + return data; + + return null; + } + private RoundTextBox[] TodosOsCampos() => new[] + { + txtId, txtEmpresaId, txtNome, txtNomeFantasia, + txtTipoPessoa, txtDocumento, txtRG, + txtInscricaoMunicipal, txtDataNascimento, + txtGrupo, txtTipoConsumidor, + txtContato, txtTelefone1, txtTelefone2, + txtCelular, txtWhatsapp, txtEmail, txtEmailNFe, txtSite, + txtCep, txtEndereco, txtNumero, txtComplemento, + txtBairro, txtCidade, txtUF, txtPais, + txtLimiteCredito, txtVendedorPadraoId, txtObservacoesCobranca, + txtBitcoin, txtEthereum, txtLitecoin, + txtObservacoes, txtCampoExtra1, txtCampoExtra2, txtCampoExtra3 + }; + + private void SetCampos(bool enabled) + { + foreach (var campo in TodosOsCampos()) + { + campo.Enabled = enabled; + campo.BackColor = enabled ? Color.White : Color.FromArgb(241, 245, 249); + } + chkBloqueado.Enabled = enabled; + chkAtivo.Enabled = enabled; + } + + public ClienteCadastroPanel() + { + Dock = DockStyle.Fill; + BackColor = Color.White; + DoubleBuffered = true; + InitializeLayout(); + SetCampos(false); + } + + private void InitializeLayout() + { + this.Controls.Clear(); + + // ── TOOLBAR ─────────────────────────────────────────────────────── + pnlToolbar = new Panel + { + Dock = DockStyle.Top, + Height = 55, + BackColor = Color.FromArgb(248, 250, 252), + BorderStyle = BorderStyle.None + }; + + var flowButtons = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(12, 10, 0, 0), + BackColor = Color.Transparent + }; + + var btnNovo = CreateToolbarButton("Novo", Color.FromArgb(34, 197, 94)); + var btnAlterar = CreateToolbarButton("Alterar", Color.FromArgb(245, 158, 11)); + var btnExcluir = CreateToolbarButton("Excluir", Color.FromArgb(239, 68, 68)); + var btnLocalizar = CreateToolbarButton("Localizar", AccentBlue); + var btnSalvar = CreateToolbarButton("Salvar", AccentBlue); + var btnCancelar = CreateToolbarButton("Cancelar", Color.FromArgb(148, 163, 184)); + + btnNovo.Click += (s, e) => BtnNovo_Click(); + btnAlterar.Click += (s, e) => BtnAlterar_Click(); + btnExcluir.Click += (s, e) => BtnExcluir_Click(); + btnLocalizar.Click += (s, e) => BtnLocalizar_Click(); + btnSalvar.Click += (s, e) => BtnSalvar_Click(); + btnCancelar.Click += (s, e) => BtnCancelar_Click(); + + flowButtons.Controls.AddRange(new Control[] + { btnNovo, btnAlterar, btnExcluir, btnLocalizar, btnSalvar, btnCancelar }); + pnlToolbar.Controls.Add(flowButtons); + this.Controls.Add(pnlToolbar); + + // ── SCROLL + CONTENT ────────────────────────────────────────────── + mainScroll = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = Color.White + }; + this.Controls.Add(mainScroll); + mainScroll.BringToFront(); + + content = new Panel + { + Width = 1100, + Height = 900, + Location = new Point(0, 0), + BackColor = Color.White + }; + mainScroll.Controls.Add(content); + + const int rowH = 52; + const int secGap = 10; + const int secH = 28; + const int inputH = 28; + + int y = 10; + + // ── 1. IDENTIFICAÇÃO DO CLIENTE ─────────────────────────────────── + content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO CLIENTE", y)); + y += secH + 4; + + txtId = AddInput(content, "ID", 20, y, 60, inputH); + txtEmpresaId = AddInput(content, "Empresa ID", 90, y, 80, inputH); + txtNome = AddInput(content, "Nome / Razão Social", 180, y, 390, inputH); + txtNomeFantasia = AddInput(content, "Nome Fantasia", 580, y, 360, inputH); + y += rowH; + + txtDocumento = AddInput(content, "CPF/CNPJ", 20, y, 170, inputH); + DocumentoHelper.Registrar(txtDocumento); + txtRG = AddInput(content, "RG / Insc. Estadual", 200, y, 170, inputH); + txtInscricaoMunicipal = AddInput(content, "Insc. Municipal", 380, y, 130, inputH); + txtDataNascimento = AddInput(content, "Dt. Nascimento", 520, y, 130, inputH); + txtTipoPessoa = AddInput(content, "Tipo Pessoa", 660, y, 110, inputH); + txtGrupo = AddInput(content, "Grupo", 780, y, 110, inputH); + txtTipoConsumidor = AddInput(content, "Tipo Consumidor", 900, y, 140, inputH); + y += rowH; + + // ── 2. CONTATOS E COMUNICAÇÃO ───────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("CONTATOS E COMUNICAÇÃO", y)); + y += secH + 4; + + txtContato = AddInput(content, "Contato", 20, y, 180, inputH); + txtEmail = AddInput(content, "E-mail", 210, y, 230, inputH); + txtEmailNFe = AddInput(content, "E-mail XML/NFe", 450, y, 230, inputH); + txtSite = AddInput(content, "Site", 690, y, 250, inputH); + y += rowH; + + txtTelefone1 = AddInput(content, "Telefone 1", 20, y, 155, inputH); + txtTelefone2 = AddInput(content, "Telefone 2", 185, y, 155, inputH); + txtCelular = AddInput(content, "Celular", 350, y, 155, inputH); + txtWhatsapp = AddInput(content, "WhatsApp", 515, y, 155, inputH); + y += rowH; + + // ── 3. ENDEREÇO COMPLETO ────────────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("ENDEREÇO COMPLETO", y)); + y += secH + 4; + + txtCep = AddInput(content, "CEP", 20, y, 95, inputH); + txtCep.Leave += (s, e) => + { + string cep = txtCep.Text.Trim().Replace("-", ""); + + if (cep.Length != 8) return; + + if (TLL.VerifyCep.verificaCEP(cep)) + { + txtEndereco.Text = TLL.VerifyCep.endereco; + txtBairro.Text = TLL.VerifyCep.bairro; + txtCidade.Text = TLL.VerifyCep.cidade; + txtUF.Text = TLL.VerifyCep.estado; + + // Formata o CEP com hífen + txtCep.Text = $"{cep[..5]}-{cep[5..]}"; + } + else + { + NT_MessageBox.Show("CEP não encontrado.", "CEP", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + };//cep + txtEndereco = AddInput(content, "Logradouro", 125, y, 370, inputH); + txtNumero = AddInput(content, "Nº", 505, y, 60, inputH); + txtComplemento = AddInput(content, "Complemento", 575, y, 175, inputH); + txtBairro = AddInput(content, "Bairro", 760, y, 180, inputH); + y += rowH; + + txtCidade = AddInput(content, "Cidade", 20, y, 280, inputH); + txtUF = AddInput(content, "UF", 310, y, 55, inputH); + txtPais = AddInput(content, "País", 375, y, 150, inputH); + y += rowH; + + // ── 4. FINANCEIRO ───────────────────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("FINANCEIRO", y)); + y += secH + 4; + + txtLimiteCredito = AddInput(content, "Limite de Crédito", 20, y, 150, inputH); + txtVendedorPadraoId = AddInput(content, "Vendedor Padrão ID", 180, y, 120, inputH); + txtObservacoesCobranca = AddInput(content, "Obs. de Cobrança", 310, y, 380, inputH); + + chkBloqueado = CreateCheckBox("Bloqueado", 705, y + 18); + chkAtivo = CreateCheckBox("Ativo", 805, y + 18); + content.Controls.Add(chkBloqueado); + content.Controls.Add(chkAtivo); + y += rowH; + + // ── 5. CARTEIRAS DIGITAIS ───────────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("CARTEIRAS DIGITAIS", y)); + y += secH + 4; + + txtBitcoin = AddInput(content, "Bitcoin (BTC)", 20, y, 290, inputH); + txtEthereum = AddInput(content, "Ethereum (ETH)", 320, y, 290, inputH); + txtLitecoin = AddInput(content, "Litecoin (LTC)", 620, y, 290, inputH); + y += rowH; + + // ── 6. CAMPOS EXTRAS ────────────────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("CAMPOS EXTRAS", y)); + y += secH + 4; + + txtCampoExtra1 = AddInput(content, "Campo Extra 1", 20, y, 290, inputH); + txtCampoExtra2 = AddInput(content, "Campo Extra 2", 320, y, 290, inputH); + txtCampoExtra3 = AddInput(content, "Campo Extra 3", 620, y, 290, inputH); + y += rowH; + + // ── 7. OBSERVAÇÕES ──────────────────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("OBSERVAÇÕES", y)); + y += secH + 4; + + txtObservacoes = AddInput(content, "Observações Internas", 20, y, 920, inputH); + y += rowH; + + // ── 8. INFORMAÇÕES DO REGISTRO ──────────────────────────────────── + y += secGap; + content.Controls.Add(CreateSectionHeader("INFORMAÇÕES DO REGISTRO", y)); + y += secH + 4; + + txtUltimaCompra = AddInput(content, "Última Compra", 20, y, 175, inputH, readOnly: true); + txtCriadoEm = AddInput(content, "Criado Em", 205, y, 175, inputH, readOnly: true); + txtAtualizadoEm = AddInput(content, "Atualizado Em", 390, y, 175, inputH, readOnly: true); + y += rowH; + + content.Height = y + 10; + } + + // ── EVENTOS ─────────────────────────────────────────────────────────── + + private void BtnNovo_Click() + { + foreach (var campo in TodosOsCampos()) + campo.Text = string.Empty; + + chkBloqueado.Checked = false; + chkAtivo.Checked = true; + + SetCampos(true); + txtId.Enabled = false; + txtId.BackColor = Color.FromArgb(241, 245, 249); + this.CarregarConfiguracoesSistema(); + txtEmpresaId.Enabled = false; + txtEmpresaId.BackColor = Color.FromArgb(241, 245, 249); + } + + private void BtnAlterar_Click() + { + if (string.IsNullOrWhiteSpace(txtId.Text)) + { + MessageBox.Show( + "Nenhum registro selecionado para alterar.", + "Atenção", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; + } + + SetCampos(true); + txtId.Enabled = false; + txtId.BackColor = Color.FromArgb(241, 245, 249); + txtEmpresaId.Enabled = false; + txtEmpresaId.BackColor = Color.FromArgb(241, 245, 249); + } + + private void BtnExcluir_Click() + { + // Solicita confirmação e exclui o registro atual + } + + private void BtnLocalizar_Click() + { + // Abre tela/diálogo de busca e preenche os campos + } + + private void BtnSalvar_Click() + { + var bll = new BLLClientes(_connectionString); + + // 🔒 validação básica front + if (string.IsNullOrWhiteSpace(txtNome.Text) || + string.IsNullOrWhiteSpace(txtDocumento.Text)) + { + NT_MessageBox.Show("Preencha ao menos Nome e Documento.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + bool isNew = string.IsNullOrWhiteSpace(txtId.Text); + + var cliente = new ModeloCliente + { + Id = isNew ? 0 : int.Parse(txtId.Text), + EmpresaId = int.TryParse(txtEmpresaId.Text, out var emp) ? emp : 0, + + Nome = txtNome.Text, + NomeFantasia = txtNomeFantasia.Text, + TipoPessoa = txtTipoPessoa.Text, + Documento = txtDocumento.Text, + + RG = txtRG.Text, + InscricaoMunicipal = txtInscricaoMunicipal.Text, + DataNascimento = ConverterData(txtDataNascimento.Text), + + Contato = txtContato.Text, + Telefone1 = txtTelefone1.Text, + Telefone2 = txtTelefone2.Text, + Celular = txtCelular.Text, + Whatsapp = txtWhatsapp.Text, + Email = txtEmail.Text, + EmailNFe = txtEmailNFe.Text, + Site = txtSite.Text, + + Grupo = txtGrupo.Text, + + Cep = txtCep.Text, + Endereco = txtEndereco.Text, + Numero = int.TryParse(txtNumero.Text, out var num) ? num : null, + Complemento = txtComplemento.Text, + Bairro = txtBairro.Text, + Cidade = txtCidade.Text, + UF = txtUF.Text, + Pais = txtPais.Text, + + LimiteCredito = decimal.TryParse(txtLimiteCredito.Text, out var lim) ? lim : 0, + Bloqueado = chkBloqueado.Checked, + ObservacoesCobranca = txtObservacoesCobranca.Text, + + VendedorPadraoId = int.TryParse(txtVendedorPadraoId.Text, out var vend) ? vend : null, + TipoConsumidor = txtTipoConsumidor.Text, + + Observacoes = txtObservacoes.Text, + + CampoExtra1 = txtCampoExtra1.Text, + CampoExtra2 = txtCampoExtra2.Text, + CampoExtra3 = txtCampoExtra3.Text, + + Bitcoin = txtBitcoin.Text, + Ethereum = txtEthereum.Text, + Litecoin = txtLitecoin.Text, + + Ativo = chkAtivo.Checked, + UltimaCompra = ConverterData(txtUltimaCompra.Text), + + // 🔥 esses o banco já gera, mas mantém compatível + CriadoEm = DateTime.Now, + AtualizadoEm = DateTime.Now + }; + + bool sucesso = false; + + try + { + sucesso = isNew + ? bll.Inserir(cliente) + : bll.Alterar(cliente); + } + catch (Exception ex) + { + NT_MessageBox.Show(ex.Message, + "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + if (!sucesso) + { + NT_MessageBox.Show("Erro ao salvar cliente.", + "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + SetCampos(false); + + NT_MessageBox.Show("Cliente salvo com sucesso!", + "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void BtnCancelar_Click() + { + foreach (var campo in TodosOsCampos()) + campo.Text = string.Empty; + + chkBloqueado.Checked = false; + chkAtivo.Checked = false; + + SetCampos(false); + } + + // ── HELPERS ─────────────────────────────────────────────────────────── + + private Panel CreateSectionHeader(string title, int y) + { + var pnl = new Panel { Location = new Point(20, y), Width = 1000, Height = 26 }; + var lbl = new Label + { + Text = title, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = AccentBlue, + AutoSize = true, + Location = new Point(0, 0) + }; + var line = new Panel + { + BackColor = BorderColor, + Height = 1, + Width = 980, + Location = new Point(0, 20) + }; + pnl.Controls.Add(lbl); + pnl.Controls.Add(line); + return pnl; + } + + private RoundTextBox AddInput(Control parent, string label, + int x, int y, int width, int height, + bool readOnly = false) + { + var lbl = new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = readOnly ? Color.Gray : TextDark, + AutoSize = true + }; + var txt = new RoundTextBox + { + Location = new Point(x, y + 16), + Size = new Size(width, height), + Radius = 4, + BorderColor = readOnly ? Color.FromArgb(203, 213, 225) : BorderColor, + FocusColor = AccentBlue, + ReadOnly = readOnly, + BackColor = readOnly ? Color.FromArgb(241, 245, 249) : Color.White + }; + parent.Controls.Add(lbl); + parent.Controls.Add(txt); + return txt; + } + + private CheckBox CreateCheckBox(string text, int x, int y) => new CheckBox + { + Text = text, + Location = new Point(x, y), + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + + private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton + { + Text = text, + Size = new Size(95, 32), + BackColor = color, + ForeColor = Color.White, + Font = new Font("Segoe UI Semibold", 8.5f), + Margin = new Padding(0, 0, 6, 0), + Cursor = Cursors.Hand + }; + } +} \ No newline at end of file diff --git a/Dashboards/Cadastros/ClienteCadastroPanel.resx b/Dashboards/Cadastros/ClienteCadastroPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Cadastros/ClienteCadastroPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Cadastros/EmpresaCadastroPanel.cs b/Dashboards/Cadastros/EmpresaCadastroPanel.cs new file mode 100644 index 0000000..06d01ad --- /dev/null +++ b/Dashboards/Cadastros/EmpresaCadastroPanel.cs @@ -0,0 +1,526 @@ +using BLL; +using CustomMessageBox; +using DAL; +using MLL; +using System.Drawing; +using System.Windows.Forms; + +namespace UI +{ + public class EmpresaCadastroPanel : UserControl + { + private string _cx = DadosDaConexao.ObterConexao(); + private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private readonly Color TextDark = Color.FromArgb(30, 41, 59); + private readonly Color BorderColor = Color.FromArgb(226, 232, 240); + + private Panel pnlToolbar = null!; + private Panel mainScroll = null!; + private Panel content = null!; + + // Identificação + private RoundTextBox txtId = null!, txtNome = null!, txtCNPJ = null!; + private RoundTextBox txtTipoEmpresa = null!, txtRegimeTributario = null!, txtCNAE = null!; + + // Endereço + private RoundTextBox txtCep = null!, txtEndereco = null!, txtNumero = null!, txtComplemento = null!; + private RoundTextBox txtBairro = null!, txtCidade = null!, txtUF = null!, txtPais = null!; + + // Contatos + private RoundTextBox txtTelefone1 = null!, txtTelefone2 = null!, txtCelular = null!, txtWhatsapp = null!; + private RoundTextBox txtEmail = null!, txtSite = null!; + + // Fiscal + private RoundTextBox txtInscricaoEstadual = null!, txtInscricaoMunicipal = null!; + + // Contador + private RoundTextBox txtCNPJCPF_Contador = null!, txtNome_Contador = null!; + + // Outros + private RoundTextBox txtTextoParaRecibo = null!; + private CheckBox chkAtivo = null!; + + // Info (readonly) + private RoundTextBox txtCriadoEm = null!, txtAtualizadoEm = null!; + + //Carregar dados da empresa atual, se houver no banco de dados + private void CarregarEmpresaAtiva() + { + var bll = new BLLEmpresa(_cx); + var empresa = bll.CarregarEmpresaAtiva(); + + if (empresa == null) + { + MessageBox.Show("Nenhuma empresa ativa encontrada.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + // Preenche todos os campos do formulário + txtId.Text = empresa.Id.ToString(); + txtNome.Text = empresa.Nome; + txtCNPJ.Text = empresa.CNPJ; + txtTipoEmpresa.Text = empresa.TipoEmpresa; + txtRegimeTributario.Text = empresa.RegimeTributario; + txtCNAE.Text = empresa.CNAE; + txtInscricaoEstadual.Text = empresa.InscricaoEstadual; + txtInscricaoMunicipal.Text = empresa.InscricaoMunicipal; + txtCep.Text = empresa.Cep; + txtEndereco.Text = empresa.Endereco; + txtNumero.Text = empresa.Numero.ToString(); + txtComplemento.Text = empresa.Complemento; + txtBairro.Text = empresa.Bairro; + txtCidade.Text = empresa.Cidade; + txtUF.Text = empresa.UF; + txtPais.Text = empresa.Pais; + txtTelefone1.Text = empresa.Telefone1; + txtTelefone2.Text = empresa.Telefone2; + txtCelular.Text = empresa.Celular; + txtWhatsapp.Text = empresa.Whatsapp; + txtEmail.Text = empresa.Email; + txtSite.Text = empresa.Site; + txtCNPJCPF_Contador.Text = empresa.CNPJCPF_Contador; + txtNome_Contador.Text = empresa.Nome_Contador; + txtTextoParaRecibo.Text = empresa.TextoParaRecibo; + chkAtivo.Checked = empresa.Ativo; + txtCriadoEm.Text = empresa.CriadoEm.ToString("dd/MM/yyyy"); + txtAtualizadoEm.Text = empresa.AtualizadoEm.ToString("dd/MM/yyyy"); + } + public EmpresaCadastroPanel() + { + Dock = DockStyle.Fill; + BackColor = Color.White; + DoubleBuffered = true; + InitializeLayout(); + // Carregar dados da empresa atual, se houver + CarregarEmpresaAtiva(); + } + + private void InitializeLayout() + { + this.Controls.Clear(); + + // ── TOOLBAR ─────────────────────────────────────────────────────── + pnlToolbar = new Panel + { + Dock = DockStyle.Top, + Height = 55, + BackColor = Color.FromArgb(248, 250, 252), + BorderStyle = BorderStyle.None + }; + + var flowButtons = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(12, 10, 0, 0), + BackColor = Color.Transparent + }; + + var btnNovo = CreateToolbarButton("Novo", Color.FromArgb(34, 197, 94)); + var btnAlterar = CreateToolbarButton("Alterar", Color.FromArgb(245, 158, 11)); + var btnExcluir = CreateToolbarButton("Excluir", Color.FromArgb(239, 68, 68)); + var btnLocalizar = CreateToolbarButton("Localizar", AccentBlue); + var btnSalvar = CreateToolbarButton("Salvar", AccentBlue); + var btnCancelar = CreateToolbarButton("Cancelar", Color.FromArgb(148, 163, 184)); + var btnCriarCert = CreateToolbarButton("Certificado", Color.FromArgb(148, 160, 184)); + var btnGerarFichaPDF = CreateToolbarButton("Ficha Tecnica", Color.FromArgb(255, 0, 0)); + + btnNovo.Click += (s, e) => BtnNovo_Click(); + btnAlterar.Click += (s, e) => BtnAlterar_Click(); + btnExcluir.Click += (s, e) => BtnExcluir_Click(); + btnLocalizar.Click += (s, e) => BtnLocalizar_Click(); + btnSalvar.Click += (s, e) => BtnSalvar_Click(); + btnCancelar.Click += (s, e) => BtnCancelar_Click(); + btnCriarCert.Click += (s, e) => BtnGerarCertificado_Click(); + btnGerarFichaPDF.Click += (s, e) => BtnFicha_Click(); + + flowButtons.Controls.AddRange(new Control[] + { btnNovo, btnAlterar, btnExcluir, btnLocalizar, btnSalvar, btnCancelar,btnCriarCert,btnGerarFichaPDF }); + pnlToolbar.Controls.Add(flowButtons); + this.Controls.Add(pnlToolbar); + + // ── SCROLL + CONTENT ────────────────────────────────────────────── + mainScroll = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = Color.White + }; + this.Controls.Add(mainScroll); + mainScroll.BringToFront(); + + content = new Panel + { + Width = 1100, + Height = 900, + Location = new Point(0, 0), + BackColor = Color.White + }; + mainScroll.Controls.Add(content); + + const int rowH = 52; + const int secGap = 10; + const int secH = 28; + const int inputH = 28; + + int y = 10; + + // ── 1. IDENTIFICAÇÃO DA EMPRESA ─────────────────────────────────── + content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DA EMPRESA", y)); + y += secH + 4; + + txtId = AddInput(content, "ID", 20, y, 60, inputH, readOnly: true); + txtNome = AddInput(content, "Nome / Razão Social", 90, y, 450, inputH); + txtCNPJ = AddInput(content, "CNPJ", 550, y, 180, inputH); + DocumentoHelper.Registrar(txtCNPJ); + txtTipoEmpresa = AddInput(content, "Tipo Empresa", 740, y, 200, inputH); + y += rowH; + + txtRegimeTributario = AddInput(content, "Regime Tributário", 20, y, 200, inputH); + txtCNAE = AddInput(content, "CNAE", 230, y, 150, inputH); + txtInscricaoEstadual = AddInput(content, "Inscrição Estadual", 390, y, 200, inputH); + txtInscricaoMunicipal = AddInput(content, "Inscrição Municipal", 600, y, 200, inputH); + + // ── 2. ENDEREÇO COMPLETO ────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("ENDEREÇO COMPLETO", y)); + y += secH + 4; + + txtCep = AddInput(content, "CEP", 20, y, 95, inputH); + // No InitializeLayout(), após criar o txtCep + txtCep.Leave += (s, e) => + { + string cep = txtCep.Text.Trim().Replace("-", ""); + + if (cep.Length != 8) return; + + if (TLL.VerifyCep.verificaCEP(cep)) + { + txtEndereco.Text = TLL.VerifyCep.endereco; + txtBairro.Text = TLL.VerifyCep.bairro; + txtCidade.Text = TLL.VerifyCep.cidade; + txtUF.Text = TLL.VerifyCep.estado; + txtPais.Text = "Brasil"; + + // Formata o CEP com hífen + txtCep.Text = $"{cep[..5]}-{cep[5..]}"; + } + else + { + NT_MessageBox.Show("CEP não encontrado.", "CEP", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + }; + txtEndereco = AddInput(content, "Logradouro", 125, y, 370, inputH); + txtNumero = AddInput(content, "Nº", 505, y, 60, inputH); + txtComplemento = AddInput(content, "Complemento", 575, y, 175, inputH); + txtBairro = AddInput(content, "Bairro", 760, y, 180, inputH); + y += rowH; + + txtCidade = AddInput(content, "Cidade", 20, y, 280, inputH); + txtUF = AddInput(content, "UF", 310, y, 55, inputH); + txtPais = AddInput(content, "País", 375, y, 150, inputH); + + // ── 3. CONTATOS E COMUNICAÇÃO ───────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("CONTATOS E COMUNICAÇÃO", y)); + y += secH + 4; + + txtTelefone1 = AddInput(content, "Telefone 1", 20, y, 155, inputH); + txtTelefone2 = AddInput(content, "Telefone 2", 185, y, 155, inputH); + txtCelular = AddInput(content, "Celular", 350, y, 155, inputH); + txtWhatsapp = AddInput(content, "WhatsApp", 515, y, 155, inputH); + y += rowH; + + txtEmail = AddInput(content, "E-mail", 20, y, 350, inputH); + txtSite = AddInput(content, "Site", 380, y, 290, inputH); + + // ── 4. DADOS DO CONTADOR ────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("DADOS DO CONTADOR", y)); + y += secH + 4; + + txtCNPJCPF_Contador = AddInput(content, "CPF/CNPJ do Contador", 20, y, 200, inputH); + DocumentoHelper.Registrar(txtCNPJCPF_Contador); + txtNome_Contador = AddInput(content, "Nome do Contador", 230, y, 400, inputH); + + // ── 5. OUTROS ───────────────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("OUTROS", y)); + y += secH + 4; + + txtTextoParaRecibo = AddInput(content, "Texto para Recibo", 20, y, 920, inputH); + y += rowH; + txtTextoParaRecibo.Multiline = true; + + + chkAtivo = CreateCheckBox("Ativo", 20, y); + content.Controls.Add(chkAtivo); + + // ── 6. INFORMAÇÕES DO REGISTRO ──────────────────────────────────── + y += 35 + secGap; + content.Controls.Add(CreateSectionHeader("INFORMAÇÕES DO REGISTRO", y)); + y += secH + 4; + + txtCriadoEm = AddInput(content, "Criado Em", 20, y, 175, inputH, readOnly: true); + txtAtualizadoEm = AddInput(content, "Atualizado Em", 205, y, 175, inputH, readOnly: true); + y += rowH; + + content.Height = y + 10; + + SetCampos(false); + } + + // ── CAMPOS ──────────────────────────────────────────────────────────── + + private RoundTextBox[] TodosOsCampos() => new[] + { + txtNome, txtCNPJ, txtTipoEmpresa, txtRegimeTributario, txtCNAE, + txtInscricaoEstadual, txtInscricaoMunicipal, + txtCep, txtEndereco, txtNumero, txtComplemento, + txtBairro, txtCidade, txtUF, txtPais, + txtTelefone1, txtTelefone2, txtCelular, txtWhatsapp, + txtEmail, txtSite, + txtCNPJCPF_Contador, txtNome_Contador, + txtTextoParaRecibo + }; + + private void SetCampos(bool enabled) + { + foreach (var campo in TodosOsCampos()) + { + campo.Enabled = enabled; + campo.BackColor = enabled ? Color.White : Color.FromArgb(241, 245, 249); + } + chkAtivo.Enabled = enabled; + } + + // ── EVENTOS ─────────────────────────────────────────────────────────── + + private void BtnNovo_Click() + { + foreach (var campo in TodosOsCampos()) + campo.Text = string.Empty; + + chkAtivo.Checked = true; + SetCampos(true); + } + + private void BtnAlterar_Click() + { + if (string.IsNullOrWhiteSpace(txtId.Text)) + { + MessageBox.Show( + "Nenhum registro selecionado para alterar.", + "Atenção", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; + } + + SetCampos(true); + txtId.Enabled = false; + txtId.BackColor = Color.FromArgb(241, 245, 249); + } + // Evento + private void BtnFicha_Click() + { + var bll = new BLLEmpresa(_cx); + var empresa = bll.CarregarEmpresaAtiva(); + + if (empresa == null) + { + MessageBox.Show("Nenhuma empresa ativa encontrada."); + return; + } + + var resultado = TLL.FichaEmpresaPDF.GerarEAbrir(empresa); + + if (!resultado.Sucesso) + MessageBox.Show(resultado.Mensagem, "Erro", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + private void BtnExcluir_Click() + { + // Solicita confirmação e exclui o registro atual + } + + private void BtnLocalizar_Click() + { + // Abre tela/diálogo de busca e preenche os campos + } + private void BtnGerarCertificado_Click() + { + ModeloEmpresa empresa = new ModeloEmpresa(); + // Após salvar a empresa com sucesso... + var resultado = TLL.CertificadoHelper.Gerar(empresa, "Nike12122020*##"); + + if (resultado.Sucesso) + NT_MessageBox.Show( + $"Certificado gerado!\nVálido até: {resultado.ValidoAte:dd/MM/yyyy}\n" + + $"Thumbprint: {resultado.Thumbprint}", + "Certificado", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + NT_MessageBox.Show(resultado.Mensagem, "Erro", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + private void BtnVerificarCert_Click() + { + ModeloEmpresa empresa = new ModeloEmpresa(); + var status = TLL.CertificadoHelper.VerificarStatus(empresa.CNPJ, "Nike12122020*##"); + + if (!status.Valido) + NT_MessageBox.Show("Certificado expirado! Gere um novo.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + + private void BtnSalvar_Click() + { + BLLEmpresa _empresaBLL = new BLLEmpresa(_cx); + + if (string.IsNullOrWhiteSpace(txtNome.Text) || + string.IsNullOrWhiteSpace(txtCNPJ.Text) || + string.IsNullOrWhiteSpace(txtEmail.Text)) + { + NT_MessageBox.Show("Preencha ao menos Nome, CNPJ e Email.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + bool isNew = string.IsNullOrWhiteSpace(txtId.Text); + + var empresa = new MLL.ModeloEmpresa( + id: isNew ? 0 : int.Parse(txtId.Text), + nome: txtNome.Text, + cNPJ: txtCNPJ.Text, + tipoEmpresa: txtTipoEmpresa.Text, + regimeTributario: txtRegimeTributario.Text, + cNAE: txtCNAE.Text, + cep: txtCep.Text, + endereco: txtEndereco.Text, + numero: string.IsNullOrWhiteSpace(txtNumero.Text) ? 0 : int.Parse(txtNumero.Text), + complemento: txtComplemento.Text, + bairro: txtBairro.Text, + cidade: txtCidade.Text, + uF: txtUF.Text, + pais: txtPais.Text, + telefone1: txtTelefone1.Text, + telefone2: txtTelefone2.Text, + celular: txtCelular.Text, + whatsapp: txtWhatsapp.Text, + email: txtEmail.Text, + site: txtSite.Text, + inscricaoEstadual: txtInscricaoEstadual.Text, + inscricaoMunicipal: txtInscricaoMunicipal.Text, + cNPJCPF_Contador: txtCNPJCPF_Contador.Text, + nome_Contador: txtNome_Contador.Text, + textoParaRecibo: txtTextoParaRecibo.Text, + ativo: chkAtivo.Checked, + criadoEm: DateTime.Now, + atualizadoEm: DateTime.Now + ); + + bool sucesso; + + if (isNew) + sucesso = _empresaBLL.Inserir(empresa); + else + sucesso = _empresaBLL.Alterar(empresa); + + if (!sucesso) + { + NT_MessageBox.Show("Erro ao salvar empresa.", + "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + // 🔹 Atualiza UI + txtAtualizadoEm.Text = DateTime.Now.ToString("dd/MM/yyyy"); + SetCampos(false); + + NT_MessageBox.Show("Empresa salva com sucesso!", "Sucesso", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void BtnCancelar_Click() + { + foreach (var campo in TodosOsCampos()) + campo.Text = string.Empty; + + chkAtivo.Checked = false; + SetCampos(false); + } + + // ── HELPERS ─────────────────────────────────────────────────────────── + + private Panel CreateSectionHeader(string title, int y) + { + var pnl = new Panel { Location = new Point(20, y), Width = 1000, Height = 26 }; + var lbl = new Label + { + Text = title, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = AccentBlue, + AutoSize = true, + Location = new Point(0, 0) + }; + var line = new Panel + { + BackColor = BorderColor, + Height = 1, + Width = 980, + Location = new Point(0, 20) + }; + pnl.Controls.Add(lbl); + pnl.Controls.Add(line); + return pnl; + } + + private RoundTextBox AddInput(Control parent, string label, + int x, int y, int width, int height, + bool readOnly = false) + { + var lbl = new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = readOnly ? Color.Gray : TextDark, + AutoSize = true + }; + var txt = new RoundTextBox + { + Location = new Point(x, y + 16), + Size = new Size(width, height), + Radius = 4, + BorderColor = readOnly ? Color.FromArgb(203, 213, 225) : BorderColor, + FocusColor = AccentBlue, + ReadOnly = readOnly, + BackColor = readOnly ? Color.FromArgb(241, 245, 249) : Color.White + }; + parent.Controls.Add(lbl); + parent.Controls.Add(txt); + return txt; + } + + private CheckBox CreateCheckBox(string text, int x, int y) => new CheckBox + { + Text = text, + Location = new Point(x, y), + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + + private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton + { + Text = text, + Size = new Size(95, 32), + BackColor = color, + ForeColor = Color.White, + Font = new Font("Segoe UI Semibold", 8.5f), + Margin = new Padding(0, 0, 6, 0), + Cursor = Cursors.Hand + }; + } +} \ No newline at end of file diff --git a/Dashboards/Cadastros/EmpresaCadastroPanel.resx b/Dashboards/Cadastros/EmpresaCadastroPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Cadastros/EmpresaCadastroPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Cadastros/EmpresaConfiguracoesPanel.cs b/Dashboards/Cadastros/EmpresaConfiguracoesPanel.cs new file mode 100644 index 0000000..16f4a1e --- /dev/null +++ b/Dashboards/Cadastros/EmpresaConfiguracoesPanel.cs @@ -0,0 +1,591 @@ +using BLL; +using CCH; +using CustomMessageBox; +using DAL; +using System.Drawing; +using System.IO; +using System.Windows.Forms; + +namespace UI +{ + public class EmpresaConfiguracoesPanel : UserControl + { + //Variaveis de ambiente + private int _idEmpresa; + private int _idConfig; + private string _connectionString = DadosDaConexao.ObterConexao(); + + private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private readonly Color TextDark = Color.FromArgb(30, 41, 59); + private readonly Color BorderColor = Color.FromArgb(226, 232, 240); + + private Panel pnlToolbar = null!; + private Panel mainScroll = null!; + private Panel content = null!; + + private RoundTextBox txtId = null!, txtEmpresaId = null!, txtNomeSistema = null!; + private RoundTextBox txtCorPrimaria = null!, txtCorSecundaria = null!; + private RoundTextBox txtLogo = null!, txtFavicon = null!; + private RoundTextBox txtDiasGarantiaPadrao = null!; + + private CheckBox chkExibirCPF = null!, chkExibirTelefone = null!, chkExibirGarantia = null!; + private CheckBox chkGerarRecibo = null!, chkExibirValoresOS = null!; + private CheckBox chkEmailAuto = null!, chkWhatsAuto = null!, chkModoEscuro = null!; + private CheckBox chkPermitirEdicaoOS = null!; + + private RoundTextBox txtCriadoEm = null!, txtAtualizadoEm = null!; + + public EmpresaConfiguracoesPanel() + { + Dock = DockStyle.Fill; + BackColor = Color.White; + DoubleBuffered = true; + InitializeLayout(); + this.CarregarConfig(); + + } + + private void InitializeLayout() + { + this.Controls.Clear(); + + // ── TOOLBAR ─────────────────────────────────────────────────────── + pnlToolbar = new Panel + { + Dock = DockStyle.Top, + Height = 55, + BackColor = Color.FromArgb(248, 250, 252) + }; + var flowButtons = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(12, 10, 0, 0) + }; + + var btnNovo = CreateToolbarButton("Novo", Color.FromArgb(34, 197, 94)); + var btnAlterar = CreateToolbarButton("Alterar", Color.FromArgb(245, 158, 11)); + var btnExcluir = CreateToolbarButton("Excluir", Color.FromArgb(239, 68, 68)); + var btnLocalizar = CreateToolbarButton("Localizar", AccentBlue); + var btnSalvar = CreateToolbarButton("Salvar", AccentBlue); + var btnCancelar = CreateToolbarButton("Cancelar", Color.FromArgb(148, 163, 184)); + var btnConfigEmpresa = CreateToolbarButton("Gerar Config", Color.FromArgb(148, 163, 184)); + + btnNovo.Click += (s, e) => BtnNovo_Click(); + btnAlterar.Click += (s, e) => BtnAlterar_Click(); + btnExcluir.Click += (s, e) => BtnExcluir_Click(); + btnLocalizar.Click += (s, e) => BtnLocalizar_Click(); + btnSalvar.Click += (s, e) => BtnSalvar_Click(); + btnCancelar.Click += (s, e) => BtnCancelar_Click(); + btnConfigEmpresa.Click += (s, e) => BtnGerarConfig_Click(); + + flowButtons.Controls.AddRange(new Control[] + { btnNovo, btnAlterar, btnExcluir, btnLocalizar, btnSalvar,btnConfigEmpresa,btnCancelar }); + pnlToolbar.Controls.Add(flowButtons); + this.Controls.Add(pnlToolbar); + + // ── SCROLL + CONTENT ────────────────────────────────────────────── + mainScroll = new Panel { Dock = DockStyle.Fill, AutoScroll = true }; + this.Controls.Add(mainScroll); + mainScroll.BringToFront(); + + content = new Panel { Width = 1100, Height = 850, Location = new Point(0, 0) }; + mainScroll.Controls.Add(content); + + int y = 10; + const int rowH = 52; + + // ── 1. IDENTIDADE DO SISTEMA ────────────────────────────────────── + content.Controls.Add(CreateSectionHeader("IDENTIDADE DO SISTEMA", y)); + y += 32; + + txtId = AddInput(content, "ID", 20, y, 60, 28, readOnly: true); + txtEmpresaId = AddInput(content, "Empresa ID", 90, y, 80, 28); + txtNomeSistema = AddInput(content, "Nome Personalizado do Sistema", 180, y, 350, 28); + y += rowH; + + txtCorPrimaria = AddInput(content, "Cor Primária (Hex)", 20, y, 150, 28); + txtCorSecundaria = AddInput(content, "Cor Secundária (Hex)", 180, y, 150, 28); + + // Logo com botão lupa + txtLogo = AddInput(content, "Caminho da Logo", 340, y, 260, 28); + var btnLogo = CreateIconButton("🔍", 608, y + 16); + btnLogo.Click += (s, e) => SelecionarImagem(txtLogo, "Logo"); + content.Controls.Add(btnLogo); + + // Favicon com botão lupa + txtFavicon = AddInput(content, "Caminho do Favicon", 650, y, 240, 28); + var btnFavicon = CreateIconButton("🔍", 898, y + 16); + btnFavicon.Click += (s, e) => SelecionarImagem(txtFavicon, "Favicon"); + content.Controls.Add(btnFavicon); + + // ── 2. REGRAS DE NEGÓCIO E EXIBIÇÃO ────────────────────────────── + y += rowH + 15; + content.Controls.Add(CreateSectionHeader("REGRAS DE NEGÓCIO E EXIBIÇÃO", y)); + y += 32; + + chkExibirCPF = CreateCheckBox("Exibir CPF Cliente na OS", 20, y + 15); + chkExibirTelefone = CreateCheckBox("Exibir Telefone na OS", 230, y + 15); + chkExibirValoresOS = CreateCheckBox("Exibir Valores na OS", 460, y + 15); + content.Controls.AddRange(new Control[] { chkExibirCPF, chkExibirTelefone, chkExibirValoresOS }); + y += rowH; + + chkExibirGarantia = CreateCheckBox("Utilizar Garantia", 20, y + 15); + txtDiasGarantiaPadrao = AddInput(content, "Dias Garantia (Padrão)", 180, y, 120, 28); + content.Controls.Add(chkExibirGarantia); + + // ── 3. AUTOMAÇÕES E COMUNICAÇÃO ─────────────────────────────────── + y += rowH + 15; + content.Controls.Add(CreateSectionHeader("AUTOMAÇÕES E COMUNICAÇÃO", y)); + y += 32; + + chkGerarRecibo = CreateCheckBox("Gerar Recibo Automático", 20, y + 15); + chkEmailAuto = CreateCheckBox("Enviar E-mail Automático", 230, y + 15); + chkWhatsAuto = CreateCheckBox("Enviar WhatsApp Automático", 460, y + 15); + content.Controls.AddRange(new Control[] { chkGerarRecibo, chkEmailAuto, chkWhatsAuto }); + + // ── 4. PREFERÊNCIAS TÉCNICAS ────────────────────────────────────── + y += rowH + 15; + content.Controls.Add(CreateSectionHeader("PREFERÊNCIAS TÉCNICAS", y)); + y += 32; + + chkModoEscuro = CreateCheckBox("Habilitar Modo Escuro", 20, y + 15); + chkPermitirEdicaoOS = CreateCheckBox("Permitir Edição de OS Finalizada", 230, y + 15); + content.Controls.AddRange(new Control[] { chkModoEscuro, chkPermitirEdicaoOS }); + + // ── 5. INFORMAÇÕES DO REGISTRO ──────────────────────────────────── + y += rowH + 15; + content.Controls.Add(CreateSectionHeader("INFORMAÇÕES DO REGISTRO", y)); + y += 32; + + txtCriadoEm = AddInput(content, "Criado Em", 20, y, 180, 28, readOnly: true); + txtAtualizadoEm = AddInput(content, "Atualizado Em", 210, y, 180, 28, readOnly: true); + y += rowH; + + content.Height = y + 20; + + SetCamposStatus(false); + } + + // ── SELEÇÃO DE IMAGEM ───────────────────────────────────────────────── + + //private void SelecionarImagem(RoundTextBox destino, string tipo) + //{ + // using var dlg = new OpenFileDialog + // { + // Title = $"Selecionar {tipo}", + // Filter = "Imagens|*.png;*.jpg;*.jpeg;*.bmp;*.ico;*.gif|Todos os arquivos|*.*" + // }; + + // if (dlg.ShowDialog() == DialogResult.OK) + // { + // var arquivo = dlg.FileName; + // destino.Text = arquivo; + + // // Valida tamanho máximo (2MB) + // var info = new FileInfo(arquivo); + // if (info.Length > 2 * 1024 * 1024) + // { + // MessageBox.Show( + // $"O arquivo selecionado para {tipo} é maior que 2MB.\nRecomendamos imagens menores para melhor desempenho.", + // "Atenção", + // MessageBoxButtons.OK, + // MessageBoxIcon.Warning); + // } + // } + //} + private void SelecionarImagem(RoundTextBox destino, string tipo) + { + using var dlg = new OpenFileDialog + { + Title = $"Selecionar {tipo}", + Filter = "Imagens|*.png;*.jpg;*.jpeg;*.bmp;*.ico;*.gif|Todos os arquivos|*.*" + }; + + if (dlg.ShowDialog() == DialogResult.OK) + { + try + { + var arquivoOriginal = dlg.FileName; + + // 📁 Pasta destino fixa + string pastaDestino = @"C:\Levelcode\LevelOS\Uploads\Images"; + + // Cria a pasta se não existir + if (!Directory.Exists(pastaDestino)) + Directory.CreateDirectory(pastaDestino); + + // 🔥 Gera nome único (evita sobrescrever) + string extensao = Path.GetExtension(arquivoOriginal); + string nomeNovo = $"{tipo}_{Guid.NewGuid()}{extensao}"; + string caminhoFinal = Path.Combine(pastaDestino, nomeNovo); + + // Copia o arquivo + File.Copy(arquivoOriginal, caminhoFinal, false); + + // Atualiza o campo + destino.Text = caminhoFinal; + + // ⚠️ Valida tamanho (2MB) + var info = new FileInfo(caminhoFinal); + if (info.Length > 2 * 1024 * 1024) + { + MessageBox.Show( + $"O arquivo selecionado para {tipo} é maior que 2MB.\nRecomendamos imagens menores para melhor desempenho.", + "Atenção", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + } + catch (Exception ex) + { + MessageBox.Show( + "Erro ao copiar imagem: " + ex.Message, + "Erro", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + }//Copiar com mais precisão + + // ── EVENTOS DOS BOTÕES ──────────────────────────────────────────────── + + private void BtnNovo_Click() + { + LimparFormulario(); + SetCamposStatus(true); + txtNomeSistema.Focus(); + BLLEmpresaConfig empresaConfig = new BLLEmpresaConfig(_connectionString); + this.txtEmpresaId.Text = empresaConfig.ObterEmpresaAtivaId().ToString(); + } + + private void BtnAlterar_Click() + { + if (string.IsNullOrWhiteSpace(txtId.Text)) + { + MessageBox.Show( + "Nenhum registro selecionado para alterar.", + "Atenção", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; + } + SetCamposStatus(true); + } + + private void BtnExcluir_Click() + { + // Solicita confirmação e exclui o registro + } + + private void BtnLocalizar_Click() + { + // Abre tela de busca e preenche os campos + } + private void BtnGerarConfig_Click() + { + var config = new ModeloEmpresaConfig + { + IdEmpresaConfig = Convert.ToInt32(txtId.Text), // você precisa ter isso carregado + IdEmpresa = Convert.ToInt32(txtEmpresaId.Text), // idem (empresa logada) + + NomeSistema = txtNomeSistema.Text, + CorPrimaria = txtCorPrimaria.Text, + CorSecundaria = txtCorSecundaria.Text, + Logo = txtLogo.Text, + Favicon = txtFavicon.Text, + + ExibirCPFCliente = chkExibirCPF.Checked, + ExibirTelefoneCliente = chkExibirTelefone.Checked, + ExibirGarantia = chkExibirGarantia.Checked, + DiasGarantiaPadrao = Convert.ToInt32(txtDiasGarantiaPadrao.Text), + + GerarReciboAutomatico = chkGerarRecibo.Checked, + ExibirValoresOS = chkExibirValoresOS.Checked, + + EnviarEmailAutomatico = chkEmailAuto.Checked, + EnviarWhatsappAutomatico = chkWhatsAuto.Checked, + + ModoEscuro = chkModoEscuro.Checked, + PermitirEdicaoOSFinalizada = chkPermitirEdicaoOS.Checked + }; + bool result = JsonHelper.SalvarBoolean(config, AppFileSystem.AppFileConfigEmpresa); + if (result) + { + NT_MessageBox.Show("Arquivo de configuração gerado com sucesso.","Arquivo gerado",MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + else + { + NT_MessageBox.Show("Não foi possivel gerar o arquivo de configuração", "falha ao gerar arquivo", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void BtnSalvar_Click() + { + try + { + // Valida campos obrigatórios + if (string.IsNullOrWhiteSpace(txtNomeSistema.Text)) + { + MessageBox.Show( + "O campo 'Nome do Sistema' é obrigatório.", + "Atenção", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + txtNomeSistema.Focus(); + return; + } + + // Valida cores HEX + if (!string.IsNullOrWhiteSpace(txtCorPrimaria.Text) && !ValidarHex(txtCorPrimaria.Text)) + { + MessageBox.Show("Cor Primária inválida. Ex: #3B82F6", "Atenção"); + txtCorPrimaria.Focus(); + return; + } + + if (!string.IsNullOrWhiteSpace(txtCorSecundaria.Text) && !ValidarHex(txtCorSecundaria.Text)) + { + MessageBox.Show("Cor Secundária inválida. Ex: #64748B", "Atenção"); + txtCorSecundaria.Focus(); + return; + } + + // Valida arquivos + if (!string.IsNullOrWhiteSpace(txtLogo.Text) && !File.Exists(txtLogo.Text)) + { + MessageBox.Show("Logo não encontrada.", "Atenção"); + return; + } + + if (!string.IsNullOrWhiteSpace(txtFavicon.Text) && !File.Exists(txtFavicon.Text)) + { + MessageBox.Show("Favicon não encontrado.", "Atenção"); + return; + } + + // 🔥 Monta o modelo + var config = new ModeloEmpresaConfig + { + IdEmpresaConfig = Convert.ToInt32(txtId.Text), // você precisa ter isso carregado + IdEmpresa = Convert.ToInt32(txtEmpresaId.Text), // idem (empresa logada) + + NomeSistema = txtNomeSistema.Text, + CorPrimaria = txtCorPrimaria.Text, + CorSecundaria = txtCorSecundaria.Text, + Logo = txtLogo.Text, + Favicon = txtFavicon.Text, + + ExibirCPFCliente = chkExibirCPF.Checked, + ExibirTelefoneCliente = chkExibirTelefone.Checked, + ExibirGarantia = chkExibirGarantia.Checked, + DiasGarantiaPadrao =Convert.ToInt32(txtDiasGarantiaPadrao.Text), + + GerarReciboAutomatico = chkGerarRecibo.Checked, + ExibirValoresOS = chkExibirValoresOS.Checked, + + EnviarEmailAutomatico = chkEmailAuto.Checked, + EnviarWhatsappAutomatico = chkWhatsAuto.Checked, + + ModoEscuro = chkModoEscuro.Checked, + PermitirEdicaoOSFinalizada = chkPermitirEdicaoOS.Checked + }; + + var bll = new BLLEmpresaConfig(_connectionString); + + // 🔥 Decide se cria ou atualiza + _idConfig = Convert.ToInt32(txtId.Text); + if (_idConfig == 0 || _idConfig == null) + { + bll.Inserir(config); + JsonHelper.Salvar(config, AppFileSystem.AppFileConfigEmpresa); + } + else + { + + bll.Alterar(config); + JsonHelper.Salvar(config, AppFileSystem.AppFileConfigEmpresa); + } + + MessageBox.Show( + "Configurações salvas com sucesso!", + "LevelOS", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + + SetCamposStatus(false); + } + catch (Exception ex) + { + MessageBox.Show( + ex.Message, + "Erro", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + private void BtnCancelar_Click() + { + LimparFormulario(); + SetCamposStatus(false); + } + + // ── HELPERS DE ESTADO ───────────────────────────────────────────────── + + private void SetCamposStatus(bool active) + { + var campos = new Control[] + { + txtEmpresaId, txtNomeSistema, txtCorPrimaria, txtCorSecundaria, + txtLogo, txtFavicon, txtDiasGarantiaPadrao, + chkExibirCPF, chkExibirTelefone, chkExibirGarantia, chkGerarRecibo, + chkExibirValoresOS, chkEmailAuto, chkWhatsAuto, chkModoEscuro, chkPermitirEdicaoOS + }; + + foreach (var c in campos) + { + c.Enabled = active; + if (c is RoundTextBox r) + r.BackColor = active ? Color.White : Color.FromArgb(241, 245, 249); + } + + // ID e datas nunca editáveis + txtId.Enabled = false; + txtId.BackColor = Color.FromArgb(241, 245, 249); + txtCriadoEm.Enabled = false; + txtAtualizadoEm.Enabled = false; + } + + private void LimparFormulario() + { + var todos = new RoundTextBox[] + { + txtId, txtEmpresaId, txtNomeSistema, txtCorPrimaria, txtCorSecundaria, + txtLogo, txtFavicon, txtDiasGarantiaPadrao, txtCriadoEm, txtAtualizadoEm + }; + foreach (var t in todos) t.Text = string.Empty; + + foreach (Control c in content.Controls) + if (c is CheckBox chk) chk.Checked = false; + } + + private static bool ValidarHex(string valor) + { + var v = valor.TrimStart('#'); + return v.Length == 6 && System.Text.RegularExpressions.Regex.IsMatch(v, @"^[0-9A-Fa-f]{6}$"); + } + + // ── HELPERS DE UI ───────────────────────────────────────────────────── + + private Panel CreateSectionHeader(string title, int y) + { + var pnl = new Panel { Location = new Point(20, y), Width = 1000, Height = 26 }; + pnl.Controls.Add(new Label + { + Text = title, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = AccentBlue, + AutoSize = true + }); + pnl.Controls.Add(new Panel + { + BackColor = BorderColor, + Height = 1, + Width = 980, + Location = new Point(0, 20) + }); + return pnl; + } + + private RoundTextBox AddInput(Control parent, string label, + int x, int y, int w, int h, + bool readOnly = false) + { + parent.Controls.Add(new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = readOnly ? Color.Gray : TextDark, + AutoSize = true + }); + var txt = new RoundTextBox + { + Location = new Point(x, y + 16), + Size = new Size(w, h), + Radius = 4, + BorderColor = readOnly ? Color.FromArgb(203, 213, 225) : BorderColor, + FocusColor = AccentBlue, + ReadOnly = readOnly, + BackColor = readOnly ? Color.FromArgb(241, 245, 249) : Color.White + }; + parent.Controls.Add(txt); + return txt; + } + + private Button CreateIconButton(string icon, int x, int y) => new Button + { + Text = icon, + Location = new Point(x, y), + Size = new Size(28, 28), + FlatStyle = FlatStyle.Flat, + Font = new Font("Segoe UI", 10f), + Cursor = Cursors.Hand, + FlatAppearance = { BorderColor = BorderColor, BorderSize = 1 }, + BackColor = Color.FromArgb(241, 245, 249) + }; + + private CheckBox CreateCheckBox(string text, int x, int y) => new CheckBox + { + Text = text, + Location = new Point(x, y), + Font = new Font("Segoe UI", 8.25f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + + private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton + { + Text = text, + Size = new Size(95, 32), + BackColor = color, + ForeColor = Color.White, + Font = new Font("Segoe UI Semibold", 8.5f), + Margin = new Padding(0, 0, 6, 0), + Cursor = Cursors.Hand + }; + + private void CarregarConfig() + { + BLLEmpresaConfig empresaConfig = new BLLEmpresaConfig(_connectionString); + int codEmpresa = empresaConfig.ObterEmpresaAtivaId(); + if (codEmpresa > 0) + { + ModeloEmpresaConfig modelo = empresaConfig.ObterPorEmpresa(codEmpresa); + this.txtId.Text = modelo.IdEmpresaConfig.ToString(); + this.txtEmpresaId.Text = modelo.IdEmpresa.ToString(); + this.txtNomeSistema.Text = modelo.NomeSistema; + this.txtCorPrimaria.Text = modelo.CorPrimaria; + this.txtCorSecundaria.Text = modelo.CorSecundaria; + this.txtLogo.Text = modelo.Logo; + this.txtFavicon.Text = modelo.Favicon; + this.txtDiasGarantiaPadrao.Text = modelo.DiasGarantiaPadrao.ToString(); + this.chkExibirCPF.Checked = modelo.ExibirCPFCliente; + this.chkExibirTelefone.Checked = modelo.ExibirTelefoneCliente; + this.chkExibirGarantia.Checked = modelo.ExibirGarantia; + this.chkGerarRecibo.Checked = modelo.GerarReciboAutomatico; + this.chkExibirValoresOS.Checked = modelo.ExibirValoresOS; + this.chkEmailAuto.Checked = modelo.EnviarEmailAutomatico; + this.chkWhatsAuto.Checked = modelo.EnviarWhatsappAutomatico; + this.chkModoEscuro.Checked = modelo.ModoEscuro; + this.chkPermitirEdicaoOS.Checked = modelo.PermitirEdicaoOSFinalizada; + this.txtCriadoEm.Text = modelo.CriadoEm.ToString(); + this.txtAtualizadoEm.Text = modelo.AtualizadoEm.ToString(); + } + else + { + NT_MessageBox.Show("Erro ao recuperar configuração da empresa, por favor contacte o administrador do sistema","Erro",MessageBoxButtons.OK,MessageBoxIcon.Error); + } + } + } +} \ No newline at end of file diff --git a/Dashboards/Cadastros/EmpresaConfiguracoesPanel.resx b/Dashboards/Cadastros/EmpresaConfiguracoesPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Cadastros/EmpresaConfiguracoesPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Cadastros/FuncionariosCadastroPanel.cs b/Dashboards/Cadastros/FuncionariosCadastroPanel.cs new file mode 100644 index 0000000..8a5958a --- /dev/null +++ b/Dashboards/Cadastros/FuncionariosCadastroPanel.cs @@ -0,0 +1,947 @@ +using BLL; +using CustomMessageBox; +using DAL; +using MLL; +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Windows.Forms; +using AForge.Video; +using AForge.Video.DirectShow; + +namespace UI +{ + public class FuncionariosCadastroPanel : UserControl + { + private int idBanco = 0; + private string _cx = DadosDaConexao.ObterConexao(); + private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private readonly Color TextDark = Color.FromArgb(30, 41, 59); + private readonly Color BorderColor = Color.FromArgb(226, 232, 240); + + private Panel pnlToolbar = null!; + private Panel mainScroll = null!; + private Panel content = null!; + + // Identificação + private RoundTextBox txtId = null!, txtCodigo = null!, txtNome = null!; + private RoundTextBox txtCPF = null!, txtCI = null!, txtCTPS = null!; + private RoundTextBox txtCNH = null!, txtCatCNH = null!; + private RoundTextBox txtECivil = null!, txtRegime = null!; + + // Filiação + private RoundTextBox txtPai = null!, txtMae = null!; + + // Endereço + private RoundTextBox txtcep=null!, txtEndereco = null!,txtEndNumero=null!, txtBairro = null!, txtCidade = null!, txtUF = null!; + + // Dados Bancários + private RoundTextBox txtBanco = null!, txtAgencia = null!, txtConta = null!; + private RoundComboBox cbBanco = null!; + + // Contato + private RoundTextBox txtTelefone = null!; + + // Acesso + private RoundTextBox txtPass = null!; + private CheckBox chkMasterUser = null!, chkVendedor = null!, chkTecnico = null!; + private CheckBox chkDemitido = null!, chkContador = null!, chkOutros = null!; + + // Outros + private RoundTextBox txtFPath = null!, txtObserv = null!; + + // Datas + private RoundTextBox txtDataAdm = null!, txtDataDem = null!, txtAniver = null!; + + // ── CARREGAR FUNCIONÁRIO ────────────────────────────────────────────── + + private void CarregarFuncionario(int id) + { + //var bll = new BLLFuncionarios(_cx); + //var f = bll.CarregarPorId(id); + + //if (f == null) + //{ + // NT_MessageBox.Show("Funcionário não encontrado.", + // "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + // return; + //} + + //PreencherCampos(f); + } + + private void PreencherCampos(ModeloFuncionarios f) + { + txtId.Text = f.ID_FUNCIONARIO.ToString(); + txtCodigo.Text = f.CODIGO; + txtNome.Text = f.NOME; + txtPai.Text = f.PAI; + txtMae.Text = f.MAE; + txtCPF.Text = f.CPF; + txtCI.Text = f.CI; + txtCTPS.Text = f.CTPS; + txtCNH.Text = f.CNH; + txtCatCNH.Text = f.CAT_CNH; + txtECivil.Text = f.ECIVIL; + txtRegime.Text = f.REGIME; + txtEndereco.Text = f.ENDERECO; + txtBairro.Text = f.BAIRRO; + txtCidade.Text = f.CIDADE; + txtUF.Text = f.UF; + txtBanco.Text = f.BANCO; + txtAgencia.Text = f.AGENCIA; + txtConta.Text = f.CONTA; + txtTelefone.Text = f.TELEFONE; + txtPass.Text = f.PASS; + txtFPath.Text = f.FPATH; + txtObserv.Text = f.OBSERV; + //txtDataAdm.Text = f.DATA_ADM; + //txtDataDem.Text = f.DATA_DEM; + //txtAniver.Text = f.ANIVER; + + //chkMasterUser.Checked = f.MASTERUSER == "S"; + //chkVendedor.Checked = f.VENDEDOR == "S"; + //chkTecnico.Checked = f.TECNICO == "S"; + //chkDemitido.Checked = f.DEMITIDO == "S"; + //chkContador.Checked = f.FTECNICO == "S"; + //chkOutros.Checked = f.FVENDEDOR == "S"; + } + private Control[] TodosOsControles() => new Control[]{ + txtCodigo, txtNome, + txtCPF, txtCI, txtCTPS, txtCNH, txtCatCNH, + txtECivil, txtRegime, + txtPai, txtMae, + txtcep, txtEndereco, txtEndNumero, txtBairro, txtCidade, txtUF, + + // 👇 ComboBox entra aqui + cbBanco, + + txtAgencia, txtConta, + txtTelefone, + txtPass, + txtFPath, txtObserv, + txtDataAdm, txtDataDem, txtAniver +};//todos os controles + private void SetCamposAtulizado(bool enabled) + { + foreach (var ctrl in TodosOsControles()) + { + ctrl.Enabled = enabled; + + // 🎨 Se for TextBox + if (ctrl is RoundTextBox txt) + { + txt.BackColor = enabled + ? Color.White + : Color.FromArgb(241, 245, 249); + } + + // 🎨 Se for ComboBox + else if (ctrl is RoundComboBox cmb) + { + cmb.BackColor = enabled + ? Color.White + : Color.FromArgb(241, 245, 249); + } + } + + foreach (var chk in TodosOsChecks()) + chk.Enabled = enabled; + }//SetCampos + private void CarregarComboBoxAtualizada() + { + BLLBancos bLLBancos = new BLLBancos(_cx); + + var tabela = bLLBancos.LocalizarTodos(); + + // 🔥 cria coluna personalizada + tabela.Columns.Add("EXIBICAO", typeof(string), "NUMERO + ' - ' + NOME"); + + cbBanco.DataSource = tabela; + cbBanco.DisplayMember = "EXIBICAO"; // 👈 aqui + cbBanco.ValueMember = "ID_BANCOS"; + + if (cbBanco.SelectedValue != null) + this.idBanco = Convert.ToInt32(cbBanco.SelectedValue); + }//CarregarComboBoxAtualizada + private DateTime? ConverterData(string texto) + { + if (string.IsNullOrWhiteSpace(texto)) + return null; + + if (DateTime.TryParse(texto, out DateTime data)) + return data; + + return null; + }//ConverterData + + public FuncionariosCadastroPanel() + { + Dock = DockStyle.Fill; + BackColor = Color.White; + DoubleBuffered = true; + InitializeLayout(); + this.CarregarComboBoxAtualizada(); + } + + private void InitializeLayout() + { + this.Controls.Clear(); + + // ── TOOLBAR ─────────────────────────────────────────────────────── + pnlToolbar = new Panel + { + Dock = DockStyle.Top, + Height = 55, + BackColor = Color.FromArgb(248, 250, 252), + BorderStyle = BorderStyle.None + }; + + var flowButtons = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(12, 10, 0, 0), + BackColor = Color.Transparent + }; + + var btnNovo = CreateToolbarButton("Novo", Color.FromArgb(34, 197, 94)); + var btnAlterar = CreateToolbarButton("Alterar", Color.FromArgb(245, 158, 11)); + var btnExcluir = CreateToolbarButton("Excluir", Color.FromArgb(239, 68, 68)); + var btnLocalizar = CreateToolbarButton("Localizar", AccentBlue); + var btnSalvar = CreateToolbarButton("Salvar", AccentBlue); + var btnGerarFicha = CreateToolbarButton("Gerar Ficha", Color.FromArgb(255,0,0)); + var btnCancelar = CreateToolbarButton("Cancelar", Color.FromArgb(148, 163, 184)); + + btnNovo.Click += (s, e) => BtnNovo_Click(); + btnAlterar.Click += (s, e) => BtnAlterar_Click(); + btnExcluir.Click += (s, e) => BtnExcluir_Click(); + btnLocalizar.Click += (s, e) => BtnLocalizar_Click(); + btnSalvar.Click += (s, e) => BtnSalvar_Click(); + btnCancelar.Click += (s, e) => BtnCancelar_Click(); + btnGerarFicha.Click += (s, e) => BtnFichaFuncionario_Click(); + flowButtons.Controls.AddRange(new Control[] + { btnNovo, btnAlterar, btnExcluir, btnLocalizar, btnSalvar,btnGerarFicha,btnCancelar }); + pnlToolbar.Controls.Add(flowButtons); + this.Controls.Add(pnlToolbar); + + // ── SCROLL + CONTENT ────────────────────────────────────────────── + mainScroll = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = Color.White + }; + this.Controls.Add(mainScroll); + mainScroll.BringToFront(); + + content = new Panel + { + Width = 1100, + Height = 900, + Location = new Point(0, 0), + BackColor = Color.White + }; + mainScroll.Controls.Add(content); + + const int rowH = 52; + const int secGap = 10; + const int secH = 28; + const int inputH = 28; + + int y = 10; + + // ── 1. IDENTIFICAÇÃO DO FUNCIONÁRIO ─────────────────────────────── + content.Controls.Add(CreateSectionHeader("IDENTIFICAÇÃO DO FUNCIONÁRIO", y)); + y += secH + 4; + + txtId = AddInput(content, "ID", 20, y, 60, inputH, readOnly: true); + txtCodigo = AddInput(content, "Código", 90, y, 100, inputH, readOnly: true); + txtNome = AddInput(content, "Nome", 200, y, 450, inputH); + y += rowH; + + txtCPF = AddInput(content, "CPF", 20, y, 160, inputH); + DocumentoHelper.Registrar(txtCPF); + txtCI = AddInput(content, "RG / CI", 190, y, 160, inputH); + txtCTPS = AddInput(content, "CTPS", 360, y, 140, inputH); + txtCNH = AddInput(content, "CNH", 510, y, 160, inputH); + txtCatCNH = AddInput(content, "Cat. CNH", 680, y, 90, inputH); + y += rowH; + + txtECivil = AddInput(content, "Estado Civil", 20, y, 160, inputH); + txtRegime = AddInput(content, "Regime", 190, y, 160, inputH); + + // ── 2. FILIAÇÃO ─────────────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("FILIAÇÃO", y)); + y += secH + 4; + + txtPai = AddInput(content, "Nome do Pai", 20, y, 400, inputH); + txtMae = AddInput(content, "Nome da Mãe", 430, y, 400, inputH); + + + // ── 3. ENDEREÇO ───────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("ENDEREÇO", y)); + y += secH + 4; + + // LINHA ÚNICA + txtcep = AddInput(content, "CEP", 20, y, 80, inputH); + txtcep.Leave += (s, e) => + { + string cep = txtcep.Text.Trim().Replace("-", ""); + + if (cep.Length != 8) return; + + if (TLL.VerifyCep.verificaCEP(cep)) + { + txtEndereco.Text = TLL.VerifyCep.endereco; + txtBairro.Text = TLL.VerifyCep.bairro; + txtCidade.Text = TLL.VerifyCep.cidade; + txtUF.Text = TLL.VerifyCep.estado; + + // Formata o CEP com hífen + txtcep.Text = $"{cep[..5]}-{cep[5..]}"; + } + else + { + NT_MessageBox.Show("CEP não encontrado.", "CEP", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + };//cep + txtEndereco = AddInput(content, "Logradouro", 110, y, 260, inputH); + txtEndNumero = AddInput(content, "Nº", 380, y, 70, inputH); + txtBairro = AddInput(content, "Bairro", 460, y, 150, inputH); + txtCidade = AddInput(content, "Cidade", 620, y, 150, inputH); + txtUF = AddInput(content, "UF", 780, y, 60, inputH); + + // ── 4. DADOS BANCÁRIOS ──────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("DADOS BANCÁRIOS", y)); + y += secH + 4; + + //txtBanco = AddInput(content, "Banco", 20, y, 280, inputH); + cbBanco = AddComboBox(content, "Banco", 20, y, 200, inputH); + txtAgencia = AddInput(content, "Agência", 310, y, 160, inputH); + txtConta = AddInput(content, "Conta", 480, y, 160, inputH); + + // ── 5. CONTATO ──────────────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("CONTATO", y)); + y += secH + 4; + + txtTelefone = AddInput(content, "Telefone", 20, y, 200, inputH); + + // ── 6. ACESSO AO SISTEMA ────────────────────────────────────────── + y += rowH + secGap; + content.Controls.Add(CreateSectionHeader("ACESSO AO SISTEMA", y)); + y += secH + 4; + + txtPass = AddInput(content, "Senha", 20, y, 200, inputH); + txtPass.PasswordChar = '*'; + y += rowH; + + chkMasterUser = CreateCheckBox("Master User", 20, y); + chkVendedor = CreateCheckBox("Vendedor", 160, y); + chkTecnico = CreateCheckBox("Técnico", 290, y); + chkOutros = CreateCheckBox("Outros", 420, y); + chkContador = CreateCheckBox("Contador", 560, y); + chkDemitido = CreateCheckBox("Demitido", 690, y); + + content.Controls.AddRange(new Control[] + { chkMasterUser, chkVendedor, chkTecnico, chkOutros, chkContador, chkDemitido }); + + // ── 7. OUTROS ───────────────────────────────────────────────────── + y += 35 + secGap; + content.Controls.Add(CreateSectionHeader("OUTROS", y)); + y += secH + 4; + + // Label da foto + var lblFoto = new Label + { + Text = "Caminho da Foto (FPATH)", + Location = new Point(20, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + content.Controls.Add(lblFoto); + + // Campo de texto da foto (menor para dar espaço ao botão lupa) + txtFPath = new RoundTextBox + { + Location = new Point(20, y + 16), + Size = new Size(560, inputH), + Radius = 4, + BorderColor = BorderColor, + FocusColor = AccentBlue, + BackColor = Color.White + }; + content.Controls.Add(txtFPath); + + // Botão lupa 🔍 + var btnFoto = new Button + { + Text = "🔍", + Location = new Point(588, y + 16), + Size = new Size(36, inputH), + FlatStyle = FlatStyle.Flat, + BackColor = Color.FromArgb(37, 99, 235), + ForeColor = Color.White, + Font = new Font("Segoe UI", 11f), + Cursor = Cursors.Hand, + TabStop = false + }; + btnFoto.FlatAppearance.BorderSize = 0; + btnFoto.Click += (s, e) => BtnFoto_Click(); + content.Controls.Add(btnFoto); + + y += rowH; + + txtObserv = AddInput(content, "Observações", 20, y, 920, inputH); + txtObserv.Multiline = true; + txtObserv.Height = 60; + + // ── 8. DATAS ────────────────────────────────────────────────────── + y += 70 + secGap; + content.Controls.Add(CreateSectionHeader("DATAS", y)); + y += secH + 4; + + txtDataAdm = AddInput(content, "Data de Admissão", 20, y, 175, inputH); + txtDataDem = AddInput(content, "Data de Demissão", 205, y, 175, inputH); + txtAniver = AddInput(content, "Aniversário", 390, y, 175, inputH); + y += rowH; + + content.Height = y + 10; + + //SetCampos(false); + SetCamposAtulizado(false); + } + + // ── FOTO: LUPA ──────────────────────────────────────────────────────── + + private void BtnFoto_Click() + { + using var dlg = new FotoOrigemDialog(); + if (dlg.ShowDialog() != DialogResult.OK) return; + + string? caminhoSalvo = dlg.UsarWebcam + ? CapturarDaWebcam() + : SelecionarDoComputador(); + + if (!string.IsNullOrEmpty(caminhoSalvo)) + txtFPath.Text = caminhoSalvo; + } + + private string? SelecionarDoComputador() + { + using var ofd = new OpenFileDialog + { + Title = "Selecionar Foto do Funcionário", + Filter = "Imagens|*.jpg;*.jpeg;*.png;*.bmp|Todos os arquivos|*.*" + }; + + if (ofd.ShowDialog() != DialogResult.OK) return null; + + return SalvarFoto(ofd.FileName); + } + + private string? CapturarDaWebcam() + { + using var webcamForm = new WebcamCaptureForm(); + if (webcamForm.ShowDialog() != DialogResult.OK) return null; + if (webcamForm.ImagemCapturada == null) return null; + + string temp = Path.Combine(Path.GetTempPath(), $"webcam_{Guid.NewGuid()}.jpg"); + webcamForm.ImagemCapturada.Save(temp, ImageFormat.Jpeg); + return SalvarFoto(temp); + } + + private string SalvarFoto(string origem) + { + const string pasta = @"C:\Levelcode\LevelOS\Uploads\Images\Funcionarios"; + Directory.CreateDirectory(pasta); + + // Nome: NomeFuncionario_yyyyMMdd_HHmmss.jpg + string nomeBase = string.IsNullOrWhiteSpace(txtNome.Text) + ? "Funcionario" + : txtNome.Text.Trim().Replace(" ", "_"); + + string nomeArq = $"{nomeBase}_{DateTime.Now:yyyyMMdd_HHmmss}.jpg"; + string destino = Path.Combine(pasta, nomeArq); + + File.Copy(origem, destino, overwrite: true); + return destino; + } + + // ── CAMPOS ──────────────────────────────────────────────────────────── + + private RoundTextBox[] TodosOsCampos() => new[] + { + txtCodigo, txtNome, + txtCPF, txtCI, txtCTPS, txtCNH, txtCatCNH, + txtECivil, txtRegime, + txtPai, txtMae, + txtcep,txtEndereco,txtEndNumero, txtBairro, txtCidade, txtUF, + /*txtBanco,*/ txtAgencia, txtConta, + txtTelefone, + txtPass, + txtFPath, txtObserv, + txtDataAdm, txtDataDem, txtAniver + }; + + private CheckBox[] TodosOsChecks() => new[] + { + chkMasterUser, chkVendedor, chkTecnico, + chkDemitido, chkContador, chkOutros + }; + + private void SetCampos(bool enabled) + { + foreach (var campo in TodosOsCampos()) + { + campo.Enabled = enabled; + campo.BackColor = enabled ? Color.White : Color.FromArgb(241, 245, 249); + } + foreach (var chk in TodosOsChecks()) + chk.Enabled = enabled; + } + + // ── EVENTOS ─────────────────────────────────────────────────────────── + + private void BtnNovo_Click() + { + foreach (var campo in TodosOsCampos()) + campo.Text = string.Empty; + + foreach (var chk in TodosOsChecks()) + chk.Checked = false; + + //SetCampos(true); + SetCamposAtulizado(true); + } + + private void BtnAlterar_Click() + { + if (string.IsNullOrWhiteSpace(txtId.Text)) + { + NT_MessageBox.Show( + "Nenhum registro selecionado para alterar.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + //SetCampos(true); + SetCamposAtulizado(true); + txtId.Enabled = false; + txtId.BackColor = Color.FromArgb(241, 245, 249); + } + + private void BtnExcluir_Click() + { + + } + + private void BtnLocalizar_Click() + { + // Abre tela/diálogo de busca e preenche os campos + } + + private void BtnSalvar_Click() + { + var bll = new BLLFuncionarios(_cx); + + if (string.IsNullOrWhiteSpace(txtNome.Text) || + string.IsNullOrWhiteSpace(txtCPF.Text)) + { + NT_MessageBox.Show("Preencha ao menos Nome e CPF.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + bool isNew = string.IsNullOrWhiteSpace(txtId.Text); + + var funcionario = new ModeloFuncionarios + { + ID_FUNCIONARIO = isNew ? 0 : int.Parse(txtId.Text), + + CODIGO = txtCodigo.Text, + NOME = txtNome.Text, + PAI = txtPai.Text, + MAE = txtMae.Text, + CPF = txtCPF.Text, + CI = txtCI.Text, + CTPS = txtCTPS.Text, + CNH = txtCNH.Text, + CAT_CNH = txtCatCNH.Text, + ECIVIL = txtECivil.Text, + REGIME = txtRegime.Text, + + CEP = txtcep.Text, + ENDERECO = txtEndereco.Text, + ENDNUMERO = txtEndNumero.Text, + BAIRRO = txtBairro.Text, + CIDADE = txtCidade.Text, + UF = txtUF.Text, + + // 🔥 BANCO vindo do ComboBox + BANCO = cbBanco.SelectedValue?.ToString(), + + AGENCIA = txtAgencia.Text, + CONTA = txtConta.Text, + TELEFONE = txtTelefone.Text, + PASS = txtPass.Text, + + // 🔥 BOOL correto + MASTERUSER = chkMasterUser.Checked, + VENDEDOR = chkVendedor.Checked, + TECNICO = chkTecnico.Checked, + DEMITIDO = chkDemitido.Checked, + + FTECNICO = chkContador.Checked ? "1" : null, + FVENDEDOR = chkOutros.Checked ? "1" : null, + + FPATH = txtFPath.Text, + OBSERV = txtObserv.Text, + + // 🔥 DATAS + DATA_ADM = ConverterData(txtDataAdm.Text), + DATA_DEM = ConverterData(txtDataDem.Text), + ANIVER = ConverterData(txtAniver.Text) + }; + + bool sucesso = isNew + ? bll.Inserir(funcionario) + : bll.Alterar(funcionario); + + if (!sucesso) + { + NT_MessageBox.Show("Erro ao salvar funcionário.", + "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + SetCampos(false); + + NT_MessageBox.Show("Funcionário salvo com sucesso!", "Sucesso", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void BtnFichaFuncionario_Click() + { + var bll = new BLLFuncionarios(_cx); + + var funcionario = bll.CarregarPorCodigo("100"); + + if (funcionario == null) + { + MessageBox.Show("Funcionário não encontrado."); + return; + } + + var resultado = TLL.FichaFuncionarioPDF.GerarEAbrir(funcionario); + + if (!resultado.Sucesso) + MessageBox.Show(resultado.Mensagem, "Erro", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private void BtnCancelar_Click() + { + foreach (var campo in TodosOsCampos()) + campo.Text = string.Empty; + + foreach (var chk in TodosOsChecks()) + chk.Checked = false; + + //SetCampos(false); + SetCamposAtulizado(false); + //this.cbBanco.Enabled = false; + + } + + // ── HELPERS ─────────────────────────────────────────────────────────── + + private Panel CreateSectionHeader(string title, int y) + { + var pnl = new Panel { Location = new Point(20, y), Width = 1000, Height = 26 }; + var lbl = new Label + { + Text = title, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = AccentBlue, + AutoSize = true, + Location = new Point(0, 0) + }; + var line = new Panel + { + BackColor = BorderColor, + Height = 1, + Width = 980, + Location = new Point(0, 20) + }; + pnl.Controls.Add(lbl); + pnl.Controls.Add(line); + return pnl; + } + + private RoundTextBox AddInput(Control parent, string label, + int x, int y, int width, int height, + bool readOnly = false) + { + var lbl = new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = readOnly ? Color.Gray : TextDark, + AutoSize = true + }; + var txt = new RoundTextBox + { + Location = new Point(x, y + 16), + Size = new Size(width, height), + Radius = 4, + BorderColor = readOnly ? Color.FromArgb(203, 213, 225) : BorderColor, + FocusColor = AccentBlue, + ReadOnly = readOnly, + BackColor = readOnly ? Color.FromArgb(241, 245, 249) : Color.White + }; + parent.Controls.Add(lbl); + parent.Controls.Add(txt); + return txt; + } + private RoundComboBox AddComboBox(Control parent, string label, + int x, int y, int width, int height) + { + var lbl = new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + var cb = new RoundComboBox + { + Location = new Point(x, y + 16), + Size = new Size(width, height), + Radius = 4, + BorderColor = BorderColor, + FocusColor = AccentBlue, + BackColor = Color.White + }; + parent.Controls.Add(lbl); + parent.Controls.Add(cb); + return cb; + } + + private CheckBox CreateCheckBox(string text, int x, int y) => new CheckBox + { + Text = text, + Location = new Point(x, y), + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }; + + private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton + { + Text = text, + Size = new Size(95, 32), + BackColor = color, + ForeColor = Color.White, + Font = new Font("Segoe UI Semibold", 8.5f), + Margin = new Padding(0, 0, 6, 0), + Cursor = Cursors.Hand + }; + } + + // ══════════════════════════════════════════════════════════════════════════ + // DIALOG: Escolher origem da foto (Computador ou Webcam) + // ══════════════════════════════════════════════════════════════════════════ + + public class FotoOrigemDialog : Form + { + public bool UsarWebcam { get; private set; } + + public FotoOrigemDialog() + { + Text = "Selecionar Foto"; + Size = new Size(340, 160); + StartPosition = FormStartPosition.CenterParent; + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + BackColor = Color.White; + + var lbl = new Label + { + Text = "Como deseja adicionar a foto?", + Font = new Font("Segoe UI", 9.5f), + Location = new Point(20, 18), + AutoSize = true + }; + + var btnComputador = new Button + { + Text = "📁 Do Computador", + Location = new Point(20, 55), + Size = new Size(140, 38), + FlatStyle = FlatStyle.Flat, + BackColor = Color.FromArgb(37, 99, 235), + ForeColor = Color.White, + Font = new Font("Segoe UI", 9f), + Cursor = Cursors.Hand + }; + btnComputador.FlatAppearance.BorderSize = 0; + btnComputador.Click += (s, e) => + { + UsarWebcam = false; + DialogResult = DialogResult.OK; + Close(); + }; + + var btnWebcam = new Button + { + Text = "📷 Webcam", + Location = new Point(172, 55), + Size = new Size(140, 38), + FlatStyle = FlatStyle.Flat, + BackColor = Color.FromArgb(16, 185, 129), + ForeColor = Color.White, + Font = new Font("Segoe UI", 9f), + Cursor = Cursors.Hand + }; + btnWebcam.FlatAppearance.BorderSize = 0; + btnWebcam.Click += (s, e) => + { + UsarWebcam = true; + DialogResult = DialogResult.OK; + Close(); + }; + + Controls.AddRange(new Control[] { lbl, btnComputador, btnWebcam }); + } + } + + // ══════════════════════════════════════════════════════════════════════════ + // FORM: Captura pela Webcam usando AForge + // ══════════════════════════════════════════════════════════════════════════ + + public class WebcamCaptureForm : Form + { + public Bitmap? ImagemCapturada { get; private set; } + + private PictureBox picPreview = null!; + private VideoCaptureDevice? _camera; + private Bitmap? _frameAtual; + + public WebcamCaptureForm() + { + Text = "Capturar Foto pela Webcam"; + Size = new Size(680, 560); + StartPosition = FormStartPosition.CenterParent; + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + BackColor = Color.FromArgb(15, 23, 42); + + picPreview = new PictureBox + { + Location = new Point(20, 20), + Size = new Size(628, 440), + SizeMode = PictureBoxSizeMode.Zoom, + BackColor = Color.Black + }; + Controls.Add(picPreview); + + var btnCapturar = new Button + { + Text = "📷 Capturar", + Location = new Point(20, 475), + Size = new Size(200, 38), + FlatStyle = FlatStyle.Flat, + BackColor = Color.FromArgb(37, 99, 235), + ForeColor = Color.White, + Font = new Font("Segoe UI", 9.5f), + Cursor = Cursors.Hand + }; + btnCapturar.FlatAppearance.BorderSize = 0; + btnCapturar.Click += BtnCapturar_Click; + Controls.Add(btnCapturar); + + var btnCancelar = new Button + { + Text = "Cancelar", + Location = new Point(234, 475), + Size = new Size(120, 38), + FlatStyle = FlatStyle.Flat, + BackColor = Color.FromArgb(100, 116, 139), + ForeColor = Color.White, + Font = new Font("Segoe UI", 9.5f), + Cursor = Cursors.Hand + }; + btnCancelar.FlatAppearance.BorderSize = 0; + btnCancelar.Click += (s, e) => { PararCamera(); DialogResult = DialogResult.Cancel; Close(); }; + Controls.Add(btnCancelar); + + FormClosing += (s, e) => PararCamera(); + + IniciarCamera(); + } + + private void IniciarCamera() + { + var cameras = new FilterInfoCollection(FilterCategory.VideoInputDevice); + + if (cameras.Count == 0) + { + MessageBox.Show("Nenhuma webcam encontrada.", "Webcam", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + DialogResult = DialogResult.Cancel; + Close(); + return; + } + + _camera = new VideoCaptureDevice(cameras[0].MonikerString); + _camera.NewFrame += Camera_NewFrame; + _camera.Start(); + } + + private void Camera_NewFrame(object sender, NewFrameEventArgs e) + { + _frameAtual?.Dispose(); + _frameAtual = (Bitmap)e.Frame.Clone(); + + picPreview.Invoke((MethodInvoker)(() => + { + picPreview.Image?.Dispose(); + picPreview.Image = (Bitmap)_frameAtual.Clone(); + })); + } + + private void BtnCapturar_Click(object? sender, EventArgs e) + { + if (_frameAtual == null) + { + MessageBox.Show("Aguarde a câmera inicializar.", "Atenção", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + ImagemCapturada = (Bitmap)_frameAtual.Clone(); + PararCamera(); + DialogResult = DialogResult.OK; + Close(); + } + + private void PararCamera() + { + if (_camera != null && _camera.IsRunning) + { + _camera.SignalToStop(); + _camera.WaitForStop(); + } + } + } +} diff --git a/Dashboards/Cadastros/FuncionariosCadastroPanel.resx b/Dashboards/Cadastros/FuncionariosCadastroPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Cadastros/FuncionariosCadastroPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Configurações/Database/FrmConfigBanco.cs b/Dashboards/Configurações/Database/FrmConfigBanco.cs new file mode 100644 index 0000000..6914ab6 --- /dev/null +++ b/Dashboards/Configurações/Database/FrmConfigBanco.cs @@ -0,0 +1,338 @@ +using CCH; +using CustomMessageBox; +using DAL; +using Microsoft.Data.SqlClient; // Certifique-se de ter este pacote NuGet instalado +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using TLL; + +namespace UI +{ + public class FrmConfigBanco : Form + { + // ── Cores LevelOS ────────────────────────────────────────────────── + private static readonly Color Surface = Color.White; + private static readonly Color Surface2 = Color.FromArgb(241, 245, 249); + private static readonly Color BorderCol = Color.FromArgb(226, 232, 240); + private static readonly Color TextPri = Color.FromArgb(15, 23, 42); + private static readonly Color TextSec = Color.FromArgb(71, 85, 105); + private static readonly Color TextMuted = Color.FromArgb(148, 163, 184); + private static readonly Color Blue = Color.FromArgb(37, 99, 235); + private static readonly Color Green = Color.FromArgb(22, 163, 74); + private static readonly Color Red = Color.FromArgb(220, 38, 38); + private static readonly Color NavyDark = Color.FromArgb(15, 30, 60); + + // ── Controles ────────────────────────────────────────────────────── + private readonly TextBox txtHost = new(); + private readonly TextBox txtPort = new(); + private readonly TextBox txtBanco = new(); + private readonly TextBox txtUsuario = new(); + private readonly TextBox txtSenha = new(); + private readonly TextBox txtTimeout = new(); + private readonly CheckBox chkEncrypt = new(); + private readonly CheckBox chkTrust = new(); + private readonly Button btnSalvar = new(); + private readonly Button btnTestar = new(); + private readonly Button btnCancelar = new(); + private readonly Label lblStatus = new(); + + public FrmConfigBanco() + { + Text = "LevelOS — Configuração do Banco de Dados"; + Size = new Size(660, 680); + StartPosition = FormStartPosition.CenterScreen; + BackColor = Surface2; + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + + BuildLayout(); + CarregarValores(); + + // ── Eventos ────────────────────────────────────────────────── + btnSalvar.Click += BtnSalvar_Click; + btnTestar.Click += BtnTestar_Click; + btnCancelar.Click += (s, e) => Close(); + + //Carregar dados + if (!File.Exists(AppFileSystem.AppFileDBSystem)) + { + NT_MessageBox.Show("Arquivo de configuração do banco de dados ausente, por favor contacte o administrador do sistema para solucionar o problema", "Erro de SQL:101", + MessageBoxButtons.OK,MessageBoxIcon.Error); + } + else + { + DatabaseHelper.Carregar(AppFileSystem.AppFileDBSystem, AppInfoSystem.AppKeyMasterCrip); + this.txtHost.Text = DadosDaConexao.Host; + this.txtPort.Text = DadosDaConexao.Port.ToString(); + this.txtBanco.Text = DadosDaConexao.Banco; + this.txtUsuario.Text = DadosDaConexao.Usuario; + this.txtSenha.Text = DadosDaConexao.Senha; + this.chkEncrypt.Checked = DadosDaConexao.Encrypt; + this.txtTimeout.Text = DadosDaConexao.ConnectTimeout.ToString(); + this.chkTrust.Checked = DadosDaConexao.TrustServerCertificate; + } + } + + private void BuildLayout() + { + // 1. TOPBAR + var topbar = new Panel { Dock = DockStyle.Top, Height = 75, BackColor = NavyDark }; + topbar.Paint += DrawTopbar; + Controls.Add(topbar); + + // 2. RODAPÉ + var footer = new Panel { Dock = DockStyle.Bottom, Height = 65, BackColor = Surface }; + footer.Paint += (s, e) => e.Graphics.DrawLine(new Pen(BorderCol), 0, 0, footer.Width, 0); + Controls.Add(footer); + + StyleButton(btnCancelar, "Cancelar", Surface, TextSec, BorderCol); + btnCancelar.SetBounds(20, 15, 100, 35); + btnCancelar.Anchor = AnchorStyles.Left; + footer.Controls.Add(btnCancelar); + + StyleButton(btnSalvar, "✔ Salvar", Blue, Color.White); + btnSalvar.SetBounds(footer.Width - 120, 15, 100, 35); + btnSalvar.Anchor = AnchorStyles.Right; + footer.Controls.Add(btnSalvar); + + StyleButton(btnTestar, "Testar conexão", Surface, TextPri, BorderCol); + btnTestar.SetBounds(btnSalvar.Left - 145, 15, 135, 35); + btnTestar.Anchor = AnchorStyles.Right; + footer.Controls.Add(btnTestar); + + lblStatus.SetBounds(130, 15, 250, 35); + lblStatus.TextAlign = ContentAlignment.MiddleLeft; + lblStatus.Font = new Font("Segoe UI", 9f); + lblStatus.Anchor = AnchorStyles.Left | AnchorStyles.Right; + footer.Controls.Add(lblStatus); + + // 3. CONTAINER DE CONTEÚDO + var pnlContainer = new Panel { Dock = DockStyle.Fill, AutoScroll = true, Padding = new Padding(0, 10, 0, 20) }; + Controls.Add(pnlContainer); + pnlContainer.BringToFront(); + + // 4. CARD BRANCO + var card = new Panel { BackColor = Surface, Width = 560, Left = 40, Top = 20 }; + pnlContainer.Controls.Add(card); + + int cy = 30; + + cy = AddSection(card, "SERVIDOR", cy); + AddLabel(card, "Host / IP", 30, cy); + AddLabel(card, "Porta", 430, cy); + cy += 20; + StyleInput(txtHost, "ex: localhost ou 192.168.0.1"); + txtHost.SetBounds(30, cy, 385, 30); card.Controls.Add(txtHost); + StyleInput(txtPort, "1433"); + txtPort.SetBounds(430, cy, 100, 30); card.Controls.Add(txtPort); + cy += 45; + + cy = AddSection(card, "BANCO DE DADOS", cy); + AddLabel(card, "Nome do Banco", 30, cy); + cy += 20; + StyleInput(txtBanco, "ex: LevelOS_DB"); + txtBanco.SetBounds(30, cy, 500, 30); card.Controls.Add(txtBanco); + cy += 45; + + cy = AddSection(card, "AUTENTICAÇÃO", cy); + AddLabel(card, "Usuário", 30, cy); + AddLabel(card, "Senha", 285, cy); + cy += 20; + StyleInput(txtUsuario, "sa"); + txtUsuario.SetBounds(30, cy, 245, 30); card.Controls.Add(txtUsuario); + StyleInput(txtSenha, "••••••••"); + txtSenha.SetBounds(285, cy, 245, 30); txtSenha.PasswordChar = '●'; card.Controls.Add(txtSenha); + cy += 45; + + cy = AddSection(card, "AVANÇADO", cy); + AddLabel(card, "Timeout de conexão (segundos)", 30, cy); + cy += 20; + StyleInput(txtTimeout, "3"); + txtTimeout.SetBounds(30, cy, 100, 30); card.Controls.Add(txtTimeout); + cy += 40; + + StyleCheckbox(chkEncrypt, "Encrypt Connection"); + chkEncrypt.SetBounds(30, cy, 250, 25); card.Controls.Add(chkEncrypt); + cy += 30; + StyleCheckbox(chkTrust, "Trust Server Certificate"); + chkTrust.SetBounds(30, cy, 250, 25); card.Controls.Add(chkTrust); + cy += 40; + + card.Height = cy; + } + + // ── Lógica de Negócio ────────────────────────────────────────────── + + private void CarregarValores() + { + txtHost.Text = DbConfig.Host; + txtPort.Text = DbConfig.Port.ToString(); + txtBanco.Text = DbConfig.Banco; + txtUsuario.Text = DbConfig.Usuario; + txtSenha.Text = DbConfig.Senha; + txtTimeout.Text = DbConfig.ConnectTimeout.ToString(); + chkEncrypt.Checked = DbConfig.Encrypt; + chkTrust.Checked = DbConfig.TrustServerCertificate; + } + + private void BtnSalvar_Click(object? sender, EventArgs e) + { + if (!Validar()) return; + + DbConfig.Host = txtHost.Text.Trim(); + DbConfig.Port = int.TryParse(txtPort.Text, out int p) ? p : 1433; + DbConfig.Banco = txtBanco.Text.Trim(); + DbConfig.Usuario = txtUsuario.Text.Trim(); + DbConfig.Senha = txtSenha.Text; + DbConfig.ConnectTimeout = int.TryParse(txtTimeout.Text, out int t) ? t : 3; + DbConfig.Encrypt = chkEncrypt.Checked; + DbConfig.TrustServerCertificate = chkTrust.Checked; + + //Preenchendo dados da conexao + DadosDaConexao.Host = DbConfig.Host; + DadosDaConexao.Port = DbConfig.Port; + DadosDaConexao.Banco =DbConfig.Banco; + DadosDaConexao.Usuario = DbConfig.Usuario; + DadosDaConexao.Senha = DbConfig.Senha; + DadosDaConexao.ConnectTimeout = DbConfig.ConnectTimeout; + DadosDaConexao.Encrypt = chkEncrypt.Checked; + DadosDaConexao.TrustServerCertificate = chkTrust.Checked; + //salvar em arquivo criptografado + DatabaseHelper.Salvar(AppFileSystem.AppFileDBSystem, AppInfoSystem.AppKeyMasterCrip); + + + SetStatus("✔ Configurações salvas!", Green); + } + + private void BtnTestar_Click(object? sender, EventArgs e) + { + if (!Validar()) return; + + SetStatus("⏳ Testando...", TextMuted); + btnTestar.Enabled = false; + Application.DoEvents(); // Força a interface a atualizar o status + + try + { + using var conn = new SqlConnection(BuildConnStr()); + conn.Open(); + SetStatus($"✔ Conectado! SQL {conn.ServerVersion}", Green); + } + catch (Exception ex) + { + SetStatus($"✖ Erro: {ex.Message}", Red); + } + finally + { + btnTestar.Enabled = true; + } + } + + private string BuildConnStr() + { + SqlConnectionStringBuilder builder = new() + { + DataSource = $"{txtHost.Text.Trim()},{txtPort.Text.Trim()}", + InitialCatalog = txtBanco.Text.Trim(), + UserID = txtUsuario.Text.Trim(), + Password = txtSenha.Text, + ConnectTimeout = int.TryParse(txtTimeout.Text, out int t) ? t : 3, + Encrypt = chkEncrypt.Checked, + TrustServerCertificate = chkTrust.Checked + }; + return builder.ConnectionString; + } + + private bool Validar() + { + if (string.IsNullOrWhiteSpace(txtHost.Text)) { SetStatus("✖ Informe o Host.", Red); txtHost.Focus(); return false; } + if (string.IsNullOrWhiteSpace(txtBanco.Text)) { SetStatus("✖ Informe o Banco.", Red); txtBanco.Focus(); return false; } + if (string.IsNullOrWhiteSpace(txtUsuario.Text)) { SetStatus("✖ Informe o Usuário.", Red); txtUsuario.Focus(); return false; } + return true; + } + + private void SetStatus(string msg, Color color) + { + lblStatus.Text = msg; + lblStatus.ForeColor = color; + } + + // ── Helpers de UI ────────────────────────────────────────────────── + + private void DrawTopbar(object sender, PaintEventArgs e) + { + var g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + var rect = new Rectangle(25, 20, 34, 34); + using var path = RoundRectPath(rect, 8); + g.FillPath(new SolidBrush(Blue), path); + g.DrawString("S", new Font("Segoe UI", 14, FontStyle.Bold), Brushes.White, rect, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); + g.DrawString("Configuração do Banco", new Font("Segoe UI Semibold", 12.5f), Brushes.White, 70, 18); + g.DrawString("Defina os parâmetros de conexão com o SQL Server", new Font("Segoe UI", 9), new SolidBrush(Color.FromArgb(148, 163, 184)), 70, 40); + } + + private int AddSection(Panel p, string title, int y) + { + var line = new Panel { BackColor = BorderCol, Height = 1, Width = p.Width - 60, Left = 30, Top = y }; + p.Controls.Add(line); + var lbl = new Label { Text = title, Font = new Font("Segoe UI", 7, FontStyle.Bold), ForeColor = TextMuted, Top = y - 7, Left = 35, AutoSize = true, BackColor = Surface }; + p.Controls.Add(lbl); + lbl.BringToFront(); + return y + 20; + } + + private void AddLabel(Panel p, string txt, int x, int y) + { + p.Controls.Add(new Label { Text = txt, Font = new Font("Segoe UI Semibold", 9), ForeColor = TextSec, Left = x, Top = y, AutoSize = true }); + } + + private void StyleInput(TextBox t, string placeholder) + { + t.BorderStyle = BorderStyle.FixedSingle; + t.Font = new Font("Segoe UI", 10); + t.PlaceholderText = placeholder; + t.BackColor = Color.FromArgb(250, 251, 253); + } + + private void StyleCheckbox(CheckBox chk, string text) + { + chk.Text = text; chk.Font = new Font("Segoe UI", 9.5f); + chk.ForeColor = TextSec; chk.Cursor = Cursors.Hand; + } + + private void StyleButton(Button b, string txt, Color bg, Color fg, Color? borda = null) + { + b.Text = txt; b.FlatStyle = FlatStyle.Flat; b.BackColor = bg; b.ForeColor = fg; b.Cursor = Cursors.Hand; + b.Font = new Font("Segoe UI Semibold", 9.5f); + b.FlatAppearance.BorderSize = borda.HasValue ? 1 : 0; + if (borda.HasValue) b.FlatAppearance.BorderColor = borda.Value; + } + + private static GraphicsPath RoundRectPath(Rectangle r, int radius) + { + var path = new GraphicsPath(); + int d = radius * 2; + path.AddArc(r.X, r.Y, d, d, 180, 90); + path.AddArc(r.Right - d, r.Y, d, d, 270, 90); + path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90); + path.AddArc(r.X, r.Bottom - d, d, d, 90, 90); + path.CloseFigure(); + return path; + } + } + + // ── Dados (DbConfig) ────────────────────────────────────────────────── + public static class DbConfig + { + public static string Host { get; set; } = "localhost"; + public static int Port { get; set; } = 1433; + public static string Banco { get; set; } = ""; + public static string Usuario { get; set; } = "sa"; + public static string Senha { get; set; } = ""; + public static int ConnectTimeout { get; set; } = 3; + public static bool Encrypt { get; set; } = true; + public static bool TrustServerCertificate { get; set; } = true; + } +} \ No newline at end of file diff --git a/Dashboards/Configurações/Database/FrmConfigBanco.resx b/Dashboards/Configurações/Database/FrmConfigBanco.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Configurações/Database/FrmConfigBanco.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Consultas/AgendaConsultaPanel.cs b/Dashboards/Consultas/AgendaConsultaPanel.cs new file mode 100644 index 0000000..b1d23fb --- /dev/null +++ b/Dashboards/Consultas/AgendaConsultaPanel.cs @@ -0,0 +1,431 @@ +using BLL; +using DAL; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace UI +{ + public class AgendaConsultaPanel : UserControl + { + // ── CORES ───────────────────────────────────────────────────────────── + private readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private readonly Color TextDark = Color.FromArgb(30, 41, 59); + private readonly Color BorderColor = Color.FromArgb(226, 232, 240); + private readonly Color GreenColor = Color.FromArgb(34, 197, 94); + private readonly Color MutedGray = Color.FromArgb(148, 163, 184); + private readonly Color SurfaceColor = Color.FromArgb(248, 250, 252); + + // ── CONTROLES ───────────────────────────────────────────────────────── + private Panel pnlToolbar = null!; + private Panel pnlFiltros = null!; + private Panel pnlRodape = null!; + private DataGridView dgvAgenda = null!; + private Label lblTotal = null!; + + // ── FILTROS ─────────────────────────────────────────────────────────── + private RoundTextBox txtFiltroCompromisso = null!; + private RoundTextBox txtFiltroFunc = null!; + private RoundTextBox txtFiltroOsVinc = null!; + private RoundTextBox txtDataInicio = null!; + private RoundTextBox txtDataFim = null!; + private ComboBox cmbSituacao = null!; + + // ── DADOS ───────────────────────────────────────────────────────────── + private List _todos = new(); + private List _filtrados = new(); + + // ── EVENTO: abre cadastro com o registro selecionado ────────────────── + public event Action? OnAbrirCadastro; + + //Carrega a string conexao com o banco de dados, para ser usada no repositório + private string _conexao = DadosDaConexao.ObterConexao(); + + // ── CONSTRUTOR ──────────────────────────────────────────────────────── + public AgendaConsultaPanel() + { + Dock = DockStyle.Fill; + BackColor = Color.White; + DoubleBuffered = true; + + InitializeLayout(); + //CarregarDadosFake(); + CarregarDadosDoBanco(); + AplicarFiltros(); + } + + // ══════════════════════════════════════════════════════════════════════ + // LAYOUT + // + // REGRA WINFORMS — ordem de adição ao Controls é INVERSA à exibição: + // 1º adicionar → Fill (ocupa o centro) + // 2º adicionar → Bottom + // 3º adicionar → Top (empurra o Fill para baixo; último = mais alto) + // + // ══════════════════════════════════════════════════════════════════════ + private void InitializeLayout() + { + Controls.Clear(); + + // ── 1º: GRID (Fill) ─────────────────────────────────────────────── + BuildGrid(); + Controls.Add(dgvAgenda); + + // ── 2º: RODAPÉ (Bottom) ─────────────────────────────────────────── + pnlRodape = new Panel + { + Dock = DockStyle.Bottom, + Height = 30, + BackColor = SurfaceColor + }; + lblTotal = new Label + { + AutoSize = true, + Location = new Point(16, 7), + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + ForeColor = MutedGray, + Text = "0 registros encontrados" + }; + pnlRodape.Controls.Add(lblTotal); + Controls.Add(pnlRodape); + + // ── 3º: FILTROS (Top) ───────────────────────────────────────────── + pnlFiltros = new Panel + { + Dock = DockStyle.Top, + Height = 95, + BackColor = SurfaceColor, + Padding = new Padding(16, 8, 16, 8) + }; + BuildFiltros(); + Controls.Add(pnlFiltros); + + // ── 4º: TOOLBAR (Top) — por último = fica acima dos filtros ─────── + pnlToolbar = new Panel + { + Dock = DockStyle.Top, + Height = 55, + BackColor = SurfaceColor + }; + + var flow = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + Padding = new Padding(12, 10, 0, 0), + BackColor = Color.Transparent + }; + + var btnPesquisar = CreateToolbarButton("Pesquisar", AccentBlue); + var btnLimpar = CreateToolbarButton("Limpar", MutedGray); + var btnAbrir = CreateToolbarButton("Abrir", GreenColor); + var btnExportar = CreateToolbarButton("Exportar", Color.FromArgb(99, 102, 241)); + + btnPesquisar.Click += (_, _) => AplicarFiltros(); + btnLimpar.Click += (_, _) => LimparFiltros(); + btnAbrir.Click += (_, _) => AbrirRegistroSelecionado(); + btnExportar.Click += (_, _) => ExportarCSV(); + + flow.Controls.AddRange(new Control[] { btnPesquisar, btnLimpar, btnAbrir, btnExportar }); + pnlToolbar.Controls.Add(flow); + Controls.Add(pnlToolbar); // ← último Top = aparece no topo + } + + // ── FILTROS ─────────────────────────────────────────────────────────── + private void BuildFiltros() + { + // Linha 1 + txtFiltroCompromisso = AddFiltroInput(pnlFiltros, "Compromisso", 0, 8, 260); + txtFiltroFunc = AddFiltroInput(pnlFiltros, "Funcionário", 270, 8, 200); + txtFiltroOsVinc = AddFiltroInput(pnlFiltros, "OS Vinculada", 480, 8, 130); + + // Linha 2 + txtDataInicio = AddFiltroInput(pnlFiltros, "Data Início", 0, 50, 130); + txtDataFim = AddFiltroInput(pnlFiltros, "Data Fim", 140, 50, 130); + + pnlFiltros.Controls.Add(new Label + { + Text = "Situação", + Location = new Point(280, 50), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }); + + cmbSituacao = new ComboBox + { + Location = new Point(280, 66), + Size = new Size(160, 26), + DropDownStyle = ComboBoxStyle.DropDownList, + Font = new Font("Segoe UI", 8.5f), + FlatStyle = FlatStyle.Flat + }; + cmbSituacao.Items.AddRange(new object[] { "Todos", "Pendente", "Realizado" }); + cmbSituacao.SelectedIndex = 0; + pnlFiltros.Controls.Add(cmbSituacao); + + foreach (var txt in new[] { txtFiltroCompromisso, txtFiltroFunc, txtFiltroOsVinc, txtDataInicio, txtDataFim }) + txt.KeyDown += (_, e) => { if (e.KeyCode == Keys.Enter) AplicarFiltros(); }; + } + + private RoundTextBox AddFiltroInput(Control parent, string label, int x, int y, int width) + { + parent.Controls.Add(new Label + { + Text = label, + Location = new Point(x, y), + Font = new Font("Segoe UI", 7.5f, FontStyle.Bold), + ForeColor = TextDark, + AutoSize = true + }); + var txt = new RoundTextBox + { + Location = new Point(x, y + 16), + Size = new Size(width, 26), + Radius = 4, + BorderColor = BorderColor, + FocusColor = AccentBlue, + BackColor = Color.White + }; + parent.Controls.Add(txt); + return txt; + } + + // ── GRID ────────────────────────────────────────────────────────────── + private void BuildGrid() + { + dgvAgenda = new DataGridView + { + Dock = DockStyle.Fill, + BackgroundColor = Color.White, + BorderStyle = BorderStyle.None, + CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal, + ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single, + GridColor = BorderColor, + RowHeadersVisible = false, + AllowUserToAddRows = false, + AllowUserToDeleteRows = false, + ReadOnly = true, + SelectionMode = DataGridViewSelectionMode.FullRowSelect, + MultiSelect = false, + Font = new Font("Segoe UI", 8.5f), + AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, + ColumnHeadersHeight = 36, + ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing, + RowTemplate = { Height = 32 } + }; + + dgvAgenda.ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle + { + BackColor = SurfaceColor, + ForeColor = TextDark, + Font = new Font("Segoe UI", 8.5f, FontStyle.Bold), + Alignment = DataGridViewContentAlignment.MiddleLeft, + Padding = new Padding(8, 0, 0, 0), + SelectionBackColor = SurfaceColor, + SelectionForeColor = TextDark + }; + + dgvAgenda.DefaultCellStyle = new DataGridViewCellStyle + { + ForeColor = TextDark, + BackColor = Color.White, + SelectionBackColor = Color.FromArgb(239, 246, 255), + SelectionForeColor = AccentBlue, + Padding = new Padding(8, 0, 0, 0) + }; + + dgvAgenda.AlternatingRowsDefaultCellStyle = new DataGridViewCellStyle + { + BackColor = SurfaceColor, + SelectionBackColor = Color.FromArgb(239, 246, 255), + SelectionForeColor = AccentBlue + }; + + dgvAgenda.Columns.AddRange(new DataGridViewColumn[] + { + new DataGridViewTextBoxColumn { Name = "colId", HeaderText = "ID", FillWeight = 5 }, + new DataGridViewTextBoxColumn { Name = "colCodigo", HeaderText = "Código", FillWeight = 8 }, + new DataGridViewTextBoxColumn { Name = "colCompromisso", HeaderText = "Compromisso", FillWeight = 26 }, + new DataGridViewTextBoxColumn { Name = "colData", HeaderText = "Data", FillWeight = 10 }, + new DataGridViewTextBoxColumn { Name = "colHora", HeaderText = "Hora", FillWeight = 7 }, + new DataGridViewTextBoxColumn { Name = "colDia", HeaderText = "Dia", FillWeight = 10 }, + new DataGridViewTextBoxColumn { Name = "colFunc", HeaderText = "Funcionário", FillWeight = 16 }, + new DataGridViewTextBoxColumn { Name = "colAvisar", HeaderText = "Avisar", FillWeight = 12 }, + new DataGridViewTextBoxColumn { Name = "colOs", HeaderText = "OS Vinc.", FillWeight = 8 }, + new DataGridViewTextBoxColumn { Name = "colSituacao", HeaderText = "Situação", FillWeight = 10 }, + }); + + dgvAgenda.CellDoubleClick += (_, e) => + { + if (e.RowIndex >= 0) AbrirRegistroSelecionado(); + }; + + dgvAgenda.CellFormatting += (_, e) => + { + if (e.RowIndex < 0 || e.ColumnIndex < 0) return; + if (dgvAgenda.Columns[e.ColumnIndex].Name != "colSituacao") return; + + bool realizado = e.Value?.ToString() == "Realizado"; + e.CellStyle.ForeColor = realizado ? Color.FromArgb(22, 101, 52) : Color.FromArgb(146, 64, 14); + e.CellStyle.Font = new Font("Segoe UI", 8f, FontStyle.Bold); + e.CellStyle.SelectionForeColor = e.CellStyle.ForeColor; + e.FormattingApplied = true; + }; + } + + // ══════════════════════════════════════════════════════════════════════ + // LÓGICA + // ══════════════════════════════════════════════════════════════════════ + private void AplicarFiltros() + { + _filtrados = _todos.ToList(); + + var termComp = txtFiltroCompromisso.Text.Trim().ToLower(); + if (!string.IsNullOrEmpty(termComp)) + _filtrados = _filtrados.Where(e => e.COMPROMISSO?.ToLower().Contains(termComp) == true).ToList(); + + var termFunc = txtFiltroFunc.Text.Trim().ToLower(); + if (!string.IsNullOrEmpty(termFunc)) + _filtrados = _filtrados.Where(e => e.FUNC?.ToLower().Contains(termFunc) == true).ToList(); + + var termOs = txtFiltroOsVinc.Text.Trim().ToLower(); + if (!string.IsNullOrEmpty(termOs)) + _filtrados = _filtrados.Where(e => e.OS_VINC?.ToLower().Contains(termOs) == true).ToList(); + + if (DateTime.TryParseExact(txtDataInicio.Text.Trim(), "dd/MM/yyyy", + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.None, out var dtIni)) + _filtrados = _filtrados.Where(e => ParseData(e.dDATA) >= dtIni).ToList(); + + if (DateTime.TryParseExact(txtDataFim.Text.Trim(), "dd/MM/yyyy", + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.None, out var dtFim)) + _filtrados = _filtrados.Where(e => ParseData(e.dDATA) <= dtFim).ToList(); + + var sit = cmbSituacao.SelectedItem?.ToString(); + if (sit == "Realizado") _filtrados = _filtrados.Where(e => e.REALIZADO?.ToUpper() == "S").ToList(); + else if (sit == "Pendente") _filtrados = _filtrados.Where(e => e.REALIZADO?.ToUpper() != "S").ToList(); + + PreencherGrid(); + } + + private void LimparFiltros() + { + txtFiltroCompromisso.Text = string.Empty; + txtFiltroFunc.Text = string.Empty; + txtFiltroOsVinc.Text = string.Empty; + txtDataInicio.Text = string.Empty; + txtDataFim.Text = string.Empty; + cmbSituacao.SelectedIndex = 0; + AplicarFiltros(); + } + + private void PreencherGrid() + { + dgvAgenda.Rows.Clear(); + + foreach (var ev in _filtrados.OrderBy(e => ParseData(e.dDATA)).ThenBy(e => e.HORA)) + { + dgvAgenda.Rows.Add( + ev.ID_AGENDA, ev.CODIGO, ev.COMPROMISSO, + ev.dDATA, ev.HORA, ev.DIA, ev.FUNC, ev.AVISAR, ev.OS_VINC, + ev.REALIZADO?.ToUpper() == "S" ? "Realizado" : "Pendente" + ); + } + + int total = _filtrados.Count; + lblTotal.Text = total == 1 ? "1 registro encontrado" : $"{total} registros encontrados"; + } + + private void AbrirRegistroSelecionado() + { + if (dgvAgenda.SelectedRows.Count == 0) + { + MessageBox.Show("Selecione um registro na lista.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + var row = dgvAgenda.SelectedRows[0]; + if (row.Cells["colId"].Value is int id) + { + var ev = _filtrados.FirstOrDefault(e => e.ID_AGENDA == id); + if (ev != null) OnAbrirCadastro?.Invoke(ev); + } + } + + private void ExportarCSV() + { + if (!_filtrados.Any()) + { + MessageBox.Show("Nenhum registro para exportar.", + "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + using var dlg = new SaveFileDialog + { + Filter = "CSV (*.csv)|*.csv", + FileName = $"Agenda_{DateTime.Today:yyyyMMdd}.csv" + }; + if (dlg.ShowDialog() != DialogResult.OK) return; + + var sb = new System.Text.StringBuilder(); + sb.AppendLine("ID;Código;Compromisso;Data;Hora;Dia;Funcionário;Avisar;OS Vinculada;Situação"); + foreach (var ev in _filtrados.OrderBy(e => ParseData(e.dDATA)).ThenBy(e => e.HORA)) + sb.AppendLine($"{ev.ID_AGENDA};{ev.CODIGO};{ev.COMPROMISSO};{ev.dDATA};" + + $"{ev.HORA};{ev.DIA};{ev.FUNC};{ev.AVISAR};{ev.OS_VINC};" + + $"{(ev.REALIZADO?.ToUpper() == "S" ? "Realizado" : "Pendente")}"); + + System.IO.File.WriteAllText(dlg.FileName, sb.ToString(), System.Text.Encoding.UTF8); + MessageBox.Show($"Exportado com sucesso!\n{dlg.FileName}", "Exportar", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + // ── DADOS FAKE — substituir pelo repositório ────────────────────────── + private void CarregarDadosFake() + { + var hoje = DateTime.Today; + _todos = new List + { + new(1, "AG001", "Reunião com cliente", hoje.ToString("dd/MM/yyyy"), "30 minutos antes", "Carlos Silva", DiaSemana(hoje), "09:00", "S", "OS-1042"), + new(2, "AG002", "Visita técnica", hoje.ToString("dd/MM/yyyy"), "1 hora antes", "Ana Souza", DiaSemana(hoje), "14:00", "N", "OS-1055"), + new(3, "AG003", "Entrega de equipamento", hoje.AddDays(4).ToString("dd/MM/yyyy"), "1 dia antes", "Pedro Lima", DiaSemana(hoje.AddDays(4)), "10:30", "N", ""), + new(4, "AG004", "Manutenção preventiva", hoje.AddDays(-2).ToString("dd/MM/yyyy"), "30 minutos antes", "Carlos Silva", DiaSemana(hoje.AddDays(-2)), "08:00", "S", "OS-1030"), + new(5, "AG005", "Treinamento equipe", hoje.AddDays(7).ToString("dd/MM/yyyy"), "1 dia antes", "Ana Souza", DiaSemana(hoje.AddDays(7)), "13:00", "N", ""), + }; + }//Carregar dados fakes para ixibição + private void CarregarDadosDoBanco() + { + BLLAgenda _agendaBLL = new BLLAgenda(_conexao); + _todos.Clear(); + _todos.AddRange(_agendaBLL.Listar()); + }//Carregar dados reais do banco de dados usando o repositório + + private static DateTime ParseData(string? value) + { + if (string.IsNullOrWhiteSpace(value)) return DateTime.MinValue; + if (DateTime.TryParseExact(value, "dd/MM/yyyy", + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.None, out var dt)) return dt; + if (DateTime.TryParse(value, out dt)) return dt; + return DateTime.MinValue; + } + + private static string DiaSemana(DateTime d) => + new System.Globalization.CultureInfo("pt-BR").DateTimeFormat.GetDayName(d.DayOfWeek); + + private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton + { + Text = text, + Size = new Size(95, 32), + BackColor = color, + ForeColor = Color.White, + Font = new Font("Segoe UI Semibold", 8.5f), + Margin = new Padding(0, 0, 6, 0), + Cursor = Cursors.Hand + }; + } +} \ No newline at end of file diff --git a/Dashboards/Consultas/AgendaConsultaPanel.resx b/Dashboards/Consultas/AgendaConsultaPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Consultas/AgendaConsultaPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Dashmain/DashboardPanel.cs b/Dashboards/Dashmain/DashboardPanel.cs new file mode 100644 index 0000000..98ca3b9 --- /dev/null +++ b/Dashboards/Dashmain/DashboardPanel.cs @@ -0,0 +1,368 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using System.Globalization; +namespace UI +{ + // ═══════════════════════════════════════════════════════════════════════ + // DashboardPanel — painel principal com KPI cards + tabela de OS + // ═══════════════════════════════════════════════════════════════════════ + public class DashboardPanel : UserControl + { + // ── Paleta ───────────────────────────────────────────────────────── + private static readonly Color Surface = Color.FromArgb(255, 255, 255); + private static readonly Color Surface2 = Color.FromArgb(248, 250, 252); + private static readonly Color Border = Color.FromArgb(226, 232, 240); + private static readonly Color TextPri = Color.FromArgb(15, 23, 42); + private static readonly Color TextSec = Color.FromArgb(71, 85, 105); + private static readonly Color TextMuted = Color.FromArgb(148, 163, 184); + + private static readonly Color Blue = Color.FromArgb(37, 99, 235); + private static readonly Color BlueLight = Color.FromArgb(219, 234, 254); + private static readonly Color Green = Color.FromArgb(22, 163, 74); + private static readonly Color GreenL = Color.FromArgb(220, 252, 231); + private static readonly Color Amber = Color.FromArgb(217, 119, 6); + private static readonly Color AmberL = Color.FromArgb(254, 243, 199); + private static readonly Color Red = Color.FromArgb(220, 38, 38); + private static readonly Color RedL = Color.FromArgb(254, 226, 226); + private static readonly Color Orange = Color.FromArgb(234, 88, 12); + private static readonly Color OrangeL = Color.FromArgb(255, 237, 213); + + // ── Dados de OS ──────────────────────────────────────────────────── + private readonly List _ordens = new() + { + new OsRow("#0001", "João Silva", "Notebook Dell", OsStatus.EmAndamento, "07/04"), + new OsRow("#0002", "Maria Souza", "PC Gamer", OsStatus.Concluida, "07/04"), + new OsRow("#0003", "Carlos Mota", "Impressora HP", OsStatus.Aguardando, "08/04"), + new OsRow("#0004", "Ana Lima", "iPhone 14", OsStatus.EmAndamento, "08/04"), + new OsRow("#0005", "Pedro Rocha", "Monitor LG", OsStatus.Pendente, "09/04"), + }; + + // ── KPI cards ────────────────────────────────────────────────────── + // CORRIGIDO: instanciação posicional explícita (sem parâmetros nomeados) + private readonly KpiCard[] _kpis; + + // ── Layout ───────────────────────────────────────────────────────── + private const int Pad = 24; + private const int KpiH = 110; + private const int KpiGap = 14; + private const int CardRad = 10; + private const int TopbarH = 56; + private const int RowH = 38; + + private readonly Font _fLabel; + private readonly Font _fValue; + private readonly Font _fDelta; + private readonly Font _fHead; + private readonly Font _fCell; + private readonly Font _fColHead; + private readonly Font _fMono; + private readonly Font _fBtn; + private readonly Font _fTopTitle; + private readonly Font _fTopSub; + + private Rectangle _btnNovaOS; + private int _hoverRow = -1; + + public DashboardPanel() + { + // CORRIGIDO: inicialização dos campos Font no construtor + // (evita o aviso "campo não anulável precisa conter valor não nulo") + _fLabel = new Font("Segoe UI", 8.5f); + _fValue = new Font("Segoe UI Semibold", 18f); + _fDelta = new Font("Segoe UI", 9f); + _fHead = new Font("Segoe UI Semibold", 10.5f); + _fCell = new Font("Segoe UI", 10f); + _fColHead = new Font("Segoe UI", 8f); + _fMono = new Font("Consolas", 9.5f); + _fBtn = new Font("Segoe UI Semibold", 10f); + _fTopTitle = new Font("Segoe UI Semibold", 13f); + _fTopSub = new Font("Segoe UI", 9f); + + // CORRIGIDO: KpiCard instanciado com construtor posicional explícito + _kpis = new[] + { + new KpiCard("OS Abertas", "12", "↑ 4 essa semana", true, BlueLight, Blue), + new KpiCard("OS Concluídas", "45", "↑ 12% vs mês", true, GreenL, Green), + new KpiCard("Faturamento", "22.5k", "↑ R$ 2.100", true, AmberL, Amber), + new KpiCard("Pendências", "3", "↓ aguardando", false, RedL, Red), + }; + + BackColor = Surface2; + DoubleBuffered = true; + SetStyle(ControlStyles.AllPaintingInWmPaint | + ControlStyles.OptimizedDoubleBuffer | + ControlStyles.ResizeRedraw, true); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _fLabel.Dispose(); _fValue.Dispose(); _fDelta.Dispose(); + _fHead.Dispose(); _fCell.Dispose(); _fColHead.Dispose(); + _fMono.Dispose(); _fBtn.Dispose(); _fTopTitle.Dispose(); + _fTopSub.Dispose(); + } + base.Dispose(disposing); + } + + // ── Paint ────────────────────────────────────────────────────────── + protected override void OnPaint(PaintEventArgs e) + { + var g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + DrawTopbar(g); + int y = TopbarH + Pad; + DrawKpiRow(g, y); + y += KpiH + 20; + DrawOsCard(g, y); + } + + // ── Topbar ───────────────────────────────────────────────────────── + private void DrawTopbar(Graphics g) + { + g.FillRectangle(new SolidBrush(Surface), 0, 0, Width, TopbarH); + g.DrawLine(new Pen(Border, 1), 0, TopbarH, Width, TopbarH); + + g.DrawString("Home", _fTopTitle, new SolidBrush(TextPri), Pad, 12); + //g.DrawString("Quinta, 09 de abril de 2026", _fTopSub, + g.DrawString( + DateTime.Now.ToString("dd 'de' MMMM 'de' yyyy", new CultureInfo("pt-BR")), _fTopSub, + new SolidBrush(TextMuted), Pad, 32); + + int bw = 110, bh = 32; + int bx = Width - Pad - bw; + int by = (TopbarH - bh) / 2; + _btnNovaOS = new Rectangle(bx, by, bw, bh); + FillRoundRect(g, new SolidBrush(Blue), _btnNovaOS, 6); + + var sf = new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }; + g.DrawString("+ Nova OS", _fBtn, new SolidBrush(Color.White), _btnNovaOS, sf); + } + + // ── KPI Row ──────────────────────────────────────────────────────── + private void DrawKpiRow(Graphics g, int y) + { + int totalGap = KpiGap * (_kpis.Length - 1); + int kpiW = (Width - Pad * 2 - totalGap) / _kpis.Length; + + for (int i = 0; i < _kpis.Length; i++) + { + int x = Pad + i * (kpiW + KpiGap); + DrawKpiCard(g, _kpis[i], new Rectangle(x, y, kpiW, KpiH)); + } + } + + private void DrawKpiCard(Graphics g, KpiCard kpi, Rectangle r) + { + FillRoundRect(g, new SolidBrush(Surface), r, CardRad); + DrawRoundBorder(g, r, CardRad, Border); + + int dotSize = 36; + var dotRect = new Rectangle(r.Right - 16 - dotSize, r.Y + 16, dotSize, dotSize); + FillRoundRect(g, new SolidBrush(kpi.DotBg), dotRect, 8); + + g.DrawString(kpi.Label, _fLabel, new SolidBrush(TextMuted), r.X + 16, r.Y + 18); + g.DrawString(kpi.Value, _fValue, new SolidBrush(TextPri), r.X + 14, r.Y + 36); + + var deltaColor = kpi.DeltaUp ? Green : Red; + g.DrawString(kpi.Delta, _fDelta, new SolidBrush(deltaColor), r.X + 16, r.Y + 76); + } + + // ── OS Card ──────────────────────────────────────────────────────── + private void DrawOsCard(Graphics g, int y) + { + string[] cols = { "OS", "Cliente", "Equipamento", "Status", "Data" }; + float[] colW = { 0.08f, 0.22f, 0.28f, 0.22f, 0.10f }; + + int cardH = 28 + RowH + RowH * _ordens.Count + 16; + var card = new Rectangle(Pad, y, Width - Pad * 2, cardH); + + FillRoundRect(g, new SolidBrush(Surface), card, CardRad); + DrawRoundBorder(g, card, CardRad, Border); + + g.DrawString("Ordens de Serviço Recentes", _fHead, + new SolidBrush(TextPri), card.X + 18, card.Y + 16); + + int tableY = card.Y + 44; + g.DrawLine(new Pen(Border, 0.5f), card.X, tableY, card.Right, tableY); + + int cx = card.X; + for (int c = 0; c < cols.Length; c++) + { + int cw = (int)(card.Width * colW[c]); + var sf = new StringFormat { LineAlignment = StringAlignment.Center }; + g.DrawString(cols[c].ToUpperInvariant(), _fColHead, + new SolidBrush(TextMuted), cx + 10, tableY + 2, sf); + cx += cw; + } + + for (int i = 0; i < _ordens.Count; i++) + { + int ry = tableY + RowH + i * RowH; + var row = _ordens[i]; + + if (i == _hoverRow) + g.FillRectangle(new SolidBrush(Surface2), + card.X + 1, ry, card.Width - 2, RowH); + + g.DrawLine(new Pen(Border, 0.5f), card.X, ry, card.Right, ry); + + cx = card.X; + int[] cws = GetColWidths(card.Width, colW); + + g.DrawString(row.OS, _fMono, + new SolidBrush(TextMuted), cx + 10, ry + (RowH - 14) / 2); + cx += cws[0]; + + g.DrawString(row.Cliente, _fCell, + new SolidBrush(TextPri), cx + 8, ry + (RowH - 14) / 2); + cx += cws[1]; + + g.DrawString(row.Equipamento, _fCell, + new SolidBrush(TextSec), cx + 8, ry + (RowH - 14) / 2); + cx += cws[2]; + + DrawBadge(g, row.Status, cx + 8, ry + (RowH - 20) / 2); + cx += cws[3]; + + g.DrawString(row.Data, _fCell, + new SolidBrush(TextMuted), cx + 8, ry + (RowH - 14) / 2); + } + } + + private static int[] GetColWidths(int total, float[] ratios) + { + var ws = new int[ratios.Length]; + for (int i = 0; i < ratios.Length; i++) + ws[i] = (int)(total * ratios[i]); + return ws; + } + + private void DrawBadge(Graphics g, OsStatus status, int x, int y) + { + var (label, bg, fg) = status switch + { + OsStatus.Concluida => ("Concluída", GreenL, Color.FromArgb(22, 101, 52)), + OsStatus.EmAndamento => ("Em andamento", AmberL, Color.FromArgb(146, 64, 14)), + OsStatus.Aguardando => ("Aguardando", BlueLight, Color.FromArgb(30, 64, 175)), + OsStatus.Pendente => ("Pendente", RedL, Color.FromArgb(153, 27, 27)), + _ => ("—", Border, TextMuted) + }; + + var sz = g.MeasureString(label, _fDelta); + int bw = (int)sz.Width + 16; + int bh = 20; + var badge = new Rectangle(x, y, bw, bh); + FillRoundRect(g, new SolidBrush(bg), badge, 10); + + var sf = new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }; + g.DrawString(label, _fDelta, new SolidBrush(fg), badge, sf); + } + + // ── Mouse ────────────────────────────────────────────────────────── + protected override void OnMouseMove(MouseEventArgs e) + { + int row = HitTestRow(e.Y); + if (row != _hoverRow) { _hoverRow = row; Invalidate(); } + Cursor = _btnNovaOS.Contains(e.Location) ? Cursors.Hand : Cursors.Default; + } + + protected override void OnMouseLeave(EventArgs e) + { + _hoverRow = -1; + Invalidate(); + } + + private int HitTestRow(int mouseY) + { + int tableY = TopbarH + Pad + KpiH + 20 + 44 + RowH; + for (int i = 0; i < _ordens.Count; i++) + { + int ry = tableY + i * RowH; + if (mouseY >= ry && mouseY < ry + RowH) return i; + } + return -1; + } + + // ── GDI Helpers ──────────────────────────────────────────────────── + private static void FillRoundRect(Graphics g, Brush brush, Rectangle r, int radius) + { + using var path = RoundRectPath(r, radius); + g.FillPath(brush, path); + } + + private static void DrawRoundBorder(Graphics g, Rectangle r, int radius, Color color) + { + using var path = RoundRectPath(r, radius); + g.DrawPath(new Pen(color, 0.5f), path); + } + + private static GraphicsPath RoundRectPath(Rectangle r, int radius) + { + var path = new GraphicsPath(); + path.AddArc(r.X, r.Y, radius * 2, radius * 2, 180, 90); + path.AddArc(r.Right - radius * 2, r.Y, radius * 2, radius * 2, 270, 90); + path.AddArc(r.Right - radius * 2, r.Bottom - radius * 2, radius * 2, radius * 2, 0, 90); + path.AddArc(r.X, r.Bottom - radius * 2, radius * 2, radius * 2, 90, 90); + path.CloseFigure(); + return path; + } + + // ── Modelos ──────────────────────────────────────────────────────── + // CORRIGIDO: usando classes simples em vez de records posicionais + // para compatibilidade com qualquer versão do compilador .NET 6+. + private class OsRow + { + public string OS { get; } + public string Cliente { get; } + public string Equipamento { get; } + public OsStatus Status { get; } + public string Data { get; } + + public OsRow(string os, string cliente, string equipamento, OsStatus status, string data) + { + OS = os; + Cliente = cliente; + Equipamento = equipamento; + Status = status; + Data = data; + } + } + + private class KpiCard + { + public string Label { get; } + public string Value { get; } + public string Delta { get; } + public bool DeltaUp { get; } + public Color DotBg { get; } + public Color DotFg { get; } + + public KpiCard(string label, string value, string delta, bool deltaUp, Color dotBg, Color dotFg) + { + Label = label; + Value = value; + Delta = delta; + DeltaUp = deltaUp; + DotBg = dotBg; + DotFg = dotFg; + } + } + + private enum OsStatus { Concluida, EmAndamento, Aguardando, Pendente } + } +} diff --git a/Dashboards/Dashmain/DashboardPanel.resx b/Dashboards/Dashmain/DashboardPanel.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Dashmain/DashboardPanel.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Dashmain/MainForm.cs b/Dashboards/Dashmain/MainForm.cs new file mode 100644 index 0000000..2f5d973 --- /dev/null +++ b/Dashboards/Dashmain/MainForm.cs @@ -0,0 +1,147 @@ +using CCH; +using CustomMessageBox; +using DAL; +using System; +using System.Drawing; +using System.Windows.Forms; +using TLL; +namespace UI +{ + public class MainForm : Form + { + private readonly SidebarControl _sidebar; + private readonly DashboardPanel _dashboard; + + private readonly ClienteCadastroPanel _pClientes; + private readonly EmpresaCadastroPanel _pEmpresa; + private readonly EmpresaConfiguracoesPanel _pEmpresaConfig; + private readonly AgendaCadastroPanel _pAgendaCadastro; + private readonly AgendaConsultaPanel _pAgendaConsulta; + private readonly FuncionariosCadastroPanel _pfuncionariosCadastro ; + private readonly Panel _pOrdens; + private readonly Panel _pProdutos; + private readonly Panel _pEstoque; + private readonly Panel _pFinanceiro; + + public MainForm() + { + Text = "LevelOS — Sistema ERP"; + this.WindowState = FormWindowState.Maximized; + this.MinimumSize = new Size(1100, 750); + this.BackColor = Color.FromArgb(248, 250, 252); + + _sidebar = new SidebarControl { Dock = DockStyle.Left }; + _sidebar.NavItemClicked += OnNavItemClicked; + + _dashboard = new DashboardPanel { Dock = DockStyle.Fill }; + + _pClientes = new ClienteCadastroPanel { Dock = DockStyle.Fill, Visible = false }; + _pEmpresa = new EmpresaCadastroPanel { Dock = DockStyle.Fill, Visible = false }; + _pEmpresaConfig = new EmpresaConfiguracoesPanel { Dock = DockStyle.Fill, Visible = false }; + _pAgendaCadastro = new AgendaCadastroPanel { Dock = DockStyle.Fill, Visible = false }; + _pAgendaConsulta = new AgendaConsultaPanel { Dock = DockStyle.Fill, Visible = false }; + _pfuncionariosCadastro = new FuncionariosCadastroPanel { Dock = DockStyle.Fill, Visible = false }; + _pOrdens = PlaceholderPanel("Ordens de Serviço", Color.FromArgb(22, 163, 74)); + _pProdutos = PlaceholderPanel("Catálogo de Produtos", Color.FromArgb(217, 119, 6)); + _pEstoque = PlaceholderPanel("Controle de Estoque", Color.FromArgb(234, 88, 12)); + _pFinanceiro = PlaceholderPanel("Fluxo Financeiro", Color.FromArgb(124, 58, 237)); + + var mainContainer = new Panel { Dock = DockStyle.Fill }; + mainContainer.Controls.Add(_pFinanceiro); + mainContainer.Controls.Add(_pAgendaCadastro); + mainContainer.Controls.Add(_pAgendaConsulta); + mainContainer.Controls.Add(_pEstoque); + mainContainer.Controls.Add(_pProdutos); + mainContainer.Controls.Add(_pOrdens); + mainContainer.Controls.Add(_pEmpresa); + mainContainer.Controls.Add(_pEmpresaConfig); + mainContainer.Controls.Add(_pClientes); + mainContainer.Controls.Add(_dashboard); + mainContainer.Controls.Add(_pfuncionariosCadastro); + + Controls.Add(mainContainer); + Controls.Add(_sidebar); + + ShowPanel(_dashboard); + + } + + private void OnNavItemClicked(object? sender, int index) + { + /* Índices: + 0 = Dashboard + 2 = Ordens de Serviço + 4 = Produtos + 5 = Estoque + 9 = Financeiro + 99 = Submenu → Clientes + 98 = Submenu → Empresa + */ + switch (index) + { + case 0: ShowPanel(_dashboard); break; + case 2: ShowPanel(_pOrdens); break; + case 4: ShowPanel(_pProdutos); break; + case 5: ShowPanel(_pEstoque); break; + case 9: ShowPanel(_pFinanceiro); break; + case 99: ShowPanel(_pClientes); break; + case 103: ShowPanel(_pfuncionariosCadastro); break; + case 106: ShowPanel(_pEmpresa); break; + + + case 202: ShowPanel(_pEmpresaConfig); break; + case 300: ShowPanel(_pAgendaCadastro); break; + case 301: ShowPanel(_pAgendaConsulta); break; + + + } + } + + private void ShowPanel(Control panelToShow) + { + _dashboard.Visible = (panelToShow == _dashboard); + _pClientes.Visible = (panelToShow == _pClientes); + _pEmpresa.Visible = (panelToShow == _pEmpresa); + _pEmpresaConfig.Visible = (panelToShow == _pEmpresaConfig); + _pOrdens.Visible = (panelToShow == _pOrdens); + _pProdutos.Visible = (panelToShow == _pProdutos); + _pEstoque.Visible = (panelToShow == _pEstoque); + _pFinanceiro.Visible = (panelToShow == _pFinanceiro); + _pAgendaCadastro.Visible = (panelToShow == _pAgendaCadastro); + _pAgendaConsulta.Visible = (panelToShow == _pAgendaConsulta); + _pfuncionariosCadastro.Visible = (panelToShow == _pfuncionariosCadastro); + + if (panelToShow.Visible) + { + panelToShow.BringToFront(); + panelToShow.Focus(); + } + } + + private static Panel PlaceholderPanel(string titulo, Color cor) + { + var p = new Panel { Dock = DockStyle.Fill, Visible = false }; + p.Paint += (s, e) => + { + var g = e.Graphics; + g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + var r = p.ClientRectangle; + g.Clear(Color.FromArgb(248, 250, 252)); + + var circle = new Rectangle(r.Width / 2 - 40, r.Height / 2 - 80, 80, 80); + g.FillEllipse(new SolidBrush(Color.FromArgb(20, cor)), circle); + + using var f1 = new Font("Segoe UI Semibold", 16f); + using var f2 = new Font("Segoe UI", 10f); + var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; + + g.DrawString(titulo, f1, new SolidBrush(Color.FromArgb(30, 41, 59)), + new RectangleF(0, r.Height / 2f - 10, r.Width, 40), sf); + + g.DrawString("Este módulo está sendo integrado ao LevelOS", f2, new SolidBrush(Color.FromArgb(148, 163, 184)), + new RectangleF(0, r.Height / 2f + 25, r.Width, 30), sf); + }; + return p; + } + } +} \ No newline at end of file diff --git a/Dashboards/Dashmain/MainForm.resx b/Dashboards/Dashmain/MainForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Dashmain/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Dashmain/SidebarControl.cs b/Dashboards/Dashmain/SidebarControl.cs new file mode 100644 index 0000000..6b5fbd8 --- /dev/null +++ b/Dashboards/Dashmain/SidebarControl.cs @@ -0,0 +1,423 @@ +using CustomMessageBox; +using DAL; +using DALL; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace UI +{ + public class SidebarControl : UserControl + { + //Recebendo a conexao + string _cx = DadosDaConexao.ObterConexao(); + + // ── Cores do Tema LevelOS ────────────────────────────────────────── + private static readonly Color NavyDark = Color.FromArgb(15, 30, 60); + private static readonly Color NavyMid = Color.FromArgb(26, 45, 80); + private static readonly Color AccentBlue = Color.FromArgb(37, 99, 235); + private static readonly Color TextLight = Color.FromArgb(255, 255, 255); + private static readonly Color TextMuted = Color.FromArgb(148, 163, 184); + private static readonly Color Divider = Color.FromArgb(40, 255, 255, 255); + + // ── Estado e Escalonamento (DPI) ─────────────────────────────────── + private float _scale = 1.0f; + private int _activeIndex = 0; + private int _hoverIndex = -1; + + // Propriedades Scaled (Ajustam-se ao monitor) + private int ScaledWidth => (int)(220 * _scale); + private int ScaledLogoH => (int)(55 * _scale); + private int ScaledSectionH => (int)(32 * _scale); + private int ScaledItemH => (int)(40 * _scale); + private int ScaledItemPadX => (int)(12 * _scale); + private int ScaledFooterH => (int)(50 * _scale); + private int ScaledIconSize => (int)(16 * _scale); + + // ── Submenus ─────────────────────────────────────────────────────── + private ContextMenuStrip _subMenuBanco, _subMenuConfiguracao, + _subMenuAjuda, _subMenuOrdemServico, _subMenuFinanceiro,_subMenuCadastro, _subMenuAgenda; + + public string UserName = "Levelcode", UserFunction = "Administrador"; + public event EventHandler? NavItemClicked; + + private readonly List _items = new() + { + new NavItem("Dashboard", SvgIcon.Grid, "Principal", null), + new NavItem("Cadastro", SvgIcon.UserPlus, null, "3"), + new NavItem("Ordens de Serviço", SvgIcon.FileText, null, "12"), + new NavItem("Agenda", SvgIcon.Calendar, null, null), + new NavItem("Produtos", SvgIcon.Package, "Gestão", null), + new NavItem("Estoque", SvgIcon.Inventory, null, null), + //new NavItem("Serviços", SvgIcon.Briefcase, null, null), + //new NavItem("Transportadoras", SvgIcon.Truck, null, null), + new NavItem("Financeiro", SvgIcon.DollarSign, null, null), + new NavItem("Banco de Dados", SvgIcon.Database, "Sistema", null), + new NavItem("Configurações", SvgIcon.Settings, null, null), + new NavItem("Suporte Técnico", SvgIcon.Support, "Ajuda", null), + }; + + public void backupFull(string conexao) + { + var backupService = new DALLBackupService(conexao); + var resultadoFull = backupService.ExecutarBackupFull(); + + if (resultadoFull.Sucesso) + NT_MessageBox.Show($"✅ Backup FULL concluído em {resultadoFull.Duracao.TotalSeconds:F1}s","Backup do banco de dados",MessageBoxButtons.OK, MessageBoxIcon.Information); + else + NT_MessageBox.Show($"❌ Erro no Backup FULL: {resultadoFull.Erro}","Erro ao tentar executar backup do sistema.",MessageBoxButtons.OK,MessageBoxIcon.Error); + }//Criar backup full + + public void backupDifrencial(string conexao) + { + var backupService = new DALLBackupService(conexao); + var resultadoDiff = backupService.ExecutarBackupDiferencial(); + + if (resultadoDiff.Sucesso) + NT_MessageBox.Show($"✅ Backup DIFERENCIAL concluído em {resultadoDiff.Duracao.TotalSeconds:F1}s","Backup diferencial concluido", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + NT_MessageBox.Show($"❌ Erro no Backup DIFERENCIAL: {resultadoDiff.Erro}","Erro ao tentar executar backup diferencial no sistema", MessageBoxButtons.OK, MessageBoxIcon.Error); + }//Criar backup diferencial + + + + public SidebarControl() + { + BackColor = NavyDark; + DoubleBuffered = true; + this.SetStyle(ControlStyles.ResizeRedraw, true); + } + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + using (Graphics g = this.CreateGraphics()) { _scale = g.DpiX / 96f; } + this.Width = ScaledWidth; + SetupSubMenus(); + } + + private void SetupSubMenus() + { + //Submenu Cadastro + _subMenuCadastro = CreateStyledMenu(); + _subMenuCadastro.Items.Add("👤 Clientes", null, (s, e) => {NavItemClicked?.Invoke(this, 99);}); + _subMenuCadastro.Items.Add("💻 Equipamentos", null, (s, e) => { NavItemClicked?.Invoke(this, 100); }); + _subMenuCadastro.Items.Add("📜 Contratos", null, (s, e) => { NavItemClicked?.Invoke(this, 101); }); + _subMenuCadastro.Items.Add("🏭 Fornecedores", null, (s, e) => { NavItemClicked?.Invoke(this, 102); }); + _subMenuCadastro.Items.Add("👔 Funcionários", null, (s, e) => { NavItemClicked?.Invoke(this, 103); }); + _subMenuCadastro.Items.Add("🚚 Transportadoras", null, (s, e) => { NavItemClicked?.Invoke(this, 104); }); + _subMenuCadastro.Items.Add("🛠️ Serviços", null, (s, e) => { NavItemClicked?.Invoke(this, 105); }); + _subMenuCadastro.Items.Add("🏢 Empresa", null, (s, e) => { NavItemClicked?.Invoke(this, 106); }); + _subMenuCadastro.Items.Add("🔑 Usuários do Sistema", null, (s, e) => { NavItemClicked?.Invoke(this, 107); }); + + _subMenuBanco = CreateStyledMenu(); + _subMenuBanco.Items.Add("⚙️ Configuração Database", null, (s, e) => showForms
()); // Substitua pelo seu Form + _subMenuBanco.Items.Add("💾 Backup de Dados (FULL)", null, (s, e) => backupFull(this._cx)); + _subMenuBanco.Items.Add("⚡ Backup de Dados (DIFF)", null, (s, e) => backupDifrencial(this._cx)); + _subMenuBanco.Items.Add("🔄 Restaurar Banco"); + + + //submenu Configurações + _subMenuConfiguracao = CreateStyledMenu(); + _subMenuConfiguracao.Items.Add("🖼️ Personalização de OS"); + _subMenuConfiguracao.Items.Add("🖥️ Personalização de Sistema"); + _subMenuConfiguracao.Items.Add(" Configuração Empresa", null, (s, e) => { NavItemClicked?.Invoke(this, 202); }); + _subMenuConfiguracao.Items.Add(new ToolStripSeparator()); + _subMenuConfiguracao.Items.Add("📂 FTP-Cliente"); // Pasta para arquivos + _subMenuConfiguracao.Items.Add("💬 Telegram-Cliente"); // Balão de conversa + _subMenuConfiguracao.Items.Add("📩 SMTP-Cliente"); // Envelope de saída + _subMenuConfiguracao.Items.Add(new ToolStripSeparator()); + // Automação + _subMenuConfiguracao.Items.Add("⏰ Backups Automáticos"); // Relógio para agendamento + _subMenuConfiguracao.Items.Add("☁️ Backup em Nuvem"); + + _subMenuAjuda = CreateStyledMenu(); + _subMenuAjuda.Items.Add("💬 Atendimento Online"); + _subMenuAjuda.Items.Add("📖 Manual do Sistema"); + + _subMenuOrdemServico = CreateStyledMenu(); + + _subMenuOrdemServico.Items.Add("✚ Abrir nova O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("✎ Alterar O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("🔒 Encerrar O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("🔍 Localizar O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("📋 Orçamento de O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("📜 Histórico de O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("📊 Relatório de O.S", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("🖨 Imprimir", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("⚠️ Chamado Técnico", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("🌐 OS WEB", null, (s, e) => { /* Lógica */ }); + _subMenuOrdemServico.Items.Add("🔓 Reabrir OS", null, (s, e) => { /* Lógica */ }); + + _subMenuFinanceiro = CreateStyledMenu(); + + _subMenuFinanceiro.Items.Add("💳 Contas", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add("📈 Contas a receber", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add("📉 Contas a pagar", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add(new ToolStripSeparator()); // Linha divisória + _subMenuFinanceiro.Items.Add("🛒 Compras", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add("💰 Vendas", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add("🧾 Notas Fiscais", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add(new ToolStripSeparator()); // Linha divisória + _subMenuFinanceiro.Items.Add("📂 Arquivo Contador", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add("🏦 Dados Bancários", null, (s, e) => { /* Lógica */ }); + _subMenuFinanceiro.Items.Add("🕒 Histórico Financeiro", null, (s, e) => { /* Lógica */ }); + + + // private ContextMenuStrip _subMenuAgenda; + _subMenuAgenda = CreateStyledMenu(); + //_subMenuAgenda.Items.Add("➕ Novo compromisso", null, (s, e) => {showForms();}); + _subMenuAgenda.Items.Add("➕ Novo compromisso", null, (s, e) => { NavItemClicked?.Invoke(this, 300); }); + _subMenuAgenda.Items.Add("🔍 Consultar compromissos", null, (s, e) => { NavItemClicked?.Invoke(this, 301); }); + _subMenuAgenda.Items.Add("✏️ Alterar compromisso", null, (s, e) => { /* Lógica de edição */ }); + _subMenuAgenda.Items.Add("🖨️ Imprimir", null, (s, e) => { /* Lógica de relatório */ }); + } + + private ContextMenuStrip CreateStyledMenu() + { + return new ContextMenuStrip + { + BackColor = NavyMid, + ForeColor = TextLight, + ShowImageMargin = false, + Font = new Font("Segoe UI", 10f * _scale), + Renderer = new ToolStripProfessionalRenderer(new SubMenuColorTable()) + }; + } + + private void showForms() where T : Form, new() + { + using (T form = new T()) + { + form.StartPosition = FormStartPosition.CenterScreen; + form.ShowDialog(); + } + } + //Abrir agenda + // AgendaForm.cs + public class AgendaForm : Form + { + public AgendaForm() + { + Text = "Agenda de Compromissos"; + Size = new Size(1150, 780); + StartPosition = FormStartPosition.CenterScreen; + BackColor = Color.White; + + var panel = new AgendaCadastroPanel(); + Controls.Add(panel); + } + }//abrir agenda de compromissos + + protected override void OnPaint(PaintEventArgs e) + { + var g = e.Graphics; + g.SmoothingMode = SmoothingMode.AntiAlias; + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + DrawLogo(g); + DrawNavItems(g, ScaledLogoH + (int)(8 * _scale)); + DrawFooter(g); + } + + private void DrawNavItems(Graphics g, int startY) + { + int y = startY; + using var fSection = new Font("Segoe UI", 8f * _scale, FontStyle.Bold); + using var fItem = new Font("Segoe UI", 10f * _scale); + using var fItemSel = new Font("Segoe UI Semibold", 10f * _scale); + + for (int i = 0; i < _items.Count; i++) + { + var item = _items[i]; + if (item.Section != null) + { + y += (int)(10 * _scale); + g.DrawString(item.Section.ToUpper(), fSection, new SolidBrush(Color.FromArgb(120, TextMuted)), ScaledItemPadX + (int)(8 * _scale), y); + y += ScaledSectionH; + } + + bool isActive = (i == _activeIndex); + bool isHover = (i == _hoverIndex && !isActive); + var itemRect = new Rectangle(ScaledItemPadX, y, Width - ScaledItemPadX * 2, ScaledItemH); + + if (isActive) FillRoundRect(g, new SolidBrush(AccentBlue), itemRect, (int)(6 * _scale)); + else if (isHover) FillRoundRect(g, new SolidBrush(Color.FromArgb(20, 255, 255, 255)), itemRect, (int)(6 * _scale)); + + var color = isActive ? TextLight : Color.FromArgb(200, TextLight); + DrawIcon(g, item.Icon, ScaledItemPadX + (int)(10 * _scale), y + (ScaledItemH - ScaledIconSize) / 2, ScaledIconSize, color); + g.DrawString(item.Label, isActive ? fItemSel : fItem, new SolidBrush(color), ScaledItemPadX + (int)(36 * _scale), y + (ScaledItemH - (int)(16 * _scale)) / 2); + + if (HasSubMenu(item.Label)) + g.DrawString("›", fItem, new SolidBrush(Color.FromArgb(100, TextLight)), Width - (int)(30 * _scale), y + (ScaledItemH - (int)(18 * _scale)) / 2); + + y += ScaledItemH + (int)(2 * _scale); + } + } + + // Adicione "Cadastro" na verificação + private bool HasSubMenu(string label) => + label == "Cadastro" || // <-- Adicionado aqui + label == "Banco de Dados" || + label == "Financeiro" || + label == "Ordens de Serviço" || + label == "Configurações" || + label == "Suporte Técnico" || + label == "Agenda" + ; + + protected override void OnMouseClick(MouseEventArgs e) + { + int hit = HitTest(e.Y); + if (hit >= 0) + { + _activeIndex = hit; Invalidate(); + string label = _items[hit].Label; + Point menuPos = new Point(Width + 2, e.Y - (int)(15 * _scale)); + + if (label == "Banco de Dados") _subMenuBanco.Show(this, menuPos); + else if (label == "Financeiro") _subMenuFinanceiro.Show(this, menuPos); + else if(label == "Agenda") _subMenuAgenda.Show(this, menuPos); + else if (label == "Ordens de Serviço") _subMenuOrdemServico.Show(this, menuPos); + else if (label == "Configurações") _subMenuConfiguracao.Show(this, menuPos); + else if (label == "Suporte Técnico") _subMenuAjuda.Show(this, menuPos); + else if (label == "Cadastro") _subMenuCadastro.Show(this, menuPos); + else NavItemClicked?.Invoke(this, hit); + } + } + + private int HitTest(int mouseY) + { + int y = ScaledLogoH + (int)(8 * _scale); + for (int i = 0; i < _items.Count; i++) + { + if (_items[i].Section != null) y += (int)(10 * _scale) + ScaledSectionH; + if (mouseY >= y && mouseY < y + ScaledItemH) return i; + y += ScaledItemH + (int)(2 * _scale); + } + return -1; + } + + protected override void OnMouseMove(MouseEventArgs e) { int hit = HitTest(e.Y); if (hit != _hoverIndex) { _hoverIndex = hit; Invalidate(); } } + protected override void OnMouseLeave(EventArgs e) { _hoverIndex = -1; Invalidate(); } + + private void DrawLogo(Graphics g) + { + var iconRect = new Rectangle((int)(16 * _scale), (int)(18 * _scale), (int)(34 * _scale), (int)(34 * _scale)); + FillRoundRect(g, new SolidBrush(AccentBlue), iconRect, (int)(8 * _scale)); + using var fIcon = new Font("Segoe UI", 14f * _scale, FontStyle.Bold); + DrawCenteredString(g, "S", fIcon, TextLight, iconRect); + g.DrawString("LevelOS", new Font("Segoe UI Semibold", 13f * _scale), new SolidBrush(TextLight), 58 * _scale, 20 * _scale); + g.DrawString("SISTEMA ERP", new Font("Segoe UI", 8f * _scale), new SolidBrush(TextMuted), 59 * _scale, 38 * _scale); + g.DrawLine(new Pen(Divider), 0, ScaledLogoH, Width, ScaledLogoH); + } + + private void DrawFooter(Graphics g) + { + int fy = Height - ScaledFooterH; + g.DrawLine(new Pen(Divider), 0, fy, Width, fy); + var avRect = new Rectangle((int)(16 * _scale), fy + (int)(14 * _scale), (int)(32 * _scale), (int)(32 * _scale)); + g.FillEllipse(new SolidBrush(AccentBlue), avRect); + DrawCenteredString(g, "AD", new Font("Segoe UI Semibold", 10f * _scale), TextLight, avRect); + g.DrawString(UserName, new Font("Segoe UI Semibold", 11f * _scale), new SolidBrush(TextLight), 56 * _scale, fy + (14 * _scale)); + g.DrawString(UserFunction, new Font("Segoe UI", 9f * _scale), new SolidBrush(TextMuted), 57 * _scale, fy + (30 * _scale)); + } + + // ── MOTOR DE ÍCONES COMPLETO (GDI+) ──────────────────────────────── + private void DrawIcon(Graphics g, SvgIcon icon, int x, int y, int size, Color color) + { + using var p = new Pen(color, 1.6f * _scale) { StartCap = LineCap.Round, EndCap = LineCap.Round, LineJoin = LineJoin.Round }; + float s = size / 24f; + g.TranslateTransform(x, y); g.ScaleTransform(s, s); + + switch (icon) + { + case SvgIcon.Grid: + g.DrawRectangle(p, 3, 3, 7, 7); g.DrawRectangle(p, 14, 3, 7, 7); g.DrawRectangle(p, 3, 14, 7, 7); g.DrawRectangle(p, 14, 14, 7, 7); break; + case SvgIcon.Users: + g.DrawEllipse(p, 5, 3, 8, 8); g.DrawArc(p, 2, 13, 14, 8, 180, 180); g.DrawArc(p, 15, 8, 6, 6, 270, 180); break; + case SvgIcon.FileText: + g.DrawLines(p, new PointF[] { new(6, 2), new(6, 22), new(18, 22), new(18, 8), new(14, 2), new(6, 2) }); g.DrawLine(p, 14, 2, 14, 8); g.DrawLine(p, 14, 8, 18, 8); break; + case SvgIcon.Package: + g.DrawLines(p, new PointF[] { new(12, 2), new(2, 7), new(12, 12), new(22, 7), new(12, 2) }); g.DrawLine(p, 2, 7, 2, 17); g.DrawLine(p, 22, 7, 22, 17); g.DrawLine(p, 12, 12, 12, 22); break; + case SvgIcon.DollarSign: + g.DrawLine(p, 12, 2, 12, 22); g.DrawArc(p, 7, 5, 10, 7, 110, 250); g.DrawArc(p, 7, 12, 10, 7, 270, 250); break; + case SvgIcon.Database: + g.DrawEllipse(p, 4, 3, 16, 6); g.DrawLine(p, 4, 6, 4, 18); g.DrawLine(p, 20, 6, 20, 18); g.DrawArc(p, 4, 15, 16, 6, 0, 180); break; + case SvgIcon.Calendar: + g.DrawRectangle(p, 3, 4, 18, 17); g.DrawLine(p, 3, 9, 21, 9); g.DrawLine(p, 8, 2, 8, 6); g.DrawLine(p, 16, 2, 16, 6); break; + case SvgIcon.Truck: + g.DrawRectangle(p, 1, 5, 13, 11); g.DrawLines(p, new PointF[] { new(14, 16), new(14, 8), new(19, 8), new(23, 12), new(23, 16) }); + g.DrawEllipse(p, 3, 15, 4, 4); g.DrawEllipse(p, 17, 15, 4, 4); break; + case SvgIcon.Factory: + g.DrawRectangle(p, 2, 10, 20, 11); g.DrawLines(p, new PointF[] { new(2, 10), new(2, 5), new(8, 10), new(8, 5), new(14, 10) }); break; + case SvgIcon.Briefcase: + g.DrawRectangle(p, 3, 7, 18, 13); g.DrawArc(p, 9, 3, 6, 8, 180, 180); break; + case SvgIcon.Support: + g.DrawArc(p, 4, 4, 16, 16, 180, 180); g.DrawRectangle(p, 3, 13, 3, 5); g.DrawRectangle(p, 18, 13, 3, 5); break; + case SvgIcon.Inventory: + g.DrawRectangle(p, 3, 3, 18, 8); g.DrawRectangle(p, 3, 13, 18, 8); break; + case SvgIcon.Settings: + g.DrawEllipse(p, 9, 9, 6, 6); + for (int a = 0; a < 360; a += 45) + { + float r = a * (float)Math.PI / 180f; + g.DrawLine(p, 12 + (float)Math.Cos(r) * 8, 12 + (float)Math.Sin(r) * 8, 12 + (float)Math.Cos(r) * 11, 12 + (float)Math.Sin(r) * 11); + } + break; + case SvgIcon.User: g.DrawEllipse(p, 8, 2, 8, 8); g.DrawArc(p, 3, 14, 18, 8, 180, 180); break; + case SvgIcon.UserCheck: g.DrawEllipse(p, 8, 3, 8, 8); g.DrawArc(p, 3, 14, 18, 8, 180, 180); g.DrawRectangle(p, 10, 15, 4, 3); break; + case SvgIcon.UserPlus: + // Desenha o corpo do usuário (círculo e arco) + g.DrawEllipse(p, 4, 4, 8, 8); // Cabeça + g.DrawArc(p, 1, 14, 14, 8, 180, 180); // Ombros + + // Desenha o sinal de "+" ao lado + // Vertical + g.DrawLine(p, 19, 7, 19, 15); + // Horizontal + g.DrawLine(p, 15, 11, 23, 11); + break; + + + } + g.ResetTransform(); + } + + // ── Helpers ── + private static void FillRoundRect(Graphics g, Brush b, Rectangle r, int rad) { using var path = RoundRectPath(r, rad); g.FillPath(b, path); } + private static GraphicsPath RoundRectPath(Rectangle r, int rad) + { + var path = new GraphicsPath(); int d = Math.Max(rad * 2, 1); + path.AddArc(r.X, r.Y, d, d, 180, 90); path.AddArc(r.Right - d, r.Y, d, d, 270, 90); + path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90); path.AddArc(r.X, r.Bottom - d, d, d, 90, 90); + path.CloseFigure(); return path; + } + private static void DrawCenteredString(Graphics g, string t, Font f, Color c, Rectangle r) + { + var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; + g.DrawString(t, f, new SolidBrush(c), r, sf); + } + + private class NavItem + { + public string Label { get; } + public SvgIcon Icon { get; } + public string? Section { get; } + public string? Badge { get; } + public NavItem(string l, SvgIcon i, string? s, string? b) { Label = l; Icon = i; Section = s; Badge = b; } + } + private class SubMenuColorTable : ProfessionalColorTable + { + public override Color ToolStripDropDownBackground => NavyMid; + public override Color MenuItemSelected => AccentBlue; + public override Color MenuItemBorder => Color.Transparent; + public override Color MenuItemSelectedGradientBegin => AccentBlue; + public override Color MenuItemSelectedGradientEnd => AccentBlue; + } + } + + public enum SvgIcon { Grid, Users, FileText, Package, DollarSign, User, Settings, Database, Truck, Factory, UserCheck, Briefcase, Support, Inventory, Wallet, ShoppingCart, ShoppingBag, Calendar , UserPlus} +} \ No newline at end of file diff --git a/Dashboards/Dashmain/SidebarControl.resx b/Dashboards/Dashmain/SidebarControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Dashboards/Dashmain/SidebarControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Dashboards/Main/Dash_main.Designer.cs b/Dashboards/Main/Dash_main.Designer.cs new file mode 100644 index 0000000..af35c5b --- /dev/null +++ b/Dashboards/Main/Dash_main.Designer.cs @@ -0,0 +1,132 @@ +namespace UI +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + lbltest = new Label(); + lV_button1 = new CPM.LV_BUTTON(); + lV_button2 = new CPM.LV_BUTTON(); + lV_button3 = new CPM.LV_BUTTON(); + SuspendLayout(); + // + // lbltest + // + lbltest.AutoSize = true; + lbltest.Location = new Point(12, 9); + lbltest.Name = "lbltest"; + lbltest.Size = new Size(38, 15); + lbltest.TabIndex = 0; + lbltest.Text = "label1"; + // + // lV_button1 + // + lV_button1.BackColor = Color.MediumSlateBlue; + lV_button1.BackgroundColor = Color.MediumSlateBlue; + lV_button1.BorderColor = Color.PaleVioletRed; + lV_button1.BorderRadius = 0; + lV_button1.BorderSize = 0; + lV_button1.ClickColor = Color.DarkBlue; + lV_button1.FlatAppearance.BorderSize = 0; + lV_button1.FlatStyle = FlatStyle.Flat; + lV_button1.ForeColor = Color.White; + lV_button1.HoverColor = Color.LightBlue; + lV_button1.Location = new Point(734, 12); + lV_button1.Name = "lV_button1"; + lV_button1.Size = new Size(148, 32); + lV_button1.TabIndex = 1; + lV_button1.Text = "FrmConfigDB"; + lV_button1.TextColor = Color.White; + lV_button1.UseVisualStyleBackColor = false; + lV_button1.Click += lV_button1_Click; + // + // lV_button2 + // + lV_button2.BackColor = Color.MediumSlateBlue; + lV_button2.BackgroundColor = Color.MediumSlateBlue; + lV_button2.BorderColor = Color.PaleVioletRed; + lV_button2.BorderRadius = 0; + lV_button2.BorderSize = 0; + lV_button2.ClickColor = Color.DarkBlue; + lV_button2.FlatAppearance.BorderSize = 0; + lV_button2.FlatStyle = FlatStyle.Flat; + lV_button2.ForeColor = Color.White; + lV_button2.HoverColor = Color.LightBlue; + lV_button2.Location = new Point(734, 50); + lV_button2.Name = "lV_button2"; + lV_button2.Size = new Size(148, 32); + lV_button2.TabIndex = 2; + lV_button2.Text = "Dashmain"; + lV_button2.TextColor = Color.White; + lV_button2.UseVisualStyleBackColor = false; + lV_button2.Click += lV_button2_Click; + // + // lV_button3 + // + lV_button3.BackColor = Color.MediumSlateBlue; + lV_button3.BackgroundColor = Color.MediumSlateBlue; + lV_button3.BorderColor = Color.PaleVioletRed; + lV_button3.BorderRadius = 0; + lV_button3.BorderSize = 0; + lV_button3.ClickColor = Color.DarkBlue; + lV_button3.FlatAppearance.BorderSize = 0; + lV_button3.FlatStyle = FlatStyle.Flat; + lV_button3.ForeColor = Color.White; + lV_button3.HoverColor = Color.LightBlue; + lV_button3.Location = new Point(734, 88); + lV_button3.Name = "lV_button3"; + lV_button3.Size = new Size(148, 32); + lV_button3.TabIndex = 3; + lV_button3.Text = "Arquivo Encryptado"; + lV_button3.TextColor = Color.White; + lV_button3.UseVisualStyleBackColor = false; + lV_button3.Click += lV_button3_Click; + // + // Form1 + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(894, 474); + Controls.Add(lV_button3); + Controls.Add(lV_button2); + Controls.Add(lV_button1); + Controls.Add(lbltest); + Name = "Form1"; + Text = "Form1"; + Load += Form1_Load; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lbltest; + private CPM.LV_BUTTON lV_button1; + private CPM.LV_BUTTON lV_button2; + private CPM.LV_BUTTON lV_button3; + } +} diff --git a/Dashboards/Main/Dash_main.cs b/Dashboards/Main/Dash_main.cs new file mode 100644 index 0000000..a942080 --- /dev/null +++ b/Dashboards/Main/Dash_main.cs @@ -0,0 +1,75 @@ +using CAB; +using CCH; +using CPM; +using CPT; +using CustomMessageBox; +using DAL; +using TLL; +using static CPT.SecurityManager; + +namespace UI +{ + public partial class Form1 : Form + { + public Form1() + { + InitializeComponent(); + string caminhoIcone = AppFileSystem.AppFileIconSystem; + + if (File.Exists(caminhoIcone)) + { + this.Icon = new Icon(caminhoIcone); + } + + } + + private void Form1_Load(object sender, EventArgs e) + { + DadosDaConexao.Host = "206.42.13.180"; + DadosDaConexao.Port = 1433; + DadosDaConexao.Banco = "Levelcode-LevelOS"; + DadosDaConexao.Usuario = "nicolas"; + DadosDaConexao.Senha = "Nike12122020*##"; + DadosDaConexao.ConnectTimeout = 1000; + DadosDaConexao.Encrypt = false; + DadosDaConexao.TrustServerCertificate = false; + + DatabaseHelper.Salvar(AppFileSystem.AppFileDBSystem, AppInfoSystem.AppKeyMasterCrip); + DatabaseHelper.Carregar(AppFileSystem.AppFileDBSystem, AppInfoSystem.AppKeyMasterCrip); + this.lbltest.Text = DadosDaConexao.Host; + if (DadosDaConexao.TestarConexao()) + { + NT_MessageBox.Show("Conexão com o banco de dados concluida com sucesso!", "Teste de conexão"); + } + } + + private void lV_button1_Click(object sender, EventArgs e) + { + FrmConfigBanco f = new FrmConfigBanco(); + f.ShowDialog(); + } + + private void lV_button2_Click(object sender, EventArgs e) + { + MainForm main = new MainForm(); + main.ShowDialog(); + } + + private void lV_button3_Click(object sender, EventArgs e) + { + string caminhoKey = @"C:\Levelcode\LevelOS\Config\config.json"; + DadosDaConexao.Host = "206.42.13.180"; + DadosDaConexao.Port = 1433; + DadosDaConexao.Banco = "Levelcode-LevelOS"; + DadosDaConexao.Usuario = "nicolas"; + DadosDaConexao.Senha = "Nike12122020*##"; + DadosDaConexao.ConnectTimeout = 1000; + DadosDaConexao.Encrypt = false; + DadosDaConexao.TrustServerCertificate = false; + DatabaseHelperCPT.Salvar(caminhoKey); + string conectionString = DatabaseHelperCPT.Carregar(caminhoKey); + NT_MessageBox.Show(conectionString); + + } + } +} diff --git a/Dashboards/Main/Dash_main.resx b/Dashboards/Main/Dash_main.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/Dashboards/Main/Dash_main.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Documentohelper.cs b/Documentohelper.cs new file mode 100644 index 0000000..4f67270 --- /dev/null +++ b/Documentohelper.cs @@ -0,0 +1,67 @@ +using System.Windows.Forms; + +namespace UI +{ + /// + /// Formata CPF ou CNPJ automaticamente enquanto o usuário digita. + /// Uso: DocumentoHelper.Registrar(txtDocumento); + /// + public static class DocumentoHelper + { + public static void Registrar(RoundTextBox txt) + { + bool formatando = false; + + txt.TextChanged += (_, _) => + { + // Evita loop: TextChanged → altera Text → TextChanged → ... + if (formatando) return; + formatando = true; + + try + { + // 1. Extrai só os dígitos + string digits = new string(txt.Text.Where(char.IsDigit).ToArray()); + + // 2. Limita ao tamanho máximo do CNPJ + if (digits.Length > 14) digits = digits[..14]; + + // 3. Formata conforme o tamanho + string formatado = digits.Length <= 11 + ? FormatarCPF(digits) + : FormatarCNPJ(digits); + + // 4. Só atualiza se realmente mudou + if (txt.Text != formatado) + { + txt.Text = formatado; + txt.SelectionStart = formatado.Length; // cursor no final + } + } + finally + { + formatando = false; + } + }; + } + + // CPF: 000.000.000-00 + private static string FormatarCPF(string d) => d.Length switch + { + <= 3 => d, + <= 6 => $"{d[..3]}.{d[3..]}", + <= 9 => $"{d[..3]}.{d[3..6]}.{d[6..]}", + _ => $"{d[..3]}.{d[3..6]}.{d[6..9]}-{d[9..]}" + }; + + // CNPJ: 00.000.000/0000-00 + private static string FormatarCNPJ(string d) => d.Length switch + { + <= 2 => d, + <= 5 => $"{d[..2]}.{d[2..]}", + <= 8 => $"{d[..2]}.{d[2..5]}.{d[5..]}", + <= 12 => $"{d[..2]}.{d[2..5]}.{d[5..8]}/{d[8..]}", + _ => $"{d[..2]}.{d[2..5]}.{d[5..8]}/{d[8..12]}-{d[12..]}" + }; + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..aa757f5 --- /dev/null +++ b/Program.cs @@ -0,0 +1,20 @@ +using CCH; + +namespace UI +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + AppFolderSystem.CriarEstruturaPastas(); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/RoundComboBox.cs b/RoundComboBox.cs new file mode 100644 index 0000000..015e1ad --- /dev/null +++ b/RoundComboBox.cs @@ -0,0 +1,125 @@ +using System.Drawing.Drawing2D; + +namespace UI +{ + public class RoundComboBox : UserControl + { + private ComboBox _comboBox = null!; + public int Radius { get; set; } = 4; + public Color BorderColor { get; set; } = Color.LightGray; + public Color FocusColor { get; set; } = Color.Blue; + private bool _focused; + + public ComboBoxStyle DropDownStyle + { + get => _comboBox.DropDownStyle; + set => _comboBox.DropDownStyle = value; + } + + public ComboBox.ObjectCollection Items => _comboBox.Items; + + public object? SelectedItem + { + get => _comboBox.SelectedItem; + set => _comboBox.SelectedItem = value; + } + + public int SelectedIndex + { + get => _comboBox.SelectedIndex; + set => _comboBox.SelectedIndex = value; + } + + public override string Text + { + get => _comboBox.Text; + set => _comboBox.Text = value; + } + + public new Color BackColor + { + get => base.BackColor; + set { base.BackColor = value; if (_comboBox != null) _comboBox.BackColor = value; } + } + + public new event EventHandler? SelectedIndexChanged + { + add => _comboBox.SelectedIndexChanged += value; + remove => _comboBox.SelectedIndexChanged -= value; + } + + public RoundComboBox() + { + DoubleBuffered = true; + base.BackColor = Color.White; + + _comboBox = new ComboBox + { + //BorderStyle = BorderStyle.None, + Font = new Font("Segoe UI", 9f), + BackColor = Color.White, + DropDownStyle = ComboBoxStyle.DropDownList, + FlatStyle = FlatStyle.Flat + }; + + _comboBox.GotFocus += (s, e) => { _focused = true; Invalidate(); }; + _comboBox.LostFocus += (s, e) => { _focused = false; Invalidate(); }; + _comboBox.TextChanged += (s, e) => OnTextChanged(e); + _comboBox.Leave += (s, e) => OnLeave(e); + + Controls.Add(_comboBox); + SizeChanged += (s, e) => AjustarComboBox(); + } + + private void AjustarComboBox() + { + _comboBox.Width = Width - 12; + _comboBox.Location = new Point(6, (Height - _comboBox.PreferredHeight) / 2); + } + public object? DataSource + { + get => _comboBox.DataSource; + set => _comboBox.DataSource = value; + } + + public string DisplayMember + { + get => _comboBox.DisplayMember; + set => _comboBox.DisplayMember = value; + } + + public string ValueMember + { + get => _comboBox.ValueMember; + set => _comboBox.ValueMember = value; + } + + public object? SelectedValue + { + get => _comboBox.SelectedValue; + set => _comboBox.SelectedValue = value; + } + + protected override void OnPaint(PaintEventArgs e) + { + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + using var path = GetPath(new Rectangle(0, 0, Width - 1, Height - 1), Radius); + using var brush = new SolidBrush(BackColor); + e.Graphics.FillPath(brush, path); + using var pen = new Pen(_focused ? FocusColor : BorderColor, _focused ? 1.5f : 1f); + e.Graphics.DrawPath(pen, path); + } + + private static GraphicsPath GetPath(Rectangle r, int rad) + { + var path = new GraphicsPath(); + int d = rad * 2; + path.AddArc(r.X, r.Y, d, d, 180, 90); + path.AddArc(r.Right - d, r.Y, d, d, 270, 90); + path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90); + path.AddArc(r.X, r.Bottom - d, d, d, 90, 90); + path.CloseFigure(); + return path; + } + } +} diff --git a/UI.csproj b/UI.csproj new file mode 100644 index 0000000..d6968f4 --- /dev/null +++ b/UI.csproj @@ -0,0 +1,28 @@ + + + + WinExe + net8.0-windows + enable + true + enable + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UI.sln b/UI.sln new file mode 100644 index 0000000..98d7aab --- /dev/null +++ b/UI.sln @@ -0,0 +1,79 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.4.11626.88 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UI", "UI.csproj", "{344A1172-B978-A3CB-44BF-B15E6902C6C7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLL", "..\MLL\MLL.csproj", "{BD112D2C-C31D-4DC4-A3C8-2C5808C17D53}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCH", "..\CCH\CCH.csproj", "{AD6AD8F1-7AE1-4BFC-A7EB-5F5B37EFE4C0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TLL", "..\TLL\TLL.csproj", "{A5F3E468-7A97-4C71-8E75-CD2CAF8B477C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPT", "..\CPT\CPT.csproj", "{970FFDEE-6F66-49FD-B41F-EBC8F50C547C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DAL", "..\DAL\DAL.csproj", "{9696C45A-97A2-445E-BE10-BB3EE320BFDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BLL", "..\BLL\BLL.csproj", "{68B73E29-9E25-4BCA-B077-400F6B2B450B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPM", "..\CPM\CPM.csproj", "{20B46C82-119A-F5E9-8B57-A756A827F265}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CAB", "..\CAB\CAB.csproj", "{19039AC1-EE08-460B-821B-0277442D04D1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CMB", "..\CMB\CMB.csproj", "{766E76F2-BAFF-4352-B376-15F6DE8BE4D9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {344A1172-B978-A3CB-44BF-B15E6902C6C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {344A1172-B978-A3CB-44BF-B15E6902C6C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {344A1172-B978-A3CB-44BF-B15E6902C6C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {344A1172-B978-A3CB-44BF-B15E6902C6C7}.Release|Any CPU.Build.0 = Release|Any CPU + {BD112D2C-C31D-4DC4-A3C8-2C5808C17D53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD112D2C-C31D-4DC4-A3C8-2C5808C17D53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD112D2C-C31D-4DC4-A3C8-2C5808C17D53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD112D2C-C31D-4DC4-A3C8-2C5808C17D53}.Release|Any CPU.Build.0 = Release|Any CPU + {AD6AD8F1-7AE1-4BFC-A7EB-5F5B37EFE4C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD6AD8F1-7AE1-4BFC-A7EB-5F5B37EFE4C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD6AD8F1-7AE1-4BFC-A7EB-5F5B37EFE4C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD6AD8F1-7AE1-4BFC-A7EB-5F5B37EFE4C0}.Release|Any CPU.Build.0 = Release|Any CPU + {A5F3E468-7A97-4C71-8E75-CD2CAF8B477C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5F3E468-7A97-4C71-8E75-CD2CAF8B477C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5F3E468-7A97-4C71-8E75-CD2CAF8B477C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5F3E468-7A97-4C71-8E75-CD2CAF8B477C}.Release|Any CPU.Build.0 = Release|Any CPU + {970FFDEE-6F66-49FD-B41F-EBC8F50C547C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {970FFDEE-6F66-49FD-B41F-EBC8F50C547C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {970FFDEE-6F66-49FD-B41F-EBC8F50C547C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {970FFDEE-6F66-49FD-B41F-EBC8F50C547C}.Release|Any CPU.Build.0 = Release|Any CPU + {9696C45A-97A2-445E-BE10-BB3EE320BFDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9696C45A-97A2-445E-BE10-BB3EE320BFDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9696C45A-97A2-445E-BE10-BB3EE320BFDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9696C45A-97A2-445E-BE10-BB3EE320BFDF}.Release|Any CPU.Build.0 = Release|Any CPU + {68B73E29-9E25-4BCA-B077-400F6B2B450B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68B73E29-9E25-4BCA-B077-400F6B2B450B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68B73E29-9E25-4BCA-B077-400F6B2B450B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68B73E29-9E25-4BCA-B077-400F6B2B450B}.Release|Any CPU.Build.0 = Release|Any CPU + {20B46C82-119A-F5E9-8B57-A756A827F265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20B46C82-119A-F5E9-8B57-A756A827F265}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20B46C82-119A-F5E9-8B57-A756A827F265}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20B46C82-119A-F5E9-8B57-A756A827F265}.Release|Any CPU.Build.0 = Release|Any CPU + {19039AC1-EE08-460B-821B-0277442D04D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19039AC1-EE08-460B-821B-0277442D04D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19039AC1-EE08-460B-821B-0277442D04D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19039AC1-EE08-460B-821B-0277442D04D1}.Release|Any CPU.Build.0 = Release|Any CPU + {766E76F2-BAFF-4352-B376-15F6DE8BE4D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {766E76F2-BAFF-4352-B376-15F6DE8BE4D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {766E76F2-BAFF-4352-B376-15F6DE8BE4D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {766E76F2-BAFF-4352-B376-15F6DE8BE4D9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {15E7E724-DCEE-49C0-90C5-A55F1E2F06BD} + EndGlobalSection +EndGlobal