K19 fertig.

Erstellte Dateien:
  - src/Koogle.Web/Components/Pages/CashBook/MembershipFeeDialog.razor - Dialog mit Monat/Jahr-Auswahl, optionalem Betrags-Override, Warnung bei bestehenden Beiträgen

  Geänderte Dateien:
  - CashBook.razor - Button "Mitgliedsbeiträge" hinzugefügt
  - CashBook.razor.cs - OpenMembershipFeeDialog() Methode, prüft auf existierende Beiträge

  Features:
  - Monat/Jahr-Auswahl
  - Optionaler Betrags-Override (Switch)
  - Warnung bei existierenden Beiträgen für gewählten Monat
  - Dispatched CreateMembershipFeesAction
This commit is contained in:
beo3000 2026-01-03 22:12:21 +01:00
parent 8a9096c95e
commit a59fdac5d5
4 changed files with 138 additions and 1 deletions

View File

@ -1717,7 +1717,7 @@ public enum CashBookEntryType { Income = 0, Expense = 1 }
| ✓ | K16 | Application | Excel Export (ClosedXML) | 3 |
| ✓ | K17 | Application | PDF Export (QuestPDF) | 1 |
| ✓ | K18 | Web | Export Controller | 1 |
| | K19 | Web | Membership Fees Feature | 2 |
| | K19 | Web | Membership Fees Feature | 2 |
| ☐ | K20 | Web | Club Settings Extension | 3 |
| ☐ | K21 | Web | Navigation Integration | 1 |
| ☐ | K22 | Tests | Unit Tests | 2 |

View File

@ -69,6 +69,10 @@
Filtern
</MudButton>
<MudSpacer />
<MudButton Variant="Variant.Outlined" Color="Color.Info" StartIcon="@Icons.Material.Filled.GroupAdd"
OnClick="OpenMembershipFeeDialog">
Mitgliedsbeiträge
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Success" StartIcon="@Icons.Material.Filled.Add"
OnClick="OpenCreateDialog">
Neue Buchung

View File

@ -114,4 +114,27 @@ public partial class CashBook
Snackbar.Add("Buchung wird gelöscht...", Severity.Info);
}
}
private async Task OpenMembershipFeeDialog()
{
// Check if there are existing membership fees for current month
var hasExisting = CashBookState.Value.Entries
.Any(e => e.CategoryName == "Mitgliedsbeitrag"
&& e.BookingDate.Month == DateTime.Today.Month
&& e.BookingDate.Year == DateTime.Today.Year);
var parameters = new DialogParameters
{
{ "HasExistingFees", hasExisting }
};
var dialog = await DialogService.ShowAsync<MembershipFeeDialog>("Mitgliedsbeiträge erfassen", parameters);
var result = await dialog.Result;
if (result != null && !result.Canceled && result.Data is CreateMembershipFeesDto dto)
{
Dispatcher.Dispatch(new CreateMembershipFeesAction(dto));
Snackbar.Add("Mitgliedsbeiträge werden erstellt...", Severity.Info);
}
}
}

View File

@ -0,0 +1,110 @@
@using Koogle.Application.DTOs
<MudDialog>
<TitleContent>
<MudText Typo="Typo.h6">Mitgliedsbeiträge erfassen</MudText>
</TitleContent>
<DialogContent>
<MudText Class="mb-4">
Erstellt automatisch Einnahme-Buchungen für alle aktiven Mitglieder.
</MudText>
<MudStack Row="true" Spacing="4" Class="mb-4">
<MudSelect T="int" @bind-Value="_selectedMonth" Label="Monat" Style="width: 150px;">
@for (int m = 1; m <= 12; m++)
{
<MudSelectItem Value="@m">@GetMonthName(m)</MudSelectItem>
}
</MudSelect>
<MudSelect T="int" @bind-Value="_selectedYear" Label="Jahr" Style="width: 120px;">
@for (int y = DateTime.Today.Year; y >= DateTime.Today.Year - 2; y--)
{
<MudSelectItem Value="@y">@y</MudSelectItem>
}
</MudSelect>
</MudStack>
<MudSwitch @bind-Value="_useOverride" Label="Betrag überschreiben" Color="Color.Primary" Class="mb-2" />
@if (_useOverride)
{
<MudNumericField @bind-Value="_overrideAmount"
Label="Beitragshöhe"
Format="N2"
Adornment="Adornment.Start"
AdornmentText="€"
Min="0.01m"
HelperText="Überschreibt den Standard-Mitgliedsbeitrag"
Class="mb-4" />
}
else
{
<MudText Typo="Typo.body2" Color="Color.Secondary" Class="mb-4">
Es wird der in den Club-Einstellungen hinterlegte Standardbeitrag verwendet.
</MudText>
}
@if (_showWarning)
{
<MudAlert Severity="Severity.Warning" Class="mb-4">
Für @GetMonthName(_selectedMonth) @_selectedYear wurden bereits Mitgliedsbeiträge erfasst.
Trotzdem fortfahren?
</MudAlert>
}
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Abbrechen</MudButton>
<MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="Submit">
Beiträge erstellen
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
private IMudDialogInstance? MudDialog { get; set; }
[Parameter]
public bool HasExistingFees { get; set; }
private int _selectedMonth = DateTime.Today.Month;
private int _selectedYear = DateTime.Today.Year;
private bool _useOverride;
private decimal _overrideAmount = 10.00m;
private bool _showWarning;
protected override void OnParametersSet()
{
_showWarning = HasExistingFees;
}
private static string GetMonthName(int month) => month switch
{
1 => "Januar",
2 => "Februar",
3 => "März",
4 => "April",
5 => "Mai",
6 => "Juni",
7 => "Juli",
8 => "August",
9 => "September",
10 => "Oktober",
11 => "November",
12 => "Dezember",
_ => month.ToString()
};
private void Cancel() => MudDialog?.Cancel();
private void Submit()
{
var dto = new CreateMembershipFeesDto
{
Year = _selectedYear,
Month = _selectedMonth,
OverrideAmount = _useOverride ? _overrideAmount : null
};
MudDialog?.Close(DialogResult.Ok(dto));
}
}