Skip to content

Commit

Permalink
#69 Support for kg/cm UPS shipments (#70)
Browse files Browse the repository at this point in the history
* UnitsSystem introduced
* UPS provider to detect units system
* PackageKgCm
  • Loading branch information
alexeybusygin authored Aug 9, 2024
1 parent 442cc56 commit 7b2e779
Show file tree
Hide file tree
Showing 24 changed files with 708 additions and 422 deletions.
45 changes: 45 additions & 0 deletions ShippingRates.Tests/Units/PackageDimensionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using NUnit.Framework;
using ShippingRates.Models;

namespace ShippingRates.Tests.Units
{
[TestFixture]
public class PackageWeightTests
{
[Test()]
public void LbsToKgs()
{
var weight1 = new PackageWeight(UnitsSystem.USCustomary, 5);
Assert.AreEqual(5, weight1.Get());
Assert.AreEqual(5, weight1.Get(UnitsSystem.USCustomary));
Assert.AreEqual(2.26796185m, weight1.Get(UnitsSystem.Metric));
Assert.AreEqual(5, weight1.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(3, weight1.GetRounded(UnitsSystem.Metric));

var weight2 = new PackageWeight(UnitsSystem.USCustomary, 0.3m);
Assert.AreEqual(0.3m, weight2.Get());
Assert.AreEqual(0.3m, weight2.Get(UnitsSystem.USCustomary));
Assert.AreEqual(0.136077711m, weight2.Get(UnitsSystem.Metric));
Assert.AreEqual(1, weight2.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(1, weight2.GetRounded(UnitsSystem.Metric));
}

[Test()]
public void KgsToLbs()
{
var weight1 = new PackageWeight(UnitsSystem.Metric, 5);
Assert.AreEqual(5, weight1.Get());
Assert.AreEqual(11.0231m, weight1.Get(UnitsSystem.USCustomary));
Assert.AreEqual(5, weight1.Get(UnitsSystem.Metric));
Assert.AreEqual(12, weight1.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(5, weight1.GetRounded(UnitsSystem.Metric));

var weight2 = new PackageWeight(UnitsSystem.Metric, 0.5m);
Assert.AreEqual(0.5m, weight2.Get());
Assert.AreEqual(1.10231m, weight2.Get(UnitsSystem.USCustomary));
Assert.AreEqual(0.5m, weight2.Get(UnitsSystem.Metric));
Assert.AreEqual(2, weight2.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(1, weight2.GetRounded(UnitsSystem.Metric));
}
}
}
26 changes: 26 additions & 0 deletions ShippingRates.Tests/Units/PackageKgCmTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using NUnit.Framework;
using ShippingRates.Models;

namespace ShippingRates.Tests.Units
{
[TestFixture]
public class PackageKgCmTests
{
[Test()]
public void TestDimensions()
{
var packageLbsInches = new Package(10, 20, 30, 40, 50);
var packageKgCm = new PackageKgCm(10, 20, 30, 40, 50);

Assert.AreNotEqual(packageKgCm.GetHeight(UnitsSystem.Metric), packageLbsInches.GetHeight(UnitsSystem.Metric));
Assert.AreNotEqual(packageKgCm.GetLength(UnitsSystem.Metric), packageLbsInches.GetLength(UnitsSystem.Metric));
Assert.AreNotEqual(packageKgCm.GetWidth(UnitsSystem.USCustomary), packageLbsInches.GetWidth(UnitsSystem.USCustomary));
Assert.AreNotEqual(packageKgCm.GetHeight(UnitsSystem.USCustomary), packageLbsInches.GetHeight(UnitsSystem.USCustomary));

Assert.AreEqual(40, packageLbsInches.GetWeight(UnitsSystem.USCustomary));
Assert.AreEqual(18.1436948m, packageLbsInches.GetWeight(UnitsSystem.Metric));
Assert.AreEqual(88.1848m, packageKgCm.GetWeight(UnitsSystem.USCustomary));
Assert.AreEqual(40, packageKgCm.GetWeight(UnitsSystem.Metric));
}
}
}
45 changes: 45 additions & 0 deletions ShippingRates.Tests/Units/PackageWeightTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using NUnit.Framework;
using ShippingRates.Models;

namespace ShippingRates.Tests.Units
{
[TestFixture]
public class PackageDimensionTests
{
[Test()]
public void InchesToCm()
{
var dimension1 = new PackageDimension(UnitsSystem.USCustomary, 5);
Assert.AreEqual(5, dimension1.Get());
Assert.AreEqual(5, dimension1.Get(UnitsSystem.USCustomary));
Assert.AreEqual(12.7m, dimension1.Get(UnitsSystem.Metric));
Assert.AreEqual(5, dimension1.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(13, dimension1.GetRounded(UnitsSystem.Metric));

var dimension2 = new PackageDimension(UnitsSystem.USCustomary, 0.4m);
Assert.AreEqual(0.4m, dimension2.Get());
Assert.AreEqual(0.4m, dimension2.Get(UnitsSystem.USCustomary));
Assert.AreEqual(1.016m, dimension2.Get(UnitsSystem.Metric));
Assert.AreEqual(1, dimension2.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(2, dimension2.GetRounded(UnitsSystem.Metric));
}

[Test()]
public void CmToInches()
{
var dimension1 = new PackageDimension(UnitsSystem.Metric, 6);
Assert.AreEqual(6, dimension1.Get());
Assert.AreEqual(2.362206m, dimension1.Get(UnitsSystem.USCustomary));
Assert.AreEqual(6, dimension1.Get(UnitsSystem.Metric));
Assert.AreEqual(3, dimension1.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(6, dimension1.GetRounded(UnitsSystem.Metric));

var dimension2 = new PackageDimension(UnitsSystem.Metric, 2.6m);
Assert.AreEqual(2.6m, dimension2.Get());
Assert.AreEqual(1.0236226m, dimension2.Get(UnitsSystem.USCustomary));
Assert.AreEqual(2.6m, dimension2.Get(UnitsSystem.Metric));
Assert.AreEqual(2, dimension2.GetRounded(UnitsSystem.USCustomary));
Assert.AreEqual(3, dimension2.GetRounded(UnitsSystem.Metric));
}
}
}
80 changes: 44 additions & 36 deletions ShippingRates/Models/Package.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using ShippingRates.Models;
using System;

namespace ShippingRates
Expand All @@ -7,6 +8,21 @@ namespace ShippingRates
/// </summary>
public class Package
{
readonly UnitsSystem _unitsSystem;
PackageWeight _weight;
PackageDimension _length;
PackageDimension _width;
PackageDimension _height;

protected Package(UnitsSystem unitsSystem, decimal length, decimal width, decimal height, decimal weight)
{
_unitsSystem = unitsSystem;
Weight = weight;
Length = length;
Width = width;
Height = height;
}

/// <summary>
/// Creates a new package object.
/// </summary>
Expand All @@ -17,7 +33,8 @@ public class Package
/// <param name="insuredValue">The insured-value of the package, in dollars.</param>
/// <param name="container">A specific packaging from a shipping provider. E.g. "LG FLAT RATE BOX" for USPS</param>
/// <param name="signatureRequiredOnDelivery">If true, will attempt to send this to the appropriate rate provider.</param>
public Package(int length, int width, int height, int weight, decimal insuredValue, string container = null, bool signatureRequiredOnDelivery = false) : this(length, width, height, (decimal) weight, insuredValue, container, signatureRequiredOnDelivery)
public Package(int length, int width, int height, int weight, decimal insuredValue, string container = null, bool signatureRequiredOnDelivery = false)
: this(length, width, height, (decimal) weight, insuredValue, container, signatureRequiredOnDelivery)
{
}

Expand All @@ -32,61 +49,52 @@ public Package(int length, int width, int height, int weight, decimal insuredVal
/// <param name="container">A specific packaging from a shipping provider. E.g. "LG FLAT RATE BOX" for USPS</param>
/// <param name="signatureRequiredOnDelivery">If true, will attempt to send this to the appropriate rate provider.</param>
public Package(decimal length, decimal width, decimal height, decimal weight, decimal insuredValue, string container = null, bool signatureRequiredOnDelivery = false)
: this(UnitsSystem.USCustomary, length, width, height, weight)

{
Length = length;
Width = width;
Height = height;
Weight = weight;
InsuredValue = insuredValue;
Container = container;
SignatureRequiredOnDelivery = signatureRequiredOnDelivery;
}

public decimal CalculatedGirth
public decimal GetCalculatedGirth(UnitsSystem unitsSystem)
{
get
{
var result = (Width * 2) + (Height * 2);
return Math.Ceiling(result);
}
var result = (_width.Get(unitsSystem) * 2) + (_height.Get(unitsSystem) * 2);
return Math.Ceiling(result);
}
public decimal Height { get; set; }

public decimal Height { get => _height.Get(); set => _height = new PackageDimension(_unitsSystem, value); }
public decimal Length { get => _length.Get(); set => _length = new PackageDimension(_unitsSystem, value); }
public decimal Width { get => _width.Get(); set => _width = new PackageDimension(_unitsSystem, value); }
public decimal Weight { get => _weight.Get(); set => _weight = new PackageWeight(_unitsSystem, value); }

public decimal InsuredValue { get; set; }
public bool IsOversize { get; set; }
public decimal Length { get; set; }
public decimal RoundedHeight
{
get { return Math.Ceiling(Height); }
}
public decimal RoundedLength
{
get { return Math.Ceiling(Length); }
}
public decimal RoundedWeight
{
get { return Math.Ceiling(Weight); }
}
public decimal RoundedWidth
{
get { return Math.Ceiling(Width); }
}
public decimal Weight { get; set; }
public decimal Width { get; set; }
public string Container { get; set; }
public bool SignatureRequiredOnDelivery { get; set; }

public decimal GetHeight(UnitsSystem unitsSystem) => _height.Get(unitsSystem);
public decimal GetLength(UnitsSystem unitsSystem) => _length.Get(unitsSystem);
public decimal GetWidth(UnitsSystem unitsSystem) => _width.Get(unitsSystem);
public decimal GetWeight(UnitsSystem unitsSystem) => _weight.Get(unitsSystem);

public decimal GetRoundedHeight(UnitsSystem unitsSystem) => _height.GetRounded(unitsSystem);
public decimal GetRoundedLength(UnitsSystem unitsSystem) => _length.GetRounded(unitsSystem);
public decimal GetRoundedWidth(UnitsSystem unitsSystem) => _width.GetRounded(unitsSystem);
public decimal GetRoundedWeight(UnitsSystem unitsSystem) => _weight.GetRounded(unitsSystem);

public PoundsAndOunces PoundsAndOunces
{
get
{
var poundsAndOunces = new PoundsAndOunces();
if (Weight <= 0)
var weight = _weight.Get(UnitsSystem.USCustomary);
if (weight > 0)
{
return poundsAndOunces;
poundsAndOunces.Pounds = (int)Math.Truncate(weight);
poundsAndOunces.Ounces = (weight - poundsAndOunces.Pounds) * 16;
}

poundsAndOunces.Pounds = (int) Math.Truncate(Weight);
poundsAndOunces.Ounces = (Weight - poundsAndOunces.Pounds) * 16;

return poundsAndOunces;
}
}
Expand Down
41 changes: 41 additions & 0 deletions ShippingRates/Models/PackageDimension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ShippingRates.Models
{
internal class PackageDimension
{
readonly UnitsSystem _unitsSystem;
readonly decimal _value;

public PackageDimension(UnitsSystem unitsSystem, decimal value)
{
_unitsSystem = unitsSystem;
_value = value;
}

public decimal Get() => _value;

public decimal Get(UnitsSystem unitsSystem)
{
if (unitsSystem == _unitsSystem)
{
return _value;
}
else if (unitsSystem == UnitsSystem.Metric && _unitsSystem == UnitsSystem.USCustomary)
{
return _value * 2.54m;
}
else if (unitsSystem == UnitsSystem.USCustomary && _unitsSystem == UnitsSystem.Metric)
{
return _value * 0.393701m;
}
throw new Exception($"Unsupported size conversion from {_unitsSystem} to {unitsSystem}");
}

public decimal GetRounded(UnitsSystem unitsSystem) => Math.Ceiling(Get(unitsSystem));
}
}
42 changes: 42 additions & 0 deletions ShippingRates/Models/PackageKgCm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace ShippingRates.Models
{
/// <summary>
/// Package object with dimensions in kgs and cm
/// </summary>
public class PackageKgCm : Package
{
/// <summary>
/// Creates a new package object with dimensions in kgs and cm
/// </summary>
/// <param name="length">The length of the package, in cm.</param>
/// <param name="width">The width of the package, in cm.</param>
/// <param name="height">The height of the package, in cm.</param>
/// <param name="weight">The weight of the package, in kgs.</param>
/// <param name="insuredValue">The insured-value of the package, in dollars.</param>
/// <param name="container">A specific packaging from a shipping provider. E.g. "LG FLAT RATE BOX" for USPS</param>
/// <param name="signatureRequiredOnDelivery">If true, will attempt to send this to the appropriate rate provider.</param>
public PackageKgCm(int length, int width, int height, int weight, decimal insuredValue, string container = null, bool signatureRequiredOnDelivery = false)
: this(length, width, height, (decimal)weight, insuredValue, container, signatureRequiredOnDelivery)
{
}

/// <summary>
/// Creates a new package object with dimensions in kgs and cm
/// </summary>
/// <param name="length">The length of the package, in cm.</param>
/// <param name="width">The width of the package, in cm.</param>
/// <param name="height">The height of the package, in cm.</param>
/// <param name="weight">The weight of the package, in kgs.</param>
/// <param name="insuredValue">The insured-value of the package, in dollars.</param>
/// <param name="container">A specific packaging from a shipping provider. E.g. "LG FLAT RATE BOX" for USPS</param>
/// <param name="signatureRequiredOnDelivery">If true, will attempt to send this to the appropriate rate provider.</param>
public PackageKgCm(decimal length, decimal width, decimal height, decimal weight, decimal insuredValue, string container = null, bool signatureRequiredOnDelivery = false)
: base(UnitsSystem.Metric, length, width, height, weight)

{
InsuredValue = insuredValue;
Container = container;
SignatureRequiredOnDelivery = signatureRequiredOnDelivery;
}
}
}
37 changes: 37 additions & 0 deletions ShippingRates/Models/PackageWeight.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;

namespace ShippingRates.Models
{
internal class PackageWeight
{
readonly UnitsSystem _unitsSystem;
readonly decimal _value;

public PackageWeight(UnitsSystem unitsSystem, decimal value)
{
_unitsSystem = unitsSystem;
_value = value;
}

public decimal Get() => _value;

public decimal Get(UnitsSystem unitsSystem)
{
if (unitsSystem == _unitsSystem)
{
return _value;
}
else if (unitsSystem == UnitsSystem.Metric && _unitsSystem == UnitsSystem.USCustomary)
{
return _value * 0.45359237m;
}
else if (unitsSystem == UnitsSystem.USCustomary && _unitsSystem == UnitsSystem.Metric)
{
return _value * 2.20462m;
}
throw new Exception($"Unsupported weight conversion from {_unitsSystem} to {unitsSystem}");
}

public decimal GetRounded(UnitsSystem unitsSystem) => Math.Ceiling(Get(unitsSystem));
}
}
5 changes: 3 additions & 2 deletions ShippingRates/Models/Shipment.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using ShippingRates.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
Expand Down Expand Up @@ -31,7 +32,7 @@ public Shipment(Address originAddress, Address destinationAddress, List<Package>
/// <summary>
/// Total shipment weight
/// </summary>
public decimal TotalPackageWeight => Packages.Sum(x => x.Weight);
public decimal GetTotalPackageWeight(UnitsSystem unitsSystem = UnitsSystem.USCustomary) => Packages.Sum(x => x.GetWeight(unitsSystem));
/// <summary>
/// Documents only in the shipment
/// </summary>
Expand All @@ -46,7 +47,7 @@ public Shipment(Address originAddress, Address destinationAddress, List<Package>
public List<Error> Errors { get; } = new List<Error>();
/// <summary>
/// Internal library errors during interaction with service provider
/// (e.g. SoapException was trown)
/// (e.g. SoapException was thrown)
/// </summary>
public List<string> InternalErrors { get; } = new List<string>();
}
Expand Down
Loading

0 comments on commit 7b2e779

Please sign in to comment.