From 8dbf562ab94531ab07a30891d3b588076af27d5b Mon Sep 17 00:00:00 2001 From: Hakim Razalan Date: Tue, 6 Sep 2022 11:25:14 +0800 Subject: [PATCH 1/2] add fulfillment order --- src/Enum/Fields/AssignedLocationFields.php | 31 +++++ src/Enum/Fields/DestinationLocationFields.php | 37 ++++++ src/Enum/Fields/FulfillmentOrderFields.php | 35 ++++++ src/Enum/FulfillmentHoldReason.php | 12 ++ src/Object/AssignedLocation.php | 16 +++ src/Object/DestinationLocation.php | 16 +++ src/Object/FulfillmentOrder.php | 30 +++++ src/Service/FulfillmentOrderService.php | 115 ++++++++++++++++++ 8 files changed, 292 insertions(+) create mode 100644 src/Enum/Fields/AssignedLocationFields.php create mode 100644 src/Enum/Fields/DestinationLocationFields.php create mode 100644 src/Enum/Fields/FulfillmentOrderFields.php create mode 100644 src/Enum/FulfillmentHoldReason.php create mode 100644 src/Object/AssignedLocation.php create mode 100644 src/Object/DestinationLocation.php create mode 100644 src/Object/FulfillmentOrder.php create mode 100644 src/Service/FulfillmentOrderService.php diff --git a/src/Enum/Fields/AssignedLocationFields.php b/src/Enum/Fields/AssignedLocationFields.php new file mode 100644 index 0000000..acfe511 --- /dev/null +++ b/src/Enum/Fields/AssignedLocationFields.php @@ -0,0 +1,31 @@ + 'integer', + 'name' => 'string', + 'address1' => 'string', + 'address2' => 'string', + 'city' => 'string', + 'zip' => 'string', + 'province' => 'string', + 'country_code' => 'string', + 'phone' => 'string' + ]; + } +} diff --git a/src/Enum/Fields/DestinationLocationFields.php b/src/Enum/Fields/DestinationLocationFields.php new file mode 100644 index 0000000..9d01cb8 --- /dev/null +++ b/src/Enum/Fields/DestinationLocationFields.php @@ -0,0 +1,37 @@ + 'integer', + 'address1' => 'string', + 'address2' => 'string', + 'city' => 'string', + 'company' => 'string', + 'country' => 'string', + 'email' => 'string', + 'first_name' => 'string', + 'last_name' => 'string', + 'phone' => 'string', + 'province' => 'string', + 'zip' => 'string', + ]; + } +} diff --git a/src/Enum/Fields/FulfillmentOrderFields.php b/src/Enum/Fields/FulfillmentOrderFields.php new file mode 100644 index 0000000..0be84c8 --- /dev/null +++ b/src/Enum/Fields/FulfillmentOrderFields.php @@ -0,0 +1,35 @@ + 'integer', + 'order_id' => 'integer', + 'shop_id' => 'integer', + 'assigned_location_id' => 'integer', + 'status' => 'string', + "supported_actions" => 'array', + "destination" => 'DestinationLocation', // Probably need new fields + 'line_items' => 'LineItem[]', + 'fulfillment_service_handle' => 'string', + "assigned_location" => 'AssignedLocation', // Probably need new fields + "merchant_requests" => 'array', // Probably need new fields + ); + } +} diff --git a/src/Enum/FulfillmentHoldReason.php b/src/Enum/FulfillmentHoldReason.php new file mode 100644 index 0000000..b6afe95 --- /dev/null +++ b/src/Enum/FulfillmentHoldReason.php @@ -0,0 +1,12 @@ +request($endpoint, 'GET', $params); + return $this->createCollection(FulfillmentOrder::class, $response['fulfillment_orders']); + } + + // Retrieves a specific fulfillment order + public function get($fulfillmentOrderId, array $params = []) + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrderId . '.json'; + $response = $this->request($endpoint, 'GET', $params); + return $this->createObject(FulfillmentOrder::class, $response); + } + + // Cancel a fulfillment order + public function cancel(FulfillmentOrder &$fulfillmentOrder) + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/cancel.json'; + $response = $this->request($endpoint, 'POST'); + $fulfillmentOrder->setData($response['fulfillment_order']); + } + + // Marks a fulfillment order as incomplete + public function close(FulfillmentOrder &$fulfillmentOrder, $message = "") + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/close.json'; + $response = $this->request( + $endpoint, + 'POST', + [ + "fulfillment_order" => [ + "message" => $message + ] + ] + ); + $fulfillmentOrder->setData($response['fulfillment_order']); + } + + // Applies a fulfillment hold on a fulfillment order with status Open + public function hold(FulfillmentOrder &$fulfillmentOrder, $reason, $reasonNotes = "") + { + FulfillmentOrder::isValidHoldReason($reason); + + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/hold.json'; + $response = $this->request( + $endpoint, + 'POST', + [ + "fulfillment_hold" => [ + "reason" => $reason, + "reason_notes" => $reasonNotes + ] + ] + ); + $fulfillmentOrder->setData($response['fulfillment_order']); + } + + // Moves a fulfillment order to a new location + public function move(FulfillmentOrder &$fulfillmentOrder, $newLocationId) + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/move.json'; + $response = $this->request( + $endpoint, + 'POST', + [ + "fulfillment_order" => [ + "new_location_id" => $newLocationId, + ] + ] + ); + $fulfillmentOrder->setData($response['fulfillment_order']); + } + + // Marks the fulfillment order as open + public function open(FulfillmentOrder &$fulfillmentOrder) + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/open.json'; + $response = $this->request($endpoint, 'POST'); + $fulfillmentOrder->setData($response['fulfillment_order']); + } + + // Releases the fulfillment hold on a fulfillment order + public function release(FulfillmentOrder &$fulfillmentOrder) + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/release_hold.json'; + $response = $this->request($endpoint, 'POST'); + $fulfillmentOrder->setData($response['fulfillment_order']); + } + + // Reschedules the fulfill_at time of a scheduled fulfillment order + public function reschedule(FulfillmentOrder &$fulfillmentOrder, $newDate) + { + $endpoint = '/fulfillment_orders/' . $fulfillmentOrder->id . '/reschedule.json'; + $response = $this->request( + $endpoint, + 'POST', + [ + "fulfillment_order" => [ + "new_fulfill_at" => $newDate, + ] + ] + ); + $fulfillmentOrder->setData($response['fulfillment_order']); + } +} From 1e31c0f75f21483ca6311faac84c07393f5ea7ab Mon Sep 17 00:00:00 2001 From: Hakim Razalan Date: Tue, 6 Sep 2022 11:40:17 +0800 Subject: [PATCH 2/2] Add tests --- data/mocks/lists/FulfillmentOrderList.json | 67 ++++++++++++++++++++ data/mocks/objects/FulfillmentOrder.json | 52 +++++++++++++++ test/Service/FulfillmentOrderServiceTest.php | 29 +++++++++ 3 files changed, 148 insertions(+) create mode 100644 data/mocks/lists/FulfillmentOrderList.json create mode 100644 data/mocks/objects/FulfillmentOrder.json create mode 100644 test/Service/FulfillmentOrderServiceTest.php diff --git a/data/mocks/lists/FulfillmentOrderList.json b/data/mocks/lists/FulfillmentOrderList.json new file mode 100644 index 0000000..3f55de6 --- /dev/null +++ b/data/mocks/lists/FulfillmentOrderList.json @@ -0,0 +1,67 @@ +{ + "fulfillments": [ + { + "id": 255858046, + "order_id": 450789469, + "status": "failure", + "created_at": "2017-10-16T16:02:08-04:00", + "service": "manual", + "updated_at": "2017-10-16T16:02:08-04:00", + "tracking_company": null, + "shipment_status": null, + "tracking_number": "1Z2345", + "tracking_numbers": [ + "1Z2345" + ], + "tracking_url": "http:\/\/wwwapps.ups.com\/etracking\/tracking.cgi?InquiryNumber1=1Z2345&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track", + "tracking_urls": [ + "http:\/\/wwwapps.ups.com\/etracking\/tracking.cgi?InquiryNumber1=1Z2345&TypeOfInquiryNumber=T&AcceptUPSLicenseAgreement=yes&submit=Track" + ], + "receipt": { + "testcase": true, + "authorization": "123456" + }, + "line_items": [ + { + "id": 466157049, + "variant_id": 39072856, + "title": "IPod Nano - 8gb", + "quantity": 1, + "price": "199.00", + "grams": 200, + "sku": "IPOD2008GREEN", + "variant_title": "green", + "vendor": null, + "fulfillment_service": "manual", + "product_id": 632910392, + "requires_shipping": true, + "taxable": true, + "gift_card": false, + "name": "IPod Nano - 8gb - green", + "variant_inventory_management": "shopify", + "properties": [ + { + "name": "Custom Engraving Front", + "value": "Happy Birthday" + }, + { + "name": "Custom Engraving Back", + "value": "Merry Christmas" + } + ], + "product_exists": true, + "fulfillable_quantity": 1, + "total_discount": "0.00", + "fulfillment_status": null, + "tax_lines": [ + { + "title": "State Tax", + "price": "3.98", + "rate": 0.06 + } + ] + } + ] + } + ] +} diff --git a/data/mocks/objects/FulfillmentOrder.json b/data/mocks/objects/FulfillmentOrder.json new file mode 100644 index 0000000..4be36ef --- /dev/null +++ b/data/mocks/objects/FulfillmentOrder.json @@ -0,0 +1,52 @@ +{ + "fulfillment_order": { + "id": 1046000778, + "shop_id": 548380009, + "order_id": 450789469, + "assigned_location_id": 24826418, + "request_status": "submitted", + "status": "open", + "supported_actions": [ + "cancel_fulfillment_order" + ], + "destination": { + "id": 1046000778, + "address1": "Chestnut Street 92", + "address2": "", + "city": "Louisville", + "company": null, + "country": "United States", + "email": "bob.norman@mail.example.com", + "first_name": "Bob", + "last_name": "Norman", + "phone": "+1(502)-459-2181", + "province": "Kentucky", + "zip": "40202" + }, + "line_items": [ + { + "id": 1058737482, + "shop_id": 548380009, + "fulfillment_order_id": 1046000778, + "quantity": 1, + "line_item_id": 518995019, + "inventory_item_id": 49148385, + "fulfillable_quantity": 1, + "variant_id": 49148385 + } + ], + "fulfillment_service_handle": "mars-fulfillment", + "assigned_location": { + "address1": null, + "address2": null, + "city": null, + "country_code": "DE", + "location_id": 24826418, + "name": "Apple Api Shipwire", + "phone": null, + "province": null, + "zip": null + }, + "merchant_requests": [] + } +} \ No newline at end of file diff --git a/test/Service/FulfillmentOrderServiceTest.php b/test/Service/FulfillmentOrderServiceTest.php new file mode 100644 index 0000000..6f50358 --- /dev/null +++ b/test/Service/FulfillmentOrderServiceTest.php @@ -0,0 +1,29 @@ +getApiMock('lists/FulfillmentOrderList.json'); + $service = new FulfillmentOrderService($api); + $events = $service->all(1); + $this->assertContainsOnlyInstancesOf( + FulfillmentOrder::class, + $events + ); + } + + public function testGet() + { + $api = $this->getApiMock('objects/Event.json'); + $service = new FulfillmentOrderService($api); + $event = $service->get(1); + $this->assertInstanceOf(FulfillmentOrder::class, $event); + } +}