From dea29d6eecb58d588fa5640ea32bbbe2c3fe71c7 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 8 Dec 2022 11:30:42 +0000 Subject: [PATCH 1/2] Handle merchant withdrawal events at the balance handling --- .../TransactionProcessor.BusinessLogic.csproj | 10 +- .../TransactionProcessor.Client.csproj | 2 +- ...ansactionProcessor.IntegrationTests.csproj | 10 +- .../MerchantBalanceProjectionTests.cs | 28 +++ .../TestData.cs | 11 + .../MerchantBalanceProjectionState.cs | 3 + .../MerchantBalanceStateDispatcher.cs | 95 +++++---- .../Projections/MerchantBalanceProjection.cs | 1 + .../MerchantBalanceStateRepository.cs | 200 +++++++++--------- .../State/MerchantBalanceState.cs | 6 + .../State/MerchantBalanceStateExtensions.cs | 15 ++ ...ansactionProcessor.ProjectionEngine.csproj | 12 +- ...ocessor.Reconciliation.DomainEvents.csproj | 2 +- ...onProcessor.ReconciliationAggregate.csproj | 2 +- ...onProcessor.Settlement.DomainEvents.csproj | 2 +- ...ctionProcessor.SettlementAggregates.csproj | 2 +- ...nProcessor.Transaction.DomainEvents.csproj | 2 +- ...ctionProcessor.TransactionAggregate.csproj | 2 +- ...ctionProcessor.Voucher.DomainEvents.csproj | 2 +- ...ansactionProcessor.VoucherAggregate.csproj | 2 +- .../TransactionProcessor.csproj | 4 +- TransactionProcessor/appsettings.json | 4 + 22 files changed, 251 insertions(+), 166 deletions(-) diff --git a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj index 26fccc3e..6b828084 100644 --- a/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj +++ b/TransactionProcessor.BusinessLogic/TransactionProcessor.BusinessLogic.csproj @@ -5,13 +5,13 @@ - + - - - - + + + + diff --git a/TransactionProcessor.Client/TransactionProcessor.Client.csproj b/TransactionProcessor.Client/TransactionProcessor.Client.csproj index 32ed2999..e2a4e21c 100644 --- a/TransactionProcessor.Client/TransactionProcessor.Client.csproj +++ b/TransactionProcessor.Client/TransactionProcessor.Client.csproj @@ -6,7 +6,7 @@ - + diff --git a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj index 5d3a697e..b7ac4d0e 100644 --- a/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj +++ b/TransactionProcessor.IntegrationTests/TransactionProcessor.IntegrationTests.csproj @@ -7,16 +7,16 @@ - + - + - + - - + + diff --git a/TransactionProcessor.ProjectionEngine.Tests/MerchantBalanceProjectionTests.cs b/TransactionProcessor.ProjectionEngine.Tests/MerchantBalanceProjectionTests.cs index 76926dcd..4e293d3f 100644 --- a/TransactionProcessor.ProjectionEngine.Tests/MerchantBalanceProjectionTests.cs +++ b/TransactionProcessor.ProjectionEngine.Tests/MerchantBalanceProjectionTests.cs @@ -58,6 +58,34 @@ public async Task MerchantBalanceProjection_Handle_ManualDepositMadeEvent_EventI newState.LastDeposit.ShouldBe(TestData.ManualDepositMadeEvent.DepositDateTime); } + [Fact] + public async Task MerchantBalanceProjection_Handle_WithdrawalMadeEvent_EventIsHandled() + { + MerchantBalanceProjection projection = new MerchantBalanceProjection(); + MerchantBalanceState state = new MerchantBalanceState(); + state = state with + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + MerchantName = TestData.MerchantName, + AvailableBalance = 100.00m, + Balance = 100.00m, + WithdrawalCount = 0, + TotalWithdrawn = 0, + LastWithdrawal = DateTime.MinValue + }; + + WithdrawalMadeEvent @event = TestData.WithdrawalMadeEvent; + + MerchantBalanceState newState = await projection.Handle(state, @event, CancellationToken.None); + + newState.AvailableBalance.ShouldBe(state.AvailableBalance - TestData.WithdrawalMadeEvent.Amount); + newState.Balance.ShouldBe(state.Balance - TestData.WithdrawalMadeEvent.Amount); + newState.WithdrawalCount.ShouldBe(1); + newState.TotalWithdrawn.ShouldBe(TestData.WithdrawalMadeEvent.Amount); + newState.LastWithdrawal.ShouldBe(TestData.WithdrawalMadeEvent.WithdrawalDateTime); + } + [Fact] public async Task MerchantBalanceProjection_Handle_ManualDepositMadeEvent_SecondDepositAfterFirst_EventIsHandled() { diff --git a/TransactionProcessor.ProjectionEngine.Tests/TestData.cs b/TransactionProcessor.ProjectionEngine.Tests/TestData.cs index daf8e5c8..f4a9a201 100644 --- a/TransactionProcessor.ProjectionEngine.Tests/TestData.cs +++ b/TransactionProcessor.ProjectionEngine.Tests/TestData.cs @@ -22,12 +22,16 @@ public class TestData public static DateTime AutomaticDepositDateTime = new DateTime(2022, 10, 13, 3, 2, 3); + public static DateTime WithdrawalDateTime = new DateTime(2022, 10, 13, 3, 2, 3); + public static Guid AutomaticDepositId = Guid.Parse("520521a1f9504ec1bf1cc5a7fd4fd905"); public static String AutomaticDepositReference = "Automatic Deposit 1"; public static Decimal AutomaticDepositAmount = 200.00m; + public static Decimal WithdrawalAmount = 100.00m; + public static Guid TransactionId = Guid.Parse("58306666-746C-4984-B264-4ECF15749BF5"); public static DateTime TransactionDateTime = new DateTime(2022, 10, 13, 7, 30, 0); @@ -57,6 +61,8 @@ public class TestData public static String ResponseCode = "ResponseCode"; public static String ResponseMessage = "ResponseMessage"; + public static Guid ManualWithdrawalId = Guid.Parse("4DCDA910-53E4-40F8-AF4B-FEEAC2338739"); + public static MerchantFeeAddedToTransactionEvent GetMerchantFeeAddedToTransactionEvent(Decimal calculatedFeeValue) => new MerchantFeeAddedToTransactionEvent(TestData.TransactionId, TestData.EstateId, @@ -104,5 +110,10 @@ public static TransactionHasBeenCompletedEvent GetTransactionHasBeenCompletedEve new AutomaticDepositMadeEvent(TestData.MerchantId, TestData.EstateId, TestData.AutomaticDepositId, TestData.AutomaticDepositReference, TestData.AutomaticDepositDateTime, TestData.AutomaticDepositAmount); + + public static WithdrawalMadeEvent WithdrawalMadeEvent => + new WithdrawalMadeEvent(TestData.MerchantId, TestData.EstateId, TestData.ManualWithdrawalId, + TestData.WithdrawalDateTime, + TestData.WithdrawalAmount); } } \ No newline at end of file diff --git a/TransactionProcessor.ProjectionEngine/Database/Entities/MerchantBalanceProjectionState.cs b/TransactionProcessor.ProjectionEngine/Database/Entities/MerchantBalanceProjectionState.cs index a9120afc..67f62526 100644 --- a/TransactionProcessor.ProjectionEngine/Database/Entities/MerchantBalanceProjectionState.cs +++ b/TransactionProcessor.ProjectionEngine/Database/Entities/MerchantBalanceProjectionState.cs @@ -12,7 +12,9 @@ public class MerchantBalanceProjectionState public Decimal AvailableBalance { get; set; } public Decimal Balance { get; init; } public Int32 DepositCount { get; set; } + public Int32 WithdrawalCount { get; set; } public Decimal TotalDeposited { get; set; } + public Decimal TotalWithdrawn { get; set; } public Int32 SaleCount { get; set; } public Decimal AuthorisedSales { get; set; } @@ -22,6 +24,7 @@ public class MerchantBalanceProjectionState public Decimal ValueOfFees { get; set; } public DateTime LastDeposit { get; set; } + public DateTime LastWithdrawal { get; set; } public DateTime LastSale { get; set; } public DateTime LastFee { get; set; } diff --git a/TransactionProcessor.ProjectionEngine/Dispatchers/MerchantBalanceStateDispatcher.cs b/TransactionProcessor.ProjectionEngine/Dispatchers/MerchantBalanceStateDispatcher.cs index 9a560eba..86ba0882 100644 --- a/TransactionProcessor.ProjectionEngine/Dispatchers/MerchantBalanceStateDispatcher.cs +++ b/TransactionProcessor.ProjectionEngine/Dispatchers/MerchantBalanceStateDispatcher.cs @@ -22,6 +22,7 @@ public async Task Dispatch(MerchantBalanceState state, MerchantCreatedEvent e => this.CreateOpeningBalanceEntry(e), ManualDepositMadeEvent e => this.CreateManualDepositBalanceEntry(state, e), AutomaticDepositMadeEvent e => this.CreateAutomaticDepositBalanceEntry(state, e), + WithdrawalMadeEvent e => this.CreateWithdrawalBalanceEntry(state, e), TransactionHasBeenCompletedEvent e => this.CreateTransactionBalanceEntry(state, e), MerchantFeeAddedToTransactionEvent e => this.CreateTransactionFeeBalanceEntry(state, e), _ => null @@ -33,20 +34,31 @@ public async Task Dispatch(MerchantBalanceState state, await this.TransactionProcessorReadRepository.AddMerchantBalanceChangedEntry(entry, cancellationToken); } - private MerchantBalanceChangedEntry CreateTransactionFeeBalanceEntry(MerchantBalanceState state, MerchantFeeAddedToTransactionEvent @event) - { - return new MerchantBalanceChangedEntry - { - MerchantId = @event.MerchantId, - EstateId = @event.EstateId, - ChangeAmount = @event.CalculatedValue, - DateTime = @event.FeeCalculatedDateTime.AddSeconds(2), - Reference = "Transaction Fee Processed", - AggregateId = @event.TransactionId, - OriginalEventId = @event.EventId, - DebitOrCredit = "C" - }; - } + private MerchantBalanceChangedEntry CreateTransactionFeeBalanceEntry(MerchantBalanceState state, + MerchantFeeAddedToTransactionEvent @event) => + new MerchantBalanceChangedEntry { + MerchantId = @event.MerchantId, + EstateId = @event.EstateId, + ChangeAmount = @event.CalculatedValue, + DateTime = @event.FeeCalculatedDateTime.AddSeconds(2), + Reference = "Transaction Fee Processed", + AggregateId = @event.TransactionId, + OriginalEventId = @event.EventId, + DebitOrCredit = "C" + }; + + private MerchantBalanceChangedEntry CreateWithdrawalBalanceEntry(MerchantBalanceState state, + WithdrawalMadeEvent @event) => + new MerchantBalanceChangedEntry { + MerchantId = @event.MerchantId, + EstateId = @event.EstateId, + ChangeAmount = @event.Amount, + DateTime = @event.WithdrawalDateTime, + Reference = "Merchant Withdrawal", + AggregateId = @event.MerchantId, + OriginalEventId = @event.EventId, + DebitOrCredit = "D" + }; private MerchantBalanceChangedEntry CreateTransactionBalanceEntry(MerchantBalanceState state, TransactionHasBeenCompletedEvent @event) { if (@event.IsAuthorised == false) @@ -74,36 +86,34 @@ private MerchantBalanceChangedEntry CreateTransactionBalanceEntry(MerchantBalanc }; } - private MerchantBalanceChangedEntry CreateManualDepositBalanceEntry(MerchantBalanceState state, ManualDepositMadeEvent @event) { - return new MerchantBalanceChangedEntry { - MerchantId = @event.MerchantId, - EstateId = @event.EstateId, - ChangeAmount = @event.Amount, - DateTime = @event.DepositDateTime, - Reference = "Merchant Deposit", - AggregateId = @event.MerchantId, - OriginalEventId = @event.EventId, - DebitOrCredit = "C" - }; - } + private MerchantBalanceChangedEntry CreateManualDepositBalanceEntry(MerchantBalanceState state, + ManualDepositMadeEvent @event) => + new MerchantBalanceChangedEntry { + MerchantId = @event.MerchantId, + EstateId = @event.EstateId, + ChangeAmount = @event.Amount, + DateTime = @event.DepositDateTime, + Reference = "Merchant Deposit", + AggregateId = @event.MerchantId, + OriginalEventId = @event.EventId, + DebitOrCredit = "C" + }; - private MerchantBalanceChangedEntry CreateAutomaticDepositBalanceEntry(MerchantBalanceState state, AutomaticDepositMadeEvent @event) - { - return new MerchantBalanceChangedEntry - { - MerchantId = @event.MerchantId, - EstateId = @event.EstateId, - ChangeAmount = @event.Amount, - DateTime = @event.DepositDateTime, - Reference = "Merchant Deposit", - AggregateId = @event.MerchantId, - OriginalEventId = @event.EventId, - DebitOrCredit = "C" - }; - } + private MerchantBalanceChangedEntry CreateAutomaticDepositBalanceEntry(MerchantBalanceState state, + AutomaticDepositMadeEvent @event) => + new MerchantBalanceChangedEntry { + MerchantId = @event.MerchantId, + EstateId = @event.EstateId, + ChangeAmount = @event.Amount, + DateTime = @event.DepositDateTime, + Reference = "Merchant Deposit", + AggregateId = @event.MerchantId, + OriginalEventId = @event.EventId, + DebitOrCredit = "C" + }; - private MerchantBalanceChangedEntry CreateOpeningBalanceEntry(MerchantCreatedEvent @event) { - return new MerchantBalanceChangedEntry { + private MerchantBalanceChangedEntry CreateOpeningBalanceEntry(MerchantCreatedEvent @event) => + new MerchantBalanceChangedEntry { MerchantId = @event.MerchantId, EstateId = @event.EstateId, CauseOfChangeId = @event.MerchantId, @@ -114,5 +124,4 @@ private MerchantBalanceChangedEntry CreateOpeningBalanceEntry(MerchantCreatedEve OriginalEventId = @event.EventId, DebitOrCredit = "C" }; - } } \ No newline at end of file diff --git a/TransactionProcessor.ProjectionEngine/Projections/MerchantBalanceProjection.cs b/TransactionProcessor.ProjectionEngine/Projections/MerchantBalanceProjection.cs index 235d7b0e..88c7489d 100644 --- a/TransactionProcessor.ProjectionEngine/Projections/MerchantBalanceProjection.cs +++ b/TransactionProcessor.ProjectionEngine/Projections/MerchantBalanceProjection.cs @@ -14,6 +14,7 @@ public async Task Handle(MerchantBalanceState state, MerchantBalanceState newState = domainEvent switch { MerchantCreatedEvent mce => state.HandleMerchantCreated(mce), ManualDepositMadeEvent mdme => state.HandleManualDepositMadeEvent(mdme), + WithdrawalMadeEvent wme => state.HandleWithdrawalMadeEvent(wme), AutomaticDepositMadeEvent adme => state.HandleAutomaticDepositMadeEvent(adme), TransactionHasStartedEvent thse => state.HandleTransactionHasStartedEvent(thse), TransactionHasBeenCompletedEvent thbce => state.HandleTransactionHasBeenCompletedEvent(thbce), diff --git a/TransactionProcessor.ProjectionEngine/Repository/MerchantBalanceStateRepository.cs b/TransactionProcessor.ProjectionEngine/Repository/MerchantBalanceStateRepository.cs index f8a2cb17..41d445d4 100644 --- a/TransactionProcessor.ProjectionEngine/Repository/MerchantBalanceStateRepository.cs +++ b/TransactionProcessor.ProjectionEngine/Repository/MerchantBalanceStateRepository.cs @@ -9,62 +9,33 @@ public class MerchantBalanceStateRepository : IProjectionStateRepository { + #region Fields + private readonly Shared.EntityFramework.IDbContextFactory ContextFactory; - private const String ConnectionStringIdentifier = "TransactionProcessorReadModel"; - public MerchantBalanceStateRepository(Shared.EntityFramework.IDbContextFactory contextFactory) - { - this.ContextFactory = contextFactory; - } - public static Event Create(String type, IDomainEvent domainEvent) - { - return new() - { - EventId = domainEvent.EventId, - Date = domainEvent.EventTimestamp.Date.Date, - Type = type - }; - } + #endregion - private async Task LoadHelper(Guid estateId, - Guid merchantId, - CancellationToken cancellationToken) - { - await using TransactionProcessorGenericContext context = await this.ContextFactory.GetContext(estateId, ConnectionStringIdentifier, cancellationToken); + #region Constructors - MerchantBalanceProjectionState? entity = - await EntityFrameworkQueryableExtensions.SingleOrDefaultAsync(context.MerchantBalanceProjectionState.Where(m => m.MerchantId == merchantId)); + public MerchantBalanceStateRepository(Shared.EntityFramework.IDbContextFactory contextFactory) { + this.ContextFactory = contextFactory; + } - if (entity == null) { - return new MerchantBalanceState(); - } + #endregion - // We have located a state record so we need to translate to the Model type - return new MerchantBalanceState() - { - Version = entity.Timestamp, - Balance = entity.Balance, - MerchantId = merchantId, - AvailableBalance = entity.AvailableBalance, - MerchantName = entity.MerchantName, - EstateId = entity.EstateId, - DeclinedSales = entity.DeclinedSales, - ValueOfFees = entity.ValueOfFees, - StartedTransactionCount = entity.StartedTransactionCount, - FeeCount = entity.FeeCount, - AuthorisedSales = entity.AuthorisedSales, - CompletedTransactionCount = entity.CompletedTransactionCount, - DepositCount = entity.DepositCount, - LastDeposit = entity.LastDeposit, - LastFee = entity.LastFee, - LastSale = entity.LastSale, - SaleCount = entity.SaleCount, - TotalDeposited = entity.TotalDeposited, - }; + #region Methods + + public static Event Create(String type, + IDomainEvent domainEvent) { + return new() { + EventId = domainEvent.EventId, + Date = domainEvent.EventTimestamp.Date.Date, + Type = type + }; } - public async Task Load(IDomainEvent @event, CancellationToken cancellationToken) - { + public async Task Load(IDomainEvent @event, + CancellationToken cancellationToken) { Guid estateId = DomainEventHelper.GetEstateId(@event); Guid merchantId = DomainEventHelper.GetMerchantId(@event); @@ -72,77 +43,114 @@ public async Task Load(IDomainEvent @event, CancellationTo } public async Task Load(Guid estateId, - Guid stateId, - CancellationToken cancellationToken) { + Guid stateId, + CancellationToken cancellationToken) { return await this.LoadHelper(estateId, stateId, cancellationToken); } - public async Task Save(MerchantBalanceState state, IDomainEvent domainEvent, CancellationToken cancellationToken) - { - - await using TransactionProcessorGenericContext context = await this.ContextFactory.GetContext(state.EstateId, ConnectionStringIdentifier, cancellationToken); + public async Task Save(MerchantBalanceState state, + IDomainEvent domainEvent, + CancellationToken cancellationToken) { + await using TransactionProcessorGenericContext context = + await this.ContextFactory.GetContext(state.EstateId, MerchantBalanceStateRepository.ConnectionStringIdentifier, cancellationToken); // Note: we don't want to select the state again here.... MerchantBalanceProjectionState entity = MerchantBalanceStateRepository.CreateMerchantBalanceProjectionState(state); - if (state.IsInitialised) - { + if (state.IsInitialised) { // handle updates here context.MerchantBalanceProjectionState.Update(entity); } - else - { + else { await context.MerchantBalanceProjectionState.AddAsync(entity, cancellationToken); } - Event @event = MerchantBalanceStateRepository.Create(state.GetType().Name, - domainEvent); + Event @event = MerchantBalanceStateRepository.Create(state.GetType().Name, domainEvent); await context.Events.AddAsync(@event, cancellationToken); - try - { + try { await context.SaveChangesAsync(cancellationToken); } - catch (DbUpdateException) - { + catch(DbUpdateException) { //This lets the next component know no changes were persisted. - state = state with - { - ChangesApplied = false - }; + state = state with { + ChangesApplied = false + }; } - + return state; } - private static MerchantBalanceProjectionState CreateMerchantBalanceProjectionState(MerchantBalanceState state) - { - MerchantBalanceProjectionState entity = new() - { - Balance = state.Balance, - EstateId = state.EstateId, - MerchantId = state.MerchantId, - AvailableBalance = state.AvailableBalance, - MerchantName = state.MerchantName, - Timestamp = state.Version, - DeclinedSales = state.DeclinedSales, - ValueOfFees = state.ValueOfFees, - StartedTransactionCount = state.StartedTransactionCount, - FeeCount = state.FeeCount, - AuthorisedSales = state.AuthorisedSales, - CompletedTransactionCount = state.CompletedTransactionCount, - DepositCount = state.DepositCount, - LastDeposit = state.LastDeposit, - LastFee = state.LastFee, - LastSale = state.LastSale, - SaleCount = state.SaleCount, - TotalDeposited = state.TotalDeposited, - }; + private static MerchantBalanceProjectionState CreateMerchantBalanceProjectionState(MerchantBalanceState state) { + MerchantBalanceProjectionState entity = new() { + Balance = state.Balance, + EstateId = state.EstateId, + MerchantId = state.MerchantId, + AvailableBalance = state.AvailableBalance, + MerchantName = state.MerchantName, + Timestamp = state.Version, + DeclinedSales = state.DeclinedSales, + ValueOfFees = state.ValueOfFees, + StartedTransactionCount = state.StartedTransactionCount, + FeeCount = state.FeeCount, + AuthorisedSales = state.AuthorisedSales, + CompletedTransactionCount = state.CompletedTransactionCount, + DepositCount = state.DepositCount, + LastDeposit = state.LastDeposit, + LastFee = state.LastFee, + LastSale = state.LastSale, + SaleCount = state.SaleCount, + TotalDeposited = state.TotalDeposited, + LastWithdrawal = state.LastWithdrawal, + TotalWithdrawn = state.TotalWithdrawn, + WithdrawalCount = state.WithdrawalCount, + }; return entity; } - //public async Task Load(Guid organisationId, Guid storeId, CancellationToken cancellationToken) - //{ - // return await LoadHelper(organisationId, storeId, 0, cancellationToken); - //} + private async Task LoadHelper(Guid estateId, + Guid merchantId, + CancellationToken cancellationToken) { + await using TransactionProcessorGenericContext context = + await this.ContextFactory.GetContext(estateId, MerchantBalanceStateRepository.ConnectionStringIdentifier, cancellationToken); + + MerchantBalanceProjectionState? entity = await context.MerchantBalanceProjectionState.Where(m => m.MerchantId == merchantId).SingleOrDefaultAsync(); + + if (entity == null) { + return new MerchantBalanceState(); + } + + // We have located a state record so we need to translate to the Model type + return new MerchantBalanceState { + Version = entity.Timestamp, + Balance = entity.Balance, + MerchantId = merchantId, + AvailableBalance = entity.AvailableBalance, + MerchantName = entity.MerchantName, + EstateId = entity.EstateId, + DeclinedSales = entity.DeclinedSales, + ValueOfFees = entity.ValueOfFees, + StartedTransactionCount = entity.StartedTransactionCount, + FeeCount = entity.FeeCount, + AuthorisedSales = entity.AuthorisedSales, + CompletedTransactionCount = entity.CompletedTransactionCount, + DepositCount = entity.DepositCount, + LastDeposit = entity.LastDeposit, + LastFee = entity.LastFee, + LastSale = entity.LastSale, + SaleCount = entity.SaleCount, + TotalDeposited = entity.TotalDeposited, + LastWithdrawal = entity.LastWithdrawal, + TotalWithdrawn = entity.TotalWithdrawn, + WithdrawalCount = entity.WithdrawalCount, + }; + } + + #endregion + + #region Others + + private const String ConnectionStringIdentifier = "TransactionProcessorReadModel"; + + #endregion } \ No newline at end of file diff --git a/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs b/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs index b6a07129..62edcc86 100644 --- a/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs +++ b/TransactionProcessor.ProjectionEngine/State/MerchantBalanceState.cs @@ -1,5 +1,7 @@ namespace TransactionProcessor.ProjectionEngine.State; +using EstateManagement.Merchant.DomainEvents; + public record MerchantBalanceState : State { public Guid EstateId { get; init; } @@ -9,7 +11,10 @@ public record MerchantBalanceState : State public Decimal Balance { get; init; } public Int32 DepositCount { get; init; } + + public Int32 WithdrawalCount { get; init; } public Decimal TotalDeposited { get; init; } + public Decimal TotalWithdrawn { get; init; } public Int32 SaleCount { get; init; } public Decimal AuthorisedSales { get; init; } @@ -19,6 +24,7 @@ public record MerchantBalanceState : State public Decimal ValueOfFees { get; init; } public DateTime LastDeposit { get; init; } + public DateTime LastWithdrawal { get; init; } public DateTime LastSale { get; init; } public DateTime LastFee { get; init; } diff --git a/TransactionProcessor.ProjectionEngine/State/MerchantBalanceStateExtensions.cs b/TransactionProcessor.ProjectionEngine/State/MerchantBalanceStateExtensions.cs index eba62ba8..a4bb5c3a 100644 --- a/TransactionProcessor.ProjectionEngine/State/MerchantBalanceStateExtensions.cs +++ b/TransactionProcessor.ProjectionEngine/State/MerchantBalanceStateExtensions.cs @@ -26,6 +26,11 @@ public static MerchantBalanceState HandleManualDepositMadeEvent(this MerchantBal ManualDepositMadeEvent mdme) => state.IncrementAvailableBalance(mdme.Amount).IncrementBalance(mdme.Amount).RecordDeposit(mdme); + [Pure] + public static MerchantBalanceState HandleWithdrawalMadeEvent(this MerchantBalanceState state, + WithdrawalMadeEvent wme) => + state.DecrementAvailableBalance(wme.Amount).DecrementBalance(wme.Amount).RecordWithdrawal(wme); + [Pure] public static MerchantBalanceState HandleAutomaticDepositMadeEvent(this MerchantBalanceState state, AutomaticDepositMadeEvent adme) => @@ -140,6 +145,16 @@ state with LastDeposit = adme.DepositDateTime > state.LastDeposit ? adme.DepositDateTime : state.LastDeposit, }; + [Pure] + public static MerchantBalanceState RecordWithdrawal(this MerchantBalanceState state, + WithdrawalMadeEvent wme) => + state with + { + WithdrawalCount = state.WithdrawalCount + 1, + TotalWithdrawn = state.TotalWithdrawn + wme.Amount, + LastWithdrawal = wme.WithdrawalDateTime > state.LastWithdrawal ? wme.WithdrawalDateTime : state.LastWithdrawal + }; + [Pure] public static MerchantBalanceState RecordAuthorisedSale(this MerchantBalanceState state, Decimal saleAmount) => diff --git a/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj b/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj index 2baf3e77..ad9cb33f 100644 --- a/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj +++ b/TransactionProcessor.ProjectionEngine/TransactionProcessor.ProjectionEngine.csproj @@ -7,10 +7,10 @@ - - - - + + + + all @@ -19,9 +19,9 @@ - + - + diff --git a/TransactionProcessor.Reconciliation.DomainEvents/TransactionProcessor.Reconciliation.DomainEvents.csproj b/TransactionProcessor.Reconciliation.DomainEvents/TransactionProcessor.Reconciliation.DomainEvents.csproj index 73da5ea7..a20ff558 100644 --- a/TransactionProcessor.Reconciliation.DomainEvents/TransactionProcessor.Reconciliation.DomainEvents.csproj +++ b/TransactionProcessor.Reconciliation.DomainEvents/TransactionProcessor.Reconciliation.DomainEvents.csproj @@ -5,6 +5,6 @@ - + diff --git a/TransactionProcessor.ReconciliationAggregate/TransactionProcessor.ReconciliationAggregate.csproj b/TransactionProcessor.ReconciliationAggregate/TransactionProcessor.ReconciliationAggregate.csproj index a426a6cb..73d6c9ea 100644 --- a/TransactionProcessor.ReconciliationAggregate/TransactionProcessor.ReconciliationAggregate.csproj +++ b/TransactionProcessor.ReconciliationAggregate/TransactionProcessor.ReconciliationAggregate.csproj @@ -6,7 +6,7 @@ - + diff --git a/TransactionProcessor.Settlement.DomainEvents/TransactionProcessor.Settlement.DomainEvents.csproj b/TransactionProcessor.Settlement.DomainEvents/TransactionProcessor.Settlement.DomainEvents.csproj index 8be74393..ef6600c6 100644 --- a/TransactionProcessor.Settlement.DomainEvents/TransactionProcessor.Settlement.DomainEvents.csproj +++ b/TransactionProcessor.Settlement.DomainEvents/TransactionProcessor.Settlement.DomainEvents.csproj @@ -5,7 +5,7 @@ - + diff --git a/TransactionProcessor.SettlementAggregates/TransactionProcessor.SettlementAggregates.csproj b/TransactionProcessor.SettlementAggregates/TransactionProcessor.SettlementAggregates.csproj index 2955834e..87b0e456 100644 --- a/TransactionProcessor.SettlementAggregates/TransactionProcessor.SettlementAggregates.csproj +++ b/TransactionProcessor.SettlementAggregates/TransactionProcessor.SettlementAggregates.csproj @@ -6,7 +6,7 @@ - + diff --git a/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj b/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj index a4484565..24ab681c 100644 --- a/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj +++ b/TransactionProcessor.Transaction.DomainEvents/TransactionProcessor.Transaction.DomainEvents.csproj @@ -5,7 +5,7 @@ - + diff --git a/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj b/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj index 744b1489..661fb3b4 100644 --- a/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj +++ b/TransactionProcessor.TransactionAgrgegate/TransactionProcessor.TransactionAggregate.csproj @@ -6,7 +6,7 @@ - + diff --git a/TransactionProcessor.Voucher.DomainEvents/TransactionProcessor.Voucher.DomainEvents.csproj b/TransactionProcessor.Voucher.DomainEvents/TransactionProcessor.Voucher.DomainEvents.csproj index a8b66816..18d91721 100644 --- a/TransactionProcessor.Voucher.DomainEvents/TransactionProcessor.Voucher.DomainEvents.csproj +++ b/TransactionProcessor.Voucher.DomainEvents/TransactionProcessor.Voucher.DomainEvents.csproj @@ -7,6 +7,6 @@ - + diff --git a/TransactionProcessor.VoucherAggregate/TransactionProcessor.VoucherAggregate.csproj b/TransactionProcessor.VoucherAggregate/TransactionProcessor.VoucherAggregate.csproj index 3dced288..a4a75fc7 100644 --- a/TransactionProcessor.VoucherAggregate/TransactionProcessor.VoucherAggregate.csproj +++ b/TransactionProcessor.VoucherAggregate/TransactionProcessor.VoucherAggregate.csproj @@ -8,7 +8,7 @@ - + diff --git a/TransactionProcessor/TransactionProcessor.csproj b/TransactionProcessor/TransactionProcessor.csproj index 94594502..8641c5cf 100644 --- a/TransactionProcessor/TransactionProcessor.csproj +++ b/TransactionProcessor/TransactionProcessor.csproj @@ -35,8 +35,8 @@ - - + + diff --git a/TransactionProcessor/appsettings.json b/TransactionProcessor/appsettings.json index 3a0699e9..5afdb0ba 100644 --- a/TransactionProcessor/appsettings.json +++ b/TransactionProcessor/appsettings.json @@ -27,6 +27,9 @@ "ManualDepositMadeEvent": [ "TransactionProcessor.ProjectionEngine.EventHandling.EventHandler,TransactionProcessor.ProjectionEngine" ], + "WithdrawalMadeEvent": [ + "TransactionProcessor.ProjectionEngine.EventHandling.EventHandler,TransactionProcessor.ProjectionEngine" + ], "AutomaticDepositMadeEvent": [ "TransactionProcessor.ProjectionEngine.EventHandling.EventHandler,TransactionProcessor.ProjectionEngine" ], @@ -47,6 +50,7 @@ "EstateCreatedEvent": "MerchantBalanceProjectionState", "MerchantCreatedEvent": "MerchantBalanceProjectionState", "ManualDepositMadeEvent": "MerchantBalanceProjectionState", + "WithdrawalMadeEvent": "MerchantBalanceProjectionState", "AutomaticDepositMadeEvent": "MerchantBalanceProjectionState", "TransactionHasStartedEvent": "MerchantBalanceProjectionState", "TransactionHasBeenCompletedEvent": "MerchantBalanceProjectionState", From fe5ec548e3495141794a67ac8ef59234014bfd86 Mon Sep 17 00:00:00 2001 From: Stuart Ferguson Date: Thu, 8 Dec 2022 12:23:56 +0000 Subject: [PATCH 2/2] Missing migrations --- ...0221208121102_recordwithdrawls.Designer.cs | 188 ++++++++++++++++++ .../20221208121102_recordwithdrawls.cs | 72 +++++++ ...0221208122239_recordwithdrawls.Designer.cs | 183 +++++++++++++++++ .../20221208122239_recordwithdrawls.cs | 52 +++++ ...ctionProcessorMySqlContextModelSnapshot.cs | 41 +++- ...nProcessorSqlServerContextModelSnapshot.cs | 45 ++++- TransactionProcessor/appsettings.json | 2 +- 7 files changed, 578 insertions(+), 5 deletions(-) create mode 100644 TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.Designer.cs create mode 100644 TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.cs create mode 100644 TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.Designer.cs create mode 100644 TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.cs diff --git a/TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.Designer.cs b/TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.Designer.cs new file mode 100644 index 00000000..aa272721 --- /dev/null +++ b/TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.Designer.cs @@ -0,0 +1,188 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TransactionProcessor.ProjectionEngine.Database; + +#nullable disable + +namespace TransactionProcessor.ProjectionEngine.Migrations +{ + [DbContext(typeof(TransactionProcessorSqlServerContext))] + [Migration("20221208121102_recordwithdrawls")] + partial class recordwithdrawls + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.Event", b => + { + b.Property("EventId") + .HasColumnType("uniqueidentifier"); + + b.Property("Type") + .HasColumnType("nvarchar(450)"); + + b.Property("Date") + .HasColumnType("date"); + + b.HasKey("EventId", "Type"); + + SqlServerKeyBuilderExtensions.IsClustered(b.HasKey("EventId", "Type")); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.MerchantBalanceChangedEntry", b => + { + b.Property("AggregateId") + .HasColumnType("uniqueidentifier"); + + b.Property("OriginalEventId") + .HasColumnType("uniqueidentifier"); + + b.Property("CauseOfChangeId") + .HasColumnType("uniqueidentifier"); + + b.Property("ChangeAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("DebitOrCredit") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EstateId") + .HasColumnType("uniqueidentifier"); + + b.Property("MerchantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reference") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("AggregateId", "OriginalEventId"); + + b.ToTable("MerchantBalanceChangedEntry"); + }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.MerchantBalanceProjectionState", b => + { + b.Property("EstateId") + .HasColumnType("uniqueidentifier"); + + b.Property("MerchantId") + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorisedSales") + .HasColumnType("decimal(18,2)"); + + b.Property("AvailableBalance") + .HasColumnType("decimal(18,2)"); + + b.Property("Balance") + .HasColumnType("decimal(18,2)"); + + b.Property("CompletedTransactionCount") + .HasColumnType("int"); + + b.Property("DeclinedSales") + .HasColumnType("decimal(18,2)"); + + b.Property("DepositCount") + .HasColumnType("int"); + + b.Property("FeeCount") + .HasColumnType("int"); + + b.Property("LastDeposit") + .HasColumnType("datetime2"); + + b.Property("LastFee") + .HasColumnType("datetime2"); + + b.Property("LastSale") + .HasColumnType("datetime2"); + + b.Property("LastWithdrawal") + .HasColumnType("datetime2"); + + b.Property("MerchantName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SaleCount") + .HasColumnType("int"); + + b.Property("StartedTransactionCount") + .HasColumnType("int"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("rowversion"); + + b.Property("TotalDeposited") + .HasColumnType("decimal(18,2)"); + + b.Property("TotalWithdrawn") + .HasColumnType("decimal(18,2)"); + + b.Property("ValueOfFees") + .HasColumnType("decimal(18,2)"); + + b.Property("WithdrawalCount") + .HasColumnType("int"); + + b.HasKey("EstateId", "MerchantId"); + + b.ToTable("MerchantBalanceProjectionState"); + }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.ViewEntities.MerchantBalanceHistoryViewEntry", b => + { + b.Property("Balance") + .HasColumnType("decimal(18,2)"); + + b.Property("ChangeAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DebitOrCredit") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntryDateTime") + .HasColumnType("datetime2"); + + b.Property("MerchantId") + .HasColumnType("uniqueidentifier"); + + b.Property("OriginalEventId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reference") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.ToTable((string)null); + + b.ToView("uvwMerchantBalanceHistory", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.cs b/TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.cs new file mode 100644 index 00000000..ee1e6ddc --- /dev/null +++ b/TransactionProcessor.ProjectionEngine/Migrations/20221208121102_recordwithdrawls.cs @@ -0,0 +1,72 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TransactionProcessor.ProjectionEngine.Migrations +{ + /// + public partial class recordwithdrawls : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_Events", + table: "Events"); + + migrationBuilder.AddColumn( + name: "LastWithdrawal", + table: "MerchantBalanceProjectionState", + type: "datetime2", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "TotalWithdrawn", + table: "MerchantBalanceProjectionState", + type: "decimal(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "WithdrawalCount", + table: "MerchantBalanceProjectionState", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddPrimaryKey( + name: "PK_Events", + table: "Events", + columns: new[] { "EventId", "Type" }) + .Annotation("SqlServer:Clustered", true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_Events", + table: "Events"); + + migrationBuilder.DropColumn( + name: "LastWithdrawal", + table: "MerchantBalanceProjectionState"); + + migrationBuilder.DropColumn( + name: "TotalWithdrawn", + table: "MerchantBalanceProjectionState"); + + migrationBuilder.DropColumn( + name: "WithdrawalCount", + table: "MerchantBalanceProjectionState"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Events", + table: "Events", + columns: new[] { "EventId", "Type" }) + .Annotation("SqlServer:Clustered", false); + } + } +} diff --git a/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.Designer.cs b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.Designer.cs new file mode 100644 index 00000000..68a8b6de --- /dev/null +++ b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.Designer.cs @@ -0,0 +1,183 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using TransactionProcessor.ProjectionEngine.Database; + +#nullable disable + +namespace TransactionProcessor.ProjectionEngine.Migrations.TransactionProcessorMySql +{ + [DbContext(typeof(TransactionProcessorMySqlContext))] + [Migration("20221208122239_recordwithdrawls")] + partial class recordwithdrawls + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.Event", b => + { + b.Property("EventId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("varchar(255)"); + + b.Property("Date") + .HasColumnType("date"); + + b.HasKey("EventId", "Type") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.MerchantBalanceChangedEntry", b => + { + b.Property("AggregateId") + .HasColumnType("char(36)"); + + b.Property("OriginalEventId") + .HasColumnType("char(36)"); + + b.Property("CauseOfChangeId") + .HasColumnType("char(36)"); + + b.Property("ChangeAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("DateTime") + .HasColumnType("datetime(6)"); + + b.Property("DebitOrCredit") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EstateId") + .HasColumnType("char(36)"); + + b.Property("MerchantId") + .HasColumnType("char(36)"); + + b.Property("Reference") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("AggregateId", "OriginalEventId"); + + b.ToTable("MerchantBalanceChangedEntry"); + }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.MerchantBalanceProjectionState", b => + { + b.Property("EstateId") + .HasColumnType("char(36)"); + + b.Property("MerchantId") + .HasColumnType("char(36)"); + + b.Property("AuthorisedSales") + .HasColumnType("decimal(65,30)"); + + b.Property("AvailableBalance") + .HasColumnType("decimal(65,30)"); + + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("CompletedTransactionCount") + .HasColumnType("int"); + + b.Property("DeclinedSales") + .HasColumnType("decimal(65,30)"); + + b.Property("DepositCount") + .HasColumnType("int"); + + b.Property("FeeCount") + .HasColumnType("int"); + + b.Property("LastDeposit") + .HasColumnType("datetime(6)"); + + b.Property("LastFee") + .HasColumnType("datetime(6)"); + + b.Property("LastSale") + .HasColumnType("datetime(6)"); + + b.Property("LastWithdrawal") + .HasColumnType("datetime(6)"); + + b.Property("MerchantName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SaleCount") + .HasColumnType("int"); + + b.Property("StartedTransactionCount") + .HasColumnType("int"); + + b.Property("Timestamp") + .IsConcurrencyToken() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("timestamp(6)"); + + b.Property("TotalDeposited") + .HasColumnType("decimal(65,30)"); + + b.Property("TotalWithdrawn") + .HasColumnType("decimal(65,30)"); + + b.Property("ValueOfFees") + .HasColumnType("decimal(65,30)"); + + b.Property("WithdrawalCount") + .HasColumnType("int"); + + b.HasKey("EstateId", "MerchantId"); + + b.ToTable("MerchantBalanceProjectionState"); + }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.ViewEntities.MerchantBalanceHistoryViewEntry", b => + { + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("ChangeAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("DebitOrCredit") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EntryDateTime") + .HasColumnType("datetime(6)"); + + b.Property("MerchantId") + .HasColumnType("char(36)"); + + b.Property("OriginalEventId") + .HasColumnType("char(36)"); + + b.Property("Reference") + .IsRequired() + .HasColumnType("longtext"); + + b.ToTable((string)null); + + b.ToView("uvwMerchantBalanceHistory", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.cs b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.cs new file mode 100644 index 00000000..3d48bfa3 --- /dev/null +++ b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/20221208122239_recordwithdrawls.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TransactionProcessor.ProjectionEngine.Migrations.TransactionProcessorMySql +{ + /// + public partial class recordwithdrawls : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastWithdrawal", + table: "MerchantBalanceProjectionState", + type: "datetime(6)", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + + migrationBuilder.AddColumn( + name: "TotalWithdrawn", + table: "MerchantBalanceProjectionState", + type: "decimal(65,30)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "WithdrawalCount", + table: "MerchantBalanceProjectionState", + type: "int", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastWithdrawal", + table: "MerchantBalanceProjectionState"); + + migrationBuilder.DropColumn( + name: "TotalWithdrawn", + table: "MerchantBalanceProjectionState"); + + migrationBuilder.DropColumn( + name: "WithdrawalCount", + table: "MerchantBalanceProjectionState"); + } + } +} diff --git a/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/TransactionProcessorMySqlContextModelSnapshot.cs b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/TransactionProcessorMySqlContextModelSnapshot.cs index 61c6b171..3823f4d7 100644 --- a/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/TransactionProcessorMySqlContextModelSnapshot.cs +++ b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorMySql/TransactionProcessorMySqlContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("ProductVersion", "7.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.Event", b => @@ -110,6 +110,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("LastSale") .HasColumnType("datetime(6)"); + b.Property("LastWithdrawal") + .HasColumnType("datetime(6)"); + b.Property("MerchantName") .IsRequired() .HasColumnType("longtext"); @@ -128,13 +131,49 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("TotalDeposited") .HasColumnType("decimal(65,30)"); + b.Property("TotalWithdrawn") + .HasColumnType("decimal(65,30)"); + b.Property("ValueOfFees") .HasColumnType("decimal(65,30)"); + b.Property("WithdrawalCount") + .HasColumnType("int"); + b.HasKey("EstateId", "MerchantId"); b.ToTable("MerchantBalanceProjectionState"); }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.ViewEntities.MerchantBalanceHistoryViewEntry", b => + { + b.Property("Balance") + .HasColumnType("decimal(65,30)"); + + b.Property("ChangeAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("DebitOrCredit") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EntryDateTime") + .HasColumnType("datetime(6)"); + + b.Property("MerchantId") + .HasColumnType("char(36)"); + + b.Property("OriginalEventId") + .HasColumnType("char(36)"); + + b.Property("Reference") + .IsRequired() + .HasColumnType("longtext"); + + b.ToTable((string)null); + + b.ToView("uvwMerchantBalanceHistory", (string)null); + }); #pragma warning restore 612, 618 } } diff --git a/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorSqlServerContextModelSnapshot.cs b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorSqlServerContextModelSnapshot.cs index 94c217e4..86fb3f18 100644 --- a/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorSqlServerContextModelSnapshot.cs +++ b/TransactionProcessor.ProjectionEngine/Migrations/TransactionProcessorSqlServerContextModelSnapshot.cs @@ -17,10 +17,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("ProductVersion", "7.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 128); - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.Entities.Event", b => { @@ -35,7 +35,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("EventId", "Type"); - SqlServerKeyBuilderExtensions.IsClustered(b.HasKey("EventId", "Type"), false); + SqlServerKeyBuilderExtensions.IsClustered(b.HasKey("EventId", "Type")); b.ToTable("Events"); }); @@ -114,6 +114,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("LastSale") .HasColumnType("datetime2"); + b.Property("LastWithdrawal") + .HasColumnType("datetime2"); + b.Property("MerchantName") .IsRequired() .HasColumnType("nvarchar(max)"); @@ -133,13 +136,49 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("TotalDeposited") .HasColumnType("decimal(18,2)"); + b.Property("TotalWithdrawn") + .HasColumnType("decimal(18,2)"); + b.Property("ValueOfFees") .HasColumnType("decimal(18,2)"); + b.Property("WithdrawalCount") + .HasColumnType("int"); + b.HasKey("EstateId", "MerchantId"); b.ToTable("MerchantBalanceProjectionState"); }); + + modelBuilder.Entity("TransactionProcessor.ProjectionEngine.Database.ViewEntities.MerchantBalanceHistoryViewEntry", b => + { + b.Property("Balance") + .HasColumnType("decimal(18,2)"); + + b.Property("ChangeAmount") + .HasColumnType("decimal(18,2)"); + + b.Property("DebitOrCredit") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EntryDateTime") + .HasColumnType("datetime2"); + + b.Property("MerchantId") + .HasColumnType("uniqueidentifier"); + + b.Property("OriginalEventId") + .HasColumnType("uniqueidentifier"); + + b.Property("Reference") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.ToTable((string)null); + + b.ToView("uvwMerchantBalanceHistory", (string)null); + }); #pragma warning restore 612, 618 } } diff --git a/TransactionProcessor/appsettings.json b/TransactionProcessor/appsettings.json index 5afdb0ba..91d9b9cc 100644 --- a/TransactionProcessor/appsettings.json +++ b/TransactionProcessor/appsettings.json @@ -85,7 +85,7 @@ // SQL Server "TransactionProcessorReadModel": "server=192.168.1.133;user id=sa;password=Sc0tland;database=TransactionProcessorReadModel;Encrypt=false" // MySql - //"TransactionProcessorReadModel": "server=127.0.0.1;userid=root;password=sp1ttal;database=TransactionProcessorReadModel;" + //"TransactionProcessorReadModel": "server=127.0.0.1;userid=root;password=sp1ttal;database=TransactionProcessorReadModel" }, "SecurityConfiguration": { "ApiName": "transactionProcessor"