diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Examples/Notifications/OrderAfterGenerateXmlSubscriber.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Examples/Notifications/OrderAfterGenerateXmlSubscriber.cs
index 19af2f5..45d53a5 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Examples/Notifications/OrderAfterGenerateXmlSubscriber.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Examples/Notifications/OrderAfterGenerateXmlSubscriber.cs
@@ -25,7 +25,7 @@ public override void OnNotify(string notification, NotificationArgs args)
if (myArgs?.Document != null)
{
var settings = SettingsManager.GetSettingsByShop(myArgs.Order.ShopId);
- if (settings != null && !settings.ErpControlsShipping)
+ if (settings != null && settings.ShippingControlMode == Constants.ShippingControlMode.DynamicwebControlsShipping)
{
var order = myArgs.Order;
var shipping = Services.Shippings.GetShipping(order.ShippingMethodId);
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Constants.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Constants.cs
index b38da14..d34d157 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Constants.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Constants.cs
@@ -77,5 +77,24 @@ internal static class OrderConfiguration
public const string DefaultShippingItemType = "ItemCharge";
}
+
+ ///
+ /// Provides string constants that define the available modes for controlling shipping calculation and data
+ /// exchange between Dynamicweb and an ERP system.
+ ///
+ /// Use these constants to specify how shipping fees and information are managed in
+ /// integrations between Dynamicweb and ERP systems. Each mode determines whether shipping is calculated by
+ /// Dynamicweb, by the ERP, or based on selections made in Dynamicweb and processed by the ERP.
+ public static class ShippingControlMode
+ {
+ /// Dynamicweb calculates and sends the shipping fee to the ERP.
+ public const string DynamicwebControlsShipping = "DynamicwebControlsShipping";
+
+ /// ERP controls shipping entirely; no shipping data is sent from Dynamicweb.
+ public const string ErpControlsShipping = "ErpControlsShipping";
+
+ /// The customer selects a shipping method in Dynamicweb; the ERP calculates the freight cost based on the selected method's identity fields.
+ public const string ErpCalculatesBasedOnDwSelection = "ErpCalculatesBasedOnDwSelection";
+ }
}
}
\ No newline at end of file
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/ISettings.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/ISettings.cs
index f89c013..f6003e2 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/ISettings.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/ISettings.cs
@@ -266,9 +266,16 @@ public interface ISettings
string ErpShippingItemKey { get; set; }
///
- /// Gets or sets if ERP controls shipping calculations
+ /// Gets or sets the shipping control mode.
///
- /// true if [ERP controls shipping calculations]; otherwise, false.
+ string ShippingControlMode { get; set; }
+
+ ///
+ /// Gets or sets whether the ERP controls shipping. Use instead.
+ /// Setting false switches to ;
+ /// setting true restores .
+ ///
+ [System.Obsolete("Use ShippingControlMode instead.")]
bool ErpControlsShipping { get; set; }
///
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Settings.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Settings.cs
index 46743a7..b540e36 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Settings.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Configuration/Settings.cs
@@ -40,7 +40,7 @@ public Settings()
WebServiceConnectionStatusGlobalTagName = "Global:LiveIntegration.IsWebServiceConnectionAvailable";
ErpControlsDiscount = true;
- ErpControlsShipping = true;
+ ShippingControlMode = Constants.ShippingControlMode.ErpControlsShipping;
SetOrderlineFixed = false;
@@ -263,10 +263,33 @@ public string InstanceName
public bool ErpControlsDiscount { get; set; }
///
- /// Gets or sets if ERP controls shipping
+ /// Gets or sets the shipping control mode.
///
- /// true if [ERP controls shipping]; otherwise, false.
- public bool ErpControlsShipping { get; set; }
+ public string ShippingControlMode
+ {
+ get => _shippingControlMode;
+ set => _shippingControlMode = NormalizeShippingControlMode(value);
+ }
+ private string _shippingControlMode;
+
+ private static string NormalizeShippingControlMode(string value)
+ {
+ if (string.Equals(value, Constants.ShippingControlMode.DynamicwebControlsShipping, StringComparison.OrdinalIgnoreCase))
+ return Constants.ShippingControlMode.DynamicwebControlsShipping;
+ if (string.Equals(value, Constants.ShippingControlMode.ErpCalculatesBasedOnDwSelection, StringComparison.OrdinalIgnoreCase))
+ return Constants.ShippingControlMode.ErpCalculatesBasedOnDwSelection;
+ return Constants.ShippingControlMode.ErpControlsShipping;
+ }
+
+ ///
+ [Obsolete("Use ShippingControlMode instead.")]
+ public bool ErpControlsShipping
+ {
+ get => ShippingControlMode != Constants.ShippingControlMode.DynamicwebControlsShipping;
+ set => ShippingControlMode = value
+ ? Constants.ShippingControlMode.ErpControlsShipping
+ : Constants.ShippingControlMode.DynamicwebControlsShipping;
+ }
///
/// Gets or sets the key for shipping item type.
@@ -470,7 +493,7 @@ public static void UpdateFrom(ISettings source, ISettings target)
target.SkipLedgerOrder = source.SkipLedgerOrder;
target.ErpControlsDiscount = source.ErpControlsDiscount;
target.DisableErpDiscountsForAnonymousUsers = source.DisableErpDiscountsForAnonymousUsers;
- target.ErpControlsShipping = source.ErpControlsShipping;
+ target.ShippingControlMode = source.ShippingControlMode;
target.ErpShippingItemType = source.ErpShippingItemType;
target.ErpShippingItemKey = source.ErpShippingItemKey;
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj
index c96f75e..cab6f7c 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj
@@ -1,6 +1,6 @@
- 10.21.5
+ 10.21.6
1.0.0.0
Live Integration
Live Integration
@@ -19,7 +19,7 @@
true
true
true
- true
+ true
snupkg
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.sln b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.sln
new file mode 100644
index 0000000..cdb2341
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Dynamicweb.Ecommerce.DynamicwebLiveIntegration.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dynamicweb.Ecommerce.DynamicwebLiveIntegration", "Dynamicweb.Ecommerce.DynamicwebLiveIntegration.csproj", "{5B09B2C6-8E15-A19A-AA43-E303D71A0874}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5B09B2C6-8E15-A19A-AA43-E303D71A0874}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5B09B2C6-8E15-A19A-AA43-E303D71A0874}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5B09B2C6-8E15-A19A-AA43-E303D71A0874}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5B09B2C6-8E15-A19A-AA43-E303D71A0874}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8116CA11-5865-48E8-9C90-5CBF48FF6A82}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveIntegrationAddIn.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveIntegrationAddIn.cs
index d9d1e04..1a3bfbb 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveIntegrationAddIn.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveIntegrationAddIn.cs
@@ -381,14 +381,23 @@ public LiveIntegrationAddIn()
public bool ErpControlsDiscount { get; set; }
///
- /// Gets or sets if ERP controls shipping calculations
+ /// Gets or sets the shipping control mode.
///
- /// true if [ERP controls shipping calculations]; otherwise, false.
- [AddInParameter("ERP controls shipping calculations")]
- [AddInParameterEditor(typeof(YesNoParameterEditor), "")]
+ [AddInParameter("Shipping control")]
+ [AddInParameterEditor(typeof(DropDownParameterEditor), "none=false")]
[AddInParameterGroup("Orders")]
[AddInParameterOrder(157)]
- public bool ErpControlsShipping { get; set; }
+ public string ShippingControlMode { get; set; }
+
+ ///
+ [Obsolete("Use ShippingControlMode instead.")]
+ public bool ErpControlsShipping
+ {
+ get => ShippingControlMode != Constants.ShippingControlMode.DynamicwebControlsShipping;
+ set => ShippingControlMode = value
+ ? Constants.ShippingControlMode.ErpControlsShipping
+ : Constants.ShippingControlMode.DynamicwebControlsShipping;
+ }
///
/// Gets or sets the key for shipping item type.
@@ -750,11 +759,16 @@ IEnumerable IParameterOptions.GetParameterOptions(string dropdo
options.Add(new("Fixed Asset", "FixedAsset"));
options.Add(new("Resource", "Resource"));
break;
+ case "Shipping control":
+ options.Add(new("Dynamicweb controls shipping", Constants.ShippingControlMode.DynamicwebControlsShipping));
+ options.Add(new("ERP controls shipping", Constants.ShippingControlMode.ErpControlsShipping));
+ options.Add(new("ERP calculates shipping cost based on Dynamicweb selection", Constants.ShippingControlMode.ErpCalculatesBasedOnDwSelection));
+ break;
case "ConnectionToType":
options.Add(new(nameof(ConnectionType.Endpoint), ConnectionType.Endpoint));
options.Add(new("Dynamicweb connector web service", ConnectionType.WebService));
break;
- case "ERP Local Currency":
+ case "ERP Local Currency":
foreach (var currency in Services.Currencies.GetAllCurrencies())
{
options.Add(new($"{currency.GetName(Services.Languages.GetDefaultLanguageId())} - {currency.Code}", currency.Code));
@@ -796,7 +810,7 @@ IEnumerable IParameterVisibility.GetHiddenParameterNames(string paramete
result.Add("Include variants in the product information request");
result.Add("Max products per request");
}
- break;
+ break;
}
return result;
}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs
index 891b0dd..aaac6e0 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/OrderHandler.cs
@@ -6,6 +6,7 @@
using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Discounts;
using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Extensions;
using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Logging;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Shipping;
using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.XmlGenerators;
using Dynamicweb.Ecommerce.Orders;
using Dynamicweb.Ecommerce.Prices;
@@ -91,6 +92,12 @@ private static ResponseCacheLevel GetOrderCacheLevel(Settings settings)
bool erpControlsDiscount = user.IsUserErpDiscountAllowed(settings);
+ if (IsAllOrderLinesDiscounts(erpControlsDiscount, order, liveIntegrationSubmitType))
+ {
+ Diagnostics.ExecutionTable.Current.Add("DynamicwebLiveIntegration.OrderHandler.UpdateOrder END");
+ return null;
+ }
+
// default states
successOrderStateId ??= settings.OrderStateAfterExportSucceeded;
@@ -103,7 +110,7 @@ private static ResponseCacheLevel GetOrderCacheLevel(Settings settings)
LiveIntegrationSubmitType = liveIntegrationSubmitType,
ReferenceName = "OrdersPut",
ErpControlsDiscount = erpControlsDiscount,
- ErpControlsShipping = settings.ErpControlsShipping,
+ ShippingControlMode = settings.ShippingControlMode,
ErpShippingItemKey = settings.ErpShippingItemKey,
ErpShippingItemType = settings.ErpShippingItemType,
CalculateOrderUsingProductNumber = settings.CalculateOrderUsingProductNumber,
@@ -904,7 +911,7 @@ private static bool ProcessResponse(in OrderResponseContext ctx, XmlDocument res
{
XmlNode orderNode = response.SelectSingleNode("//item [@table='EcomOrders']");
PriceInfo shippingFeeSentInRequest = null;
- if (!createOrder && !ctx.Settings.ErpControlsShipping && !string.IsNullOrEmpty(order.ShippingMethodId))
+ if (!createOrder && ctx.Settings.ShippingControlMode == Constants.ShippingControlMode.DynamicwebControlsShipping && !string.IsNullOrEmpty(order.ShippingMethodId))
{
shippingFeeSentInRequest = order.ShippingFee;
}
@@ -954,8 +961,15 @@ private static bool ProcessResponse(in OrderResponseContext ctx, XmlDocument res
else
{
SetOrderPrices(order, orderNode, ctx, logger, orderId, out updatePriceBeforeFeesFromOrderPrice);
+ }
+ if (ctx.Settings.ShippingControlMode == Constants.ShippingControlMode.ErpCalculatesBasedOnDwSelection)
+ {
+ ErpShippingFeeProvider.ProcessShipping(ctx.Settings, order, orderNode, logger);
+ }
+ else if (ctx.Settings.ShippingControlMode != Constants.ShippingControlMode.DynamicwebControlsShipping)
+ {
+ LiveShippingFeeProvider.ProcessShipping(ctx.Settings, order, orderNode, logger);
}
- LiveShippingFeeProvider.ProcessShipping(ctx.Settings, order, orderNode, logger);
}
else
{
@@ -979,7 +993,7 @@ private static bool ProcessResponse(in OrderResponseContext ctx, XmlDocument res
}
else
{
- if (!ctx.Settings.ErpControlsShipping && shippingFeeSentInRequest != null)
+ if (ctx.Settings.ShippingControlMode == Constants.ShippingControlMode.DynamicwebControlsShipping && shippingFeeSentInRequest != null)
{
UpdateDynamicwebShipping(order, orderNode, shippingFeeSentInRequest, ctx.Settings, logger, updatePriceBeforeFeesFromOrderPrice);
}
@@ -1174,7 +1188,7 @@ private static void SetPrices(Settings settings, Order order, XmlNode orderNode,
/// The order node.
private static void SetShippingWarning(Settings settings, Order order, XmlNode orderNode)
{
- if (!settings.ErpControlsShipping)
+ if (settings.ShippingControlMode == Constants.ShippingControlMode.DynamicwebControlsShipping)
{
var node = orderNode.SelectSingleNode("column [@columnName='OrderShippingWarning']");
if (node != null)
@@ -1397,6 +1411,19 @@ internal static void SetCurrentlyProcessingOrder(Order order)
internal static void RemoveCurrentlyProcessingOrder(Order order)
{
Caching.Cache.Current.Remove(OrderCacheKey(order));
- }
+ }
+
+ private static bool IsAllOrderLinesDiscounts(bool erpControlsDiscountForUser, Order order, SubmitType liveIntegrationSubmitType)
+ {
+ //If no product lines and all lines are discounts remove discount lines and recalculate order
+ if (!order.Complete && erpControlsDiscountForUser && liveIntegrationSubmitType == SubmitType.LiveOrderOrCart && order.OrderLines.All(ol => ol.IsDiscount()))
+ {
+ order.OrderLines.RemoveDiscounts();
+ order.AllowOverridePrices = false;
+ Services.Orders.ForcePriceRecalculation(order);
+ return true;
+ }
+ return false;
+ }
}
}
\ No newline at end of file
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/CartAfterShippingCalculation.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/CartAfterShippingCalculation.cs
new file mode 100644
index 0000000..92f5b8f
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/CartAfterShippingCalculation.cs
@@ -0,0 +1,31 @@
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.NotificationSubscribers;
+using Dynamicweb.Ecommerce.Prices;
+using Dynamicweb.Extensibility.Notifications;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Shipping
+{
+ [Subscribe(Ecommerce.Notifications.Ecommerce.Cart.AfterShippingCalculation)]
+ public class CartAfterShippingCalculation : NotificationSubscriberBase
+ {
+ public override void OnNotify(string notification, NotificationArgs args)
+ {
+ if (args is null || Context.Current?.Items is null)
+ return;
+
+ var calculationArgs = (Ecommerce.Notifications.Ecommerce.Cart.AfterShippingCalculationArgs)args;
+ if (string.IsNullOrEmpty(calculationArgs.Shipping?.Id) || calculationArgs.Order is null || Context.Current.Session?[ErpShippingFeeProvider.OrderMarkerKey(calculationArgs.Order.Id)] is null)
+ {
+ return;
+ }
+
+ var cached = Context.Current.Session[ErpShippingFeeProvider.MethodCacheKey(calculationArgs.Order.Id, calculationArgs.Shipping?.Id)] as PriceInfo;
+ if (cached is null)
+ return;
+
+ calculationArgs.Price.PriceWithVAT = cached.PriceWithVAT;
+ calculationArgs.Price.PriceWithoutVAT = cached.PriceWithoutVAT;
+ calculationArgs.Price.VAT = cached.VAT;
+ calculationArgs.Price.VATPercent = cached.VATPercent;
+ }
+ }
+}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/ErpShippingFeeProvider.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/ErpShippingFeeProvider.cs
new file mode 100644
index 0000000..904c6bd
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/ErpShippingFeeProvider.cs
@@ -0,0 +1,81 @@
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Logging;
+using Dynamicweb.Ecommerce.Orders;
+using Dynamicweb.Ecommerce.Prices;
+using System.Xml;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Shipping
+{
+ internal class ErpShippingFeeProvider
+ {
+ private const string CachePrefix = "ErpShippingFeeProvider_";
+
+ internal static string OrderMarkerKey(string orderId) => CachePrefix + orderId;
+ internal static string MethodCacheKey(string orderId, string shippingMethodId) => CachePrefix + orderId + "_" + shippingMethodId;
+
+ internal static void ProcessShipping(Settings settings, Order order, XmlNode orderNode, Logger logger)
+ {
+ string shippingFee = orderNode.SelectSingleNode("column [@columnName='OrderShippingFee']")?.InnerText;
+ if (string.IsNullOrEmpty(shippingFee))
+ {
+ ClearCache(order);
+ return;
+ }
+
+ double fee = Helpers.ToDouble(settings, logger, shippingFee);
+
+ string shippingFeeWithoutVat = orderNode.SelectSingleNode("column [@columnName='OrderShippingFeeWithoutVat']")?.InnerText;
+ double feeWithoutVat = 0;
+ double vatPercent = order.Price.VATPercent;
+ if (!string.IsNullOrEmpty(shippingFeeWithoutVat))
+ {
+ feeWithoutVat = Helpers.ToDouble(settings, logger, shippingFeeWithoutVat);
+ feeWithoutVat = feeWithoutVat > fee ? fee : feeWithoutVat;
+ vatPercent = feeWithoutVat > 0 ? (fee / feeWithoutVat - 1) * 100 : 0;
+ }
+ if (feeWithoutVat <= 0)
+ {
+ feeWithoutVat = MinusVat(fee, vatPercent);
+ }
+
+ var price = new PriceInfo(order.Currency);
+ price.PriceWithVAT = fee;
+ price.PriceWithoutVAT = feeWithoutVat;
+ price.VATPercent = vatPercent;
+ price.VAT = fee - feeWithoutVat;
+
+ AddToCache(order, price);
+
+ order.AllowOverrideShippingFee = true;
+ order.ShippingFee.PriceWithVAT = price.PriceWithVAT;
+ order.ShippingFee.VATPercent = price.VATPercent;
+ order.ShippingFee.PriceWithoutVAT = price.PriceWithoutVAT;
+ order.ShippingFee.VAT = price.VAT;
+ }
+
+ internal static double MinusVat(double price, double percent)
+ {
+ return (double)((decimal)price / ((decimal)percent / 100M + 1M));
+ }
+
+ private static void AddToCache(Order order, PriceInfo shippingFee)
+ {
+ if (Context.Current?.Session is null || string.IsNullOrEmpty(order.ShippingMethodId))
+ return;
+
+ // Existence marker lets the notification subscriber know ERP fee caching is active for this order
+ Context.Current.Session[OrderMarkerKey(order.Id)] = true;
+ Context.Current.Session[MethodCacheKey(order.Id, order.ShippingMethodId)] = shippingFee;
+ }
+
+ private static void ClearCache(Order order)
+ {
+ if (Context.Current?.Session is null)
+ return;
+
+ Context.Current.Session.Remove(OrderMarkerKey(order.Id));
+ if (!string.IsNullOrEmpty(order.ShippingMethodId))
+ Context.Current.Session.Remove(MethodCacheKey(order.Id, order.ShippingMethodId));
+ }
+ }
+}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveShippingFeeProvider.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/LiveShippingFeeProvider.cs
similarity index 87%
rename from src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveShippingFeeProvider.cs
rename to src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/LiveShippingFeeProvider.cs
index c8452ea..3a69895 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/LiveShippingFeeProvider.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Shipping/LiveShippingFeeProvider.cs
@@ -28,13 +28,13 @@ public override PriceRaw CalculateShippingFee(Order order)
PriceRaw rate = null;
if (Context.Current != null && Context.Current.Items != null && Context.Current.Items["DynamicwebLiveShippingFeeProvider" + order.Id] != null)
- {
+ {
double shippingFee = (double)Context.Current.Items["DynamicwebLiveShippingFeeProvider" + order.Id];
rate = new PriceRaw(shippingFee, order.Currency);
- }
+ }
return rate;
- }
+ }
///
/// Processes the shipping.
@@ -43,12 +43,9 @@ public override PriceRaw CalculateShippingFee(Order order)
/// The order node.
internal static void ProcessShipping(Settings settings, Order order, XmlNode orderNode, Logger logger)
{
- if (settings.ErpControlsShipping)
- {
- Diagnostics.ExecutionTable.Current.Add("DynamicwebLiveIntegration.LiveShippingFeeProvider.ProcessShipping START");
- ProcessLiveIntegrationShipping(settings, order, orderNode, logger);
- Diagnostics.ExecutionTable.Current.Add("DynamicwebLiveIntegration.LiveShippingFeeProvider.ProcessShipping END");
- }
+ Diagnostics.ExecutionTable.Current.Add("DynamicwebLiveIntegration.LiveShippingFeeProvider.ProcessShipping START");
+ ProcessLiveIntegrationShipping(settings, order, orderNode, logger);
+ Diagnostics.ExecutionTable.Current.Add("DynamicwebLiveIntegration.LiveShippingFeeProvider.ProcessShipping END");
}
///
@@ -68,9 +65,9 @@ private static void AddToCache(Order order, double shippingFee)
/// Gets the shipping.
///
/// Shipping.
- private static Shipping GetShipping()
- {
- return Services.Shippings.GetShippingsWithoutRegions(false).FirstOrDefault(s => !string.IsNullOrEmpty(s.ServiceSystemName) &&
+ private static Ecommerce.Orders.Shipping GetShipping()
+ {
+ return Services.Shippings.GetShippingsWithoutRegions(false).FirstOrDefault(s => !string.IsNullOrEmpty(s.ServiceSystemName) &&
(string.Equals(typeof(LiveShippingFeeProvider).GetTypeNameWithAssembly(), s.ServiceSystemName) ||
string.Equals(s.ServiceSystemName, typeof(LiveShippingFeeProvider).FullName, StringComparison.OrdinalIgnoreCase)));
}
@@ -80,7 +77,7 @@ private static void ProcessLiveIntegrationShipping(Settings settings, Order orde
string shippingFee = orderNode.SelectSingleNode("column [@columnName='OrderShippingFee']")?.InnerText;
if (!string.IsNullOrEmpty(shippingFee))
{
- Shipping liveIntegrationShipping = GetShipping();
+ var liveIntegrationShipping = GetShipping();
if (liveIntegrationShipping != null)
{
order.ShippingMethodId = liveIntegrationShipping.Id;
@@ -98,7 +95,7 @@ private static void ProcessLiveIntegrationShipping(Settings settings, Order orde
if (!order.IsCart)
{
- order.ShippingFee.PriceWithVAT = fee;
+ order.ShippingFee.PriceWithVAT = fee;
}
else
{
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs
index 3c81743..8c5a352 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/UI/Commands/DownloadOrderXmlCommand.cs
@@ -85,7 +85,7 @@ private static string GetOrderCurrentXml(Settings settings, Order order)
//For anonymous orders, CustomerAccessUserId can be unset, GetUserById returns null, and IsUserErpDiscountAllowed falls back
//to the current anonymous-user setting. Therefore, ErpControlsDiscount here reflects current evaluation rather than historical checkout-time configuration.
ErpControlsDiscount = isUserErpDiscountAllowed,
- ErpControlsShipping = settings.ErpControlsShipping,
+ ShippingControlMode = settings.ShippingControlMode,
ErpShippingItemKey = settings.ErpShippingItemKey,
ErpShippingItemType = settings.ErpShippingItemType,
CalculateOrderUsingProductNumber = settings.CalculateOrderUsingProductNumber
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Updates/LiveIntegrationUpdateProvider.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Updates/LiveIntegrationUpdateProvider.cs
new file mode 100644
index 0000000..76398bd
--- /dev/null
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/Updates/LiveIntegrationUpdateProvider.cs
@@ -0,0 +1,75 @@
+using Dynamicweb.Core;
+using Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Configuration;
+using Dynamicweb.Updates;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Xml;
+
+namespace Dynamicweb.Ecommerce.DynamicwebLiveIntegration.Updates
+{
+ public sealed class LiveIntegrationUpdateProvider : UpdateProvider
+ {
+ public override IEnumerable GetUpdates() => new List()
+ {
+ new MethodUpdate("cd637b81-dd91-41ba-955e-6131c646a172", this, UpdateShippingControlMode),
+ };
+
+ private static void UpdateShippingControlMode(UpdateContext context)
+ {
+ if (!Directory.Exists(Path.Combine(SystemInformation.MapPath("/Files"), "System", "LiveIntegration")))
+ return;
+
+ bool updated = false;
+
+ foreach (string file in Directory.GetFiles(Path.Combine(SystemInformation.MapPath("/Files"), "System", "LiveIntegration"), "*.Setup.xml"))
+ {
+ if (!file.Contains(Constants.AddInName, StringComparison.OrdinalIgnoreCase))
+ continue;
+
+
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(File.ReadAllText(file));
+
+ var shippingControlModeNode = doc.SelectSingleNode("//Settings/ShippingControlMode");
+ if (shippingControlModeNode != null && !string.IsNullOrEmpty(shippingControlModeNode.InnerText))
+ continue;
+
+ var erpControlsShippingNode = doc.SelectSingleNode("//Settings/ErpControlsShipping");
+ if (string.IsNullOrEmpty(erpControlsShippingNode?.InnerText))
+ continue;
+
+ bool erpControlsShipping = Converter.ToBoolean(erpControlsShippingNode.InnerText);
+
+ string shippingControlMode = erpControlsShipping
+ ? Constants.ShippingControlMode.ErpControlsShipping
+ : Constants.ShippingControlMode.DynamicwebControlsShipping;
+
+ XmlNode settingsNode = doc.SelectSingleNode("//Settings");
+ if (settingsNode is not null)
+ {
+ if (shippingControlModeNode != null)
+ {
+ shippingControlModeNode.InnerText = shippingControlMode;
+ }
+ else
+ {
+ XmlElement newShippingControlModeNode = doc.CreateElement("ShippingControlMode");
+ newShippingControlModeNode.InnerText = shippingControlMode;
+ settingsNode.AppendChild(newShippingControlModeNode);
+ }
+
+ settingsNode.RemoveChild(erpControlsShippingNode);
+
+ doc.Save(file);
+ updated = true;
+ }
+ }
+
+ if (updated)
+ {
+ SettingsManager.Reload();
+ }
+ }
+ }
+}
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs
index 1287a1a..882489f 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGenerator.cs
@@ -57,7 +57,7 @@ public string GenerateOrderXml(Settings currentSettings, Order order, OrderXmlGe
/// The order node.
/// The order.
private static void AddCustomerInformation(Settings currentSettings, XmlElement orderNode, Order order, User user)
- {
+ {
AddChildXmlNode(orderNode, "OrderCustomerAccessUserExternalId", !string.IsNullOrWhiteSpace(user?.ExternalID) ? user.ExternalID : currentSettings.AnonymousUserKey);
AddChildXmlNode(orderNode, "OrderCustomerNumber", !string.IsNullOrWhiteSpace(user?.CustomerNumber) ? user.CustomerNumber : currentSettings.AnonymousUserKey);
AddChildXmlNode(orderNode, "OrderCustomerName", !string.IsNullOrWhiteSpace(user?.Name) ? user.Name : order.CustomerName);
@@ -87,10 +87,10 @@ private void AddOrderDeliveryInformation(OrderXmlGeneratorSettings settings, Xml
UserAddress deliveryAddress = null;
if (settings.CreateOrder && order.DeliveryAddressId > 0)
{
- deliveryAddress = UserManagementServices.UserAddresses.GetAddressById(order.DeliveryAddressId);
+ deliveryAddress = UserManagementServices.UserAddresses.GetAddressById(order.DeliveryAddressId);
}
string deliveryName = !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);
@@ -228,29 +228,35 @@ private XmlNode BuildOrderXml(Settings currentSettings, XmlDocument xmlDocument,
AddChildXmlNode(itemNode, "OrderShippingDate", order.ShippingDate.HasValue ? order.ShippingDate.ToIntegrationString(currentSettings, logger) : string.Empty);
AddChildXmlNode(itemNode, "OrderReference", order.Reference);
- if (settings.ErpControlsShipping)
- {
- // AX handles shipping
- AddChildXmlNode(itemNode, "OrderShippingMethodName", string.Empty, true);
- AddChildXmlNode(itemNode, "OrderShippingMethodId", string.Empty);
- AddChildXmlNode(itemNode, "OrderShippingFee", string.Empty);
- }
- else
+ if (settings.ShippingControlMode == Constants.ShippingControlMode.DynamicwebControlsShipping)
{
- // Dynamicweb handles shipping
+ // DW calculates and sends shipping fee
AddChildXmlNode(itemNode, "OrderShippingMethodName", order.ShippingMethod, true);
AddChildXmlNode(itemNode, "OrderShippingMethodId", order.ShippingMethodId);
- if (!settings.GenerateXmlForHash)
- {
- AddChildXmlNode(itemNode, "OrderShippingFee", order.ShippingFee.PriceWithVAT.ToIntegrationString(currentSettings, logger));
- AddChildXmlNode(itemNode, "OrderShippingFeeWithoutVat", order.ShippingFee.PriceWithoutVAT.ToIntegrationString(currentSettings, logger));
- }
+ AddShippingFeeNodes(currentSettings, itemNode, order, settings, logger);
AddChildXmlNode(itemNode, "OrderShippingItemType", settings.ErpShippingItemType);
AddChildXmlNode(itemNode, "OrderShippingItemKey", settings.ErpShippingItemKey);
AddChildXmlNode(itemNode, "OrderShippingCode", order.ShippingMethodCode);
AddChildXmlNode(itemNode, "OrderShippingAgentCode", order.ShippingMethodAgentCode);
AddChildXmlNode(itemNode, "OrderShippingAgentServiceCode", order.ShippingMethodAgentServiceCode);
}
+ else if (settings.ShippingControlMode == Constants.ShippingControlMode.ErpCalculatesBasedOnDwSelection)
+ {
+ // DW selects the shipping method and sends the current fee; ERP may recalculate the freight cost based on the identity fields
+ AddChildXmlNode(itemNode, "OrderShippingMethodName", order.ShippingMethod, true);
+ AddChildXmlNode(itemNode, "OrderShippingMethodId", order.ShippingMethodId);
+ AddChildXmlNode(itemNode, "OrderShippingCode", order.ShippingMethodCode);
+ AddChildXmlNode(itemNode, "OrderShippingAgentCode", order.ShippingMethodAgentCode);
+ AddChildXmlNode(itemNode, "OrderShippingAgentServiceCode", order.ShippingMethodAgentServiceCode);
+ AddShippingFeeNodes(currentSettings, itemNode, order, settings, logger);
+ }
+ else
+ {
+ // ERP controls shipping entirely — send empty values
+ AddChildXmlNode(itemNode, "OrderShippingMethodName", string.Empty, true);
+ AddChildXmlNode(itemNode, "OrderShippingMethodId", string.Empty);
+ AddChildXmlNode(itemNode, "OrderShippingFee", string.Empty);
+ }
if (!settings.GenerateXmlForHash)
{
@@ -273,6 +279,15 @@ private XmlNode BuildOrderXml(Settings currentSettings, XmlDocument xmlDocument,
return tableNode;
}
+ private static void AddShippingFeeNodes(Settings currentSettings, XmlElement itemNode, Order order, OrderXmlGeneratorSettings settings, Logger logger)
+ {
+ if (!settings.GenerateXmlForHash)
+ {
+ AddChildXmlNode(itemNode, "OrderShippingFee", order.ShippingFee.PriceWithVAT.ToIntegrationString(currentSettings, logger));
+ AddChildXmlNode(itemNode, "OrderShippingFeeWithoutVat", order.ShippingFee.PriceWithoutVAT.ToIntegrationString(currentSettings, logger));
+ }
+ }
+
///
/// Creates the order line XML.
///
@@ -406,7 +421,7 @@ public double GetGiftCardAmountWithoutVat(OrderLine giftCardOrderLine)
return unitPrice.PriceWithoutVAT;
}
else
- {
+ {
var giftCardDiscount = _orderPriceWithoutVat.Value;
_orderPriceWithoutVat = 0d;
return giftCardDiscount > 0 ? giftCardDiscount * -1 : giftCardDiscount;
diff --git a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGeneratorSettings.cs b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGeneratorSettings.cs
index b660251..2a1473b 100644
--- a/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGeneratorSettings.cs
+++ b/src/Dynamicweb.Ecommerce.DynamicwebLiveIntegration/XmlGenerators/OrderXmlGeneratorSettings.cs
@@ -31,10 +31,9 @@ public class OrderXmlGeneratorSettings : XmlGeneratorSettings
public bool ErpControlsDiscount { get; set; }
///
- /// Gets or sets if ERP controls shipping
+ /// Gets or sets the shipping control mode.
///
- /// true if [ERP controls shipping]; otherwise, false.
- public bool ErpControlsShipping { get; set; }
+ public string ShippingControlMode { get; set; }
///
/// Gets or sets the key for shipping item type.