Add transaction dialog and enhance transaction view
This commit is contained in:
parent
d21c49d486
commit
ece9618f09
13 changed files with 240 additions and 19 deletions
|
|
@ -3,7 +3,7 @@ using Schaad.Accounting.Models;
|
|||
|
||||
namespace Schaad.Accounting.Datasets
|
||||
{
|
||||
public class TransactionDataset : Transaction
|
||||
public record TransactionDataset : Transaction
|
||||
{
|
||||
public Account OriginAccount { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ namespace Schaad.Accounting.Interfaces
|
|||
void SaveTransaction(Transaction transaction);
|
||||
|
||||
Transaction GetTransaction(string id);
|
||||
void DeleteTransaction(string id);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||
|
||||
namespace Schaad.Accounting.Models
|
||||
{
|
||||
public class Transaction
|
||||
public record Transaction
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string BankTransactionId { get; set; }
|
||||
|
|
@ -18,21 +18,26 @@ namespace Schaad.Accounting.Models
|
|||
public string RelatedParty { get; set; }
|
||||
|
||||
[Display(Name = "Valuta")]
|
||||
[Required]
|
||||
public DateTime ValueDate { get; set; }
|
||||
|
||||
[Display(Name = "Buchung")]
|
||||
public DateTime BookingDate { get; set; }
|
||||
|
||||
[Display(Name = "Buchungstext")]
|
||||
[Required]
|
||||
public string Text { get; set; }
|
||||
|
||||
[Display(Name = "Betrag")]
|
||||
[Required]
|
||||
public decimal Value { get; set; }
|
||||
|
||||
[Display(Name = "Habenkonto")]
|
||||
[Required]
|
||||
public string OriginAccountId { get; set; }
|
||||
|
||||
[Display(Name = "Sollkonto")]
|
||||
[Required]
|
||||
public string TargetAccountId { get; set; }
|
||||
|
||||
[Display(Name = "Währungskurs")]
|
||||
|
|
|
|||
|
|
@ -76,5 +76,15 @@ namespace Schaad.Accounting.Repositories
|
|||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete transaction
|
||||
/// </summary>
|
||||
public void DeleteTransaction(string id)
|
||||
{
|
||||
var transactions = GetTransactionList();
|
||||
transactions.RemoveAll(t => t.Id == id);
|
||||
Save(transactions, TRANSACTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -136,8 +136,7 @@ namespace Schaad.Accounting.Services
|
|||
new TransactionDataset(
|
||||
t,
|
||||
accountList.Single(a => a.Id == t.OriginAccountId),
|
||||
accountList.Single(a => a.Id == t.TargetAccountId)
|
||||
)
|
||||
accountList.Single(a => a.Id == t.TargetAccountId))
|
||||
)
|
||||
.ToList();
|
||||
|
||||
|
|
@ -155,7 +154,7 @@ namespace Schaad.Accounting.Services
|
|||
var transactionViewList = transactionList.Select(
|
||||
t =>
|
||||
new TransactionDataset(
|
||||
t,
|
||||
Prepare(t),
|
||||
accountList.Single(a => a.Id == t.OriginAccountId),
|
||||
accountList.Single(a => a.Id == t.TargetAccountId)
|
||||
)
|
||||
|
|
@ -163,6 +162,18 @@ namespace Schaad.Accounting.Services
|
|||
.ToList();
|
||||
|
||||
return transactionViewList;
|
||||
|
||||
Transaction Prepare(Transaction t)
|
||||
{
|
||||
var account = accountList.Single(a => a.Id == t.OriginAccountId);
|
||||
|
||||
if (account.Class == ClassIds.Activa && accountId == t.OriginAccountId )
|
||||
{
|
||||
return t with { Value = -t.Value };
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public partial class MyHeader : ComponentBase
|
|||
private int selectedYear;
|
||||
|
||||
private List<string> mandators = new ();
|
||||
private string selectedMandator;
|
||||
private string selectedMandator = null!;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
@using Schaad.Accounting.Models
|
||||
@implements IDialogContentComponent<Schaad.Accounting.Models.Transaction>
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<FluentDialogHeader ShowDismiss="true">
|
||||
<FluentStack VerticalAlignment="VerticalAlignment.Center">
|
||||
<FluentIcon Value="@(new Icons.Regular.Size24.WindowApps())" />
|
||||
<FluentLabel Typo="Typography.PaneHeader">
|
||||
@Dialog.Instance.Parameters.Title
|
||||
</FluentLabel>
|
||||
</FluentStack>
|
||||
</FluentDialogHeader>
|
||||
|
||||
<FluentDialogBody>
|
||||
<EditForm EditContext="@editContext">
|
||||
<DataAnnotationsValidator />
|
||||
<FluentDatePicker @bind-Value="@SelectedValue" Label="Valuta" Style="width: 300px;"/>
|
||||
<FluentSelect TOption="Account"
|
||||
Label="von"
|
||||
Items="@accounts"
|
||||
Width="300px"
|
||||
Height="250px"
|
||||
Required="true"
|
||||
Placeholder="Konto auswählen..."
|
||||
OptionValue="@(p => p.Id)"
|
||||
OptionText="@(p => p.Number + " / " + p.Name)"
|
||||
@bind-Value="@Content.OriginAccountId" />
|
||||
<FluentSelect TOption="Account"
|
||||
Label="nach"
|
||||
Items="@accounts"
|
||||
Width="300px"
|
||||
Height="250px"
|
||||
Required="true"
|
||||
Placeholder="Konto auswählen..."
|
||||
OptionValue="@(p => p.Id)"
|
||||
OptionText="@(p => p.Number + " / " + p.Name)"
|
||||
@bind-Value="@Content.TargetAccountId" />
|
||||
<FluentNumberField @bind-Value="@Content.Value" Label="Betrag" Style="width: 300px;"/>
|
||||
<FluentTextField @bind-Value="@Content.Text" Label="Buchungstext" Style="width: 300px;" />
|
||||
|
||||
<div>
|
||||
<FluentValidationSummary />
|
||||
</div>
|
||||
</EditForm>
|
||||
</FluentDialogBody>
|
||||
|
||||
<FluentDialogFooter>
|
||||
<FluentButton Appearance="Appearance.Neutral"
|
||||
OnClick="@CancelAsync">
|
||||
Abbrechen
|
||||
</FluentButton>
|
||||
<FluentButton Appearance="Appearance.Accent"
|
||||
OnClick="@SaveAsync">
|
||||
Speichern
|
||||
</FluentButton>
|
||||
</FluentDialogFooter>
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Schaad.Accounting.Interfaces;
|
||||
using Schaad.Accounting.Models;
|
||||
|
||||
namespace Schaad.Accounting.UI.Components.Pages.Dialogs;
|
||||
|
||||
public partial class TransactionDialog : ComponentBase
|
||||
{
|
||||
private EditContext editContext = null!;
|
||||
|
||||
[CascadingParameter]
|
||||
public FluentDialog Dialog { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public Transaction Content { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ITransactionRepository transactionRepository { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IViewService viewService { get; set; } = null!;
|
||||
|
||||
private IReadOnlyList<Account> accounts = [];
|
||||
private DateTime? SelectedValue;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
SelectedValue = Content.ValueDate;
|
||||
editContext = new EditContext(Content);
|
||||
accounts = viewService.GetAccountViewList();
|
||||
}
|
||||
|
||||
private async Task SaveAsync()
|
||||
{
|
||||
if (editContext.Validate())
|
||||
{
|
||||
Content.ValueDate = SelectedValue!.Value;
|
||||
Content.BookingDate = SelectedValue!.Value;
|
||||
transactionRepository.SaveTransaction(Content);
|
||||
await Dialog.CloseAsync(Content);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CancelAsync()
|
||||
{
|
||||
await Dialog.CancelAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
</div>
|
||||
<div style="margin-left: auto;">
|
||||
<FluentBadge Appearance="Appearance.Neutral">
|
||||
@account.BalanceCHF.ToString("C2")
|
||||
@Math.Abs(account.BalanceCHF).ToString("C2")
|
||||
</FluentBadge>
|
||||
</div>
|
||||
</FluentStack>
|
||||
|
|
@ -29,21 +29,35 @@
|
|||
</FluentNavMenu>
|
||||
|
||||
<FluentBodyContent>
|
||||
<FluentPaginator State="@pagination" SummaryTemplate="@template" />
|
||||
|
||||
<FluentDataGrid Items="@transactionList" Pagination="@pagination">
|
||||
<PropertyColumn Property="@(p => p.BookingDate)" Format="dd.MM.yyyy" Sortable="true" IsDefaultSortColumn="true" InitialSortDirection="SortDirection.Descending" />
|
||||
<PropertyColumn Property="@(p => p.ValueDate)" Format="dd.MM.yyyy" Sortable="true" />
|
||||
<PropertyColumn Property="@(p => p.Text)" />
|
||||
<FluentGrid Justify="JustifyContent.FlexStart">
|
||||
<FluentGridItem xs="4" Class="align-content-center title">
|
||||
@selectedAccount.Name
|
||||
</FluentGridItem>
|
||||
<FluentGridItem xs="4" Class="align-content-center">
|
||||
Total @Math.Abs(selectedAccount.Balance).ToString("C2") in @transactionList?.Count() Transaktionen
|
||||
</FluentGridItem>
|
||||
<FluentGridItem xs="4" Class="align-content-center" Justify="JustifyContent.FlexEnd">
|
||||
<FluentButton IconStart="@(new Icons.Regular.Size16.Add())" Appearance="Appearance.Neutral" OnClick="AddAsync">Neue Transaktion hinzufügen</FluentButton>
|
||||
</FluentGridItem>
|
||||
</FluentGrid>
|
||||
|
||||
<FluentPaginator State="@pagination" SummaryTemplate="@template"/>
|
||||
<FluentDataGrid Items="@transactionList" Pagination="@pagination" RowSize="DataGridRowSize.Medium">
|
||||
<PropertyColumn Property="@(p => p.BookingDate)" Format="dd.MM.yyyy" Sortable="true" IsDefaultSortColumn="true" InitialSortDirection="SortDirection.Descending"/>
|
||||
<PropertyColumn Property="@(p => p.ValueDate)" Format="dd.MM.yyyy" Sortable="true"/>
|
||||
<PropertyColumn Property="@(p => p.Text)"/>
|
||||
<TemplateColumn Title="Gegenkonto">
|
||||
@GetAccountName(context)
|
||||
</TemplateColumn>
|
||||
<PropertyColumn Property="@(p => p.Value)" Format="C2" Align="Align.End"/>
|
||||
|
||||
|
||||
<TemplateColumn Align="Align.Center" Width="50px">
|
||||
<FluentButton IconEnd="@(new Icons.Regular.Size16.Delete())" Appearance="Appearance.Neutral" OnClick="@(() => DeleteAsync(context.Id))"/>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn Align="Align.Center" Width="50px">
|
||||
<FluentButton IconEnd="@(new Icons.Regular.Size16.Edit())" Appearance="Appearance.Neutral" OnClick="@(() => EditAsync(context.Id))"/>
|
||||
</TemplateColumn>
|
||||
</FluentDataGrid>
|
||||
</FluentBodyContent>
|
||||
|
||||
</FluentStack>
|
||||
|
||||
@code
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Schaad.Accounting.Datasets;
|
||||
using Schaad.Accounting.Interfaces;
|
||||
using Schaad.Accounting.Models;
|
||||
using Schaad.Accounting.UI.Components.Pages.Dialogs;
|
||||
|
||||
namespace Schaad.Accounting.UI.Components.Pages;
|
||||
|
||||
|
|
@ -8,21 +11,30 @@ public partial class Transactions : ComponentBase
|
|||
{
|
||||
[Inject]
|
||||
private IViewService viewService { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ITransactionRepository transactionRepository { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IDialogService dialogService { get; set; } = null!;
|
||||
|
||||
private IReadOnlyList<AccountDataset> accounts = null!;
|
||||
|
||||
private IQueryable<TransactionDataset>? transactionList;
|
||||
private string? selectedAccountId;
|
||||
private string selectedAccountId = null!;
|
||||
private AccountDataset selectedAccount = null!;
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
accounts = viewService.GetAccountViewList();
|
||||
return base.OnInitializedAsync();
|
||||
accounts = viewService.GetAccountViewList();
|
||||
ShowTransactions(accounts.First().Id);
|
||||
return base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private void ShowTransactions(string accountId)
|
||||
{
|
||||
selectedAccountId = accountId;
|
||||
selectedAccount = accounts.Single(a => a.Id == accountId);
|
||||
transactionList = viewService.GetTransactionViewList(accountId).AsQueryable();
|
||||
}
|
||||
|
||||
|
|
@ -35,4 +47,57 @@ public partial class Transactions : ComponentBase
|
|||
|
||||
return transaction.OriginAccount.Name;
|
||||
}
|
||||
|
||||
private async Task AddAsync()
|
||||
{
|
||||
var data = new Transaction
|
||||
{
|
||||
ValueDate = DateTime.Now,
|
||||
BookingDate = DateTime.Now,
|
||||
TargetAccountId = selectedAccountId
|
||||
};
|
||||
var dialog = await dialogService.ShowDialogAsync<TransactionDialog>(data, new DialogParameters()
|
||||
{
|
||||
Height = "500px",
|
||||
Title = "Transaktion",
|
||||
PreventDismissOnOverlayClick = true,
|
||||
PreventScroll = true,
|
||||
});
|
||||
|
||||
var result = await dialog.Result;
|
||||
if (!result.Cancelled && result.Data != null)
|
||||
{
|
||||
transactionList = viewService.GetTransactionViewList(selectedAccountId).AsQueryable();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task EditAsync(string id)
|
||||
{
|
||||
var data = transactionRepository.GetTransaction(id);
|
||||
var dialog = await dialogService.ShowDialogAsync<TransactionDialog>(data, new DialogParameters()
|
||||
{
|
||||
Height = "500px",
|
||||
Title = "Transaktion",
|
||||
PreventDismissOnOverlayClick = true,
|
||||
PreventScroll = true,
|
||||
});
|
||||
|
||||
var result = await dialog.Result;
|
||||
if (!result.Cancelled && result.Data != null)
|
||||
{
|
||||
transactionList = viewService.GetTransactionViewList(selectedAccountId).AsQueryable();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteAsync(string id)
|
||||
{
|
||||
var transaction = transactionRepository.GetTransaction(id);
|
||||
var dialog = await dialogService.ShowConfirmationAsync($"Transaction '{transaction.Text}' mit Betrag {transaction.Value} wirklich löschen?", "Ja", "Nein", "Transaktion löschen");
|
||||
var result = await dialog.Result;
|
||||
if (!result.Cancelled)
|
||||
{
|
||||
transactionRepository.DeleteTransaction(id);
|
||||
transactionList = viewService.GetTransactionViewList(selectedAccountId).AsQueryable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
.title {
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
@using System.ComponentModel.DataAnnotations
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.FluentUI.AspNetCore.Components.Extensions
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
|
|
|
|||
|
|
@ -27,4 +27,9 @@
|
|||
<PackageReference Include="Plotly.Blazor" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Components\Pages\Transactions.razor.css" />
|
||||
<Content Include="Components\Pages\Transactions.razor.css" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Reference in a new issue