adding despesas e receitas
This commit is contained in:
parent
b9908b36b7
commit
9a107ce9e8
@ -22,6 +22,11 @@ namespace OpenCand.API.Controllers
|
|||||||
[EnableRateLimiting(RateLimitingConfig.CandidatoSearchPolicy)]
|
[EnableRateLimiting(RateLimitingConfig.CandidatoSearchPolicy)]
|
||||||
public async Task<CandidatoSearchResult> CandidatoSearch([FromQuery] string q)
|
public async Task<CandidatoSearchResult> CandidatoSearch([FromQuery] string q)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(q) || q.Length == 1)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Query parameter 'q' cannot be null/empty.", nameof(q));
|
||||||
|
}
|
||||||
|
|
||||||
return await openCandService.SearchCandidatosAsync(q);
|
return await openCandService.SearchCandidatosAsync(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,5 +57,17 @@ namespace OpenCand.API.Controllers
|
|||||||
await Task.Delay(randomWait);
|
await Task.Delay(randomWait);
|
||||||
return await openCandService.GetCandidatoCpfById(id);
|
return await openCandService.GetCandidatoCpfById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}/despesas")]
|
||||||
|
public async Task<DespesasResult> GetCandidatoDespesas([FromRoute] Guid id)
|
||||||
|
{
|
||||||
|
return await openCandService.GetDespesasByIdAndYear(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id}/receitas")]
|
||||||
|
public async Task<ReceitaResult> GetCandidatoReceitas([FromRoute] Guid id)
|
||||||
|
{
|
||||||
|
return await openCandService.GetReceitasByIdAndYear(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,14 @@ namespace OpenCand.API.Model
|
|||||||
{
|
{
|
||||||
public string Cpf { get; set; }
|
public string Cpf { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class DespesasResult
|
||||||
|
{
|
||||||
|
public List<Despesa> Despesas { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReceitaResult
|
||||||
|
{
|
||||||
|
public List<Receita> Receitas { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ namespace OpenCand.API
|
|||||||
builder.Services.AddScoped<OpenCandRepository>();
|
builder.Services.AddScoped<OpenCandRepository>();
|
||||||
builder.Services.AddScoped<CandidatoRepository>();
|
builder.Services.AddScoped<CandidatoRepository>();
|
||||||
builder.Services.AddScoped<BemCandidatoRepository>();
|
builder.Services.AddScoped<BemCandidatoRepository>();
|
||||||
|
builder.Services.AddScoped<DespesaReceitaRepository>();
|
||||||
builder.Services.AddScoped<OpenCandService>();
|
builder.Services.AddScoped<OpenCandService>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
OpenCand.API/Repository/DespesaReceitaRepository.cs
Normal file
42
OpenCand.API/Repository/DespesaReceitaRepository.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Npgsql;
|
||||||
|
using OpenCand.Core.Models;
|
||||||
|
|
||||||
|
namespace OpenCand.Repository
|
||||||
|
{
|
||||||
|
public class DespesaReceitaRepository : BaseRepository
|
||||||
|
{
|
||||||
|
public DespesaReceitaRepository(IConfiguration configuration) : base(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Despesa>> GetDespesasByCandidatoIdYearAsync(Guid idcandidato)
|
||||||
|
{
|
||||||
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
return (await connection.QueryAsync<Despesa>(@"
|
||||||
|
SELECT * FROM despesas_candidato
|
||||||
|
WHERE idcandidato = @idcandidato
|
||||||
|
ORDER BY valor DESC;", new
|
||||||
|
{
|
||||||
|
idcandidato
|
||||||
|
})).AsList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Receita>> GetReceitasByCandidatoIdYearAsync(Guid idcandidato)
|
||||||
|
{
|
||||||
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
return (await connection.QueryAsync<Receita>(@"
|
||||||
|
SELECT * FROM receitas_candidato
|
||||||
|
WHERE idcandidato = @idcandidato
|
||||||
|
ORDER BY valor DESC;", new
|
||||||
|
{
|
||||||
|
idcandidato
|
||||||
|
})).AsList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ namespace OpenCand.API.Services
|
|||||||
private readonly OpenCandRepository openCandRepository;
|
private readonly OpenCandRepository openCandRepository;
|
||||||
private readonly CandidatoRepository candidatoRepository;
|
private readonly CandidatoRepository candidatoRepository;
|
||||||
private readonly BemCandidatoRepository bemCandidatoRepository;
|
private readonly BemCandidatoRepository bemCandidatoRepository;
|
||||||
|
private readonly DespesaReceitaRepository despesaReceitaRepository;
|
||||||
private readonly IConfiguration configuration;
|
private readonly IConfiguration configuration;
|
||||||
private readonly FotosSettings fotoSettings;
|
private readonly FotosSettings fotoSettings;
|
||||||
private readonly ILogger<OpenCandService> logger;
|
private readonly ILogger<OpenCandService> logger;
|
||||||
@ -20,6 +21,7 @@ namespace OpenCand.API.Services
|
|||||||
OpenCandRepository openCandRepository,
|
OpenCandRepository openCandRepository,
|
||||||
CandidatoRepository candidatoRepository,
|
CandidatoRepository candidatoRepository,
|
||||||
BemCandidatoRepository bemCandidatoRepository,
|
BemCandidatoRepository bemCandidatoRepository,
|
||||||
|
DespesaReceitaRepository despesaReceitaRepository,
|
||||||
IOptions<FotosSettings> fotoSettings,
|
IOptions<FotosSettings> fotoSettings,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
ILogger<OpenCandService> logger)
|
ILogger<OpenCandService> logger)
|
||||||
@ -27,6 +29,7 @@ namespace OpenCand.API.Services
|
|||||||
this.openCandRepository = openCandRepository;
|
this.openCandRepository = openCandRepository;
|
||||||
this.candidatoRepository = candidatoRepository;
|
this.candidatoRepository = candidatoRepository;
|
||||||
this.bemCandidatoRepository = bemCandidatoRepository;
|
this.bemCandidatoRepository = bemCandidatoRepository;
|
||||||
|
this.despesaReceitaRepository = despesaReceitaRepository;
|
||||||
this.fotoSettings = fotoSettings.Value;
|
this.fotoSettings = fotoSettings.Value;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
@ -113,5 +116,33 @@ namespace OpenCand.API.Services
|
|||||||
Cpf = result
|
Cpf = result
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<DespesasResult> GetDespesasByIdAndYear(Guid idcandidato)
|
||||||
|
{
|
||||||
|
var result = await despesaReceitaRepository.GetDespesasByCandidatoIdYearAsync(idcandidato);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return new DespesasResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DespesasResult()
|
||||||
|
{
|
||||||
|
Despesas = result.OrderByDescending(d => d.Ano).ThenByDescending(d => d.Valor).ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ReceitaResult> GetReceitasByIdAndYear(Guid idcandidato)
|
||||||
|
{
|
||||||
|
var result = await despesaReceitaRepository.GetReceitasByCandidatoIdYearAsync(idcandidato);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return new ReceitaResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReceitaResult()
|
||||||
|
{
|
||||||
|
Receitas = result.OrderByDescending(d => d.Ano).ThenByDescending(d => d.Valor).ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ namespace OpenCand.Core.Models
|
|||||||
public string Apelido { get; set; }
|
public string Apelido { get; set; }
|
||||||
public string SqCandidato { get; set; }
|
public string SqCandidato { get; set; }
|
||||||
public int Ano { get; set; }
|
public int Ano { get; set; }
|
||||||
|
public string Turno { get; set; }
|
||||||
public string TipoEleicao { get; set; }
|
public string TipoEleicao { get; set; }
|
||||||
public string SiglaUF { get; set; }
|
public string SiglaUF { get; set; }
|
||||||
public string NomeUE { get; set; }
|
public string NomeUE { get; set; }
|
||||||
|
25
OpenCand.Core/Models/Despesa.cs
Normal file
25
OpenCand.Core/Models/Despesa.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace OpenCand.Core.Models
|
||||||
|
{
|
||||||
|
public class Despesa
|
||||||
|
{
|
||||||
|
public Guid IdDespesa { get; set; }
|
||||||
|
public Guid IdCandidato { get; set; }
|
||||||
|
public int Ano { get; set; }
|
||||||
|
public int Turno { get; set; }
|
||||||
|
|
||||||
|
public string SqCandidato { get; set; }
|
||||||
|
|
||||||
|
public string SgPartido { get; set; }
|
||||||
|
public string TipoFornecedor { get; set; }
|
||||||
|
public string CpfFornecedor { get; set; }
|
||||||
|
public string CnpjFornecedor { get; set; }
|
||||||
|
public string NomeFornecedor { get; set; }
|
||||||
|
public string NomeFornecedorRFB { get; set; }
|
||||||
|
public string MunicipioFornecedor { get; set; }
|
||||||
|
public string TipoDocumento { get; set; }
|
||||||
|
public DateTime? DataDespesa { get; set; }
|
||||||
|
public string OrigemDespesa { get; set; }
|
||||||
|
public string Descricao { get; set; }
|
||||||
|
public float Valor { get; set; }
|
||||||
|
}
|
||||||
|
}
|
26
OpenCand.Core/Models/Receita.cs
Normal file
26
OpenCand.Core/Models/Receita.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
namespace OpenCand.Core.Models
|
||||||
|
{
|
||||||
|
public class Receita
|
||||||
|
{
|
||||||
|
public Guid IdReceita { get; set; }
|
||||||
|
public Guid IdCandidato { get; set; }
|
||||||
|
public int Ano { get; set; }
|
||||||
|
public int Turno { get; set; }
|
||||||
|
|
||||||
|
public string SqCandidato { get; set; }
|
||||||
|
|
||||||
|
public string SgPartido { get; set; }
|
||||||
|
public string FonteReceita { get; set; }
|
||||||
|
public string OrigemReceita { get; set; }
|
||||||
|
public string NaturezaReceita { get; set; }
|
||||||
|
public string EspecieReceita { get; set; }
|
||||||
|
public string CpfDoador { get; set; }
|
||||||
|
public string CnpjDoador { get; set; }
|
||||||
|
public string NomeDoador { get; set; }
|
||||||
|
public string NomeDoadorRFB { get; set; }
|
||||||
|
public string MunicipioDoador { get; set; }
|
||||||
|
public DateTime? DataReceita { get; set; }
|
||||||
|
public string Descricao { get; set; }
|
||||||
|
public float Valor { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,5 +5,7 @@ namespace OpenCand.Config
|
|||||||
public string CandidatosFolder { get; set; } = string.Empty;
|
public string CandidatosFolder { get; set; } = string.Empty;
|
||||||
public string BensCandidatosFolder { get; set; } = string.Empty;
|
public string BensCandidatosFolder { get; set; } = string.Empty;
|
||||||
public string RedesSociaisFolder { get; set; } = string.Empty;
|
public string RedesSociaisFolder { get; set; } = string.Empty;
|
||||||
|
public string ReceitaCandidatoFolder { get; set; } = string.Empty;
|
||||||
|
public string DespesaCandidatoFolder { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
OpenCand.ETL/Extensions/StringExtensions.cs
Normal file
12
OpenCand.ETL/Extensions/StringExtensions.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace OpenCand.ETL.Extensions
|
||||||
|
{
|
||||||
|
public static class StringExtensions
|
||||||
|
{
|
||||||
|
public static bool IsNullOrEmpty(this string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(value) ||
|
||||||
|
value == "#NE" ||
|
||||||
|
value == "#NULO";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +0,0 @@
|
|||||||
using CsvHelper.Configuration;
|
|
||||||
using OpenCand.Parser.Models;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace OpenCand.Parser.CsvMappers
|
|
||||||
{
|
|
||||||
public class BemCandidatoMap : ClassMap<BemCandidatoCSV>
|
|
||||||
{
|
|
||||||
public BemCandidatoMap()
|
|
||||||
{
|
|
||||||
AutoMap(CultureInfo.InvariantCulture);
|
|
||||||
// Explicitly handle any special mappings if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
using CsvHelper.Configuration;
|
|
||||||
using OpenCand.Parser.Models;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace OpenCand.Parser.CsvMappers
|
|
||||||
{
|
|
||||||
public class CandidatoMap : ClassMap<CandidatoCSV>
|
|
||||||
{
|
|
||||||
public CandidatoMap()
|
|
||||||
{
|
|
||||||
AutoMap(CultureInfo.InvariantCulture);
|
|
||||||
// Explicitly handle any special mappings if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
using System.Globalization;
|
|
||||||
using CsvHelper.Configuration;
|
|
||||||
using OpenCand.Parser.Models;
|
|
||||||
|
|
||||||
namespace OpenCand.ETL.Parser.CsvMappers
|
|
||||||
{
|
|
||||||
public class RedeSocialMap : ClassMap<BemCandidatoCSV>
|
|
||||||
{
|
|
||||||
public RedeSocialMap()
|
|
||||||
{
|
|
||||||
AutoMap(CultureInfo.InvariantCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -73,8 +73,10 @@ namespace OpenCand.Parser.Services
|
|||||||
{
|
{
|
||||||
if (columns.Length > headerCount)
|
if (columns.Length > headerCount)
|
||||||
{
|
{
|
||||||
logger.LogCritical($"FixCsvFile - Line {i + 1} has {columns.Length} columns, expected {headerCount}. Halting process.");
|
// logger.LogCritical($"FixCsvFile - Line {i + 1} has {columns.Length} columns, expected {headerCount}. Halting process.");
|
||||||
return string.Empty; // Critical error, cannot fix this line => needs manual intervention
|
// return string.Empty; // Critical error, cannot fix this line => needs manual intervention
|
||||||
|
// consider as normal line
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.LogWarning($"FixCsvFile - Line {i + 1} has {columns.Length} columns, expected {headerCount}. Attempting to fix [i = {lineJump}]...");
|
logger.LogWarning($"FixCsvFile - Line {i + 1} has {columns.Length} columns, expected {headerCount}. Attempting to fix [i = {lineJump}]...");
|
||||||
|
@ -11,6 +11,9 @@ namespace OpenCand.Parser.Models
|
|||||||
[Name("TP_ABRANGENCIA")]
|
[Name("TP_ABRANGENCIA")]
|
||||||
public string TipoAbrangencia { get; set; }
|
public string TipoAbrangencia { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_TURNO")]
|
||||||
|
public string Turno { get; set; }
|
||||||
|
|
||||||
[Name("SG_UF")]
|
[Name("SG_UF")]
|
||||||
public string SiglaUF { get; set; }
|
public string SiglaUF { get; set; }
|
||||||
|
|
||||||
|
97
OpenCand.ETL/Parser/Models/DespesasCSV.cs
Normal file
97
OpenCand.ETL/Parser/Models/DespesasCSV.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
using CsvHelper.Configuration.Attributes;
|
||||||
|
|
||||||
|
namespace OpenCand.Parser.Models
|
||||||
|
{
|
||||||
|
public class DespesasCSV
|
||||||
|
{
|
||||||
|
[Name("AA_ELEICAO")]
|
||||||
|
public int AnoEleicao { get; set; }
|
||||||
|
|
||||||
|
[Name("ST_TURNO")]
|
||||||
|
public string Turno { get; set; }
|
||||||
|
|
||||||
|
[Name("DT_PRESTACAO_CONTAS")]
|
||||||
|
public string DataPrestacaoContas { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_PRESTADOR_CONTAS")]
|
||||||
|
public string SequencialPrestadorContas { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_UF")]
|
||||||
|
public string SiglaUF { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_UE")]
|
||||||
|
public string NomeUE { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CNPJ_PRESTADOR_CONTA")]
|
||||||
|
public string CnpjPrestadorConta { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_CANDIDATO")]
|
||||||
|
public string SequencialCandidato { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CPF_CANDIDATO")]
|
||||||
|
public string CpfCandidato { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_PARTIDO")]
|
||||||
|
public string SiglaPartido { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_TIPO_FORNECEDOR")]
|
||||||
|
public string TipoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("CD_CNAE_FORNECEDOR")]
|
||||||
|
public string CodigoCnaeFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_CNAE_FORNECEDOR")]
|
||||||
|
public string DescricaoCnaeFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CPF_CNPJ_FORNECEDOR")]
|
||||||
|
public string CpfCnpjFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_FORNECEDOR")]
|
||||||
|
public string NomeFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_FORNECEDOR_RFB")]
|
||||||
|
public string NomeFornecedorRFB { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_UF_FORNECEDOR")]
|
||||||
|
public string SiglaUFFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_MUNICIPIO_FORNECEDOR")]
|
||||||
|
public string NomeMunicipioFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_CANDIDATO_FORNECEDOR")]
|
||||||
|
public string SequencialCandidatoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CANDIDATO_FORNECEDOR")]
|
||||||
|
public string NumeroCandidatoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_CARGO_FORNECEDOR")]
|
||||||
|
public string CargoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_PARTIDO_FORNECEDOR")]
|
||||||
|
public string NumeroPartidoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_PARTIDO_FORNECEDOR")]
|
||||||
|
public string SiglaPartidoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_PARTIDO_FORNECEDOR")]
|
||||||
|
public string NomePartidoFornecedor { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_TIPO_DOCUMENTO")]
|
||||||
|
public string TipoDocumento { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_ORIGEM_DESPESA")]
|
||||||
|
public string OrigemDespesa { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_DESPESA")]
|
||||||
|
public string SequencialDespesa { get; set; }
|
||||||
|
|
||||||
|
[Name("DT_DESPESA")]
|
||||||
|
public string DataDespesa { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_DESPESA")]
|
||||||
|
public string DescricaoDespesa { get; set; }
|
||||||
|
|
||||||
|
[Name("VR_DESPESA_CONTRATADA")]
|
||||||
|
public float ValorDespesaContratada { get; set; }
|
||||||
|
}
|
||||||
|
}
|
94
OpenCand.ETL/Parser/Models/ReceitasCSV.cs
Normal file
94
OpenCand.ETL/Parser/Models/ReceitasCSV.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using CsvHelper.Configuration.Attributes;
|
||||||
|
|
||||||
|
namespace OpenCand.Parser.Models
|
||||||
|
{
|
||||||
|
public class ReceitasCSV
|
||||||
|
{
|
||||||
|
[Name("AA_ELEICAO")]
|
||||||
|
public int AnoEleicao { get; set; }
|
||||||
|
|
||||||
|
[Name("ST_TURNO")]
|
||||||
|
public string Turno { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_PRESTADOR_CONTAS")]
|
||||||
|
public string SequencialPrestadorContas { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_UF")]
|
||||||
|
public string SiglaUF { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_UE")]
|
||||||
|
public string NomeUE { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CNPJ_PRESTADOR_CONTA")]
|
||||||
|
public string CnpjPrestadorConta { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_CANDIDATO")]
|
||||||
|
public string SequencialCandidato { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CPF_CANDIDATO")]
|
||||||
|
public string CpfCandidato { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_PARTIDO")]
|
||||||
|
public string SiglaPartido { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_FONTE_RECEITA")]
|
||||||
|
public string FonteReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_ORIGEM_RECEITA")]
|
||||||
|
public string OrigemReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_NATUREZA_RECEITA")]
|
||||||
|
public string NaturezaReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_ESPECIE_RECEITA")]
|
||||||
|
public string EspecieReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("CD_CNAE_DOADOR")]
|
||||||
|
public string CodigoCnaeDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_CNAE_DOADOR")]
|
||||||
|
public string DescricaoCnaeDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_CPF_CNPJ_DOADOR")]
|
||||||
|
public string CpfCnpjDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_DOADOR")]
|
||||||
|
public string NomeDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_DOADOR_RFB")]
|
||||||
|
public string NomeDoadorRFB { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_UF_DOADOR")]
|
||||||
|
public string SiglaUFDoaror { get; set; }
|
||||||
|
|
||||||
|
[Name("NM_MUNICIPIO_DOADOR")]
|
||||||
|
public string NomeMunicipioDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_CANDIDATO_DOADOR")]
|
||||||
|
public string SequencialCandidatoDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("SG_PARTIDO_DOADOR")]
|
||||||
|
public string SiglaPartidoDoador { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_RECIBO_DOACAO")]
|
||||||
|
public string NumeroReciboDoacao { get; set; }
|
||||||
|
|
||||||
|
[Name("NR_DOCUMENTO_DOACAO")]
|
||||||
|
public string NumeroDocumentoDoacao { get; set; }
|
||||||
|
|
||||||
|
[Name("SQ_RECEITA")]
|
||||||
|
public string SequencialReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("DT_RECEITA")]
|
||||||
|
public string DataReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_RECEITA")]
|
||||||
|
public string DescricaoReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("VR_RECEITA")]
|
||||||
|
public float ValorReceita { get; set; }
|
||||||
|
|
||||||
|
[Name("DS_GENERO")]
|
||||||
|
public string Genero { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,8 @@ namespace OpenCand.Parser
|
|||||||
private readonly CsvParserService<CandidatoCSV> candidatoParserService;
|
private readonly CsvParserService<CandidatoCSV> candidatoParserService;
|
||||||
private readonly CsvParserService<BemCandidatoCSV> bemCandidatoParserService;
|
private readonly CsvParserService<BemCandidatoCSV> bemCandidatoParserService;
|
||||||
private readonly CsvParserService<RedeSocialCSV> redeSocialParserService;
|
private readonly CsvParserService<RedeSocialCSV> redeSocialParserService;
|
||||||
|
private readonly CsvParserService<DespesasCSV> despesaParserService;
|
||||||
|
private readonly CsvParserService<ReceitasCSV> receitaParserService;
|
||||||
|
|
||||||
private readonly string BasePath;
|
private readonly string BasePath;
|
||||||
|
|
||||||
@ -24,7 +26,9 @@ namespace OpenCand.Parser
|
|||||||
IConfiguration configuration,
|
IConfiguration configuration,
|
||||||
CsvParserService<CandidatoCSV> candidatoParserService,
|
CsvParserService<CandidatoCSV> candidatoParserService,
|
||||||
CsvParserService<BemCandidatoCSV> bemCandidatoParserService,
|
CsvParserService<BemCandidatoCSV> bemCandidatoParserService,
|
||||||
CsvParserService<RedeSocialCSV> redeSocialParserService)
|
CsvParserService<RedeSocialCSV> redeSocialParserService,
|
||||||
|
CsvParserService<DespesasCSV> despesaParserService,
|
||||||
|
CsvParserService<ReceitasCSV> receitaParserService)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.csvSettings = csvSettings.Value;
|
this.csvSettings = csvSettings.Value;
|
||||||
@ -32,6 +36,8 @@ namespace OpenCand.Parser
|
|||||||
this.candidatoParserService = candidatoParserService;
|
this.candidatoParserService = candidatoParserService;
|
||||||
this.bemCandidatoParserService = bemCandidatoParserService;
|
this.bemCandidatoParserService = bemCandidatoParserService;
|
||||||
this.redeSocialParserService = redeSocialParserService;
|
this.redeSocialParserService = redeSocialParserService;
|
||||||
|
this.despesaParserService = despesaParserService;
|
||||||
|
this.receitaParserService = receitaParserService;
|
||||||
|
|
||||||
// Get the base path from either SampleFolder in csvSettings or the BasePath in configuration
|
// Get the base path from either SampleFolder in csvSettings or the BasePath in configuration
|
||||||
BasePath = configuration.GetValue<string>("BasePath") ?? string.Empty;
|
BasePath = configuration.GetValue<string>("BasePath") ?? string.Empty;
|
||||||
@ -49,10 +55,14 @@ namespace OpenCand.Parser
|
|||||||
var candidatosDirectory = Path.Combine(BasePath, csvSettings.CandidatosFolder);
|
var candidatosDirectory = Path.Combine(BasePath, csvSettings.CandidatosFolder);
|
||||||
var bensCandidatosDirectory = Path.Combine(BasePath, csvSettings.BensCandidatosFolder);
|
var bensCandidatosDirectory = Path.Combine(BasePath, csvSettings.BensCandidatosFolder);
|
||||||
var redesSociaisDirectory = Path.Combine(BasePath, csvSettings.RedesSociaisFolder);
|
var redesSociaisDirectory = Path.Combine(BasePath, csvSettings.RedesSociaisFolder);
|
||||||
|
var despesasDirectory = Path.Combine(BasePath, csvSettings.DespesaCandidatoFolder);
|
||||||
|
var receitasDirectory = Path.Combine(BasePath, csvSettings.ReceitaCandidatoFolder);
|
||||||
|
|
||||||
await ParseFolder(candidatosDirectory, candidatoParserService);
|
//await ParseFolder(candidatosDirectory, candidatoParserService);
|
||||||
await ParseFolder(bensCandidatosDirectory, bemCandidatoParserService);
|
//await ParseFolder(bensCandidatosDirectory, bemCandidatoParserService);
|
||||||
await ParseFolder(redesSociaisDirectory, redeSocialParserService);
|
//await ParseFolder(redesSociaisDirectory, redeSocialParserService);
|
||||||
|
await ParseFolder(despesasDirectory, despesaParserService);
|
||||||
|
await ParseFolder(receitasDirectory, receitaParserService);
|
||||||
|
|
||||||
logger.LogInformation("ParseFullDataAsync - Full data parsing completed!");
|
logger.LogInformation("ParseFullDataAsync - Full data parsing completed!");
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using OpenCand.ETL.Contracts;
|
|||||||
using OpenCand.Parser.Models;
|
using OpenCand.Parser.Models;
|
||||||
using OpenCand.Services;
|
using OpenCand.Services;
|
||||||
using OpenCand.Parser.Services;
|
using OpenCand.Parser.Services;
|
||||||
|
using OpenCand.ETL.Extensions;
|
||||||
|
|
||||||
namespace OpenCand.ETL.Parser.ParserServices
|
namespace OpenCand.ETL.Parser.ParserServices
|
||||||
{
|
{
|
||||||
@ -25,7 +26,7 @@ namespace OpenCand.ETL.Parser.ParserServices
|
|||||||
{
|
{
|
||||||
// Parse decimal value
|
// Parse decimal value
|
||||||
decimal? valor = null;
|
decimal? valor = null;
|
||||||
if (!string.IsNullOrEmpty(record.ValorBemCandidato))
|
if (!record.ValorBemCandidato.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
string normalizedValue = record.ValorBemCandidato.Replace(".", "").Replace(",", ".");
|
string normalizedValue = record.ValorBemCandidato.Replace(".", "").Replace(",", ".");
|
||||||
if (decimal.TryParse(normalizedValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var parsedValue))
|
if (decimal.TryParse(normalizedValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var parsedValue))
|
||||||
|
@ -63,6 +63,7 @@ namespace OpenCand.ETL.Parser.ParserServices
|
|||||||
Apelido = record.Apelido,
|
Apelido = record.Apelido,
|
||||||
SqCandidato = record.SequencialCandidato,
|
SqCandidato = record.SequencialCandidato,
|
||||||
Ano = record.AnoEleicao,
|
Ano = record.AnoEleicao,
|
||||||
|
Turno = record.Turno,
|
||||||
TipoEleicao = record.TipoAbrangencia,
|
TipoEleicao = record.TipoAbrangencia,
|
||||||
NomeUE = record.NomeUE,
|
NomeUE = record.NomeUE,
|
||||||
SiglaUF = record.SiglaUF,
|
SiglaUF = record.SiglaUF,
|
||||||
|
88
OpenCand.ETL/Parser/ParserServices/DespesaParserService.cs
Normal file
88
OpenCand.ETL/Parser/ParserServices/DespesaParserService.cs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using OpenCand.Core.Models;
|
||||||
|
using OpenCand.ETL.Contracts;
|
||||||
|
using OpenCand.ETL.Extensions;
|
||||||
|
using OpenCand.ETL.Services;
|
||||||
|
using OpenCand.Parser.Models;
|
||||||
|
|
||||||
|
namespace OpenCand.ETL.Parser.ParserServices
|
||||||
|
{
|
||||||
|
public class DespesaParserService : IParserService<DespesasCSV>
|
||||||
|
{
|
||||||
|
private readonly ILogger<DespesaParserService> logger;
|
||||||
|
private readonly DespesaReceitaService despesaReceitaService;
|
||||||
|
|
||||||
|
public DespesaParserService(
|
||||||
|
ILogger<DespesaParserService> logger,
|
||||||
|
DespesaReceitaService despesaReceitaService)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.despesaReceitaService = despesaReceitaService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ParseObject(DespesasCSV record)
|
||||||
|
{
|
||||||
|
var despesa = new Despesa
|
||||||
|
{
|
||||||
|
SgPartido = record.SiglaPartido,
|
||||||
|
Ano = record.AnoEleicao,
|
||||||
|
Turno = int.Parse(record.Turno),
|
||||||
|
Descricao = record.DescricaoDespesa,
|
||||||
|
OrigemDespesa = record.OrigemDespesa,
|
||||||
|
MunicipioFornecedor = record.NomeMunicipioFornecedor,
|
||||||
|
NomeFornecedor = record.NomeFornecedor,
|
||||||
|
NomeFornecedorRFB = record.NomeFornecedorRFB,
|
||||||
|
SqCandidato = record.SequencialCandidato,
|
||||||
|
TipoDocumento = record.TipoDocumento,
|
||||||
|
TipoFornecedor = record.TipoFornecedor,
|
||||||
|
Valor = record.ValorDespesaContratada / 100
|
||||||
|
};
|
||||||
|
|
||||||
|
if (DateTime.TryParse(record.DataDespesa, out var dataDespesa))
|
||||||
|
{
|
||||||
|
despesa.DataDespesa = dataDespesa;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
despesa.DataDespesa = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.CpfCnpjFornecedor.Length == 0 || record.CpfCnpjFornecedor == "-4")
|
||||||
|
{
|
||||||
|
despesa.CpfFornecedor = null;
|
||||||
|
despesa.CnpjFornecedor = null;
|
||||||
|
}
|
||||||
|
else if (record.CpfCnpjFornecedor.Length == 11)
|
||||||
|
{
|
||||||
|
despesa.CpfFornecedor = record.CpfCnpjFornecedor;
|
||||||
|
despesa.CnpjFornecedor = null;
|
||||||
|
}
|
||||||
|
else if (record.CpfCnpjFornecedor.Length == 14)
|
||||||
|
{
|
||||||
|
despesa.CnpjFornecedor = record.CpfCnpjFornecedor;
|
||||||
|
despesa.CpfFornecedor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (despesa.Descricao.IsNullOrEmpty())
|
||||||
|
despesa.Descricao = null;
|
||||||
|
if (despesa.OrigemDespesa.IsNullOrEmpty())
|
||||||
|
despesa.OrigemDespesa = null;
|
||||||
|
if (despesa.MunicipioFornecedor.IsNullOrEmpty())
|
||||||
|
despesa.MunicipioFornecedor = null;
|
||||||
|
if (despesa.NomeFornecedor.IsNullOrEmpty())
|
||||||
|
despesa.NomeFornecedor = null;
|
||||||
|
if (despesa.NomeFornecedorRFB.IsNullOrEmpty())
|
||||||
|
despesa.NomeFornecedorRFB = null;
|
||||||
|
if (despesa.TipoDocumento.IsNullOrEmpty())
|
||||||
|
despesa.TipoDocumento = null;
|
||||||
|
if (despesa.CpfFornecedor.IsNullOrEmpty())
|
||||||
|
despesa.CpfFornecedor = null;
|
||||||
|
if (despesa.CnpjFornecedor.IsNullOrEmpty())
|
||||||
|
despesa.CnpjFornecedor = null;
|
||||||
|
if (despesa.TipoFornecedor.IsNullOrEmpty())
|
||||||
|
despesa.TipoFornecedor = null;
|
||||||
|
|
||||||
|
await despesaReceitaService.AddDespesaAsync(despesa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
OpenCand.ETL/Parser/ParserServices/ReceitaParserService.cs
Normal file
84
OpenCand.ETL/Parser/ParserServices/ReceitaParserService.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using OpenCand.Core.Models;
|
||||||
|
using OpenCand.ETL.Contracts;
|
||||||
|
using OpenCand.ETL.Extensions;
|
||||||
|
using OpenCand.ETL.Services;
|
||||||
|
using OpenCand.Parser.Models;
|
||||||
|
|
||||||
|
namespace OpenCand.ETL.Parser.ParserServices
|
||||||
|
{
|
||||||
|
public class ReceitaParserService : IParserService<ReceitasCSV>
|
||||||
|
{
|
||||||
|
private readonly ILogger<ReceitaParserService> logger;
|
||||||
|
private readonly DespesaReceitaService despesaReceitaService;
|
||||||
|
|
||||||
|
public ReceitaParserService(
|
||||||
|
ILogger<ReceitaParserService> logger,
|
||||||
|
DespesaReceitaService despesaReceitaService)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
this.despesaReceitaService = despesaReceitaService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ParseObject(ReceitasCSV record)
|
||||||
|
{
|
||||||
|
var receita = new Receita
|
||||||
|
{
|
||||||
|
EspecieReceita = record.EspecieReceita,
|
||||||
|
MunicipioDoador = record.NomeMunicipioDoador,
|
||||||
|
SgPartido = record.SiglaPartido,
|
||||||
|
FonteReceita = record.FonteReceita,
|
||||||
|
NaturezaReceita = record.NaturezaReceita,
|
||||||
|
Ano = record.AnoEleicao,
|
||||||
|
Descricao = record.DescricaoReceita,
|
||||||
|
NomeDoador = record.NomeDoador,
|
||||||
|
NomeDoadorRFB = record.NomeDoadorRFB,
|
||||||
|
OrigemReceita = record.OrigemReceita,
|
||||||
|
Turno = int.Parse(record.Turno),
|
||||||
|
SqCandidato = record.SequencialCandidato,
|
||||||
|
Valor = record.ValorReceita / 100
|
||||||
|
};
|
||||||
|
|
||||||
|
if (DateTime.TryParse(record.DataReceita, out var dataReceita))
|
||||||
|
{
|
||||||
|
receita.DataReceita = dataReceita;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
receita.DataReceita = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.CpfCnpjDoador.Length == 0 || record.CpfCnpjDoador == "-4") {
|
||||||
|
receita.CpfDoador = null;
|
||||||
|
receita.CnpjDoador = null;
|
||||||
|
}
|
||||||
|
else if (record.CpfCnpjDoador.Length == 11)
|
||||||
|
{
|
||||||
|
receita.CpfDoador = record.CpfCnpjDoador;
|
||||||
|
receita.CnpjDoador = null;
|
||||||
|
}
|
||||||
|
else if (record.CpfCnpjDoador.Length == 14)
|
||||||
|
{
|
||||||
|
receita.CnpjDoador = record.CpfCnpjDoador;
|
||||||
|
receita.CpfDoador = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receita.Descricao.IsNullOrEmpty())
|
||||||
|
receita.Descricao = null;
|
||||||
|
if (receita.MunicipioDoador.IsNullOrEmpty())
|
||||||
|
receita.MunicipioDoador = null;
|
||||||
|
if (receita.NomeDoador.IsNullOrEmpty())
|
||||||
|
receita.NomeDoador = null;
|
||||||
|
if (receita.NomeDoadorRFB.IsNullOrEmpty())
|
||||||
|
receita.NomeDoadorRFB = null;
|
||||||
|
if (receita.OrigemReceita.IsNullOrEmpty())
|
||||||
|
receita.OrigemReceita = null;
|
||||||
|
if (receita.CpfDoador.IsNullOrEmpty())
|
||||||
|
receita.CpfDoador = null;
|
||||||
|
if (receita.CnpjDoador.IsNullOrEmpty())
|
||||||
|
receita.CnpjDoador = null;
|
||||||
|
|
||||||
|
await despesaReceitaService.AddReceitaAsync(receita);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using OpenCand.Config;
|
|||||||
using OpenCand.ETL.Contracts;
|
using OpenCand.ETL.Contracts;
|
||||||
using OpenCand.ETL.Parser.ParserServices;
|
using OpenCand.ETL.Parser.ParserServices;
|
||||||
using OpenCand.ETL.Repository;
|
using OpenCand.ETL.Repository;
|
||||||
|
using OpenCand.ETL.Services;
|
||||||
using OpenCand.Parser;
|
using OpenCand.Parser;
|
||||||
using OpenCand.Parser.Models;
|
using OpenCand.Parser.Models;
|
||||||
using OpenCand.Parser.Services;
|
using OpenCand.Parser.Services;
|
||||||
@ -60,13 +61,19 @@ namespace OpenCand
|
|||||||
services.AddTransient<IParserService<CandidatoCSV>, CandidatoParserService>();
|
services.AddTransient<IParserService<CandidatoCSV>, CandidatoParserService>();
|
||||||
services.AddTransient<IParserService<BemCandidatoCSV>, BemCandidatoParserService>();
|
services.AddTransient<IParserService<BemCandidatoCSV>, BemCandidatoParserService>();
|
||||||
services.AddTransient<IParserService<RedeSocialCSV>, RedeSocialParserService>();
|
services.AddTransient<IParserService<RedeSocialCSV>, RedeSocialParserService>();
|
||||||
|
services.AddTransient<IParserService<DespesasCSV>, DespesaParserService>();
|
||||||
|
services.AddTransient<IParserService<ReceitasCSV>, ReceitaParserService>();
|
||||||
services.AddTransient<CsvParserService<CandidatoCSV>>();
|
services.AddTransient<CsvParserService<CandidatoCSV>>();
|
||||||
services.AddTransient<CsvParserService<BemCandidatoCSV>>();
|
services.AddTransient<CsvParserService<BemCandidatoCSV>>();
|
||||||
services.AddTransient<CsvParserService<RedeSocialCSV>>();
|
services.AddTransient<CsvParserService<RedeSocialCSV>>();
|
||||||
|
services.AddTransient<CsvParserService<DespesasCSV>>();
|
||||||
|
services.AddTransient<CsvParserService<ReceitasCSV>>();
|
||||||
services.AddTransient<ParserManager>();
|
services.AddTransient<ParserManager>();
|
||||||
|
services.AddTransient<DespesaReceitaService>();
|
||||||
services.AddTransient<CandidatoService>();
|
services.AddTransient<CandidatoService>();
|
||||||
services.AddTransient<BemCandidatoService>();
|
services.AddTransient<BemCandidatoService>();
|
||||||
services.AddTransient<RedeSocialService>();
|
services.AddTransient<RedeSocialService>();
|
||||||
|
services.AddTransient<DespesaReceitaRepository>();
|
||||||
services.AddTransient<CandidatoRepository>();
|
services.AddTransient<CandidatoRepository>();
|
||||||
services.AddTransient<BemCandidatoRepository>();
|
services.AddTransient<BemCandidatoRepository>();
|
||||||
services.AddTransient<RedeSocialRepository>();
|
services.AddTransient<RedeSocialRepository>();
|
||||||
|
@ -49,8 +49,8 @@ namespace OpenCand.Repository
|
|||||||
using (var connection = new NpgsqlConnection(ConnectionString))
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
{
|
{
|
||||||
await connection.ExecuteAsync(@"
|
await connection.ExecuteAsync(@"
|
||||||
INSERT INTO candidato_mapping (idcandidato, cpf, nome, apelido, sqcandidato, ano, tipoeleicao, siglauf, nomeue, cargo, nrcandidato, sgpartido, resultado)
|
INSERT INTO candidato_mapping (idcandidato, cpf, nome, apelido, sqcandidato, ano, turno, tipoeleicao, siglauf, nomeue, cargo, nrcandidato, sgpartido, resultado)
|
||||||
VALUES (@idcandidato, @cpf, @nome, @apelido, @sqcandidato, @ano, @tipoeleicao, @siglauf, @nomeue, @cargo, @nrcandidato, @sgpartido, @resultado)
|
VALUES (@idcandidato, @cpf, @nome, @apelido, @sqcandidato, @ano, @turno, @tipoeleicao, @siglauf, @nomeue, @cargo, @nrcandidato, @sgpartido, @resultado)
|
||||||
ON CONFLICT DO NOTHING;",
|
ON CONFLICT DO NOTHING;",
|
||||||
new
|
new
|
||||||
{
|
{
|
||||||
@ -60,6 +60,7 @@ namespace OpenCand.Repository
|
|||||||
apelido = candidatoMapping.Apelido,
|
apelido = candidatoMapping.Apelido,
|
||||||
sqcandidato = candidatoMapping.SqCandidato,
|
sqcandidato = candidatoMapping.SqCandidato,
|
||||||
ano = candidatoMapping.Ano,
|
ano = candidatoMapping.Ano,
|
||||||
|
turno = candidatoMapping.Turno,
|
||||||
tipoeleicao = candidatoMapping.TipoEleicao,
|
tipoeleicao = candidatoMapping.TipoEleicao,
|
||||||
siglauf = candidatoMapping.SiglaUF,
|
siglauf = candidatoMapping.SiglaUF,
|
||||||
nomeue = candidatoMapping.NomeUE,
|
nomeue = candidatoMapping.NomeUE,
|
||||||
@ -83,6 +84,18 @@ namespace OpenCand.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Guid?> GetIdCandidatoBySqCandidato(string sqcandidato)
|
||||||
|
{
|
||||||
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var query = @"
|
||||||
|
SELECT idcandidato
|
||||||
|
FROM candidato_mapping
|
||||||
|
WHERE sqcandidato = @sqcandidato";
|
||||||
|
return await connection.QueryFirstOrDefaultAsync<Guid>(query, new { sqcandidato });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Candidato?> GetCandidatoByNome(string nome, DateTime datanascimento)
|
public async Task<Candidato?> GetCandidatoByNome(string nome, DateTime datanascimento)
|
||||||
{
|
{
|
||||||
using (var connection = new NpgsqlConnection(ConnectionString))
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
|
139
OpenCand.ETL/Repository/DespesaReceitaRepository.cs
Normal file
139
OpenCand.ETL/Repository/DespesaReceitaRepository.cs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Npgsql;
|
||||||
|
using OpenCand.Core.Models;
|
||||||
|
|
||||||
|
namespace OpenCand.Repository
|
||||||
|
{
|
||||||
|
public class DespesaReceitaRepository : BaseRepository
|
||||||
|
{
|
||||||
|
public DespesaReceitaRepository(IConfiguration configuration) : base(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddDespesaAsync(Despesa despesa)
|
||||||
|
{
|
||||||
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
await connection.ExecuteAsync(@"
|
||||||
|
INSERT INTO despesas_candidato (
|
||||||
|
idcandidato,
|
||||||
|
ano,
|
||||||
|
turno,
|
||||||
|
sqcandidato,
|
||||||
|
sgpartido,
|
||||||
|
tipofornecedor,
|
||||||
|
cnpjfornecedor,
|
||||||
|
cpffornecedor,
|
||||||
|
nomefornecedor,
|
||||||
|
nomefornecedorrfb,
|
||||||
|
municipiofornecedor,
|
||||||
|
tipodocumento,
|
||||||
|
datadespesa,
|
||||||
|
descricao,
|
||||||
|
origemdespesa,
|
||||||
|
valor
|
||||||
|
) VALUES (
|
||||||
|
@idCandidato,
|
||||||
|
@ano,
|
||||||
|
@turno,
|
||||||
|
@sqCandidato,
|
||||||
|
@sgPartido,
|
||||||
|
@tipoFornecedor,
|
||||||
|
@cnpjFornecedor,
|
||||||
|
@cpfFornecedor,
|
||||||
|
@nomeFornecedor,
|
||||||
|
@nomeFornecedorRFB,
|
||||||
|
@municipioFornecedor,
|
||||||
|
@tipoDocumento,
|
||||||
|
@dataDespesa,
|
||||||
|
@descricao,
|
||||||
|
@origemdespesa,
|
||||||
|
@valor
|
||||||
|
)", new
|
||||||
|
{
|
||||||
|
idCandidato = despesa.IdCandidato,
|
||||||
|
ano = despesa.Ano,
|
||||||
|
turno = despesa.Turno,
|
||||||
|
sqCandidato = despesa.SqCandidato,
|
||||||
|
sgPartido = despesa.SgPartido,
|
||||||
|
tipoFornecedor = despesa.TipoFornecedor,
|
||||||
|
cnpjFornecedor = despesa.CnpjFornecedor,
|
||||||
|
cpfFornecedor = despesa.CpfFornecedor,
|
||||||
|
nomeFornecedor = despesa.NomeFornecedor,
|
||||||
|
nomeFornecedorRFB = despesa.NomeFornecedorRFB,
|
||||||
|
municipioFornecedor = despesa.MunicipioFornecedor,
|
||||||
|
tipoDocumento = despesa.TipoDocumento,
|
||||||
|
dataDespesa = despesa.DataDespesa,
|
||||||
|
descricao = despesa.Descricao,
|
||||||
|
origemdespesa = despesa.OrigemDespesa,
|
||||||
|
valor = despesa.Valor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddReceitaAsync(Receita receita)
|
||||||
|
{
|
||||||
|
using (var connection = new NpgsqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
await connection.ExecuteAsync(@"
|
||||||
|
INSERT INTO receitas_candidato (
|
||||||
|
idcandidato,
|
||||||
|
ano,
|
||||||
|
turno,
|
||||||
|
sqcandidato,
|
||||||
|
sgpartido,
|
||||||
|
fontereceita,
|
||||||
|
origemreceita,
|
||||||
|
naturezareceita,
|
||||||
|
especiereceita,
|
||||||
|
cnpjdoador,
|
||||||
|
cpfdoador,
|
||||||
|
nomedoador,
|
||||||
|
nomedoadorrfb,
|
||||||
|
municipiodoador,
|
||||||
|
datareceita,
|
||||||
|
descricao,
|
||||||
|
valor
|
||||||
|
) VALUES (
|
||||||
|
@idCandidato,
|
||||||
|
@ano,
|
||||||
|
@turno,
|
||||||
|
@sqCandidato,
|
||||||
|
@sgPartido,
|
||||||
|
@fonteReceita,
|
||||||
|
@origemReceita,
|
||||||
|
@naturezaReceita,
|
||||||
|
@especieReceita,
|
||||||
|
@cnpjDoador,
|
||||||
|
@cpfDoador,
|
||||||
|
@nomeDoador,
|
||||||
|
@nomeDoadorRFB,
|
||||||
|
@municipioDoador,
|
||||||
|
@dataReceita,
|
||||||
|
@descricao,
|
||||||
|
@valor
|
||||||
|
)", new
|
||||||
|
{
|
||||||
|
idCandidato = receita.IdCandidato,
|
||||||
|
ano = receita.Ano,
|
||||||
|
turno = receita.Turno,
|
||||||
|
sqCandidato = receita.SqCandidato,
|
||||||
|
sgPartido = receita.SgPartido,
|
||||||
|
fonteReceita = receita.FonteReceita,
|
||||||
|
origemReceita = receita.OrigemReceita,
|
||||||
|
naturezaReceita = receita.NaturezaReceita,
|
||||||
|
especieReceita = receita.EspecieReceita,
|
||||||
|
cnpjDoador = receita.CnpjDoador,
|
||||||
|
cpfDoador = receita.CpfDoador,
|
||||||
|
nomeDoador = receita.NomeDoador,
|
||||||
|
nomeDoadorRFB = receita.NomeDoadorRFB,
|
||||||
|
municipioDoador = receita.MunicipioDoador,
|
||||||
|
dataReceita = receita.DataReceita,
|
||||||
|
descricao = receita.Descricao,
|
||||||
|
valor = receita.Valor
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
OpenCand.ETL/Services/DespesaReceitaService.cs
Normal file
54
OpenCand.ETL/Services/DespesaReceitaService.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using OpenCand.Core.Models;
|
||||||
|
using OpenCand.Repository;
|
||||||
|
|
||||||
|
namespace OpenCand.ETL.Services
|
||||||
|
{
|
||||||
|
public class DespesaReceitaService
|
||||||
|
{
|
||||||
|
private readonly DespesaReceitaRepository despesaReceitaRepository;
|
||||||
|
private readonly CandidatoRepository candidatorepository;
|
||||||
|
|
||||||
|
public DespesaReceitaService(DespesaReceitaRepository despesaReceitaRepository, CandidatoRepository candidatoRepository)
|
||||||
|
{
|
||||||
|
this.despesaReceitaRepository = despesaReceitaRepository;
|
||||||
|
this.candidatorepository = candidatoRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddDespesaAsync(Despesa despesa)
|
||||||
|
{
|
||||||
|
if (despesa == null || string.IsNullOrEmpty(despesa.SqCandidato))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(despesa), "Despesa cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
var idCandidato = await candidatorepository.GetIdCandidatoBySqCandidato(despesa.SqCandidato);
|
||||||
|
if (idCandidato == Guid.Empty)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Candidato with SqCandidato {despesa.SqCandidato} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
despesa.IdCandidato = (Guid)idCandidato;
|
||||||
|
|
||||||
|
await despesaReceitaRepository.AddDespesaAsync(despesa);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddReceitaAsync(Receita receita)
|
||||||
|
{
|
||||||
|
if (receita == null || string.IsNullOrEmpty(receita.SqCandidato))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(receita), "Receita cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
var idCandidato = await candidatorepository.GetIdCandidatoBySqCandidato(receita.SqCandidato);
|
||||||
|
if (idCandidato == Guid.Empty)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Candidato with SqCandidato {receita.SqCandidato} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
receita.IdCandidato = (Guid)idCandidato;
|
||||||
|
|
||||||
|
await despesaReceitaRepository.AddReceitaAsync(receita);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -12,11 +12,15 @@
|
|||||||
"CsvSettings": {
|
"CsvSettings": {
|
||||||
"CandidatosFolder": "data/consulta_cand",
|
"CandidatosFolder": "data/consulta_cand",
|
||||||
"BensCandidatosFolder": "data/bem_candidato",
|
"BensCandidatosFolder": "data/bem_candidato",
|
||||||
"RedesSociaisFolder": "data/rede_social"
|
"RedesSociaisFolder": "data/rede_social",
|
||||||
|
"DespesaCandidatoFolder": "data/despesas_candidato",
|
||||||
|
"ReceitaCandidatoFolder": "data/receitas_candidato"
|
||||||
},
|
},
|
||||||
"ParserSettings": {
|
"ParserSettings": {
|
||||||
"DefaultThreads": 40,
|
"DefaultThreads": 40,
|
||||||
"CandidatoCSVThreads": 5
|
"CandidatoCSVThreads": 5,
|
||||||
|
"DepesasCSVThreads": 50,
|
||||||
|
"ReceitasCSVThreads": 50
|
||||||
},
|
},
|
||||||
"BasePath": "sample"
|
"BasePath": "sample"
|
||||||
}
|
}
|
||||||
|
89
README.md
89
README.md
@ -8,4 +8,91 @@ OpenCand is built using:
|
|||||||
* .NET 8 - for parsing initial information from CSV files to the PostgreSQL database using Entity Framework.
|
* .NET 8 - for parsing initial information from CSV files to the PostgreSQL database using Entity Framework.
|
||||||
* .NET Core 8 - for the API
|
* .NET Core 8 - for the API
|
||||||
* PostgreSQL - for the database
|
* PostgreSQL - for the database
|
||||||
* React - for the front-end
|
* React - for the front-end
|
||||||
|
|
||||||
|
## Disponibilidade de dados (Prod)
|
||||||
|
|
||||||
|
* ✅ = Disponível
|
||||||
|
* ❌ = Não disponível
|
||||||
|
* ⛔ = Sem dados
|
||||||
|
|
||||||
|
| Nome do dado | Ano | Disponível? |
|
||||||
|
|-------------------|------|-------------|
|
||||||
|
| Candidatos | 2024 | ✅ |
|
||||||
|
| Bem Candidato | 2024 | ✅ |
|
||||||
|
| Despesas/Receitas | 2024 | ✅ |
|
||||||
|
| Rede Social | 2024 | ✅ |
|
||||||
|
| Fotos | 2024 | ✅ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2022 | ✅ |
|
||||||
|
| Bem Candidato | 2022 | ✅ |
|
||||||
|
| Despesas/Receitas | 2022 | ✅ |
|
||||||
|
| Rede Social | 2022 | ✅ |
|
||||||
|
| Fotos | 2022 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2020 | ✅ |
|
||||||
|
| Bem Candidato | 2020 | ✅ |
|
||||||
|
| Despesas/Receitas | 2020 | ✅ |
|
||||||
|
| Rede Social | 2020 | ✅ |
|
||||||
|
| Fotos | 2020 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2018 | ✅ |
|
||||||
|
| Bem Candidato | 2018 | ✅ |
|
||||||
|
| Despesas/Receitas | 2018 | ❌ |
|
||||||
|
| Rede Social | 2018 | ❌ |
|
||||||
|
| Fotos | 2018 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2016 | ✅ |
|
||||||
|
| Bem Candidato | 2016 | ✅ |
|
||||||
|
| Despesas/Receitas | 2016 | ❌ |
|
||||||
|
| Rede Social | 2016 | ❌ |
|
||||||
|
| Fotos | 2016 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2014 | ✅ |
|
||||||
|
| Bem Candidato | 2014 | ✅ |
|
||||||
|
| Despesas/Receitas | 2014 | ❌ |
|
||||||
|
| Rede Social | 2014 | ❌ |
|
||||||
|
| Fotos | 2014 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2012 | ✅ |
|
||||||
|
| Bem Candidato | 2012 | ✅ |
|
||||||
|
| Despesas/Receitas | 2012 | ❌ |
|
||||||
|
| Rede Social | 2012 | ❌ |
|
||||||
|
| Fotos | 2012 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2010 | ✅ |
|
||||||
|
| Bem Candidato | 2010 | ✅ |
|
||||||
|
| Despesas/Receitas | 2010 | ❌ |
|
||||||
|
| Rede Social | 2010 | ❌ |
|
||||||
|
| Fotos | 2010 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2008 | ✅ |
|
||||||
|
| Bem Candidato | 2008 | ✅ |
|
||||||
|
| Despesas/Receitas | 2008 | ❌ |
|
||||||
|
| Rede Social | 2008 | ❌ |
|
||||||
|
| Fotos | 2008 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2006 | ✅ |
|
||||||
|
| Bem Candidato | 2006 | ✅ |
|
||||||
|
| Despesas/Receitas | 2006 | ❌ |
|
||||||
|
| Rede Social | 2006 | ❌ |
|
||||||
|
| Fotos | 2006 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2004 | ✅ |
|
||||||
|
| Bem Candidato | 2004 | ❌ |
|
||||||
|
| Despesas/Receitas | 2004 | ❌ |
|
||||||
|
| Rede Social | 2004 | ❌ |
|
||||||
|
| Fotos | 2004 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2002 | ✅ |
|
||||||
|
| Bem Candidato | 2002 | ❌ |
|
||||||
|
| Despesas/Receitas | 2002 | ❌ |
|
||||||
|
| Rede Social | 2002 | ❌ |
|
||||||
|
| Fotos | 2002 | ❌ |
|
||||||
|
| - | - | - |
|
||||||
|
| Candidatos | 2000 | ✅ |
|
||||||
|
| Bem Candidato | 2000 | ⛔ |
|
||||||
|
| Despesas/Receitas | 2000 | ⛔ |
|
||||||
|
| Rede Social | 2000 | ⛔ |
|
||||||
|
| Fotos | 2000 | ⛔ |
|
||||||
|
| - | - | - |
|
||||||
|
61
db/db.sql
61
db/db.sql
@ -3,6 +3,8 @@ DROP TABLE IF EXISTS candidato_mapping CASCADE;
|
|||||||
DROP TABLE IF EXISTS rede_social CASCADE;
|
DROP TABLE IF EXISTS rede_social CASCADE;
|
||||||
DROP TABLE IF EXISTS candidato CASCADE;
|
DROP TABLE IF EXISTS candidato CASCADE;
|
||||||
DROP TABLE IF EXISTS partido CASCADE;
|
DROP TABLE IF EXISTS partido CASCADE;
|
||||||
|
DROP TABLE IF EXISTS despesas_candidato CASCADE;
|
||||||
|
DROP TABLE IF EXISTS receitas_candidato CASCADE;
|
||||||
|
|
||||||
CREATE TABLE candidato (
|
CREATE TABLE candidato (
|
||||||
idcandidato UUID NOT NULL PRIMARY KEY,
|
idcandidato UUID NOT NULL PRIMARY KEY,
|
||||||
@ -25,7 +27,8 @@ CREATE TABLE candidato_mapping (
|
|||||||
cpf VARCHAR(11),
|
cpf VARCHAR(11),
|
||||||
nome VARCHAR(255) NOT NULL,
|
nome VARCHAR(255) NOT NULL,
|
||||||
apelido VARCHAR(255),
|
apelido VARCHAR(255),
|
||||||
sqcandidato TEXT,
|
sqcandidato VARCHAR(50) NOT NULL,
|
||||||
|
turno VARCHAR(2) NOT NULL,
|
||||||
ano INT NOT NULL,
|
ano INT NOT NULL,
|
||||||
tipoeleicao VARCHAR(50),
|
tipoeleicao VARCHAR(50),
|
||||||
siglauf VARCHAR(2),
|
siglauf VARCHAR(2),
|
||||||
@ -76,4 +79,58 @@ CREATE TABLE partido (
|
|||||||
numero INT NOT NULL
|
numero INT NOT NULL
|
||||||
);
|
);
|
||||||
CREATE INDEX idx_partido_nome ON partido (nome);
|
CREATE INDEX idx_partido_nome ON partido (nome);
|
||||||
CREATE INDEX idx_partido_numero ON partido (numero);
|
CREATE INDEX idx_partido_numero ON partido (numero);
|
||||||
|
|
||||||
|
---- Tables for storing despesas e receitas of candidacies
|
||||||
|
CREATE TABLE despesas_candidato (
|
||||||
|
idreceita UUID NOT NULL DEFAULT gen_random_uuid(),
|
||||||
|
idcandidato UUID NOT NULL,
|
||||||
|
ano INT NOT NULL,
|
||||||
|
turno VARCHAR(2) NOT NULL,
|
||||||
|
sqcandidato VARCHAR(50) NOT NULL,
|
||||||
|
sgpartido VARCHAR(50) NOT NULL,
|
||||||
|
tipofornecedor VARCHAR(150),
|
||||||
|
cnpjfornecedor VARCHAR(14),
|
||||||
|
cpffornecedor VARCHAR(11),
|
||||||
|
nomefornecedor VARCHAR(255),
|
||||||
|
nomefornecedorrfb VARCHAR(255),
|
||||||
|
municipiofornecedor VARCHAR(100),
|
||||||
|
tipodocumento VARCHAR(50),
|
||||||
|
datadespesa TIMESTAMPTZ,
|
||||||
|
descricao TEXT,
|
||||||
|
origemdespesa TEXT,
|
||||||
|
valor NUMERIC(20, 2),
|
||||||
|
CONSTRAINT pk_despesas_candidato PRIMARY KEY (idreceita),
|
||||||
|
CONSTRAINT fk_despesas_candidato_candidato FOREIGN KEY (idcandidato) REFERENCES candidato(idcandidato) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_despesas_candidato_idcandidato ON despesas_candidato (idcandidato);
|
||||||
|
CREATE INDEX idx_despesas_candidato_ano ON despesas_candidato (ano);
|
||||||
|
CREATE INDEX idx_despesas_candidato_sqcandidato ON despesas_candidato (sqcandidato);
|
||||||
|
CREATE INDEX idx_despesas_candidato_sgpartido ON despesas_candidato (sgpartido);
|
||||||
|
|
||||||
|
CREATE TABLE receitas_candidato (
|
||||||
|
idreceita UUID NOT NULL DEFAULT gen_random_uuid(),
|
||||||
|
idcandidato UUID NOT NULL,
|
||||||
|
ano INT NOT NULL,
|
||||||
|
turno VARCHAR(2) NOT NULL,
|
||||||
|
sqcandidato VARCHAR(50) NOT NULL,
|
||||||
|
sgpartido VARCHAR(50) NOT NULL,
|
||||||
|
fontereceita VARCHAR(150),
|
||||||
|
origemreceita VARCHAR(250),
|
||||||
|
naturezareceita VARCHAR(250),
|
||||||
|
especiereceita VARCHAR(250),
|
||||||
|
cnpjdoador VARCHAR(14),
|
||||||
|
cpfdoador VARCHAR(11),
|
||||||
|
nomedoador VARCHAR(255),
|
||||||
|
nomedoadorrfb VARCHAR(255),
|
||||||
|
municipiodoador VARCHAR(100),
|
||||||
|
datareceita TIMESTAMPTZ,
|
||||||
|
descricao TEXT,
|
||||||
|
valor NUMERIC(20, 2),
|
||||||
|
CONSTRAINT pk_receitas_candidato PRIMARY KEY (idreceita),
|
||||||
|
CONSTRAINT fk_receitas_candidato_candidato FOREIGN KEY (idcandidato) REFERENCES candidato(idcandidato) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_receitas_candidato_idcandidato ON receitas_candidato (idcandidato);
|
||||||
|
CREATE INDEX idx_receitas_candidato_ano ON receitas_candidato (ano);
|
||||||
|
CREATE INDEX idx_receitas_candidato_sqcandidato ON receitas_candidato (sqcandidato);
|
||||||
|
CREATE INDEX idx_receitas_candidato_sgpartido ON receitas_candidato (sgpartido);
|
Loading…
x
Reference in New Issue
Block a user