public async Task CannnotWithdrawCashIfOverdrafdIsExceeded(decimal deposit, decimal overdraft, decimal withdraw) { var accCreatedEv = new AccountCreated(CorrelatedMessage.NewRoot()) { AccountId = _accountId, Name = "Jake Sanders" }; var depositSetEv = new CashDeposited(CorrelatedMessage.NewRoot()) { AccountId = _accountId, Amount = deposit }; var overdraftSetEv = new OverdraftLimitSet(CorrelatedMessage.NewRoot()) { AccountId = _accountId, OverdraftLimit = overdraft }; var cmd = new WithdrawCash() { AccountId = _accountId, Amount = withdraw }; var withdrawalFailedEv = new WithdrawalFailed(CorrelatedMessage.NewRoot()) { AccountId = _accountId, Amount = cmd.Amount }; var accBlockedEv = new AccountBlocked(CorrelatedMessage.NewRoot()) { AccountId = _accountId }; await _runner.Run( def => def .Given(accCreatedEv, depositSetEv, overdraftSetEv) .When(cmd) .Then(withdrawalFailedEv, accBlockedEv)); }
public async Task CanSetOverdraftLimit(decimal limit) { var accCreatedEv = new AccountCreated(CorrelatedMessage.NewRoot()) { AccountId = _accountId, Name = "Jake Sanders" }; var cmd = new SetOverdraftLimit { AccountId = _accountId, OverdraftLimit = limit }; var limitSetEv = new OverdraftLimitSet(CorrelatedMessage.NewRoot()) { AccountId = cmd.AccountId, OverdraftLimit = cmd.OverdraftLimit }; await _runner.Run( def => def.Given(accCreatedEv).When(cmd).Then(limitSetEv) ); }
public static async Task <Tuple <string, bool> > SetOverdraftForInterestForSpecificAccount ([ActivityTrigger] IDurableActivityContext interestOverdraftContext) { string accountNumber = interestOverdraftContext.GetInput <string>(); #region Tracing telemetry Activity.Current.AddTag("Account Number", accountNumber); #endregion bool success = true; Command cmdPayInterest = new Command( new CommandAttribute("Bank", "Pay Interest", interestOverdraftContext.InstanceId) ); if (!string.IsNullOrWhiteSpace(accountNumber)) { string result = "No overdraft required"; await cmdPayInterest.InitiateStep(AccountCommands.COMMAND_STEP_OVERDRAFT, "Bank", "Account", accountNumber); // run the "set overdraft limit for interest" function // 1- Get interest due... Projection prjInterestDue = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(InterestDue) ) ); // get the interest owed / due as now InterestDue interestDue = await prjInterestDue.Process <InterestDue>(); if (null != interestDue) { // if the interest due is negative we need to make sure the account has sufficient balance if (interestDue.Due < 0.00M) { Projection prjBankAccountBalance = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(InterestDue) ) ); Balance balance = await prjBankAccountBalance.Process <Balance>(); if (null != balance) { decimal availableBalance = balance.CurrentBalance; // is there an overdraft? Projection prjBankAccountOverdraft = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(OverdraftLimit) ) ); OverdraftLimit overdraft = await prjBankAccountOverdraft.Process <OverdraftLimit>(); if (null != overdraft) { availableBalance += overdraft.CurrentOverdraftLimit; } if (availableBalance < interestDue.Due) { // Force an overdraft extension EventStream bankAccountEvents = new EventStream( new EventStreamAttribute( "Bank", "Account", accountNumber ) ); decimal newOverdraft = overdraft.CurrentOverdraftLimit; decimal extension = 10.00M + Math.Abs(interestDue.Due % 10.00M); OverdraftLimitSet evNewLimit = new OverdraftLimitSet() { OverdraftLimit = newOverdraft + extension, Commentary = $"Overdraft extended to pay interest of {interestDue.Due} ", Unauthorised = true }; result = $"Overdraft set to {evNewLimit.OverdraftLimit } ({evNewLimit.Commentary})"; try { await bankAccountEvents.AppendEvent(evNewLimit, balance.CurrentSequenceNumber); } catch (EventSourcingOnAzureFunctions.Common.EventSourcing.Exceptions.EventStreamWriteException) { success = false; } } } } } // Log the step completion if it was successful if (success) { await cmdPayInterest.StepCompleted(AccountCommands.COMMAND_STEP_OVERDRAFT, result, "Bank", "Account", accountNumber); } } return(new Tuple <string, bool>(accountNumber, success)); }
public static async void SetOverdraftForInterestCommandStep ([EventGridTrigger] EventGridEvent egStepTriggered ) { // Get the parameters from the event grid trigger // (Payload is a Command Step Initiated) Command cmdApplyAccruedInterest = new Command(egStepTriggered); if (null != cmdApplyAccruedInterest) { string result = $"No overdraft extension required"; if (cmdApplyAccruedInterest.CommandName == COMMAND_STEP_OVERDRAFT) { // Get the parameter for account number string accountNumber = (string)(await cmdApplyAccruedInterest.GetParameterValue("Account Number")); if (!string.IsNullOrWhiteSpace(accountNumber)) { // run the "set overdraft limit for interest" function // 1- Get interest due... Projection prjInterestDue = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(InterestDue) ) ); // get the interest owed / due as now InterestDue interestDue = await prjInterestDue.Process <InterestDue>(); if (null != interestDue) { // if the interest due is negative we need to make sure the account has sufficient balance if (interestDue.Due < 0.00M) { Projection prjBankAccountBalance = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(InterestDue) ) ); Balance balance = await prjBankAccountBalance.Process <Balance>(); if (null != balance) { decimal availableBalance = balance.CurrentBalance; // is there an overdraft? Projection prjBankAccountOverdraft = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(OverdraftLimit) ) ); OverdraftLimit overdraft = await prjBankAccountOverdraft.Process <OverdraftLimit>(); if (null != overdraft) { availableBalance += overdraft.CurrentOverdraftLimit; } if (availableBalance < interestDue.Due) { // Force an overdraft extension EventStream bankAccountEvents = new EventStream( new EventStreamAttribute( "Bank", "Account", accountNumber ) ); decimal newOverdraft = overdraft.CurrentOverdraftLimit; decimal extension = 10.00M + Math.Abs(interestDue.Due % 10.00M); OverdraftLimitSet evNewLimit = new OverdraftLimitSet() { OverdraftLimit = newOverdraft + extension, Commentary = $"Overdraft extended to pay interest of {interestDue.Due} ", Unauthorised = true }; await bankAccountEvents.AppendEvent(evNewLimit); result = $"{evNewLimit.Commentary} on account {accountNumber }"; } } } } } } // mark this step as complete await cmdApplyAccruedInterest.StepCompleted(COMMAND_STEP_OVERDRAFT, result); } }
public static async Task <int> SetOverdraftForInterestCommandStep ([ActivityTrigger] IDurableActivityContext setOverdraftContext) { int overdraftSequenceNumber = 0; CommandAttribute payload = setOverdraftContext.GetInput <CommandAttribute>(); Command cmdApplyAccruedInterest = null; if (payload == null) { cmdApplyAccruedInterest = new Command(payload); } else { cmdApplyAccruedInterest = new Command(new CommandAttribute("Bank", "Apply Accrued Interest")); } // Set the next step "setting an overdraft if needed" await cmdApplyAccruedInterest.InitiateStep(COMMAND_STEP_OVERDRAFT); string accountNumber = (string)(await cmdApplyAccruedInterest.GetParameterValue("Account Number")); string result = $"No overdraft extension required"; if (!string.IsNullOrWhiteSpace(accountNumber)) { // run the "set overdraft limit for interest" function // 1- Get interest due... Projection prjInterestDue = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(InterestDue) ) ); // get the interest owed / due as now InterestDue interestDue = await prjInterestDue.Process <InterestDue>(); if (null != interestDue) { // if the interest due is negative we need to make sure the account has sufficient balance if (interestDue.Due < 0.00M) { Projection prjBankAccountBalance = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(InterestDue) ) ); Balance balance = await prjBankAccountBalance.Process <Balance>(); if (null != balance) { decimal availableBalance = balance.CurrentBalance; // is there an overdraft? Projection prjBankAccountOverdraft = new Projection( new ProjectionAttribute( "Bank", "Account", accountNumber, nameof(OverdraftLimit) ) ); OverdraftLimit overdraft = await prjBankAccountOverdraft.Process <OverdraftLimit>(); if (null != overdraft) { availableBalance += overdraft.CurrentOverdraftLimit; } if (availableBalance < interestDue.Due) { // Force an overdraft extension EventStream bankAccountEvents = new EventStream( new EventStreamAttribute( "Bank", "Account", accountNumber ) ); decimal newOverdraft = overdraft.CurrentOverdraftLimit; decimal extension = 10.00M + Math.Abs(interestDue.Due % 10.00M); OverdraftLimitSet evNewLimit = new OverdraftLimitSet() { OverdraftLimit = newOverdraft + extension, Commentary = $"Overdraft extended to pay interest of {interestDue.Due} ", Unauthorised = true }; await bankAccountEvents.AppendEvent(evNewLimit, overdraft.CurrentSequenceNumber); overdraftSequenceNumber = 1 + overdraft.CurrentSequenceNumber; await cmdApplyAccruedInterest.SetParameter("Overdraft Extension", extension); result = $"{evNewLimit.Commentary} on account {accountNumber }"; } } } } } await cmdApplyAccruedInterest.SetParameter("Overdraft Event Sequence Number", overdraftSequenceNumber); // mark this step as complete await cmdApplyAccruedInterest.StepCompleted(COMMAND_STEP_OVERDRAFT, result); return(overdraftSequenceNumber); }
public static async Task <HttpResponseMessage> ExtendOverdraftForInterestRun( [HttpTrigger(AuthorizationLevel.Function, "POST", Route = @"ExtendOverdraftForInterest/{accountnumber}")] HttpRequestMessage req, string accountnumber, [EventStream("Bank", "Account", "{accountnumber}")] EventStream bankAccountEvents, [Projection("Bank", "Account", "{accountnumber}", nameof(InterestDue))] Projection prjInterestDue, [Projection("Bank", "Account", "{accountnumber}", nameof(Balance))] Projection prjBankAccountBalance, [Projection("Bank", "Account", "{accountnumber}", nameof(OverdraftLimit))] Projection prjBankAccountOverdraft ) { // Bolierplate: Set the start time for how long it took to process the message DateTime startTime = DateTime.UtcNow; // Check the balance is negative // get the interest owed / due as now InterestDue interestDue = await prjInterestDue.Process <InterestDue>(); if (null != interestDue) { // if the interest due is negative we need to make sure the account has sufficient balance if (interestDue.Due < 0.00M) { Balance balance = await prjBankAccountBalance.Process <Balance>(); if (null != balance) { decimal availableBalance = balance.CurrentBalance; // is there an overdraft? OverdraftLimit overdraft = await prjBankAccountOverdraft.Process <OverdraftLimit>(); if (null != overdraft) { availableBalance += overdraft.CurrentOverdraftLimit; } if (availableBalance < interestDue.Due) { decimal newOverdraft = overdraft.CurrentOverdraftLimit; decimal extension = 10.00M + Math.Abs(interestDue.Due % 10.00M); OverdraftLimitSet evNewLimit = new OverdraftLimitSet() { OverdraftLimit = newOverdraft + extension, Commentary = $"Overdraft extended to pay interest of {interestDue.Due} ", Unauthorised = true }; await bankAccountEvents.AppendEvent(evNewLimit); return(req.CreateResponse <ProjectionFunctionResponse>(System.Net.HttpStatusCode.OK, ProjectionFunctionResponse.CreateResponse(startTime, false, $"Extended the overdraft by {extension} for payment of interest {interestDue.Due} for account {accountnumber}", interestDue.CurrentSequenceNumber), FunctionResponse.MEDIA_TYPE)); } } } // Not needed return(req.CreateResponse <ProjectionFunctionResponse>(System.Net.HttpStatusCode.OK, ProjectionFunctionResponse.CreateResponse(startTime, false, $"Extending the overdraft for interest not required for account {accountnumber}", interestDue.CurrentSequenceNumber), FunctionResponse.MEDIA_TYPE)); } else { return(req.CreateResponse <ProjectionFunctionResponse>(System.Net.HttpStatusCode.Forbidden, ProjectionFunctionResponse.CreateResponse(startTime, true, $"Unable to extend the overdraft for account {accountnumber} for interest payment", 0), FunctionResponse.MEDIA_TYPE )); } }