I am working on a project where I have to calculate the totals of a transaction.  Unfortunately, coupons have proven to be quite an issue.  There are four types of coupons: transaction percentage, transaction dollar amounts, item percentage and item dollar amounts.I ended-up with this beast of a method, and was wondering if it is clear why I'm doing each part in the way I am.  Are my comments are detailed enough?  Is my code is more-or-less readable?  Is there a way to simplify any of it?private static Totals CalculateTotals(List<Item> items, List<Coupon> coupons, List<Payment> payments){    // Local vars, totals gets returned.    Totals totals = new Totals();    decimal subtotal = 0;    decimal workingSubtotal = 0;    decimal discounts = 0;    decimal tax = 0;    decimal paid = 0;    decimal taxRate = (Initialization.Location.TaxRate ?? 0);    // Get the subtotal before any discounts.    items.ForEach(i => subtotal += (i.Price ?? 0));    // An ItemCoupon takes a whole amount or percentage off of a single Item.    // It can take it off of the most expensive, or least.  Nothing in the middle.    foreach (var coupon in coupons.OfType<ItemCoupon>())    {        // new Item to hold the item to be discounted.        Item item;        // Find which item to discount.        if (coupon.DiscountMostExpensive)        {            item = items.OrderByDescending(i => i.Price).FirstOrDefault();        }        else // Otherwise, Discount LEAST Expensive.        {            item = items.OrderByDescending(i => i.Price).LastOrDefault();        }        // Remove it from the list, before editing the price.        items.Remove(item);        // Set new price of item based on the type of coupon. (Percent, or whole dollar.)        if (coupon.PercentageCoupon)        {            item.Price = Utils.CalculatePercentage(item.Price, coupon.DiscountPercentage);        }        else        {            item.Price = (item.Price ?? 0) - (coupon.DiscountAmount ?? 0);        }        // Add the item back to the list, with the new price.        items.Add(item);    }    // Now that the single items have been discounted, let's get a wroking subtotal.    items.ForEach(i => workingSubtotal += (i.Price ?? 0));    // A TransactionCoupon takes a whole amount or percentage off of the entire transaction.     // To simplfy tax caculation--and because some items are non-taxable,     // oh and, because we don't want any one item going below zero--we     // split the discount over all the items, evenly.    foreach (var coupon in coupons.OfType<TransactionCoupon>())    {        if (coupon.PercentageCoupon)        {            // If it is a Percentage Coupon, simply take said percentage of off each item.            items.ForEach(i => i.Price = Utils.CalculatePercentage(i.Price, coupon.DiscountPercentage));        }        else        {            // If it is a whole amount, get each items percent of the of the subtotal, and discount them equally.            // This would look way too confusing using lambda.            foreach (var item in items)            {                decimal discount = (item.Price ?? 0) * ((coupon.DiscountAmount ?? 0) / workingSubtotal);                item.Price = item.Price - discount;            }        }    }    // Let's get the new-new-new subtotal.    workingSubtotal = 0;    items.ForEach(i => workingSubtotal += (i.Price ?? 0));    // Calculate the total discounts.    discounts += (subtotal - workingSubtotal);    // Set tax for order.  (This must be done after ALL discounts have been applied)    foreach (var item in items.Where(i => i.Taxable))    {        tax += ((item.Price ?? 0) * taxRate);    }    // Get the total amount paid.    payments.ForEach(p => paid += p.Amount);    // Add all the results to the Totals struct.    totals.Subtotal = subtotal;  // Never return the workingSubtotal;    totals.Discounts = discounts;    totals.Tax = tax;    totals.Paid = paid;    totals.Total = ((workingSubtotal + tax) - paid);    return totals;}
Calculating totals of a transaction
c#;linq;finance