Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Makes `ReferralCustomer.RetrieveEasypostStripeApiKey` public to help facilitate adding credit cards using Stripe.js
- Correctly passes `end_shipper_id` param instead of `end_shipper` in shipment buy calls (closes [669](https://github.com/EasyPost/easypost-csharp/issues/669))
- Add `Surcharge` model and `Surcharges` property to `Rate` class
- Adds support for `FedexDefaultAccount`, `GofoWalletAccount`, `UpsDapAccount`, `UniUniWalletAccount`, and `VehoWalletAccount` by properly routing carrier-account create requests to the `/carrier_accounts/open` endpoint

## v7.10.0 (2026-07-24)

Expand Down
33 changes: 17 additions & 16 deletions EasyPost.Tests/ServicesTests/CarrierAccountServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,29 @@ public async Task TestCreate()
Assert.Equal("DhlEcsAccount", carrierAccount.Type);
}

[Fact]
[Theory]
[CrudOperations.Create]
[Testing.Parameters]
public async Task TestCreateWithCustomWorkflow()
[InlineData("FedexAccount")]
[InlineData("FedexSmartpostAccount")]
[InlineData("AmazonShippingAccount")]
[InlineData("UpsAccount")]
[InlineData("UpsMailInnovationsAccount")]
[InlineData("UpsSurepostAccount")]
[InlineData("UspsShipAccount")]
[InlineData("FedexDefaultAccount")]
[InlineData("GofoWalletAccount")]
[InlineData("UpsDapAccount")]
[InlineData("UniUniWalletAccount")]
[InlineData("VehoWalletAccount")]
public async Task TestCreateWithCustomWorkflow(string carrierType)
{
UseVCR("create_with_custom_workflow");

// FedEx or UPS should trigger a function error since not supported by legacy parameter method
try
{
Dictionary<string, object> parameters = Fixtures.BasicCarrierAccount;
parameters["type"] = CarrierAccountType.FedEx.Name;
parameters["registration_data"] = new Dictionary<string, object>();
Dictionary<string, object> parameters = Fixtures.BasicCarrierAccount;
parameters["type"] = carrierType;

CarrierAccount carrierAccount = await Client.CarrierAccount.Create(parameters);
CleanUpAfterTest(carrierAccount.Id);
}
catch (InvalidFunctionError e)
{
// Function should have been halted due to incompatible carrier account type
Assert.NotNull(e);
}
await Assert.ThrowsAsync<InvalidFunctionError>(async () => await Client.CarrierAccount.Create(parameters));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using EasyPost.Exceptions.API;
using EasyPost.Exceptions.General;
using EasyPost.Models.API;
using EasyPost.Tests._Utilities;
using EasyPost.Tests._Utilities.Attributes;
using EasyPost.Utilities.Internal.Attributes;
using Newtonsoft.Json.Linq;
using Xunit;

namespace EasyPost.Tests.ServicesTests.WithParameters
Expand Down Expand Up @@ -110,6 +113,28 @@ public async Task TestCreateUps()
Assert.StartsWith("ca_", carrierAccount.Id);
}

[Theory]
[CrudOperations.Create]
[Testing.Parameters]
[MemberData(nameof(CreateUrlRoutingData))]
public async Task TestCreateUrlRouting(Parameters.CarrierAccount.ACreate parameters, string cassetteName, string expectedEndpoint, string expectedBodyKey)
{
UseVCR(cassetteName);

try
{
CarrierAccount carrierAccount = await Client.CarrierAccount.Create(parameters);
CleanUpAfterTest(carrierAccount.Id);
}
catch (ApiError error)
{
Assert.NotEqual(404, error.StatusCode);
Assert.NotEqual(500, error.StatusCode);
}

AssertCassetteRequest(cassetteName, expectedEndpoint, expectedBodyKey);
}

[Fact]
[CrudOperations.Create]
[Testing.Exception]
Expand Down Expand Up @@ -196,6 +221,63 @@ public async Task TestUpdateUps()

#endregion

public static IEnumerable<object[]> CreateUrlRoutingData()
{
yield return new object[] { Fixtures.Parameters.CarrierAccounts.CreateFedEx(new Dictionary<string, object>()), "create_url_routing_fedex", "/carrier_accounts/register", "carrier_account" };
yield return new object[] { CreateFedExSmartPostParameters(), "create_url_routing_fedex_smartpost", "/carrier_accounts/register", "carrier_account" };
yield return new object[] { new Parameters.CarrierAccount.CreateFedExDefault(), "create_url_routing_fedex_default", "/carrier_accounts/open", "carrier_account" };
yield return new object[] { new Parameters.CarrierAccount.CreateGofoWallet(), "create_url_routing_gofo_wallet", "/carrier_accounts/open", "carrier_account" };
yield return new object[] { new Parameters.CarrierAccount.CreateUpsDap(), "create_url_routing_ups_dap", "/carrier_accounts/open", "carrier_account" };
yield return new object[] { new Parameters.CarrierAccount.CreateUniUniWallet(), "create_url_routing_uniuni_wallet", "/carrier_accounts/open", "carrier_account" };
yield return new object[] { new Parameters.CarrierAccount.CreateVehoWallet(), "create_url_routing_veho_wallet", "/carrier_accounts/open", "carrier_account" };
yield return new object[] { new Parameters.CarrierAccount.CreateOauth { Type = CarrierAccountType.AmazonShippingAccount.Name }, "create_url_routing_amazon_shipping", "/carrier_accounts/register_oauth", "carrier_account_oauth_registrations" };
yield return new object[] { Fixtures.Parameters.CarrierAccounts.CreateUps(new Dictionary<string, object>()), "create_url_routing_ups", "/carrier_accounts/register_oauth", "carrier_account_oauth_registrations" };
yield return new object[] { new Parameters.CarrierAccount.CreateUpsMailInnovations { AccountNumber = "123456789" }, "create_url_routing_ups_mail_innovations", "/carrier_accounts/register_oauth", "carrier_account_oauth_registrations" };
yield return new object[] { new Parameters.CarrierAccount.CreateUpsSurePost { AccountNumber = "123456789" }, "create_url_routing_ups_surepost", "/carrier_accounts/register_oauth", "carrier_account_oauth_registrations" };
yield return new object[] { new Parameters.CarrierAccount.CreateOauth { Type = CarrierAccountType.UspsShipAccount.Name }, "create_url_routing_usps_ship", "/carrier_accounts/register_oauth", "carrier_account_oauth_registrations" };
}

private static Parameters.CarrierAccount.CreateFedExSmartPost CreateFedExSmartPostParameters()
{
return new Parameters.CarrierAccount.CreateFedExSmartPost
{
AccountNumber = "123456789",
HubId = "1234",
CorporateAddressCity = "San Francisco",
CorporateAddressCountryCode = "US",
CorporateAddressPostalCode = "94105",
CorporateAddressState = "CA",
CorporateAddressStreet = "345 California St",
CorporateCompanyName = "EasyPost",
CorporateEmailAddress = "me@example.com",
CorporateFirstName = "Demo",
CorporateLastName = "User",
CorporateJobTitle = "Developer",
CorporatePhoneNumber = "5555555555",
ShippingAddressCity = "San Francisco",
ShippingAddressCountryCode = "US",
ShippingAddressPostalCode = "94105",
ShippingAddressState = "CA",
ShippingAddressStreet = "345 California St",
};
}

private static void AssertCassetteRequest(string cassetteName, string expectedEndpoint, string expectedBodyKey)
{
string cassettePath = Path.GetFullPath(Path.Combine(TestUtils.GetSourceFileDirectory(), "..", "..", "cassettes", "carrier_account_service_with_parameters", $"{cassetteName}.json"));
string cassetteJson = File.ReadAllText(cassettePath);
JArray interactions = JArray.Parse(cassetteJson);
JToken? interaction = interactions.FirstOrDefault();

Assert.NotNull(interaction);

string? requestUri = interaction!["Request"]?["Uri"]?.Value<string>();
string? requestBody = interaction["Request"]?["Body"]?.Value<string>();

Assert.EndsWith(expectedEndpoint, requestUri);
Assert.Contains(expectedBodyKey, requestBody);
}

#endregion
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading