diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj
index 1d23077..c08430a 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj
@@ -1,6 +1,6 @@
- 10.4.22
+ 10.4.23
1.0.0.0
Live Integration
Live Integration
@@ -24,8 +24,10 @@
+
+
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Licensing/LicenseService.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Licensing/LicenseService.cs
index 51d530b..42eb3b7 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Licensing/LicenseService.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Licensing/LicenseService.cs
@@ -47,11 +47,7 @@ internal static void ValidateLicense(string endpoint, string response, Logger lo
var status = GetStatus(endpoint);
if (status == null || status.Expired)
{
- if (!Helpers.ParseResponseToXml(response, logger, out XmlDocument doc))
- {
- logger.Log(ErrorLevel.DebugInfo, $"License Response is not valid XML");
- }
- else
+ if (Helpers.ParseResponseToXml(response, logger, out XmlDocument doc))
{
ValidateLicense(doc, endpoint, status, logger);
}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs
index b7dd3c3..1eae2c6 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs
@@ -120,6 +120,7 @@ private static ResponseCacheLevel GetOrderCacheLevel(Settings settings)
string lastHash = GetLastOrderHash(settings);
if (liveIntegrationSubmitType != SubmitType.ScheduledTask && liveIntegrationSubmitType != SubmitType.CaptureTask &&
+ liveIntegrationSubmitType != SubmitType.ManualSubmit &&
!string.IsNullOrEmpty(lastHash) && lastHash == currentHash)
{
// no changes to order
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs
new file mode 100644
index 0000000..2eeacec
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs
@@ -0,0 +1,96 @@
+using Dynamicweb.CoreUI.Data;
+using Dynamicweb.CoreUI.Data.Validation;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Logging;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.XmlGenerators;
+using Dynamicweb.Ecommerce.Orders;
+using System.IO;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Commands;
+
+public sealed class DownloadOrderXmlCommand : CommandBase
+{
+ [Required]
+ public string OrderId { get; set; }
+
+ [Required]
+ public bool GetOriginalXml { get; set; }
+
+ public override CommandResult Handle()
+ {
+ var order = Services.Orders.GetById(OrderId);
+ if (order is null)
+ {
+ return new CommandResult
+ {
+ Message = $"The order with id: '{OrderId}' was not found",
+ Status = CommandResult.ResultType.NotFound
+ };
+ }
+
+ Settings settings = SettingsManager.GetSettingsByShop(order.ShopId);
+ if (settings is null && !GetOriginalXml)
+ {
+ return new CommandResult
+ {
+ Message = $"No active Dynamicweb Live integration instance found for Order id: {order.Id} and Shop Id: {order.ShopId}.",
+ Status = CommandResult.ResultType.NotFound
+ };
+ }
+
+ var fileName = $"Order_{order.Id}.xml";
+ var xml = GetOriginalXml ? GetOrderOriginalXml(order) : GetOrderCurrentXml(settings, order);
+
+ var stream = new MemoryStream();
+ using (var writeFile = new StreamWriter(stream, leaveOpen: true))
+ {
+ writeFile.Write(xml);
+ }
+ stream.Position = 0;
+
+ return new CommandResult
+ {
+ Status = CommandResult.ResultType.Ok,
+ Model = new FileResult
+ {
+ FileStream = stream,
+ ContentType = "application/octet-stream",
+ FileDownloadName = fileName
+ }
+ };
+ }
+
+ ///
+ /// Occurs when the button was clicked from edit order page. Gets the XML for the order and returns it to the browser.
+ ///
+ private static string GetOrderCurrentXml(Settings settings, Order order)
+ {
+ var logger = new Logger(settings);
+ var xmlGeneratorSettings = new OrderXmlGeneratorSettings
+ {
+ AddOrderLineFieldsToRequest = settings.AddOrderLineFieldsToRequest,
+ AddOrderFieldsToRequest = settings.AddOrderFieldsToRequest,
+ CreateOrder = true,
+ Beautify = true,
+ LiveIntegrationSubmitType = SubmitType.DownloadedFromBackEnd,
+ ReferenceName = "OrdersPut",
+ ErpControlsDiscount = settings.ErpControlsDiscount,
+ ErpControlsShipping = settings.ErpControlsShipping,
+ ErpShippingItemKey = settings.ErpShippingItemKey,
+ ErpShippingItemType = settings.ErpShippingItemType,
+ CalculateOrderUsingProductNumber = settings.CalculateOrderUsingProductNumber
+ };
+ return new OrderXmlGenerator().GenerateOrderXml(settings, order, xmlGeneratorSettings, logger);
+ }
+
+ ///
+ /// Gets the original XML by reading the original file from disk.
+ ///
+ private static string GetOrderOriginalXml(Order order) => File.ReadAllText(BuildXmlFileName(order));
+
+ internal static string BuildXmlFileName(Order order)
+ {
+ return OrderHandler.BuildXmlCopyPath(order.Id, OrderHandler.GetLogFolderForXmlCopies(order.CompletedDate));
+ }
+}
+
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/TransferOrderToErpCommand.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/TransferOrderToErpCommand.cs
new file mode 100644
index 0000000..4e6bd40
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/TransferOrderToErpCommand.cs
@@ -0,0 +1,42 @@
+using Dynamicweb.CoreUI.Data;
+using Dynamicweb.CoreUI.Data.Validation;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Commands;
+
+public sealed class TransferOrderToErpCommand : CommandBase
+{
+ [Required]
+ public string OrderId { get; set; }
+
+ public override CommandResult Handle()
+ {
+ var order = Services.Orders.GetById(OrderId);
+ if (order is null)
+ {
+ return new CommandResult
+ {
+ Message = $"The order with id: '{OrderId}' was not found",
+ Status = CommandResult.ResultType.NotFound
+ };
+ }
+
+ Settings settings = SettingsManager.GetSettingsByShop(order.ShopId);
+ if (settings is null)
+ {
+ return new CommandResult
+ {
+ Message = $"No active Dynamicweb Live integration instance found for Order id: {order.Id} and Shop Id: {order.ShopId}.",
+ Status = CommandResult.ResultType.NotFound
+ };
+ }
+
+ bool result = OrderHandler.UpdateOrder(settings, order, SubmitType.ManualSubmit) ?? false;
+ return new CommandResult
+ {
+ Message = result ? "Order successfully transferred to ERP" : "Error creating order in ERP. Check the LiveIntegration log for details",
+ Status = result ? CommandResult.ResultType.Ok : CommandResult.ResultType.Error
+ };
+ }
+}
+
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/TransferOrdersToErpCommand.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/TransferOrdersToErpCommand.cs
new file mode 100644
index 0000000..cc06e03
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/TransferOrdersToErpCommand.cs
@@ -0,0 +1,102 @@
+using Dynamicweb.CoreUI.Data;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+using Dynamicweb.Ecommerce.Orders;
+using Dynamicweb.Ecommerce.UI.Commands;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Commands;
+
+public sealed class TransferOrdersToErpCommand : OrderBulkActionCommand
+{
+ public override CommandResult Handle()
+ {
+ var orders = GetSelectedOrders().ToList();
+ if (orders.Count == 0)
+ {
+ return new()
+ {
+ Status = CommandResult.ResultType.NotFound,
+ Message = "The selected Orders could not be found"
+ };
+ }
+
+ List exportedOrders = new List();
+ List alreadyExportedOrders = new List();
+
+ foreach (var order in orders)
+ {
+ if (string.IsNullOrEmpty(order.IntegrationOrderId))
+ {
+ var settings = SettingsManager.GetSettingsByShop(order.ShopId);
+ if (settings is null)
+ continue;
+
+ bool exported = OrderHandler.UpdateOrder(settings, order, SubmitType.ManualSubmit) ?? false;
+ if (exported)
+ {
+ exportedOrders.Add(order.Id);
+ }
+ }
+ else
+ {
+ alreadyExportedOrders.Add(order.Id);
+ }
+ }
+
+ var message = GetExportedOrdersMessage(orders, exportedOrders, alreadyExportedOrders, out var success);
+
+ return new()
+ {
+ Status = success ? CommandResult.ResultType.Ok : CommandResult.ResultType.Error,
+ Message = message
+ };
+ }
+
+ ///
+ /// Gets the exported orders message.
+ ///
+ /// System.String.
+ private static string GetExportedOrdersMessage(List orders, List exportedOrders, List alreadyExportedOrders, out bool success)
+ {
+ string output = string.Empty;
+ success = false;
+
+ if (alreadyExportedOrders.Count > 0 && alreadyExportedOrders.Count == orders.Count())
+ {
+ output = "All selected orders are already transferred to ERP.";
+ success = true;
+ }
+ else if (exportedOrders.Count > 0 || alreadyExportedOrders.Count > 0)
+ {
+ if ((exportedOrders.Count + alreadyExportedOrders.Count) == orders.Count())
+ {
+ output = "All selected orders were successfully transferred to ERP.";
+ success = true;
+ }
+ else
+ {
+ if (alreadyExportedOrders.Count > 0)
+ {
+ output += $"Orders with IDs [{string.Join(",", alreadyExportedOrders)}] were already transferred to ERP. ";
+ }
+
+ if (exportedOrders.Count > 0)
+ {
+ output += $"Orders with IDs [{string.Join(",", exportedOrders)}] were successfully transferred to ERP. ";
+ }
+
+ output += $"Orders with IDs [{string.Join(",", orders
+ .Where(o => !(exportedOrders.Contains(o.Id) ||
+ alreadyExportedOrders.Contains(o.Id)))
+ .Select(o => o.Id).Distinct().ToArray())}] were not transferred to ERP. Check the LiveIntegration log for details";
+ }
+ }
+ else
+ {
+ output = "None of the selected orders were transferred to ERP. Check the LiveIntegration log for details.";
+ }
+
+ return output;
+ }
+}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderEditScreenInjector.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderEditScreenInjector.cs
new file mode 100644
index 0000000..9e7088d
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderEditScreenInjector.cs
@@ -0,0 +1,94 @@
+using Dynamicweb.CoreUI.Actions;
+using Dynamicweb.CoreUI.Actions.Implementations;
+using Dynamicweb.CoreUI.Icons;
+using Dynamicweb.CoreUI.Screens;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Commands;
+using Dynamicweb.Ecommerce.Orders;
+using Dynamicweb.Ecommerce.UI.Models;
+using Dynamicweb.Ecommerce.UI.Screens;
+using System.Collections.Generic;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Injectors
+{
+ public sealed class OrderEditScreenInjector : EditScreenInjector
+ {
+ internal static readonly string LiveIntegrationTab = "Live Integration";
+
+ public override IEnumerable GetScreenActions()
+ {
+ return GetOrderScreenActions(Screen?.Model?.Id, Screen?.Model?.IntegrationOrderId);
+ }
+
+ internal static List GetOrderScreenActions(string orderId, string integrationOrderId)
+ {
+ var order = Services.Orders.GetById(orderId);
+ if (order is null)
+ return [];
+
+ var settings = SettingsManager.GetSettingsByShop(order.ShopId);
+ bool isLiveIntegrationFound = settings is not null;
+
+ if (isLiveIntegrationFound)
+ {
+ bool exported = !string.IsNullOrEmpty(integrationOrderId);
+ var actionNodes = new List()
+ {
+ new()
+ {
+ Name = "Transfer via Live Integration",
+ Title = exported ? "Order already transferred" : "Transfer to ERP via Live Integration",
+ Icon = Icon.SignOutAlt,
+ NodeAction = ConfirmAction.For(RunCommandAction.For(new TransferOrderToErpCommand { OrderId = orderId }).WithReloadOnSuccess(),
+ "Transfer to ERP via Live Integration?",
+ exported ? $"Order {orderId} is already in the ERP, update again?" : $"Transfer order {orderId} to ERP via Live Integration?")
+ }
+ };
+ actionNodes.AddRange(GetOrderExportToXmlActions(settings, order));
+
+ return new List()
+ {
+ new()
+ {
+ Name = LiveIntegrationTab,
+ Title = LiveIntegrationTab,
+ Nodes = actionNodes
+ }
+ };
+ }
+
+ return [];
+ }
+
+ private static IEnumerable GetOrderExportToXmlActions(Settings settings, Order order)
+ {
+ bool saveOrderXml = settings.SaveCopyOfOrderXml;
+
+ bool enableButton = saveOrderXml && System.IO.File.Exists(DownloadOrderXmlCommand.BuildXmlFileName(order));
+
+ return [
+ new ActionNode()
+ {
+ Icon = Icon.FileDownload,
+ Name = "Original XML",
+ Title = enableButton ?
+ "Downloads the original XML for an order as sent to the ERP" :
+ !saveOrderXml ?
+ "This option is not available because saving XML files is not enabled in the Live Integration setup." :
+ "This option is not available because the XML file does not exist.",
+ Disabled = !enableButton,
+ NodeAction = enableButton ? DownloadFileAction.Using(new DownloadOrderXmlCommand { OrderId = order.Id, GetOriginalXml = true }) : null
+ },
+
+ new ActionNode()
+ {
+ Icon = Icon.FileDownload,
+ Name = "Current XML",
+ Title = "Exports the order to an XML document",
+ NodeAction = DownloadFileAction.Using(new DownloadOrderXmlCommand { OrderId = order.Id, GetOriginalXml = false })
+ }
+ ];
+ }
+ }
+}
+
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderListScreenInjector.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderListScreenInjector.cs
new file mode 100644
index 0000000..ab688fc
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderListScreenInjector.cs
@@ -0,0 +1,46 @@
+using Dynamicweb.CoreUI.Actions;
+using Dynamicweb.CoreUI.Actions.Implementations;
+using Dynamicweb.CoreUI.Icons;
+using Dynamicweb.CoreUI.Screens;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Commands;
+using Dynamicweb.Ecommerce.UI.Models;
+using Dynamicweb.Ecommerce.UI.Screens;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Injectors;
+
+public sealed class OrderListScreenInjector : ListScreenInjector
+{
+ public override IEnumerable GetScreenActions()
+ {
+ if (SettingsManager.ActiveSettingsByShopId.Count == 0 ||
+ Screen?.Model?.Data is null ||
+ Screen?.Query is null ||
+ !Screen.Model.Data.Any(o => SettingsManager.GetSettingsByShop(o.ShopId) is not null))
+ return [];
+
+ return new List()
+ {
+ new()
+ {
+ Name = OrderEditScreenInjector.LiveIntegrationTab,
+ Title = OrderEditScreenInjector.LiveIntegrationTab,
+ Nodes = new List()
+ {
+ new ActionNode()
+ {
+ Name = "Transfer via Live Integration",
+ Title = "Transfer to ERP via Live Integration",
+ Icon = Icon.SignOutAlt,
+ NodeAction = ConfirmAction.For(RunCommandAction.For().With(Screen.Query).WithReloadOnSuccess(),
+ "Transfer to ERP via Live Integration?",
+ "Transfer selected orders to ERP via Live Integration?")
+ }
+ }
+ }
+ };
+
+ }
+}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderOverviewScreenInjector.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderOverviewScreenInjector.cs
new file mode 100644
index 0000000..2ac6f34
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Injectors/OrderOverviewScreenInjector.cs
@@ -0,0 +1,21 @@
+using Dynamicweb.CoreUI;
+using Dynamicweb.CoreUI.Layout;
+using Dynamicweb.CoreUI.Screens;
+using Dynamicweb.Ecommerce.UI.Screens;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.UI.Injectors;
+
+public sealed class OrderOverviewScreenInjector : ScreenInjector
+{
+ public override void OnAfter(OrderOverviewScreen screen, UiComponentBase content)
+ {
+ if (!content.TryGet(out var layout))
+ return;
+
+ var actions = OrderEditScreenInjector.GetOrderScreenActions(Screen?.Model?.Id, Screen?.Model?.IntegrationOrderId);
+ if (actions.Count > 0)
+ {
+ layout.ContextActionGroups.AddRange(actions);
+ }
+ }
+}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs
index 6e2eee3..6af86f5 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs
@@ -89,7 +89,7 @@ private void AddOrderDeliveryInformation(OrderXmlGeneratorSettings settings, Xml
deliveryAddress = UserManagementServices.UserAddresses.GetAddressById(order.DeliveryAddressId);
}
string deliveryName = (deliveryAddress is object && !string.IsNullOrEmpty(order.DeliveryName)) ? order.DeliveryName :
- !string.IsNullOrWhiteSpace(order.CustomerName) ? order.CustomerName : user.Name;
+ !string.IsNullOrWhiteSpace(order.CustomerName) ? order.CustomerName : user?.Name ?? "";
AddChildXmlNode(orderNode, "OrderDeliveryName", deliveryName);
AddChildXmlNode(orderNode, "OrderDeliveryAddress", order.DeliveryAddress);