November Happy Hour will be moved to Thursday December 5th.

Splitting shipments and recalculating totals

Vote:
 

Hi All,

Commerce version 12.5.0

What is the correct way to split shipments in code?  For example, I have a shipment that has 1 lineitem qty 5. Via integration we receive a request to split the shipment (for whatever reason) into 2 shipments.  Shipment 1 has qty 2, Shipment 2 has qty 3.

Currently we create the shipment via OrderGroupExtensions, set the shipping method (this is a $0 shipping method since we don't want to charge for shipping again), add lineitems (again via CreateLineItem in OrderGroupExtensions), set appropriate properties, etc.  Then call ReleaseShipment on the ShipmentProcessor and Save on the OrderRepository - this all seems to work fine on a straight forward shipment.  What I've noticed on a lineitem that has a discount is that the LineItemDiscountAmount doesn't get updated for the original or split item, so I think I either need to do that manually or call a Processor/Calculator..?  Any advise on process or sample code would be great.

Thanks
Mark

#198424
Oct 29, 2018 4:42
Vote:
 

Normally splitting shipment should mean recalculating discounts because changed shipping total etc. Means different discounts and taxes. Do you have a reason not to?

#198431
Oct 29, 2018 7:49
Vote:
 

No reason, someone else wrote this code, so just trying to determine best approach.

At this point we are dealing with a PO.

So would you recommend something like ValidateAndCalculateOrder in the IOrderGroupExtensions?

orderGroup.ValidateOrRemoveLineItems
orderGroup.AdjustInventoryOrRemoveLineItems
orderGroup.ApplyDiscounts

Thanks
Mark

#198474
Oct 29, 2018 14:22
Vote:
 

That looks about right. I know we have checks that make sure splitting shipment will work properly - i.e. you already reserved 5 for the shipment, you don't have to worry about cancelling that and reserve 2 and 3. 

#198475
Oct 29, 2018 14:24
Vote:
 

I'm still having issues with this. Once a lineitem has been split into multiple shipments as per my original question, what is the correct way to split the lineitem discount? or should that happen automatically?

var newShipment = po.CreateShipment(orderGroupFactory);
// Set shipment properties, i.e. shipping method, shipping address
po.AddShipment(newShipment);

var splitLineitem = po.CreateLineItem(lineitem.Code, orderGroupFactory);
// Set lineitem properties, i.e. quantity, price, etc...
splitShipment.LineItems.Add(splitLineitem);

po.UpdateShipmentLineItemQuantity(lineitem.LineItemId, (Shipment)shipment, lineitem.Quantity - splitItem.Quantity);

_shipmentProcessor.ReleaseShipment(po, splitShipment);

_orderRepository.Save(po);

I believe Save calls "CalculateTotals" on the order group, but do I need to do anything else?

Are there any updated examples of manipulating purchase orders using the new api? i.e specifically splitting a lineitem.

#198713
Nov 05, 2018 6:54
Vote:
 

If you run the promotion engine (i.e. ApplyDiscounts ) again, the discount should be properly distributed

#198715
Edited, Nov 05, 2018 8:04
Vote:
 

I'm reluctant to do that since I'm not sure when the split will occur, i.e. straight away or days later.  If days later the promotion may not be valid anymore or a new promotion may be applied when it shouldn't.  I want the discount that is currently applied to just be distributed correctly after the split occurs.

#198717
Nov 05, 2018 8:30
Vote:
 

If you are going to split shipments after the day it is created, it is much trickier and you can't get it to be perfectly accurate. For example you might have shipping promotion that give free shipping (or a discount) if the shipping cost is > $100. But if you accepts some quirks and inaccuracies, you can look into ILineItemDiscountAmount. Here you can set EntryAmount and OrderAmount that are lineitem-level discount amount and order-level discount amount to distribute the discounts 

#198719
Nov 05, 2018 11:00
Vote:
 

Thanks Quan, Yeah I was already setting the entry amount in ILineItemDiscountAmount, but the value wouldn't persist.  I worked out my issue in the end and created a method similar to PurchaseOrderManager.UpdateShipmentLineItemQuantity

i.e.

var originalLineItem = ((Shipment)shipment).Parent.LineItems.FirstOrDefault(x => x.LineItemId == lineItem.LineItemId);
originalLineItem?.SetEntryDiscountValue(entryAmount);
#198757
Nov 06, 2018 6:03
Vote:
 

This is the implementation of SetEntryDiscountValue

            var lineItemDiscountAmounts = lineItem as ILineItemDiscountAmount;
            if (lineItemDiscountAmounts == null)
            {
                return;
            }

            lineItemDiscountAmounts.EntryAmount = value;

unless I'm missing something by a very early morning, how is that different?

#198758
Nov 06, 2018 6:08
Vote:
 

Just to make sure - the values won't be persisted until you save it. 

#198759
Nov 06, 2018 6:09
Vote:
 

I'm iterating through the lineitems in a specific shipment to determine which ones need to be split.  So my issue was updating the value on the original lineitem, setting the value on the newly created lineitem wasn't an issue. Where I was trying to set the value my lineitem was actually a SerializableLineItem rather than a LineItem, so when I call _orderRepository.Save(po) the value didn't persist.

For the new lineitem I use

newItem.TrySetDiscountValue(l => l.EntryAmount, newEntryAmount);
#198760
Nov 06, 2018 6:19
* 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.