What I'm trying to do is export some specific products from an order (to a CSV file) once payment has been taken, and then to mark those products as processed so that anybody viewing the back end would be able to see that those products don't need to be included in any further shipment (they are offloaded to a third party).
The process is triggered once the Paypal IPN is received and we know the payment has been taken successfully and the code which exports the relevant products to a CSV file is working fine. The bit i'm having trouble with is marking the relevant products as shipped/processed.
From looking in the back end, I can see that you can use the action to "Fulfill" on an order, which allows you to create a shipment and select specific products from the order to be included in that shipment. So it seems the best way to achieve what I want would be to create a shipment programmatically after performing the CSV export and adding the relevant items to it.
I can see in the back end that once you create a shipment on an order, it then appears in the "shipments" tab when viewing that order and if the "Fulfill" action is used again, the system already knows which products are already included in a shipment. From this, its apparent that the shipment is linked to the invoice somehow but for the life of me I cant see where that link is created/recorded either in the database or in code. I see no reference to the invoice or order id from the shipment record.
Guid invoiceKey = Guid.Parse(successURL.ParseQueryString()["InvoiceKey"]);
var invoice = _merchelloContext.Services.InvoiceService.GetByKey(invoiceKey);
var shipmentStatus = _merchelloContext.Services.ShipmentService.GetAllShipmentStatuses().First(s => s.Alias == "packaging");
var defaultWarehouseAddress = _merchelloContext.Services.WarehouseService.GetDefaultWarehouse().AsAddress();
var shipment = _merchelloContext.Services.ShipmentService.CreateShipment(shipmentStatus, defaultWarehouseAddress, address, invoice.Items);
//I have created the shipment. Now how do I link it to the invoice?
_merchelloContext.Services.ShipmentService.Save(shipment);
From the code I have written, how do I link the newly created shipment to the pre existing invoice?
var shipment = _merchelloContext.Services.ShipmentService.CreateShipment(shipmentStatus, defaultWarehouseAddress, address, invoice.Items);
_merchelloContext.Services.ShipmentService.Save(shipment);
it now looks like this:
var shipment = _merchelloContext.Services.ShipmentService.CreateShipment(shipmentStatus, defaultWarehouseAddress, address);
shipment.Items.Add(invoice.Orders.First().Items);
_merchelloContext.Services.ShipmentService.Save(shipment);
I found that the overload of CreateShipment I was using previously tries to filter out non shippable line items but in the process makes copies of the line items which are missing important information like the primary key and orderKey of that line item, so when it comes to actually saving it, it tries to save with an empty guid for the orderKey hence the previous foreign key error.
With the new code it is now successfully creating the shipment which I can see in the database. The only problem is when i log in to the back end, view the relevant invoice and then click on the "Shipments" tab, the newly created shipment doesn't appear.
I have tracked it down to the InvoiceApicontroller.GetInvoice method in the Merchello.Web project getting a cached version of the invoice. So it seems I have to update the cache after adding the shipment. So far have tried adding the below after saving the shipment:
I have confirmed that it's a cache issue but its not automatically updating, even after a long period of time. After three days of no activity and then going back on to the system again it was still not showing the shipment against the relevant invoice.
However after manually deleting the contents of the App_Data/TEMP directory its now displaying correctly.
In addition to the above attempt to clear the cache, I have also tried this:
var IndexProvider = Examine.ExamineManager.Instance.IndexProviderCollection["MerchelloInvoiceIndexer"];
IndexProvider.DeleteFromIndex(invoice.Key.ToString());
But this doesn't work either. Any suggestions would be appreciated.
I ended up taking a different approach with it. My initial thoughts were to try to replicate what the backend was doing to create a shipment however the classes/methods used are marked as internal so are unavailable from outside the merchello assembly.
So I ended up calling the web api controller directly as below:
var shipmentApicontroller = new Web.Editors.ShipmentApiController();
var shipmentModel = new Web.Models.Shipping.ShipmentRequestDisplay();
shipmentModel.ShipmentStatusKey = shipmentStatus.Key;
shipmentModel.ShipMethodKey = new Guid("5f850937-de92-43bf-9808-792686022f10");
shipmentModel.TrackingNumber = "";
var shipmentOrderDetails = new Web.Models.ContentEditing.OrderDisplay();
shipmentModel.Order = shipmentOrderDetails;
shipmentOrderDetails.Key = order.Key;
var shipmentItems = new List<Web.Models.ContentEditing.OrderLineItemDisplay>();
foreach(var lineItem in shipmentLineItems)
{
var shipmentItem = new Web.Models.ContentEditing.OrderLineItemDisplay();
shipmentItems.Add(shipmentItem);
shipmentItem.Key = lineItem.Key;
}
shipmentOrderDetails.Items = shipmentItems;
shipmentApicontroller.NewShipment(shipmentModel);
Probably not a recommended way to use web api controllers but it's the only thing that has worked for me. Now the shipment is immediately visible in the back end.
I'm looking at all sorts of hacky ways at this point as well. Is there a better way to manually create a shipment outside of using any shipment providers at all? Any better approach a year later?
I started creating manual line items with a sku of something like "myShipSku" but then there is no way to set the "Ship To" under "Billing Address".
This way you can create a shipment and update the order status. Only thing not included is check if items are in stock and the part of the task chain that decreases the stock but that shouldn't be hard to implement.
// invoice
var invoice = _invoiceService.GetByKey(order.InvoiceKey);
var currentOrder = _orderService.GetByKey(order.Key);
// shipment line item
var shipmentLineItem = invoice.Items.FirstOrDefault(x => x.LineItemType == LineItemType.Shipping);
// the shipment
var quoted = shipmentLineItem.ExtendedData.GetShipment<InvoiceLineItem>();
var status = _shipmentService.GetShipmentStatusByKey(Merchello.Core.Constants.ShipmentStatus.Quoted);
var shipment = _shipmentService.CreateShipment(status, quoted.GetOriginAddress(), quoted.GetDestinationAddress());
shipment.ShipMethodKey = new Guid("96BBF5DD-D0AB-4CF5-ABE7-67F5312A9C91");
shipment.VersionKey = quoted.VersionKey;
shipment.Carrier = "";
shipment.TrackingCode = "";
shipment.TrackingUrl = "";
shipment.Items.Add(currentOrder.Items);
_shipmentService.Save(shipment);
var orderStatus = _orderService.GetOrderStatusByKey(Merchello.Core.Constants.OrderStatus.Open);
currentOrder.OrderStatus = orderStatus;
_orderService.Save(currentOrder);
manually create shipment for an order/invoice
What I'm trying to do is export some specific products from an order (to a CSV file) once payment has been taken, and then to mark those products as processed so that anybody viewing the back end would be able to see that those products don't need to be included in any further shipment (they are offloaded to a third party).
The process is triggered once the Paypal IPN is received and we know the payment has been taken successfully and the code which exports the relevant products to a CSV file is working fine. The bit i'm having trouble with is marking the relevant products as shipped/processed.
From looking in the back end, I can see that you can use the action to "Fulfill" on an order, which allows you to create a shipment and select specific products from the order to be included in that shipment. So it seems the best way to achieve what I want would be to create a shipment programmatically after performing the CSV export and adding the relevant items to it.
I can see in the back end that once you create a shipment on an order, it then appears in the "shipments" tab when viewing that order and if the "Fulfill" action is used again, the system already knows which products are already included in a shipment. From this, its apparent that the shipment is linked to the invoice somehow but for the life of me I cant see where that link is created/recorded either in the database or in code. I see no reference to the invoice or order id from the shipment record.
From the code I have written, how do I link the newly created shipment to the pre existing invoice?
Am I approaching this in the right way?
My merchello version is 1.11.
Note when I run the code above, no shipment is added to the database.
I think I have found the database link between the shipment and the invoice. There is an orderKey and a shipmentKey field on the merchOrderItem table.
Regarding the above code not creating a shipment, I have found that there is an exception thrown on the last line:
Note: the original idea to add the line items this way comes from here: https://gist.github.com/rustyswayne/598049064a02fce1597c#file-gistfile1-cs-L83
Made a bit of progress. Instead of this:
it now looks like this:
I found that the overload of CreateShipment I was using previously tries to filter out non shippable line items but in the process makes copies of the line items which are missing important information like the primary key and orderKey of that line item, so when it comes to actually saving it, it tries to save with an empty guid for the orderKey hence the previous foreign key error.
With the new code it is now successfully creating the shipment which I can see in the database. The only problem is when i log in to the back end, view the relevant invoice and then click on the "Shipments" tab, the newly created shipment doesn't appear.
So it seems i'm still missing something.
I have tracked it down to the InvoiceApicontroller.GetInvoice method in the Merchello.Web project getting a cached version of the invoice. So it seems I have to update the cache after adding the shipment. So far have tried adding the below after saving the shipment:
Which hasn't solved it.
I have confirmed that it's a cache issue but its not automatically updating, even after a long period of time. After three days of no activity and then going back on to the system again it was still not showing the shipment against the relevant invoice.
However after manually deleting the contents of the App_Data/TEMP directory its now displaying correctly.
In addition to the above attempt to clear the cache, I have also tried this:
But this doesn't work either. Any suggestions would be appreciated.
I ended up taking a different approach with it. My initial thoughts were to try to replicate what the backend was doing to create a shipment however the classes/methods used are marked as internal so are unavailable from outside the merchello assembly.
So I ended up calling the web api controller directly as below:
Probably not a recommended way to use web api controllers but it's the only thing that has worked for me. Now the shipment is immediately visible in the back end.
Hi, i just what i need.. thanks a lot
Hey Ryan,
I'm looking at all sorts of hacky ways at this point as well. Is there a better way to manually create a shipment outside of using any shipment providers at all? Any better approach a year later?
I started creating manual line items with a sku of something like "myShipSku" but then there is no way to set the "Ship To" under "Billing Address".
Hello
This way you can create a shipment and update the order status. Only thing not included is check if items are in stock and the part of the task chain that decreases the stock but that shouldn't be hard to implement.
is working on a reply...