Last active
May 23, 2024 13:27
-
-
Save alyleite/d386510bed1de38776a5d59b0a8abe36 to your computer and use it in GitHub Desktop.
Poc para calcular saldo diário do extrato em c# e ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'logger' | |
module AccountManager | |
class ExtractGenerator < M2yService | |
attr_reader :alias_account, :alias_branch, :start_date, :end_date, :page, :pages | |
def initialize(alias_account, alias_branch, start_date, end_date, page) | |
@alias_account = alias_account | |
@alias_branch = alias_branch | |
@start_date = start_date | |
@end_date = end_date | |
@page = page | |
@logger = Logger.new(STDOUT) | |
@logger.level = Logger::WARN | |
end | |
def call | |
balance = fetch_balance | |
return if balance[:content].empty? | |
transactions = fetch_transactions | |
#return if transactions[:content].empty? | |
initial_balance = balance[:content][0]['vlSdoIni'] | |
final_balance = balance[:content][0]['vlSdoFin'] | |
@logger.warn("dataInicial: #{start_date}") | |
@logger.warn("dataFinal: #{end_date}") | |
@logger.warn("valorInicial: #{initial_balance}") | |
@logger.warn("valorFinal: #{final_balance}\n") | |
ordered_transactions = transactions[:content].sort_by { |t| t['dtLanc'] } | |
grouped_transactions = group_transactions_by_date(ordered_transactions) | |
all_transactions = [] # List to store all transactions including initial balance | |
date = Date.strptime(start_date, "%d/%m/%Y") - 1.day | |
# Add initial balance transaction | |
add_balance_transaction(all_transactions, date.strftime('%Y%m%d'), initial_balance, true) | |
current_balance = initial_balance | |
grouped_transactions.each do |date_t, transactions_t| | |
@logger.warn("Data: #{date_t}\n") | |
@logger.warn("Saldo Anterior: #{current_balance}\n") | |
# Add actual transactions | |
all_transactions.concat(transactions_t.map(&:to_hash)) | |
calculated_balance = calculate_balance(transactions_t) | |
balance_day = (current_balance + calculated_balance).round(2) | |
@logger.warn("Soma dos lançamentos do dia: #{calculated_balance}") | |
@logger.warn("Saldo do dia: (#{current_balance} + #{calculated_balance}): #{balance_day}\n") | |
add_balance_transaction(all_transactions, date_t, balance_day) | |
current_balance += calculated_balance | |
end | |
total_balance_change = calculate_balance(ordered_transactions) | |
@logger.warn("Valor final calculado: #{total_balance_change}") | |
@logger.warn("Valor dos lançamentos somados (#{initial_balance} + #{total_balance_change}): #{(initial_balance + total_balance_change).round(2)}\n") | |
@logger.warn("Transactions: #{all_transactions}\n") | |
all_transactions | |
end | |
private | |
def @logger.warn(message) | |
@logger.warn(message) | |
end | |
def fetch_transactions | |
AccountManager::Extract.call(@alias_account, @alias_branch, @start_date, @end_date, @page) | |
end | |
def fetch_balance | |
AccountManager::ExtractFindBalance.call(@alias_account, @alias_branch, @start_date, @end_date, @page) | |
end | |
def group_transactions_by_date(transactions) | |
transactions.group_by { |transaction| transaction['dtLanc'] } | |
end | |
def calculate_balance(transactions) | |
transactions.sum do |transaction| | |
if transaction['tpSinal'] == "D" | |
-transaction['vlLanc'] | |
else | |
transaction['vlLanc'] | |
end | |
end | |
end | |
def add_balance_transaction(all_transactions, date, balance_day, first = false) | |
description = first ? "SALDO ANTERIOR" : "SALDO DO DIA" | |
all_transactions << { dtLanc: date, dtIncsis: date, tpSinal: "S", vlLanc: balance_day, dsLanc: description, dsTransr: description } | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task Main() | |
{ | |
try | |
{ | |
var dtIni = 20230101; | |
var dtFin = 20240507; | |
var lancamentos = await ConsultaLancamento(dtIni, dtFin); | |
if(lancamentos.Count == 0) return; | |
var extrato = await ConsultaExtrato(dtIni, dtFin); | |
var valorInicial = extrato.VlSdoIni; | |
var valorFinal = extrato.VlSdoFin; | |
_logger.LogWarning($"dataInicial: {dtIni}"); | |
_logger.LogWarning($"dataFinal: {dtFin}"); | |
_logger.LogWarning($"valorInicial: {valorInicial}"); | |
_logger.LogWarning($"valorFinal: {valorFinal}\n"); | |
var listaOrdenada = lancamentos.OrderBy(l => l.DtLanc).ToList(); | |
var listaAgrupada = listaOrdenada | |
.GroupBy(x => x.DtLanc) | |
.ToDictionary(gdc => gdc.Key, gdc => gdc.ToList()); | |
var valorIni = valorInicial; | |
foreach (var keyValuePair in listaAgrupada) | |
{ | |
_logger.LogWarning($"Data: {keyValuePair.Key}\n"); | |
_logger.LogWarning($"Valor Inicial da data: {valorIni}\n"); | |
var valorCalc = keyValuePair.Value.Sum(lancamento => lancamento.TpSinal.Equals("D") ? lancamento.VlLanc * -1 : lancamento.VlLanc); | |
_logger.LogWarning($"Valor calculado da data: {valorCalc}"); | |
_logger.LogWarning($"Valor final da data: ({valorIni} + {valorCalc}): {valorIni + valorCalc}\n"); | |
valorIni += valorCalc; | |
} | |
var valor = listaOrdenada.Sum(lancamento => lancamento.TpSinal.Equals("D") ? lancamento.VlLanc * -1 : lancamento.VlLanc); | |
_logger.LogWarning($"Valor final calculado: {valor}"); | |
_logger.LogWarning($"Valor dos lançamentos somados ({valorInicial} + {valor}): {valorInicial + valor}\n"); | |
} | |
catch (Exception ex) | |
{ | |
_logger.LogError($"Erro execução : {ex.Message}"); | |
} | |
} | |
private async Task<List<ConsultaLancamento>> ConsultaLancamento(int dtIni, int dtFin) | |
{ | |
var options = new JsonSerializerOptions | |
{ | |
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, | |
WriteIndented = true, | |
PropertyNameCaseInsensitive = true, | |
Converters = { new JsonStringEnumConverter(), new CustomDateTimeConverter("yyyy-MM-dd") } | |
}; | |
using var httpClient = new HttpClient(); | |
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic ***"); | |
httpClient.DefaultRequestHeaders.Add("Accept", "*/*"); | |
httpClient.DefaultRequestHeaders.Add("Cookie", "XSRF-TOKEN=543e6a98-db4d-46ab-998b-0780c1ebf01e"); | |
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); | |
var url = "<api>/BJ08M01/BJ08M01/BJ08SS0101C/v2/listaLancamentos"; | |
var requestStr = "{\"cdCta\": 144142, \"dtIni\": " + dtIni + ", \"dtFin\": " + dtFin + ", \"nrAgen\": 19, \"nrInst\": 1414, \"nrSeq\": 0}"; | |
var content = new StringContent(requestStr, Encoding.UTF8, "application/json"); | |
var response = await httpClient.PostAsync(url, content); | |
if (!response.StatusCode.Equals(HttpStatusCode.OK)) throw new Exception($"Erro ao realizar requisição: {response.StatusCode} - {response.ReasonPhrase}"); | |
var responseContent = await response.Content.ReadAsStringAsync(); | |
var responseDto = JsonSerializer.Deserialize<ResponseLancamento>(responseContent, options); | |
if(responseDto?.ConsultaLancamento is null) | |
throw new Exception($"Erro ao converter json de response dos lançamentos: {responseContent}"); | |
return responseDto.ConsultaLancamento; | |
} | |
private async Task<Extrato> ConsultaExtrato(int dtIni, int dtFin) | |
{ | |
var options = new JsonSerializerOptions | |
{ | |
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, | |
WriteIndented = true, | |
PropertyNameCaseInsensitive = true, | |
Converters = { new JsonStringEnumConverter(), new CustomDateTimeConverter("yyyy-MM-dd") } | |
}; | |
using var httpClient = new HttpClient(); | |
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic ***"); | |
httpClient.DefaultRequestHeaders.Add("Accept", "*/*"); | |
httpClient.DefaultRequestHeaders.Add("Cookie", "XSRF-TOKEN=543e6a98-db4d-46ab-998b-0780c1ebf01e"); | |
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); | |
var url = "<api>/BJ08M01/BJ08M01/BJ08SS0101C/consultaExtrato"; | |
var requestStr = "{\"cdCta\": 144142, \"dtIni\": " + dtIni + ", \"dtFin\": " + dtFin + ", \"nrAgen\": 19, \"nrInst\": 1414, \"nrSeq\": 0}"; | |
var content = new StringContent(requestStr, Encoding.UTF8, "application/json"); | |
var response = await httpClient.PostAsync(url, content); | |
if (!response.StatusCode.Equals(HttpStatusCode.OK)) throw new Exception($"Erro ao realizar requisição: {response.StatusCode} - {response.ReasonPhrase}"); | |
var responseContent = await response.Content.ReadAsStringAsync(); | |
var responseDto = JsonSerializer.Deserialize<ResponseExtrato>(responseContent, options); | |
if(responseDto?.Extrato?.FirstOrDefault() == null) | |
throw new Exception($"Erro ao converter json de response do extrato: {responseContent}"); | |
return responseDto.Extrato!.FirstOrDefault(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Response | |
{ | |
public class Extrato | |
{ | |
public int CdConta { get; set; } | |
public decimal VlSdoIni { get; set; } | |
public decimal VlSdoFin { get; set; } | |
public decimal VlSdoBlq { get; set; } | |
public decimal VlLimCre { get; set; } | |
public decimal VlJurAcu { get; set; } | |
public decimal VlIofAcu { get; set; } | |
} | |
public class ResponseExtrato | |
{ | |
public List<Extrato> Extrato { get; set; } | |
} | |
public class ResponseLancamento | |
{ | |
public List<ConsultaLancamento> ConsultaLancamento { get; set; } | |
} | |
public class ConsultaLancamento | |
{ | |
public int Seq { get; set; } | |
public int NrInstituicao { get; set; } | |
public int NrAgencia { get; set; } | |
public int NrConta { get; set; } | |
public string NrCpfCnpj { get; set; } | |
public string NmPessoa { get; set; } | |
public int DtLanc { get; set; } | |
public decimal VlLanc { get; set; } | |
public string DsLanc { get; set; } | |
public string TpSinal { get; set; } | |
public string DtIncsis { get; set; } | |
public string HrIncsis { get; set; } | |
public string NrAuten { get; set; } | |
public string NrAutenTransf { get; set; } | |
public int? IdTrans { get; set; } | |
public int? CdTrans { get; set; } | |
public string DsTransr { get; set; } | |
public string DsTransc { get; set; } | |
public int? IdMovto { get; set; } | |
public string NmContraparte { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment