コード例 #1
0
		public PendingTransactionEventArgs(IBankAccount From, IBankAccount To, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string LogMessage) : base()
		{
			this.fromAccount = From;
			this.toAccount = To;
			this.Amount = Amount;
			this.Options = Options;
			this.TransactionMessage = TransactionMessage;
			this.JournalLogMessage = LogMessage;
			this.IsCancelled = false;
		}
コード例 #2
0
 /// <summary>
 /// Asynchronously transfers to another account.
 /// </summary>
 public Task<BankTransferEventArgs> TransferToAsync(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage) {
     Guid profile = SEconomyPlugin.Profiler.Enter(string.Format("transferAsync: {0} to {1}", this.UserAccountName, ToAccount.UserAccountName));
     return Task.Factory.StartNew<BankTransferEventArgs>(() => {
         BankTransferEventArgs args = TransferTo(ToAccount, Amount, Options, TransactionMessage, JournalMessage);
         return args;
     }).ContinueWith((task) => {
         SEconomyPlugin.Profiler.ExitLog(profile);
         return task.Result;
     });
 }
コード例 #3
0
        /// <summary>
        /// Asynchronously transfers to another account.
        /// </summary>
        public Task <BankTransferEventArgs> TransferToAsync(int Index, Money Amount, BankAccountTransferOptions Options, string Message = "")
        {
            Economy.EconomyPlayer ePlayer = SEconomyPlugin.GetEconomyPlayerSafe(Index);

            Guid profile = SEconomyPlugin.Profiler.Enter(string.Format("transferAsync: {0} to {1}", this.UserAccountName, ePlayer.BankAccount != null ? ePlayer.BankAccount.UserAccountName : "Unknown"));

            return(Task.Factory.StartNew <BankTransferEventArgs>(() => {
                BankTransferEventArgs args = TransferTo(ePlayer.BankAccount, Amount, Options, UseProfiler: false, Message: Message);
                return args;
            }).ContinueWith((task) => {
                SEconomyPlugin.Profiler.ExitLog(profile);
                return task.Result;
            }));
        }
コード例 #4
0
 public BankTransferEventArgs TransferTo(IBankAccount Account, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
 {
     return(journal.TransferBetween(this, Account, Amount, Options, TransactionMessage, JournalMessage));
 }
コード例 #5
0
        public BankTransferEventArgs TransferBetween(IBankAccount FromAccount, IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
        {
            long accountCount = -1;
            PendingTransactionEventArgs pendingTransaction = new PendingTransactionEventArgs(FromAccount, ToAccount, Amount, Options, TransactionMessage, JournalMessage);
            ITransaction          sourceTran, destTran;
            MySqlConnection       conn = null;
            MySqlTransaction      sqlTrans = null;
            BankTransferEventArgs args = new BankTransferEventArgs()
            {
                TransferSucceeded = false
            };
            string accountVerifyQuery = @"select count(*)
										  from `bank_account`
										  where	`bank_account_id` = @0;"                                        ;

            Stopwatch sw = new Stopwatch();

            if (SEconomyInstance.Configuration.EnableProfiler == true)
            {
                sw.Start();
            }
            if (ToAccount == null ||
                TransferMaySucceed(FromAccount, ToAccount, Amount, Options) == false)
            {
                return(args);
            }

            if ((conn = Connection) == null)
            {
                TShock.Log.ConsoleError(" seconomy mysql: Cannot connect to the SQL server");
                return(args);
            }

            conn.Open();

            if ((accountCount = Connection.QueryScalar <long>(accountVerifyQuery, FromAccount.BankAccountK)) != 1)
            {
                TShock.Log.ConsoleError(" seconomy mysql: Source account " + FromAccount.BankAccountK + " does not exist.");
                conn.Dispose();
                return(args);
            }

            if ((accountCount = Connection.QueryScalar <long>(accountVerifyQuery, ToAccount.BankAccountK)) != 1)
            {
                TShock.Log.ConsoleError(" seconomy mysql: Source account " + FromAccount.BankAccountK + " does not exist.");
                conn.Dispose();
                return(args);
            }

            if (BankTransactionPending != null)
            {
                BankTransactionPending(this, pendingTransaction);
            }

            if (pendingTransaction == null ||
                pendingTransaction.IsCancelled == true)
            {
                return(args);
            }

            args.Amount             = pendingTransaction.Amount;
            args.SenderAccount      = pendingTransaction.FromAccount;
            args.ReceiverAccount    = pendingTransaction.ToAccount;
            args.TransferOptions    = Options;
            args.TransactionMessage = pendingTransaction.TransactionMessage;

            try {
                sqlTrans = conn.BeginTransaction();
                if ((sourceTran = BeginSourceTransaction(sqlTrans, FromAccount.BankAccountK, pendingTransaction.Amount, pendingTransaction.JournalLogMessage)) == null)
                {
                    throw new Exception("BeginSourceTransaction failed");
                }

                if ((destTran = FinishEndTransaction(sqlTrans, ToAccount, pendingTransaction.Amount, pendingTransaction.JournalLogMessage)) == null)
                {
                    throw new Exception("FinishEndTransaction failed");
                }

                BindTransactions(sqlTrans, sourceTran.BankAccountTransactionK, destTran.BankAccountTransactionK);
                sqlTrans.Commit();
            } catch (Exception ex) {
                if (conn != null &&
                    conn.State == ConnectionState.Open)
                {
                    try {
                        sqlTrans.Rollback();
                    } catch {
                        TShock.Log.ConsoleError(" seconomy mysql: error in rollback:" + ex.ToString());
                    }
                }
                TShock.Log.ConsoleError(" seconomy mysql: database error in transfer:" + ex.ToString());
                args.Exception = ex;
                return(args);
            } finally {
                if (conn != null)
                {
                    conn.Dispose();
                }
            }

            FromAccount.SyncBalance();
            ToAccount.SyncBalance();

            args.TransferSucceeded = true;
            if (BankTransferCompleted != null)
            {
                BankTransferCompleted(this, args);
            }

            if (SEconomyInstance.Configuration.EnableProfiler == true)
            {
                sw.Stop();
                TShock.Log.ConsoleInfo("seconomy mysql: transfer took {0} ms", sw.ElapsedMilliseconds);
            }

            return(args);
        }
コード例 #6
0
        /// <summary>
        /// Asynchronously transfers to another account.
        /// </summary>
        public Task <BankTransferEventArgs> TransferToAsync(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string Message = "")
        {
            Guid profile = SEconomyPlugin.Profiler.Enter(string.Format("transferAsync: {0} to {1}", this.UserAccountName, ToAccount.UserAccountName));

            return(Task.Factory.StartNew <BankTransferEventArgs>(() => {
                BankTransferEventArgs args = TransferTo(ToAccount, Amount, Options, UseProfiler: false, Message: Message);
                return args;
            }).ContinueWith((task) => {
                SEconomyPlugin.Profiler.ExitLog(profile);
                return task.Result;
            }));
        }
コード例 #7
0
        /// <summary>
        /// Transfers money from this account to the destination account, if negative, takes money from the destination account into this account.
        /// </summary>
        public BankTransferEventArgs TransferTo(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, bool UseProfiler = true, string Message = "")
        {
            lock (__tranlock) {
                BankTransferEventArgs args = new BankTransferEventArgs();
                Guid profile = Guid.Empty;

                if (UseProfiler)
                {
                    profile = SEconomyPlugin.Profiler.Enter(string.Format("transfer: {0} to {1}", this.UserAccountName, ToAccount.UserAccountName));
                }

                if (ToAccount != null && TransferMaySucceed(this, ToAccount, Amount, Options))
                {
                    args.Amount            = Amount;
                    args.SenderAccount     = this;
                    args.ReceiverAccount   = ToAccount;
                    args.TransferOptions   = Options;
                    args.TransferSucceeded = false;

                    //insert the source negative transaction
                    XTransaction sourceTran = BeginSourceTransaction(Amount, Message);
                    if (sourceTran != null && !string.IsNullOrEmpty(sourceTran.BankAccountTransactionK))
                    {
                        //insert the destination inverse transaction
                        XTransaction destTran = FinishEndTransaction(sourceTran.BankAccountTransactionK, ToAccount, Amount, Message);

                        if (destTran != null && !string.IsNullOrEmpty(destTran.BankAccountTransactionK))
                        {
                            //perform the double-entry binding
                            BindTransactions(ref sourceTran, ref destTran);

                            args.TransactionID = sourceTran.BankAccountTransactionK;

                            //update balances
                            this.Balance      += (Amount * (-1));
                            ToAccount.Balance += Amount;

                            //transaction complete
                            args.TransferSucceeded = true;
                        }
                    }
                }
                else
                {
                    args.TransferSucceeded = false;

                    if (!ToAccount.IsSystemAccount && !ToAccount.IsPluginAccount)
                    {
                        if (Amount < 0)
                        {
                            this.Owner.TSPlayer.SendErrorMessageFormat("Invalid amount.");
                        }
                        else
                        {
                            this.Owner.TSPlayer.SendErrorMessageFormat("You need {0} more money to make this payment.", ((Money)(this.Balance - Amount)).ToLongString());
                        }
                    }
                }

                //raise the transfer event
                OnBankTransferComplete(args);

                if (UseProfiler)
                {
                    SEconomyPlugin.Profiler.ExitLog(profile);
                }

                return(args);
            }
        }
コード例 #8
0
 public Task <BankTransferEventArgs> TransferBetweenAsync(IBankAccount FromAccount, IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
 {
     return(Task.Factory.StartNew(() => TransferBetween(FromAccount, ToAccount, Amount, Options, TransactionMessage, JournalMessage)));
 }
コード例 #9
0
ファイル: MySQLBankAccount.cs プロジェクト: GNR092/SEconomy
		public async Task<BankTransferEventArgs> TransferToAsync(IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
		{
			return await Task.Factory.StartNew(() => TransferTo(ToAccount, Amount, Options, TransactionMessage, JournalMessage));
		}
コード例 #10
0
ファイル: MySQLBankAccount.cs プロジェクト: GNR092/SEconomy
		public async Task<BankTransferEventArgs> TransferToAsync(int Index, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
		{
			IBankAccount account;

			if (SEconomyPlugin.Instance == null
			    || (account = SEconomyPlugin.Instance.GetBankAccount(Index)) == null) {
				return null;
			}

			return await Task.Factory.StartNew(() => TransferTo(account, Amount, Options, TransactionMessage, JournalMessage));
		}
コード例 #11
0
ファイル: MySQLBankAccount.cs プロジェクト: GNR092/SEconomy
		public BankTransferEventArgs TransferTo(IBankAccount Account, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
		{
			return journal.TransferBetween(this, Account, Amount, Options, TransactionMessage, JournalMessage);
		}
コード例 #12
0
 public PendingTransactionEventArgs(IBankAccount From, IBankAccount To, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string LogMessage) : base()
 {
     this.fromAccount        = From;
     this.toAccount          = To;
     this.Amount             = Amount;
     this.Options            = Options;
     this.TransactionMessage = TransactionMessage;
     this.JournalLogMessage  = LogMessage;
     this.IsCancelled        = false;
 }
コード例 #13
0
        public BankTransferEventArgs TransferBetween(IBankAccount FromAccount, IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
        {
            BankTransferEventArgs args = new BankTransferEventArgs();
            Guid profile = Guid.Empty;

            try {
                if (ToAccount != null && TransferMaySucceed(FromAccount, ToAccount, Amount, Options)) {
                    PendingTransactionEventArgs pendingTransaction = new PendingTransactionEventArgs(FromAccount, ToAccount, Amount, Options, TransactionMessage, JournalMessage);

                    if (BankTransactionPending != null) {
                        BankTransactionPending(this, pendingTransaction);
                    }

                    if (pendingTransaction == null) {
                        return args;
                    }

                    args.Amount = pendingTransaction.Amount;
                    args.SenderAccount = pendingTransaction.FromAccount;
                    args.ReceiverAccount = pendingTransaction.ToAccount;
                    args.TransferOptions = Options;
                    args.TransferSucceeded = false;
                    args.TransactionMessage = pendingTransaction.TransactionMessage;


                    if (pendingTransaction.IsCancelled) {
                        return args;
                    }

                    //insert the source negative transaction
                    ITransaction sourceTran = BeginSourceTransaction(FromAccount.BankAccountK, pendingTransaction.Amount, pendingTransaction.JournalLogMessage);
                    if (sourceTran != null) {
                        //insert the destination inverse transaction
                        ITransaction destTran = FinishEndTransaction(sourceTran.BankAccountTransactionK, ToAccount, pendingTransaction.Amount, pendingTransaction.JournalLogMessage);

                        if (destTran != null) {
                            //perform the double-entry binding
                            BindTransactions(ref sourceTran, ref destTran);

                            args.TransactionID = sourceTran.BankAccountTransactionK;

                            //update balances
                            FromAccount.Balance += (Amount * (-1));
                            ToAccount.Balance += Amount;

                            //transaction complete
                            args.TransferSucceeded = true;
                        }
                    }
                } else {
                    args.TransferSucceeded = false;
                    TSPlayer from;

                    if ((from = TShockAPI.TShock.Players.FirstOrDefault(i => i.UserAccountName == FromAccount.UserAccountName)) == null) {
                        return args;
                    }


                    /*
                     * concept: ??????
                     * if the amount coming from "this" account is a negative then the "sender account" needs to know the transfer failed.
                     * if the amount coming from "this" acount is a positive then the "reciever account" needs to know the transfer failed.
                     */
                    if (ToAccount.IsSystemAccount == false && ToAccount.IsPluginAccount == false) {
                        if (Amount < 0) {
                            from.SendErrorMessage(SEconomyPlugin.Locale.StringOrDefault(83, "Invalid amount."));
                        } else {
                            from.SendErrorMessage(SEconomyPlugin.Locale.StringOrDefault(84, "You need {0} more to make this payment."), ((Money)(FromAccount.Balance - Amount)).ToLongString());
                        }
                    }
                }
            } catch (Exception ex) {
                args.Exception = ex;
                args.TransferSucceeded = false;
            }

            if (BankTransferCompleted != null) {
                BankTransferCompleted(this, args);
            }

            return args;
        }
コード例 #14
0
        /// <summary>
        /// Asynchronously transfers to another account.
        /// </summary>
        public Task<BankTransferEventArgs> TransferToAsync(int Index, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage) {
            Economy.EconomyPlayer ePlayer = SEconomyPlugin.GetEconomyPlayerSafe(Index);

            Guid profile = SEconomyPlugin.Profiler.Enter(string.Format("transferAsync: {0} to {1}", this.UserAccountName, ePlayer.BankAccount != null ? ePlayer.BankAccount.UserAccountName : "Unknown"));
            return Task.Factory.StartNew<BankTransferEventArgs>(() => {
                BankTransferEventArgs args = TransferTo(ePlayer.BankAccount, Amount, Options, TransactionMessage, JournalMessage);
                return args;
            }).ContinueWith((task) => {
                SEconomyPlugin.Profiler.ExitLog(profile);
                return task.Result;
            });
        }
コード例 #15
0
        public async Task <BankTransferEventArgs> TransferToAsync(int Index, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
        {
            IBankAccount account;

            if (SEconomyPlugin.Instance == null ||
                (account = SEconomyPlugin.Instance.GetBankAccount(Index)) == null)
            {
                return(null);
            }

            return(await Task.Factory.StartNew(() => TransferTo(account, Amount, Options, TransactionMessage, JournalMessage)));
        }
コード例 #16
0
		public BankTransferEventArgs TransferBetween(IBankAccount FromAccount, IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
		{
			long accountCount = -1;
			PendingTransactionEventArgs pendingTransaction = new PendingTransactionEventArgs(FromAccount, ToAccount, Amount, Options, TransactionMessage, JournalMessage);
			ITransaction sourceTran, destTran;
			MySqlConnection conn = null;
			MySqlTransaction sqlTrans = null;
			BankTransferEventArgs args = new BankTransferEventArgs() {
				TransferSucceeded = false
			};
			string accountVerifyQuery = @"select count(*)
										  from `bank_account`
										  where	`bank_account_id` = @0;";

			Stopwatch sw = new Stopwatch();
			if (SEconomyInstance.Configuration.EnableProfiler == true) {
				sw.Start();
			}
			if (ToAccount == null 
                || TransferMaySucceed(FromAccount, ToAccount, Amount, Options) == false) {
				return args;
			}

			if ((conn = Connection) == null) {
				TShock.Log.ConsoleError(" seconomy mysql: Cannot connect to the SQL server");
				return args;
			}

			conn.Open();

			if ((accountCount = Connection.QueryScalar<long>(accountVerifyQuery, FromAccount.BankAccountK)) != 1) {
				TShock.Log.ConsoleError(" seconomy mysql: Source account " + FromAccount.BankAccountK + " does not exist.");
				conn.Dispose();
				return args;
			}

			if ((accountCount = Connection.QueryScalar<long>(accountVerifyQuery, ToAccount.BankAccountK)) != 1) {
				TShock.Log.ConsoleError(" seconomy mysql: Source account " + FromAccount.BankAccountK + " does not exist.");
				conn.Dispose();
				return args;
			}

			if (BankTransactionPending != null) {
				BankTransactionPending(this, pendingTransaction);
			}

			if (pendingTransaction == null 
                || pendingTransaction.IsCancelled == true) {
				return args;
			}

			args.Amount = pendingTransaction.Amount;
			args.SenderAccount = pendingTransaction.FromAccount;
			args.ReceiverAccount = pendingTransaction.ToAccount;
			args.TransferOptions = Options;
			args.TransactionMessage = pendingTransaction.TransactionMessage;

			try {
				sqlTrans = conn.BeginTransaction();
				if ((sourceTran = BeginSourceTransaction(sqlTrans, FromAccount.BankAccountK, pendingTransaction.Amount, pendingTransaction.JournalLogMessage)) == null) {
					throw new Exception("BeginSourceTransaction failed");
				}

				if ((destTran = FinishEndTransaction(sqlTrans, ToAccount, pendingTransaction.Amount, pendingTransaction.JournalLogMessage)) == null) {
					throw new Exception("FinishEndTransaction failed");
				}

				BindTransactions(sqlTrans, sourceTran.BankAccountTransactionK, destTran.BankAccountTransactionK);
				sqlTrans.Commit();
			} catch (Exception ex) {
				if (conn != null
				    && conn.State == ConnectionState.Open) {
					try {
						sqlTrans.Rollback();
					} catch {
						TShock.Log.ConsoleError(" seconomy mysql: error in rollback:" + ex.ToString());
					}
				}
				TShock.Log.ConsoleError(" seconomy mysql: database error in transfer:" + ex.ToString());
				args.Exception = ex;
				return args;
			} finally {
				if (conn != null) {
					conn.Dispose();
				}
			}
			
			FromAccount.SyncBalance();
			ToAccount.SyncBalance();

			args.TransferSucceeded = true;
			if (BankTransferCompleted != null) {
				BankTransferCompleted(this, args);
			}

			if (SEconomyInstance.Configuration.EnableProfiler == true) {
				sw.Stop();
				TShock.Log.ConsoleInfo("seconomy mysql: transfer took {0} ms", sw.ElapsedMilliseconds);
			}

			return args;
		}
コード例 #17
0
 public async Task <BankTransferEventArgs> TransferToAsync(IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
 {
     return(await Task.Factory.StartNew(() => TransferTo(ToAccount, Amount, Options, TransactionMessage, JournalMessage)));
 }
コード例 #18
0
		public async Task<BankTransferEventArgs> TransferBetweenAsync(IBankAccount FromAccount, IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
		{
			return await Task.Run(() => TransferBetween(FromAccount, ToAccount, Amount, Options, TransactionMessage, JournalMessage));
		}
コード例 #19
0
        public BankTransferEventArgs TransferBetween(IBankAccount FromAccount, IBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage)
        {
            BankTransferEventArgs args = new BankTransferEventArgs();
            Guid profile = Guid.Empty;

            try {
                if (ToAccount != null && TransferMaySucceed(FromAccount, ToAccount, Amount, Options))
                {
                    PendingTransactionEventArgs pendingTransaction = new PendingTransactionEventArgs(FromAccount, ToAccount, Amount, Options, TransactionMessage, JournalMessage);

                    if (BankTransactionPending != null)
                    {
                        BankTransactionPending(this, pendingTransaction);
                    }

                    if (pendingTransaction == null)
                    {
                        return(args);
                    }

                    args.Amount             = pendingTransaction.Amount;
                    args.SenderAccount      = pendingTransaction.FromAccount;
                    args.ReceiverAccount    = pendingTransaction.ToAccount;
                    args.TransferOptions    = Options;
                    args.TransferSucceeded  = false;
                    args.TransactionMessage = pendingTransaction.TransactionMessage;


                    if (pendingTransaction.IsCancelled)
                    {
                        return(args);
                    }

                    //insert the source negative transaction
                    ITransaction sourceTran = BeginSourceTransaction(FromAccount.BankAccountK, pendingTransaction.Amount, pendingTransaction.JournalLogMessage);
                    if (sourceTran != null)
                    {
                        //insert the destination inverse transaction
                        ITransaction destTran = FinishEndTransaction(sourceTran.BankAccountTransactionK, ToAccount, pendingTransaction.Amount, pendingTransaction.JournalLogMessage);

                        if (destTran != null)
                        {
                            //perform the double-entry binding
                            BindTransactions(ref sourceTran, ref destTran);

                            args.TransactionID = sourceTran.BankAccountTransactionK;

                            //update balances
                            FromAccount.Balance += (Amount * (-1));
                            ToAccount.Balance   += Amount;

                            //transaction complete
                            args.TransferSucceeded = true;
                        }
                    }
                }
                else
                {
                    args.TransferSucceeded = false;
                    TSPlayer from;

                    if ((from = TShockAPI.TShock.Players.FirstOrDefault(i => i.Name == FromAccount.UserAccountName)) == null)
                    {
                        return(args);
                    }


                    /*
                     * concept: ??????
                     * if the amount coming from "this" account is a negative then the "sender account" needs to know the transfer failed.
                     * if the amount coming from "this" acount is a positive then the "reciever account" needs to know the transfer failed.
                     */
                    if (ToAccount.IsSystemAccount == false && ToAccount.IsPluginAccount == false)
                    {
                        if (Amount < 0)
                        {
                            from.SendErrorMessage(SEconomyPlugin.Locale.StringOrDefault(83, "Invalid amount."));
                        }
                        else
                        {
                            from.SendErrorMessage(SEconomyPlugin.Locale.StringOrDefault(84, "You need {0} more to make this payment."), ((Money)(FromAccount.Balance - Amount)).ToLongString());
                        }
                    }
                }
            } catch (Exception ex) {
                args.Exception         = ex;
                args.TransferSucceeded = false;
            }

            if (BankTransferCompleted != null)
            {
                BankTransferCompleted(this, args);
            }

            return(args);
        }
コード例 #20
0
        /// <summary>
        /// Transfers money from this account to the destination account, if negative, takes money from the destination account into this account.
        /// </summary>
        public BankTransferEventArgs TransferTo(XBankAccount ToAccount, Money Amount, BankAccountTransferOptions Options, string TransactionMessage, string JournalMessage) {
            BankTransferEventArgs args = new BankTransferEventArgs();
            Guid profile = Guid.Empty;

            try {
                lock (__tranlock) {
                  
                    if (ToAccount != null) {
                        if (TransferMaySucceed(this, ToAccount, Amount, Options)) {
                            if (SEconomyPlugin.Configuration.EnableProfiler) {
                                profile = SEconomyPlugin.Profiler.Enter(string.Format("transfer: {0} to {1}", !string.IsNullOrEmpty(this.UserAccountName) ? this.UserAccountName : "Unknown", ToAccount != null && !string.IsNullOrEmpty(ToAccount.UserAccountName) ? ToAccount.UserAccountName : "Unknown"));
                            }
                            args.Amount = Amount;
                            args.SenderAccount = this;
                            args.ReceiverAccount = ToAccount;
                            args.TransferOptions = Options;
                            args.TransferSucceeded = false;
                            args.TransactionMessage = TransactionMessage;

                            //insert the source negative transaction
                            XTransaction sourceTran = BeginSourceTransaction(Amount, JournalMessage);
                            if (sourceTran != null && !string.IsNullOrEmpty(sourceTran.BankAccountTransactionK)) {
                                //insert the destination inverse transaction
                                XTransaction destTran = FinishEndTransaction(sourceTran.BankAccountTransactionK, ToAccount, Amount, JournalMessage);

                                if (destTran != null && !string.IsNullOrEmpty(destTran.BankAccountTransactionK)) {
                                    //perform the double-entry binding
                                    BindTransactions(ref sourceTran, ref destTran);

                                    args.TransactionID = sourceTran.BankAccountTransactionK;

                                    //update balances
                                    this.Balance += (Amount * (-1));
                                    ToAccount.Balance += Amount;

                                    //transaction complete
                                    args.TransferSucceeded = true;
                                }
                            }
                        } else {
                            args.TransferSucceeded = false;

                            //concept: ??????
                            //if the amount coming from "this" account is a negative then the "sender account" needs to know the transfer failed.
                            //if the amount coming from "this" acount is a positive then the "reciever account" needs to know the transfer failed.

                            if (!ToAccount.IsSystemAccount && !ToAccount.IsPluginAccount) {
                                if (this.Owner != null) {
                                    if (Amount < 0) {
                                        this.Owner.TSPlayer.SendErrorMessageFormat("Invalid amount.");
                                    } else {
                                        this.Owner.TSPlayer.SendErrorMessageFormat("You need {0} more money to make this payment.", ((Money)(this.Balance - Amount)).ToLongString());
                                    }
                                }
                            }
                        }
                    }

                    //raise the transfer event
                    OnBankTransferComplete(args);

                    if (SEconomyPlugin.Configuration.EnableProfiler) {
                        SEconomyPlugin.Profiler.ExitLog(profile);
                    }
                }

            } catch (Exception ex) {
                args.Exception = ex;
                args.TransferSucceeded = false;
            }

            return args;
        }