diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs index 26ef9c0d..bd2adaaa 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs @@ -3,6 +3,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using Database; using Models; using Moq; using RequestHandlers; @@ -17,8 +18,9 @@ public class TransactionRequestHandlerTests public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_IsHandled() { Mock transactionService = new Mock(); + Mock databaseContext = new Mock(); transactionService.Setup(t => t.PerformLogon(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.PerformLogonResponseModel); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionService.Object, databaseContext.Object); LogonTransactionRequest request = LogonTransactionRequest.Create(TestData.TransactionDateTime, TestData.TransactionNumber, @@ -34,8 +36,9 @@ public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_IsHan public async Task TransactionRequestHandler_PerformMobileTopupRequest_Handle_IsHandled() { Mock transactionService = new Mock(); + Mock databaseContext = new Mock(); transactionService.Setup(t => t.PerformMobileTopup(It.IsAny(), It.IsAny())).ReturnsAsync(true); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionService.Object,databaseContext.Object); PerformMobileTopupRequest request = PerformMobileTopupRequest.Create(TestData.TransactionDateTime, TestData.TransactionNumber, @@ -57,8 +60,9 @@ public async Task TransactionRequestHandler_PerformMobileTopupRequest_Handle_IsH public async Task TransactionRequestHandler_PerformVoucherIssueRequest_Handle_IsHandled() { Mock transactionService = new Mock(); + Mock databaseContext = new Mock(); transactionService.Setup(t => t.PerformVoucherIssue(It.IsAny(), It.IsAny())).ReturnsAsync(true); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionService.Object,databaseContext.Object); PerformVoucherIssueRequest request = PerformVoucherIssueRequest.Create(TestData.TransactionDateTime, TestData.TransactionNumber, diff --git a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index 904e99f6..1efeb345 100644 --- a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -1,5 +1,6 @@ namespace TransactionMobile.Maui.BusinessLogic.RequestHandlers; +using Database; using MediatR; using Models; using Requests; @@ -13,13 +14,16 @@ public class TransactionRequestHandler : IRequestHandler Handle(PerformMobileTopupRequest request, CancellationToken cancellationToken) { + (TransactionRecord transactionRecord, Int64 transactionNumber) transaction = await this.CreateTransactionRecord(request, cancellationToken); + // TODO: Factory PerformMobileTopupRequestModel model = new PerformMobileTopupRequestModel { @@ -46,23 +52,108 @@ public async Task Handle(PerformMobileTopupRequest request, Boolean result = await this.TransactionService.PerformMobileTopup(model, cancellationToken); + await this.UpdateTransactionRecord(transaction.transactionRecord, result, cancellationToken); + return result; } + private async Task<(TransactionRecord transactionRecord, Int64 transactionNumber)> CreateTransactionRecord(LogonTransactionRequest request, + CancellationToken cancellationToken) + { + TransactionRecord transactionRecord = new TransactionRecord + { + ApplicationVersion = request.ApplicationVersion, + DeviceIdentifier = request.DeviceIdentifier, + TransactionDateTime = request.TransactionDateTime, + TransactionType = 1 + }; + Int64 transactionNumber = await this.DatabaseContext.CreateTransaction(transactionRecord); + + return (transactionRecord, transactionNumber); + } + + private async Task<(TransactionRecord transactionRecord, Int64 transactionNumber)> CreateTransactionRecord(PerformMobileTopupRequest request, + CancellationToken cancellationToken) + { + TransactionRecord transactionRecord = new TransactionRecord + { + ApplicationVersion = request.ApplicationVersion, + DeviceIdentifier = request.DeviceIdentifier, + TransactionDateTime = request.TransactionDateTime, + TransactionType = 2, + Amount = request.TopupAmount, + ProductId = request.ProductId, + ContractId = request.ContractId, + CustomerAccountNumber = request.CustomerAccountNumber, + CustomerEmailAddress = request.CustomerEmailAddress, + OperatorIdentifier = request.OperatorIdentifier + }; + Int64 transactionNumber = await this.DatabaseContext.CreateTransaction(transactionRecord); + + return (transactionRecord, transactionNumber); + } + + private async Task<(TransactionRecord transactionRecord, Int64 transactionNumber)> CreateTransactionRecord(PerformVoucherIssueRequest request, + CancellationToken cancellationToken) + { + TransactionRecord transactionRecord = new TransactionRecord + { + ApplicationVersion = request.ApplicationVersion, + DeviceIdentifier = request.DeviceIdentifier, + TransactionDateTime = request.TransactionDateTime, + TransactionType = 2, + Amount = request.VoucherAmount, + ProductId = request.ProductId, + ContractId = request.ContractId, + RecipientEmailAddress = request.RecipientEmailAddress, + RecipientMobileNumber = request.RecipientMobileNumber, + CustomerEmailAddress = request.CustomerEmailAddress, + OperatorIdentifier = request.OperatorIdentifier + }; + Int64 transactionNumber = await this.DatabaseContext.CreateTransaction(transactionRecord); + + return (transactionRecord, transactionNumber); + } + + private async Task UpdateTransactionRecord(TransactionRecord transactionRecord, + PerformLogonResponseModel result, + CancellationToken cancellationToken) + { + transactionRecord.IsSuccessful = result.IsSuccessful; + transactionRecord.ResponseMessage = result.ResponseMessage; + transactionRecord.EstateId = result.EstateId; + transactionRecord.MerchantId = result.MerchantId; + + await this.DatabaseContext.UpdateTransaction(transactionRecord); + } + + private async Task UpdateTransactionRecord(TransactionRecord transactionRecord, + Boolean result, + CancellationToken cancellationToken) + { + transactionRecord.IsSuccessful = result; + + await this.DatabaseContext.UpdateTransaction(transactionRecord); + } + public async Task Handle(LogonTransactionRequest request, CancellationToken cancellationToken) { + (TransactionRecord transactionRecord, Int64 transactionNumber) transaction = await this.CreateTransactionRecord(request, cancellationToken); + // TODO: Factory PerformLogonRequestModel model = new PerformLogonRequestModel { ApplicationVersion = request.ApplicationVersion, DeviceIdentifier = request.DeviceIdentifier, TransactionDateTime = request.TransactionDateTime, - TransactionNumber = request.TransactionNumber - }; - + TransactionNumber = transaction.transactionNumber.ToString() + }; + PerformLogonResponseModel result = await this.TransactionService.PerformLogon(model, cancellationToken); + await this.UpdateTransactionRecord(transaction.transactionRecord, result, cancellationToken); + return result; } @@ -71,6 +162,7 @@ public async Task Handle(LogonTransactionRequest requ public async Task Handle(PerformVoucherIssueRequest request, CancellationToken cancellationToken) { + (TransactionRecord transactionRecord, Int64 transactionNumber) transaction = await this.CreateTransactionRecord(request, cancellationToken); // TODO: Factory PerformVoucherIssueRequestModel model = new PerformVoucherIssueRequestModel { @@ -84,11 +176,13 @@ public async Task Handle(PerformVoucherIssueRequest request, ProductId = request.ProductId, VoucherAmount = request.VoucherAmount, TransactionDateTime = request.TransactionDateTime, - TransactionNumber = request.TransactionNumber - }; + TransactionNumber = transaction.transactionNumber.ToString() + }; Boolean result = await this.TransactionService.PerformVoucherIssue(model, cancellationToken); + await this.UpdateTransactionRecord(transaction.transactionRecord, result, cancellationToken); + return result; } } \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic/TransactionMobile.Maui.BusinessLogic.csproj b/TransactionMobile.Maui.BusinessLogic/TransactionMobile.Maui.BusinessLogic.csproj index cfdcafbb..ed90a3a4 100644 --- a/TransactionMobile.Maui.BusinessLogic/TransactionMobile.Maui.BusinessLogic.csproj +++ b/TransactionMobile.Maui.BusinessLogic/TransactionMobile.Maui.BusinessLogic.csproj @@ -19,4 +19,8 @@ + + + + diff --git a/TransactionMobile.Maui.BusinessLogic/ViewModels/Support/SupportPageViewModel.cs b/TransactionMobile.Maui.BusinessLogic/ViewModels/Support/SupportPageViewModel.cs index 82eedc17..429475f3 100644 --- a/TransactionMobile.Maui.BusinessLogic/ViewModels/Support/SupportPageViewModel.cs +++ b/TransactionMobile.Maui.BusinessLogic/ViewModels/Support/SupportPageViewModel.cs @@ -6,6 +6,7 @@ namespace TransactionMobile.Maui.BusinessLogic.ViewModels.Support { + using Database; using MvvmHelpers; using UIServices; @@ -15,12 +16,17 @@ public class SupportPageViewModel : BaseViewModel private readonly IApplicationInfoService ApplicationInfoService; - public SupportPageViewModel(IDeviceService deviceService,IApplicationInfoService applicationInfoService) + private readonly IDatabaseContext DatabaseContext; + + public SupportPageViewModel(IDeviceService deviceService,IApplicationInfoService applicationInfoService,IDatabaseContext databaseContext) { this.DeviceService = deviceService; this.ApplicationInfoService = applicationInfoService; + this.DatabaseContext = databaseContext; } + public String NumberTransactionsStored => $"Transactions Stored: {this.DatabaseContext.GetTransactions().Result.Count()}"; + public String ApplicationName => $"{this.ApplicationInfoService.ApplicationName} v{this.ApplicationInfoService.VersionString}"; //public string AppVersion => $"Version: {this.ApplicationInfoService.VersionString}{Environment.NewLine}Copyright © 2022 Stuart Ferguson"; diff --git a/TransactionMobile.Maui.Database/IDatabaseContext.cs b/TransactionMobile.Maui.Database/IDatabaseContext.cs new file mode 100644 index 00000000..f0c7aec2 --- /dev/null +++ b/TransactionMobile.Maui.Database/IDatabaseContext.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TransactionMobile.Maui.Database +{ + using SQLite; + + public interface IDatabaseContext + { + Task InitialiseDatabase(); + + Task CreateTransaction(TransactionRecord transactionRecord); + + Task UpdateTransaction(TransactionRecord transactionRecord); + + Task> GetTransactions(); + } + + public class DatabaseContext : IDatabaseContext + { + private readonly SQLiteConnection Connection; + + public DatabaseContext(String connectionString) + { + this.Connection = new SQLiteConnection(connectionString); + } + + public async Task InitialiseDatabase() + { + this.Connection.CreateTable(); + } + + public async Task CreateTransaction(TransactionRecord transactionRecord) + { + this.Connection.Insert(transactionRecord); + + return SQLite3.LastInsertRowid(this.Connection.Handle); + } + + public async Task UpdateTransaction(TransactionRecord transactionRecord) + { + this.Connection.Update(transactionRecord); + } + + public async Task> GetTransactions() + { + return this.Connection.Table().ToList(); + } + } + + public class TransactionRecord + { + public String ApplicationVersion { get; set; } + + public Guid ContractId { get; set; } + + public String CustomerAccountNumber { get; set; } + + public String CustomerEmailAddress { get; set; } + + public String DeviceIdentifier { get; set; } + + public String OperatorIdentifier { get; set; } + + public Guid ProductId { get; set; } + + public Decimal Amount { get; set; } + + public DateTime TransactionDateTime { get; set; } + + [PrimaryKey, AutoIncrement] + public Int32 TransactionNumber { get; set; } + + public String RecipientMobileNumber { get; set; } + public String RecipientEmailAddress { get; set; } + + public Int32 TransactionType { get; set; } + + public Guid EstateId { get; set; } + public Guid MerchantId { get; set; } + public Boolean IsSuccessful { get; set; } + + public String ResponseMessage { get; set; } + + } +} diff --git a/TransactionMobile.Maui.Database/TransactionMobile.Maui.Database.csproj b/TransactionMobile.Maui.Database/TransactionMobile.Maui.Database.csproj new file mode 100644 index 00000000..1003f9ad --- /dev/null +++ b/TransactionMobile.Maui.Database/TransactionMobile.Maui.Database.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/TransactionMobile.Maui.sln b/TransactionMobile.Maui.sln index 4f367132..d4c164e4 100644 --- a/TransactionMobile.Maui.sln +++ b/TransactionMobile.Maui.sln @@ -9,9 +9,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1CBEF4C1-7D9 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB312EE3-CBA4-469A-8694-67C5466298C5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionMobile.Maui.BusinessLogic.Tests", "TransactionMobile.Maui.BusinessLogic.Tests\TransactionMobile.Maui.BusinessLogic.Tests.csproj", "{0894F054-5C4D-4DDD-A8E9-636416189234}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionMobile.Maui.BusinessLogic.Tests", "TransactionMobile.Maui.BusinessLogic.Tests\TransactionMobile.Maui.BusinessLogic.Tests.csproj", "{0894F054-5C4D-4DDD-A8E9-636416189234}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionMobile.Maui.BusinessLogic", "TransactionMobile.Maui.BusinessLogic\TransactionMobile.Maui.BusinessLogic.csproj", "{902D54CF-CD5F-4932-B1DC-01A3937AC054}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TransactionMobile.Maui.BusinessLogic", "TransactionMobile.Maui.BusinessLogic\TransactionMobile.Maui.BusinessLogic.csproj", "{902D54CF-CD5F-4932-B1DC-01A3937AC054}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TransactionMobile.Maui.Database", "TransactionMobile.Maui.Database\TransactionMobile.Maui.Database.csproj", "{692DD081-BA36-4289-9A81-96C9F604E864}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +35,10 @@ Global {902D54CF-CD5F-4932-B1DC-01A3937AC054}.Debug|Any CPU.Build.0 = Debug|Any CPU {902D54CF-CD5F-4932-B1DC-01A3937AC054}.Release|Any CPU.ActiveCfg = Release|Any CPU {902D54CF-CD5F-4932-B1DC-01A3937AC054}.Release|Any CPU.Build.0 = Release|Any CPU + {692DD081-BA36-4289-9A81-96C9F604E864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {692DD081-BA36-4289-9A81-96C9F604E864}.Debug|Any CPU.Build.0 = Debug|Any CPU + {692DD081-BA36-4289-9A81-96C9F604E864}.Release|Any CPU.ActiveCfg = Release|Any CPU + {692DD081-BA36-4289-9A81-96C9F604E864}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -41,6 +47,7 @@ Global {73668181-7A26-435D-83E3-CF141AC8FD0B} = {1CBEF4C1-7D90-4A78-AA55-D81F1447A70E} {0894F054-5C4D-4DDD-A8E9-636416189234} = {AB312EE3-CBA4-469A-8694-67C5466298C5} {902D54CF-CD5F-4932-B1DC-01A3937AC054} = {1CBEF4C1-7D90-4A78-AA55-D81F1447A70E} + {692DD081-BA36-4289-9A81-96C9F604E864} = {1CBEF4C1-7D90-4A78-AA55-D81F1447A70E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} diff --git a/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs b/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs index 88ff41a1..7c5163fd 100644 --- a/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs +++ b/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs @@ -1,5 +1,6 @@ namespace TransactionMobile.Maui.Extensions { + using BusinessLogic.Models; using BusinessLogic.RequestHandlers; using BusinessLogic.Requests; @@ -9,6 +10,7 @@ using BusinessLogic.ViewModels; using BusinessLogic.ViewModels.Support; using BusinessLogic.ViewModels.Transactions; + using Database; using MediatR; using UIServices; @@ -16,6 +18,16 @@ public static class MauiAppBuilderExtensions { #region Methods + public static MauiAppBuilder ConfigureDatabase(this MauiAppBuilder builder) + { + String connectionString = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "transactionpos.db"); + IDatabaseContext database = new DatabaseContext(connectionString); + database.InitialiseDatabase(); + builder.Services.AddSingleton(database); + + return builder; + } + public static MauiAppBuilder ConfigureAppServices(this MauiAppBuilder builder) { builder.Services.AddSingleton(); diff --git a/TransactionMobile.Maui/MauiProgram.cs b/TransactionMobile.Maui/MauiProgram.cs index fe0ced7c..2631cfb8 100644 --- a/TransactionMobile.Maui/MauiProgram.cs +++ b/TransactionMobile.Maui/MauiProgram.cs @@ -4,6 +4,7 @@ namespace TransactionMobile.Maui; using BusinessLogic.UIServices; using CommunityToolkit.Maui; +//using SQLitePCL; using UIServices; public static class MauiProgram @@ -11,9 +12,10 @@ public static class MauiProgram public static MauiApp Container; public static MauiApp CreateMauiApp() { + //raw.SetProvider(new SQLite3Provider_sqlite3()); var builder = MauiApp.CreateBuilder(); - builder.UseMauiApp().ConfigureRequestHandlers().ConfigureViewModels().ConfigureAppServices().ConfigureUIServices().UseMauiCommunityToolkit() - .ConfigureFonts(fonts => + builder.UseMauiApp().ConfigureRequestHandlers().ConfigureViewModels().ConfigureAppServices().ConfigureUIServices().UseMauiCommunityToolkit().ConfigureDatabase() + .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); }) @@ -21,6 +23,7 @@ public static MauiApp CreateMauiApp() .AddMemoryCache(); Container = builder.Build(); + return Container; } } diff --git a/TransactionMobile.Maui/Pages/Support/SupportPage.xaml b/TransactionMobile.Maui/Pages/Support/SupportPage.xaml index a56d4532..fdf3f2ea 100644 --- a/TransactionMobile.Maui/Pages/Support/SupportPage.xaml +++ b/TransactionMobile.Maui/Pages/Support/SupportPage.xaml @@ -22,6 +22,9 @@