private void CanadaPostGetRates(Shipments AllShipments, out string RTShipRequest, out string RTShipResponse, decimal ExtraFee, Decimal MarkupPercent, decimal ShippingTaxRate, ref ShippingMethodCollection shippingMethods) { RTShipRequest = String.Empty; RTShipResponse = String.Empty; if (!AppConfigProvider.GetAppConfigValue("Localization.StoreCurrency", StoreId, true).Trim().Equals("cad", StringComparison.InvariantCultureIgnoreCase)) { RTShipResponse += "Localization.StoreCurrency == CAD required to use Canada Post as a carrier."; return; } if (!AppConfigProvider.GetAppConfigValue("Localization.WeightUnits", StoreId, true).Equals("kg", StringComparison.InvariantCultureIgnoreCase)) { RTShipResponse += "Localization.WeightUnits == kg required to use Canada Post as a carrier."; return; } foreach (Packages Shipment in AllShipments) { HasFreeItems = false; PackageQuantity = 1; if (Shipment.Weight > AppConfigProvider.GetAppConfigValueUsCulture <decimal>("RTShipping.CanadaPost.MaxWeight", StoreId, true)) { shippingMethods.ErrorMsg = string.Format("{0} {1}", CanadaPostName, AppConfigProvider.GetAppConfigValue("RTShipping.CallForShippingPrompt", StoreId, true)); return; } // create a rate request CanadaPost.ratesAndServicesRequest rateRequest = new CanadaPost.ratesAndServicesRequest(); rateRequest.merchantCPCID = AppConfigProvider.GetAppConfigValue("RTShipping.CanadaPost.MerchantID", StoreId, true); // Canada Post merchant credentials // ship-to address rateRequest.city = Shipment.DestinationCity; rateRequest.provOrState = Shipment.DestinationStateProvince; rateRequest.country = Shipment.DestinationCountryCode; rateRequest.postalCode = Shipment.DestinationZipPostalCode; // create one lineitem request per package in shipment rateRequest.lineItems.item = new CanadaPost.item[Shipment.Count]; int packageIndex = 0; foreach (Package p in Shipment) { if (p.IsFreeShipping) { HasFreeItems = true; } if (p.IsShipSeparately) { PackageQuantity = p.Quantity; } // shipment details rateRequest.itemsPrice = p.InsuredValue.ToString("#####.00"); rateRequest.lineItems.item[packageIndex] = new CanadaPost.item(); rateRequest.lineItems.item[packageIndex].weight = p.Weight.ToString("####.0"); // dimensions if (p.Length + p.Width + p.Height == 0) // if package has no dimensions, we use default { string dimensions = AppConfigProvider.GetAppConfigValue("RTShipping.CanadaPost.DefaultPackageSize", StoreId, true); p.Width = Convert.ToDecimal(dimensions.Split('x')[0].Trim()); p.Height = Convert.ToDecimal(dimensions.Split('x')[1].Trim()); p.Length = Convert.ToDecimal(dimensions.Split('x')[2].Trim()); } rateRequest.lineItems.item[packageIndex].length = p.Length.ToString("###.0"); rateRequest.lineItems.item[packageIndex].width = p.Width.ToString("###.0"); rateRequest.lineItems.item[packageIndex].height = p.Height.ToString("###.0"); packageIndex++; } // initialize eParcel request CanadaPost.eparcel request = new CanadaPost.eparcel(); // choose language for reply text request.language = AppConfigProvider.GetAppConfigValue("RTShipping.CanadaPost.Language", StoreId, true).Trim(); if (request.language.Equals("auto", StringComparison.InvariantCultureIgnoreCase)) // set the language based on the customers locale { Customer ThisCustomer = System.Web.HttpContext.Current.GetCustomer(); if (ThisCustomer.LocaleSetting.Trim().StartsWith("fr", StringComparison.InvariantCultureIgnoreCase)) { request.language = "fr"; } else { request.language = "en"; } } request.Items = new CanadaPost.ratesAndServicesRequest[1]; request.Items[0] = rateRequest; // serialize eParcel request class XmlSerializer serRequest = new XmlSerializer(typeof(CanadaPost.eparcel)); StringWriter swRequest = new StringWriter(); serRequest.Serialize(swRequest, request); string req = swRequest.ToString().Replace(@" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""", ""); // open a TCP socket with Canada Post server Socket socCanadaPost = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint remoteEndPoint; socCanadaPost.ReceiveTimeout = 10000; // milliseconds to wait for a response try { remoteEndPoint = new IPEndPoint(Dns.GetHostAddresses(AppConfigProvider.GetAppConfigValue("RTShipping.CanadaPost.Server", StoreId, true))[0], AppLogic.AppConfigNativeInt("RTShipping.CanadaPost.ServerPort")); socCanadaPost.Connect(remoteEndPoint); } catch (SocketException e) { RTShipResponse += "Tried to reach Canada Post Server (" + AppConfigProvider.GetAppConfigValue("RTShipping.CanadaPost.Server", StoreId, true) + ":" + AppLogic.AppConfigNativeInt("RTShipping.CanadaPost.ServerPort") + "): " + e.Message; return; } // send request to Canada Post byte[] data = System.Text.Encoding.ASCII.GetBytes(req); socCanadaPost.Send(data); //receive response from Canada Post string resp = String.Empty; byte[] buffer = new byte[8192]; int iRx = 0; while (!resp.Contains("<!--END_OF_EPARCEL-->")) { try { iRx += socCanadaPost.Receive(buffer, iRx, 8192 - iRx, SocketFlags.None); } catch (SocketException e) { if (e.SocketErrorCode == SocketError.TimedOut) { break; } else { throw e; } } resp = new string((System.Text.Encoding.UTF8.GetChars(buffer, 0, iRx))); // decode byte array to string } // close socket socCanadaPost.Close(); // create an eParcel response class CanadaPost.eparcel response = new CanadaPost.eparcel(); // deserialize the xml response into the eParcel response XmlSerializer serResponse = new XmlSerializer(typeof(CanadaPost.eparcel)); StringReader srResponse = new StringReader(resp); try { response = (CanadaPost.eparcel)serResponse.Deserialize(srResponse); } catch (InvalidOperationException e) // invalid xml, or no reply received from Canada Post { RTShipResponse += "Canada Post error: Could not parse response from Canada Post server: " + e.Message + " Response received: " + resp; return; } srResponse.Close(); // Check the response object for Faults if (response.Items[0] is CanadaPost.error) { CanadaPost.error respError = (CanadaPost.error)response.Items[0]; RTShipResponse += respError.statusMessage[0]; return; } // Check the response object for Ratings if (!(response.Items[0] is CanadaPost.ratesAndServicesResponse)) { RTShipResponse += "Canada Post Error: No rating responses returned from Canada Post"; return; } // no faults, so extract rate information CanadaPost.ratesAndServicesResponse ratesResp = (CanadaPost.ratesAndServicesResponse)response.Items[0]; foreach (CanadaPost.product product in ratesResp.product) { decimal total = Localization.ParseUSDecimal(product.rate); // ignore zero-cost methods, and methods not allowed if (total != 0 && ShippingMethodIsAllowed(product.name, CanadaPostName)) { total = total * PackageQuantity * (1.00M + (MarkupPercent / 100.0M)); decimal vat = Decimal.Round(total * ShippingTaxRate); if (!shippingMethods.MethodExists(product.name)) { var s_method = new ShippingMethod(); s_method.Carrier = CanadaPostName; s_method.Name = product.name; s_method.Freight = total; s_method.VatRate = vat; s_method.IsRealTime = true; s_method.Id = Shipping.GetShippingMethodID(s_method.Name); if (HasFreeItems) { s_method.FreeItemsRate = total; } shippingMethods.Add(s_method); } else { int IndexOf = shippingMethods.GetIndex(product.name); var s_method = shippingMethods[IndexOf]; s_method.Freight += total; s_method.VatRate += vat; if (HasFreeItems) { s_method.FreeItemsRate += total; } shippingMethods[IndexOf] = s_method; } } } RTShipRequest += req; // stash request & response for this shipment RTShipResponse += resp; } // Handling fee should only be added per shipping address not per package // let's just compute it here after we've gone through all the packages. // Also, since we can't be sure about the ordering of the method call here // and that the collection SM includes shipping methods from all possible carriers // we'll need to filter out the methods per this carrier to avoid side effects on the main collection foreach (ShippingMethod shipMethod in shippingMethods.PerCarrier(CanadaPostName)) { if (shipMethod.Freight != System.Decimal.Zero) //Don't add the fee to free methods. { shipMethod.Freight += ExtraFee; } } }
static public ShippingMethodCollection GetRates(Shipments AllShipments, decimal ShipmentWeight, decimal ShipmentValue, decimal ShippingTaxRate, out string RTShipRequest, out string RTShipResponse, ref ups2.ShippingSection ShippingConfig, ref ups2.UPSSection UPSConfig) { // instantiate return variables ShippingMethodCollection UPS2ShipMethods = new ShippingMethodCollection(); RTShipRequest = String.Empty; RTShipResponse = String.Empty; // is weight within shippable limit? if (ShipmentWeight > UPSConfig.MaxWeight) { UPS2ShipMethods.ErrorMsg = "UPS " + ShippingConfig.CallForShippingPrompt; return(UPS2ShipMethods); } // check for required configuration variables if (UPSConfig.UserName.Length < 3) { throw new Exception("UPS Error: RTShipping.UPS.UserName must contain the User ID used to signin to ups.com."); } if (UPSConfig.Password.Length < 3) { throw new Exception("UPS Error: RTShipping.UPS.Password must contain the Password used to signin to ups.com."); } if (UPSConfig.License.Length < 7) { throw new Exception("UPS Error: RTShipping.UPS.License must contain the Access Key assigned by UPS to access UPS OnLine Tools API's."); } // for negotiated rates, do we have the UPS account number? if (UPSConfig.GetNegotiatedRates && UPSConfig.AccountNumber.Length != 6) { throw new Exception("UPS Error: RTShipping.UPS.GetNegotiatedRates is 'true', but a six-character UPS account number " + "is not specified in RTShipping.UPS.AccountNumber. The account number is required to retrieve negotiated rates."); } // retrieve correct UPS Server URL string UPSServer; if (ShippingConfig.UseTestRates) { UPSServer = UPSConfig.TestServer; } else { UPSServer = UPSConfig.Server; } foreach (Packages Shipment in AllShipments) { // createUPS OnLine Tools access credentials ups2.AccessRequest accessCredentials = new ups2.AccessRequest(); accessCredentials.AccessLicenseNumber = UPSConfig.License; accessCredentials.UserId = UPSConfig.UserName; accessCredentials.Password = UPSConfig.Password; // create a rate request ups2.RatingRequest rateRequest = new ups2.RatingRequest(); // shipment details rateRequest.Shipment.Shipper = new ups2.RequestShipmentShipper(); rateRequest.Shipment.Shipper.ShipperNumber = UPSConfig.AccountNumber; rateRequest.Shipment.RateInformation = new ups2.ShipmentRateInformation(); rateRequest.Shipment.RateInformation.NegotiatedRatesIndicator = String.Empty; // UPS PickupType try { rateRequest.PickupType.Code = Enum.Format(typeof(ups2.RequestPickupTypeCode), Enum.Parse(typeof(ups2.RequestPickupTypeCode), UPSConfig.PickupType, true), "d").PadLeft(2, '0'); } catch (ArgumentException) { throw new Exception("UPS Error: RTShipping.UPS.UPSPickupType == '" + UPSConfig.PickupType + "'. Legal values are UPSDailyPickup, " + "UPSCustomerCounter, UPSOneTimePickup, UPSOnCallAir, UPSSuggestedRetailRates, UPSLetterCenter, or UPSAirServiceCenter."); } // UPS CustomerClassification if (UPSConfig.CustomerClassification != string.Empty) { rateRequest.CustomerClassification.Code = UPSConfig.CustomerClassification; // default is Wholesale, '01' } // shipment origin ups2.UPSAddress Origin = new ups2.UPSAddress(); // check Shipment for Origin address if (Shipment.OriginZipPostalCode != string.Empty) { Origin.AddressLine1 = Shipment.OriginAddress1; Origin.AddressLine2 = Shipment.OriginAddress2; Origin.City = Shipment.OriginCity; Origin.StateProvinceCode = Shipment.OriginStateProvince; Origin.PostalCode = Shipment.OriginZipPostalCode; Origin.CountryCode = Shipment.OriginCountryCode; } else // shipment didn't have origin address, so use default address from appConfigs. { Origin.AddressLine1 = ShippingConfig.OriginAddress; Origin.AddressLine2 = ShippingConfig.OriginAddress2; Origin.City = ShippingConfig.OriginCity; Origin.StateProvinceCode = ShippingConfig.OriginState; Origin.PostalCode = ShippingConfig.OriginZip; Origin.CountryCode = ShippingConfig.OriginCountry; } // for UK, verify the Origin Country is set to GB if (Origin.CountryCode == "UK") { Origin.CountryCode = "GB"; } rateRequest.Shipment.Shipper.Address = Origin; // ship-to address ups2.UPSAddress Dest = new ups2.UPSAddress(); Dest.AddressLine1 = Shipment.DestinationAddress1; Dest.AddressLine2 = Shipment.DestinationAddress2; Dest.City = Shipment.DestinationCity; Dest.StateProvinceCode = Shipment.DestinationStateProvince; Dest.PostalCode = Shipment.DestinationZipPostalCode; Dest.CountryCode = Shipment.DestinationCountryCode; // residential address indicator if ((UPSConfig.AddressTypeBehavior.ToLower() == "forceallresidential" || Shipment.DestinationResidenceType == ResidenceTypes.Residential || Shipment.DestinationResidenceType == ResidenceTypes.Unknown && UPSConfig.AddressTypeBehavior.ToLower() != "unknownsarecommercial") && UPSConfig.AddressTypeBehavior.ToLower() != "forceallcommercial") { Dest.ResidentialAddressIndicator = ""; // the mere presence of this tag indicates Residential } // for UK, verify the Destination Country is set to GB if (Dest.CountryCode == "UK") { Dest.CountryCode = "GB"; } rateRequest.Shipment.ShipTo.Address = Dest; // add destination address to request // create one package per package in shipment rateRequest.Shipment.Package = new ups2.ShipmentPackage[Shipment.Count]; int pIndex = 0; int PackageQuantity = 1; bool HasFreeItems = false; foreach (Package p in Shipment) { rateRequest.Shipment.Package[pIndex] = new ups2.ShipmentPackage(); ups2.ShipmentPackage upsPackage = rateRequest.Shipment.Package[pIndex]; // shipment details // UPS packaging type if (UPSConfig.PackagingType != string.Empty) { upsPackage.PackagingType.Code = UPSConfig.PackagingType; // default is CustomerSuppliedPackage, '02' } // package weight upsPackage.PackageWeight.Weight = p.Weight; upsPackage.PackageWeight.UnitOfMeasurement = new ups2.UPSShipmentWeightUnitOfMeasurement(); if (ShippingConfig.WeightUnits.ToLower().Contains("kg") || ShippingConfig.WeightUnits.ToLower().Contains("kilo")) // default is pounds { upsPackage.PackageWeight.UnitOfMeasurement.Code = ups2.UPSShipmentWeightUnitOfMeasurementCode.Kilograms; } // insurance if (p.Insured && p.InsuredValue != 0) { upsPackage.PackageServiceOptions = new ups2.ShipmentPackageServiceOptions(); upsPackage.PackageServiceOptions.InsuredValue = new ups2.UPSMoney(); upsPackage.PackageServiceOptions.InsuredValue.MonetaryValue = p.InsuredValue.ToString(); upsPackage.PackageServiceOptions.InsuredValue.CurrencyCode = ShippingConfig.Currency.ToUpper(); } // delivery confirmation if (UPSConfig.DeliveryConfirmation != string.Empty) { if (upsPackage.PackageServiceOptions == null) { upsPackage.PackageServiceOptions = new ups2.ShipmentPackageServiceOptions(); } upsPackage.PackageServiceOptions.DeliveryConfirmation = new ups2.ShipmentDeliveryConfirmation(); try { upsPackage.PackageServiceOptions.DeliveryConfirmation.DCISType = Enum.Format(typeof(ups2.DCISTypeCode), Enum.Parse(typeof(ups2.DCISTypeCode), UPSConfig.DeliveryConfirmation, true), "d"); } catch (ArgumentException) { throw new Exception("UPS Error: RTShipping.UPS.DeliveryConfirmation == '" + UPSConfig.DeliveryConfirmation + "'. " + "Legal values are DeliveryConfirmation, SignatureRequired, or AdultSignatureRequired."); } } // dimensions if (p.Length + p.Width + p.Height != 0) // if package has no dimensions, do not include them { upsPackage.Dimensions = new ups2.ShipmentPackageDimensions(); upsPackage.Dimensions.Length = p.Length; upsPackage.Dimensions.Width = p.Width; upsPackage.Dimensions.Height = p.Height; // if weight is kg, UPS requires size to be cm. if (upsPackage.PackageWeight.UnitOfMeasurement.Code == ups2.UPSShipmentWeightUnitOfMeasurementCode.Kilograms) { upsPackage.Dimensions.UnitOfMeasurement.Code = ups2.DimensionsUnitOfMeasurementCode.Centimeters; // default is inches } } if (p.IsShipSeparately) { PackageQuantity = p.Quantity; } if (p.IsFreeShipping) { HasFreeItems = true; } pIndex++; } // serialize AccessRequest class XmlSerializer serAccessRequest = new XmlSerializer(typeof(ups2.AccessRequest)); StringWriter swAccessRequest = new StringWriter(); serAccessRequest.Serialize(swAccessRequest, accessCredentials); string req = swAccessRequest.ToString(); // serialize RatingRequest class XmlSerializer serRatingRequest = new XmlSerializer(typeof(ups2.RatingRequest)); StringWriter swRatingRequest = new StringWriter(); serRatingRequest.Serialize(swRatingRequest, rateRequest); req += swRatingRequest.ToString(); // append RatingRequest to AccessRequest // Send xml rate request to UPS server HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(UPSServer); webRequest.Method = "POST"; // Transmit the request to UPS byte[] data = System.Text.Encoding.ASCII.GetBytes(req); webRequest.ContentLength = data.Length; Stream requestStream; try { requestStream = webRequest.GetRequestStream(); } catch (WebException e) // could not connect to UPS endpoint { RTShipResponse += "Tried to reach UPS Server (" + UPSServer + "): " + e.Message; return(UPS2ShipMethods); } requestStream.Write(data, 0, data.Length); requestStream.Close(); // get the response from UPS WebResponse webResponse = null; string resp; try { webResponse = webRequest.GetResponse(); } catch (WebException e) // could not receive a response from UPS endpoint { RTShipResponse += "No response from UPS Server (" + UPSServer + "): " + e.Message; return(UPS2ShipMethods); } using (StreamReader sr = new StreamReader(webResponse.GetResponseStream())) { resp = sr.ReadToEnd(); sr.Close(); } webResponse.Close(); // deserialize the xml response into a RatingResponse object ups2.RatingResponse response = new ups2.RatingResponse(); XmlSerializer serResponse = new XmlSerializer(typeof(ups2.RatingResponse)); StringReader srResponse = new StringReader(resp); try { response = (ups2.RatingResponse)serResponse.Deserialize(srResponse); } catch (InvalidOperationException e) // invalid xml, or no reply received from UPS { RTShipResponse += "Could not parse response from UPS server: " + e.Message + " Response received: " + resp; return(UPS2ShipMethods); } srResponse.Close(); // Check the response object for Faults if (response.Response.Error != null) { RTShipResponse += "UPS Error: " + response.Response.Error.ErrorDescription; if (response.Response.Error.ErrorLocation != null) { RTShipResponse += " " + response.Response.Error.ErrorLocation.ErrorLocationElementName; } return(UPS2ShipMethods); } // Check the response object for RatedShipments if (response.RatedShipment == null) { RTShipResponse += "UPS Error: No rating responses returned from UPS."; return(UPS2ShipMethods); } // walk the services list, looking for matches in the returned rates foreach (string service in UPSConfig.Services.Split(',')) { // interate the returned rates, matching with the service from the UPSServices list foreach (ups2.ResponseRatedShipment ratedShipment in response.RatedShipment) { string serviceDescription = string.Empty; // check for a match between the returned rate and the current service if (ratedShipment.Service.Code == service.Split(';')[0]) { serviceDescription = service.Split(';')[1]; } // verify the quoted rate is in the same currency as the store if (ratedShipment.TotalCharges.CurrencyCode != ShippingConfig.Currency.ToUpper()) { RTShipResponse += "UPS Error: Received rates with currency code " + ratedShipment.TotalCharges.CurrencyCode + ", but store is configured for " + ShippingConfig.Currency + "."; return(UPS2ShipMethods); } decimal total; // use either negotiated rates or regular rates if (UPSConfig.GetNegotiatedRates) { if (ratedShipment.NegotiatedRates != null) { total = Convert.ToDecimal(ratedShipment.NegotiatedRates.NetSummaryCharges.GrandTotal.MonetaryValue); } else // no negotiated rates found { throw new Exception("UPS Error: GetNegotiatedRates is 'true', but no negotiated rates were returned. " + "Cantact UPS to ensure that you are authorized to receive negotiated rates."); } } else { total = Convert.ToDecimal(ratedShipment.TotalCharges.MonetaryValue); } // ignore zero-cost methods, and methods not allowed if (total == 0 || serviceDescription == string.Empty || !RTShipping.ShippingMethodIsAllowed(serviceDescription, RTShipping.UpsName)) { continue; } total = total * PackageQuantity * (1.00M + (ShippingConfig.MarkupPercent / 100.0M)) + ShippingConfig.ExtraFee; decimal vat = Decimal.Round(total * ShippingTaxRate); // add or update method in UPS2ShipMethods shipping methods collection if (!UPS2ShipMethods.MethodExists(serviceDescription)) { ShippingMethod s_method = new ShippingMethod(); s_method.Carrier = RTShipping.UpsName; s_method.Name = serviceDescription; s_method.Freight = total; s_method.VatRate = vat; s_method.IsRealTime = true; s_method.Id = Shipping.GetShippingMethodID(s_method.Name); if (HasFreeItems) { s_method.FreeItemsRate = total; } UPS2ShipMethods.Add(s_method); } else { int IndexOf = UPS2ShipMethods.GetIndex(serviceDescription); ShippingMethod s_method = UPS2ShipMethods[IndexOf]; s_method.Freight += total; s_method.VatRate += vat; if (HasFreeItems) { s_method.FreeItemsRate += total; } UPS2ShipMethods[IndexOf] = s_method; } } } RTShipRequest += req; // stash request & response for this shipment RTShipResponse += resp; } return(UPS2ShipMethods); }
private void AusPostGetRates(Shipments AllShipments, out string RTShipRequest, out string RTShipResponse, decimal ExtraFee, Decimal MarkupPercent, decimal ShippingTaxRate, ref ShippingMethodCollection shippingMethods) { RTShipRequest = String.Empty; RTShipResponse = String.Empty; if (!AppConfigProvider.GetAppConfigValue("Localization.StoreCurrency", StoreId, true).Trim().Equals("aud", StringComparison.InvariantCultureIgnoreCase)) { throw new Exception("Localization.StoreCurrency == AUD required to use Australia Post as a carrier."); } if (!AppConfigProvider.GetAppConfigValue("Localization.WeightUnits", StoreId, true).Equals("kg", StringComparison.InvariantCultureIgnoreCase)) { throw new Exception("Localization.WeightUnits == kg required to use Australia Post as a carrier."); } // is weight within shippable limit? if (ShipmentWeight > AppConfigProvider.GetAppConfigValueUsCulture <decimal>("RTShipping.AusPost.MaxWeight", StoreId, true)) { shippingMethods.ErrorMsg = "Australia Post " + AppConfigProvider.GetAppConfigValue("RTShipping.CallForShippingPrompt", StoreId, true); return; } foreach (Packages Shipment in AllShipments) { HasFreeItems = false; PackageQuantity = 1; foreach (Package p in Shipment) { if (p.IsFreeShipping) { HasFreeItems = true; } if (p.IsShipSeparately) { PackageQuantity = p.Quantity; } // get list of service classes string AusPostServices; if (Shipment.DestinationCountryCode == "AU") { AusPostServices = AppConfigProvider.GetAppConfigValue("RTShipping.AusPost.DomesticServices", StoreId, true); } else { AusPostServices = AppConfigProvider.GetAppConfigValue("RTShipping.AusPost.IntlServices", StoreId, true); } // create individual requests, one for each service foreach (string service in AusPostServices.Split(',')) { ausPost.Request request = new ausPost.Request(); // dimensions (all specified in mm) if (p.Length + p.Width + p.Height == 0) // if package has no dimensions, we use default { string dimensions = AppConfigProvider.GetAppConfigValue("RTShipping.AusPost.DefaultPackageSize", StoreId, true); try { p.Width = Convert.ToDecimal(dimensions.Split('x')[0].Trim()); p.Height = Convert.ToDecimal(dimensions.Split('x')[1].Trim()); p.Length = Convert.ToDecimal(dimensions.Split('x')[2].Trim()); } catch (FormatException e) { throw new Exception("Check the RTShipping.AusPost.DefaultPackageSize AppConfig. " + "Must be three dimensions (in cm) separated by 'x'. Example: 15x15x15. " + e.Message); } } request.Length = Convert.ToInt32(Math.Ceiling(p.Length * 10)); // convert all from cm to mm request.Width = Convert.ToInt32(Math.Ceiling(p.Width * 10)); request.Height = Convert.ToInt32(Math.Ceiling(p.Height * 10)); request.Weight = Convert.ToInt32(Math.Ceiling(p.Weight * 1000)); // convert from kg to g request.Quantity = PackageQuantity; // shipping addresses request.Pickup_Postcode = OriginZipPostalCode.PadRight(4).Substring(0, 4); request.Country = Shipment.DestinationCountryCode; request.Destination_Postcode = Shipment.DestinationZipPostalCode.PadRight(4).Substring(0, 4); // Service Type try { request.Service_Type = (ausPost.Request.ServiceType)Enum.Parse(typeof(ausPost.Request.ServiceType), service.Split(';')[0], true); } catch (ArgumentException e) { if (Shipment.DestinationCountryCode == "AU") { throw new Exception("Check the RTShipping.AusPost.DomesticServices AppConfig. " + "Legal values are STANDARD or EXPRESS, followed by a semi-colon and Name. " + e.Message); } else { throw new Exception("Check the RTShipping.AusPost.IntlServices AppConfig. " + "Legal values are AIR, SEA, ECI_D, ECI_M, or EPI, followed by a semi-colon and Name. " + e.Message); } } // convert rateRequests into a URL string req = Convert.ToString(request); // Send rate request to AusPost server HttpWebRequest webRequest = (HttpWebRequest)System.Net.WebRequest.Create(req); // get the response from AusPost WebResponse webResponse; string resp; try { webResponse = webRequest.GetResponse(); } catch (WebException e) // could not receive a response from AusPost endpoint { RTShipResponse += "No response from Australia Post Server: " + e.Message; return; } using (StreamReader sr = new StreamReader(webResponse.GetResponseStream())) { resp = sr.ReadToEnd(); sr.Close(); } webResponse.Close(); // Convert the response into a Response object ausPost.Response response; try { response = (ausPost.Response)TypeDescriptor.GetConverter(typeof(ausPost.Response)).ConvertFromString(resp); } catch (InvalidOperationException e) // invalid or no reply received from AusPost { RTShipResponse += "Could not parse response from Australia Post server: " + e.Message + " Response received: " + resp; return; } // Check the response object for an error if (response.Err_msg != "OK") { RTShipResponse += "Austalia Post Error: " + response.Err_msg + Environment.NewLine; continue; } // we have a good estimate decimal total = response.Charge; // ignore zero-cost methods, and methods not allowed if ((total == 0 && AppConfigProvider.GetAppConfigValue <bool>("FilterOutShippingMethodsThatHave0Cost", StoreId, true)) || !ShippingMethodIsAllowed(service.Split(';')[1], string.Empty)) { continue; } total = total * (1.00M + (MarkupPercent / 100.0M)); decimal vat = Decimal.Round(total * ShippingTaxRate); // add shipping method if (!shippingMethods.MethodExists(service.Split(';')[1])) { var s_method = new ShippingMethod(); s_method.Carrier = AustraliaPostName; s_method.Name = service.Split(';')[1]; s_method.Freight = total; s_method.VatRate = vat; s_method.IsRealTime = true; s_method.Id = Shipping.GetShippingMethodID(s_method.Name); if (HasFreeItems) { s_method.FreeItemsRate = total; } shippingMethods.Add(s_method); } else { int IndexOf = shippingMethods.GetIndex(service.Split(';')[1]); var s_method = shippingMethods[IndexOf]; s_method.Freight += total; s_method.VatRate += vat; if (HasFreeItems) { s_method.FreeItemsRate += total; } shippingMethods[IndexOf] = s_method; } RTShipRequest += req + Environment.NewLine; RTShipResponse += resp.Replace('\n', ' ').Replace('\r', ' ') + Environment.NewLine; } } } // Handling fee should only be added per shipping address not per package // let's just compute it here after we've gone through all the packages. // Also, since we can't be sure about the ordering of the method call here // and that the collection SM includes shipping methods from all possible carriers // we'll need to filter out the methods per this carrier to avoid side effects on the main collection foreach (ShippingMethod shipMethod in shippingMethods.PerCarrier(AustraliaPostName)) { if (shipMethod.Freight != System.Decimal.Zero) //Don't add the fee to free methods. { shipMethod.Freight += ExtraFee; } } }
void FedExGetRates(Shipments shipments, out string rtShipRequest, out string rtShipResponse, decimal extraFee, decimal markupPercent, decimal shippingTaxRate, Cache cache, ref ShippingMethodCollection shippingMethods) { rtShipRequest = string.Empty; rtShipResponse = string.Empty; var maxWeight = AppConfigProvider.GetAppConfigValueUsCulture <decimal>("RTShipping.Fedex.MaxWeight", StoreId, true); if (maxWeight == 0) { maxWeight = 150; } if (ShipmentWeight > maxWeight) { shippingMethods.ErrorMsg = "FedEx " + AppConfigProvider.GetAppConfigValue("RTShipping.CallForShippingPrompt", StoreId, true); return; } foreach (var shipment in shipments) { HasFreeItems = shipments .SelectMany(packages => packages) .Where(package => package.IsFreeShipping) .Any(); var rateRequest = CreateRateRequest(shipment); rtShipRequest = SerializeToString(rateRequest); string cacheKey = null; RateReply rateReply = null; if (cache != null) { // Hash the content var md5 = System.Security.Cryptography.MD5.Create(); using (var hashDataStream = new MemoryStream()) { using (var hashDataWriter = new StreamWriter(hashDataStream, Encoding.UTF8, 1024, true)) hashDataWriter.Write(StripShipTimestampNode(rtShipRequest)); hashDataStream.Flush(); hashDataStream.Position = 0; cacheKey = string.Format("RTShipping.FedEx.{0}", md5.ComputeHash(hashDataStream).ToString("-")); } // See if the cache contains the content var cachedResponse = cache.Get(cacheKey) as RateReply; if (cachedResponse != null) { rateReply = cachedResponse; } } try { if (rateReply == null) { var rateService = new RateService { Url = FedexServer, }; rateReply = rateService.getRates(rateRequest); rtShipResponse = SerializeToString(rateReply); if (cache != null && cacheKey != null) { cache.Insert(cacheKey, rateReply, null, DateTime.Now.AddMinutes(15), Cache.NoSlidingExpiration); } } if (rateReply.RateReplyDetails == null || (rateReply.HighestSeverity != NotificationSeverityType.SUCCESS && rateReply.HighestSeverity != NotificationSeverityType.NOTE && rateReply.HighestSeverity != NotificationSeverityType.WARNING)) { rtShipResponse = "Error: Call Not Successful " + rateReply.Notifications[0].Message; return; } // Create a list of available services foreach (var rateReplyDetail in rateReply.RateReplyDetails) { var ratedShipmentDetail = rateReplyDetail.RatedShipmentDetails .Where(rsd => rsd.ShipmentRateDetail.RateType == ReturnedRateType.PAYOR_ACCOUNT_PACKAGE || rsd.ShipmentRateDetail.RateType == ReturnedRateType.PAYOR_ACCOUNT_SHIPMENT || rsd.ShipmentRateDetail.RateType == ReturnedRateType.RATED_ACCOUNT_PACKAGE || rsd.ShipmentRateDetail.RateType == ReturnedRateType.RATED_ACCOUNT_SHIPMENT) .FirstOrDefault(); var rateName = string.Format("FedEx {0}", FedExGetCodeDescription(rateReplyDetail.ServiceType.ToString())); if (!ShippingMethodIsAllowed(rateName, FedExName)) { continue; } var totalCharges = ratedShipmentDetail.ShipmentRateDetail.TotalNetCharge.Amount; // Multiply the returned rate by the quantity in the package to avoid calling // more than necessary if there were multiple IsShipSeparately items // ordered. If there weren't, Shipment.PackageCount is 1 and the rate is normal. totalCharges = totalCharges * shipment.PackageCount; if (markupPercent != 0) { totalCharges = decimal.Round(totalCharges * (1 + (markupPercent / 100m)), 2, MidpointRounding.AwayFromZero); } var vat = decimal.Round(totalCharges * shippingTaxRate, 2, MidpointRounding.AwayFromZero); if (!shippingMethods.MethodExists(rateName)) { var shippingMethod = new ShippingMethod { Carrier = FedExName, Name = rateName, Freight = totalCharges, VatRate = vat, IsRealTime = true, Id = Shipping.GetShippingMethodID(rateName), }; if (HasFreeItems) { shippingMethod.FreeItemsRate = totalCharges; } shippingMethods.Add(shippingMethod); } else { var shippingMethodIndex = shippingMethods.GetIndex(rateName); var shippingMethod = shippingMethods[shippingMethodIndex]; shippingMethod.Freight += totalCharges; shippingMethod.VatRate += vat; if (HasFreeItems) { shippingMethod.FreeItemsRate += totalCharges; } shippingMethods[shippingMethodIndex] = shippingMethod; } } // Handling fee should only be added per shipping address not per package // let's just compute it here after we've gone through all the packages. // Also, since we can't be sure about the ordering of the method call here // and that the collection SM includes shipping methods from all possible carriers // we'll need to filter out the methods per this carrier to avoid side effects on the main collection foreach (var shippingMethod in shippingMethods.PerCarrier(FedExName)) { if (shippingMethod.Freight != 0) //Don't add the fee to free methods. { shippingMethod.Freight += extraFee; } } } catch (SoapException exception) { rtShipResponse = "FedEx Error: " + exception.Detail.InnerXml; } catch (Exception exception) { while (exception.InnerException != null) { exception = exception.InnerException; } rtShipResponse = "FedEx Error: " + exception.Message; } } }
/// <summary> /// Get shipping rates from DHL for International shipments /// </summary> private void DHLIntlGetRates(Shipments allShipments, out string rtShipRequest, out string rtShipResponse, decimal ExtraFee, decimal markupPercent, decimal shippingTaxRate, ref ShippingMethodCollection shippingMethods) { rtShipRequest = String.Empty; rtShipResponse = String.Empty; // is weight within shippable limit? if (ShipmentWeight > AppLogic.AppConfigUSDecimal("RTShipping.DHLIntl.MaxWeight")) { shippingMethods.ErrorMsg = "DHL " + AppLogic.AppConfig("RTShipping.CallForShippingPrompt"); return; } // retrieve correct DHL Server URL string dhlServer; if (AppLogic.AppConfigBool("RTShipping.UseTestRates")) { dhlServer = AppLogic.AppConfig("RTShipping.DHL.TestServer"); } else { dhlServer = AppLogic.AppConfig("RTShipping.DHL.Server"); } // calculate legal ship date DateTime shipDate = DateTime.Now.AddDays(AppLogic.AppConfigUSDouble("RTShipping.DHL.ShipInDays")); if (shipDate.DayOfWeek == DayOfWeek.Saturday) { shipDate = shipDate.AddDays(2); } if (shipDate.DayOfWeek == DayOfWeek.Sunday) { shipDate = shipDate.AddDays(1); } // error 4112 is tripped by asking for a rate quote on a Sunday or a Holiday bool error4112 = false; do { if (error4112) { error4112 = false; shipDate = shipDate.AddDays(1); } foreach (Packages shipment in allShipments) { HasFreeItems = false; PackageQuantity = 1; foreach (Package p in shipment) { if (p.IsFreeShipping) { HasFreeItems = true; } if (p.IsShipSeparately) { PackageQuantity = p.Quantity; } // initialize rate requests dhl.InternationalRateRequest rateRequests = new dhl.InternationalRateRequest(); rateRequests.Requestor.ID = AppLogic.AppConfig("RTShipping.DHL.APISystemID"); rateRequests.Requestor.Password = AppLogic.AppConfig("RTShipping.DHL.APISystemPassword"); string dhlServices = AppLogic.AppConfig("RTShipping.DHLIntl.Services"); // create an array of individual requests, one for each service rateRequests.Shipment = new dhl.InternationalRequest[dhlServices.Split(',').Length]; // populate the array int serviceIndex = 0; foreach (string service in dhlServices.Split(',')) { rateRequests.Shipment[serviceIndex] = new dhl.InternationalRequest(); dhl.InternationalRequest request = rateRequests.Shipment[serviceIndex]; // DHL rating API credentials request.ShippingCredentials.ShippingKey = AppLogic.AppConfig("RTShipping.DHLIntl.ShippingKey"); request.ShippingCredentials.AccountNbr = AppLogic.AppConfig("RTShipping.DHL.AccountNumber"); // shipment details request.ShipmentDetail.ShipDate = shipDate.ToString("yyyy-MM-dd"); request.ShipmentDetail.ShipmentType.Code = AppLogic.AppConfig("RTShipping.DHLIntl.Packaging").ToUpperInvariant(); // used to allow 'O' (Other) packaging types, which are now 'P' types if (request.ShipmentDetail.ShipmentType.Code == "O") { request.ShipmentDetail.ShipmentType.Code = "P"; } // package weight if (request.ShipmentDetail.ShipmentType.Code == "L") { request.ShipmentDetail.Weight = p.Weight.ToString("#0.0"); } else { request.ShipmentDetail.Weight = Math.Ceiling(p.Weight).ToString("##0"); } request.ShipmentDetail.ContentDesc = "ContentDesc"; // billing details request.Billing.Party.Code = AppLogic.AppConfig("RTShipping.DHLIntl.BillingParty").ToUpperInvariant(); if (request.Billing.Party.Code != "S") { request.Billing.AccountNbr = AppLogic.AppConfig("RTShipping.DHLIntl.BillingAccountNbr").ToUpperInvariant(); } request.Billing.DutyPaymentType = AppLogic.AppConfig("RTShipping.DHLIntl.DutyPayment").ToUpperInvariant(); if (request.Billing.DutyPaymentType == "3") { request.Billing.DutyPaymentAccountNbr = AppLogic.AppConfig("RTShipping.DHLIntl.DutyPaymentAccountNbr").ToUpperInvariant(); } // import duty declaration request.Dutiable.DutiableFlag = AppLogic.AppConfig("RTShipping.DHLIntl.Dutiable").ToUpperInvariant(); request.Dutiable.CustomsValue = p.InsuredValue.ToString("######"); // overrides string overrideCodes = AppLogic.AppConfig("RTShipping.DHLIntl.Overrides"); if (overrideCodes.Length > 0) { request.ShipmentProcessingInstructions.Overrides = new dhl.Override[overrideCodes.Split(',').Length]; int overrideIndex = 0; foreach (string overrideCode in overrideCodes.Split(',')) { request.ShipmentProcessingInstructions.Overrides[overrideIndex] = new dhl.Override(); request.ShipmentProcessingInstructions.Overrides[overrideIndex].Code = overrideCode; overrideIndex++; } } // ship-to address request.Receiver.Address.Street = "Street"; request.Receiver.Address.City = shipment.DestinationCity; if (shipment.DestinationCountryCode.Equals("ca", StringComparison.OrdinalIgnoreCase) || shipment.DestinationCountryCode.Equals("us", StringComparison.OrdinalIgnoreCase)) { request.Receiver.Address.State = shipment.DestinationStateProvince; } request.Receiver.Address.Country = shipment.DestinationCountryCode.ToUpperInvariant(); request.Receiver.Address.PostalCode = shipment.DestinationZipPostalCode.ToUpperInvariant(); // dimensions if (p.Length + p.Width + p.Height != 0) { request.ShipmentDetail.Dimensions = new dhl.Dimensions(); request.ShipmentDetail.Dimensions.Length = p.Length.ToString("###"); request.ShipmentDetail.Dimensions.Width = p.Width.ToString("###"); request.ShipmentDetail.Dimensions.Height = p.Height.ToString("###"); } // insurance if (p.Insured && p.InsuredValue != 0) { request.ShipmentDetail.AdditionalProtection.Code = "AP"; // additional protection request.ShipmentDetail.AdditionalProtection.Value = p.InsuredValue.ToString("######"); } else { request.ShipmentDetail.AdditionalProtection.Code = "NR"; // not required request.ShipmentDetail.AdditionalProtection.Value = "0"; } // add the service code, and service name to the request request.ShipmentDetail.Service.Code = service.Split(';')[0]; request.TransactionTrace = service.Split(';')[1]; // add this individual service request to the rateRequests rateRequests.Shipment[serviceIndex] = request; serviceIndex++; } // serialize rateRequests into an xml string XmlWriterSettings xwSettings = new XmlWriterSettings(); xwSettings.OmitXmlDeclaration = true; XmlSerializer serRequest = new XmlSerializer(rateRequests.GetType()); StringWriter swRequest = new StringWriter(); XmlWriter xwRequest = XmlWriter.Create(swRequest, xwSettings); serRequest.Serialize(xwRequest, rateRequests); string req = swRequest.ToString(); // Send xml rate request to DHL server HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(dhlServer); webRequest.Method = "POST"; webRequest.ProtocolVersion = HttpVersion.Version11; webRequest.ContentType = "application/xml; charset=UTF-8"; webRequest.Accept = "application/xml; charset=UTF-8"; // Transmit the request to DHL byte[] data = System.Text.Encoding.ASCII.GetBytes(req); webRequest.ContentLength = data.Length; Stream requestStream; try { requestStream = webRequest.GetRequestStream(); } catch (WebException e) { // could not connect to DHL endpoint rtShipResponse += "Tried to reach DHL Server (" + dhlServer + "): " + e.Message; return; } requestStream.Write(data, 0, data.Length); requestStream.Close(); // get the response from DHL WebResponse webResponse = null; string resp; try { webResponse = webRequest.GetResponse(); } catch (WebException e) { // could not receive a response from DHL endpoint rtShipResponse += "No response from DHL Server (" + dhlServer + "): " + e.Message; return; } using (StreamReader sr = new StreamReader(webResponse.GetResponseStream())) { resp = sr.ReadToEnd(); sr.Close(); } webResponse.Close(); // deserialize the xml response into an InternationalRateResponse object dhl.InternationalRateResponse response = new dhl.InternationalRateResponse(); XmlSerializer serResponse = new XmlSerializer(typeof(dhl.InternationalRateResponse)); StringReader srResponse = new StringReader(resp); try { response = (dhl.InternationalRateResponse)serResponse.Deserialize(srResponse); } catch (InvalidOperationException e) { // invalid xml, or no reply received from DHL rtShipResponse += "Could not parse response from DHL server: " + e.Message + " Response received: " + resp; return; } srResponse.Close(); // Check the response object for Ratings if (response.Shipment == null) { rtShipResponse += "DHL Error: No rating responses returned from DHL."; return; } // Check the response object for Faults if (response.Shipment[0].Faults != null) { if (response.Shipment[0].Faults[0].Code == "4112") { error4112 = true; } else { rtShipResponse += "DHL Error: " + response.Shipment[0].Faults[0].Desc; return; } } // one response for each rate request foreach (dhl.Response rateResponse in response.Shipment) { // check for a rate estimate if (rateResponse.EstimateDetail == null) { break; } // we have a good estimate decimal total = Localization.ParseUSDecimal(rateResponse.EstimateDetail.RateEstimate.TotalChargeEstimate); // ignore zero-cost methods, and methods not allowed if ((total == 0 && AppLogic.AppConfigBool("FilterOutShippingMethodsThatHave0Cost")) || !ShippingMethodIsAllowed(rateResponse.TransactionTrace, string.Empty)) { break; } total = total * PackageQuantity * (1.00M + (markupPercent / 100.0M)); decimal vat = Decimal.Round(total * shippingTaxRate); if (!shippingMethods.MethodExists(rateResponse.TransactionTrace)) { ShippingMethod s_method = new ShippingMethod(); s_method.Carrier = "DHL"; s_method.Name = rateResponse.TransactionTrace; s_method.Freight = total; s_method.VatRate = vat; s_method.IsRealTime = true; s_method.Id = Shipping.GetShippingMethodID(s_method.Name); if (HasFreeItems) { s_method.FreeItemsRate = total; } shippingMethods.Add(s_method); } else { int indexOf = shippingMethods.GetIndex(rateResponse.TransactionTrace); ShippingMethod s_method = shippingMethods[indexOf]; s_method.Freight += total; s_method.VatRate += vat; if (HasFreeItems) { s_method.FreeItemsRate += total; } shippingMethods[indexOf] = s_method; } } rtShipRequest += req; rtShipResponse += resp; } } }while (error4112 == true); // Handling fee should only be added per shipping address not per package // let's just compute it here after we've gone through all the packages. // Also, since we can't be sure about the ordering of the method call here // and that the collection SM includes shipping methods from all possible carriers // we'll need to filter out the methods per this carrier to avoid side effects on the main collection foreach (ShippingMethod shipMethod in shippingMethods.PerCarrier("DHL")) { if (shipMethod.Freight != System.Decimal.Zero) //Don't add the fee to free methods. { shipMethod.Freight += ExtraFee; } } }