예제 #1
0
        private async Task <AgencyAccount> WriteAuditLogWithReferenceCode(AgencyAccount account, ChargedMoneyData paymentData, AccountEventType eventType,
                                                                          UserInfo user)
        {
            var eventData = new AccountBalanceLogEventData(paymentData.Reason, account.Balance);
            await _auditService.Write(eventType,
                                      account.Id,
                                      paymentData.Amount,
                                      user,
                                      eventData,
                                      paymentData.ReferenceCode);

            return(account);
        }
        public async Task <Result> ChargeMoney(int accountId, ChargedMoneyData paymentData, ApiCaller apiCaller)
        {
            return(await GetAccount(accountId)
                   .Ensure(IsReasonProvided, "Payment reason cannot be empty")
                   .Ensure(a => AreCurrenciesMatch(a, paymentData), "Account and payment currency mismatch")
                   .BindWithLock(_locker, a => Result.Success(a)
                                 .Ensure(IsBalanceSufficient, "Could not charge money, insufficient balance")
                                 .BindWithTransaction(_context, account => Result.Success(account)
                                                      .Map(ChargeMoney)
                                                      .Map(WriteAuditLog))));

            bool IsReasonProvided(AgencyAccount account) => !string.IsNullOrEmpty(paymentData.Reason);

            bool IsBalanceSufficient(AgencyAccount account) => this.IsBalanceSufficient(account, paymentData.Amount);


            async Task <AgencyAccount> ChargeMoney(AgencyAccount account)
            {
                account.Balance -= paymentData.Amount;
                _context.Update(account);
                await _context.SaveChangesAsync();

                _context.Detach(account);
                return(account);
            }

            async Task <AgencyAccount> WriteAuditLog(AgencyAccount account)
            {
                var eventData = new AccountBalanceLogEventData(paymentData.Reason, account.Balance);
                await _auditService.Write(AccountEventType.Charge,
                                          account.Id,
                                          paymentData.Amount,
                                          apiCaller,
                                          eventData,
                                          paymentData.ReferenceCode);

                return(account);
            }
        }
예제 #3
0
        public async Task <Result> DecreaseManually(int agencyAccountId, PaymentData paymentData, UserInfo userInfo)
        {
            return(await GetAgencyAccount(agencyAccountId)
                   .Ensure(a => AreCurrenciesMatch(a, paymentData), "Account and payment currency mismatch")
                   .Ensure(IsReasonProvided, "Payment reason cannot be empty")
                   .Ensure(IsAmountPositive, "Payment amount must be a positive number")
                   .BindWithLock(_locker, a => Result.Success(a)
                                 .BindWithTransaction(_context, accounts => Result.Success(accounts)
                                                      .Map(Decrease)
                                                      .Map(WriteAuditLog))));

            bool IsReasonProvided(AgencyAccount _) => !string.IsNullOrEmpty(paymentData.Reason);

            bool IsAmountPositive(AgencyAccount _) => paymentData.Amount.IsGreaterThan(decimal.Zero);


            async Task <AgencyAccount> WriteAuditLog(AgencyAccount account)
            {
                var eventData = new AccountBalanceLogEventData(paymentData.Reason, account.Balance);
                await _auditService.Write(AccountEventType.ManualDecrease,
                                          account.Id,
                                          paymentData.Amount,
                                          userInfo,
                                          eventData,
                                          null);

                return(account);
            }

            async Task <AgencyAccount> Decrease(AgencyAccount agencyAccount)
            {
                agencyAccount.Balance -= paymentData.Amount;
                _context.Update(agencyAccount);
                await _context.SaveChangesAsync();

                return(agencyAccount);
            }
        }
예제 #4
0
        public async Task <Result> AddMoney(int accountId, PaymentData paymentData, UserInfo user)
        {
            return(await GetAccount(accountId)
                   .Ensure(IsReasonProvided, "Payment reason cannot be empty")
                   .Ensure(a => AreCurrenciesMatch(a, paymentData), "Account and payment currency mismatch")
                   .BindWithLock(_locker, a => Result.Success(a)
                                 .BindWithTransaction(_context, account => Result.Success(account)
                                                      .Map(AddMoney)
                                                      .Map(WriteAuditLog)
                                                      )));


            bool IsReasonProvided(AgencyAccount account) => !string.IsNullOrEmpty(paymentData.Reason);


            async Task <AgencyAccount> AddMoney(AgencyAccount account)
            {
                account.Balance += paymentData.Amount;
                _context.Update(account);
                await _context.SaveChangesAsync();

                return(account);
            }

            async Task <AgencyAccount> WriteAuditLog(AgencyAccount account)
            {
                var eventData = new AccountBalanceLogEventData(paymentData.Reason, account.Balance);
                await _auditService.Write(AccountEventType.Add,
                                          account.Id,
                                          paymentData.Amount,
                                          user,
                                          eventData,
                                          null);

                return(account);
            }
        }
        public async Task <Result> TransferToDefaultAgency(int counterpartyAccountId, MoneyAmount amount, UserInfo user)
        {
            return(await Result.Success(counterpartyAccountId)
                   .Ensure(IsAmountPositive, "Payment amount must be a positive number")
                   .Bind(GetCounterpartyAccount)
                   .Ensure(a => AreCurrenciesMatch(a, amount), "Account and payment currency mismatch")
                   .Bind(GetDefaultAgencyAccount)
                   .BindWithLock(_locker, a => Result.Success(a)
                                 .Ensure(IsBalanceSufficient, "Could not charge money, insufficient balance")
                                 .BindWithTransaction(_context, accounts => Result.Success(accounts)
                                                      .Map(TransferMoney)
                                                      .Map(WriteAuditLog))));

            bool IsAmountPositive(int _) => amount.Amount.IsGreaterThan(decimal.Zero);


            bool IsBalanceSufficient((CounterpartyAccount counterpartyAccount, AgencyAccount agencyAccount) accounts)
            => accounts.counterpartyAccount.Balance.IsGreaterOrEqualThan(amount.Amount);


            async Task <Result <(CounterpartyAccount, AgencyAccount)> > GetDefaultAgencyAccount(CounterpartyAccount counterpartyAccount)
            {
                var defaultAgency = await _context.Agencies
                                    .Where(a => a.CounterpartyId == counterpartyAccount.CounterpartyId && a.ParentId == null)
                                    .SingleOrDefaultAsync();

                if (defaultAgency == null)
                {
                    return(Result.Failure <(CounterpartyAccount, AgencyAccount)>("Could not find the default agency of the account owner"));
                }

                var agencyAccount = await _context.AgencyAccounts
                                    .Where(a => a.AgencyId == defaultAgency.Id && a.Currency == amount.Currency)
                                    .SingleOrDefaultAsync();

                if (agencyAccount == null)
                {
                    return(Result.Failure <(CounterpartyAccount, AgencyAccount)>("Could not find the default agency account"));
                }

                return(Result.Success <(CounterpartyAccount, AgencyAccount)>((counterpartyAccount, agencyAccount)));
            }

            async Task <(CounterpartyAccount, AgencyAccount)> TransferMoney((CounterpartyAccount, AgencyAccount) accounts)
            {
                var(counterpartyAccount, agencyAccount) = accounts;

                counterpartyAccount.Balance -= amount.Amount;
                _context.Update(counterpartyAccount);

                agencyAccount.Balance += amount.Amount;
                _context.Update(agencyAccount);

                await _context.SaveChangesAsync();

                return(counterpartyAccount, agencyAccount);
            }

            async Task <(CounterpartyAccount, AgencyAccount)> WriteAuditLog((CounterpartyAccount, AgencyAccount) accounts)
            {
                var(counterpartyAccount, agencyAccount) = accounts;

                var counterpartyEventData = new CounterpartyAccountBalanceLogEventData(null, counterpartyAccount.Balance);
                await _auditService.Write(AccountEventType.CounterpartyTransferToAgency,
                                          counterpartyAccount.Id,
                                          amount.Amount,
                                          user,
                                          counterpartyEventData,
                                          null);

                var agencyEventData = new AccountBalanceLogEventData(null, agencyAccount.Balance);
                await _auditService.Write(AccountEventType.CounterpartyTransferToAgency,
                                          agencyAccount.Id,
                                          amount.Amount,
                                          user,
                                          agencyEventData,
                                          null);

                return(counterpartyAccount, agencyAccount);
            }
        }