diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba4ded72..340f480a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - `referralCustomer.addCreditCardFromStripe` - `referralCustomer.addBankAccountFromStripe` - Adds `tracking_codes` param to tracker index endpoint +- Routes `AmazonShippingAccount` to the correct endpoint - Fixes error parsing - Allows for alternative format of `errors` field (previously we deserialized the `errors` field into a list of `Error` objects; however, sometimes the errors are simply a list of strings. This change make the `errors` field a list of `Object` allowing for either the new `FieldError` object or a list of strings. Users will need to check for the type of error returned and handle appropriately) - Removed the unused `Error` model diff --git a/Makefile b/Makefile index aea2299e3..6656afa92 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ clean: ## coverage - Test (and build) the project to generate a coverage report coverage: - mvn verify -Dgpg.skip=true -Dcheckstyle.skip=true -Ddependency-check.skip=true -Djavadoc.skip=true jacoco:report + mvn test -Dgpg.skip=true -Dcheckstyle.skip=true -Ddependency-check.skip=true -Djavadoc.skip=true jacoco:report ## checkstyle - Check if project follows CheckStyle rules (must run install-checkstyle first) checkstyle: diff --git a/src/main/java/com/easypost/Constants.java b/src/main/java/com/easypost/Constants.java index c36f743b5..53a6c68f5 100644 --- a/src/main/java/com/easypost/Constants.java +++ b/src/main/java/com/easypost/Constants.java @@ -61,13 +61,17 @@ public abstract static class ErrorCodes { } public abstract static class CarrierAccountTypes { - public static final List CARRIER_TYPES_WITH_CUSTOM_WORKFLOW = ImmutableList.of("FedexAccount", - "FedexSmartpostAccount"); - } + public static final List CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_WORKFLOW = ImmutableList.of( + "FedexAccount", "FedexSmartpostAccount" + ); + + public static final List UPS_OAUTH_CARRIER_ACCOUNT_TYPES = ImmutableList.of( + "UpsAccount", "UpsMailInnovationsAccount", "UpsSurepostAccount" + ); - public abstract static class UpsAccountTypes { - public static final List UPS_OAUTH_CARRIER_ACCOUNT_TYPES = ImmutableList.of("UpsAccount", - "UpsMailInnovationsAccount", "UpsSurepostAccount"); + public static final List CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_OAUTH = ImmutableList.of( + "AmazonShippingAccount" + ); } public abstract static class Http { diff --git a/src/main/java/com/easypost/service/CarrierAccountService.java b/src/main/java/com/easypost/service/CarrierAccountService.java index b40e8ea6a..34f2a21f7 100644 --- a/src/main/java/com/easypost/service/CarrierAccountService.java +++ b/src/main/java/com/easypost/service/CarrierAccountService.java @@ -93,7 +93,7 @@ public CarrierAccount update(String id, final Map params) throws Map wrappedParams = new HashMap(); wrappedParams.put(selectTopLayerKey(type), params); - String endpoint = (Constants.UpsAccountTypes.UPS_OAUTH_CARRIER_ACCOUNT_TYPES.contains(type) + String endpoint = (Constants.CarrierAccountTypes.UPS_OAUTH_CARRIER_ACCOUNT_TYPES.contains(type) ? "ups_oauth_registrations/" : "carrier_accounts/") + id; @@ -121,10 +121,12 @@ public void delete(String id) throws EasyPostException { * @return The endpoint for the carrier account creation request. */ private static String selectCarrierAccountCreationEndpoint(final String carrierAccountType) { - if (Constants.CarrierAccountTypes.CARRIER_TYPES_WITH_CUSTOM_WORKFLOW.contains(carrierAccountType)) { + if (Constants.CarrierAccountTypes.CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_WORKFLOW.contains(carrierAccountType)) { return "carrier_accounts/register"; - } else if (Constants.UpsAccountTypes.UPS_OAUTH_CARRIER_ACCOUNT_TYPES.contains(carrierAccountType)) { + } else if (Constants.CarrierAccountTypes.UPS_OAUTH_CARRIER_ACCOUNT_TYPES.contains(carrierAccountType)) { return "ups_oauth_registrations"; + } else if (Constants.CarrierAccountTypes.CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_OAUTH.contains(carrierAccountType)) { + return "carrier_accounts/register_oauth"; } else { return "carrier_accounts"; } @@ -136,15 +138,20 @@ private static String selectCarrierAccountCreationEndpoint(final String carrierA * * @param carrierAccountType The type of carrier account to create. * @return The top-layer key for the carrier account creation/update request. + * @throws MissingParameterError when the request fails. */ - private static String selectTopLayerKey(final String carrierAccountType) throws EasyPostException { + private static String selectTopLayerKey(final String carrierAccountType) throws MissingParameterError { if (carrierAccountType == null) { throw new MissingParameterError( String.format(Constants.ErrorMessages.MISSING_REQUIRED_PARAMETER, "carrier account type")); } - return Constants.UpsAccountTypes.UPS_OAUTH_CARRIER_ACCOUNT_TYPES.contains(carrierAccountType) - ? "ups_oauth_registrations" - : "carrier_account"; + if (Constants.CarrierAccountTypes.UPS_OAUTH_CARRIER_ACCOUNT_TYPES.contains(carrierAccountType)) { + return "ups_oauth_registrations"; + } else if (Constants.CarrierAccountTypes.CARRIER_ACCOUNT_TYPES_WITH_CUSTOM_OAUTH.contains(carrierAccountType)) { + return "carrier_account_oauth_registrations"; + } else { + return "carrier_account"; + } } } diff --git a/src/test/cassettes/carrier_account/create_with_amazon.json b/src/test/cassettes/carrier_account/create_with_amazon.json new file mode 100644 index 000000000..070044b8d --- /dev/null +++ b/src/test/cassettes/carrier_account/create_with_amazon.json @@ -0,0 +1,263 @@ +[ + { + "recordedAt": 1744665939, + "request": { + "body": "{\n \"carrier_account_oauth_registrations\": {\n \"type\": \"AmazonShippingAccount\"\n }\n}", + "method": "POST", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ], + "Content-Type": [ + "application/json" + ] + }, + "uri": "https://api.easypost.com/v2/carrier_accounts/register_oauth" + }, + "response": { + "body": "{\n \"readable\": \"Amazon Shipping\",\n \"credentials\": {},\n \"created_at\": \"2025-04-14T21:25:39Z\",\n \"description\": null,\n \"type\": \"AmazonShippingAccount\",\n \"reference\": null,\n \"updated_at\": \"2025-04-14T21:25:39Z\",\n \"clone\": false,\n \"billing_type\": \"carrier\",\n \"logo\": null,\n \"id\": \"ca_490363c69ed34e26a8b8e74a5238170a\",\n \"fields\": {\n \"credentials\": {}\n },\n \"object\": \"CarrierAccount\"\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 201 Created" + ], + "content-length": [ + "1432" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb54nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "1a43adb967fd7d53e2bc3d1c003c98d6" + ], + "x-proxied": [ + "intlb4nuq 284c5d344a", + "extlb1nuq 99aac35317" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.074536" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202504111751-33c61fb414-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 201, + "message": "Created" + }, + "uri": "https://api.easypost.com/v2/carrier_accounts/register_oauth" + }, + "duration": 185 + }, + { + "recordedAt": 1744665939, + "request": { + "body": "", + "method": "GET", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ] + }, + "uri": "https://api.easypost.com/v2/carrier_accounts/ca_490363c69ed34e26a8b8e74a5238170a" + }, + "response": { + "body": "{\n \"readable\": \"Amazon Shipping\",\n \"credentials\": {},\n \"created_at\": \"2025-04-14T21:25:39Z\",\n \"description\": null,\n \"type\": \"AmazonShippingAccount\",\n \"reference\": null,\n \"updated_at\": \"2025-04-14T21:25:39Z\",\n \"clone\": false,\n \"billing_type\": \"carrier\",\n \"logo\": null,\n \"id\": \"ca_490363c69ed34e26a8b8e74a5238170a\",\n \"fields\": {\n \"credentials\": {}\n },\n \"object\": \"CarrierAccount\"\n}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 200 OK" + ], + "content-length": [ + "1432" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb34nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "1a43adb967fd7d53e2bc3d1d003c991e" + ], + "x-proxied": [ + "intlb4nuq 284c5d344a", + "extlb1nuq 99aac35317" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.032996" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202504111751-33c61fb414-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 200, + "message": "OK" + }, + "uri": "https://api.easypost.com/v2/carrier_accounts/ca_490363c69ed34e26a8b8e74a5238170a" + }, + "duration": 140 + }, + { + "recordedAt": 1744665939, + "request": { + "body": "", + "method": "DELETE", + "headers": { + "Accept-Charset": [ + "UTF-8" + ], + "User-Agent": [ + "REDACTED" + ] + }, + "uri": "https://api.easypost.com/v2/carrier_accounts/ca_490363c69ed34e26a8b8e74a5238170a" + }, + "response": { + "body": "{}", + "httpVersion": null, + "headers": { + "null": [ + "HTTP/1.1 200 OK" + ], + "content-length": [ + "2" + ], + "expires": [ + "0" + ], + "x-node": [ + "bigweb34nuq" + ], + "x-frame-options": [ + "SAMEORIGIN" + ], + "x-download-options": [ + "noopen" + ], + "x-permitted-cross-domain-policies": [ + "none" + ], + "x-backend": [ + "easypost" + ], + "pragma": [ + "no-cache" + ], + "strict-transport-security": [ + "max-age\u003d31536000; includeSubDomains; preload" + ], + "x-xss-protection": [ + "1; mode\u003dblock" + ], + "x-content-type-options": [ + "nosniff" + ], + "x-ep-request-uuid": [ + "1a43adb967fd7d53e2bc3d35003c994c" + ], + "x-proxied": [ + "intlb4nuq 284c5d344a", + "extlb1nuq 99aac35317" + ], + "referrer-policy": [ + "strict-origin-when-cross-origin" + ], + "x-runtime": [ + "0.052300" + ], + "content-type": [ + "application/json; charset\u003dutf-8" + ], + "x-version-label": [ + "easypost-202504111751-33c61fb414-master" + ], + "cache-control": [ + "private, no-cache, no-store" + ] + }, + "status": { + "code": 200, + "message": "OK" + }, + "uri": "https://api.easypost.com/v2/carrier_accounts/ca_490363c69ed34e26a8b8e74a5238170a" + }, + "duration": 164 + } +] \ No newline at end of file diff --git a/src/test/java/com/easypost/CarrierAccountTest.java b/src/test/java/com/easypost/CarrierAccountTest.java index 24f3119eb..18b672912 100644 --- a/src/test/java/com/easypost/CarrierAccountTest.java +++ b/src/test/java/com/easypost/CarrierAccountTest.java @@ -29,10 +29,7 @@ public final class CarrierAccountTest { private static TestUtils.VCR vcr; - private static MockedStatic requestMock = Mockito.mockStatic(Requestor.class); - private static CarrierAccount createBasicCarrierAccount() throws EasyPostException { - // This method creates DhlEcsAccount carrier account. CarrierAccount carrierAccount = vcr.client.carrierAccount.create(Fixtures.basicCarrierAccount()); testCarrierAccountId = carrierAccount.getId(); // trigger deletion after test return carrierAccount; @@ -43,9 +40,9 @@ private static CarrierAccount createUpsCarrierAccount() throws EasyPostException data.put("type", "UpsAccount"); data.put("account_number", "123456789"); - CarrierAccount upsAccount = vcr.client.carrierAccount.create(data); - testCarrierAccountId = upsAccount.getId(); // trigger deletion after test - return upsAccount; + CarrierAccount carrierAccount = vcr.client.carrierAccount.create(data); + testCarrierAccountId = carrierAccount.getId(); // trigger deletion after test + return carrierAccount; } /** @@ -126,11 +123,31 @@ public void testCreateWithCustomWorkflow() throws EasyPostException { public void testCreateWithUPS() throws EasyPostException { vcr.setUpTest("create_with_ups"); - CarrierAccount upsAccount = createUpsCarrierAccount(); + CarrierAccount carrierAccount = createUpsCarrierAccount(); + + assertInstanceOf(CarrierAccount.class, carrierAccount); + assertTrue(carrierAccount.getId().startsWith("ca_")); + assertEquals("UpsAccount", carrierAccount.getType()); + } + + /** + * Test creating an Amazon carrier account. + * + * @throws EasyPostException when the request fails. + */ + @Test + public void testCreateWithAmazon() throws EasyPostException { + vcr.setUpTest("create_with_amazon"); + + Map data = new HashMap<>(); + data.put("type", "AmazonShippingAccount"); + + CarrierAccount carrierAccount = vcr.client.carrierAccount.create(data); + testCarrierAccountId = carrierAccount.getId(); // trigger deletion after test - assertInstanceOf(CarrierAccount.class, upsAccount); - assertTrue(upsAccount.getId().startsWith("ca_")); - assertEquals("UpsAccount", upsAccount.getType()); + assertInstanceOf(CarrierAccount.class, carrierAccount); + assertTrue(carrierAccount.getId().startsWith("ca_")); + assertEquals("AmazonShippingAccount", carrierAccount.getType()); } /** @@ -197,15 +214,15 @@ public void testUpdate() throws EasyPostException { public void testUpdateUpsAccount() throws EasyPostException { vcr.setUpTest("update_ups"); - CarrierAccount upsAccount = createUpsCarrierAccount(); + CarrierAccount carrierAccount = createUpsCarrierAccount(); Map updateParams = new HashMap<>(); updateParams.put("account_number", "987654321"); - CarrierAccount updatedUpsAccount = vcr.client.carrierAccount.update(upsAccount.getId(), updateParams); + CarrierAccount updatedCarrierAccount = vcr.client.carrierAccount.update(carrierAccount.getId(), updateParams); - assertInstanceOf(CarrierAccount.class, updatedUpsAccount); - assertTrue(updatedUpsAccount.getId().startsWith("ca_")); - assertEquals("UpsAccount", updatedUpsAccount.getType()); + assertInstanceOf(CarrierAccount.class, updatedCarrierAccount); + assertTrue(updatedCarrierAccount.getId().startsWith("ca_")); + assertEquals("UpsAccount", updatedCarrierAccount.getType()); } /** @@ -265,6 +282,8 @@ public void testCarrierFieldsJsonDeserialization() { */ @Test public void testCarrierFieldsJsonSerialization() { + MockedStatic requestMock = Mockito.mockStatic(Requestor.class); + String carrierAccountJson = "[{\"id\":\"ca_123\",\"object\":\"CarrierAccount\",\"fields\":{\"credentials\":" + "{\"account_number\":{\"visibility\":\"visible\",\"label\":\"DHL Account Number\"," + "\"value\":\"123456\"},\"country\":{\"visibility\":\"visible\",\"label\":" +