K13: OrderInfo Get Total Discounts

Jay Asbury asked on July 17, 2024 17:32

I have an OrderInfo object and need to get the Total discounts applied. I see one way of parsing the xml in OrderDiscounts. Is there a way to get the numeric total in main currency without parsing the xml? I can parse but I was looking for a similar property like OrderTotalTax and such.

Correct Answer

Jay Asbury answered on July 19, 2024 00:26

        /// <summary>
    /// Calculates all the possible discounts from the OrderInfo object and returns the total amount without any currency conversion.
    /// </summary>
    /// <param name="order"><see cref="OrderInfo"/> object to get discounts from</param>
    /// <param name="includeGiftCards">Set to true to also calculate discounts from any gift cards as discounts instead of treating as payment after the total.</param>
    /// <returns><see cref="Decimal"/> total discounts added </returns>
    public static decimal GetOrderDiscountsTotal(this OrderInfo order, bool includeGiftCards = false)
    {
        var orderDiscountSummary = new ValuesSummary(order.OrderDiscounts);

        var itemTotalDiscounts = new ValuesSummary();
        foreach (var orderItem in OrderItemInfoProvider.GetOrderItems(order.OrderID))
        {
            var productDiscountsSummary = new ValuesSummary(orderItem.OrderItemProductDiscounts);
            decimal productTotalDiscount = productDiscountsSummary.Sum(i => i.Value) * orderItem.OrderItemUnitCount;
            itemTotalDiscounts.Add(new SummaryItem($"{orderItem.OrderItemID}-ProductDiscounts", productTotalDiscount));

            var itemDiscountsSummary = new ValuesSummary(orderItem.OrderItemDiscountSummary);
            decimal itemTotalDiscount = itemDiscountsSummary.Sum(i => i.Value);
            itemTotalDiscounts.Add(new SummaryItem($"{orderItem.OrderItemID}-ItemDiscounts", itemTotalDiscount));
        }
        orderDiscountSummary.Merge(itemTotalDiscounts);

        if (includeGiftCards)
        {
            var giftCardsSumary = new ValuesSummary(order.OrderOtherPayments);
            orderDiscountSummary.Merge(giftCardsSumary);
        }

        return orderDiscountSummary.Sum(i => i.Value);
    }
0 votesVote for this answer Unmark Correct answer

Recent Answers


Zdeněk Cetkovský answered on July 18, 2024 16:52

Hi Jay,

The total value of all discounts applied in an Order is not stored by default.

One option other than parsing the summary XMLs of the order items and the order itself (as we have different types of discounts) could be to supply a custom calculator into the pipeline. That would calculate the total discount along the calculation pipeline run and store this into custom property, which would then be saved with an OrderInfo. However, going through the summary XML data appear to be likely easier. You could use already available classes and methods:

ValuesSummary constructor (accepting summary XML) and the Sum method to get the sum for various discounts:

        var orderDiscountSummary = new ValuesSummary(orderInfo.OrderDiscounts);
        decimal orderDiscountsTotal = orderDiscountSummary.Sum(i => i.Value);

Please note that there is also the OrderInfo.OrderOtherPayments summary with "Gift cards" application, Moreover, each OrderItemInfo has its own summary about unit-level discounts and the item-level discounts application, which you may want to incorporate in the total.

in the loop through all OrderItemInfo objects for the given Order, it could look like:

                var productDiscountsSummary = new ValuesSummary(orderItem.OrderItemProductDiscounts);
                decimal productTotalDiscount = productDiscountsSummary.Sum(i => i.Value) * orderItem.OrderItemUnitCount;

                var itemDiscountsSummary = new ValuesSummary(orderItem.OrderItemDiscountSummary);
                decimal itemTotalDiscount = itemDiscountsSummary.Sum(i => i.Value);

                decimal orderItemTotalDiscount = productTotalDiscount + itemTotalDiscount;

Obviously, you may need to adjust the value currency if it differs from main and you want to compare in main.

Please let me know if this helps.

By the way, for a different direction (and possibly requirement), my colleague wrote an article earlier about creating reports of applied discounts for Orders at https://devnet.kentico.com/articles/creating-reports-for-discounts

Best regards,

Zdenek

0 votesVote for this answer Mark as a Correct answer

Jay Asbury answered on July 18, 2024 23:04

Thank you. Yes that is exactly the issue I have. Not knowing all the pieces and all to gather. I'll take a look at the report article which may help. I do understand the complexity of all the possible ones which is why I asked if there was a Kentico thingy to get the value before I went down a fun rabbit hole. Along with that answer could you adjust documentation like https://docs.kentico.com/13api/e-commerce/discounts to talk about gathering the different discounts or link to that report article or something. I did try to dig into documentation and saw some potentials but did not see a Kentico answer to if you want to get the total discounts from an OrderInfo...Start here kind of thing. Let you know if it helped. Thanks for the answer.

0 votesVote for this answer Mark as a Correct answer

Jay Asbury answered on July 18, 2024 23:54

Would something like this as an extension method to OrderInfo seem right? Yes I still need to make sure right currency. Do you see any issue with the following code?

        var orderDiscountSummary = new ValuesSummary(order.OrderDiscounts);
        var giftCardsSumary = new ValuesSummary(order.OrderOtherPayments);
        var itemTotalDiscounts = new ValuesSummary();
        foreach (var orderItem in OrderItemInfoProvider.GetOrderItems(order.OrderID))
        {
            var productDiscountsSummary = new ValuesSummary(orderItem.OrderItemProductDiscounts);
            decimal productTotalDiscount = productDiscountsSummary.Sum(i => i.Value) * orderItem.OrderItemUnitCount;
            itemTotalDiscounts.Add(new SummaryItem($"{orderItem.OrderItemID}-ProductDiscounts", productTotalDiscount));

            var itemDiscountsSummary = new ValuesSummary(orderItem.OrderItemDiscountSummary);
            decimal itemTotalDiscount = itemDiscountsSummary.Sum(i => i.Value);
            itemTotalDiscounts.Add(new SummaryItem($"{orderItem.OrderItemID}-ItemDiscounts", itemTotalDiscount));
        }
        orderDiscountSummary.Merge(itemTotalDiscounts);
        orderDiscountSummary.Merge(giftCardsSumary);


        decimal orderDiscountsTotal = orderDiscountSummary.Sum(i => i.Value);
0 votesVote for this answer Mark as a Correct answer

Jay Asbury answered on July 19, 2024 00:17

Something to watch out for I guess is do you count gift cards as discounts or not. Since they are technically a form of payment it is after tax so maybe a default don't include and a boolean flag that says include gift cards may be the best way to handle that situation.

0 votesVote for this answer Mark as a Correct answer

Zdeněk Cetkovský answered on July 19, 2024 13:28

Thank you for the responses!

I didn't suggest any specific place where to run this, as it may depend on the scenario requirements, but an extension method is a handy idea.

Indeed, the Gift cards are applied after tax calculation and application, therefore you may not want to include it with other discounts, in selected regions or in given scenarios. Furthermore, it may not necessarily be a discount, it could be also used to add some extra fee (as we show in one example in documentation).

Using Merge on the ValuesSummary is also clever if you want to list the individual discount type totals (discount sub-totals), but if you only need to get the total value, it's not necessary.

The final method version with boolean switch on gift card inclusion looks good.

Best Regards,
Zdenek

0 votesVote for this answer Mark as a Correct answer

Jay Asbury answered on July 19, 2024 14:50

Wasn't sure if I wanted to do the individual discounts later and break it up to two functions. One building all discount totals and one just the number. Why I did the merge that way. That way the example shows both ideas so if someone wanted to go the other way and return the ValueSumnary all together, they could. Yes I could have added the sums along the way. But thanks for the help.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.