Bug - USPS for 4.20 - "Please enter a valid weight in ounces"

4 months ago
1. nopCommerce version: 4.20
2. Expected behavior:  USPS should return services/rates
3. Actual behavior  :  USPS reports error "Please enter a valid weight in ounces"
4. Steps to reproduce the problem:
Create a product with a weight of 1.75 lbs  (includes fraction)

The problem is that in the prior versions of the USPS plugin, the var weight was an int.  Now, it's a decimal returned by function GetWeight()

Here's some LinqPad to see the issue

decimal weight = 28.0M;  //weight in ounces

(weight / 16).Dump("(weight / 16)");

//old - incorrect
var pounds = Convert.ToInt32(weight / 16);

//new correct
//var pounds = Convert.ToInt32(Math.Floor(weight / 16));

var ounces = Convert.ToInt32(weight - (pounds * 16.0M));

pounds.Dump("pounds");
ounces.Dump("ounces");



(weight / 16)
1.75

--old--
pounds
2

ounces
-4

--new--
pounds
1

ounces
12


5. Modifications
\Plugins\Nop.Plugin.Shipping.USPS\Services\USPSService.cs

Option 1
Existing code:
private string CreateRequest(...
...
  var weight = GetWeight(getShippingOptionRequest);
  ...
  var pounds = Convert.ToInt32(weight / 16);
  var ounces = Convert.ToInt32(weight - (pounds * 16.0M));
  ...


The correct expression is to use Math.Floor:

  var pounds = Convert.ToInt32(Math.Floor(weight / 16));



Option 2 - better :)
Alternately, leave the above as-is, and change the function GetWeight() to return an int, ...
considering that it's returning weight in ounces as per
   USPSShippingDefaults.MEASURE_WEIGHT_SYSTEM_KEYWORD = "ounce"


Old code
private decimal GetWeight(GetShippingOptionRequest shippingOptionRequest, int minRate = 1)
{
  var measureWeight = _measureService.GetMeasureWeightBySystemKeyword(USPSShippingDefaults.MEASURE_WEIGHT_SYSTEM_KEYWORD)
    ?? throw new NopException($"USPS shipping service. Could not load \"{USPSShippingDefaults.MEASURE_WEIGHT_SYSTEM_KEYWORD}\" measure weight");

  var weight = _shippingService.GetTotalWeight(shippingOptionRequest, ignoreFreeShippedItems: true);
  weight = _measureService.ConvertFromPrimaryMeasureWeight(weight, measureWeight);
  weight = Convert.ToInt32(Math.Ceiling(weight));
  return Math.Max(weight, minRate);
}


New Code
1) return type changed to int
2) parameter
..., int minRate = 1)
renamed to
..., int minWeight = 1)
3) moved the Math.Max & Convert.ToInt32

private int GetWeight(GetShippingOptionRequest shippingOptionRequest, int minWeight = 1)
{
  var measureWeight = _measureService.GetMeasureWeightBySystemKeyword(USPSShippingDefaults.MEASURE_WEIGHT_SYSTEM_KEYWORD)
    ?? throw new NopException($"USPS shipping service. Could not load \"{USPSShippingDefaults.MEASURE_WEIGHT_SYSTEM_KEYWORD}\" measure weight");

  var weight = _shippingService.GetTotalWeight(shippingOptionRequest, ignoreFreeShippedItems: true);
  weight = _measureService.ConvertFromPrimaryMeasureWeight(weight, measureWeight);
  weight = Math.Max(Math.Ceiling(weight), minWeight);
  return Convert.ToInt32(weight);

}



(P.S. There are warnings in the same code file:
Message  IDE0051  Private member 'USPSService.GetDimensionsForSingleItem' is unused.
Message  IDE0051  Private member 'USPSService.GetWeightForSingleItem' is unused.
4 months ago
Thanks for your investigation. Here is a work item for this issue.
4 months ago
Done. Please see this commit.