/// <summary> /// Populates the adapter configuration for each delivery mode identifier key in the passed in dictionary. /// </summary> /// <param name="context">The request context.</param> /// <param name="deliveryModeIdMapper">The delivery mode identifier mapper.</param> private static void PopulateAdapterConfig(RequestContext context, Dictionary <string, TrackingConfig> deliveryModeIdMapper) { if (context == null) { throw new ArgumentNullException("context"); } if (deliveryModeIdMapper == null) { throw new ArgumentNullException("deliveryModeIdMapper"); } List <string> nonDuplicateDeliveryIds = new List <string>(deliveryModeIdMapper.Keys); // Fetch adapter configuration table for all the delivery mode ids. var dataServiceRequest = new GetShippingAdapterConfigurationDataRequest(nonDuplicateDeliveryIds, QueryResultSettings.AllRecords); var dataServiceResponse = context.Execute <EntityDataServiceResponse <ShippingAdapterConfig> >(dataServiceRequest); var shippingAdapterConfigTable = dataServiceResponse.PagedEntityCollection.Results; // Consolidate adapter config entries by having separate property bags per deliveryModeId. foreach (var adapterConfigLine in shippingAdapterConfigTable) { var trackingConfig = deliveryModeIdMapper[adapterConfigLine.DeliveryModeId]; string keyName = adapterConfigLine.KeyName; string keyValue = adapterConfigLine.KeyValue; trackingConfig.AdapterConfig[keyName] = keyValue; } }
/// <summary> /// Validates the address. /// </summary> /// <param name="shippingRequest">The shipping request.</param> /// <returns>The response.</returns> /// <remarks>Throws an exception if the address field in the request is null.</remarks> private static ValidateShippingAddressServiceResponse ValidateShippingAddress(ValidateShippingAddressServiceRequest shippingRequest) { if (shippingRequest.AddressToValidate == null) { throw new ArgumentNullException("shippingRequest", "shippingRequest.AddressToValidate"); } if (shippingRequest.DeliveryModeId == null) { throw new ArgumentNullException("shippingRequest", "shippingRequest.DeliveryModeId"); } var dataServiceRequest = new GetShippingAdapterConfigurationDataRequest(new[] { shippingRequest.DeliveryModeId }, QueryResultSettings.AllRecords); var dataServiceResponse = shippingRequest.RequestContext.Execute <EntityDataServiceResponse <ShippingAdapterConfig> >(dataServiceRequest); var shippingAdapterConfigLines = dataServiceResponse.PagedEntityCollection.Results; ParameterSet adapterConfig = ExtractAdapterConfigForSpecificDeliveryMode(shippingRequest.DeliveryModeId, shippingAdapterConfigLines); var carrierServiceRequest = new ValidateShippingAddressCarrierServiceRequest(adapterConfig, shippingRequest.AddressToValidate, shippingRequest.SuggestAddress); IRequestHandler carrierAdapterHandler = GetCarrierAdapterService(shippingRequest.RequestContext, carrierServiceRequest.GetType(), adapterConfig); bool isAddressValid = true; IEnumerable <Address> addressSuggestions = null; if (carrierAdapterHandler != null) { // Call the adapter's validation method var carrierServiceResponse = shippingRequest.RequestContext.Runtime.Execute <ValidateShippingAddressCarrierServiceResponse>(carrierServiceRequest, shippingRequest.RequestContext, carrierAdapterHandler); isAddressValid = carrierServiceResponse.IsAddressValid; addressSuggestions = carrierServiceResponse.RecommendedAddresses; } else { NetTracer.Warning("No registered shipping carrier is found."); } return(new ValidateShippingAddressServiceResponse(isAddressValid, addressSuggestions)); }
/// <summary> /// Gets the shipping adapter configuration. /// </summary> /// <param name="request">The request.</param> /// <returns>The response with the shipping adapter configuration.</returns> private EntityDataServiceResponse <ShippingAdapterConfig> GetShippingAdapterConfiguration(GetShippingAdapterConfigurationDataRequest request) { var shippingDataManager = this.GetDataManagerInstance(request.RequestContext); var adapterConfiguration = shippingDataManager.GetShippingAdapterConfiguration(request.DeliveryModeIds, request.QueryResultSettings.ColumnSet); return(new EntityDataServiceResponse <ShippingAdapterConfig>(adapterConfiguration)); }
/// <summary> /// Gets the shipping rate from the external carriers. /// </summary> /// <param name="request">Contains the sales line item details for which the shipping rate needs to be computed.</param> /// <returns>The response containing the shipping response.</returns> /// <remarks> /// No exception is thrown if the delivery mode identifier is empty for a sales line. /// </remarks> private static GetExternalShippingRateServiceResponse GetExternalShippingRate(GetExternalShippingRateServiceRequest request) { // Check each salesLine for: // 1) an item id (used for getting dimensions, // 2) delivery mode id (used for determining shipping adapter to use) // 3) InventoryLocationId (used to determine ShippFromAddress) // 4) ShippingAddress(use to determine ShipToAddress) // Create a list of item ids for contacting database for item dimensions List <string> itemIds = new List <string>(); // Create a list of warehouse ids for contacting database for warehouse addresses List <string> warehouseIds = new List <string>(); // Create a list of delivery mode ids for contacting database for adapter configurations List <string> deliverModeIds = new List <string>(); // Divide sales lines into groups that have the same delivery mode id and origin and destination shipping addresses. Dictionary <int, List <SalesLine> > groupedSalesLines = new Dictionary <int, List <SalesLine> >(); bool isValidSalesLine; Collection <string> linesWithoutDeliveryModeId = new Collection <string>(); Collection <string> linesWithoutShippingAddress = new Collection <string>(); Collection <string> linesWithoutInventoryLocationId = new Collection <string>(); foreach (var salesLine in request.SalesLines) { // Assume that a sales line is valid until found otherwise. isValidSalesLine = true; if (salesLine == null) { throw new ArgumentNullException("request", "salesLine is not set in sales lines"); } if (string.IsNullOrWhiteSpace(salesLine.ItemId)) { throw new ArgumentNullException("request", "salesLine.ItemId"); } if (string.IsNullOrWhiteSpace(salesLine.InventoryLocationId)) { linesWithoutInventoryLocationId.Add(salesLine.LineId); isValidSalesLine = false; } if (string.IsNullOrWhiteSpace(salesLine.DeliveryMode)) { linesWithoutDeliveryModeId.Add(salesLine.LineId); isValidSalesLine = false; } if (salesLine.ShippingAddress == null) { linesWithoutShippingAddress.Add(salesLine.LineId); isValidSalesLine = false; } if (isValidSalesLine) { itemIds.Add(salesLine.ItemId); warehouseIds.Add(salesLine.InventoryLocationId); deliverModeIds.Add(salesLine.DeliveryMode); // Group all sales line with the same delivery mode, warehouse id and destination shipping address together int key = (salesLine.DeliveryMode + salesLine.InventoryLocationId + salesLine.ShippingAddress.GetHashCode()).GetHashCode(); if (!groupedSalesLines.ContainsKey(key)) { groupedSalesLines.Add(key, new List <SalesLine>()); } groupedSalesLines[key].Add(salesLine); } } RaiseNotificationForInvalidLines(request.RequestContext, linesWithoutDeliveryModeId, linesWithoutInventoryLocationId, linesWithoutShippingAddress); var getWarehouseDataRequest = new GetWarehouseDetailsDataRequest(warehouseIds, QueryResultSettings.AllRecords); var getWarehouseDataResponse = request.RequestContext.Execute <EntityDataServiceResponse <WarehouseDetails> >(getWarehouseDataRequest); var warehouseDetailsRecords = getWarehouseDataResponse.PagedEntityCollection.Results; Dictionary <string, Address> warehouseAddresses = warehouseDetailsRecords.ToDictionary(key => key.InventoryLocationId.ToUpperInvariant(), value => (Address)value); // Validate that a warehouse address was retrieved for each inventory location id. foreach (var warehouseId in warehouseIds) { if (!warehouseAddresses.ContainsKey(warehouseId.ToUpperInvariant())) { throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidShippingAddress, string.Format(CultureInfo.InvariantCulture, "Address for inventory location id {0} could not be found", warehouseId)); } } var getItemDimensionsDataRequest = new GetItemDimensionsDataRequest(itemIds, QueryResultSettings.AllRecords); var getItemDimensionsDataResponse = request.RequestContext.Execute <EntityDataServiceResponse <ItemDimensions> >(getItemDimensionsDataRequest); var itemDimensionsRecords = getItemDimensionsDataResponse.PagedEntityCollection.Results; Dictionary <string, decimal> itemGrossWeights = itemDimensionsRecords.ToDictionary(key => key.ItemId.ToUpperInvariant(), value => value.GrossWeight); // Validate that a weight value was retrieved for each item id. foreach (var itemId in itemIds) { if (!itemGrossWeights.ContainsKey(itemId.ToUpperInvariant())) { throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_GrossWeightForItemNotFound, string.Format(CultureInfo.InvariantCulture, "Gross Weight for item id {0} could not be found", itemId)); } } var shippingAdapterConfigDataRequest = new GetShippingAdapterConfigurationDataRequest(deliverModeIds, QueryResultSettings.AllRecords); var shippingAdapterConfigDataResponse = request.RequestContext.Execute <EntityDataServiceResponse <ShippingAdapterConfig> >(shippingAdapterConfigDataRequest); var shippingAdapterConfigRecords = shippingAdapterConfigDataResponse.PagedEntityCollection.Results; var salesLineShippingRates = CalculateShippingRates( groupedSalesLines, warehouseAddresses, itemGrossWeights, shippingAdapterConfigRecords, request.RequestContext); return(new GetExternalShippingRateServiceResponse(salesLineShippingRates.AsPagedResult())); }