diff --git a/README.md b/README.md index 1a35f06..409a45e 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ FedEx Rest API documentation https://developer.fedex.com/api/en-us/get-started.h - [ ] Postal Code Validation API - [x] Rate Quotes API - [ ] Service Availability API +- [ ] Trade Documents Upload API ### Other - [x] [oAuth authorization](#authorization) diff --git a/src/FedexRest/Services/TradeDocument/Entity/Document.php b/src/FedexRest/Services/TradeDocument/Entity/Document.php new file mode 100644 index 0000000..fa5b29f --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/Entity/Document.php @@ -0,0 +1,56 @@ +workflowName = $workflowName; + return $this; + } + + public function setName(string $name): Document + { + $this->name = $name; + return $this; + } + + public function setContentType(string $contentType): Document + { + $this->contentType = $contentType; + return $this; + } + + public function setMeta(Meta $meta): Document + { + $this->meta = $meta; + return $this; + } + + public function setCarrierCode(string $carrierCode): Document + { + $this->carrierCode = $carrierCode; + return $this; + } + + public function prepare(): array + { + $data = [ + 'workflowName' => $this->workflowName, + 'name' => $this->name, + 'contentType' => $this->contentType, + 'meta' => $this->meta->prepare(), + ]; + if (!empty($this->carrierCode)) { + $data['carrierCode'] = $this->carrierCode; + } + return $data; + } +} \ No newline at end of file diff --git a/src/FedexRest/Services/TradeDocument/Entity/ImageDocument.php b/src/FedexRest/Services/TradeDocument/Entity/ImageDocument.php new file mode 100644 index 0000000..a0cd799 --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/Entity/ImageDocument.php @@ -0,0 +1,44 @@ +referenceId = $referenceId; + return $this; + } + public function setName(string $name): ImageDocument + { + $this->name = $name; + return $this; + } + + public function setContentType(string $contentType): ImageDocument + { + $this->contentType = $contentType; + return $this; + } + + public function setMeta(ImageMeta $meta): ImageDocument + { + $this->meta = $meta; + return $this; + } + + public function prepare(): array + { + return [ + 'referenceId' => $this->referenceId, + 'name' => $this->name, + 'contentType' => $this->contentType, + 'meta' => $this->meta->prepare(), + ]; + } +} \ No newline at end of file diff --git a/src/FedexRest/Services/TradeDocument/Entity/ImageMeta.php b/src/FedexRest/Services/TradeDocument/Entity/ImageMeta.php new file mode 100644 index 0000000..9241f81 --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/Entity/ImageMeta.php @@ -0,0 +1,30 @@ +imageType = $imageType; + return $this; + } + + public function setImageIndex(string $imageIndex): ImageMeta + { + $this->imageIndex = $imageIndex; + return $this; + } + + public function prepare(): array + { + return [ + 'imageType' => $this->imageType, + 'imageIndex' => $this->imageIndex, + ]; + } +} diff --git a/src/FedexRest/Services/TradeDocument/Entity/Meta.php b/src/FedexRest/Services/TradeDocument/Entity/Meta.php new file mode 100644 index 0000000..0ad54b6 --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/Entity/Meta.php @@ -0,0 +1,88 @@ +shipDocumentType = $shipDocumentType; + return $this; + } + + public function setOriginCountryCode(string $originCountryCode): Meta + { + $this->originCountryCode = $originCountryCode; + return $this; + } + + public function setDestinationCountryCode(string $destinationCountryCode): Meta + { + $this->destinationCountryCode = $destinationCountryCode; + return $this; + } + + public function setFormCode(string $formCode): Meta + { + $this->formCode = $formCode; + return $this; + } + + public function setTrackingNumber(string $trackingNumber): Meta + { + $this->trackingNumber = $trackingNumber; + return $this; + } + + public function setShipmentDate(string $shipmentDate): Meta + { + $this->shipmentDate = $shipmentDate; + return $this; + } + + public function setOriginLocationCode(string $originLocationCode): Meta + { + $this->originLocationCode = $originLocationCode; + return $this; + } + + public function setDestinationLocationCode(string $destinationLocationCode): Meta + { + $this->destinationLocationCode = $destinationLocationCode; + return $this; + } + + public function prepare(): array + { + $data = [ + 'shipDocumentType' => $this->shipDocumentType, + 'originCountryCode' => $this->originCountryCode, + 'destinationCountryCode' => $this->destinationCountryCode, + ]; + if (!empty($this->formCode)) { + $data['formCode'] = $this->formCode; + } + if (!empty($this->trackingNumber)) { + $data['trackingNumber'] = $this->trackingNumber; + } + if (!empty($this->shipmentDate)) { + $data['shipmentDate'] = $this->shipmentDate; + } + if (!empty($this->originLocationCode)) { + $data['originLocationCode'] = $this->originLocationCode; + } + if (!empty($this->destinationLocationCode)) { + $data['destinationLocationCode'] = $this->destinationLocationCode; + } + return $data; + } +} diff --git a/src/FedexRest/Services/TradeDocument/Entity/Rule.php b/src/FedexRest/Services/TradeDocument/Entity/Rule.php new file mode 100644 index 0000000..c735011 --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/Entity/Rule.php @@ -0,0 +1,21 @@ +workflowName = $workflowName; + return $this; + } + + public function prepare(): array + { + return [ + 'workflowName' => $this->workflowName, + ]; + } +} \ No newline at end of file diff --git a/src/FedexRest/Services/TradeDocument/UploadDocument.php b/src/FedexRest/Services/TradeDocument/UploadDocument.php new file mode 100644 index 0000000..c0f8bef --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/UploadDocument.php @@ -0,0 +1,68 @@ +attachment = $attachment; + return $this; + } + + public function setDocument(Document $document): UploadDocument + { + $this->document = $document; + return $this; + } + + public function prepare(): array { + return [ + [ + 'name' => 'attachment', + 'contents' => $this->attachment, + 'filename' => $this->document->name, + 'headers' => [ + 'Content-Type' => $this->document->contentType + ] + ], + [ + 'name' => 'document', + 'contents' => json_encode($this->document->prepare()) + ] + ]; + } + + public function setApiEndpoint() + { + return '/documents/v1/etds/upload'; + } + + /** + * @throws MissingAccessTokenException + * @throws GuzzleException + */ + public function request() { + parent::request(); + try { + $query = $this->http_client->post($this->getApiUri($this->api_endpoint), [ + 'multipart' => $this->prepare(), + 'http_errors' => FALSE, + ]); + return ($this->raw === true) ? $query : json_decode($query->getBody()->getContents()); + } catch (\Exception $e) { + return $e->getMessage(); + } + } +} diff --git a/src/FedexRest/Services/TradeDocument/UploadImages.php b/src/FedexRest/Services/TradeDocument/UploadImages.php new file mode 100644 index 0000000..11a44d0 --- /dev/null +++ b/src/FedexRest/Services/TradeDocument/UploadImages.php @@ -0,0 +1,82 @@ +attachment = $attachment; + return $this; + } + + public function setDocument(ImageDocument $document): UploadImages + { + $this->document = $document; + return $this; + } + + public function setRules(Rule $rules): UploadImages + { + $this->rules = $rules; + return $this; + } + + public function prepare(): array { + $document = [ + 'document' => $this->document->prepare(), + 'rules' => $this->rules->prepare(), + ]; + // The order of the parameters in the request is fixed. You have to put the "document" param before the "attachment" param. + return [ + [ + 'name' => 'document', + 'contents' => json_encode($document) + ], + [ + 'name' => 'attachment', + 'contents' => $this->attachment, + 'filename' => $this->document->name, + 'headers' => [ + 'Content-Type' => $this->document->contentType + ] + ] + ]; + } + + public function setApiEndpoint() + { + return '/documents/v1/lhsimages/upload'; + } + + /** + * @throws MissingAccessTokenException + * @throws GuzzleException + */ + public function request() { + parent::request(); + try { + $query = $this->http_client->post($this->getApiUri($this->api_endpoint), [ + 'multipart' => $this->prepare(), + 'http_errors' => FALSE, + ]); + return ($this->raw === true) ? $query : json_decode($query->getBody()->getContents()); + } catch (\Exception $e) { + return $e->getMessage(); + } + } +} diff --git a/tests/FedexRest/Tests/TradeDocument/UploadDocumentTest.php b/tests/FedexRest/Tests/TradeDocument/UploadDocumentTest.php new file mode 100644 index 0000000..4b69aa5 --- /dev/null +++ b/tests/FedexRest/Tests/TradeDocument/UploadDocumentTest.php @@ -0,0 +1,86 @@ +auth = (new Authorize) + ->setClientId('l7749d031872cf4b55a7889376f360d045') + ->setClientSecret('bd59d91084e8482895d4ae2fb4fb79a3'); + } + + public function testUploadDocument() + { + $meta = (new Meta()) + ->setShipDocumentType('COMMERCIAL_INVOICE') + //->setFormCode('USMCA') + //->setTrackingNumber('794791292805') + //->setShipmentDate('2021-02-17T00:00:00') + //->setOriginLocationCode('GVTKK') + ->setOriginCountryCode('US') + //->setDestinationLocationCode('DEL') + ->setDestinationCountryCode('IN'); + $document = (new Document()) + ->setWorkflowName('ETDPreshipment') + //->setCarrierCode('FDXE') + ->setName('file.txt') + ->setContentType('text/plain') + ->setMeta($meta); + $path = __DIR__.'/../../resources/document.txt'; + $content = file_get_contents($path); + $request = (new UploadDocument()) + ->setAccessToken((string) $this->auth->authorize()->access_token) + ->setDocument($document) + ->setAttachment($content) + ->request(); + $this->assertObjectHasProperty('customerTransactionId', $request); + $this->assertObjectNotHasProperty('errors', $request); + $this->assertObjectHasProperty('output', $request); + $this->assertObjectHasProperty('meta', $request->output); + $this->assertObjectHasProperty('docId', $request->output->meta); + $this->assertNotEmpty($request->output->meta->docId); + } + + public function testUploadImages() + { + //$this->markTestIncomplete('Always fails with: "Invalid request: invalid input : WorkFlow Name"'); + $meta = (new ImageMeta()) + ->setImageType('SIGNATURE') + ->setImageIndex('IMAGE_1'); + $rules = (new Rule())->setWorkflowName('LetterheadSignature'); + $document = (new ImageDocument()) + ->setReferenceId('1234') + ->setName('LH2.PNG') + ->setContentType('image/png') + ->setMeta($meta); + $path = __DIR__.'/../../resources/signature.png'; + $content = file_get_contents($path); + $request = (new UploadImages()) + ->setAccessToken((string) $this->auth->authorize()->access_token) + ->setDocument($document) + ->setRules($rules) + ->setAttachment($content) + ->request(); + $this->assertObjectHasProperty('customerTransactionId', $request); + $this->assertObjectNotHasProperty('errors', $request); + $this->assertObjectHasProperty('output', $request); + $this->assertObjectHasProperty('documentReferenceId', $request->output); + $this->assertNotEmpty($request->output->documentReferenceId); + } +} \ No newline at end of file diff --git a/tests/FedexRest/resources/document.txt b/tests/FedexRest/resources/document.txt new file mode 100644 index 0000000..e07beac --- /dev/null +++ b/tests/FedexRest/resources/document.txt @@ -0,0 +1 @@ +Invoice \ No newline at end of file diff --git a/tests/FedexRest/resources/signature.png b/tests/FedexRest/resources/signature.png new file mode 100644 index 0000000..076e786 Binary files /dev/null and b/tests/FedexRest/resources/signature.png differ