Beispiel #1
0
        private void SerializeTransactionBody( XmlWriter xmlWriter, Transaction trans )
        {
            xmlWriter.WriteElementString( "Date", trans.Date.ToShortDateString() );
            xmlWriter.WriteWhitespace( Environment.NewLine );
            xmlWriter.WriteElementString( "Amount", trans.Amount.ToString() );
            xmlWriter.WriteWhitespace( Environment.NewLine );
            if( trans.Description != null && trans.Description.Length > 0 )
            {
                xmlWriter.WriteElementString( "Description", trans.Description );
                xmlWriter.WriteWhitespace( Environment.NewLine );
            }
            /*
            // TODO: Remove Transaction.Number
            if( trans.HasNumber )
            {
                xmlWriter.WriteElementString( "Number", trans.Number );
                xmlWriter.WriteWhitespace( Environment.NewLine );
            }
            */
            if( trans.Memo != null && trans.Memo.Length > 0 )
            {
                xmlWriter.WriteElementString( "Memo", trans.Memo );
                xmlWriter.WriteWhitespace( Environment.NewLine );
            }

            bool canUseShortcut = false;

            LineItem[] credits = trans.GetCreditLineItems();
            LineItem[] debits = trans.GetDebitLineItems();

            /*
            if( credits.Length != 1 || debits.Length != 1 )
                canUseShortcut = false;
            else
            {
                if( credits[0].IsReconciled )
                    canUseShortcut = false;
                if( debits[0].IsReconciled )
                    canUseShortcut = false;
                if( debits[0].Account.AccountType != AccountType.Expense )
                    canUseShortcut = false;
            }
            */

            if( canUseShortcut )
            {
                xmlWriter.WriteElementString( "AccountId", credits[0].Account.Id.ToString() );
                xmlWriter.WriteWhitespace( Environment.NewLine );
                if( debits[0].CategoryObject != null )
                {
                    xmlWriter.WriteElementString( "Category", debits[0].CategoryObject.Name );
                    xmlWriter.WriteWhitespace( Environment.NewLine );
                }
            }
            else
            {
                xmlWriter.WriteStartElement( "LineItems" );
                xmlWriter.WriteWhitespace( Environment.NewLine );
                foreach( LineItem lineItem in trans.LineItems )
                {
                    // <Credit> or <Debit>
                    xmlWriter.WriteStartElement( lineItem.TransactionType.ToString() );
                    // Line items now have unique identifiers, too.
                    if( lineItem.Id > 0 )
                        xmlWriter.WriteAttributeString( "Id", lineItem.Id.ToString() );
                    xmlWriter.WriteAttributeString( "AccountId", lineItem.Account.Id.ToString() );
                    // Number is new in 1.2 format
                    if( lineItem.Number != null && lineItem.Number.Length > 0 )
                        xmlWriter.WriteAttributeString( "Number", lineItem.Number );
                    // Memo became an attribute in 1.2 format
                    if( lineItem.CategoryObject != null )
                        xmlWriter.WriteAttributeString( "Category", lineItem.CategoryObject.Name );
                    if( lineItem.Memo != null && lineItem.Memo != trans.Memo )
                        xmlWriter.WriteAttributeString( "Memo", lineItem.Memo );
                    if( lineItem.Amount != trans.Amount )
                        xmlWriter.WriteAttributeString( "Amount", lineItem.Amount.ToString() );
                    if( lineItem.IsReconciled )
                        xmlWriter.WriteAttributeString( "Reconciled", "true" );

                    // New: Write the associated online transaction for this line item.
                    if( lineItem.OnlineTransaction != null )
                    {
                        xmlWriter.WriteWhitespace( Environment.NewLine );
                        OnlineTransactionStorageXml ostorage = new OnlineTransactionStorageXml();
                        ostorage.SerializeTransaction( xmlWriter, lineItem.OnlineTransaction );
                        xmlWriter.WriteWhitespace( Environment.NewLine );
                    }

                    xmlWriter.WriteEndElement(); // </Credit> or </Debit>
                    xmlWriter.WriteWhitespace( Environment.NewLine );
                }
                xmlWriter.WriteEndElement(); // </LineItems>
                xmlWriter.WriteWhitespace( Environment.NewLine );
            }
        }
Beispiel #2
0
        /// <summary>
        /// Deserialize from an XML reader into a Transaction object.
        /// </summary>
        /// <param name="xmlReader">XmlReader to deserialize from.</param>
        /// <param name="ledger">Parent Ledger object.</param>
        /// <returns>A Transaction object.</returns>
        public Transaction DeserializeTransaction( XmlReader xmlReader, Version version, Ledger ledger )
        {
            if( xmlReader.NodeType != XmlNodeType.Element || xmlReader.Name != "Transaction" )
                throw new ApplicationException( "Needs a Transaction node to deserialize an transaction object." );

            OnlineTransactionStorageXml ostorage = new OnlineTransactionStorageXml();
            Transaction trans = new Transaction();

            if( xmlReader.GetAttribute( "Id" ) != null )
                trans.Id = Int32.Parse( xmlReader.GetAttribute( "Id" ) );

            string voidAttribute = xmlReader.GetAttribute( "Void" );
            string pendingAttribute = xmlReader.GetAttribute( "Pending" );
            //string reconciledAttribute = xmlReader.GetAttribute( "Reconciled" );
            string recurringAttribute = xmlReader.GetAttribute( "Recurring" );

            // What's the best way to do a case-insensitive string compare?
            // Options:
            // x.Equals( y, StringComparison.OrdinalIgnoreCase)
            // x.ToLower() == y.ToLower()
            // string.Compare( x, y, true );
            // string.Compare( x, y, StringComparison.OrdinalIgnoreCase );

            if( string.Compare( voidAttribute, "true", StringComparison.OrdinalIgnoreCase ) == 0 )
                trans.Flags |= TransactionFlags.Void;
            if( string.Compare( pendingAttribute, "true", StringComparison.OrdinalIgnoreCase ) == 0 )
                trans.Flags |= TransactionFlags.Pending;
            //if( string.Compare( reconciledAttribute, "true", StringComparison.OrdinalIgnoreCase ) == 0 )
            //	trans.Flags |= TransactionFlags.Reconciled;
            if( string.Compare( recurringAttribute, "true", StringComparison.OrdinalIgnoreCase ) == 0 )
                trans.Flags |= TransactionFlags.Recurring;

            bool accountShortcut = false;
            LineItem lineItem = null;

            while( xmlReader.Read() )
            {
                string accountName = null;
                Account account = null;
                string categoryName = null;
                Category category = null;
                int accountId = 0;
                decimal amount = 0;
                string memo = null;

                switch( xmlReader.NodeType )
                {
                    case XmlNodeType.Element:
                        switch( xmlReader.Name )
                        {
                            case "Date":
                                trans.Date = DateTime.Parse( xmlReader.ReadString() );
                                break;
                            case "Amount":
                                trans.Amount = Decimal.Parse( xmlReader.ReadString() );
                                break;
                            case "Description":
                                trans.Description = xmlReader.ReadString();
                                break;
                            case "Memo":
                                trans.Memo = xmlReader.ReadString();
                                break;
                            case "Account":
                                // Shortcut for LineItems
                                accountShortcut = true;
                                accountName = xmlReader.ReadString();
                                account = ledger.FindAccount( accountName );
                                if( account == null )
                                    throw new ArgumentException( "Reference to undefined account named " + accountName );
                                lineItem = new LineItemCredit( account, trans.Amount );
                                lineItem.Transaction = trans;
                                trans.LineItems.Add( lineItem );
                                break;
                            case "AccountId":
                                // Shortcut for LineItems
                                accountShortcut = true;
                                accountId = Int32.Parse( xmlReader.ReadString() );
                                account = ledger.FindAccount( accountId );
                                if( account == null )
                                    throw new ArgumentException( "Reference to unknown account Id " + accountId );
                                lineItem = new LineItemCredit( account, trans.Amount );
                                trans.LineItems.Add( lineItem );
                                account = ledger.FindAccount( "Expenses" );
                                if( account == null )
                                    throw new ArgumentException( "Expense account not defined." );
                                lineItem = new LineItemDebit( account, trans.Amount );
                                lineItem.Transaction = trans;
                                trans.LineItems.Add( lineItem );
                                break;
                            case "Category":
                                // Shortcut for LineItems
                                if( trans.LineItems.Count == 0 )
                                    throw new ArgumentException( "Account or AccountId must be specified before Category element." );
                                LineItem[] debits = trans.GetDebitLineItems();
                                if( debits.Length != 1 )
                                    throw new ArgumentException( "Category element can only be used when there is exactly one debit line item." );
                                account = ledger.FindAccount( "Expenses" );
                                categoryName = xmlReader.ReadString();
                                category = account.GetCategory( categoryName );
                                debits[0].CategoryObject = category;
                                break;
                            case "Credit":
                                if( accountShortcut )
                                    throw new ArgumentException( "LineItems not expected when using Account/Category elements." );
                                if( version == new Version( 1, 0 ) )
                                {
                                    throw new ApplicationException( "Version 1.0 data files are no longer supported." );
                                }
                                else if( version >= new Version( 1, 1 ) )
                                {
                                    if( xmlReader.GetAttribute( "AccountId" ) != null )
                                    {
                                        accountId = Int32.Parse( xmlReader.GetAttribute( "AccountId" ) );
                                        account = ledger.FindAccount( accountId );
                                    }
                                    else
                                    {
                                        account = ledger.FindAccount( xmlReader.GetAttribute( "Account" ) );
                                        if( account == null )
                                            throw new ArgumentException( "Reference to undefined account named " + xmlReader.GetAttribute( "Account" ) );
                                        accountId = account.Id;
                                    }
                                    if( xmlReader.GetAttribute( "Category" ) != null )
                                        category = account.GetCategory( xmlReader.GetAttribute( "Category" ) );
                                    if( xmlReader.GetAttribute( "Amount" ) != null )
                                        amount = Decimal.Parse( xmlReader.GetAttribute( "Amount" ) );
                                    else
                                        amount = trans.Amount;

                                    if( version >= new Version( 1, 2 ) )
                                        memo = xmlReader.GetAttribute( "Memo" );
                                    else
                                        memo = xmlReader.ReadString();
                                }
                                lineItem = new LineItemCredit( account, amount, category );
                                lineItem.Transaction = trans;
                                lineItem.Memo = memo;
                                lineItem.Number = xmlReader.GetAttribute( "Number" );	// could be null
                                if( xmlReader.GetAttribute( "Reconciled" ) != null )
                                    lineItem.IsReconciled = (xmlReader.GetAttribute( "Reconciled" ).ToLower() == "true");
                                if( xmlReader.GetAttribute( "Id" ) != null )
                                    lineItem.Id = int.Parse( xmlReader.GetAttribute( "Id" ) );
                                trans.LineItems.Add( lineItem );
                                break;
                            case "Debit":
                                if( accountShortcut )
                                    throw new ArgumentException( "LineItems not expected when using Account/Category elements." );
                                if( version == new Version( 1, 0 ) )
                                {
                                    throw new ApplicationException( "Version 1.0 data files are no longer supported." );
                                }
                                else if( version >= new Version( 1, 1 ) )
                                {
                                    if( xmlReader.GetAttribute( "AccountId" ) != null )
                                    {
                                        accountId = Int32.Parse( xmlReader.GetAttribute( "AccountId" ) );
                                        account = ledger.FindAccount( accountId );
                                    }
                                    else
                                    {
                                        account = ledger.FindAccount( xmlReader.GetAttribute( "Account" ) );
                                        if( account == null )
                                            throw new ArgumentException( "Reference to undefined account named " + xmlReader.GetAttribute( "Account" ) );
                                        accountId = account.Id;
                                    }
                                    if( xmlReader.GetAttribute( "Category" ) != null )
                                        category = account.GetCategory( xmlReader.GetAttribute( "Category" ) );
                                    if( xmlReader.GetAttribute( "Amount" ) != null )
                                        amount = Decimal.Parse( xmlReader.GetAttribute( "Amount" ) );
                                    else
                                        amount = trans.Amount;

                                    if( version >= new Version( 1, 2 ) )
                                        memo = xmlReader.GetAttribute( "Memo" );
                                    else
                                        memo = xmlReader.ReadString();
                                }
                                lineItem = new LineItemDebit( account, amount, category );
                                lineItem.Transaction = trans;
                                lineItem.Memo = memo;
                                lineItem.Number = xmlReader.GetAttribute( "Number" );	// could be null
                                if( xmlReader.GetAttribute( "Reconciled" ) != null )
                                    lineItem.IsReconciled = (xmlReader.GetAttribute( "Reconciled" ).ToLower() == "true");
                                if( xmlReader.GetAttribute( "Id" ) != null )
                                    lineItem.Id = int.Parse( xmlReader.GetAttribute( "Id" ) );
                                trans.LineItems.Add( lineItem );
                                break;
                            case "OnlineTransaction":
                                // We need to figure out whether this is a child of
                                // the Transaction element or a Credit/Debit element.
                                // Try examining xmlReader.Depth.
                                OnlineTransaction otrans = ostorage.DeserializeTransaction( xmlReader, version );
                                if( xmlReader.Depth > 3 )
                                {
                                    // Associate with LineItem
                                    lineItem.OnlineTransaction = otrans;
                                }
                                else
                                {
                                    throw new StorageException( "OnlineTransaction nodes are no longer supported at the Transaction level." );
                                    // Associate with Transaction (deprecated)
                                    // trans.OnlineTransactions.Add( otrans );
                                }
                                break;
                            default:
                                break;
                        }
                        break;

                    case XmlNodeType.EndElement:
                        if( xmlReader.Name == "Transaction" )
                            return trans;
                        break;
                }
            }

            trans.SetUnmodified();

            return trans;
        }