Update Shipment Status From LineItem ID

Vote:
 

I'm trying to update the shipment status on an order but I'm only given the line item id. How can I search commerce manager to update a shipment status on an order?

I see that there is a status on the OrderForm and Shipment table. Which is the correct table to update shipment status?

#77751
Nov 25, 2013 21:42
Vote:
 

If I remember correctly, there is an enum called OrderShipmentStatus (in Mediachase.Commerce.dll) used to set this property on the Shipment object. There is a class called OrderStatusManager with a method signature like below used to set a Shipment object’s status.

private static Shipment SetShipmentStatus(Shipment shipment, OrderShipmentStatus status) {}

It is a private method that sets the Status property on a shipment instance, runs some workflows, and does some other housekeeping. It is called in other parts of the class as shown in the following public static methods of OrderStatusManager that take a Shipment object as a parameter:

// in ReleaseOrderShipment()
SetShipmentStatus(shipment, OrderShipmentStatus.Released);

// in CancelOrderShipment()
SetShipmentStatus(shipment, OrderShipmentStatus.Cancelled);

// in CompleteOrderShipment()
SetShipmentStatus(shipment, OrderShipmentStatus.Shipped);

// in PickForPackingOrderShipment()
SetShipmentStatus(shipment, OrderShipmentStatus.Packing);

// in ReturnFromPackingOrderShipment()
SetShipmentStatus(shipment, OrderShipmentStatus.Released);

If you take a look at the underlying [Shipment] table there is a column for Status where the enum value is stored as a string. There is also a LineItemIds column that stores a string representation of the associated line items. Of course, it is NOT advised to modify the database table directly and use the API instead to make sure all the proper operations (workflows, etc) are run as well as protect against dependencies that could break code in future versions.

#77822
Nov 26, 2013 18:56
Vote:
 

Oh cool.

So how do you handle shipments that are exactly the same but made by different customers.

Say for instance, there were two orders by two customers for the same items. How would I distinguish which shipment would need to be updated if I only know the line item ids for the orders?

#77823
Nov 26, 2013 19:39
Vote:
 

If you use the API this should be a non-issue as a Shipment is linked to it's parent OrderForm type which is further linked to its parent OrderGroup type (which can be something like a PurchaseOrder or a PaymentPlan). So if you do something with a Shipment instance like:

var orderGroup = shipment.Parent.Parent // get a reference to parent OrderGroup instance

Following this, if you have two separate customers making two separate orders, their respective shipments will belong to two different OrderForm instances that belong to their own OrderGroup.

#77824
Nov 26, 2013 20:23
Vote:
 

Oh I see it now but I'm a little lost on a couple things. Is there a repository or service class that allows you to search for a shipment by only line item ids?

I've created a Google spreadsheet of some sample data.

https://docs.google.com/spreadsheet/ccc?key=0Arks5K5urmOidHZhUkFmNHliMmo0WVpWMWI3aGxtZUE&usp=sharing

I forgot to mention that when I look up the shipment based on line item ids, the customer context is unknown as well. I'm grabbing a message from a topic in ActiveMQ that only contains line item ids and the shipment tracking number.

#77826
Nov 26, 2013 20:50
Vote:
 

I took a look at your Google spreadsheet and it looks like you also have the OrderGroupId available.

You can use the OrderContext class (Mediachase.Commerce.dll) to start off with something like this.

// set your values
int orderGroupId;
int orderFormId;
int shipmentId;
int lineitemId;

var purchaseOrder = OrderContext.Current.GetPurchaseOrderById(orderGroupId);
foreach(OrderForm orderForm in purchaseOrder.OrderForms)
{
    if(orderForm.OrderFormId == orderFormId) // find the right OrderForm
    {
        foreach(Shipment shipment in orderForm.Shipments) // find the right Shipment
        {
            if(shipment.ShipmentId == shipmentId)
            {
                // use Shipment class static methods

                // get collection of line items
                var lineItems = Shipment.GetShipmentLineItems(shipment); 
                
                // get the quantity of a line item in a shipment
                foreach(LineItem lineItem in lineItems)
                {
                    var lineItemQuantity = Shipment.GetLineItemQuantity(shipment, lineItem.LineItemId);
                }
            }
            break;
        }
    }
    break;
}

EDIT: Added some static method examples from Shipment class.
EDIT: Code syntax highlighting.

#77878
Edited, Nov 27, 2013 23:26
Vote:
 

Oh got it. So I do need to at least have an orderGroupId in order for this to get the shipment ID?

#78042
Dec 02, 2013 15:30
Vote:
 

Yes, that's right. You would need the orderGroupId in the OrderContext API to easily get to the OrderGroup root object. There are other methods in OrderContext that can help you find and retrieve an order, but using the orderGroupId would be the most direct way.

#78043
Dec 02, 2013 19:48
Vote:
 

Cool. Is there any other way if you don't have the OrderContext or any other forms of information except the line item ids and quantity of each line item id?

#78044
Dec 02, 2013 19:51
Vote:
 

I suppose you could then look at the database tables and infer backward. If you know the line item id, you can see the OrderFormId and OrderGroupId values from the [LineItem] table row. You can also look at the [Shipment] table to see which shipments belong to a particular OrderFormId. However, it isn't recommended to do this and you should probably alter this design before you are stuck with this as the only option. 

#78045
Dec 02, 2013 19:59
Vote:
 

Okay. I've made the request to alter the design of the system we're integrating with. 

#78789
Dec 03, 2013 15:11
Vote:
 

Hey Jeff,

I have one more question. How can I search for a lineitem in the LineItem table by lineitemid?

Here's a sample of table data.

https://docs.google.com/spreadsheet/ccc?key=0Arks5K5urmOidE5nYXAtRFozaURsVXBRMFlackY3QXc&usp=sharing

#78888
Dec 04, 2013 17:25
Vote:
 

You can use something like the sample code from the 11/27/13 post above.
In the innermost foreach loop just do a check for equality on the lineItemId value you have, like below.

// get the quantity of a line item in a shipment
foreach(LineItem lineItem in lineItems)
{
    if (lineItem.LineItemId == lineitemId)
    {
        // do your stuff here, like get quantity of the line item in a shipment
        var lineItemQuantity = Shipment.GetLineItemQuantity(shipment, lineItem.LineItemId);
    }
}

If you want to see the line items associated at a higher level with an OrderForm instead of with the OrderForm's shipments, do something like below.

// set your values
int orderGroupId;
int orderFormId;
int lineitemId;

var purchaseOrder = OrderContext.Current.GetPurchaseOrderById(orderGroupId);
foreach(OrderForm orderForm in purchaseOrder.OrderForms)
{
    if(orderForm.OrderFormId == orderFormId) // find the right OrderForm
    {
        // get the quantity of a line item in a shipment
        foreach(LineItem lineItem in orderForm.LineItems)
        {
                if (lineItem.LineItemId == lineitemId)
                {
                    // do your stuff with lineItem here
                }
        }
    }
    break;
}

 

#78889
Dec 04, 2013 18:47
Vote:
 

What if you don't have the orderGroupId and orderFormId?

#78890
Dec 04, 2013 18:49
Vote:
 

Then I'm afraid I'd have the same answer as my 12/2/13 post. Namely, inferring backward from the sql table. If you know the line item id, you can see the OrderFormId and OrderGroupId values from the [LineItem] table row.

select OrderGroupId, OrderFormId 
from LineItem 
where LineItemId = 2 -- your id here

Then plug those values back into the api calls. OrderGroupId is the only one really needed though since there is usually only one OrderForm in an OrderGroup and you can find it using the api. Of course, if you can get this data in your feed in the first place, you'll save that additional round trip. :)

#78891
Dec 04, 2013 18:57
Vote:
 

Oh. So there's no repository or service class I can use to retrieve the line item?

#78892
Dec 04, 2013 19:03
Vote:
 

BTW, before I forget, all Commerce forum posts should be entered EPiServer Commerce forum, link here:
http://world.episerver.com/Modules/Forum/Pages/Forum.aspx?id=40089&epslanguage=en

#78893
Dec 04, 2013 19:04
Vote:
 

Oh yea. You're right. I forgot about that. Can this thread be moved?

#78894
Dec 04, 2013 19:06
Vote:
 

I'm not sure if this thread can be moved, but I can check on that.

Regarding your other question about search, my colleague pointed out that there might be another way to do what you're looking to do based on this blog. Give it a quick read and let me know if that helps you. Especially item #6.

http://world.episerver.com/Blogs/Shannon-Gray/Dates/2012/12/EPiServer-Commerce-Order-Search-Made-Easy/

#78895
Dec 04, 2013 19:21
Vote:
 

It works but I keep getting this exception:

+ _innerException {"Validation Error: Number 205 - 'Defective authorization total' \n"} System.Exception {System.Workflow.ComponentModel.Compiler.WorkflowValidationFailedException}

#78897
Dec 04, 2013 20:47
Vote:
 

I think we'll need a little more context to solve that error. You should submit a support ticket.

#78899
Dec 05, 2013 0:50
Vote:
 

Okay.

#78953
Dec 05, 2013 15:00
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.