From 79bd52969c60b785b024e2c433709289688c680d Mon Sep 17 00:00:00 2001 From: JLdgu Date: Thu, 18 Jun 2026 08:57:34 +0100 Subject: [PATCH 1/2] Move repository interfaces into class file --- .../ApplicationSettingsRepository.cs | 5 +++++ .../IApplicationSettingsRepository.cs | 8 -------- .../Repositories/IImportHistoryRepository.cs | 7 ------- .../Repositories/ILocationsRepository.cs | 6 ------ .../Repositories/IPhonesRepository.cs | 16 ---------------- .../Repositories/IServiceRequestsRepository.cs | 5 ----- .../Repositories/ImportHistoryRepository.cs | 6 ++++++ .../Repositories/LocationsRepository.cs | 5 +++++ .../Repositories/PhonesRepository.cs | 14 ++++++++++++++ .../Repositories/ServiceRequestsRepository.cs | 8 +++++--- 10 files changed, 35 insertions(+), 45 deletions(-) delete mode 100644 PhoneAssistant.Model/Repositories/IApplicationSettingsRepository.cs delete mode 100644 PhoneAssistant.Model/Repositories/IImportHistoryRepository.cs delete mode 100644 PhoneAssistant.Model/Repositories/ILocationsRepository.cs delete mode 100644 PhoneAssistant.Model/Repositories/IPhonesRepository.cs delete mode 100644 PhoneAssistant.Model/Repositories/IServiceRequestsRepository.cs diff --git a/PhoneAssistant.Model/Repositories/ApplicationSettingsRepository.cs b/PhoneAssistant.Model/Repositories/ApplicationSettingsRepository.cs index 274acae0..66e83de1 100644 --- a/PhoneAssistant.Model/Repositories/ApplicationSettingsRepository.cs +++ b/PhoneAssistant.Model/Repositories/ApplicationSettingsRepository.cs @@ -1,5 +1,10 @@ namespace PhoneAssistant.Model; +public interface IApplicationSettingsRepository +{ + ApplicationSettings ApplicationSettings { get; init; } + void Save(); +} public sealed class ApplicationSettingsRepository : IApplicationSettingsRepository { private readonly string _appSettingsPath; diff --git a/PhoneAssistant.Model/Repositories/IApplicationSettingsRepository.cs b/PhoneAssistant.Model/Repositories/IApplicationSettingsRepository.cs deleted file mode 100644 index fe271bb0..00000000 --- a/PhoneAssistant.Model/Repositories/IApplicationSettingsRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PhoneAssistant.Model; - -public interface IApplicationSettingsRepository -{ - ApplicationSettings ApplicationSettings { get; init; } - - void Save(); -} \ No newline at end of file diff --git a/PhoneAssistant.Model/Repositories/IImportHistoryRepository.cs b/PhoneAssistant.Model/Repositories/IImportHistoryRepository.cs deleted file mode 100644 index e709ecd2..00000000 --- a/PhoneAssistant.Model/Repositories/IImportHistoryRepository.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PhoneAssistant.Model; - -public interface IImportHistoryRepository -{ - Task CreateAsync(ImportType importType, string file); - Task GetLatestImportAsync(ImportType importType); -} \ No newline at end of file diff --git a/PhoneAssistant.Model/Repositories/ILocationsRepository.cs b/PhoneAssistant.Model/Repositories/ILocationsRepository.cs deleted file mode 100644 index d56d84f3..00000000 --- a/PhoneAssistant.Model/Repositories/ILocationsRepository.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PhoneAssistant.Model; - -public interface ILocationsRepository -{ - Task> GetAllLocationsAsync(); -} \ No newline at end of file diff --git a/PhoneAssistant.Model/Repositories/IPhonesRepository.cs b/PhoneAssistant.Model/Repositories/IPhonesRepository.cs deleted file mode 100644 index ef4a93b3..00000000 --- a/PhoneAssistant.Model/Repositories/IPhonesRepository.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace PhoneAssistant.Model; - -public interface IPhonesRepository -{ - Task AssetTagUniqueAsync(string? assetTag); - Task ConcurrentChange(string imei, string lastUpdate); - Task CreateAsync(Phone phone); - Task ExistsAsync(string imei); - Task> GetActivePhonesAsync(); - Task> GetAllPhonesAsync(); - Task GetPhoneAsync(string imei); - Task UserHasProductionPhone(string user); - Task PhoneNumberExistsAsync(string phoneNumber); - Task UpdateAsync(Phone phone); - Task UpdateStatusAsync(string imei, string status); -} \ No newline at end of file diff --git a/PhoneAssistant.Model/Repositories/IServiceRequestsRepository.cs b/PhoneAssistant.Model/Repositories/IServiceRequestsRepository.cs deleted file mode 100644 index fae5c732..00000000 --- a/PhoneAssistant.Model/Repositories/IServiceRequestsRepository.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace PhoneAssistant.Model; - -public interface IServiceRequestsRepository -{ -} \ No newline at end of file diff --git a/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs b/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs index bbb902c1..c1b4c5ea 100644 --- a/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs +++ b/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs @@ -2,6 +2,12 @@ namespace PhoneAssistant.Model; +public interface IImportHistoryRepository +{ + Task CreateAsync(ImportType importType, string file); + Task GetLatestImportAsync(ImportType importType); +} + public sealed class ImportHistoryRepository(PhoneAssistantDbContext dbContext) : IImportHistoryRepository { private readonly PhoneAssistantDbContext _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); diff --git a/PhoneAssistant.Model/Repositories/LocationsRepository.cs b/PhoneAssistant.Model/Repositories/LocationsRepository.cs index 52a7803d..ca1ff5c3 100644 --- a/PhoneAssistant.Model/Repositories/LocationsRepository.cs +++ b/PhoneAssistant.Model/Repositories/LocationsRepository.cs @@ -2,6 +2,11 @@ namespace PhoneAssistant.Model; +public interface ILocationsRepository +{ + Task> GetAllLocationsAsync(); +} + public sealed class LocationsRepository : ILocationsRepository { private readonly PhoneAssistantDbContext _dbContext; diff --git a/PhoneAssistant.Model/Repositories/PhonesRepository.cs b/PhoneAssistant.Model/Repositories/PhonesRepository.cs index 3f97014b..5ea48262 100644 --- a/PhoneAssistant.Model/Repositories/PhonesRepository.cs +++ b/PhoneAssistant.Model/Repositories/PhonesRepository.cs @@ -2,6 +2,20 @@ namespace PhoneAssistant.Model; +public interface IPhonesRepository +{ + Task AssetTagUniqueAsync(string? assetTag); + Task ConcurrentChange(string imei, string lastUpdate); + Task CreateAsync(Phone phone); + Task ExistsAsync(string imei); + Task> GetActivePhonesAsync(); + Task> GetAllPhonesAsync(); + Task GetPhoneAsync(string imei); + Task UserHasProductionPhone(string user); + Task PhoneNumberExistsAsync(string phoneNumber); + Task UpdateAsync(Phone phone); + Task UpdateStatusAsync(string imei, string status); +} public sealed class PhonesRepository(PhoneAssistantDbContext dbContext) : IPhonesRepository { public async Task AssetTagUniqueAsync(string? assetTag) diff --git a/PhoneAssistant.Model/Repositories/ServiceRequestsRepository.cs b/PhoneAssistant.Model/Repositories/ServiceRequestsRepository.cs index 5d6feec9..3f41c85d 100644 --- a/PhoneAssistant.Model/Repositories/ServiceRequestsRepository.cs +++ b/PhoneAssistant.Model/Repositories/ServiceRequestsRepository.cs @@ -1,8 +1,10 @@ namespace PhoneAssistant.Model; -public sealed class ServiceRequestsRepository : IServiceRequestsRepository +public interface IServiceRequestsRepository { - private readonly PhoneAssistantDbContext _dbContext; +} - public ServiceRequestsRepository(PhoneAssistantDbContext dbContext) => _dbContext = dbContext; +public sealed class ServiceRequestsRepository(PhoneAssistantDbContext dbContext) : IServiceRequestsRepository +{ + private readonly PhoneAssistantDbContext _dbContext = dbContext; } \ No newline at end of file From a7883a6e5c1cd1636c9a54a1df801e9607b9b601 Mon Sep 17 00:00:00 2001 From: JLdgu Date: Thu, 18 Jun 2026 09:56:38 +0100 Subject: [PATCH 2/2] Use sim history to obtain latest import data --- DbUtil/SqlScripts.cs | 11 ----- PhoneAssistant.Cli/EECommand/EE.cs | 19 +++----- .../ImportHistoryRepositoryTests.cs | 46 ------------------- .../Repositories/SimRepositoryTests.cs | 37 +++++++++++++++ .../Entities/ImportHistory.cs | 14 ------ .../PhoneAssistantDbContext.cs | 10 ---- .../Repositories/ImportHistoryRepository.cs | 35 -------------- .../Repositories/SimRepository.cs | 10 ++++ .../ApplicationServicesExtension.cs | 1 - .../BaseReport/BaseReportMainViewModel.cs | 6 +-- 10 files changed, 56 insertions(+), 133 deletions(-) delete mode 100644 PhoneAssistant.Model.Tests/Repositories/ImportHistoryRepositoryTests.cs create mode 100644 PhoneAssistant.Model.Tests/Repositories/SimRepositoryTests.cs delete mode 100644 PhoneAssistant.Model/Entities/ImportHistory.cs delete mode 100644 PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs diff --git a/DbUtil/SqlScripts.cs b/DbUtil/SqlScripts.cs index 29539baa..9e30878e 100644 --- a/DbUtil/SqlScripts.cs +++ b/DbUtil/SqlScripts.cs @@ -14,7 +14,6 @@ public SqlScripts() new Script("Restructure Locations",RestructureLocations), new Script("Add 3 columns to Phones", Add3ColumnsToPhones), new Script("Create SIMs Table", CreateSIMsTable), - new Script("Replace ImportHistory Table", ReplaceImportHistoryTable) ]; } @@ -48,16 +47,6 @@ PRIMARY KEY (PhoneNumber, BillingPeriod) ); """; - private const string ReplaceImportHistoryTable = """ - DROP TABLE ImportHistory; - CREATE TABLE ImportHistory ( - Name TEXT NOT NULL, - Run TEXT NOT NULL, - ImportDate TEXT NOT NULL DEFAULT (CURRENT_TIMESTAMP), - PRIMARY KEY (Name, Run) - ) - """; - private static string RestructureLocations { get diff --git a/PhoneAssistant.Cli/EECommand/EE.cs b/PhoneAssistant.Cli/EECommand/EE.cs index a31f64cf..1ec700f8 100644 --- a/PhoneAssistant.Cli/EECommand/EE.cs +++ b/PhoneAssistant.Cli/EECommand/EE.cs @@ -1,13 +1,9 @@ -using System.CommandLine; -using System.IO.Compression; -using System.Numerics; -using System.Text; - -using FluentResults; - +using FluentResults; using PhoneAssistant.Model; - using Serilog; +using System.CommandLine; +using System.IO.Compression; +using System.Text; namespace PhoneAssistant.Cli.EECommand; @@ -90,9 +86,9 @@ private static void Execute(DirectoryInfo? directory) Log.Information("Billing period identified as: {BillingPeriod}", billingPeriod); PhoneAssistantDbContext dbContext = ModelContext.Create(); - ImportHistoryRepository importRepository = new(dbContext); - bool runExists = importRepository.RunExistsAsync(ImportType.BaseReport, billingPeriod).GetAwaiter().GetResult(); - if (runExists) + SimRepository repository = new(dbContext); + string latestBillingPeriod = repository.GetLatestBillingPeriod().GetAwaiter().GetResult(); + if (latestBillingPeriod == billingPeriod) { Log.Error("A run for this billing period already exists."); return; @@ -145,7 +141,6 @@ private static void Execute(DirectoryInfo? directory) dbContext.Sims.Add(sim); } - importRepository.CreateAsync(ImportType.BaseReport, billingPeriod).GetAwaiter().GetResult(); dbContext.SaveChanges(); Log.Information("Import completed. {LineCount} records processed.", lineCount); } diff --git a/PhoneAssistant.Model.Tests/Repositories/ImportHistoryRepositoryTests.cs b/PhoneAssistant.Model.Tests/Repositories/ImportHistoryRepositoryTests.cs deleted file mode 100644 index 227044c0..00000000 --- a/PhoneAssistant.Model.Tests/Repositories/ImportHistoryRepositoryTests.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace PhoneAssistant.Model.Tests; - -public class ImportHistoryRepositoryTests -{ - readonly DbTestHelper _helper = new(); - readonly ImportHistoryRepository _repository; - - public ImportHistoryRepositoryTests() - { - _repository = new(_helper.DbContext); - } - - [Test] - public async Task RunExistsAsync_ShouldReturnFalse_WhenRunDoesNotExist() - { - bool actual = await _repository.RunExistsAsync(ImportType.BaseReport, "DoesNotExist"); - - await Assert.That(actual).IsFalse(); - } - - [Test] - public async Task RunExistsAsync_ShouldReturnTrue_WhenRunExists() - { - _helper.DbContext.Imports.Add(new ImportHistory { Name = ImportType.BaseReport, Run = "202602", ImportDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }); - await _helper.DbContext.SaveChangesAsync(); - - bool actual = await _repository.RunExistsAsync(ImportType.BaseReport, "202602"); - - await Assert.That(actual).IsTrue(); - } - - [Test] - public async Task GetLatestImport_WhenImportExists_ShouldReturnLatest() - { - ImportHistory import1 = new() {Name = ImportType.BaseReport, Run = "202602", ImportDate = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd HH:mm:ss") }; - ImportHistory import2 = new() {Name = ImportType.BaseReport, Run = "202601", ImportDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; - - _helper.DbContext.Imports.Add(import1); - _helper.DbContext.Imports.Add(import2); - await _helper.DbContext.SaveChangesAsync(); - - ImportHistory? actual = await _repository.GetLatestImportAsync(ImportType.BaseReport); - - await Assert.That(actual).IsEqualTo(import1); - } -} diff --git a/PhoneAssistant.Model.Tests/Repositories/SimRepositoryTests.cs b/PhoneAssistant.Model.Tests/Repositories/SimRepositoryTests.cs new file mode 100644 index 00000000..cfb67724 --- /dev/null +++ b/PhoneAssistant.Model.Tests/Repositories/SimRepositoryTests.cs @@ -0,0 +1,37 @@ +namespace PhoneAssistant.Model.Tests; + +public class SimRepositoryTests +{ + readonly DbTestHelper _helper = new(); + readonly SimRepository _repository; + + public SimRepositoryTests() + { + _repository = new(_helper.DbContext); + } + + [Test] + public async Task GetLatestBillingPeriod_should_return_Latest_when_Sims_exist() + { + Sim sim1 = new() { BillingPeriod = "202601", SIMNumber = "8944122605563572205", PhoneNumber = "07814209742", UserName = "John Doe", BroadbandData = 100 , TextMessages = 50, VoiceCalls = 20 }; + Sim sim2 = new() { BillingPeriod = "202602", SIMNumber = "8944122605563572206", PhoneNumber = "07814209743", UserName = "Jane Smith", BroadbandData = 150, TextMessages = 75, VoiceCalls = 30 }; + Sim sim3 = new() { BillingPeriod = "202501", SIMNumber = "8944122605563572207", PhoneNumber = "07814209744", UserName = "Bob Johnson", BroadbandData = 200, TextMessages = 100, VoiceCalls = 40 }; + + _helper.DbContext.Sims.Add(sim1); + _helper.DbContext.Sims.Add(sim2); + await _helper.DbContext.SaveChangesAsync(); + + var actual = await _repository.GetLatestBillingPeriod(); + + await Assert.That(actual).IsEqualTo("202602"); + } + + [Test] + public async Task GetLatestBillingPeriod_should_return_Unknown_when_no_Sims_exist() + { + var actual = await _repository.GetLatestBillingPeriod(); + + await Assert.That(actual).IsEqualTo("Unknown"); + } + +} diff --git a/PhoneAssistant.Model/Entities/ImportHistory.cs b/PhoneAssistant.Model/Entities/ImportHistory.cs deleted file mode 100644 index c1aaaf95..00000000 --- a/PhoneAssistant.Model/Entities/ImportHistory.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace PhoneAssistant.Model; - -public class ImportHistory -{ - public required ImportType Name { get; set; } - public required string Run { get; set; } - public required string ImportDate { get; set; } -} - -public enum ImportType -{ - BaseReport, - Reconiliation -} \ No newline at end of file diff --git a/PhoneAssistant.Model/PhoneAssistantDbContext.cs b/PhoneAssistant.Model/PhoneAssistantDbContext.cs index d8e714a7..77ca27d5 100644 --- a/PhoneAssistant.Model/PhoneAssistantDbContext.cs +++ b/PhoneAssistant.Model/PhoneAssistantDbContext.cs @@ -11,8 +11,6 @@ public PhoneAssistantDbContext() { } public PhoneAssistantDbContext(DbContextOptions options) : base(options) { } - public DbSet Imports => Set(); - public DbSet Locations => Set(); public DbSet Phones => Set(); @@ -42,14 +40,6 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder) { - modelBuilder.Entity() - .ToTable("ImportHistory") - .HasKey(e => new { e.Name, e.Run }); - modelBuilder.Entity() - .Property(e => e.Name).HasConversion(n => n.ToString(), n => Enum.Parse(n)); - modelBuilder.Entity() - .Property(e => e.ImportDate).HasDefaultValueSql("CURRENT_TIMESTAMP"); - modelBuilder.Entity(l => { l.HasKey(e => e.Name); diff --git a/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs b/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs deleted file mode 100644 index c1b4c5ea..00000000 --- a/PhoneAssistant.Model/Repositories/ImportHistoryRepository.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace PhoneAssistant.Model; - -public interface IImportHistoryRepository -{ - Task CreateAsync(ImportType importType, string file); - Task GetLatestImportAsync(ImportType importType); -} - -public sealed class ImportHistoryRepository(PhoneAssistantDbContext dbContext) : IImportHistoryRepository -{ - private readonly PhoneAssistantDbContext _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); - - public async Task CreateAsync(ImportType importType, string run) - { - ImportHistory importHistory = new() { Name = importType, Run = run, ImportDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") }; - _dbContext.Imports.Add(importHistory); - await _dbContext.SaveChangesAsync(); - return importHistory; - } - - public async Task RunExistsAsync(ImportType importType, string run) - { - ImportHistory? importHistory = await _dbContext.Imports.FirstOrDefaultAsync(i => i.Name == importType && i.Run == run); - return importHistory is not null; - } - - public async Task GetLatestImportAsync(ImportType importType) - { - return await _dbContext.Imports - .OrderByDescending(i => i.Run) - .FirstOrDefaultAsync(i => i.Name == importType); - } -} diff --git a/PhoneAssistant.Model/Repositories/SimRepository.cs b/PhoneAssistant.Model/Repositories/SimRepository.cs index c039d69f..25c5f551 100644 --- a/PhoneAssistant.Model/Repositories/SimRepository.cs +++ b/PhoneAssistant.Model/Repositories/SimRepository.cs @@ -5,6 +5,7 @@ namespace PhoneAssistant.Model; public interface ISimRepository { Task CreateAsync(Sim sim); + Task GetLatestBillingPeriod(); Task> GetSim(string phoneNumber); Task GetSimNumberAsync(string phoneNumber); } @@ -17,6 +18,15 @@ public async Task CreateAsync(Sim sim) await dbContext.SaveChangesAsync(); } + public async Task GetLatestBillingPeriod() + { + string? latestBillingPeriod = await dbContext.Sims + .OrderByDescending(s => s.BillingPeriod) + .Select(s => s.BillingPeriod) + .FirstOrDefaultAsync(); + return latestBillingPeriod ?? "Unknown"; + } + public async Task> GetSim(string phoneNumber) { IEnumerable sims = await dbContext.Sims diff --git a/PhoneAssistant.WPF/Application/ApplicationServicesExtension.cs b/PhoneAssistant.WPF/Application/ApplicationServicesExtension.cs index b87950a5..43681be9 100644 --- a/PhoneAssistant.WPF/Application/ApplicationServicesExtension.cs +++ b/PhoneAssistant.WPF/Application/ApplicationServicesExtension.cs @@ -44,7 +44,6 @@ public static IHostBuilder ConfigureApplicationServices(this IHostBuilder host) new UpdateOptions() { AllowVersionDowngrade = true })); // Repositories - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/PhoneAssistant.WPF/Features/BaseReport/BaseReportMainViewModel.cs b/PhoneAssistant.WPF/Features/BaseReport/BaseReportMainViewModel.cs index 6adc7bde..211eee32 100644 --- a/PhoneAssistant.WPF/Features/BaseReport/BaseReportMainViewModel.cs +++ b/PhoneAssistant.WPF/Features/BaseReport/BaseReportMainViewModel.cs @@ -10,9 +10,8 @@ public interface IBaseReportMainViewModel : IViewModel { } -public partial class BaseReportMainViewModel(IImportHistoryRepository importHistory, ISimRepository repository) : ViewModelBase, IBaseReportMainViewModel +public partial class BaseReportMainViewModel(ISimRepository repository) : ViewModelBase, IBaseReportMainViewModel { - private readonly IImportHistoryRepository _import = importHistory ?? throw new ArgumentNullException(nameof(importHistory)); private readonly ISimRepository _repository = repository ?? throw new ArgumentNullException(nameof(repository)); public ObservableCollection BaseReportSims { get; } = []; @@ -45,8 +44,7 @@ private async Task EnterKey() public override async Task LoadAsync() { - ImportHistory? importHistory = await _import.GetLatestImportAsync(ImportType.BaseReport); - LatestImport = importHistory is null ? $"Latest Import: None" : $"Latest Import: {importHistory.Run} ({importHistory.ImportDate})"; + LatestImport = $"Latest Import: {await _repository.GetLatestBillingPeriod()}"; } }