diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35063fc --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +## A streamlined .gitignore for modern .NET projects +## including temporary files, build results, and +## files generated by popular .NET tools. If you are +## developing with Visual Studio, the VS .gitignore +## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +## has more thorough IDE-specific entries. +## +## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg + +# Others +~$* +*~ +CodeCoverage/ + +# MSBuild Binary and Structured Log +*.binlog + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml \ No newline at end of file diff --git a/README.md b/README.md index 668a6a2..c2a1bdb 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,72 @@ -# Reto Técnico: Procesamiento de Transacciones Bancarias (CLI) +# 📊 Procesador de Transacciones Bancarias (CLI) - .NET 8 -## Objetivo: +## 🧾 Introducción -Desarrolla una aplicación de línea de comandos (CLI) que procese un archivo CSV con transacciones bancarias y genere un reporte que incluya: +Este proyecto es una aplicación de línea de comandos desarrollada en **C# con .NET 8**. Su objetivo es procesar un archivo CSV con transacciones bancarias para generar un reporte que contenga: -- **Balance Final:** - Suma de los montos de las transacciones de tipo "Crédito" menos la suma de los montos de las transacciones de tipo "Débito". +- 💰 Balance Final (Créditos - Débitos) +- 🔍 Transacción de Mayor Monto +- 📊 Conteo de Transacciones por tipo ("Crédito" y "Débito") -- **Transacción de Mayor Monto:** - Identificar el ID y el monto de la transacción con el valor más alto. +--- + +## ▶️ Instrucciones de Ejecución + +### 1. Requisitos + +- Tener instalado **.NET 8 SDK** + - Verifica la instalación con: `dotnet --version` + - Descarga desde: https://dotnet.microsoft.com/download/dotnet/8.0 + +### 2. Crear archivo CSV de prueba -- **Conteo de Transacciones:** - Número total de transacciones para cada tipo ("Crédito" y "Débito"). +Contenido sugerido para `datos.csv`: + +id,tipo,monto +1,Crédito,100.00 +2,Débito,50.00 +3,Crédito,200.00 +4,Débito,75.00 +5,Crédito,150.00 + +### 3. Ejecutar la aplicación + +Ubicado en la carpeta del proyecto: + +dotnet run -- ../data.csv --- -## Instrucciones - -1. **Repositorio Base:** - Clona o haz un fork del repositorio base disponible en: - `https://github.com/codeableorg/interbank-academy-25` - -2. **Entrada de Datos:** - La aplicación deberá leer un archivo CSV. Ejemplo de contenido: - - ``` - id,tipo,monto - 1,Crédito,100.00 - 2,Débito,50.00 - 3,Crédito,200.00 - 4,Débito,75.00 - 5,Crédito,150.00 - ``` - -3. **Salida del Programa:** - La aplicación debe mostrar el reporte final en la terminal. - Ejemplo de salida: - - ``` - Reporte de Transacciones - --------------------------------------------- - Balance Final: 325.00 - Transacción de Mayor Monto: ID 3 - 200.00 - Conteo de Transacciones: Crédito: 3 Débito: 2 - ``` - -4. **Lenguaje de Programación:** - Utiliza el lenguaje de tu preferencia. Opciones recomendadas: - - - Python - - Java - - C# - - JavaScript (Node.js) - -5. **README del Proyecto:** - Incluye un archivo `README.md` con la siguiente estructura: - - - **Introducción:** Breve descripción del reto y su propósito. - - **Instrucciones de Ejecución:** Cómo instalar dependencias y ejecutar la aplicación. - - **Enfoque y Solución:** Lógica implementada y decisiones de diseño. - - **Estructura del Proyecto:** Archivos y carpetas principales. - -6. **Documentación y Calidad del Código:** - - Código bien documentado y fácil de leer. - - Comentarios explicando pasos clave y lógica del programa. +## ⚙️ Enfoque y Solución + +- Se creó una clase `Transaccion` para representar los datos. +- Toda la lógica de lectura, cálculo y reporte se colocó en `ProcesadorTransacciones.cs`. +- Se usó LINQ para sumar, contar y encontrar la transacción con mayor monto. +- Se separaron las responsabilidades y se manejaron errores de entrada. + +--- + +## 📁 Estructura del Proyecto + +TransaccionesApp/ +├── Program.cs +├── Models/Transaccion.cs +├── Services/ProcesadorTransacciones.cs +├── data.csv +├── TransaccionesApp.csproj +└── README.md + +La estructura del proyecto sigue una organización clara y modular: +- El archivo `Program.cs` actúa como punto de entrada principal, mientras que la carpeta `Models` contiene la clase `Transaccion.cs` que representa los datos de cada transacción. +- La lógica de procesamiento y generación del reporte está encapsulada en `ProcesadorTransacciones.cs`, dentro de la carpeta `Services`, promoviendo la separación de responsabilidades y facilitando el mantenimiento del código. + +--- + +## ✅ Resultado Esperado + +=== Procesador de Transacciones === +Reporte de Transacciones +--------------------------------------------- +Balance Final: 325.00 +Transacción de Mayor Monto: ID 3 - 200.00 +Conteo de Transacciones: Crédito: 3 Débito: 2 \ No newline at end of file diff --git a/TransaccionesApp/Models/Transaccion.cs b/TransaccionesApp/Models/Transaccion.cs new file mode 100644 index 0000000..31117c2 --- /dev/null +++ b/TransaccionesApp/Models/Transaccion.cs @@ -0,0 +1,11 @@ +namespace TransaccionesApp; + +/// +/// Representa una transacción bancaria con ID, tipo y monto. +/// +public class Transaccion +{ + public int Id { get; set; } // ID único de la transacción + public required string Tipo { get; set; } // Tipo de transacción: "Crédito" o "Débito" + public decimal Monto { get; set; } // Monto de la transacción +} diff --git a/TransaccionesApp/Program.cs b/TransaccionesApp/Program.cs new file mode 100644 index 0000000..b07fe39 --- /dev/null +++ b/TransaccionesApp/Program.cs @@ -0,0 +1,15 @@ +// See https://aka.ms/new-console-template for more information +using TransaccionesApp; + +Console.WriteLine("=== Procesador de Transacciones ==="); +Console.WriteLine(); + +// Validación de argumentos: se espera que se pase un solo argumento (la ruta del archivo CSV) +if (args.Length != 1) +{ + Console.WriteLine("Uso: dotnet run "); + return; +} + +ProcesadorTransacciones.ProcesarArchivo(args[0]); +Console.WriteLine(); \ No newline at end of file diff --git a/TransaccionesApp/Services/ProcesadorTransacciones.cs b/TransaccionesApp/Services/ProcesadorTransacciones.cs new file mode 100644 index 0000000..23890f4 --- /dev/null +++ b/TransaccionesApp/Services/ProcesadorTransacciones.cs @@ -0,0 +1,87 @@ +using System.Globalization; + +namespace TransaccionesApp; + +/// +/// Clase que contiene la lógica para procesar transacciones desde un archivo CSV. +/// +public static class ProcesadorTransacciones +{ + public static void ProcesarArchivo(string rutaArchivo) + { + // Validar si el archivo existe en la ruta especificada + if (!File.Exists(rutaArchivo)) + { + Console.WriteLine("El archivo no existe: " + rutaArchivo); + return; + } + + var transacciones = new List(); // Lista donde se almacenarán todas las transacciones + + try + { + // Leer todas las líneas del archivo, ignorando la primera (encabezados) + var lineas = File.ReadAllLines(rutaArchivo).Skip(1); + + // Procesar cada línea del archivo CSV + foreach (var linea in lineas) + { + var partes = linea.Split(','); + + // Validar que la línea tenga exactamente 3 partes: id, tipo, monto + if (partes.Length != 3) + continue; + + // Crear un objeto Transaccion a partir de la línea + transacciones.Add(new Transaccion + { + Id = int.Parse(partes[0]), + Tipo = partes[1].Trim(), + Monto = decimal.Parse(partes[2], CultureInfo.InvariantCulture) + }); + } + + // Calcular el total de montos para transacciones de tipo "Crédito" + var totalCredito = transacciones + .Where(t => t.Tipo.Equals("Crédito", StringComparison.OrdinalIgnoreCase)) + .Sum(t => t.Monto); + + // Calcular el total de montos para transacciones de tipo "Débito" + var totalDebito = transacciones + .Where(t => t.Tipo.Equals("Débito", StringComparison.OrdinalIgnoreCase)) + .Sum(t => t.Monto); + + // Calcular el balance final: créditos - débitos + var balanceFinal = totalCredito - totalDebito; + + // Encontrar la transacción con el monto más alto + var transaccionMayor = transacciones + .OrderByDescending(t => t.Monto) + .First(); + + // Contar la cantidad de transacciones de tipo "Crédito" + var conteoCredito = transacciones + .Count(t => t.Tipo.Equals("Crédito", StringComparison.OrdinalIgnoreCase)); + + // Contar la cantidad de transacciones de tipo "Débito" + var conteoDebito = transacciones + .Count(t => t.Tipo.Equals("Débito", StringComparison.OrdinalIgnoreCase)); + + // Mostrar el reporte en la terminal + Console.WriteLine("Reporte de Transacciones"); + Console.WriteLine("---------------------------------------------"); + Console.WriteLine($"Balance Final: {balanceFinal:F2}"); + Console.WriteLine($"Transacción de Mayor Monto: ID {transaccionMayor.Id} - {transaccionMayor.Monto:F2}"); + Console.WriteLine($"Conteo de Transacciones: Crédito: {conteoCredito} Débito: {conteoDebito}"); + } + catch (Exception ex) + { + Console.WriteLine("Error procesando el archivo: " + ex.Message); + } + finally + { + Console.WriteLine(); + Console.WriteLine(" - Proceso de lectura de transacciones finalizado."); + } + } +} diff --git a/TransaccionesApp/TransaccionesApp.csproj b/TransaccionesApp/TransaccionesApp.csproj new file mode 100644 index 0000000..206b89a --- /dev/null +++ b/TransaccionesApp/TransaccionesApp.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/interbank-academy-25.sln b/interbank-academy-25.sln new file mode 100644 index 0000000..061b8e6 --- /dev/null +++ b/interbank-academy-25.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransaccionesApp", "TransaccionesApp\TransaccionesApp.csproj", "{33BC2708-774C-2881-CEE1-7F7F98EDB2B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33BC2708-774C-2881-CEE1-7F7F98EDB2B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33BC2708-774C-2881-CEE1-7F7F98EDB2B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33BC2708-774C-2881-CEE1-7F7F98EDB2B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33BC2708-774C-2881-CEE1-7F7F98EDB2B3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {137CE233-29AA-4688-BEE1-2D17EAA89DA4} + EndGlobalSection +EndGlobal