Inheritance: ITransaction
Example #1
0
        ITransaction BeginSourceTransaction(long BankAccountK, Money Amount, string Message)
        {
            IBankAccount bankAccount = GetBankAccount(BankAccountK);
            ITransaction sourceTran  = new XmlTransaction(bankAccount);

            sourceTran.Flags = Journal.BankAccountTransactionFlags.FundsAvailable;
            sourceTran.TransactionDateUtc = DateTime.UtcNow;
            sourceTran.Amount             = (Amount * (-1));

            if (!string.IsNullOrEmpty(Message))
            {
                sourceTran.Message = Message;
            }

            return(bankAccount.AddTransaction(sourceTran));
        }
Example #2
0
        ITransaction FinishEndTransaction(long SourceBankTransactionKey, IBankAccount ToAccount, Money Amount, string Message)
        {
            ITransaction destTran = new XmlTransaction(ToAccount);

            destTran.BankAccountFK            = ToAccount.BankAccountK;
            destTran.Flags                    = Journal.BankAccountTransactionFlags.FundsAvailable;
            destTran.TransactionDateUtc       = DateTime.UtcNow;
            destTran.Amount                   = Amount;
            destTran.BankAccountTransactionFK = SourceBankTransactionKey;

            if (!string.IsNullOrEmpty(Message))
            {
                destTran.Message = Message;
            }

            return(ToAccount.AddTransaction(destTran));
        }
Example #3
0
        public async Task SquashJournalAsync()
        {
            int  bankAccountCount = BankAccounts.Count();
            bool responsibleForTurningBackupsBackOn = false;

            Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(81, "seconomy xml: beginning Squash"));

            if (SEconomyInstance.RunningJournal.BackupsEnabled == true)
            {
                SEconomyInstance.RunningJournal.BackupsEnabled = false;
                responsibleForTurningBackupsBackOn             = true;
            }

            for (int i = 0; i < bankAccountCount; i++)
            {
                IBankAccount account = BankAccounts.ElementAtOrDefault(i);
                if (account == null)
                {
                    continue;
                }

                // Add the squished summary
                ITransaction squash = new XmlTransaction(account)
                {
                    Amount             = account.Transactions.Sum(x => x.Amount),
                    Flags              = BankAccountTransactionFlags.FundsAvailable | BankAccountTransactionFlags.Squashed,
                    TransactionDateUtc = DateTime.UtcNow,
                    Message            = "Transaction squash"
                };

                account.Transactions.Clear();
                account.AddTransaction(squash);
            }

            //abandon the old journal and assign the squashed one
            Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(82, "re-syncing online accounts."));

            foreach (TSPlayer player in TShockAPI.TShock.Players)
            {
                IBankAccount account = null;
                if (player == null ||
                    SEconomyPlugin.Instance == null ||
                    (account = SEconomyPlugin.Instance.GetBankAccount(player)) == null)
                {
                    return;
                }
                Console.WriteLine("re-syncing {0}", player.Name);
                await account.SyncBalanceAsync();
            }

            await SaveJournalAsync();

            if (responsibleForTurningBackupsBackOn)
            {
                /*
                 * the backups could already have been disabled by something else.
                 * We don't want to be the ones turning it back on
                 */
                SEconomyInstance.RunningJournal.BackupsEnabled = true;
            }
        }
Example #4
0
        public bool LoadJournal()
        {
            MemoryStream uncompressedData;
            JournalLoadingPercentChangedEventArgs parsingArgs = new JournalLoadingPercentChangedEventArgs()
            {
                Label = "Loading"
            };
            JournalLoadingPercentChangedEventArgs finalArgs = new JournalLoadingPercentChangedEventArgs()
            {
                Label = "Verify"
            };

            ConsoleEx.WriteLineColour(ConsoleColor.Cyan, " Using XML journal - {0}", path);

            try {
                byte[] fileData = new byte[0];
initPoint:
                try {
                    fileData = File.ReadAllBytes(path);
                } catch (Exception ex) {
                    Console.ForegroundColor = ConsoleColor.DarkCyan;

                    if (ex is System.IO.FileNotFoundException || ex is System.IO.DirectoryNotFoundException)
                    {
                        TShock.Log.ConsoleInfo(" * It appears you do not have a journal yet, one will be created for you.");
                        SaveJournal();
                        //yes there are valid uses for goto, don't judge me fool
                        goto initPoint;
                    }
                    else if (ex is System.Security.SecurityException)
                    {
                        TShock.Log.ConsoleError(" * Access denied to the journal file.  Check permissions.");
                    }
                    else
                    {
                        TShock.Log.ConsoleError(" * Loading your journal failed: " + ex.Message);
                    }
                }

                try {
                    uncompressedData = GZipDecompress(fileData);
                } catch {
                    TShock.Log.ConsoleError(" * Decompression failed.");
                    return(false);
                }

                if (JournalLoadingPercentChanged != null)
                {
                    JournalLoadingPercentChanged(this, parsingArgs);
                }

                try {
                    Hashtable bankAccountMap = new Hashtable();
                    Hashtable transactionMap = new Hashtable();

                    //You can't use XDocument.Parse when you have an XDeclaration for some even dumber reason than the write
                    //issue, XDocument has to be constructed from a .net 3.5 XmlReader in this case
                    //or you get a parse exception complaining about literal content.
                    using (XmlTextReader xmlStream = new XmlTextReader(uncompressedData)) {
                        XDocument doc              = XDocument.Load(xmlStream);
                        var       bankAccountList  = doc.XPathSelectElements("/Journal/BankAccounts/BankAccount");
                        int       bankAccountCount = bankAccountList.Count();
                        int       i          = 0;
                        int       oldPercent = 0;

                        foreach (XElement elem in bankAccountList)
                        {
                            long   bankAccountK    = 0L;
                            double percentComplete = (double)i / (double)bankAccountCount * 100;

                            var account = new XmlBankAccount(this)
                            {
                                Description     = elem.Attribute("Description").Value,
                                UserAccountName = elem.Attribute("UserAccountName").Value,
                                WorldID         = long.Parse(elem.Attribute("WorldID").Value),
                                Flags           = (BankAccountFlags)Enum.Parse(typeof(BankAccountFlags), elem.Attribute("Flags").Value)
                            };

                            if (!long.TryParse(elem.Attribute("BankAccountK").Value, out bankAccountK))
                            {
                                //we've overwritten the old bank account key, add it to the old/new map
                                bankAccountK = Interlocked.Increment(ref _bankAccountSeed);
                                bankAccountMap.Add(elem.Attribute("BankAccountK").Value, bankAccountK);
                            }

                            account.BankAccountK = bankAccountK;

                            //parse transactions under this node
                            if (elem.Element("Transactions") != null)
                            {
                                foreach (XElement txElement in elem.Element("Transactions").Elements("Transaction"))
                                {
                                    long     transactionK  = 0L;
                                    long     transactionFK = 0;
                                    long     amount        = long.Parse(txElement.Attribute("Amount").Value);
                                    DateTime transactionDate;
                                    BankAccountTransactionFlags flags;

                                    long.TryParse(txElement.Attribute("BankAccountTransactionK").Value, out transactionK);
                                    long.TryParse(txElement.Attribute("BankAccountTransactionFK").Value, out transactionFK);
                                    DateTime.TryParse(txElement.Attribute("TransactionDateUtc").Value, out transactionDate);
                                    Enum.TryParse <BankAccountTransactionFlags>(txElement.Attribute("Flags").Value, out flags);

                                    //ignore orphaned transactions
                                    var trans = new XmlTransaction(account)
                                    {
                                        Amount = amount,
                                        BankAccountTransactionK  = transactionK,
                                        BankAccountTransactionFK = transactionFK,
                                        TransactionDateUtc       = transactionDate,
                                        Flags = flags
                                    };

                                    trans.Message = txElement.Attribute("Message") != null?txElement.Attribute("Message").Value : null;

                                    account.AddTransaction(trans);
                                }
                            }

                            account.SyncBalance();

                            if (oldPercent != (int)percentComplete)
                            {
                                parsingArgs.Percent = (int)percentComplete;
                                if (JournalLoadingPercentChanged != null)
                                {
                                    JournalLoadingPercentChanged(this, parsingArgs);
                                }
                                oldPercent = (int)percentComplete;
                            }

                            Interlocked.Increment(ref i);

                            bankAccounts.Add(account);
                        }

                        Interlocked.Exchange(ref _bankAccountSeed, bankAccounts.Count() > 0 ? bankAccounts.Max(sum => sum.BankAccountK) : 0);

                        //delete transactions with duplicate IDs

                        var qAccounts = from summary in bankAccounts
                                        group summary by summary.BankAccountK into g
                                        where g.Count() > 1
                                        select new {
                            name  = g.Key,
                            count = g.Count()
                        };

                        long[] duplicateAccounts = qAccounts.Select(pred => pred.name).ToArray();

                        int removedAccounts = bankAccounts.RemoveAll(pred => duplicateAccounts.Contains(pred.BankAccountK));

                        if (removedAccounts > 0)
                        {
                            TShock.Log.Warn("seconomy journal: removed " + removedAccounts + " accounts with duplicate IDs.");
                        }

                        //transactions in the old schema.
                        int tranCount = doc.XPathSelectElements("/Journal/Transactions/Transaction").Count();
                        i = 0; //reset index

                        foreach (XElement elem in doc.XPathSelectElements("/Journal/Transactions/Transaction"))
                        {
                            //Parallel.ForEach(doc.XPathSelectElements("/Journal/Transactions/Transaction"), (elem) => {
                            double percentComplete = (double)i / (double)tranCount * 100;
                            long   bankAccountFK   = 0L;
                            long   transactionK    = 0L;
                            long   amount          = long.Parse(elem.Attribute("Amount").Value);

                            if (!long.TryParse(elem.Attribute("BankAccountFK").Value, out bankAccountFK))
                            {
                                if (bankAccountMap.ContainsKey(elem.Attribute("BankAccountFK").Value))
                                {
                                    Interlocked.Exchange(ref bankAccountFK, (long)bankAccountMap[elem.Attribute("BankAccountFK").Value]);
                                }
                            }

                            IBankAccount bankAccount = GetBankAccount(bankAccountFK);


                            long.TryParse(elem.Attribute("BankAccountTransactionK").Value, out transactionK);

                            //ignore orphaned transactions
                            if (bankAccount != null)
                            {
                                var trans = new XmlTransaction(bankAccount)
                                {
                                    Amount = amount,
                                    BankAccountTransactionK = transactionK
                                };

                                if (elem.Attribute("BankAccountTransactionFK") != null)
                                {
                                    trans.CustomValues.Add(XmlTransaction.kXmlTransactionOldTransactonFK, elem.Attribute("BankAccountTransactionFK").Value);
                                }

                                trans.Message = elem.Attribute("Message") != null?elem.Attribute("Message").Value : null;

                                bankAccount.AddTransaction(trans);

                                transactionMap.Add(elem.Attribute("BankAccountTransactionK").Value, trans.BankAccountTransactionK);
                            }

                            Interlocked.Increment(ref i);
                        }

                        int txCount = Transactions.Count();
                        int x       = 0;

                        finalArgs.Percent = 0;

                        if (JournalLoadingPercentChanged != null)
                        {
                            JournalLoadingPercentChanged(this, finalArgs);
                        }

                        foreach (IBankAccount account in bankAccounts)
                        {
                            foreach (XmlTransaction trans in account.Transactions)
                            {
                                double pcc = (double)x / (double)txCount * 100;

                                //assigns the transactionK according to the hashmap of the old key stored as custom values
                                if (trans.CustomValues.ContainsKey(XmlTransaction.kXmlTransactionOldTransactonFK))
                                {
                                    object value = transactionMap[trans.CustomValues[XmlTransaction.kXmlTransactionOldTransactonFK]];

                                    trans.BankAccountTransactionFK = value != null ? (long)value : -1L;
                                }
                                if (oldPercent != (int)pcc)
                                {
                                    if (JournalLoadingPercentChanged != null)
                                    {
                                        finalArgs.Percent = (int)pcc;
                                        JournalLoadingPercentChanged(this, finalArgs);
                                        oldPercent = (int)pcc;
                                    }
                                }
                                Interlocked.Increment(ref x);

                                trans.CustomValues.Clear();
                                trans.CustomValues = null;
                            }
                        }

                        bankAccountMap = null;
                        transactionMap = null;

                        // CleanJournal(PurgeOptions.RemoveOrphanedAccounts | PurgeOptions.RemoveZeroBalanceAccounts);

                        var accountCount = bankAccounts.Count;
                        Console.WriteLine();
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        Console.WriteLine("\r\n Journal clean: {0} accounts and {1} transactions.", accountCount, Transactions.Count());
                        Console.ResetColor();
                    }
                } catch (Exception ex) {
                    ConsoleEx.WriteAtEnd(2, ConsoleColor.Red, "[{0}]\r\n", SEconomyPlugin.Locale.StringOrDefault(79, "corrupt"));
                    TShock.Log.ConsoleError(ex.ToString());
                    Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(80, "Your transaction journal appears to be corrupt and transactions have been lost.\n\nYou will start with a clean journal.\nYour old journal file has been move to SEconomy.journal.xml.gz.corrupt"));
                    File.Move(path, path + "." + DateTime.Now.ToFileTime().ToString() + ".corrupt");

                    SaveJournal();

                    //yes there are valid uses for goto, don't judge me fool
                    goto initPoint;
                }
            } finally {
                Console.WriteLine();
            }

            return(true);
        }
Example #5
0
        ITransaction FinishEndTransaction(long SourceBankTransactionKey, IBankAccount ToAccount, Money Amount, string Message)
        {
            ITransaction destTran = new XmlTransaction(ToAccount);

            destTran.BankAccountFK = ToAccount.BankAccountK;
            destTran.Flags = Journal.BankAccountTransactionFlags.FundsAvailable;
            destTran.TransactionDateUtc = DateTime.UtcNow;
            destTran.Amount = Amount;
            destTran.BankAccountTransactionFK = SourceBankTransactionKey;

            if (!string.IsNullOrEmpty(Message)) {
                destTran.Message = Message;
            }

            return ToAccount.AddTransaction(destTran);
        }
Example #6
0
        ITransaction BeginSourceTransaction(long BankAccountK, Money Amount, string Message)
        {
            IBankAccount bankAccount = GetBankAccount(BankAccountK);
            ITransaction sourceTran = new XmlTransaction(bankAccount);

            sourceTran.Flags = Journal.BankAccountTransactionFlags.FundsAvailable;
            sourceTran.TransactionDateUtc = DateTime.UtcNow;
            sourceTran.Amount = (Amount * (-1));

            if (!string.IsNullOrEmpty(Message)) {
                sourceTran.Message = Message;
            }

            return bankAccount.AddTransaction(sourceTran);
        }
Example #7
0
        public async Task SquashJournalAsync()
        {
            int bankAccountCount = BankAccounts.Count();
            bool responsibleForTurningBackupsBackOn = false;

            Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(81, "seconomy xml: beginning Squash"));

            if (SEconomyInstance.RunningJournal.BackupsEnabled == true) {
                SEconomyInstance.RunningJournal.BackupsEnabled = false;
                responsibleForTurningBackupsBackOn = true;
            }

            for (int i = 0; i < bankAccountCount; i++) {
                IBankAccount account = BankAccounts.ElementAtOrDefault(i);
                if (account == null) {
                    continue;
                }

                // Add the squished summary
                ITransaction squash = new XmlTransaction(account) {
                    Amount = account.Transactions.Sum(x => x.Amount),
                    Flags = BankAccountTransactionFlags.FundsAvailable | BankAccountTransactionFlags.Squashed,
                    TransactionDateUtc = DateTime.UtcNow,
                    Message = "Transaction squash"
                };

                account.Transactions.Clear();
                account.AddTransaction(squash);
            }

            //abandon the old journal and assign the squashed one
            Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(82, "re-syncing online accounts."));

            foreach (TSPlayer player in TShockAPI.TShock.Players) {
                IBankAccount account = null;
                if (player == null
                    || SEconomyPlugin.Instance == null
                    || (account = SEconomyPlugin.Instance.GetBankAccount(player)) == null) {
                    return;
                }
                Console.WriteLine("re-syncing {0}", player.Name);
                await account.SyncBalanceAsync();
            }

            await SaveJournalAsync();
            if (responsibleForTurningBackupsBackOn) {
                /* 
                 * the backups could already have been disabled by something else.  
                 * We don't want to be the ones turning it back on
                 */
                SEconomyInstance.RunningJournal.BackupsEnabled = true;
            }
        }
Example #8
0
        public bool LoadJournal()
        {
            MemoryStream uncompressedData;
            JournalLoadingPercentChangedEventArgs parsingArgs = new JournalLoadingPercentChangedEventArgs() {
                Label = "Loading"
            };
            JournalLoadingPercentChangedEventArgs finalArgs = new JournalLoadingPercentChangedEventArgs() {
                Label = "Verify"
            };

            ConsoleEx.WriteLineColour(ConsoleColor.Cyan, " Using XML journal - {0}", path);

            try {
                byte[] fileData = new byte[0];
            initPoint:
                try {
                    fileData = File.ReadAllBytes(path);
                } catch (Exception ex) {
                    Console.ForegroundColor = ConsoleColor.DarkCyan;

                    if (ex is System.IO.FileNotFoundException || ex is System.IO.DirectoryNotFoundException) {
                        TShock.Log.ConsoleInfo(" * It appears you do not have a journal yet, one will be created for you.");
                        SaveJournal();
                        //yes there are valid uses for goto, don't judge me fool
                        goto initPoint;
                    } else if (ex is System.Security.SecurityException) {
                        TShock.Log.ConsoleError(" * Access denied to the journal file.  Check permissions.");
                    } else {
                        TShock.Log.ConsoleError(" * Loading your journal failed: " + ex.Message);
                    }
                }

                try {
                    uncompressedData = GZipDecompress(fileData);
                } catch {
                    TShock.Log.ConsoleError(" * Decompression failed.");
                    return false;
                }

                if (JournalLoadingPercentChanged != null) {
                    JournalLoadingPercentChanged(this, parsingArgs);
                }

                try {
                    Hashtable bankAccountMap = new Hashtable();
                    Hashtable transactionMap = new Hashtable();

                    //You can't use XDocument.Parse when you have an XDeclaration for some even dumber reason than the write
                    //issue, XDocument has to be constructed from a .net 3.5 XmlReader in this case
                    //or you get a parse exception complaining about literal content.
                    using (XmlTextReader xmlStream = new XmlTextReader(uncompressedData)) {
                        XDocument doc = XDocument.Load(xmlStream);
                        var bankAccountList = doc.XPathSelectElements("/Journal/BankAccounts/BankAccount");
                        int bankAccountCount = bankAccountList.Count();
                        int i = 0;
                        int oldPercent = 0;

                        foreach (XElement elem in bankAccountList) {
                            long bankAccountK = 0L;
                            double percentComplete = (double)i / (double)bankAccountCount * 100;

                            var account = new XmlBankAccount(this) {
                                Description = elem.Attribute("Description").Value,
                                UserAccountName = elem.Attribute("UserAccountName").Value,
                                WorldID = long.Parse(elem.Attribute("WorldID").Value),
                                Flags = (BankAccountFlags)Enum.Parse(typeof(BankAccountFlags), elem.Attribute("Flags").Value)
                            };

                            if (!long.TryParse(elem.Attribute("BankAccountK").Value, out bankAccountK)) {
                                //we've overwritten the old bank account key, add it to the old/new map
                                bankAccountK = Interlocked.Increment(ref _bankAccountSeed);
                                bankAccountMap.Add(elem.Attribute("BankAccountK").Value, bankAccountK);
                            }

                            account.BankAccountK = bankAccountK;

                            //parse transactions under this node
                            if (elem.Element("Transactions") != null) {
                                foreach (XElement txElement in elem.Element("Transactions").Elements("Transaction")) {
                                    long transactionK = 0L;
                                    long transactionFK = 0;
                                    long amount = long.Parse(txElement.Attribute("Amount").Value);
                                    DateTime transactionDate;
                                    BankAccountTransactionFlags flags;

                                    long.TryParse(txElement.Attribute("BankAccountTransactionK").Value, out transactionK);
                                    long.TryParse(txElement.Attribute("BankAccountTransactionFK").Value, out transactionFK);
                                    DateTime.TryParse(txElement.Attribute("TransactionDateUtc").Value, out transactionDate);
                                    Enum.TryParse<BankAccountTransactionFlags>(txElement.Attribute("Flags").Value, out flags);

                                    //ignore orphaned transactions
                                    var trans = new XmlTransaction(account) {
                                        Amount = amount,
                                        BankAccountTransactionK = transactionK,
                                        BankAccountTransactionFK = transactionFK,
                                        TransactionDateUtc = transactionDate,
                                        Flags = flags
                                    };

                                    trans.Message = txElement.Attribute("Message") != null ? txElement.Attribute("Message").Value : null;

                                    account.AddTransaction(trans);
                                }
                            }

                            account.SyncBalance();

                            if (oldPercent != (int)percentComplete) {
                                parsingArgs.Percent = (int)percentComplete;
                                if (JournalLoadingPercentChanged != null) {
                                    JournalLoadingPercentChanged(this, parsingArgs);
                                }
                                oldPercent = (int)percentComplete;
                            }

                            Interlocked.Increment(ref i);

                            bankAccounts.Add(account);
                        }

                        Interlocked.Exchange(ref _bankAccountSeed, bankAccounts.Count() > 0 ? bankAccounts.Max(sum => sum.BankAccountK) : 0);

                        //delete transactions with duplicate IDs

                        var qAccounts = from summary in bankAccounts
                                        group summary by summary.BankAccountK into g
                                        where g.Count() > 1
                                        select new {
                                            name = g.Key,
                                            count = g.Count()
                                        };

                        long[] duplicateAccounts = qAccounts.Select(pred => pred.name).ToArray();

                        int removedAccounts = bankAccounts.RemoveAll(pred => duplicateAccounts.Contains(pred.BankAccountK));

                        if (removedAccounts > 0) {
                            TShock.Log.Warn("seconomy journal: removed " + removedAccounts + " accounts with duplicate IDs.");
                        }

                        //transactions in the old schema.
                        int tranCount = doc.XPathSelectElements("/Journal/Transactions/Transaction").Count();
                        i = 0; //reset index

                        foreach (XElement elem in doc.XPathSelectElements("/Journal/Transactions/Transaction")) {
                            //Parallel.ForEach(doc.XPathSelectElements("/Journal/Transactions/Transaction"), (elem) => {
                            double percentComplete = (double)i / (double)tranCount * 100;
                            long bankAccountFK = 0L;
                            long transactionK = 0L;
                            long amount = long.Parse(elem.Attribute("Amount").Value);

                            if (!long.TryParse(elem.Attribute("BankAccountFK").Value, out bankAccountFK)) {
                                if (bankAccountMap.ContainsKey(elem.Attribute("BankAccountFK").Value)) {
                                    Interlocked.Exchange(ref bankAccountFK, (long)bankAccountMap[elem.Attribute("BankAccountFK").Value]);
                                }
                            }

                            IBankAccount bankAccount = GetBankAccount(bankAccountFK);


                            long.TryParse(elem.Attribute("BankAccountTransactionK").Value, out transactionK);

                            //ignore orphaned transactions
                            if (bankAccount != null) {
                                var trans = new XmlTransaction(bankAccount) {
                                    Amount = amount,
                                    BankAccountTransactionK = transactionK
                                };

                                if (elem.Attribute("BankAccountTransactionFK") != null) {
                                    trans.CustomValues.Add(XmlTransaction.kXmlTransactionOldTransactonFK, elem.Attribute("BankAccountTransactionFK").Value);
                                }

                                trans.Message = elem.Attribute("Message") != null ? elem.Attribute("Message").Value : null;

                                bankAccount.AddTransaction(trans);

                                transactionMap.Add(elem.Attribute("BankAccountTransactionK").Value, trans.BankAccountTransactionK);
                            }

                            Interlocked.Increment(ref i);
                        }

                        int txCount = Transactions.Count();
                        int x = 0;

                        finalArgs.Percent = 0;

                        if (JournalLoadingPercentChanged != null) {
                            JournalLoadingPercentChanged(this, finalArgs);
                        }

                        foreach (IBankAccount account in bankAccounts) {
                            foreach (XmlTransaction trans in account.Transactions) {
                                double pcc = (double)x / (double)txCount * 100;

                                //assigns the transactionK according to the hashmap of the old key stored as custom values
                                if (trans.CustomValues.ContainsKey(XmlTransaction.kXmlTransactionOldTransactonFK)) {
                                    object value = transactionMap[trans.CustomValues[XmlTransaction.kXmlTransactionOldTransactonFK]];

                                    trans.BankAccountTransactionFK = value != null ? (long)value : -1L;
                                }
                                if (oldPercent != (int)pcc) {
                                    if (JournalLoadingPercentChanged != null) {
                                        finalArgs.Percent = (int)pcc;
                                        JournalLoadingPercentChanged(this, finalArgs);
                                        oldPercent = (int)pcc;
                                    }
                                }
                                Interlocked.Increment(ref x);

                                trans.CustomValues.Clear();
                                trans.CustomValues = null;
                            }
                        }

                        bankAccountMap = null;
                        transactionMap = null;

                       // CleanJournal(PurgeOptions.RemoveOrphanedAccounts | PurgeOptions.RemoveZeroBalanceAccounts);

                        var accountCount = bankAccounts.Count;
                        Console.WriteLine();
                        Console.ForegroundColor = ConsoleColor.Cyan;
                        Console.WriteLine("\r\n Journal clean: {0} accounts and {1} transactions.", accountCount, Transactions.Count());
                        Console.ResetColor();
                    }
                } catch (Exception ex) {
                    ConsoleEx.WriteAtEnd(2, ConsoleColor.Red, "[{0}]\r\n", SEconomyPlugin.Locale.StringOrDefault(79, "corrupt"));
                    TShock.Log.ConsoleError(ex.ToString());
                    Console.WriteLine(SEconomyPlugin.Locale.StringOrDefault(80, "Your transaction journal appears to be corrupt and transactions have been lost.\n\nYou will start with a clean journal.\nYour old journal file has been move to SEconomy.journal.xml.gz.corrupt"));
                    File.Move(path, path + "." + DateTime.Now.ToFileTime().ToString() + ".corrupt");

                    SaveJournal();

                    //yes there are valid uses for goto, don't judge me fool
                    goto initPoint;
                }
            } finally {
                Console.WriteLine();
            }

            return true;
        }