Primer comit

This commit is contained in:
2025-09-13 17:08:14 -06:00
commit be8111c2b8
30 changed files with 1339 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

10
.idea/.idea.AdminFinanceRCA/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/.idea.AdminFinanceRCA.iml
/contentModel.xml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AvaloniaProject">
<option name="projectPerEditor">
<map>
<entry key="AdminFinanceRCA/App.axaml" value="AdminFinanceRCA/AdminFinanceRCA.csproj" />
<entry key="AdminFinanceRCA/Views/MainWindow.axaml" value="AdminFinanceRCA/AdminFinanceRCA.csproj" />
<entry key="AdminFinanceRCA/Views/Mantenimiento_DepartTrabajo.axaml" value="AdminFinanceRCA/AdminFinanceRCA.csproj" />
<entry key="AdminFinanceRCA/Views/MovimientoWindow.axaml" value="AdminFinanceRCA/AdminFinanceRCA.csproj" />
</map>
</option>
</component>
</project>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

16
AdminFinanceRCA.sln Normal file
View File

@@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdminFinanceRCA", "AdminFinanceRCA\AdminFinanceRCA.csproj", "{1917BD06-B762-42E3-BD49-67C08B3848BD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1917BD06-B762-42E3-BD49-67C08B3848BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1917BD06-B762-42E3-BD49-67C08B3848BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1917BD06-B762-42E3-BD49-67C08B3848BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1917BD06-B762-42E3-BD49-67C08B3848BD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAdminFinanceRCA_002EViewModels_002EMantenimiento_005FDepartTrabajoViewModel_002Eg_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fef78e682e56c19e39b0e3efe9d5c77fc453833_003FAdminFinanceRCA_002EViewModels_002EMantenimiento_005FDepartTrabajoViewModel_002Eg_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApplication_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F9a5cc8ddf36e8c8f422071f068cc8edb16e814991aa851aa131f3fa14425ed_003FApplication_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fbf9021a960b74107a7e141aa06bc9d8a0a53c929178c2fb95b1597be8af8dc_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARelayCommand_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F20c0f49b8854743afaecc2f359655fdbfc6c5264f49e9eb333686e85a87bf_003FRelayCommand_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fb90d6b47d6330753e855af18818b97d4207f32c6ee4b793faffc029f069f4_003FString_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

View File

@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.3.0" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.3.0" />
<PackageReference Include="Avalonia.Desktop" Version="11.3.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.0" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.0" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.0">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="Material.Avalonia" Version="3.13.0" />
<PackageReference Include="Material.Avalonia.Dialogs" Version="3.13.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.0-preview.7.25380.108" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.0-preview.7.25380.108" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0-preview.7.25380.108" />
<PackageReference Include="System.Data.SQLite" Version="2.0.1" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

17
AdminFinanceRCA/App.axaml Normal file
View File

@@ -0,0 +1,17 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AdminFinanceRCA.App"
xmlns:local="using:AdminFinanceRCA"
RequestedThemeVariant="Default"
xmlns:themes="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"
>
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
<themes:MaterialTheme BaseTheme="Dark" PrimaryColor="Purple" SecondaryColor="Lime" />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>
</Application>

View File

@@ -0,0 +1,47 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using System.Linq;
using Avalonia.Markup.Xaml;
using AdminFinanceRCA.ViewModels;
using AdminFinanceRCA.Views;
namespace AdminFinanceRCA;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
}
base.OnFrameworkInitializationCompleted();
}
private void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
namespace AdminFinanceRCA;
public class AppConfig
{
private readonly IConfiguration _configuration;
public AppConfig()
{
var builder = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
_configuration = builder.Build();
}
public string GetConnectionString(string name = "DefaultConnection")
{
return _configuration.GetConnectionString(name);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

View File

@@ -0,0 +1,107 @@
using System;
using CommunityToolkit.Mvvm.ComponentModel;
namespace AdminFinanceRCA.Models;
// Clase para la tabla Concepto
public class Concepto
{
public int ID { get; set; }
public string Nombre { get; set; } = string.Empty;
public Concepto() { }
public Concepto(string nombre)
{
Nombre = nombre;
}
}
// Clase para la tabla DepartTrabajo
public class DepartTrabajo : ObservableObject
{
public int Id { get; set; }
public string Nombre { get; set; } = string.Empty;
public string Descripcion { get; set; } = string.Empty;
public DepartTrabajo() { }
public DepartTrabajo(string nombre)
{
Nombre = nombre;
}
public DepartTrabajo(string nombre, string descripcion)
{
Nombre = nombre;
Descripcion = descripcion;
}
}
// Clase para la tabla TipoMovimiento
public class TipoMovimiento : ObservableObject
{
public int ID { get; set; }
public string Nombre { get; set; } = string.Empty;
public TipoMovimiento() { }
public TipoMovimiento(string nombre)
{
Nombre = nombre;
}
}
// Clase principal para la tabla Movimientos con relaciones
public class Movimiento : ObservableObject
{
public int ID { get; set; }
public decimal Monto { get; set; }
public int TipoMov { get; set; }
public int DeptoTrabajo { get; set; }
public DateTime FechaMovimiento { get; set; }
public DateTime FechaRegistro { get; set; }
public int Concepto { get; set; }
public string Descripcion { get; set; } = string.Empty;
// Propiedades de navegación para las relaciones (opcionales pero útiles)
public TipoMovimiento TipoMovimientoNav { get; set; } = new TipoMovimiento();
public DepartTrabajo DepartTrabajoNav { get; set; } = new DepartTrabajo();
public Concepto ConceptoNav { get; set; } = new Concepto();
public Movimiento() { }
public Movimiento(decimal monto, int tipoMov, int deptoTrabajo,
DateTime fechaMovimiento, int concepto, string descripcion = "")
{
Monto = monto;
TipoMov = tipoMov;
DeptoTrabajo = deptoTrabajo;
FechaMovimiento = fechaMovimiento;
FechaRegistro = DateTime.Now;
Concepto = concepto;
Descripcion = descripcion;
}
}
// Clase para resultados de consultas JOIN
public class MovimientoCompleto : ObservableObject
{
public int ID { get; set; }
public decimal Monto { get; set; }
public DateTime FechaMovimiento { get; set; }
public DateTime FechaRegistro { get; set; }
public string Descripcion { get; set; } = string.Empty;
// Datos de TipoMovimiento
public int TipoMovID { get; set; }
public string TipoMovNombre { get; set; } = string.Empty;
// Datos de DepartTrabajo
public int DeptoTrabajoID { get; set; }
public string DeptoTrabajoNombre { get; set; } = string.Empty;
// Datos de Concepto
public int ConceptoID { get; set; }
public string ConceptoNombre { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,21 @@
using Avalonia;
using System;
namespace AdminFinanceRCA;
sealed class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}

View File

@@ -0,0 +1,302 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using AdminFinanceRCA.Models;
namespace AdminFinanceRCA;
using System.Data;
using Dapper;
using Microsoft.Data.Sqlite;
public class FinanzasRepository
{
private readonly string _connectionString;
public FinanzasRepository()
{
var config = new AppConfig();
_connectionString = config.GetConnectionString();
InitializeDatabase();
}
// Constructor alternativo para testing
public FinanzasRepository(string connectionString)
{
_connectionString = connectionString;
InitializeDatabase();
}
private void InitializeDatabase()
{
using (var connection = new SqliteConnection(_connectionString))
{
connection.Open();
// Crear tablas si no existen
connection.Execute(@"
CREATE TABLE IF NOT EXISTS Concepto (
ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Nombre TEXT NOT NULL
)");
connection.Execute(@"
CREATE TABLE IF NOT EXISTS DepartTrabajo (
Id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Nombre TEXT NOT NULL
)");
connection.Execute(@"
CREATE TABLE IF NOT EXISTS TipoMovimiento (
ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Nombre TEXT NOT NULL
)");
connection.Execute(@"
CREATE TABLE IF NOT EXISTS Movimientos (
ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
Monto REAL NOT NULL,
TipoMov INTEGER NOT NULL,
DeptoTrabajo INTEGER NOT NULL,
FechaMovimiento TEXT NOT NULL,
FechaRegistro TEXT NOT NULL,
Concepto INTEGER NOT NULL,
Descripcion TEXT,
FOREIGN KEY(TipoMov) REFERENCES TipoMovimiento(ID),
FOREIGN KEY(DeptoTrabajo) REFERENCES DepartTrabajo(Id),
FOREIGN KEY(Concepto) REFERENCES Concepto(ID)
)");
// Crear índice
connection.Execute(@"
CREATE INDEX IF NOT EXISTS Mov ON Movimientos (Concepto ASC, TipoMov ASC)");
// Insertar datos básicos si las tablas están vacías
InsertarDatosBasicos(connection);
}
}
private void InsertarDatosBasicos(SqliteConnection connection)
{
// Verificar si TipoMovimiento está vacío
var countTipos = connection.ExecuteScalar<int>("SELECT COUNT(*) FROM TipoMovimiento");
if (countTipos == 0)
{
connection.Execute("INSERT INTO TipoMovimiento (Nombre) VALUES ('Ingreso')");
connection.Execute("INSERT INTO TipoMovimiento (Nombre) VALUES ('Egreso')");
}
// Verificar si Concepto está vacío
var countConceptos = connection.ExecuteScalar<int>("SELECT COUNT(*) FROM Concepto");
if (countConceptos == 0)
{
connection.Execute("INSERT INTO Concepto (Nombre) VALUES ('Ventas')");
connection.Execute("INSERT INTO Concepto (Nombre) VALUES ('Compras')");
connection.Execute("INSERT INTO Concepto (Nombre) VALUES ('Nómina')");
connection.Execute("INSERT INTO Concepto (Nombre) VALUES ('Servicios')");
}
// Verificar si DepartTrabajo está vacío
var countDeptos = connection.ExecuteScalar<int>("SELECT COUNT(*) FROM DepartTrabajo");
if (countDeptos == 0)
{
connection.Execute("INSERT INTO DepartTrabajo (Nombre) VALUES ('Administración')");
connection.Execute("INSERT INTO DepartTrabajo (Nombre) VALUES ('Ventas')");
connection.Execute("INSERT INTO DepartTrabajo (Nombre) VALUES ('Producción')");
connection.Execute("INSERT INTO DepartTrabajo (Nombre) VALUES ('Logística')");
}
}
public IDbConnection GetConnection()
{
return new SqliteConnection(_connectionString);
}
#region Operaciones para Movimientos
public async Task<int> CreateMovimientoAsync(Movimiento movimiento)
{
using (var connection = GetConnection())
{
var sql = @"INSERT INTO Movimientos
(Monto, TipoMov, DeptoTrabajo, FechaMovimiento, FechaRegistro, Concepto, Descripcion)
VALUES (@Monto, @TipoMov, @DeptoTrabajo, @FechaMovimiento, @FechaRegistro, @Concepto, @Descripcion);
SELECT last_insert_rowid();";
var id = await connection.ExecuteScalarAsync<int>(sql, movimiento);
return id;
}
}
public async Task<IEnumerable<Movimiento>> GetAllMovimientosAsync()
{
using (var connection = GetConnection())
{
var sql = "SELECT * FROM Movimientos ORDER BY FechaMovimiento DESC";
return await connection.QueryAsync<Movimiento>(sql);
}
}
public async Task<IEnumerable<MovimientoCompleto>> GetAllMovimientosCompletosAsync()
{
using (var connection = GetConnection())
{
var sql = @"
SELECT
m.ID, m.Monto, m.FechaMovimiento, m.FechaRegistro, m.Descripcion,
tm.ID as TipoMovID, tm.Nombre as TipoMovNombre,
dt.Id as DeptoTrabajoID, dt.Nombre as DeptoTrabajoNombre,
c.ID as ConceptoID, c.Nombre as ConceptoNombre
FROM Movimientos m
INNER JOIN TipoMovimiento tm ON m.TipoMov = tm.ID
INNER JOIN DepartTrabajo dt ON m.DeptoTrabajo = dt.Id
INNER JOIN Concepto c ON m.Concepto = c.ID
ORDER BY m.FechaMovimiento DESC";
return await connection.QueryAsync<MovimientoCompleto>(sql);
}
}
public async Task<Movimiento> GetMovimientoByIdAsync(int id)
{
using (var connection = GetConnection())
{
var sql = "SELECT * FROM Movimientos WHERE ID = @Id";
return await connection.QueryFirstOrDefaultAsync<Movimiento>(sql, new { Id = id });
}
}
public async Task<bool> UpdateMovimientoAsync(Movimiento movimiento)
{
using (var connection = GetConnection())
{
var sql = @"UPDATE Movimientos SET
Monto = @Monto,
TipoMov = @TipoMov,
DeptoTrabajo = @DeptoTrabajo,
FechaMovimiento = @FechaMovimiento,
Concepto = @Concepto,
Descripcion = @Descripcion
WHERE ID = @ID";
var affectedRows = await connection.ExecuteAsync(sql, movimiento);
return affectedRows > 0;
}
}
public async Task<bool> DeleteMovimientoAsync(int id)
{
using (var connection = GetConnection())
{
var sql = "DELETE FROM Movimientos WHERE ID = @Id";
var affectedRows = await connection.ExecuteAsync(sql, new { Id = id });
return affectedRows > 0;
}
}
#endregion
#region Operaciones para Concepto
public async Task<IEnumerable<Concepto>> GetAllConceptosAsync()
{
using (var connection = GetConnection())
{
var sql = "SELECT * FROM Concepto ORDER BY Nombre";
return await connection.QueryAsync<Concepto>(sql);
}
}
public async Task<int> CreateConceptoAsync(Concepto concepto)
{
using (var connection = GetConnection())
{
var sql = "INSERT INTO Concepto (Nombre) VALUES (@Nombre); SELECT last_insert_rowid();";
return await connection.ExecuteScalarAsync<int>(sql, concepto);
}
}
#endregion
#region Operaciones para DepartTrabajo
public async Task<IEnumerable<DepartTrabajo>> GetAllDepartamentosAsync()
{
using (var connection = GetConnection())
{
var sql = "SELECT * FROM DepartTrabajo ORDER BY Nombre";
return await connection.QueryAsync<DepartTrabajo>(sql);
}
}
public async Task<int> CreateDepartamentoAsync(DepartTrabajo departamento)
{
using (var connection = GetConnection())
{
var sql = "INSERT INTO DepartTrabajo (Nombre, Descripcion) VALUES (@Nombre, @Descripcion); SELECT last_insert_rowid();";
return await connection.ExecuteScalarAsync<int>(sql, departamento);
}
}
public async Task<bool> UpdateDepartamentoAsync(DepartTrabajo departamento)
{
using (var connection = GetConnection())
{
var sql = @"UPDATE DepartTrabajo
SET Nombre = @Nombre,
Descripcion = @Descripcion
WHERE Id = @Id;";
var rowsAffected = await connection.ExecuteAsync(sql, departamento);
return rowsAffected > 0;
}
}
#endregion
#region Operaciones para TipoMovimiento
public async Task<IEnumerable<TipoMovimiento>> GetAllTiposMovimientoAsync()
{
using (var connection = GetConnection())
{
var sql = "SELECT * FROM TipoMovimiento ORDER BY Nombre";
return await connection.QueryAsync<TipoMovimiento>(sql);
}
}
public async Task<int> CreateTipoMovimientoAsync(TipoMovimiento tipoMovimiento)
{
using (var connection = GetConnection())
{
var sql = "INSERT INTO TipoMovimiento (Nombre) VALUES (@Nombre); SELECT last_insert_rowid();";
return await connection.ExecuteScalarAsync<int>(sql, tipoMovimiento);
}
}
#endregion
#region Métodos de exportación
public async Task<string> ExportToCsvAsync(string filePath)
{
var movimientos = await GetAllMovimientosCompletosAsync();
var csv = new StringBuilder();
// Encabezados
csv.AppendLine("ID;FechaMovimiento;Monto;TipoMovimiento;Departamento;Concepto;Descripcion");
// Datos
foreach (var mov in movimientos)
{
csv.AppendLine($"{mov.ID};{mov.FechaMovimiento:yyyy-MM-dd};{mov.Monto};" +
$"{mov.TipoMovNombre};{mov.DeptoTrabajoNombre};{mov.ConceptoNombre};" +
$"\"{mov.Descripcion}\"");
}
// Guardar archivo
await File.WriteAllTextAsync(filePath, csv.ToString(), Encoding.UTF8);
return filePath;
}
#endregion
}

View File

@@ -0,0 +1,42 @@
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
namespace AdminFinanceRCA;
// Interface
public interface IWindowService
{
Window? GetWindowForViewModel(object viewModel);
Window? GetActiveWindow();
Window? GetMainWindow();
}
// Implementación
public class WindowService : IWindowService
{
public Window? GetWindowForViewModel(object viewModel)
{
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return null;
return desktop.Windows.FirstOrDefault(window => ReferenceEquals(window.DataContext, viewModel));
}
public Window? GetActiveWindow()
{
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return null;
return desktop.Windows.FirstOrDefault(w => w.IsActive);
}
public Window? GetMainWindow()
{
if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return null;
return desktop.MainWindow;
}
}

View File

@@ -0,0 +1,30 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using AdminFinanceRCA.ViewModels;
namespace AdminFinanceRCA;
public class ViewLocator : IDataTemplate
{
public Control? Build(object? param)
{
if (param is null)
return null;
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using AdminFinanceRCA.Models;
using AdminFinanceRCA.Views;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace AdminFinanceRCA.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
private readonly FinanzasRepository _repository;
[ObservableProperty]
private ObservableCollection<MovimientoCompleto> _movimientos;
[ObservableProperty]
private ObservableCollection<Concepto> _conceptos;
[ObservableProperty]
private ObservableCollection<DepartTrabajo> _departamentos;
[ObservableProperty]
private ObservableCollection<TipoMovimiento> _tiposMovimiento;
public MainWindowViewModel()
{
_repository = new FinanzasRepository();
CargarDatos();
}
[RelayCommand]
public void AgregarDepartamento()
{
Mantenimiento_DepartTrabajoViewModel mantenimientoDepart = new Mantenimiento_DepartTrabajoViewModel();
Mantenimiento_DepartTrabajo departTrabajo = new Mantenimiento_DepartTrabajo()
{
DataContext = mantenimientoDepart
};
departTrabajo.ShowDialog(GetCurrentWindow<MainWindow>());
}
[RelayCommand]
public void AgregarMovimiento()
{
MovimientoWindowViewModel mwvm = new MovimientoWindowViewModel();
MovimientoWindow mw = new MovimientoWindow();
mw.DataContext = mwvm;
mw.ShowDialog(GetCurrentWindow<MainWindow>());
}
[RelayCommand]
public void Salir()
{
GetCurrentWindow<MainWindow>().Close();
}
private async Task<string> ShowSaveFileDialogAsync(Window window, string defaultFileName = "movimientos.csv")
{
var saveFileDialog = new SaveFileDialog
{
Title = "Guardar archivo CSV",
InitialFileName = defaultFileName,
DefaultExtension = "csv",
Filters = new List<FileDialogFilter>
{
new FileDialogFilter
{
Name = "Archivos CSV",
Extensions = new List<string> { "csv" }
},
new FileDialogFilter
{
Name = "Todos los archivos",
Extensions = new List<string> { "*" }
}
}
};
var result = await saveFileDialog.ShowAsync(window);
return result;
}
[RelayCommand]
public async void CrearCsv()
{
try
{
var window = GetCurrentWindow<MainWindow>(); //WindowService?.GetActiveWindow() ?? WindowService?.GetWindowForViewModel(this);
if (window != null)
{
string result = await ShowSaveFileDialogAsync(window);
if (!string.IsNullOrEmpty(result))
{
var filePath = await _repository.ExportToCsvAsync(result);
Console.WriteLine($"CSV creado en: {filePath}");
// Opcional: abrir el archivo con la aplicación predeterminada
Process.Start(new ProcessStartInfo(filePath) { UseShellExecute = true });
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error al crear CSV: {ex.Message}");
}
}
public async void CargarDatos()
{
try
{
var movimientosTask = _repository.GetAllMovimientosCompletosAsync();
var conceptosTask = _repository.GetAllConceptosAsync();
var departamentosTask = _repository.GetAllDepartamentosAsync();
var tiposTask = _repository.GetAllTiposMovimientoAsync();
await Task.WhenAll(movimientosTask, conceptosTask, departamentosTask, tiposTask);
// Actualizar collections
Movimientos = new ObservableCollection<MovimientoCompleto>(await movimientosTask);
Conceptos = new ObservableCollection<Concepto>(await conceptosTask);
Departamentos = new ObservableCollection<DepartTrabajo>(await departamentosTask);
TiposMovimiento = new ObservableCollection<TipoMovimiento>(await tiposTask);
}
catch (Exception ex)
{
Console.WriteLine($"Error al cargar datos: {ex.Message}");
}
}
}

View File

@@ -0,0 +1,68 @@
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using AdminFinanceRCA.Models;
using AdminFinanceRCA.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Material.Dialog.Views;
namespace AdminFinanceRCA.ViewModels;
public partial class Mantenimiento_DepartTrabajoViewModel : ViewModelBase
{
private readonly FinanzasRepository _departTrabajoService;
[ObservableProperty] private ObservableCollection<DepartTrabajo> _gruposTrabajo;
[ObservableProperty] private DepartTrabajo _grupoSeleccionado;
[ObservableProperty] private DepartTrabajo _grupoEditando;
[ObservableProperty] private bool _estaEditando;
[ObservableProperty] private string _nombre;
[ObservableProperty] private string _descripcion;
public Mantenimiento_DepartTrabajoViewModel()
{
_departTrabajoService = new FinanzasRepository();
_ = CargarDatosAsync();
}
async Task CargarDatosAsync()
{
var dt = await _departTrabajoService.GetAllDepartamentosAsync();
GruposTrabajo = new ObservableCollection<DepartTrabajo>(dt);
}
[RelayCommand]
private void NuevoDepartTrabajo()
{
Nombre = string.Empty;
Descripcion = string.Empty;
EstaEditando = false;
}
[RelayCommand]
private async Task GuardarRegistros()
{
if (EstaEditando)
{
GrupoSeleccionado.Nombre = Nombre;
GrupoSeleccionado.Descripcion = Descripcion;
_departTrabajoService.UpdateDepartamentoAsync(GrupoSeleccionado);
}
else
{
if(string.IsNullOrEmpty(Nombre))
return;
DepartTrabajo depart = new DepartTrabajo(Nombre, Descripcion);
await _departTrabajoService.CreateDepartamentoAsync(depart);
Nombre = string.Empty;
Descripcion = string.Empty;
AlertDialog ad = new AlertDialog();
ad.Title = "Exito";
ad.Content = "Registro agregado con exito";
ad.Show(GetCurrentWindow<Mantenimiento_DepartTrabajo>());
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using AdminFinanceRCA.Models;
using AdminFinanceRCA.Views;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace AdminFinanceRCA.ViewModels;
public partial class MovimientoWindowViewModel : ViewModelBase
{
private readonly FinanzasRepository _finanzasRepository;
[ObservableProperty] private ObservableCollection<DepartTrabajo> _departTrabajos;
[ObservableProperty] private ObservableCollection<TipoMovimiento> _tipoMovimientos;
[ObservableProperty] private ObservableCollection<Concepto> _conceptos;
[ObservableProperty] private DateTime _fechaMov;
[ObservableProperty] private decimal _montoDecimal;
[ObservableProperty] private string _descripcion;
[ObservableProperty] private TipoMovimiento _tipoMovimientoSelecionado;
[ObservableProperty] private DepartTrabajo _departaDepartTrabajoSeleccionado;
[ObservableProperty] private Concepto _conceptoSeleccionado;
public MovimientoWindowViewModel()
{
_fechaMov = DateTime.Now;
_finanzasRepository = new FinanzasRepository();
_ = CargarDatosAsync();
}
private async Task CargarDatosAsync()
{
var dt = await _finanzasRepository.GetAllDepartamentosAsync();
DepartTrabajos = new ObservableCollection<DepartTrabajo>(dt);
var tm = await _finanzasRepository.GetAllTiposMovimientoAsync();
TipoMovimientos = new ObservableCollection<TipoMovimiento>(tm);
var cpt = await _finanzasRepository.GetAllConceptosAsync();
Conceptos = new ObservableCollection<Concepto>(cpt);
}
[RelayCommand]
public async void GuardarDatosAsync()
{
Movimiento mv = new Movimiento(MontoDecimal, TipoMovimientoSelecionado.ID, DepartaDepartTrabajoSeleccionado.Id,
FechaMov, ConceptoSeleccionado.ID, Descripcion);
await _finanzasRepository.CreateMovimientoAsync(mv);
}
[RelayCommand]
public void Salir()
{
GetCurrentWindow<MovimientoWindow>().Close();
}
}

View File

@@ -0,0 +1,28 @@
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using CommunityToolkit.Mvvm.ComponentModel;
namespace AdminFinanceRCA.ViewModels;
public class ViewModelBase : ObservableObject
{
protected IWindowService? WindowService { get; set; }
/// <summary>
/// Obtiene la ventana asociada al ViewModel actual.
/// </summary>
/// <typeparam name="TWindow">El tipo de ventana a obtener (por ejemplo, MainWindow, LoginWindow).</typeparam>
/// <returns>La ventana asociada al ViewModel, o null si no se encuentra.</returns>
public TWindow? GetCurrentWindow<TWindow>() where TWindow : Window
{
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
//return desktop.Windows.OfType<TWindow>().FirstOrDefault(w => w.DataContext == this);
return desktop.Windows.OfType<TWindow>().FirstOrDefault(w => w.DataContext == this);
}
return null;
}
}

View File

@@ -0,0 +1,113 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:AdminFinanceRCA.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="950" d:DesignHeight="500"
x:Class="AdminFinanceRCA.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="AdminFinanceRCA"
WindowState="Maximized"
WindowStartupLocation="CenterScreen"
FontFamily="Segoe UI">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<DockPanel LastChildFill="True" Background="#F5F5F5">
<!-- Menú superior estilo moderno -->
<Menu DockPanel.Dock="Top" Background="#2C3E50" Foreground="White" Height="35" VerticalAlignment="Top">
<!-- Menú Archivo -->
<MenuItem Header="Archivo">
<MenuItem Header="Exportar CSV" Command="{Binding CrearCsvCommand}"/>
<Separator/>
<MenuItem Header="Salir" Command="{Binding SalirCommand}" />
</MenuItem>
<!-- Menú Herramientas -->
<MenuItem Header="Herramientas">
<MenuItem Header="Departamentos" Command="{Binding AgregarDepartamentoCommand}" />
<MenuItem Header="Tipos de Movimiento" />
<MenuItem Header="Conceptos"/>
</MenuItem>
</Menu>
<!-- Título con estilo moderno -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" HorizontalAlignment="Center" >
<TextBlock FontSize="24" Margin="0 15" Text="Administrador Financiero Grupos"
Foreground="Black" FontWeight="SemiBold"/>
</StackPanel>
<!-- Botones flotantes estilo moderno -->
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 10 20 20">
<Button Content="Agregar Movimiento"
Background="#27AE60" Foreground="White" FontWeight="Bold"
Padding="15 8" CornerRadius="5" Margin="0 0 10 0" Command="{Binding AgregarMovimientoCommand}"/>
</StackPanel>
<!-- DataGrid con estilo moderno -->
<DataGrid Margin="15" HorizontalAlignment="Stretch" BorderThickness="1" CornerRadius="3" ItemsSource="{Binding Movimientos}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="ID" Width="80">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ID}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Fecha Mov" Width="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FechaMovimiento}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Grupo de Trabajo" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DeptoTrabajoNombre}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Monto" Width="120">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Monto}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Tipo Movimiento" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding TipoMovNombre}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Concepto" Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ConceptoNombre}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Descripcion" Width="250">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Descripcion}" Foreground="Black" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>

View File

@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace AdminFinanceRCA.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,64 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="using:AdminFinanceRCA.ViewModels"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="350" CanResize="False"
Width="800" Height="350"
WindowStartupLocation="CenterScreen"
x:DataType="vm:Mantenimiento_DepartTrabajoViewModel"
x:Class="AdminFinanceRCA.Views.Mantenimiento_DepartTrabajo"
Title="Mantenimiento Departamentos de Trabajo">
<Design.DataContext>
<vm:Mantenimiento_DepartTrabajoViewModel/>
</Design.DataContext>
<DockPanel Margin="10">
<!-- Barra de herramientas -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,10" Spacing="5">
<Button Content="Nuevo" Width="90" Command="{Binding NuevoDepartTrabajoCommand}" />
<Button Content="Guardar" Width="90" Command="{Binding GuardarRegistrosCommand}"/>
<Button Content="Cancelar" Width="90" />
</StackPanel>
<Grid ColumnDefinitions="*,2*" Margin="0,10,0,0" ShowGridLines="False">
<!-- Lista de grupos -->
<StackPanel Grid.Column="0" Margin="0,0,10,0">
<TextBlock Text="Grupos de Trabajo" FontWeight="Bold" Margin="0,0,0,5"/>
<ListBox ItemsSource="{Binding GruposTrabajo}" DoubleTapped="OnListBoxDoubleTapped"
Height="200">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock FontWeight="Bold"/>
<TextBlock Foreground="Gray" Text="{Binding Nombre}"
TextTrimming="CharacterEllipsis"/>
<TextBlock />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
<!-- Formulario de edición -->
<Border Grid.Column="1" Margin="0 0 0 0" BorderBrush="LightGray" BorderThickness="3" Padding="10" Height="250" Width="500">
<StackPanel Spacing="10">
<TextBlock Text="Editar Grupo" FontSize="16" FontWeight="Bold"/>
<StackPanel>
<TextBlock Text="Nombre *" Margin="0,0,0,2"/>
<TextBox Watermark="Ingrese el nombre" Text="{Binding Nombre}"/>
</StackPanel>
<StackPanel>
<TextBlock Text="Descripción" Margin="0,0,0,2"/>
<TextBox AcceptsReturn="True"
Watermark="Ingrese la descripción" Height="60" Text="{Binding Descripcion}"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</DockPanel>
</Window>

View File

@@ -0,0 +1,29 @@
using AdminFinanceRCA.Models;
using AdminFinanceRCA.ViewModels;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
namespace AdminFinanceRCA.Views;
public partial class Mantenimiento_DepartTrabajo : Window
{
public Mantenimiento_DepartTrabajo()
{
InitializeComponent();
}
private void OnListBoxDoubleTapped(object sender, TappedEventArgs e)
{
if (DataContext is Mantenimiento_DepartTrabajoViewModel viewModel &&
sender is ListBox listBox &&
listBox.SelectedItem is DepartTrabajo selected)
{
viewModel.GrupoSeleccionado = selected;
viewModel.Nombre = selected.Nombre;
viewModel.Descripcion = selected.Descripcion;
viewModel.EstaEditando = true;
}
}
}

View File

@@ -0,0 +1,93 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="500" Width="600" Height="500"
CanResize="False"
x:Class="AdminFinanceRCA.Views.MovimientoWindow"
xmlns:vm="using:AdminFinanceRCA.ViewModels"
x:DataType="vm:MovimientoWindowViewModel"
Title="Agregar Movimiento"
FontFamily="Segoe UI"
FontSize="12"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterScreen">
<Design.DataContext>
<vm:MovimientoWindowViewModel/>
</Design.DataContext>
<Grid Margin="20" Width="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Título -->
<TextBlock Grid.Row="0" Grid.ColumnSpan="2" Text="Nuevo Movimiento"
FontSize="20" FontWeight="Bold" Margin="0 0 0 20"
HorizontalAlignment="Center"/>
<!-- Departamento de Trabajo -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="Departamento:" VerticalAlignment="Center" Margin="0 5"/>
<ComboBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding DepartTrabajos}" SelectedItem="{Binding DepartaDepartTrabajoSeleccionado}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Nombre}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Tipo de Movimiento -->
<TextBlock Grid.Row="2" Grid.Column="0" Text="Tipo Movimiento:" VerticalAlignment="Center" Margin="0 5"/>
<ComboBox Grid.Row="2" Grid.Column="1" Margin="0 5" ItemsSource="{Binding TipoMovimientos}" SelectedItem="{Binding TipoMovimientoSelecionado}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Nombre}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Concepto -->
<TextBlock Grid.Row="3" Grid.Column="0" Text="Concepto:" VerticalAlignment="Center" Margin="0 5"/>
<ComboBox Grid.Row="3" Grid.Column="1" Margin="0 0" ItemsSource="{Binding Conceptos}" SelectedItem="{Binding ConceptoSeleccionado}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Nombre}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Monto -->
<TextBlock Grid.Row="4" Grid.Column="0" Text="Monto:" VerticalAlignment="Center" Margin="0 5" FontSize="14"/>
<TextBox Grid.Row="4" Grid.Column="1" Margin="0 5" Height="35" Watermark="Ingrese el monto" Text="{Binding MontoDecimal, StringFormat='{}{0:0.00}'}" FontSize="14"/>
<!-- Fecha de Movimiento -->
<TextBlock Grid.Row="5" Grid.Column="0" Text="Fecha Movimiento:" VerticalAlignment="Center" Margin="0 5"/>
<DatePicker Grid.Row="5" Grid.Column="1" Margin="0 5" Height="35" SelectedDate="{Binding FechaMov}" DayFormat="dd/MM/yyyy"/>
<!-- Descripción -->
<TextBlock Grid.Row="6" Grid.Column="0" Text="Descripción:" VerticalAlignment="Top" Margin="0 10 0 5"/>
<TextBox Grid.Row="6" Grid.Column="1" Margin="0 5" Height="80" AcceptsReturn="True" TextWrapping="Wrap" Watermark="Ingrese una descripción opcional" Text="{Binding Descripcion}"/>
<!-- Botones -->
<StackPanel Grid.Row="7" Grid.ColumnSpan="2" Orientation="Horizontal"
HorizontalAlignment="Right" Margin="0 20 0 0">
<Button Content="Cancelar" Width="100" Height="35" Margin="0 0 10 0"
Background="#E74C3C" Foreground="White" Command="{Binding SalirCommand}"/>
<Button Content="Guardar" Width="100" Height="35"
Background="#27AE60" Foreground="White" FontWeight="Bold" Command="{Binding GuardarDatosAsyncCommand}"/>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace AdminFinanceRCA.Views;
public partial class MovimientoWindow : Window
{
public MovimientoWindow()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="AdminFinanceRCA.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

View File

@@ -0,0 +1,12 @@
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=/home/adalberto/Documentos/RocaFinanceGrupos.db"
},
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}