Added Slop

This commit is contained in:
joel.leirer
2026-08-25 17:14:54 +02:00
commit fb1f90a9ca
151 changed files with 5870 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Lagerprogramm.Models;
namespace Lagerprogramm.ViewModels;
public class AdditionSearchDialogViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<Addition> _allAdditions;
private readonly ObservableCollection<Addition> _filteredAdditions;
private string _searchText = string.Empty;
private Addition? _selectedAddition;
public ObservableCollection<Addition> FilteredAdditions => _filteredAdditions;
public Addition? SelectedAddition
{
get => _selectedAddition;
set
{
_selectedAddition = value;
OnPropertyChanged();
}
}
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
FilterAdditions();
OnPropertyChanged();
}
}
public AdditionSearchDialogViewModel(ObservableCollection<Addition> additions)
{
_allAdditions = additions;
_filteredAdditions = new ObservableCollection<Addition>(additions);
}
private void FilterAdditions()
{
_filteredAdditions.Clear();
if (string.IsNullOrWhiteSpace(SearchText))
{
foreach (var a in _allAdditions)
_filteredAdditions.Add(a);
return;
}
var query = SearchText.ToLower();
var matches = _allAdditions.Where(a =>
a.Comment.ToLower().Contains(query) ||
a.Date.ToString("yyyy-MM-dd").Contains(query) ||
a.Lines.Any(l => l.PartInternalNumber.ToLower().Contains(query))
).ToList();
foreach (var a in matches)
_filteredAdditions.Add(a);
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

View File

@@ -0,0 +1,119 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Lagerprogramm.Models;
using Lagerprogramm.Services;
namespace Lagerprogramm.ViewModels;
public partial class AdditionsViewModel : ObservableObject
{
private readonly JsonDataService _dataService;
private readonly AppData _appData;
public AppData AppData => _appData;
[ObservableProperty]
private ObservableCollection<Addition> _additions = new();
[ObservableProperty]
private ObservableCollection<TransactionLine> _lines = new();
[ObservableProperty]
private DateTime _date = DateTime.Now;
[ObservableProperty]
private string _comment = string.Empty;
public ObservableCollection<string> PartNumbers { get; } = new();
public AdditionsViewModel(JsonDataService dataService, AppData appData)
{
_dataService = dataService;
_appData = appData;
RefreshPartNumbers();
foreach (var a in appData.Additions.OrderByDescending(a => a.Date))
Additions.Add(a);
Lines.Add(new TransactionLine());
}
[RelayCommand]
private void AddLine() => Lines.Add(new TransactionLine());
[RelayCommand]
private void RemoveLine(TransactionLine? line)
{
if (line is null) return;
Lines.Remove(line);
}
[RelayCommand]
private void SearchPart(TransactionLine? line)
{
}
[RelayCommand]
private void SearchAddition()
{
}
[RelayCommand]
private void Save()
{
if (Lines.Count == 0) return;
if (Lines.Any(l => string.IsNullOrWhiteSpace(l.PartInternalNumber) || l.Quantity <= 0))
return;
var addition = new Addition
{
Date = Date,
Comment = Comment.Trim(),
Lines = Lines.Select(l => new TransactionLine
{
PartInternalNumber = l.PartInternalNumber.Trim(),
Quantity = l.Quantity
}).ToList()
};
_appData.Additions.Add(addition);
Additions.Insert(0, addition);
foreach (var line in addition.Lines)
{
var part = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == line.PartInternalNumber);
if (part is not null)
part.StockQuantity += line.Quantity;
}
_dataService.Save(_appData);
Comment = string.Empty;
Date = DateTime.Now;
Lines.Clear();
Lines.Add(new TransactionLine());
RefreshPartNumbers();
}
[RelayCommand]
private void DeleteAddition(Addition? addition)
{
if (addition is null) return;
foreach (var line in addition.Lines)
{
var part = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == line.PartInternalNumber);
if (part is not null)
part.StockQuantity -= line.Quantity;
}
_appData.Additions.Remove(addition);
Additions.Remove(addition);
_dataService.Save(_appData);
RefreshPartNumbers();
}
private void RefreshPartNumbers()
{
PartNumbers.Clear();
foreach (var p in _appData.Parts.OrderBy(p => p.InternalPartNumber))
PartNumbers.Add(p.InternalPartNumber);
}
}

View File

@@ -0,0 +1,69 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Lagerprogramm.Models;
namespace Lagerprogramm.ViewModels;
public class DeductionSearchDialogViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<Deduction> _allDeductions;
private readonly ObservableCollection<Deduction> _filteredDeductions;
private string _searchText = string.Empty;
private Deduction? _selectedDeduction;
public ObservableCollection<Deduction> FilteredDeductions => _filteredDeductions;
public Deduction? SelectedDeduction
{
get => _selectedDeduction;
set
{
_selectedDeduction = value;
OnPropertyChanged();
}
}
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
FilterDeductions();
OnPropertyChanged();
}
}
public DeductionSearchDialogViewModel(ObservableCollection<Deduction> deductions)
{
_allDeductions = deductions;
_filteredDeductions = new ObservableCollection<Deduction>(deductions);
}
private void FilterDeductions()
{
_filteredDeductions.Clear();
if (string.IsNullOrWhiteSpace(SearchText))
{
foreach (var d in _allDeductions)
_filteredDeductions.Add(d);
return;
}
var query = SearchText.ToLower();
var matches = _allDeductions.Where(d =>
d.Customer.ToLower().Contains(query) ||
d.Comment.ToLower().Contains(query) ||
d.Date.ToString("yyyy-MM-dd").Contains(query) ||
d.Lines.Any(l => l.PartInternalNumber.ToLower().Contains(query))
).ToList();
foreach (var d in matches)
_filteredDeductions.Add(d);
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

View File

@@ -0,0 +1,178 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Lagerprogramm.Models;
using Lagerprogramm.Services;
namespace Lagerprogramm.ViewModels;
public partial class DeductionsViewModel : ObservableObject
{
private readonly JsonDataService _dataService;
private readonly AppData _appData;
public AppData AppData => _appData;
[ObservableProperty]
private ObservableCollection<Deduction> _deductions = new();
[ObservableProperty]
private ObservableCollection<TransactionLine> _lines = new();
[ObservableProperty]
private DateTime _date = DateTime.Now;
[ObservableProperty]
private string _comment = string.Empty;
[ObservableProperty]
private string _customer = string.Empty;
[ObservableProperty]
private bool _generateDeliveryNote;
public ObservableCollection<string> PartNumbers { get; } = new();
public DeductionsViewModel(JsonDataService dataService, AppData appData)
{
_dataService = dataService;
_appData = appData;
RefreshPartNumbers();
foreach (var d in appData.Deductions.OrderByDescending(d => d.Date))
Deductions.Add(d);
Lines.Add(new TransactionLine());
}
[RelayCommand]
private void AddLine() => Lines.Add(new TransactionLine());
[RelayCommand]
private void RemoveLine(TransactionLine? line)
{
if (line is null) return;
Lines.Remove(line);
}
[RelayCommand]
private void SearchPart(TransactionLine? line)
{
}
[RelayCommand]
private void SearchDeduction()
{
}
[RelayCommand]
private void Save()
{
if (Lines.Count == 0) return;
if (Lines.Any(l => string.IsNullOrWhiteSpace(l.PartInternalNumber) || l.Quantity <= 0))
return;
foreach (var line in Lines)
{
var part = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == line.PartInternalNumber);
if (part is null || part.StockQuantity < line.Quantity)
return;
}
var deduction = new Deduction
{
Date = Date,
Comment = Comment.Trim(),
Customer = Customer.Trim(),
GenerateDeliveryNote = GenerateDeliveryNote,
Lines = Lines.Select(l => new TransactionLine
{
PartInternalNumber = l.PartInternalNumber.Trim(),
Quantity = l.Quantity
}).ToList()
};
_appData.Deductions.Add(deduction);
Deductions.Insert(0, deduction);
foreach (var line in deduction.Lines)
{
var part = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == line.PartInternalNumber);
if (part is not null)
part.StockQuantity -= line.Quantity;
}
_dataService.Save(_appData);
if (GenerateDeliveryNote)
WriteDeliveryNote(deduction);
Comment = string.Empty;
Customer = string.Empty;
GenerateDeliveryNote = false;
Date = DateTime.Now;
Lines.Clear();
Lines.Add(new TransactionLine());
RefreshPartNumbers();
}
[RelayCommand]
private void DeleteDeduction(Deduction? deduction)
{
if (deduction is null) return;
foreach (var line in deduction.Lines)
{
var part = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == line.PartInternalNumber);
if (part is not null)
part.StockQuantity += line.Quantity;
}
_appData.Deductions.Remove(deduction);
Deductions.Remove(deduction);
_dataService.Save(_appData);
RefreshPartNumbers();
}
private void RefreshPartNumbers()
{
PartNumbers.Clear();
foreach (var p in _appData.Parts.OrderBy(p => p.InternalPartNumber))
PartNumbers.Add(p.InternalPartNumber);
}
private void WriteDeliveryNote(Deduction deduction)
{
var path = string.IsNullOrWhiteSpace(_appData.Settings.StoragePath)
? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
: _appData.Settings.StoragePath;
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
var fileName = Path.Combine(path, $"DeliveryNote_{deduction.Id:N}_{deduction.Date:yyyyMMdd}.txt");
var sb = new StringBuilder();
sb.AppendLine("Delivery Note");
sb.AppendLine($"Company: {_appData.Settings.CompanyName}");
sb.AppendLine($"Date: {deduction.Date:yyyy-MM-dd}");
sb.AppendLine($"Customer: {deduction.Customer}");
sb.AppendLine();
foreach (var line in deduction.Lines)
{
var part = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == line.PartInternalNumber);
sb.AppendLine($"Part: {line.PartInternalNumber} Qty: {line.Quantity}");
if (part is not null)
{
sb.AppendLine($" Description: {part.Description}");
sb.AppendLine($" MSRP: {part.Msrp:C}");
sb.AppendLine($" Line Total: {part.Msrp * line.Quantity:C}");
}
sb.AppendLine();
}
var grandTotal = deduction.Lines
.Sum(l => (_appData.Parts.FirstOrDefault(p => p.InternalPartNumber == l.PartInternalNumber)?.Msrp ?? 0) * l.Quantity);
sb.AppendLine($"Grand Total: {grandTotal:C}");
sb.AppendLine();
sb.AppendLine($"Comment: {deduction.Comment}");
File.WriteAllText(fileName, sb.ToString());
}
}

View File

@@ -0,0 +1,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Lagerprogramm.ViewModels;
public partial class DesignPreviewViewModel : ObservableObject
{
}

View File

@@ -0,0 +1,65 @@
using System;
using System.IO;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Lagerprogramm.Models;
using Lagerprogramm.Services;
namespace Lagerprogramm.ViewModels;
public partial class MainWindowViewModel : ObservableObject
{
private readonly JsonDataService _dataService;
private readonly AppData _appData;
[ObservableProperty]
private object? _currentView;
[ObservableProperty]
private string _currentViewName = string.Empty;
public MainWindowViewModel()
{
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Lagerprogramm",
"data.json");
_dataService = new JsonDataService(path);
_appData = _dataService.Load();
}
[RelayCommand]
private void ShowParts()
{
CurrentView = new PartsViewModel(_dataService, _appData);
CurrentViewName = "Parts";
}
[RelayCommand]
private void ShowAdditions()
{
CurrentView = new AdditionsViewModel(_dataService, _appData);
CurrentViewName = "Additions";
}
[RelayCommand]
private void ShowDeductions()
{
CurrentView = new DeductionsViewModel(_dataService, _appData);
CurrentViewName = "Deductions";
}
[RelayCommand]
private void ShowSettings()
{
CurrentView = new SettingsViewModel(_dataService, _appData);
CurrentViewName = "Settings";
}
[RelayCommand]
private void ShowDesignPreview()
{
CurrentView = new DesignPreviewViewModel();
CurrentViewName = "Design Preview";
}
}

View File

@@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using Lagerprogramm.Models;
namespace Lagerprogramm.ViewModels;
public class PartSearchDialogViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<Part> _allParts;
private readonly ObservableCollection<Part> _filteredParts;
private string _searchText = string.Empty;
private Part? _selectedPart;
public ObservableCollection<Part> FilteredParts => _filteredParts;
public Part? SelectedPart
{
get => _selectedPart;
set
{
_selectedPart = value;
OnPropertyChanged();
}
}
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
FilterParts();
OnPropertyChanged();
}
}
public PartSearchDialogViewModel(IEnumerable<Part> parts)
{
_allParts = new ObservableCollection<Part>(parts);
_filteredParts = new ObservableCollection<Part>(_allParts);
}
private void FilterParts()
{
_filteredParts.Clear();
if (string.IsNullOrWhiteSpace(SearchText))
{
foreach (var part in _allParts)
_filteredParts.Add(part);
return;
}
var query = SearchText.ToLower();
var matches = _allParts.Where(p =>
p.InternalPartNumber.ToLower().Contains(query) ||
p.ManufacturerPartNumber.ToLower().Contains(query) ||
p.Ean.ToLower().Contains(query) ||
p.SupplierPartNumber.ToLower().Contains(query) ||
p.Manufacturer.ToLower().Contains(query) ||
p.Supplier.ToLower().Contains(query) ||
p.Description.ToLower().Contains(query)
).ToList();
foreach (var part in matches)
_filteredParts.Add(part);
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}

View File

@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Lagerprogramm.Models;
using Lagerprogramm.Services;
namespace Lagerprogramm.ViewModels;
public partial class PartsViewModel : ObservableObject
{
private readonly JsonDataService _dataService;
private readonly AppData _appData;
[ObservableProperty]
private ObservableCollection<Part> _parts = new();
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSave))]
private Part? _selectedPart;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSave))]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private string _internalPartNumber = string.Empty;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSave))]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private string _manufacturerPartNumber = string.Empty;
[ObservableProperty]
private string _ean = string.Empty;
[ObservableProperty]
private string _supplierPartNumber = string.Empty;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSave))]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private string _manufacturer = string.Empty;
[ObservableProperty]
private string _supplier = string.Empty;
[ObservableProperty]
private string _storageLocation = string.Empty;
[ObservableProperty]
private string _storageLocationReserve = string.Empty;
[ObservableProperty]
private string _description = string.Empty;
[ObservableProperty]
private string _partComment = string.Empty;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(CanSave))]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private decimal _purchasePrice;
[ObservableProperty]
private decimal _msrp;
[ObservableProperty]
private int _stockQuantity;
public bool CanSave =>
!string.IsNullOrWhiteSpace(InternalPartNumber)
&& !string.IsNullOrWhiteSpace(ManufacturerPartNumber)
&& !string.IsNullOrWhiteSpace(Manufacturer)
&& PurchasePrice >= 0;
public PartsViewModel(JsonDataService dataService, AppData appData)
{
_dataService = dataService;
_appData = appData;
foreach (var p in appData.Parts)
Parts.Add(p);
}
partial void OnSelectedPartChanged(Part? value)
{
if (value is null)
{
ClearFields();
return;
}
InternalPartNumber = value.InternalPartNumber;
ManufacturerPartNumber = value.ManufacturerPartNumber;
Ean = value.Ean;
SupplierPartNumber = value.SupplierPartNumber;
Manufacturer = value.Manufacturer;
Supplier = value.Supplier;
StorageLocation = value.StorageLocation;
StorageLocationReserve = value.StorageLocationReserve;
Description = value.Description;
PartComment = value.Comment;
PurchasePrice = value.PurchasePrice;
Msrp = value.Msrp;
StockQuantity = value.StockQuantity;
}
[RelayCommand(CanExecute = nameof(CanSave))]
private void Save()
{
var existing = _appData.Parts.FirstOrDefault(p => p.InternalPartNumber == InternalPartNumber);
if (existing is not null)
{
existing.ManufacturerPartNumber = ManufacturerPartNumber;
existing.Ean = Ean;
existing.SupplierPartNumber = SupplierPartNumber;
existing.Manufacturer = Manufacturer;
existing.Supplier = Supplier;
existing.StorageLocation = StorageLocation;
existing.StorageLocationReserve = StorageLocationReserve;
existing.Description = Description;
existing.Comment = PartComment;
existing.PurchasePrice = PurchasePrice;
existing.Msrp = Msrp;
// StockQuantity not edited here
}
else
{
var part = new Part
{
InternalPartNumber = InternalPartNumber.Trim(),
ManufacturerPartNumber = ManufacturerPartNumber.Trim(),
Ean = Ean.Trim(),
SupplierPartNumber = SupplierPartNumber.Trim(),
Manufacturer = Manufacturer.Trim(),
Supplier = Supplier.Trim(),
StorageLocation = StorageLocation.Trim(),
StorageLocationReserve = StorageLocationReserve.Trim(),
Description = Description.Trim(),
Comment = PartComment.Trim(),
PurchasePrice = PurchasePrice,
Msrp = Msrp,
StockQuantity = 0
};
_appData.Parts.Add(part);
Parts.Add(part);
}
_dataService.Save(_appData);
SelectedPart = null;
ClearFields();
}
[RelayCommand]
private void NewPart()
{
SelectedPart = null;
ClearFields();
}
[RelayCommand]
private void DeletePart()
{
if (SelectedPart is null) return;
_appData.Parts.Remove(SelectedPart);
Parts.Remove(SelectedPart);
_dataService.Save(_appData);
SelectedPart = null;
}
[RelayCommand]
private void SearchPart()
{
}
private void ClearFields()
{
InternalPartNumber = string.Empty;
ManufacturerPartNumber = string.Empty;
Ean = string.Empty;
SupplierPartNumber = string.Empty;
Manufacturer = string.Empty;
Supplier = string.Empty;
StorageLocation = string.Empty;
StorageLocationReserve = string.Empty;
Description = string.Empty;
PartComment = string.Empty;
PurchasePrice = 0;
Msrp = 0;
StockQuantity = 0;
}
}

View File

@@ -0,0 +1,34 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Lagerprogramm.Models;
using Lagerprogramm.Services;
namespace Lagerprogramm.ViewModels;
public partial class SettingsViewModel : ObservableObject
{
private readonly JsonDataService _dataService;
private readonly AppData _appData;
[ObservableProperty]
private string _storagePath = string.Empty;
[ObservableProperty]
private string _companyName = string.Empty;
public SettingsViewModel(JsonDataService dataService, AppData appData)
{
_dataService = dataService;
_appData = appData;
StoragePath = appData.Settings.StoragePath;
CompanyName = appData.Settings.CompanyName;
}
[RelayCommand]
private void Save()
{
_appData.Settings.StoragePath = StoragePath.Trim();
_appData.Settings.CompanyName = CompanyName.Trim();
_dataService.Save(_appData);
}
}

View File

@@ -0,0 +1,5 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace Lagerprogramm.ViewModels;
public class ViewModelBase : ObservableObject { }