private static void SetItemCategory(AwsLineItem item, AwsProduct product, string operation) { if (product.ProductCode != "AmazonEC2" && product.ProductCode != "AmazonRDS") return; string usageType = item.UsageType; string code = null; string name = null; if (usageType.StartsWith("EBS:")) { code = "EBS"; name = "Amazon EC2 EBS"; item.UsageType = item.UsageType.Substring(4); } else if (usageType.StartsWith("CW:")) { code = "CW"; name = "Amazon CloudWatch"; item.UsageType = item.UsageType.Substring(3); } else if (usageType.StartsWith("ElasticIP:")) { code = "ElasticIP"; name = "Elastic IP Addresses"; item.UsageType = item.UsageType.Substring(10); } else if (usageType.StartsWith("SpotUsage:")) { code = "SpotUsage"; name = "Spot Instances"; } else if (operation == "LoadBalancing") { code = operation; name = "Elastic Load Balancing"; } else if (operation == "RunInstances") { code = operation; name = "Amazon EC2 running Linux/UNIX"; } else if (operation == "RunInstances:0002") { code = operation; name = "Amazon EC2 running Windows"; } else if (operation == "RunInstances:0006") { code = operation; name = "Amazon EC2 running Windows with SQL Server"; } else if (operation == "CreateDBInstance" || usageType == "RDS:StorageIOUsage") { code = "CreateDBInstance"; name = "Amazon RDS Storage"; } else if (usageType == "RDS:ChargedBackupUsage") { code = usageType; name = "Amazon RDS Automated Backups"; } else if (operation == "CreateDBInstance:0002") { code = operation; name = "Amazon RDS for MySQL Community Edition"; } item.Category = code; item.CategoryName = name; }
private static AwsStatement Read(System.IO.TextReader reader) { // Split the CSV data into individual line item records var items = ParseCsv(reader); // Create our resulting statement object AwsStatement statement = new AwsStatement(); statement.Accounts = new List<AwsAccount>(); // Get a list of the distinct payer accounts in the data var payerAccounts = items.Where(i => !String.IsNullOrEmpty(i.PayerAccountID)).Select(i => i.PayerAccountID).Distinct(); // For each account, // create an account object // add it to the statement // and fill it with data foreach (var accountId in payerAccounts) { // Get the items that apply to this account var accountItems = items.Where(i => i.PayerAccountID == accountId); // Create an account object AwsAccount account = new AwsAccount(); account.Invoices = new List<AwsInvoice>(); account.AccountId = accountId; statement.Accounts.Add(account); // Get the list of invoices from the items which // apply to the current account var invoiceIds = accountItems.Where(i => !String.IsNullOrEmpty(i.InvoiceID)).Select(i => i.InvoiceID).Distinct(); // For each invoice // create an invoice object // add it to the account object // and fill it with data foreach (var invoiceId in invoiceIds) { // Get the list of items for the current account // and the current invoice var invoiceItems = accountItems.Where(i => i.InvoiceID == invoiceId).Select(i => i); System.Diagnostics.Debug.Assert(invoiceItems.Count() > 0); // Create an invoice object AwsInvoice invoice = new AwsInvoice(); invoice.InvoiceId = invoiceId; invoice.Products = new List<AwsProduct>(); invoice.InvoiceDate = invoiceItems.First().InvoiceDate.Value; account.Invoices.Add(invoice); // Get the line items for this invoice var lineItems = invoiceItems .Where(i => i.RecordType == "PayerLineItem") .Select(i => i); // Get the list of unique products used // by this invoice var productCodes = lineItems.Select(i => i.ProductCode).Distinct().OrderBy(i => i); // For each product // create a product object // add it to the invoice // and fill it with data foreach (var productCode in productCodes) { // Get the list of line items which only apply to this product var productLineItems = lineItems.Where(i => i.ProductCode == productCode).Select(i => i).OrderBy(i => i.UsageType); System.Diagnostics.Debug.Assert(productLineItems.Count() > 0); // We need a product name, so get it from one of the items string productName = productLineItems.First().ProductName; // Create our product object AwsProduct product = new AwsProduct(); product.Items = new List<AwsLineItem>(); product.ProductCode = productCode; product.ProductName = productName; invoice.Products.Add(product); // For each line item // create a line item object // and populate it's data. foreach (var lineItem in productLineItems) { // Create our line item object and fill it with data AwsLineItem item = new AwsLineItem(); item.Description = lineItem.ItemDescription; item.UsageQuantity = lineItem.UsageQuantity.Value; item.FormattedUsageQuantity = Format3Or6(item.UsageQuantity); item.CostBeforeTaxes = lineItem.CostBeforeTaxes.Value; item.UsageType = lineItem.UsageType; // Find an appropriate region and category for this item/product. SetItemRegion(item, product); SetItemCategory(item, product, lineItem.Operation); product.Items.Add(item); } } // Try to find an invoice total amongst the chaos. // If one is found, then save some of it's data var invoiceTotal = invoiceItems.Where(i => i.RecordType == "InvoiceTotal").Select(i => i).FirstOrDefault(); if (invoiceTotal != null) { invoice.StartDate = invoiceTotal.BillingPeriodStartDate.Value; invoice.EndDate = invoiceTotal.BillingPeriodEndDate.Value; invoice.Taxes = invoiceTotal.TaxAmount.Value; invoice.Total = invoiceTotal.TotalCost.Value; } } // Account total? } // Try to find an statement total amongst the chaos. // If one is found, then save some of it's data var statementTotal = items.Where(i => i.RecordType == "StatementTotal").Select(i => i).FirstOrDefault(); if (statementTotal != null) { statement.StartDate = statementTotal.BillingPeriodStartDate.Value; statement.EndDate = statementTotal.BillingPeriodEndDate.Value; statement.Taxes = statementTotal.TaxAmount.Value; statement.Total = statementTotal.TotalCost.Value; } return statement; }
// Finds an appropriate region for the supplied item in the product's list of // regions. If one is found, then return the existing item. // If one is not found, create one, add it to the product's list, and return it. // Some products don't use regions. In these cases, return null. private static void SetItemRegion(AwsLineItem item, AwsProduct product) { // These products don't use regions if (product.ProductCode == "AmazonRoute53") return; else if (product.ProductCode == "AmazonSES") return; string usageType = item.UsageType; // Default to US East string code = "us-east-1"; string name = "US East (Northern Virginia) Region"; // S3 uses a different name for US East if (product.ProductCode == "AmazonS3") name = "US Standard Region"; else if (product.ProductCode == "AWSDataTransfer") name = "US East (Northern Virginia) and US Standard Regions"; // If usage type starts with special prefixes, then that means // it belongs to a particular region that is not US East. if (usageType.StartsWith("US-")) { // No change to region, is US East (Virginia) item.UsageType = item.UsageType.Substring(3); } else if (usageType.StartsWith("USW1-")) { code = "us-west-1"; name = "US West (Northern California) Region"; item.UsageType = item.UsageType.Substring(5); } else if (usageType.StartsWith("USW2-")) { code = "us-west-2"; name = "US West (Oregon) Region"; item.UsageType = item.UsageType.Substring(5); } else if (usageType.StartsWith("EU-")) { code = "eu-west-1"; name = "EU West (Ireland) Region"; item.UsageType = item.UsageType.Substring(3); } else if (usageType.StartsWith("APS1-")) { code = "ap-southeast-1"; name = "Asia Pacific (Singapore) Region"; item.UsageType = item.UsageType.Substring(5); } else if (usageType.StartsWith("APN1-")) { code = "ap-northeast-1"; name = "Asia Pacific (Tokyo) Region"; item.UsageType = item.UsageType.Substring(5); } else if (usageType.StartsWith("UGW1-")) { code = "us-gov-west-1"; name = "GovCloud (US) Region"; item.UsageType = item.UsageType.Substring(5); } else if (usageType.StartsWith("SAE1-")) { code = "sa-east-1"; name = "South America (Sao Paulo) Region"; item.UsageType = item.UsageType.Substring(5); } item.Region = code; item.RegionName = name; }