diff --git a/CHANGELOG.md b/CHANGELOG.md index 567e7a28..ff40451e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # CHANGELOG -## Next Release +## v8.3.0 (2025-11-10) - Adds support for `UspsShipAccount` - Adds `tracker.retrieveBatch` function +- Adds `verify_carrier` address param ## v8.2.0 (2025-06-18) diff --git a/composer.json b/composer.json index 620f0f0d..cc1b01e8 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "easypost/easypost-php", "description": "EasyPost Shipping API Client Library for PHP", - "version": "8.2.0", + "version": "8.3.0", "keywords": [ "shipping", "api", diff --git a/lib/EasyPost/Constant/Constants.php b/lib/EasyPost/Constant/Constants.php index 16119a19..ae2e8945 100644 --- a/lib/EasyPost/Constant/Constants.php +++ b/lib/EasyPost/Constant/Constants.php @@ -11,7 +11,7 @@ abstract class Constants const BETA_API_VERSION = 'beta'; // Library constants - const LIBRARY_VERSION = '8.2.0'; + const LIBRARY_VERSION = '8.3.0'; const SUPPORT_EMAIL = 'support@easypost.com'; // Validation diff --git a/lib/EasyPost/Service/AddressService.php b/lib/EasyPost/Service/AddressService.php index 351ddec9..74969d59 100644 --- a/lib/EasyPost/Service/AddressService.php +++ b/lib/EasyPost/Service/AddressService.php @@ -66,6 +66,12 @@ public function create(mixed $params = null): mixed $wrappedParams['verify_strict'] = $verifyStrict; } + if (isset($params['verify_carrier'])) { + $verifyCarrier = $params['verify_carrier']; + unset($params['verify_carrier']); + $wrappedParams['verify_carrier'] = $verifyCarrier; + } + $wrappedParams['address'] = $params; return self::createResource(self::serviceModelClassName(self::class), $wrappedParams); @@ -79,10 +85,18 @@ public function create(mixed $params = null): mixed */ public function createAndVerify(mixed $params = null): mixed { - $params = InternalUtil::wrapParams($params, 'address'); + $wrappedParams = []; + + if (isset($params['verify_carrier'])) { + $verifyCarrier = $params['verify_carrier']; + unset($params['verify_carrier']); + $wrappedParams['verify_carrier'] = $verifyCarrier; + } + + $wrappedParams['address'] = $params; $url = self::classUrl(self::serviceModelClassName(self::class)); - $response = Requestor::request($this->client, 'post', $url . '/create_and_verify', $params); + $response = Requestor::request($this->client, 'post', $url . '/create_and_verify', $wrappedParams); return InternalUtil::convertToEasyPostObject($this->client, $response['address']); } diff --git a/test/EasyPost/AddressTest.php b/test/EasyPost/AddressTest.php index 09947b8f..2d993c05 100644 --- a/test/EasyPost/AddressTest.php +++ b/test/EasyPost/AddressTest.php @@ -233,4 +233,45 @@ public function testVerifyInvalid(): void $this->assertEquals('Unable to verify address.', $error->getMessage()); } } + + /** + * Test creating a verified address with verify_carrier. + * + * We purposefully pass in slightly incorrect data to get the corrected address back once verified. + */ + public function testCreateVerifyCarrier(): void + { + TestUtil::setupCassette('addresses/createVerifyCarrier.yml'); + + $addressData = Fixture::incorrectAddress(); + + $addressData['verify'] = true; + $addressData['verify_carrier'] = 'UPS'; + $address = self::$client->address->create($addressData); + + $this->assertInstanceOf(Address::class, $address); + + $this->assertEquals('Address not found', $address->verifications->delivery->errors[0]->message); + $this->assertEquals('Address not found', $address->verifications->zip4->errors[0]->message); + } + + /** + * Test creating a verified address with verify_carrier. + * + * We purposefully pass in slightly incorrect data to get the corrected address back once verified. + */ + public function testCreateAndVerifyCarrier(): void + { + TestUtil::setupCassette('addresses/createAndVerifyCarrier.yml'); + + $addressData = Fixture::incorrectAddress(); + + $addressData['verify_carrier'] = 'UPS'; + $address = self::$client->address->createAndVerify($addressData); + + $this->assertInstanceOf(Address::class, $address); + + $this->assertEquals('Address not found', $address->verifications->delivery->errors[0]->message); + $this->assertEquals('Address not found', $address->verifications->zip4->errors[0]->message); + } } diff --git a/test/cassettes/addresses/createAndVerifyCarrier.yml b/test/cassettes/addresses/createAndVerifyCarrier.yml new file mode 100644 index 00000000..6463448f --- /dev/null +++ b/test/cassettes/addresses/createAndVerifyCarrier.yml @@ -0,0 +1,82 @@ + +- + request: + method: POST + url: 'https://api.easypost.com/v2/addresses/create_and_verify' + headers: + Host: api.easypost.com + Expect: '' + Accept-Encoding: '' + Accept: application/json + Authorization: '' + Content-Type: application/json + User-Agent: '' + body: '{"verify_carrier":"UPS","address":{"company":"EasyPost","street1":"000 unknown street","city":"Not A City","state":"ZZ","zip":"00001","country":"US","email":"test@example.com","phone":"5555555555"}}' + response: + status: + code: 200 + message: OK + headers: + x-frame-options: SAMEORIGIN + x-xss-protection: '1; mode=block' + x-content-type-options: nosniff + x-download-options: noopen + x-permitted-cross-domain-policies: none + referrer-policy: strict-origin-when-cross-origin + x-ep-request-uuid: bcd43725690e365ee786afa002a5d5f7 + cache-control: 'private, no-cache, no-store' + pragma: no-cache + expires: '0' + location: /api/v2/addresses/adr_374a9a5ebc0511f094003cecef1b359e + content-type: 'application/json; charset=utf-8' + content-length: '820' + x-runtime: '0.753222' + x-node: bigweb55nuq + x-version-label: easypost-202511071655-85836cab32-master + x-backend: easypost + x-proxied: ['intlb3nuq c0061e0a2e', 'extlb2nuq cbbd141214'] + strict-transport-security: 'max-age=31536000; includeSubDomains; preload' + body: '{"address":{"id":"adr_374a9a5ebc0511f094003cecef1b359e","object":"Address","created_at":"2025-11-07T18:11:43Z","updated_at":"2025-11-07T18:11:43Z","name":null,"company":"EASYPOST","street1":"000 UNKNOWN STREET","street2":"","city":"NOT A CITY","state":"ZZ","zip":"00001","country":"US","phone":"","email":"","mode":"test","carrier_facility":null,"residential":null,"federal_tax_id":null,"state_tax_id":null,"verifications":{"zip4":{"success":true,"errors":[{"code":"E.ADDRESS.NOT_FOUND","field":"address","message":"Address not found","suggestion":null}],"details":null},"delivery":{"success":true,"errors":[{"code":"E.ADDRESS.NOT_FOUND","field":"address","message":"Address not found","suggestion":null}],"details":{"latitude":null,"longitude":null,"time_zone":null}},"verify_carrier":"ups"}}}' + curl_info: + url: 'https://api.easypost.com/v2/addresses/create_and_verify' + content_type: 'application/json; charset=utf-8' + http_code: 200 + header_size: 754 + request_size: 524 + filetime: -1 + ssl_verify_result: 0 + redirect_count: 0 + total_time: 0.925778 + namelookup_time: 0.003742 + connect_time: 0.058394 + pretransfer_time: 0.114748 + size_upload: 198.0 + size_download: 820.0 + speed_download: 885.0 + speed_upload: 213.0 + download_content_length: 820.0 + upload_content_length: 198.0 + starttransfer_time: 0.925706 + redirect_time: 0.0 + redirect_url: '' + primary_ip: 169.62.110.130 + certinfo: { } + primary_port: 443 + local_ip: 10.130.6.31 + local_port: 50329 + http_version: 2 + protocol: 2 + ssl_verifyresult: 0 + scheme: https + appconnect_time_us: 114699 + connect_time_us: 58394 + namelookup_time_us: 3742 + pretransfer_time_us: 114748 + redirect_time_us: 0 + starttransfer_time_us: 925706 + posttransfer_time_us: 114747 + total_time_us: 925778 + effective_method: POST + capath: '' + cainfo: '' + index: 0 diff --git a/test/cassettes/addresses/createVerifyCarrier.yml b/test/cassettes/addresses/createVerifyCarrier.yml new file mode 100644 index 00000000..b3c682a9 --- /dev/null +++ b/test/cassettes/addresses/createVerifyCarrier.yml @@ -0,0 +1,82 @@ + +- + request: + method: POST + url: 'https://api.easypost.com/v2/addresses' + headers: + Host: api.easypost.com + Expect: '' + Accept-Encoding: '' + Accept: application/json + Authorization: '' + Content-Type: application/json + User-Agent: '' + body: '{"verify":"true","verify_carrier":"UPS","address":{"company":"EasyPost","street1":"000 unknown street","city":"Not A City","state":"ZZ","zip":"00001","country":"US","email":"test@example.com","phone":"5555555555"}}' + response: + status: + code: 201 + message: Created + headers: + x-frame-options: SAMEORIGIN + x-xss-protection: '1; mode=block' + x-content-type-options: nosniff + x-download-options: noopen + x-permitted-cross-domain-policies: none + referrer-policy: strict-origin-when-cross-origin + x-ep-request-uuid: bcd43722690e365ee786af9f02a5d437 + cache-control: 'private, no-cache, no-store' + pragma: no-cache + expires: '0' + location: /api/v2/addresses/adr_36b9f6f8bc0511f0a79aac1f6bc539aa + content-type: 'application/json; charset=utf-8' + content-length: '808' + x-runtime: '0.546585' + x-node: bigweb65nuq + x-version-label: easypost-202511071655-85836cab32-master + x-backend: easypost + x-proxied: ['intlb3nuq c0061e0a2e', 'extlb2nuq cbbd141214'] + strict-transport-security: 'max-age=31536000; includeSubDomains; preload' + body: '{"id":"adr_36b9f6f8bc0511f0a79aac1f6bc539aa","object":"Address","created_at":"2025-11-07T18:11:42Z","updated_at":"2025-11-07T18:11:42Z","name":null,"company":"EASYPOST","street1":"000 UNKNOWN STREET","street2":"","city":"NOT A CITY","state":"ZZ","zip":"00001","country":"US","phone":"","email":"","mode":"test","carrier_facility":null,"residential":null,"federal_tax_id":null,"state_tax_id":null,"verifications":{"zip4":{"success":true,"errors":[{"code":"E.ADDRESS.NOT_FOUND","field":"address","message":"Address not found","suggestion":null}],"details":null},"delivery":{"success":true,"errors":[{"code":"E.ADDRESS.NOT_FOUND","field":"address","message":"Address not found","suggestion":null}],"details":{"latitude":null,"longitude":null,"time_zone":null}},"verify_carrier":"ups"}}' + curl_info: + url: 'https://api.easypost.com/v2/addresses' + content_type: 'application/json; charset=utf-8' + http_code: 201 + header_size: 759 + request_size: 522 + filetime: -1 + ssl_verify_result: 0 + redirect_count: 0 + total_time: 0.76288 + namelookup_time: 0.047738 + connect_time: 0.10146 + pretransfer_time: 0.158975 + size_upload: 214.0 + size_download: 808.0 + speed_download: 1059.0 + speed_upload: 280.0 + download_content_length: 808.0 + upload_content_length: 214.0 + starttransfer_time: 0.762726 + redirect_time: 0.0 + redirect_url: '' + primary_ip: 169.62.110.130 + certinfo: { } + primary_port: 443 + local_ip: 10.130.6.31 + local_port: 50328 + http_version: 2 + protocol: 2 + ssl_verifyresult: 0 + scheme: https + appconnect_time_us: 158032 + connect_time_us: 101460 + namelookup_time_us: 47738 + pretransfer_time_us: 158975 + redirect_time_us: 0 + starttransfer_time_us: 762726 + posttransfer_time_us: 158974 + total_time_us: 762880 + effective_method: POST + capath: '' + cainfo: '' + index: 0