Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        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));
        }
Ejemplo n.º 4
0
        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
                                                                       ));
            }
        }