Jafet Valdez
Jun 17, 2018
  3243
(5 votes)

Tools of the Trade - Diagnosing orders with errors

Hello world.

Welcome to my first blog post here on Episerver World! :D

Today I thought that I’d share one of my most commonly used tools to diagnose and debug errors on PurchaseOrders or Carts.

First a little bit of background

For the last couple of years, I’ve been involved in a project that has had some pretty complicated order handling logic. It has advanced return and exchange handling, different payment providers, different shipping methods, split shipments and multi warehouses while also having integrations on many of these processes that could fail for whatever reason.

With so many processes being able to affect an order in various stages there has unfortunately been some cases where an order has come out the other end all weird looking. Maybe this weirdness manifested itself in a button being disabled unexpectedly, a return failing to be processed even though it shouldn’t, some data missing or things of that nature.

So what is this "Tool of the trade"?

It’s a very simple tool, really. Just some SQL SELECT queries that gathers up all the relevant information for an order in one place. While Commerce Manager is great in many ways in terms of displaying information, it still doesn’t display all the possible fields that could be relevant for you when you have your detective hat on.

Alright no more talking, here it is:

DECLARE @OrderGroupId int = '12345' -- Set this to the ordergroupId of the order you want to inspect

SELECT *
FROM OrderGroup og
JOIN OrderGroup_PurchaseOrder po ON og.OrderGroupId = po.ObjectId
WHERE og.OrderGroupId = @OrderGroupId
-- or you can JOIN OrderGroup_ShoppingCart instead if you want to inspect Carts

SELECT * 
FROM OrderForm oform
JOIN OrderFormEx ofex ON oform.OrderFormId = ofex.ObjectId
WHERE oform.OrderGroupId = @OrderGroupId

SELECT *
FROM Shipment sh
JOIN ShipmentEx shex ON sh.ShipmentId = shex.ObjectId
WHERE sh.OrderGroupId = @OrderGroupId

SELECT *
FROM LineItem l
JOIN LineItemEx lex ON l.LineItemId = lex.ObjectId
WHERE OrderGroupId = @OrderGroupId
ORDER BY LineItemOrdering ASC

SELECT *
FROM OrderGroupAddress oga
JOIN OrderGroupAddressEx ogae ON oga.OrderGroupAddressId = ogae.ObjectId
WHERE oga.OrderGroupId = @OrderGroupId

-- Add SELECTs for as many payment types that an order can have:

SELECT *
FROM OrderFormPayment ofp
JOIN OrderFormPayment_Other ofpex ON ofp.PaymentId = ofpex.ObjectId
WHERE ofp.OrderGroupId = @OrderGroupId

SELECT *
FROM OrderFormPayment ofp
JOIN OrderFormPayment_GiftCard ofpex ON ofp.PaymentId = ofpex.ObjectId
WHERE ofp.OrderGroupId = @OrderGroupId

/*
For payments you can JOIN these tables:

OrderFormPayment_Other
OrderFormPayment_GiftCard
OrderFormPayment_CashCard
OrderFormPayment_CreditCard
OrderFormPayment_Invoice
*/

Pretty simple really. Based on an OrderGroupId we get data about the OrderGroup, all the OrderForms (including “ReturnForms”), Shipments, LineItems, OrderAdresses and Payments. On all the levels of abstraction you also get their additional metadata that you’ve added joined up, so it’s all in one convenient place for you to inspect.

Obviously, you’ll need to find a way to retrieve the OrderGroupId before putting it into this query. I’m actually running a bit more complicated version where I can use a custom order tracking number and an id from our main payment provider to retrieve the order data instead of an OrderGroupId. I omitted that in what I shared above because it’s not really general enough to be used by everyone.

Ok, now I can see the data, what do I do with it?

What I look for are oddities. This could maybe be a field missing a value because it got nulled away in some dark corner of a Workflow. Or maybe a string MetaField containing serialized data that got cut off because you didn’t expect that a customer would ever use THAT many bonus checks.

Either way, after you’ve used this query in various stages of your order processing flow you’ll develop a feel for what seems out of place for orders in your project.

My orders never have any issues, any other use cases?

First, I’d like to say that I’m impressed! :D

Secondly, here’s some other examples of where I use this query:

  • Teaching the structure of Carts/PurchaseOrders in Episerver Commerce to new developers.
    This is kind of a nerdy approach, but it’s been very useful so far. Most developers are used to the database way of structuring things. Showing the data and structure like this I can explain what each level of abstraction is responsible for and what data they contain, but also the fact that the system is extensible because you can add your own meta fields.
  • While developing new order handling features
    I can use this to make sure that the database is correct along the way and spot any unexpected issues with the data being stored.
  • When joining a new project that’s been going on for a while.
    It’s useful to get details on what meta fields have been added so that you know what you have to work with. This of course also reduces the risk of you adding a field that stores the same data as an existing one.

But hey, don’t take my word for it!

Me and my colleagues have used it extensively, but I actually got inspired to share this more publicly after helping a fellow Episerver Developer on the forums figure out why a button in Commerce Manager didn’t work.

Here’s the thread:

https://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=194165

Thanks for reading! I hope that this will help you in your diagnosing and debugging endeavors!

Jafet “Jeff” Valdez

Jun 17, 2018

Comments

Quan Mai
Quan Mai Jun 18, 2018 08:41 AM

It's very nice that you start sharing your experience and knowledge as blog posts. Keep it up and you might earn you-know-what very soon.

One comment - as we always say database schema is blackbox and we don't guarantee backward compatibility on it, it's recommended to use the stored procedure at least. The SQL you wrote can be replaced by this

declare @p8 int
set @p8=476
exec ecf_Search_PurchaseOrder @SQLClause=N'OrderGroupId=12345',@MetaSQLClause=N'',@OrderBy=N'OrderGroupId DESC',@Namespace=N'Mediachase.Commerce.Orders',@Classes=N'PurchaseOrder',@StartingRec=0,@NumRecords=10,@RecordCount=@p8 output
select @p8


which is safer and you don't have to worry about missing this or that data

Jafet Valdez
Jafet Valdez Jun 18, 2018 10:47 AM

Cool, yeah that seems useful for inspecting order data. The output is a bit messier but also includes more stuff. :D

Anyway your example didn't really work for me but this did:

For Purchase Orders

declare @OrderGroupId nvarchar(64) = '12345' -- Set this to the ordergroupId of the order you want to inspect
declare @ApplicationIdInput uniqueidentifier = '' -- Set this to an application Id currently found in SELECT * FROM Application


declare @Query nvarchar(96) = CONCAT('OrderGroupId=',@OrderGroupId)
declare @p8 int
set @p8=476
exec ecf_Search_PurchaseOrder @ApplicationId=@ApplicationIdInput, @SQLClause=@Query, @MetaSQLClause=N'',@OrderBy=N'OrderGroupId DESC',@Namespace=N'Mediachase.Commerce.Orders',@Classes=N'PurchaseOrder',@StartingRec=0,@NumRecords=10,@RecordCount=@p8 output
select @p8

And heres a version for searching for Carts instead:

declare @OrderGroupId nvarchar(64) = '12345' -- Set this to the ordergroupId of the order you want to inspect
declare @ApplicationIdInput uniqueidentifier = '' -- Set this to an application Id currently found in SELECT * FROM Application


declare @Query nvarchar(96) = CONCAT('OrderGroupId=',@OrderGroupId)
declare @p8 int
set @p8=476
exec ecf_Search_ShoppingCart @ApplicationId=@ApplicationIdInput, @SQLClause=@Query, @MetaSQLClause=N'',@OrderBy=N'OrderGroupId DESC',@Namespace=N'Mediachase.Commerce.Orders',@Classes=N'ShoppingCart',@StartingRec=0,@NumRecords=10,@RecordCount=@p8 output
select @p8

Quan Mai
Quan Mai Jun 18, 2018 11:37 AM

You are using Commerce 10.x or earlier. ApplicationId was removed in Commerce 11.

Stay on the edge! 

Jafet Valdez
Jafet Valdez Jun 18, 2018 12:33 PM

Busted! surprised

Please login to comment.
Latest blogs
Copy Optimizely SaaS CMS Settings to ENV Format Via Bookmarklet

Do you work with multiple Optimizely SaaS CMS instances? Use a bookmarklet to automatically copy them to your clipboard, ready to paste into your e...

Daniel Isaacs | Dec 22, 2024 | Syndicated blog

Increase timeout for long running SQL queries using SQL addon

Learn how to increase the timeout for long running SQL queries using the SQL addon.

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Overriding the help text for the Name property in Optimizely CMS

I recently received a question about how to override the Help text for the built-in Name property in Optimizely CMS, so I decided to document my...

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Resize Images on the Fly with Optimizely DXP's New CDN Feature

With the latest release, you can now resize images on demand using the Content Delivery Network (CDN). This means no more storing multiple versions...

Satata Satez | Dec 19, 2024

Simplify Optimizely CMS Configuration with JSON Schema

Optimizely CMS is a powerful and versatile platform for content management, offering extensive configuration options that allow developers to...

Hieu Nguyen | Dec 19, 2024

Useful Optimizely CMS Web Components

A list of useful Optimizely CMS components that can be used in add-ons.

Bartosz Sekula | Dec 18, 2024 | Syndicated blog