private decimal?GetRate(decimal weight, int shippingMethodId, int storeId, int warehouseId, int countryId, int stateProvinceId, string zip, GetShippingOptionRequest getShippingOptionRequest) { decimal queryWeight = weight; decimal realWeight = _shippingService.GetTotalWeight(getShippingOptionRequest); if (realWeight > weight) { queryWeight = realWeight; } var dhlRecord = _dhlService.FindRecord(shippingMethodId, storeId, warehouseId, countryId, stateProvinceId, zip, queryWeight); if (dhlRecord == null) { if (_dhlSettings.LimitMethodsToCreated) { return(null); } return(decimal.Zero); } #region X Üzeri Ücretsiz Kargo decimal shippingTotal = decimal.Zero; decimal?orderTotal = decimal.Zero; foreach (var packageItem in getShippingOptionRequest.Items) { //TODO we should use getShippingOptionRequest.Items.GetQuantity() method to get subtotal orderTotal += _priceCalculationService.GetSubTotal(packageItem.ShoppingCartItem); } if (orderTotal.HasValue) { var trueOrderTotal = _currencyService.ConvertToPrimaryStoreCurrency(orderTotal.Value, _workContext.WorkingCurrency); if (dhlRecord.FreeShippingOverXEnabled && trueOrderTotal >= dhlRecord.FreeShippingOverXValue) { return(decimal.Zero); } } #endregion X Üzeri Ücretsiz Kargo if (dhlRecord.IsFixedRate) { return(dhlRecord.FixedRate); } shippingTotal += dhlRecord.Factor; if (shippingTotal < decimal.Zero) { shippingTotal = decimal.Zero; } return(shippingTotal); }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns>Represents a response of getting shipping rate options</returns> public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException("getShippingOptionRequest"); } var response = new GetShippingOptionResponse(); if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) { response.AddError("No shipment items"); return(response); } if (getShippingOptionRequest.ShippingAddress == null) { var originAddress = _shippingSettings.ShippingOriginAddressId > 0 ? _addressService.GetAddressById(_shippingSettings.ShippingOriginAddressId) : null; if (originAddress == null) { response.AddError("Origin Address or Shipping address is not set"); return(response); } getShippingOptionRequest.ShippingAddress = originAddress; } int countryId = getShippingOptionRequest.ShippingAddress.CountryId.HasValue ? getShippingOptionRequest.ShippingAddress.CountryId.Value : 0; decimal subTotal = decimal.Zero; foreach (var shoppingCartItem in getShippingOptionRequest.Items) { if (shoppingCartItem.IsFreeShipping || !shoppingCartItem.IsShipEnabled) { continue; } subTotal += _priceCalculationService.GetSubTotal(shoppingCartItem, true); } decimal deci = GetShoppingCartTotalDeci(getShippingOptionRequest.Items); var shippingMethods = _shippingService.GetAllShippingMethods(countryId); decimal additionalRate = _settingService.GetSettingByKey <decimal>("ShippingRateComputationMethod.ByWeight.DHLRate"); additionalRate = Math.Max(1, additionalRate); foreach (var shippingMethod in shippingMethods) { decimal?rate = GetRate(subTotal, deci, shippingMethod.Id, countryId); if (rate.HasValue) { var shippingOption = new ShippingOption(); shippingOption.Name = shippingMethod.GetLocalized(x => x.Name); shippingOption.Description = shippingMethod.GetLocalized(x => x.Description); shippingOption.Rate = rate.Value * additionalRate; response.ShippingOptions.Add(shippingOption); } } return(response); }
public GetShippingOptionResponse GetShippingOptions( GetShippingOptionRequest getShippingOptionRequest ) { if (getShippingOptionRequest == null) { throw new ArgumentNullException( nameof(getShippingOptionRequest) ); } // Validate that 'lb' measure weight exists in system var lbsMeasureWeight = _measureService.GetMeasureWeightBySystemKeyword("lb"); if (lbsMeasureWeight == null) { return(new GetShippingOptionResponse { Errors = new[] { "Cannot perform weight conversion, unable " + "to find 'lb' measure weight. Make sure a measure weight " + "with 'lb' system keyword exists." } }); } if (!getShippingOptionRequest.Items?.Any() ?? true) { return(new GetShippingOptionResponse { Errors = new[] { "No shipment items" } }); } // Check that destination zip/postal was provided var destinationZip = getShippingOptionRequest.ShippingAddress?.ZipPostalCode; if (destinationZip == null) { return(new GetShippingOptionResponse { Errors = new[] { "Destination shipping zip/postal code is not set" } }); } var weight = _shippingService.GetTotalWeight( getShippingOptionRequest ); var weightInLbs = _measureService.ConvertFromPrimaryMeasureWeight( weight, lbsMeasureWeight); // If under minimum, don't provide as option if (weightInLbs < _settings.MinimumWeightLimitInLbs) { return(new GetShippingOptionResponse()); } decimal rateQuote; try { rateQuote = _rateQuoteService.GetRateQuote( destinationZip, decimal.ToInt32(decimal.Round(weightInLbs)) ); } catch (NopException ex) { return(new GetShippingOptionResponse { Errors = new[] { $"{ex.Message}" } }); } var response = new GetShippingOptionResponse(); response.ShippingOptions.Add(new ShippingOption() { Name = _settings.ShippingOptionName, Rate = rateQuote }); return(response); }
/// <summary> /// Create packages (total volume of shopping cart items determines number of packages) /// </summary> /// <param name="request">Shipping request</param> /// <param name="getShippingOptionRequest">Shipping option request</param> /// <param name="orderSubTotal"></param> /// <param name="currencyCode">Currency code</param> private void SetIndividualPackageLineItemsCubicRootDimensions(FedexRate.RateRequest request, GetShippingOptionRequest getShippingOptionRequest, decimal orderSubTotal, string currencyCode) { //From FedEx Guide (Ground): //Dimensional weight is based on volume (the amount of space a package //occupies in relation to its actual weight). If the cubic size of your FedEx //Ground package measures three cubic feet (5,184 cubic inches or 84,951 //cubic centimetres) or greater, you will be charged the greater of the //dimensional weight or the actual weight. //A package weighing 150 lbs. (68 kg) or less and measuring greater than //130 inches (330 cm) in combined length and girth will be classified by //FedEx Ground as an “Oversize” package. All packages must have a //combined length and girth of no more than 165 inches (419 cm). An //oversize charge of $30 per package will also apply to any package //measuring greater than 130 inches (330 cm) in combined length and //girth. //Shipping charges for packages smaller than three cubic feet are based //on actual weight // Dimensional Weight applies to packages with volume 5,184 cubic inches or more // cube root(5184) = 17.3 // Packages that exceed 130 inches in length and girth (2xHeight + 2xWidth) // are considered “oversize” packages. // Assume a cube (H=W=L) of that size: 130 = D + (2xD + 2xD) = 5xD : D = 130/5 = 26 // 26x26x26 = 17,576 // Avoid oversize by using 25" // 25x25x25 = 15,625 // Which is less $ - multiple small packages, or one large package using dimensional weight // 15,625 / 5184 = 3.014 = 3 packages // Ground for total weight: 60lbs 15lbs // 3 packages 17x17x17 (20 lbs each) = $66.21 39.39 // 1 package 25x25x25 (60 lbs) = $71.70 71.70 var totalPackagesDims = 1; var length = 0M; var height = 0M; var width = 0M; if (getShippingOptionRequest.Items.Count == 1 && getShippingOptionRequest.Items[0].GetQuantity() == 1) { var sci = getShippingOptionRequest.Items[0].ShoppingCartItem; //get dimensions and weight of the single cubic size of package var item = getShippingOptionRequest.Items.FirstOrDefault().ShoppingCartItem; (width, length, height) = GetDimensionsForSingleItem(item); } else { //or try to get them var dimension = 0; //get total volume of the package var totalVolume = getShippingOptionRequest.Items.Sum(item => { //get dimensions and weight of the single item var(itemWidth, itemLength, itemHeight) = GetDimensionsForSingleItem(item.ShoppingCartItem); return(item.GetQuantity() * itemWidth * itemLength * itemHeight); }); if (totalVolume > decimal.Zero) { //use default value (in cubic inches) if not specified var packageVolume = _fedexSettings.PackingPackageVolume; if (packageVolume <= 0) { packageVolume = 5184; } //calculate cube root (floor) dimension = Convert.ToInt32(Math.Floor(Math.Pow(Convert.ToDouble(packageVolume), 1.0 / 3.0))); if (IsPackageTooLarge(dimension, dimension, dimension)) { throw new NopException("fedexSettings.PackingPackageVolume exceeds max package size"); } //adjust package volume for dimensions calculated packageVolume = dimension * dimension * dimension; totalPackagesDims = Convert.ToInt32(Math.Ceiling(totalVolume / packageVolume)); } width = length = height = dimension; } width = Math.Max(width, 1); length = Math.Max(length, 1); height = Math.Max(height, 1); var weight = GetWeight(getShippingOptionRequest); var totalPackagesWeights = 1; if (IsPackageTooHeavy(weight)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling(weight / FedexShippingDefaults.MAX_PACKAGE_WEIGHT)); } var totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; var orderSubTotalPerPackage = orderSubTotal / totalPackages; var weightPerPackage = weight / totalPackages; request.RequestedShipment.PackageCount = totalPackages.ToString(); request.RequestedShipment.RequestedPackageLineItems = Enumerable.Range(1, totalPackages) .Select(i => CreatePackage(width, length, height, weightPerPackage, orderSubTotalPerPackage, i.ToString(), currencyCode)) .ToArray(); }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns>Represents a response of getting shipping rate options</returns> public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException(nameof(getShippingOptionRequest)); } var response = new GetShippingOptionResponse(); if (getShippingOptionRequest.Items == null || !getShippingOptionRequest.Items.Any()) { response.AddError("No shipment items"); return(response); } //choose the shipping rate calculation method if (_fixedOrByWeightSettings.ShippingByWeightEnabled) { //shipping rate calculation by products weight if (getShippingOptionRequest.ShippingAddress == null) { response.AddError("Shipping address is not set"); return(response); } var storeId = getShippingOptionRequest.StoreId != 0 ? getShippingOptionRequest.StoreId : _storeContext.CurrentStore.Id; var countryId = getShippingOptionRequest.ShippingAddress.CountryId ?? 0; var stateProvinceId = getShippingOptionRequest.ShippingAddress.StateProvinceId ?? 0; var warehouseId = getShippingOptionRequest.WarehouseFrom?.Id ?? 0; var zip = getShippingOptionRequest.ShippingAddress.ZipPostalCode; //get subtotal of shipped items var subTotal = decimal.Zero; foreach (var packageItem in getShippingOptionRequest.Items) { if (packageItem.ShoppingCartItem.IsFreeShipping(_productService, _productAttributeParser)) { continue; } //TODO we should use getShippingOptionRequest.Items.GetQuantity() method to get subtotal subTotal += _priceCalculationService.GetSubTotal(packageItem.ShoppingCartItem); } //get weight of shipped items (excluding items with free shipping) var weight = _shippingService.GetTotalWeight(getShippingOptionRequest, ignoreFreeShippedItems: true); foreach (var shippingMethod in _shippingService.GetAllShippingMethods(countryId)) { var rate = GetRate(subTotal, weight, shippingMethod.Id, storeId, warehouseId, countryId, stateProvinceId, zip); if (!rate.HasValue) { continue; } response.ShippingOptions.Add(new ShippingOption { Name = shippingMethod.GetLocalized(x => x.Name), Description = shippingMethod.GetLocalized(x => x.Description), Rate = rate.Value }); } } else { //shipping rate calculation by fixed rate var restrictByCountryId = getShippingOptionRequest.ShippingAddress?.Country?.Id; response.ShippingOptions = _shippingService.GetAllShippingMethods(restrictByCountryId).Select(shippingMethod => new ShippingOption { Name = shippingMethod.GetLocalized(x => x.Name), Description = shippingMethod.GetLocalized(x => x.Description), Rate = GetRate(shippingMethod.Id) }).ToList(); } return(response); }
private string CreateRequest(string accessKey, string username, string password, GetShippingOptionRequest getShippingOptionRequest, UPSCustomerClassification customerClassification, UPSPickupType pickupType, UPSPackagingType packagingType) { string zipPostalCodeFrom = getShippingOptionRequest.ZipPostalCodeFrom; string zipPostalCodeTo = getShippingOptionRequest.ShippingAddress.ZipPostalCode; string countryCodeFrom = getShippingOptionRequest.CountryFrom.TwoLetterIsoCode; var country = _countryService.GetCountryById(getShippingOptionRequest.ShippingAddress.CountryId); string countryCodeTo = country.TwoLetterIsoCode; var sb = new StringBuilder(); sb.Append("<?xml version='1.0'?>"); sb.Append("<AccessRequest xml:lang='en-US'>"); sb.AppendFormat("<AccessLicenseNumber>{0}</AccessLicenseNumber>", accessKey); sb.AppendFormat("<UserId>{0}</UserId>", username); sb.AppendFormat("<Password>{0}</Password>", password); sb.Append("</AccessRequest>"); sb.Append("<?xml version='1.0'?>"); sb.Append("<RatingServiceSelectionRequest xml:lang='en-US'>"); sb.Append("<Request>"); sb.Append("<TransactionReference>"); sb.Append("<CustomerContext>Bare Bones Rate Request</CustomerContext>"); sb.Append("<XpciVersion>1.0001</XpciVersion>"); sb.Append("</TransactionReference>"); sb.Append("<RequestAction>Rate</RequestAction>"); sb.Append("<RequestOption>Shop</RequestOption>"); sb.Append("</Request>"); if (String.Equals(countryCodeFrom, "US", StringComparison.InvariantCultureIgnoreCase)) { sb.Append("<PickupType>"); sb.AppendFormat("<Code>{0}</Code>", GetPickupTypeCode(pickupType)); sb.Append("</PickupType>"); sb.Append("<CustomerClassification>"); sb.AppendFormat("<Code>{0}</Code>", GetCustomerClassificationCode(customerClassification)); sb.Append("</CustomerClassification>"); } sb.Append("<Shipment>"); sb.Append("<Shipper>"); sb.Append("<Address>"); sb.AppendFormat("<PostalCode>{0}</PostalCode>", zipPostalCodeFrom); sb.AppendFormat("<CountryCode>{0}</CountryCode>", countryCodeFrom); sb.Append("</Address>"); sb.Append("</Shipper>"); sb.Append("<ShipTo>"); sb.Append("<Address>"); sb.Append("<ResidentialAddressIndicator/>"); sb.AppendFormat("<PostalCode>{0}</PostalCode>", zipPostalCodeTo); sb.AppendFormat("<CountryCode>{0}</CountryCode>", countryCodeTo); sb.Append("</Address>"); sb.Append("</ShipTo>"); sb.Append("<ShipFrom>"); sb.Append("<Address>"); sb.AppendFormat("<PostalCode>{0}</PostalCode>", zipPostalCodeFrom); sb.AppendFormat("<CountryCode>{0}</CountryCode>", countryCodeFrom); sb.Append("</Address>"); sb.Append("</ShipFrom>"); sb.Append("<Service>"); sb.Append("<Code>03</Code>"); sb.Append("</Service>"); string currencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; //get subTotalWithoutDiscountBase, for use as insured value (when Settings.InsurePackage) //(note: prior versions used "with discount", but "without discount" better reflects true value to insure.) decimal orderSubTotalDiscountAmount; List <Discount> orderSubTotalAppliedDiscounts; decimal subTotalWithoutDiscountBase; decimal subTotalWithDiscountBase; //TODO we should use getShippingOptionRequest.Items.GetQuantity() method to get subtotal _orderTotalCalculationService.GetShoppingCartSubTotal(getShippingOptionRequest.Items.Select(x => x.ShoppingCartItem).ToList(), false, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscounts, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); if (_upsSettings.Tracing) { _traceMessages.AppendLine(" Packing Type: " + _upsSettings.PackingType.ToString()); } switch (_upsSettings.PackingType) { case PackingType.PackByOneItemPerPackage: SetIndividualPackageLineItemsOneItemPerPackage(sb, getShippingOptionRequest, packagingType, currencyCode); break; case PackingType.PackByVolume: SetIndividualPackageLineItemsCubicRootDimensions(sb, getShippingOptionRequest, packagingType, subTotalWithoutDiscountBase, currencyCode); break; case PackingType.PackByDimensions: default: SetIndividualPackageLineItems(sb, getShippingOptionRequest, packagingType, subTotalWithoutDiscountBase, currencyCode); break; } sb.Append("</Shipment>"); sb.Append("</RatingServiceSelectionRequest>"); return(sb.ToString()); }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns>Represents a response of getting shipping rate options</returns> public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException("getShippingOptionRequest"); } var response = new GetShippingOptionResponse(); if (getShippingOptionRequest.Items == null) { response.AddError("No shipment items"); return(response); } if (getShippingOptionRequest.ShippingAddress == null) { response.AddError("Shipping address is not set"); return(response); } if (getShippingOptionRequest.ShippingAddress.Country == null) { response.AddError("Shipping country is not set"); return(response); } if (getShippingOptionRequest.ShippingAddress.StateProvince == null) { response.AddError("Shipping state is not set"); return(response); } try { var profile = new Profile(); profile.MerchantId = _canadaPostSettings.CustomerId; var destination = new Destination(); destination.City = getShippingOptionRequest.ShippingAddress.City; destination.StateOrProvince = getShippingOptionRequest.ShippingAddress.StateProvince.Abbreviation; destination.Country = getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode; destination.PostalCode = getShippingOptionRequest.ShippingAddress.ZipPostalCode; var items = CreateItems(getShippingOptionRequest); var lang = CanadaPostLanguageEnum.English; if (_workContext.WorkingLanguage.LanguageCulture.StartsWith("fr", StringComparison.InvariantCultureIgnoreCase)) { lang = CanadaPostLanguageEnum.French; } var requestResult = GetShippingOptionsInternal(profile, destination, items, lang); if (requestResult.IsError) { response.AddError(requestResult.StatusMessage); } else { foreach (var dr in requestResult.AvailableRates) { var so = new ShippingOption(); so.Name = dr.Name; if (!string.IsNullOrEmpty(dr.DeliveryDate)) { so.Name += string.Format(" - {0}", dr.DeliveryDate); } so.Rate = dr.Amount; response.ShippingOptions.Add(so); } } foreach (var shippingOption in response.ShippingOptions) { if (!shippingOption.Name.StartsWith("canada post", StringComparison.InvariantCultureIgnoreCase)) { shippingOption.Name = string.Format("Canada Post {0}", shippingOption.Name); } } } catch (Exception e) { response.AddError(e.Message); } return(response); }
/// <summary> /// Gets fixed shipping rate (if shipping rate computation method allows it and the rate can be calculated before checkout). /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the fixed shipping rate; or null in case there's no fixed shipping rate /// </returns> public Task <decimal?> GetFixedRateAsync(GetShippingOptionRequest getShippingOptionRequest) { return(Task.FromResult <decimal?>(null)); }
private void SetIndividualPackageLineItems(RateRequest request, GetShippingOptionRequest getShippingOptionRequest, decimal orderSubTotal, string currencyCode) { // Rate request setup - Total Dimensions of Shopping Cart Items determines number of packages var usedMeasureWeight = GetUsedMeasureWeight(); var usedMeasureDimension = GetUsedMeasureDimension(); int length = ConvertFromPrimaryMeasureDimension(getShippingOptionRequest.GetTotalLength(), usedMeasureDimension); int height = ConvertFromPrimaryMeasureDimension(getShippingOptionRequest.GetTotalHeight(), usedMeasureDimension); int width = ConvertFromPrimaryMeasureDimension(getShippingOptionRequest.GetTotalWidth(), usedMeasureDimension); int weight = ConvertFromPrimaryMeasureWeight(_shippingService.GetShoppingCartTotalWeight(getShippingOptionRequest.Items), usedMeasureWeight); if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } if (weight < 1) { weight = 1; } if ((!IsPackageTooHeavy(weight)) && (!IsPackageTooLarge(length, height, width))) { request.RequestedShipment.PackageCount = "1"; request.RequestedShipment.RequestedPackageLineItems = new RequestedPackageLineItem[1]; request.RequestedShipment.RequestedPackageLineItems[0] = new RequestedPackageLineItem(); request.RequestedShipment.RequestedPackageLineItems[0].SequenceNumber = "1"; // package sequence number request.RequestedShipment.RequestedPackageLineItems[0].Weight = new RateServiceWebReference.Weight(); // package weight request.RequestedShipment.RequestedPackageLineItems[0].Weight.Units = RateServiceWebReference.WeightUnits.LB; request.RequestedShipment.RequestedPackageLineItems[0].Weight.Value = weight; request.RequestedShipment.RequestedPackageLineItems[0].Dimensions = new RateServiceWebReference.Dimensions(); // package dimensions request.RequestedShipment.RequestedPackageLineItems[0].Dimensions.Length = _fedexSettings.PassDimensions ? length.ToString() : "0"; request.RequestedShipment.RequestedPackageLineItems[0].Dimensions.Width = _fedexSettings.PassDimensions ? width.ToString() : "0"; request.RequestedShipment.RequestedPackageLineItems[0].Dimensions.Height = _fedexSettings.PassDimensions ? height.ToString() : "0"; request.RequestedShipment.RequestedPackageLineItems[0].Dimensions.Units = RateServiceWebReference.LinearUnits.IN; request.RequestedShipment.RequestedPackageLineItems[0].InsuredValue = new RateServiceWebReference.Money(); // insured value request.RequestedShipment.RequestedPackageLineItems[0].InsuredValue.Amount = orderSubTotal; request.RequestedShipment.RequestedPackageLineItems[0].InsuredValue.Currency = currencyCode; } else { int totalPackages = 1; int totalPackagesDims = 1; int totalPackagesWeights = 1; if (IsPackageTooHeavy(weight)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling((decimal)weight / (decimal)MAXPACKAGEWEIGHT)); } if (IsPackageTooLarge(length, height, width)) { totalPackagesDims = Convert.ToInt32(Math.Ceiling((decimal)TotalPackageSize(length, height, width) / (decimal)108)); } totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; if (totalPackages == 0) { totalPackages = 1; } int weight2 = weight / totalPackages; int height2 = height / totalPackages; int width2 = width / totalPackages; int length2 = length / totalPackages; if (weight2 < 1) { weight2 = 1; } if (height2 < 1) { height2 = 1; } if (width2 < 1) { width2 = 1; } if (length2 < 1) { length2 = 1; } decimal orderSubTotal2 = orderSubTotal / totalPackages; request.RequestedShipment.PackageCount = totalPackages.ToString(); request.RequestedShipment.RequestedPackageLineItems = new RequestedPackageLineItem[totalPackages]; for (int i = 0; i < totalPackages; i++) { request.RequestedShipment.RequestedPackageLineItems[i] = new RequestedPackageLineItem(); request.RequestedShipment.RequestedPackageLineItems[i].SequenceNumber = (i + 1).ToString(); // package sequence number request.RequestedShipment.RequestedPackageLineItems[i].Weight = new RateServiceWebReference.Weight(); // package weight request.RequestedShipment.RequestedPackageLineItems[i].Weight.Units = RateServiceWebReference.WeightUnits.LB; request.RequestedShipment.RequestedPackageLineItems[i].Weight.Value = (decimal)weight2; request.RequestedShipment.RequestedPackageLineItems[i].Dimensions = new RateServiceWebReference.Dimensions(); // package dimensions request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Length = _fedexSettings.PassDimensions ? length2.ToString() : "0"; request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Width = _fedexSettings.PassDimensions ? width2.ToString() : "0"; request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Height = _fedexSettings.PassDimensions ? height2.ToString() : "0"; request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Units = RateServiceWebReference.LinearUnits.IN; request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue = new RateServiceWebReference.Money(); // insured value request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue.Amount = orderSubTotal2; request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue.Currency = currencyCode; } } }
/// <summary> /// Create packages (total volume of shopping cart items determines number of packages) /// </summary> /// <param name="shippingOptionRequest">shipping option request</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the packages /// </returns> private async Task <IEnumerable <UPSRate.PackageType> > GetPackagesByCubicRootAsync(GetShippingOptionRequest shippingOptionRequest) { //Dimensional weight is based on volume (the amount of space a package occupies in relation to its actual weight). //If the cubic size of package measures three cubic feet (5,184 cubic inches or 84,951 cubic centimetres) or greater, you will be charged the greater of the dimensional weight or the actual weight. //This algorithm devides total package volume by the UPS settings PackingPackageVolume so that no package requires dimensional weight; this could result in an under-charge. var totalPackagesBySizeLimit = 1; var width = 0M; var length = 0M; var height = 0M; //if there is only one item, no need to calculate dimensions if (shippingOptionRequest.Items.Count == 1 && shippingOptionRequest.Items.FirstOrDefault().GetQuantity() == 1) { //get dimensions and weight of the single cubic size of package var item = shippingOptionRequest.Items.FirstOrDefault(); (width, length, height) = await GetDimensionsForSingleItemAsync(item.ShoppingCartItem, item.Product); } else { //or try to get them var dimension = 0; //get total volume of the package var totalVolume = await shippingOptionRequest.Items.SumAwaitAsync(async item => { //get dimensions and weight of the single item var(itemWidth, itemLength, itemHeight) = await GetDimensionsForSingleItemAsync(item.ShoppingCartItem, item.Product); return(item.GetQuantity() * itemWidth *itemLength *itemHeight); }); if (totalVolume > decimal.Zero) { //use default value (in cubic inches) if not specified var packageVolume = _upsSettings.PackingPackageVolume; if (packageVolume <= 0) { packageVolume = 5184; } //calculate cube root (floor) dimension = Convert.ToInt32(Math.Floor(Math.Pow(Convert.ToDouble(packageVolume), 1.0 / 3.0))); if (GetPackageSize(dimension, dimension, dimension) > await GetSizeLimitAsync()) { throw new NopException("PackingPackageVolume exceeds max package size"); } //adjust package volume for dimensions calculated packageVolume = dimension * dimension * dimension; totalPackagesBySizeLimit = Convert.ToInt32(Math.Ceiling(totalVolume / packageVolume)); } width = length = height = dimension; } //get total packages number according to package limits var weight = await GetWeightAsync(shippingOptionRequest); var weightLimit = await GetWeightLimitAsync(); var totalPackagesByWeightLimit = weight > weightLimit ? Convert.ToInt32(Math.Ceiling(weight / weightLimit)) : 1; var totalPackages = Math.Max(Math.Max(totalPackagesBySizeLimit, totalPackagesByWeightLimit), 1); var insuranceAmountPerPackage = 0; if (_upsSettings.InsurePackage) { //The maximum declared amount per package: 50000 USD. //use subTotalWithoutDiscount as insured value var cart = shippingOptionRequest.Items.Select(item => { var shoppingCartItem = item.ShoppingCartItem; shoppingCartItem.Quantity = item.GetQuantity(); return(shoppingCartItem); }).ToList(); var(_, _, subTotalWithoutDiscount, _, _) = await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(cart, false); insuranceAmountPerPackage = Convert.ToInt32(subTotalWithoutDiscount / totalPackages); } //create packages according to calculated value var package = await CreatePackageAsync(width, length, height, weight / totalPackages, insuranceAmountPerPackage); return(Enumerable.Repeat(package, totalPackages)); }
/// <summary> /// Gets shipping rates /// </summary> /// <param name="shippingOptionRequest">Shipping option request details</param> /// <param name="saturdayDelivery">Whether to get rates for Saturday Delivery</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the shipping options; errors if exist /// </returns> private async Task <(IList <ShippingOption> shippingOptions, string error)> GetShippingOptionsAsync(GetShippingOptionRequest shippingOptionRequest, bool saturdayDelivery = false) { try { //create request details var request = await CreateRateRequestAsync(shippingOptionRequest, saturdayDelivery); //get rate response var rateResponse = await GetRatesAsync(request); //prepare shipping options return((await PrepareShippingOptionsAsync(rateResponse)).Select(shippingOption => { //correct option name if (!shippingOption.Name.ToLowerInvariant().StartsWith("ups")) { shippingOption.Name = $"UPS {shippingOption.Name}"; } if (saturdayDelivery) { shippingOption.Name = $"{shippingOption.Name} - Saturday Delivery"; } //add additional handling charge shippingOption.Rate += _upsSettings.AdditionalHandlingCharge; return shippingOption; }).ToList(), null); } catch (Exception exception) { //log errors var message = $"Error while getting UPS rates{Environment.NewLine}{exception.Message}"; await _logger.ErrorAsync(message, exception, shippingOptionRequest.Customer); return(new List <ShippingOption>(), message); } }
/// <summary> /// Create packages (total dimensions of shopping cart items determines number of packages) /// </summary> /// <param name="shippingOptionRequest">shipping option request</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the packages /// </returns> private async Task <IEnumerable <UPSRate.PackageType> > GetPackagesByDimensionsAsync(GetShippingOptionRequest shippingOptionRequest) { //get dimensions and weight of the whole package var(width, length, height) = await GetDimensionsAsync(shippingOptionRequest.Items); var weight = await GetWeightAsync(shippingOptionRequest); //whether the package doesn't exceed the weight and size limits var weightLimit = await GetWeightLimitAsync(); var sizeLimit = await GetSizeLimitAsync(); if (weight <= weightLimit && GetPackageSize(width, length, height) <= sizeLimit) { var insuranceAmount = 0; if (_upsSettings.InsurePackage) { //The maximum declared amount per package: 50000 USD. //use subTotalWithoutDiscount as insured value var cart = shippingOptionRequest.Items.Select(item => { var shoppingCartItem = item.ShoppingCartItem; shoppingCartItem.Quantity = item.GetQuantity(); return(shoppingCartItem); }).ToList(); var(_, _, subTotalWithoutDiscount, _, _) = await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(cart, false); insuranceAmount = Convert.ToInt32(subTotalWithoutDiscount); } return(new[] { await CreatePackageAsync(width, length, height, weight, insuranceAmount) }); } //get total packages number according to package limits var totalPackagesByWeightLimit = weight > weightLimit ? Convert.ToInt32(Math.Ceiling(weight / weightLimit)) : 1; var totalPackagesBySizeLimit = GetPackageSize(width, length, height) > sizeLimit ? Convert.ToInt32(Math.Ceiling(GetPackageSize(width, length, height) / await GetLengthLimitAsync())) : 1; var totalPackages = Math.Max(Math.Max(totalPackagesBySizeLimit, totalPackagesByWeightLimit), 1); width = Math.Max(width / totalPackages, 1); length = Math.Max(length / totalPackages, 1); height = Math.Max(height / totalPackages, 1); weight = Math.Max(weight / totalPackages, 1); var insuranceAmountPerPackage = 0; if (_upsSettings.InsurePackage) { //The maximum declared amount per package: 50000 USD. //use subTotalWithoutDiscount as insured value var cart = shippingOptionRequest.Items.Select(item => { var shoppingCartItem = item.ShoppingCartItem; shoppingCartItem.Quantity = item.GetQuantity(); return(shoppingCartItem); }).ToList(); var(_, _, subTotalWithoutDiscount, _, _) = await _orderTotalCalculationService.GetShoppingCartSubTotalAsync(cart, false); insuranceAmountPerPackage = Convert.ToInt32(subTotalWithoutDiscount / totalPackages); } //create packages according to calculated value var package = await CreatePackageAsync(width, length, height, weight, insuranceAmountPerPackage); return(Enumerable.Repeat(package, totalPackages)); }
/// <summary> /// Create packages (each shopping cart item is a separate package) /// </summary> /// <param name="shippingOptionRequest">shipping option request</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the packages /// </returns> private async Task <IEnumerable <UPSRate.PackageType> > GetPackagesForOneItemPerPackageAsync(GetShippingOptionRequest shippingOptionRequest) { return(await shippingOptionRequest.Items.SelectManyAwait(async packageItem => { //get dimensions and weight of the single item var(width, length, height) = await GetDimensionsForSingleItemAsync(packageItem.ShoppingCartItem, packageItem.Product); var weight = await GetWeightForSingleItemAsync(packageItem.ShoppingCartItem, shippingOptionRequest.Customer, packageItem.Product); var insuranceAmount = 0; if (_upsSettings.InsurePackage) { //The maximum declared amount per package: 50000 USD. insuranceAmount = Convert.ToInt32(packageItem.Product.Price); } //create packages according to item quantity var package = await CreatePackageAsync(width, length, height, weight, insuranceAmount); return Enumerable.Repeat(package, packageItem.GetQuantity()); }).ToListAsync()); }
/// <summary> /// Create request details to get shipping rates /// </summary> /// <param name="shippingOptionRequest">Shipping option request</param> /// <param name="saturdayDelivery">Whether to get rates for Saturday Delivery</param> /// <returns> /// A task that represents the asynchronous operation /// The task result contains the rate request details /// </returns> private async Task <UPSRate.RateRequest> CreateRateRequestAsync(GetShippingOptionRequest shippingOptionRequest, bool saturdayDelivery = false) { //set request details var request = new UPSRate.RateRequest { Request = new UPSRate.RequestType { //used to define the request type //Shop - the server validates the shipment, and returns rates for all UPS products from the ShipFrom to the ShipTo addresses RequestOption = new[] { "Shop" } } }; //prepare addresses details var stateCodeTo = (await _stateProvinceService.GetStateProvinceByAddressAsync(shippingOptionRequest.ShippingAddress))?.Abbreviation; var stateCodeFrom = shippingOptionRequest.StateProvinceFrom?.Abbreviation; var countryCodeFrom = (shippingOptionRequest.CountryFrom ?? (await _countryService.GetAllCountriesAsync()).FirstOrDefault())?.TwoLetterIsoCode ?? string.Empty; var addressFromDetails = new UPSRate.ShipAddressType { AddressLine = new[] { shippingOptionRequest.AddressFrom }, City = shippingOptionRequest.CityFrom, StateProvinceCode = stateCodeFrom, CountryCode = countryCodeFrom, PostalCode = shippingOptionRequest.ZipPostalCodeFrom }; var addressToDetails = new UPSRate.ShipToAddressType { AddressLine = new[] { shippingOptionRequest.ShippingAddress.Address1, shippingOptionRequest.ShippingAddress.Address2 }, City = shippingOptionRequest.ShippingAddress.City, StateProvinceCode = stateCodeTo, CountryCode = (await _countryService.GetCountryByAddressAsync(shippingOptionRequest.ShippingAddress))?.TwoLetterIsoCode, PostalCode = shippingOptionRequest.ShippingAddress.ZipPostalCode, ResidentialAddressIndicator = string.Empty }; //set shipment details request.Shipment = new UPSRate.ShipmentType { Shipper = new UPSRate.ShipperType { ShipperNumber = _upsSettings.AccountNumber, Address = addressFromDetails }, ShipFrom = new UPSRate.ShipFromType { Address = addressFromDetails }, ShipTo = new UPSRate.ShipToType { Address = addressToDetails } }; //set pickup options and customer classification for US shipments if (countryCodeFrom.Equals("US", StringComparison.InvariantCultureIgnoreCase)) { request.PickupType = new UPSRate.CodeDescriptionType { Code = GetUpsCode(_upsSettings.PickupType) }; request.CustomerClassification = new UPSRate.CodeDescriptionType { Code = GetUpsCode(_upsSettings.CustomerClassification) }; } //set negotiated rates details if (!string.IsNullOrEmpty(_upsSettings.AccountNumber) && !string.IsNullOrEmpty(stateCodeFrom) && !string.IsNullOrEmpty(stateCodeTo)) { request.Shipment.ShipmentRatingOptions = new UPSRate.ShipmentRatingOptionsType { NegotiatedRatesIndicator = string.Empty, UserLevelDiscountIndicator = string.Empty }; } //set Saturday delivery details if (saturdayDelivery) { request.Shipment.ShipmentServiceOptions = new UPSRate.ShipmentServiceOptionsType { SaturdayDeliveryIndicator = string.Empty }; } //set packages details request.Shipment.Package = _upsSettings.PackingType switch { PackingType.PackByOneItemPerPackage => (await GetPackagesForOneItemPerPackageAsync(shippingOptionRequest)).ToArray(), PackingType.PackByVolume => (await GetPackagesByCubicRootAsync(shippingOptionRequest)).ToArray(), _ => (await GetPackagesByDimensionsAsync(shippingOptionRequest)).ToArray() }; return(request); }
private void SetIndividualPackageLineItemsCubicRootDimensions(StringBuilder sb, GetShippingOptionRequest getShippingOptionRequest, UPSPackagingType packagingType, decimal orderSubTotal, string currencyCode) { // Rate request setup - Total Volume of Shopping Cart Items determines number of packages //Dimensional weight is based on volume (the amount of space a package //occupies in relation to its actual weight). If the cubic size of your //package measures three cubic feet (5,184 cubic inches or 84,951 //cubic centimetres) or greater, you will be charged the greater of the //dimensional weight or the actual weight. //This algorithm devides total package volume by the UPS settings PackingPackageVolume //so that no package requires dimensional weight; this could result in an under-charge. var usedMeasureWeight = GetUsedMeasureWeight(); var usedMeasureDimension = GetUsedMeasureDimension(); int totalPackagesDims; int length; int height; int width; if (getShippingOptionRequest.Items.Count == 1 && getShippingOptionRequest.Items[0].GetQuantity() == 1) { var sci = getShippingOptionRequest.Items[0].ShoppingCartItem; //get dimensions for qty 1 decimal lengthTmp, widthTmp, heightTmp; _shippingService.GetDimensions(new List <GetShippingOptionRequest.PackageItem> { new GetShippingOptionRequest.PackageItem(sci, 1) }, out widthTmp, out lengthTmp, out heightTmp); totalPackagesDims = 1; length = ConvertFromPrimaryMeasureDimension(lengthTmp, usedMeasureDimension); height = ConvertFromPrimaryMeasureDimension(heightTmp, usedMeasureDimension); width = ConvertFromPrimaryMeasureDimension(widthTmp, usedMeasureDimension); } else { decimal totalVolume = 0; foreach (var item in getShippingOptionRequest.Items) { var sci = item.ShoppingCartItem; //get dimensions for qty 1 decimal lengthTmp, widthTmp, heightTmp; _shippingService.GetDimensions(new List <GetShippingOptionRequest.PackageItem> { new GetShippingOptionRequest.PackageItem(sci, 1) }, out widthTmp, out lengthTmp, out heightTmp); int productLength = ConvertFromPrimaryMeasureDimension(lengthTmp, usedMeasureDimension); int productHeight = ConvertFromPrimaryMeasureDimension(lengthTmp, usedMeasureDimension); int productWidth = ConvertFromPrimaryMeasureDimension(widthTmp, usedMeasureDimension); totalVolume += item.GetQuantity() * (productHeight * productWidth * productLength); } int dimension; if (totalVolume == 0) { dimension = 0; totalPackagesDims = 1; } else { // cubic inches int packageVolume = _upsSettings.PackingPackageVolume; if (packageVolume <= 0) { packageVolume = 5184; } // cube root (floor) dimension = Convert.ToInt32(Math.Floor(Math.Pow(Convert.ToDouble(packageVolume), (double)(1.0 / 3.0)))); if (IsPackageTooLarge(dimension, dimension, dimension)) { throw new NopException("upsSettings.PackingPackageVolume exceeds max package size"); } // adjust packageVolume for dimensions calculated packageVolume = dimension * dimension * dimension; totalPackagesDims = Convert.ToInt32(Math.Ceiling(totalVolume / packageVolume)); } length = width = height = dimension; } if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } int weight = ConvertFromPrimaryMeasureWeight(_shippingService.GetTotalWeight(getShippingOptionRequest), usedMeasureWeight); if (weight < 1) { weight = 1; } int totalPackagesWeights = 1; if (IsPackageTooHeavy(weight)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling((decimal)weight / (decimal)MAXPACKAGEWEIGHT)); } int totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; int weightPerPackage = weight / totalPackages; //The maximum declared amount per package: 50000 USD. int insuranceAmountPerPackage = _upsSettings.InsurePackage ? Convert.ToInt32(orderSubTotal / totalPackages) : 0; for (int i = 0; i < totalPackages; i++) { AppendPackageRequest(sb, packagingType, length, height, width, weightPerPackage, insuranceAmountPerPackage, currencyCode); } }
private void SetIndividualPackageLineItemsOneItemPerPackage(RateRequest request, GetShippingOptionRequest getShippingOptionRequest, decimal orderSubTotal, string currencyCode) { // Rate request setup - each Shopping Cart Item is a separate package var usedMeasureWeight = GetUsedMeasureWeight(); var usedMeasureDimension = GetUsedMeasureDimension(); var items = getShippingOptionRequest.Items; var totalItems = items.GetTotalProducts(); request.RequestedShipment.PackageCount = totalItems.ToString(); request.RequestedShipment.RequestedPackageLineItems = new RequestedPackageLineItem[totalItems]; int i = 0; foreach (var sci in items) { int length = ConvertFromPrimaryMeasureDimension(sci.Item.Product.Length, usedMeasureDimension); int height = ConvertFromPrimaryMeasureDimension(sci.Item.Product.Height, usedMeasureDimension); int width = ConvertFromPrimaryMeasureDimension(sci.Item.Product.Width, usedMeasureDimension); int weight = ConvertFromPrimaryMeasureWeight(sci.Item.Product.Weight, usedMeasureWeight); if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } if (weight < 1) { weight = 1; } for (int j = 0; j < sci.Item.Quantity; j++) { request.RequestedShipment.RequestedPackageLineItems[i] = new RequestedPackageLineItem(); request.RequestedShipment.RequestedPackageLineItems[i].SequenceNumber = (i + 1).ToString(); // package sequence number request.RequestedShipment.RequestedPackageLineItems[i].Weight = new RateServiceWebReference.Weight(); // package weight request.RequestedShipment.RequestedPackageLineItems[i].Weight.Units = RateServiceWebReference.WeightUnits.LB; request.RequestedShipment.RequestedPackageLineItems[i].Weight.Value = (decimal)weight; request.RequestedShipment.RequestedPackageLineItems[i].Dimensions = new RateServiceWebReference.Dimensions(); // package dimensions request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Length = length.ToString(); request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Height = height.ToString(); request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Width = width.ToString(); request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Units = RateServiceWebReference.LinearUnits.IN; request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue = new RateServiceWebReference.Money(); // insured value request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue.Amount = sci.Item.Product.Price; request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue.Currency = currencyCode; i++; } } }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns>Represents a response of getting shipping rate options</returns> public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException("getShippingOptionRequest"); } var response = new GetShippingOptionResponse(); if (getShippingOptionRequest.Items == null) { response.AddError("No shipment items"); return(response); } if (getShippingOptionRequest.ShippingAddress == null) { response.AddError("Shipping address is not set"); return(response); } if (String.IsNullOrEmpty(getShippingOptionRequest.ShippingAddress.CountryId)) { response.AddError("Shipping country is not set"); return(response); } if (getShippingOptionRequest.CountryFrom == null) { getShippingOptionRequest.CountryFrom = _countryService.GetAllCountries().FirstOrDefault(); } try { string requestString = CreateRequest(_upsSettings.AccessKey, _upsSettings.Username, _upsSettings.Password, getShippingOptionRequest, _upsSettings.CustomerClassification, _upsSettings.PickupType, _upsSettings.PackagingType); if (_upsSettings.Tracing) { _traceMessages.AppendLine("Request:").AppendLine(requestString); } string responseXml = DoRequest(_upsSettings.Url, requestString); if (_upsSettings.Tracing) { _traceMessages.AppendLine("Response:").AppendLine(responseXml); } string error = ""; var shippingOptions = ParseResponse(responseXml, ref error); if (String.IsNullOrEmpty(error)) { foreach (var shippingOption in shippingOptions) { if (!shippingOption.Name.ToLower().StartsWith("ups")) { shippingOption.Name = string.Format("UPS {0}", shippingOption.Name); } shippingOption.Rate += _upsSettings.AdditionalHandlingCharge; response.ShippingOptions.Add(shippingOption); } } else { response.AddError(error); } } finally { if (_upsSettings.Tracing && _traceMessages.Length > 0) { string shortMessage = String.Format("UPS Get Shipping Options for customer {0}. {1} item(s) in cart", getShippingOptionRequest.Customer.Email, getShippingOptionRequest.Items.Count); _logger.Information(shortMessage, new Exception(_traceMessages.ToString()), getShippingOptionRequest.Customer); } } return(response); }
private void SetIndividualPackageLineItemsCubicRootDimensions(RateRequest request, GetShippingOptionRequest getShippingOptionRequest, decimal orderSubTotal, string currencyCode) { // Rate request setup - Total Volume of Shopping Cart Items determines number of packages //From FedEx Guide (Ground): //Dimensional weight is based on volume (the amount of space a package //occupies in relation to its actual weight). If the cubic size of your FedEx //Ground package measures three cubic feet (5,184 cubic inches or 84,951 //cubic centimetres) or greater, you will be charged the greater of the //dimensional weight or the actual weight. //A package weighing 150 lbs. (68 kg) or less and measuring greater than //130 inches (330 cm) in combined length and girth will be classified by //FedEx Ground as an “Oversize” package. All packages must have a //combined length and girth of no more than 165 inches (419 cm). An //oversize charge of $30 per package will also apply to any package //measuring greater than 130 inches (330 cm) in combined length and //girth. //Shipping charges for packages smaller than three cubic feet are based //on actual weight // Dimensional Weight applies to packages with volume 5,184 cubic inches or more // cube root(5184) = 17.3 // Packages that exceed 130 inches in length and girth (2xHeight + 2xWidth) // are considered “oversize” packages. // Assume a cube (H=W=L) of that size: 130 = D + (2xD + 2xD) = 5xD : D = 130/5 = 26 // 26x26x26 = 17,576 // Avoid oversize by using 25" // 25x25x25 = 15,625 // Which is less $ - multiple small pakages, or one large package using dimensional weight // 15,625 / 5184 = 3.014 = 3 packages // Ground for total weight: 60lbs 15lbs // 3 packages 17x17x17 (20 lbs each) = $66.21 39.39 // 1 package 25x25x25 (60 lbs) = $71.70 71.70 var usedMeasureWeight = GetUsedMeasureWeight(); var usedMeasureDimension = GetUsedMeasureDimension(); int totalPackagesDims; int length; int height; int width; if (getShippingOptionRequest.Items.Count == 1 && getShippingOptionRequest.Items[0].Item.Quantity == 1) { totalPackagesDims = 1; var product = getShippingOptionRequest.Items[0].Item.Product; length = ConvertFromPrimaryMeasureDimension(product.Length, usedMeasureDimension); height = ConvertFromPrimaryMeasureDimension(product.Height, usedMeasureDimension); width = ConvertFromPrimaryMeasureDimension(product.Width, usedMeasureDimension); } else { decimal totalVolume = 0; foreach (var item in getShippingOptionRequest.Items) { var product = item.Item.Product; int productLength = ConvertFromPrimaryMeasureDimension(product.Length, usedMeasureDimension); int productHeight = ConvertFromPrimaryMeasureDimension(product.Height, usedMeasureDimension); int productWidth = ConvertFromPrimaryMeasureDimension(product.Width, usedMeasureDimension); totalVolume += item.Item.Quantity * (productHeight * productWidth * productLength); } int dimension; if (totalVolume == 0) { dimension = 0; totalPackagesDims = 1; } else { // cubic inches int packageVolume = _fedexSettings.PackingPackageVolume; if (packageVolume <= 0) { packageVolume = 5184; } // cube root (floor) dimension = Convert.ToInt32(Math.Floor(Math.Pow(Convert.ToDouble(packageVolume), (double)(1.0 / 3.0)))); if (IsPackageTooLarge(dimension, dimension, dimension)) { throw new SmartException("fedexSettings.PackingPackageVolume exceeds max package size"); } // adjust packageVolume for dimensions calculated packageVolume = dimension * dimension * dimension; totalPackagesDims = Convert.ToInt32(Math.Ceiling(totalVolume / packageVolume)); } length = width = height = dimension; } if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } int weight = ConvertFromPrimaryMeasureWeight(_shippingService.GetShoppingCartTotalWeight(getShippingOptionRequest.Items), usedMeasureWeight); if (weight < 1) { weight = 1; } int totalPackagesWeights = 1; if (IsPackageTooHeavy(weight)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling((decimal)weight / (decimal)MAXPACKAGEWEIGHT)); } int totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; decimal orderSubTotalPerPackage = orderSubTotal / totalPackages; int weightPerPackage = weight / totalPackages; request.RequestedShipment.PackageCount = totalPackages.ToString(); request.RequestedShipment.RequestedPackageLineItems = new RequestedPackageLineItem[totalPackages]; for (int i = 0; i < totalPackages; i++) { request.RequestedShipment.RequestedPackageLineItems[i] = new RequestedPackageLineItem(); request.RequestedShipment.RequestedPackageLineItems[i].SequenceNumber = (i + 1).ToString(); // package sequence number request.RequestedShipment.RequestedPackageLineItems[i].Weight = new RateServiceWebReference.Weight(); // package weight request.RequestedShipment.RequestedPackageLineItems[i].Weight.Units = RateServiceWebReference.WeightUnits.LB; request.RequestedShipment.RequestedPackageLineItems[i].Weight.Value = (decimal)weightPerPackage; request.RequestedShipment.RequestedPackageLineItems[i].Dimensions = new RateServiceWebReference.Dimensions(); // package dimensions request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Length = length.ToString(); request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Height = height.ToString(); request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Width = width.ToString(); request.RequestedShipment.RequestedPackageLineItems[i].Dimensions.Units = RateServiceWebReference.LinearUnits.IN; request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue = new RateServiceWebReference.Money(); // insured value request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue.Amount = orderSubTotalPerPackage; request.RequestedShipment.RequestedPackageLineItems[i].InsuredValue.Currency = currencyCode; } }
private string CreateRequest(string username, string password, GetShippingOptionRequest getShippingOptionRequest) { var usedMeasureWeight = _measureService.GetMeasureWeightBySystemKeyword(MEASUREWEIGHTSYSTEMKEYWORD); if (usedMeasureWeight == null) { throw new SmartException(string.Format("USPS shipping service. Could not load \"{0}\" measure weight", MEASUREWEIGHTSYSTEMKEYWORD)); } var baseusedMeasureWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId); if (baseusedMeasureWeight == null) { throw new SmartException("Primary weight can't be loaded"); } var usedMeasureDimension = _measureService.GetMeasureDimensionBySystemKeyword(MEASUREDIMENSIONSYSTEMKEYWORD); if (usedMeasureDimension == null) { throw new SmartException(string.Format("USPS shipping service. Could not load \"{0}\" measure dimension", MEASUREDIMENSIONSYSTEMKEYWORD)); } var baseusedMeasureDimension = _measureService.GetMeasureDimensionById(_measureSettings.BaseDimensionId); if (usedMeasureDimension == null) { throw new SmartException("Primary dimension can't be loaded"); } int length = Convert.ToInt32(Math.Ceiling(getShippingOptionRequest.GetTotalLength() / baseusedMeasureDimension.Ratio * usedMeasureDimension.Ratio)); int height = Convert.ToInt32(Math.Ceiling(getShippingOptionRequest.GetTotalHeight() / baseusedMeasureDimension.Ratio * usedMeasureDimension.Ratio)); int width = Convert.ToInt32(Math.Ceiling(getShippingOptionRequest.GetTotalWidth() / baseusedMeasureDimension.Ratio * usedMeasureDimension.Ratio)); int weight = Convert.ToInt32(Math.Ceiling(_shippingService.GetShoppingCartTotalWeight(getShippingOptionRequest.Items) / baseusedMeasureWeight.Ratio * usedMeasureWeight.Ratio)); if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } if (weight < 1) { weight = 1; } string zipPostalCodeFrom = getShippingOptionRequest.ZipPostalCodeFrom; string zipPostalCodeTo = getShippingOptionRequest.ShippingAddress.ZipPostalCode; //valid values for testing. http://testing.shippingapis.com/ShippingAPITest.dll //Zip to = "20008"; Zip from ="10022"; weight = 2; int pounds = Convert.ToInt32(weight / 16); int ounces = Convert.ToInt32(weight - (pounds * 16.0M)); int girth = height + height + width + width; var taxRate = decimal.Zero; //Get shopping cart sub-total. V2 International rates require the package value to be declared. decimal subTotal = decimal.Zero; foreach (var shoppingCartItem in getShippingOptionRequest.Items) { if (shoppingCartItem.Item.IsFreeShipping || !shoppingCartItem.Item.IsShipEnabled) { continue; } var itemSubTotal = _priceCalculationService.GetSubTotal(shoppingCartItem, true); var itemSubTotalInclTax = _taxService.GetProductPrice(shoppingCartItem.Item.Product, itemSubTotal, true, getShippingOptionRequest.Customer, out taxRate); subTotal += itemSubTotalInclTax; } string requestString = string.Empty; bool isDomestic = IsDomesticRequest(getShippingOptionRequest); if (isDomestic) { #region domestic request zipPostalCodeFrom = zipPostalCodeFrom.Truncate(5).EnsureNumericOnly(); zipPostalCodeTo = zipPostalCodeTo.Truncate(5).EnsureNumericOnly(); var sb = new StringBuilder(); sb.AppendFormat("<RateV4Request USERID=\"{0}\" PASSWORD=\"{1}\">", username, password); sb.Append("<Revision>2</Revision>"); var xmlStrings = new USPSStrings(); // Create new instance with string array if ((!IsPackageTooHeavy(pounds)) && (!IsPackageTooLarge(length, height, width))) { var packageSize = GetPackageSize(length, height, width); // RJH get all XML strings not commented out for USPSStrings. // RJH V3 USPS Service must be Express, Express SH, Express Commercial, Express SH Commercial, First Class, Priority, Priority Commercial, Parcel, Library, BPM, Media, ALL or ONLINE; // AC - Updated to V4 API and made minor improvements to allow First Class Packages (package only - not envelopes). foreach (string element in xmlStrings.Elements) // Loop over elements with property { if ((element == "First Class") && (weight >= 14)) { // AC - At the time of coding there aren't any First Class shipping options for packages over 13 ounces. } else { sb.Append("<Package ID=\"0\">"); sb.AppendFormat("<Service>{0}</Service>", element); if (element == "First Class") { sb.Append("<FirstClassMailType>PARCEL</FirstClassMailType>"); } sb.AppendFormat("<ZipOrigination>{0}</ZipOrigination>", zipPostalCodeFrom); sb.AppendFormat("<ZipDestination>{0}</ZipDestination>", zipPostalCodeTo); sb.AppendFormat("<Pounds>{0}</Pounds>", pounds); sb.AppendFormat("<Ounces>{0}</Ounces>", ounces); sb.Append("<Container/>"); sb.AppendFormat("<Size>{0}</Size>", packageSize); sb.AppendFormat("<Width>{0}</Width>", width); sb.AppendFormat("<Length>{0}</Length>", length); sb.AppendFormat("<Height>{0}</Height>", height); sb.AppendFormat("<Girth>{0}</Girth>", girth); sb.Append("<Machinable>FALSE</Machinable>"); sb.Append("</Package>"); } } } else { int totalPackages = 1; int totalPackagesDims = 1; int totalPackagesWeights = 1; if (IsPackageTooHeavy(pounds)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling((decimal)pounds / (decimal)MAXPACKAGEWEIGHT)); } if (IsPackageTooLarge(length, height, width)) { totalPackagesDims = Convert.ToInt32(Math.Ceiling((decimal)TotalPackageSize(length, height, width) / (decimal)108)); } totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; if (totalPackages == 0) { totalPackages = 1; } int pounds2 = pounds / totalPackages; //we don't use ounces int ounces2 = ounces / totalPackages; int height2 = height / totalPackages; int width2 = width / totalPackages; int length2 = length / totalPackages; if (pounds2 < 1) { pounds2 = 1; } if (height2 < 1) { height2 = 1; } if (width2 < 1) { width2 = 1; } if (length2 < 1) { length2 = 1; } var packageSize = GetPackageSize(length2, height2, width2); int girth2 = height2 + height2 + width2 + width2; for (int i = 0; i < totalPackages; i++) { foreach (string element in xmlStrings.Elements) { if ((element == "First Class") && (weight >= 14)) { // AC - At the time of coding there aren't any First Class shipping options for packages over 13 ounces. } else { sb.AppendFormat("<Package ID=\"{0}\">", i.ToString()); sb.AppendFormat("<Service>{0}</Service>", element); if (element == "First Class") { sb.Append("<FirstClassMailType>PARCEL</FirstClassMailType>"); } sb.AppendFormat("<ZipOrigination>{0}</ZipOrigination>", zipPostalCodeFrom); sb.AppendFormat("<ZipDestination>{0}</ZipDestination>", zipPostalCodeTo); sb.AppendFormat("<Pounds>{0}</Pounds>", pounds2); sb.AppendFormat("<Ounces>{0}</Ounces>", ounces2); sb.Append("<Container/>"); sb.AppendFormat("<Size>{0}</Size>", packageSize); sb.AppendFormat("<Width>{0}</Width>", width2); sb.AppendFormat("<Length>{0}</Length>", length2); sb.AppendFormat("<Height>{0}</Height>", height2); sb.AppendFormat("<Girth>{0}</Girth>", girth2); sb.Append("<Machinable>FALSE</Machinable>"); sb.Append("</Package>"); } } } } sb.Append("</RateV4Request>"); requestString = "API=RateV4&XML=" + sb.ToString(); #endregion } else { #region international request var sb = new StringBuilder(); // sb.AppendFormat("<IntlRateRequest USERID=\"{0}\" PASSWORD=\"{1}\">", username, password); sb.AppendFormat("<IntlRateV2Request USERID=\"{0}\" PASSWORD=\"{1}\">", username, password); //V2 International rates require the package value to be declared. Max content value for most shipping options is $400 so it is limited here. decimal intlSubTotal = decimal.Zero; if (subTotal > 400) { intlSubTotal = 400; } else { intlSubTotal = subTotal; } //little hack here for international requests length = 12; width = 12; height = 12; girth = height + height + width + width; string mailType = "Package"; //Package, Envelope var packageSize = GetPackageSize(length, height, width); if ((!IsPackageTooHeavy(pounds)) && (!IsPackageTooLarge(length, height, width))) { sb.Append("<Package ID=\"0\">"); sb.AppendFormat("<Pounds>{0}</Pounds>", pounds); sb.AppendFormat("<Ounces>{0}</Ounces>", ounces); sb.Append("<Machinable>FALSE</Machinable>"); sb.AppendFormat("<MailType>{0}</MailType>", mailType); sb.Append("<GXG>"); sb.Append("<POBoxFlag>N</POBoxFlag>"); sb.Append("<GiftFlag>N</GiftFlag>"); sb.Append("</GXG>"); sb.AppendFormat("<ValueOfContents>{0}</ValueOfContents>", intlSubTotal); sb.AppendFormat("<Country>{0}</Country>", getShippingOptionRequest.ShippingAddress.Country.Name); sb.Append("<Container>RECTANGULAR</Container>"); sb.AppendFormat("<Size>{0}</Size>", packageSize); sb.AppendFormat("<Width>{0}</Width>", width); sb.AppendFormat("<Length>{0}</Length>", length); sb.AppendFormat("<Height>{0}</Height>", height); sb.AppendFormat("<Girth>{0}</Girth>", girth); sb.Append("<CommercialFlag>N</CommercialFlag>"); sb.Append("</Package>"); } else { int totalPackages = 1; int totalPackagesDims = 1; int totalPackagesWeights = 1; if (IsPackageTooHeavy(pounds)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling((decimal)pounds / (decimal)MAXPACKAGEWEIGHT)); } if (IsPackageTooLarge(length, height, width)) { totalPackagesDims = Convert.ToInt32(Math.Ceiling((decimal)TotalPackageSize(length, height, width) / (decimal)108)); } totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; if (totalPackages == 0) { totalPackages = 1; } int pounds2 = pounds / totalPackages; //we don't use ounces int ounces2 = ounces / totalPackages; int height2 = height / totalPackages; int width2 = width / totalPackages; int length2 = length / totalPackages; if (pounds2 < 1) { pounds2 = 1; } if (height2 < 1) { height2 = 1; } if (width2 < 1) { width2 = 1; } if (length2 < 1) { length2 = 1; } //little hack here for international requests length2 = 12; width2 = 12; height2 = 12; var packageSize2 = GetPackageSize(length2, height2, width2); int girth2 = height2 + height2 + width2 + width2; for (int i = 0; i < totalPackages; i++) { sb.AppendFormat("<Package ID=\"{0}\">", i.ToString()); sb.AppendFormat("<Pounds>{0}</Pounds>", pounds2); sb.AppendFormat("<Ounces>{0}</Ounces>", ounces2); sb.Append("<Machinable>FALSE</Machinable>"); sb.AppendFormat("<MailType>{0}</MailType>", mailType); sb.Append("<GXG>"); sb.Append("<POBoxFlag>N</POBoxFlag>"); sb.Append("<GiftFlag>N</GiftFlag>"); sb.Append("</GXG>"); sb.AppendFormat("<ValueOfContents>{0}</ValueOfContents>", intlSubTotal); sb.AppendFormat("<Country>{0}</Country>", getShippingOptionRequest.ShippingAddress.Country.Name); sb.Append("<Container>RECTANGULAR</Container>"); sb.AppendFormat("<Size>{0}</Size>", packageSize2); sb.AppendFormat("<Width>{0}</Width>", width2); sb.AppendFormat("<Length>{0}</Length>", length2); sb.AppendFormat("<Height>{0}</Height>", height2); sb.AppendFormat("<Girth>{0}</Girth>", girth2); sb.Append("<CommercialFlag>N</CommercialFlag>"); sb.Append("</Package>"); } } sb.Append("</IntlRateV2Request>"); requestString = "API=IntlRateV2&XML=" + sb.ToString(); #endregion } return(requestString); }
private RateRequest CreateRateRequest(GetShippingOptionRequest getShippingOptionRequest, out Currency requestedShipmentCurrency) { // Build the RateRequest var request = new RateRequest(); request.WebAuthenticationDetail = new RateServiceWebReference.WebAuthenticationDetail(); request.WebAuthenticationDetail.UserCredential = new RateServiceWebReference.WebAuthenticationCredential(); request.WebAuthenticationDetail.UserCredential.Key = _fedexSettings.Key; request.WebAuthenticationDetail.UserCredential.Password = _fedexSettings.Password; request.ClientDetail = new RateServiceWebReference.ClientDetail(); request.ClientDetail.AccountNumber = _fedexSettings.AccountNumber; request.ClientDetail.MeterNumber = _fedexSettings.MeterNumber; request.TransactionDetail = new RateServiceWebReference.TransactionDetail(); request.TransactionDetail.CustomerTransactionId = "***Rate Available Services v7 Request***"; // This is a reference field for the customer. Any value can be used and will be provided in the response. request.Version = new RateServiceWebReference.VersionId(); // WSDL version information, value is automatically set from wsdl request.ReturnTransitAndCommit = true; request.ReturnTransitAndCommitSpecified = true; request.CarrierCodes = new RateServiceWebReference.CarrierCodeType[2]; // Insert the Carriers you would like to see the rates for request.CarrierCodes[0] = RateServiceWebReference.CarrierCodeType.FDXE; request.CarrierCodes[1] = RateServiceWebReference.CarrierCodeType.FDXG; decimal subTotalBase = decimal.Zero; decimal orderSubTotalDiscountAmount = decimal.Zero; Discount orderSubTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; _orderTotalCalculationService.GetShoppingCartSubTotal(getShippingOptionRequest.Items, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); subTotalBase = subTotalWithDiscountBase; request.RequestedShipment = new RequestedShipment(); SetOrigin(request, getShippingOptionRequest); SetDestination(request, getShippingOptionRequest); requestedShipmentCurrency = GetRequestedShipmentCurrency( request.RequestedShipment.Shipper.Address.CountryCode, // origin request.RequestedShipment.Recipient.Address.CountryCode); // destination decimal subTotalShipmentCurrency; var primaryStoreCurrency = _services.StoreContext.CurrentStore.PrimaryStoreCurrency; if (requestedShipmentCurrency.CurrencyCode == primaryStoreCurrency.CurrencyCode) { subTotalShipmentCurrency = subTotalBase; } else { subTotalShipmentCurrency = _currencyService.ConvertFromPrimaryStoreCurrency(subTotalBase, requestedShipmentCurrency); } Debug.WriteLine(String.Format("SubTotal (Primary Currency) : {0} ({1})", subTotalBase, primaryStoreCurrency.CurrencyCode)); Debug.WriteLine(String.Format("SubTotal (Shipment Currency): {0} ({1})", subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode)); SetShipmentDetails(request, getShippingOptionRequest, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); SetPayment(request, getShippingOptionRequest); switch (_fedexSettings.PackingType) { case PackingType.PackByOneItemPerPackage: SetIndividualPackageLineItemsOneItemPerPackage(request, getShippingOptionRequest, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); break; case PackingType.PackByVolume: SetIndividualPackageLineItemsCubicRootDimensions(request, getShippingOptionRequest, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); break; case PackingType.PackByDimensions: default: SetIndividualPackageLineItems(request, getShippingOptionRequest, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); break; } return(request); }
/// <summary> /// Create request details to get shipping rates /// </summary> /// <param name="shippingOptionRequest">Shipping option request</param> /// <param name="saturdayDelivery">Whether to get rates for Saturday Delivery</param> /// <returns>Rate request details</returns> private FedexRate.RateRequest CreateRateRequest(GetShippingOptionRequest shippingOptionRequest, out Currency requestedShipmentCurrency) { // Build the RateRequest var request = new FedexRate.RateRequest { WebAuthenticationDetail = new FedexRate.WebAuthenticationDetail { UserCredential = new FedexRate.WebAuthenticationCredential { Key = _fedexSettings.Key, Password = _fedexSettings.Password } }, ClientDetail = new FedexRate.ClientDetail { AccountNumber = _fedexSettings.AccountNumber, MeterNumber = _fedexSettings.MeterNumber }, TransactionDetail = new FedexRate.TransactionDetail { CustomerTransactionId = "***Rate Available Services v16 Request - nopCommerce***" // This is a reference field for the customer. Any value can be used and will be provided in the response. }, Version = new FedexRate.VersionId(), // WSDL version information, value is automatically set from wsdl ReturnTransitAndCommit = true, ReturnTransitAndCommitSpecified = true, // Insert the Carriers you would like to see the rates for CarrierCodes = new[] { FedexRate.CarrierCodeType.FDXE, FedexRate.CarrierCodeType.FDXG } }; //TODO we should use getShippingOptionRequest.Items.GetQuantity() method to get subtotal _orderTotalCalculationService.GetShoppingCartSubTotal( shippingOptionRequest.Items.Select(x => x.ShoppingCartItem).ToList(), false, out var _, out var _, out var _, out var subTotalWithDiscountBase); request.RequestedShipment = new FedexRate.RequestedShipment(); SetOrigin(request, shippingOptionRequest); SetDestination(request, shippingOptionRequest); requestedShipmentCurrency = GetRequestedShipmentCurrency( request.RequestedShipment.Shipper.Address.CountryCode, // origin request.RequestedShipment.Recipient.Address.CountryCode); // destination decimal subTotalShipmentCurrency; var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); if (requestedShipmentCurrency.CurrencyCode == primaryStoreCurrency.CurrencyCode) { subTotalShipmentCurrency = subTotalWithDiscountBase; } else { subTotalShipmentCurrency = _currencyService.ConvertFromPrimaryStoreCurrency(subTotalWithDiscountBase, requestedShipmentCurrency); } Debug.WriteLine($"SubTotal (Primary Currency) : {subTotalWithDiscountBase} ({primaryStoreCurrency.CurrencyCode})"); Debug.WriteLine($"SubTotal (Shipment Currency): {subTotalShipmentCurrency} ({requestedShipmentCurrency.CurrencyCode})"); SetShipmentDetails(request, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); SetPayment(request); //set packages details switch (_fedexSettings.PackingType) { case PackingType.PackByOneItemPerPackage: SetIndividualPackageLineItemsOneItemPerPackage(request, shippingOptionRequest, requestedShipmentCurrency.CurrencyCode); break; case PackingType.PackByVolume: SetIndividualPackageLineItemsCubicRootDimensions(request, shippingOptionRequest, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); break; case PackingType.PackByDimensions: default: SetIndividualPackageLineItems(request, shippingOptionRequest, subTotalShipmentCurrency, requestedShipmentCurrency.CurrencyCode); break; } return(request); }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns>Represents a response of getting shipping rate options</returns> public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException("getShippingOptionRequest"); } var response = new GetShippingOptionResponse(); if (getShippingOptionRequest.Items == null) { response.AddError(T("Admin.System.Warnings.NoShipmentItems")); return(response); } if (getShippingOptionRequest.ShippingAddress == null || getShippingOptionRequest.ShippingAddress.Country == null) { return(response); } Currency requestedShipmentCurrency; var request = CreateRateRequest(getShippingOptionRequest, out requestedShipmentCurrency); var service = new RateService(); // Initialize the service service.Url = _fedexSettings.Url; try { // This is the call to the web service passing in a RateRequest and returning a RateReply var reply = service.getRates(request); // Service call if (reply.HighestSeverity == RateServiceWebReference.NotificationSeverityType.SUCCESS || reply.HighestSeverity == RateServiceWebReference.NotificationSeverityType.NOTE || reply.HighestSeverity == RateServiceWebReference.NotificationSeverityType.WARNING) // check if the call was successful { if (reply != null && reply.RateReplyDetails != null) { var shippingOptions = ParseResponse(reply, requestedShipmentCurrency); foreach (var shippingOption in shippingOptions) { response.ShippingOptions.Add(shippingOption); } } else { if (reply != null && reply.Notifications != null && reply.Notifications.Length > 0 && !String.IsNullOrEmpty(reply.Notifications[0].Message)) { response.AddError(string.Format("{0} (code: {1})", reply.Notifications[0].Message, reply.Notifications[0].Code)); return(response); } else { response.AddError("Could not get reply from shipping server"); return(response); } } } else { Debug.WriteLine(reply.Notifications[0].Message); response.AddError(reply.Notifications[0].Message); return(response); } } catch (SoapException e) { Debug.WriteLine(e.Detail.InnerText); response.AddError(e.Detail.InnerText); return(response); } catch (Exception e) { Debug.WriteLine(e.Message); response.AddError(e.Message); return(response); } return(response); }
/// <summary> /// Create packages (each shopping cart item is a separate package) /// </summary> /// <param name="request">Shipping request</param> /// <param name="getShippingOptionRequest">Shipping option request</param> /// <param name="currencyCode">Currency code</param> private void SetIndividualPackageLineItemsOneItemPerPackage(FedexRate.RateRequest request, GetShippingOptionRequest getShippingOptionRequest, string currencyCode) { // Rate request setup - each Shopping Cart Item is a separate package var i = 1; var items = getShippingOptionRequest.Items; var totalItems = items.Sum(x => x.GetQuantity()); request.RequestedShipment.PackageCount = totalItems.ToString(); request.RequestedShipment.RequestedPackageLineItems = getShippingOptionRequest.Items.SelectMany(packageItem => { //get dimensions and weight of the single item var(width, length, height) = GetDimensionsForSingleItem(packageItem.ShoppingCartItem); var weight = GetWeightForSingleItem(packageItem.ShoppingCartItem); var package = CreatePackage(width, length, height, weight, packageItem.ShoppingCartItem.Product.Price, (i + 1).ToString(), currencyCode); package.GroupPackageCount = "1"; var packs = Enumerable.Range(i, packageItem.GetQuantity()) .Select(j => CreatePackage(width, length, height, weight, packageItem.ShoppingCartItem.Product.Price, j.ToString(), currencyCode)).ToArray(); i += packageItem.GetQuantity(); return(packs); }).ToArray(); }
public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException("getShippingOptionRequest"); } var response = new GetShippingOptionResponse(); if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) { response.AddError("No shipment items"); return(response); } if (getShippingOptionRequest.ShippingAddress == null) { response.AddError("Shipping address is not set"); return(response); } if (getShippingOptionRequest.ShippingAddress.Country == null) { response.AddError("Shipping country is not set"); return(response); } var orderRef = "NOP" + getShippingOptionRequest.Items.FirstOrDefault().ShoppingCartItem.Id; var checkSum = CheckSumCalculator.CalculateChecksum( new Dictionary <string, string> { { "accountId", _settings.AccountId }, { "action", "START" }, { "customerCountry", getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode }, { "orderReference", orderRef } }, _settings.PassPhrase); var storeUrl = _storeContext.CurrentStore.Url; if (!storeUrl.EndsWith("/")) { storeUrl += "/"; } var confirmUrl = storeUrl + "Plugins/BpostShippingManager/ConfirmHandler"; var cancelUrl = storeUrl + "Plugins/BpostShippingManager/CancelHandler"; var errorUrl = storeUrl + "Plugins/BpostShippingManager/ErrorHandler"; var street = string.Empty; var streetNumber = string.Empty; if (!string.IsNullOrEmpty(getShippingOptionRequest.ShippingAddress.Address1)) { var streetNumberStart = getShippingOptionRequest.ShippingAddress.Address1.IndexOfAny("0123456789".ToCharArray()); if (streetNumberStart >= 0) { street = getShippingOptionRequest.ShippingAddress.Address1.Substring(0, streetNumberStart - 1); streetNumber = getShippingOptionRequest.ShippingAddress.Address1.Substring(streetNumberStart); } } var rate = _workContext.CurrentCustomer.GetAttribute <decimal>(CustomCustomerAttributeNames.DeliveryMethodRate, _storeContext.CurrentStore.Id); var deliveryMethodAddress = _workContext.CurrentCustomer.GetAttribute <string>(CustomCustomerAttributeNames.DeliveryMethodAddress, _storeContext.CurrentStore.Id); var deliveryMethod = _workContext.CurrentCustomer.GetAttribute <string>(CustomCustomerAttributeNames.DeliveryMethod, _storeContext.CurrentStore.Id); LocaleStringResource deliveryMethodDescription = null; var buttonDiv = string.Empty; var loadShm = string.Format( "loadShm('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}', '{10}', '{11}', '{12}', '{13}', '{14}');", _settings.AccountId, orderRef, getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode, checkSum, getShippingOptionRequest.ShippingAddress.FirstName, getShippingOptionRequest.ShippingAddress.LastName, getShippingOptionRequest.Customer.Email, street, getShippingOptionRequest.ShippingAddress.ZipPostalCode, getShippingOptionRequest.ShippingAddress.City, confirmUrl, cancelUrl, errorUrl, _workContext.WorkingLanguage.UniqueSeoCode, streetNumber); var startupShmScript = @"<script>$(document).ready(function() { " + loadShm + " expandShm(); }); </script>"; if (!string.IsNullOrEmpty(deliveryMethod)) { deliveryMethodDescription = _localizationService.GetLocaleStringResourceByName( $"MakeIT.Nop.Shipping.Bpost.ShippingManager.DeliveryMethod.{deliveryMethod.Replace(" ", "")}"); buttonDiv = @"<div><input class='{13}' type='button' onclick=""loadShm('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', '{7}', '{8}', '{9}', '{10}', '{11}', '{12}', '{15}', '{16}');"" value='{14}'></div>"; startupShmScript = @" <script> $(document).ready(function() { collapseShm(); }); </script> "; } var collectPoint = String.Empty; if (!string.IsNullOrEmpty(deliveryMethodAddress) && deliveryMethodDescription != null) { collectPoint = $"<div style='margin-bottom: 10px;'>{deliveryMethodDescription.ResourceValue}<br/>{deliveryMethodAddress}</div>"; } var description = string.Format( collectPoint + buttonDiv + @"<div id='shm-inline-container' style='width: 100%; margin-top: 10px;'></div>", _settings.AccountId, orderRef, getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode, checkSum, getShippingOptionRequest.ShippingAddress.FirstName, getShippingOptionRequest.ShippingAddress.LastName, getShippingOptionRequest.Customer.Email, street, getShippingOptionRequest.ShippingAddress.ZipPostalCode, getShippingOptionRequest.ShippingAddress.City, confirmUrl, cancelUrl, errorUrl, _settings.ButtonCssClass, _localizationService.GetResource("MakeIT.Nop.Shipping.Bpost.ShippingManager.ButtonCaption"), _workContext.WorkingLanguage.UniqueSeoCode, streetNumber); var shmShippingOption = new ShippingOption { Name = _localizationService.GetResource("MakeIT.Nop.Shipping.Bpost.ShippingManager.ShippingOptionTitle"), Rate = (rate > 0) ? rate : _settings.Standardprice, ShippingRateComputationMethodSystemName = "Shipping.Bpost.ShippingManager", Description = description + startupShmScript }; response.ShippingOptions.Add(shmShippingOption); return(response); }
/// <summary> /// Gets available shipping options /// </summary> /// <param name="getShippingOptionRequest">A request for getting shipping options</param> /// <returns>Represents a response of getting shipping rate options</returns> public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) { if (getShippingOptionRequest == null) { throw new ArgumentNullException("getShippingOptionRequest"); } if (getShippingOptionRequest.Items == null) { return new GetShippingOptionResponse { Errors = new List <string> { "No shipment items" } } } ; if (getShippingOptionRequest.ShippingAddress == null) { return new GetShippingOptionResponse { Errors = new List <string> { "Shipping address is not set" } } } ; if (getShippingOptionRequest.ShippingAddress.Country == null) { return new GetShippingOptionResponse { Errors = new List <string> { "Shipping country is not set" } } } ; if (string.IsNullOrEmpty(getShippingOptionRequest.ZipPostalCodeFrom)) { return new GetShippingOptionResponse { Errors = new List <string> { "Origin postal code is not set" } } } ; //get available services string errors; var availableServices = CanadaPostHelper.GetServices(getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode, _canadaPostSettings.ApiKey, _canadaPostSettings.UseSandbox, out errors); if (availableServices == null) { return new GetShippingOptionResponse { Errors = new List <string> { errors } } } ; //create object for the get rates requests var result = new GetShippingOptionResponse(); object destinationCountry; switch (getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode.ToLowerInvariant()) { case "us": destinationCountry = new mailingscenarioDestinationUnitedstates { zipcode = getShippingOptionRequest.ShippingAddress.ZipPostalCode }; break; case "ca": destinationCountry = new mailingscenarioDestinationDomestic { postalcode = getShippingOptionRequest.ShippingAddress.ZipPostalCode.Replace(" ", string.Empty).ToUpperInvariant() }; break; default: destinationCountry = new mailingscenarioDestinationInternational { countrycode = getShippingOptionRequest.ShippingAddress.Country.TwoLetterIsoCode }; break; } var mailingScenario = new mailingscenario { quotetype = mailingscenarioQuotetype.counter, quotetypeSpecified = true, originpostalcode = getShippingOptionRequest.ZipPostalCodeFrom.Replace(" ", string.Empty).ToUpperInvariant(), destination = new mailingscenarioDestination { Item = destinationCountry } }; //set contract customer properties if (!string.IsNullOrEmpty(_canadaPostSettings.CustomerNumber)) { mailingScenario.quotetype = mailingscenarioQuotetype.commercial; mailingScenario.customernumber = _canadaPostSettings.CustomerNumber; mailingScenario.contractid = !string.IsNullOrEmpty(_canadaPostSettings.ContractId) ? _canadaPostSettings.ContractId : null; } //get original parcel characteristics decimal originalLength; decimal originalWidth; decimal originalHeight; decimal originalWeight; GetWeight(getShippingOptionRequest, out originalWeight); GetDimensions(getShippingOptionRequest, out originalLength, out originalWidth, out originalHeight); //get rate for all available services var errorSummary = new StringBuilder(); foreach (var service in availableServices.service) { var currentService = CanadaPostHelper.GetServiceDetails(_canadaPostSettings.ApiKey, service.link.href, service.link.mediatype, out errors); if (currentService != null) { #region parcels count calculation var totalParcels = 1; //parcels count by weight var maxWeight = currentService.restrictions != null && currentService.restrictions.weightrestriction != null && currentService.restrictions.weightrestriction.maxSpecified ? currentService.restrictions.weightrestriction.max : int.MaxValue; if (originalWeight * 1000 > maxWeight) { var parcelsOnWeight = Convert.ToInt32(Math.Ceiling(originalWeight * 1000 / maxWeight)); if (parcelsOnWeight > totalParcels) { totalParcels = parcelsOnWeight; } } //parcels count by length var maxLength = currentService.restrictions != null && currentService.restrictions.dimensionalrestrictions != null && currentService.restrictions.dimensionalrestrictions.length != null && currentService.restrictions.dimensionalrestrictions.length.maxSpecified ? currentService.restrictions.dimensionalrestrictions.length.max : int.MaxValue; if (originalLength > maxLength) { var parcelsOnLength = Convert.ToInt32(Math.Ceiling(originalLength / maxLength)); if (parcelsOnLength > totalParcels) { totalParcels = parcelsOnLength; } } //parcels count by width var maxWidth = currentService.restrictions != null && currentService.restrictions.dimensionalrestrictions != null && currentService.restrictions.dimensionalrestrictions.width != null && currentService.restrictions.dimensionalrestrictions.width.maxSpecified ? currentService.restrictions.dimensionalrestrictions.width.max : int.MaxValue; if (originalWidth > maxWidth) { var parcelsOnWidth = Convert.ToInt32(Math.Ceiling(originalWidth / maxWidth)); if (parcelsOnWidth > totalParcels) { totalParcels = parcelsOnWidth; } } //parcels count by height var maxHeight = currentService.restrictions != null && currentService.restrictions.dimensionalrestrictions != null && currentService.restrictions.dimensionalrestrictions.height != null && currentService.restrictions.dimensionalrestrictions.height.maxSpecified ? currentService.restrictions.dimensionalrestrictions.height.max : int.MaxValue; if (originalHeight > maxHeight) { var parcelsOnHeight = Convert.ToInt32(Math.Ceiling(originalHeight / maxHeight)); if (parcelsOnHeight > totalParcels) { totalParcels = parcelsOnHeight; } } //parcel count by girth var lengthPlusGirthMax = currentService.restrictions != null && currentService.restrictions.dimensionalrestrictions != null && currentService.restrictions.dimensionalrestrictions.lengthplusgirthmaxSpecified ? currentService.restrictions.dimensionalrestrictions.lengthplusgirthmax : int.MaxValue; var lengthPlusGirth = 2 * (originalWidth + originalHeight) + originalLength; if (lengthPlusGirth > lengthPlusGirthMax) { var parcelsOnHeight = Convert.ToInt32(Math.Ceiling(lengthPlusGirth / lengthPlusGirthMax)); if (parcelsOnHeight > totalParcels) { totalParcels = parcelsOnHeight; } } //parcel count by sum of length, width and height var lengthWidthHeightMax = currentService.restrictions != null && currentService.restrictions.dimensionalrestrictions != null && currentService.restrictions.dimensionalrestrictions.lengthheightwidthsummaxSpecified ? currentService.restrictions.dimensionalrestrictions.lengthheightwidthsummax : int.MaxValue; var lengthWidthHeight = originalLength + originalWidth + originalHeight; if (lengthWidthHeight > lengthWidthHeightMax) { var parcelsOnHeight = Convert.ToInt32(Math.Ceiling(lengthWidthHeight / lengthWidthHeightMax)); if (parcelsOnHeight > totalParcels) { totalParcels = parcelsOnHeight; } } #endregion //set parcel characteristics mailingScenario.services = new[] { currentService.servicecode }; mailingScenario.parcelcharacteristics = new mailingscenarioParcelcharacteristics { weight = Math.Round(originalWeight / totalParcels, 3), dimensions = new mailingscenarioParcelcharacteristicsDimensions { length = Math.Round(originalLength / totalParcels, 1), width = Math.Round(originalWidth / totalParcels, 1), height = Math.Round(originalHeight / totalParcels, 1) } }; //get rate var priceQuotes = CanadaPostHelper.GetShippingRates(mailingScenario, _canadaPostSettings.ApiKey, _canadaPostSettings.UseSandbox, out errors); if (priceQuotes != null) { foreach (var option in priceQuotes.pricequote) { result.ShippingOptions.Add(new ShippingOption { Name = option.servicename, Rate = PriceToPrimaryStoreCurrency(option.pricedetails.due * totalParcels), Description = string.Format("Delivery {0}into {1} parcels", option.servicestandard != null && !string.IsNullOrEmpty(option.servicestandard.expectedtransittime) ? string.Format("in {0} days ", option.servicestandard.expectedtransittime) : string.Empty, totalParcels), }); } } else { errorSummary.AppendLine(errors); } } else { errorSummary.AppendLine(errors); } } //write errors var errorString = errorSummary.ToString(); if (!string.IsNullOrEmpty(errorString)) { _logger.Error(errorString); } if (!result.ShippingOptions.Any()) { result.AddError(errorString); } return(result); }
private void SetIndividualPackageLineItems(StringBuilder sb, GetShippingOptionRequest getShippingOptionRequest, UPSPackagingType packagingType, decimal orderSubTotal, string currencyCode) { // Rate request setup - Total Dimensions of Shopping Cart Items determines number of packages var usedMeasureWeight = GetUsedMeasureWeight(); var usedMeasureDimension = GetUsedMeasureDimension(); decimal lengthTmp, widthTmp, heightTmp; _shippingService.GetDimensions(getShippingOptionRequest.Items, out widthTmp, out lengthTmp, out heightTmp); int length = ConvertFromPrimaryMeasureDimension(lengthTmp, usedMeasureDimension); int height = ConvertFromPrimaryMeasureDimension(heightTmp, usedMeasureDimension); int width = ConvertFromPrimaryMeasureDimension(widthTmp, usedMeasureDimension); int weight = ConvertFromPrimaryMeasureWeight(_shippingService.GetTotalWeight(getShippingOptionRequest), usedMeasureWeight); if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } if (weight < 1) { weight = 1; } if ((!IsPackageTooHeavy(weight)) && (!IsPackageTooLarge(length, height, width))) { if (!_upsSettings.PassDimensions) { length = width = height = 0; } int insuranceAmount = _upsSettings.InsurePackage ? Convert.ToInt32(orderSubTotal) : 0; AppendPackageRequest(sb, packagingType, length, height, width, weight, insuranceAmount, currencyCode); } else { int totalPackagesDims = 1; int totalPackagesWeights = 1; if (IsPackageTooHeavy(weight)) { totalPackagesWeights = Convert.ToInt32(Math.Ceiling((decimal)weight / (decimal)MAXPACKAGEWEIGHT)); } if (IsPackageTooLarge(length, height, width)) { totalPackagesDims = Convert.ToInt32(Math.Ceiling((decimal)TotalPackageSize(length, height, width) / (decimal)108)); } var totalPackages = totalPackagesDims > totalPackagesWeights ? totalPackagesDims : totalPackagesWeights; if (totalPackages == 0) { totalPackages = 1; } int weight2 = weight / totalPackages; int height2 = height / totalPackages; int width2 = width / totalPackages; int length2 = length / totalPackages; if (weight2 < 1) { weight2 = 1; } if (height2 < 1) { height2 = 1; } if (width2 < 1) { width2 = 1; } if (length2 < 1) { length2 = 1; } if (!_upsSettings.PassDimensions) { length2 = width2 = height2 = 0; } //The maximum declared amount per package: 50000 USD. int insuranceAmountPerPackage = _upsSettings.InsurePackage ? Convert.ToInt32(orderSubTotal / totalPackages) : 0; for (int i = 0; i < totalPackages; i++) { AppendPackageRequest(sb, packagingType, length2, height2, width2, weight2, insuranceAmountPerPackage, currencyCode); } } }
public static string GetFromPostalCode(IAddressService _addressService, ShippingSettings _shippingSettings, GetShippingOptionRequest getShippingOptionRequest) { if (String.IsNullOrEmpty(getShippingOptionRequest.ZipPostalCodeFrom)) { return(_addressService.GetAddressById(_shippingSettings.ShippingOriginAddressId).ZipPostalCode); } else { return(getShippingOptionRequest.ZipPostalCodeFrom); } }
private void SetIndividualPackageLineItemsOneItemPerPackage(StringBuilder sb, GetShippingOptionRequest getShippingOptionRequest, UPSPackagingType packagingType, string currencyCode) { // Rate request setup - each Shopping Cart Item is a separate package var usedMeasureWeight = GetUsedMeasureWeight(); var usedMeasureDimension = GetUsedMeasureDimension(); foreach (var packageItem in getShippingOptionRequest.Items) { var sci = packageItem.ShoppingCartItem; var qty = packageItem.GetQuantity(); //get dimensions for qty 1 decimal lengthTmp, widthTmp, heightTmp; _shippingService.GetDimensions(new List <GetShippingOptionRequest.PackageItem> { new GetShippingOptionRequest.PackageItem(sci, 1) }, out widthTmp, out lengthTmp, out heightTmp); int length = ConvertFromPrimaryMeasureDimension(lengthTmp, usedMeasureDimension); int height = ConvertFromPrimaryMeasureDimension(heightTmp, usedMeasureDimension); int width = ConvertFromPrimaryMeasureDimension(widthTmp, usedMeasureDimension); var product = EngineContext.Current.Resolve <IProductService>().GetProductById(sci.ProductId); int weight = ConvertFromPrimaryMeasureWeight(product.Weight, usedMeasureWeight); if (length < 1) { length = 1; } if (height < 1) { height = 1; } if (width < 1) { width = 1; } if (weight < 1) { weight = 1; } //The maximum declared amount per package: 50000 USD. //TODO: Currently using Product.Price - should we use GetUnitPrice() instead? // Convert.ToInt32(_priceCalculationService.GetUnitPrice(sci, includeDiscounts:false)) //One could argue that the insured value should be based on Cost rather than Price. //GetUnitPrice handles Attribute Adjustments and also Customer Entered Price. //But, even with includeDiscounts:false, it could apply a "discount" from Tier pricing. int insuranceAmountPerPackage = _upsSettings.InsurePackage ? Convert.ToInt32(product.Price) : 0; for (int j = 0; j < qty; j++) { AppendPackageRequest(sb, packagingType, length, height, width, weight, insuranceAmountPerPackage, currencyCode); } } }
public decimal?GetFixedRate( GetShippingOptionRequest getShippingOptionRequest ) { return(0.0M); }
private int GetWidth(GetShippingOptionRequest getShippingOptionRequest) { int value = Convert.ToInt32(Math.Ceiling(this._measureService.ConvertFromPrimaryMeasureDimension(_shippingService.GetTotalWidth(getShippingOptionRequest.Items), this.GatewayMeasureDimension))); return(value < MIN_LENGTH ? MIN_LENGTH : value); }