diff --git a/.gitignore b/.gitignore index 78b49ee..a8de2b9 100644 --- a/.gitignore +++ b/.gitignore @@ -229,3 +229,4 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +/.vs diff --git a/ShippingEasy.Console/Program.cs b/ShippingEasy.Console/Program.cs index b9fcb37..6f7cf3a 100644 --- a/ShippingEasy.Console/Program.cs +++ b/ShippingEasy.Console/Program.cs @@ -13,6 +13,8 @@ static void Main(string[] args) var apiKey = appSettings["ShippingEasy.ApiKey"]; var apiSecret = appSettings["ShippingEasy.ApiSecret"]; var baseUrl = appSettings["ShippingEasy.BaseUrl"]; + string orderId = "1111"; + try { var client = new Client(apiKey, apiSecret, baseUrl); @@ -20,9 +22,18 @@ static void Main(string[] args) const string storeApiKey = "c71dc6da574eea04e2c926906bcb4eab"; switch (command) { + case "STORES": + response = client.GetStores().HttpResponse; + break; + case "ORDERS_ID": + response = client.GetOrder(orderId).HttpResponse; + break; case "ORDERS": response = client.GetOrders().HttpResponse; break; + case "ORDERSBYNUMBER": + response = client.GetOrders(new OrderQuery() { OrderNumber = "1", Status = "ready_for_shipment,shipped" }).HttpResponse; + break; case "STORE_ORDERS": response = client.GetOrders(new OrderQuery { diff --git a/ShippingEasy/Client.cs b/ShippingEasy/Client.cs index 06763e5..bc8e472 100644 --- a/ShippingEasy/Client.cs +++ b/ShippingEasy/Client.cs @@ -62,6 +62,12 @@ public CancelOrderResponse CancelOrder(string storeApiKey, string externalOrderI return _responseHandler.Build(response); } + public StoreQueryResponse GetStores() + { + var response = Connection.GetAllStoresJson(); + return _responseHandler.Build(response); + } + /// /// Downloads orders from your ShippingEasy account /// @@ -76,6 +82,13 @@ public OrderQueryResponse GetOrders(OrderQuery query = null) return _responseHandler.Build(response); } + public OrderResponse GetOrder(string id) + { + var response = Connection.GetOrderJson(id); + return _responseHandler.Build(response); + + } + public static string OrderToJson(Order order) { return JsonConvert.SerializeObject(order, Formatting.Indented, Serialization.Settings); diff --git a/ShippingEasy/Connection.cs b/ShippingEasy/Connection.cs index 025ff13..256829c 100644 --- a/ShippingEasy/Connection.cs +++ b/ShippingEasy/Connection.cs @@ -75,12 +75,22 @@ public HttpResponse CreateOrderFromJson(string storeApiKey, string jsonBody) return MakeRequest("POST", String.Format("/api/stores/{0}/orders", storeApiKey), jsonBody); } + public HttpResponse GetAllStoresJson() + { + return MakeRequest("GET", String.Format("/api/stores")); + } + public HttpResponse CancelOrderJson(string storeApiKey, string externalOrderIdentifier) { return MakeRequest("POST", String.Format("/api/stores/{0}/orders/{1}/cancellations", storeApiKey, externalOrderIdentifier)); } - + + public HttpResponse GetOrderJson(string id) + { + return MakeRequest("GET", String.Format("/api/orders/{0}", id)); + } + /// /// A hook to override the method that takes a fully-constructed WebRequest and returns a response string /// diff --git a/ShippingEasy/Order.cs b/ShippingEasy/Order.cs index 059b844..69f568d 100644 --- a/ShippingEasy/Order.cs +++ b/ShippingEasy/Order.cs @@ -6,6 +6,12 @@ namespace ShippingEasy { public class Order { + public Order() + { + Shipments = new List(); + Tags = new List(); + } + private readonly List _recipients = new List(); /// @@ -59,6 +65,18 @@ public List Recipients public string BillingEmail { get; set; } [JsonProperty] public string StoreApiKey { get; private set; } + public List Shipments { get; set; } + public List Tags { get; set; } + public string Notes { get; set; } + [JsonProperty("custom_1")] + public string Custom1 { get; set; } + [JsonProperty("custom_2")] + public string Custom2 { get; set; } + [JsonProperty("custom_3")] + public string Custom3 { get; set; } + [JsonProperty("internal_notes")] + public string InternalNotes { get; set; } + } public class Recipient @@ -94,6 +112,10 @@ public class Recipient public string ShippingMethod { get; set; } public int? ItemsShipped { get; set; } public int? ExtShippingDetailId { get; set; } + [JsonProperty("internal_notes")] + public string InternalNotes { get; set; } + [JsonProperty("original_order")] + public OriginalOrder OriginalOrder { get; set; } } public class LineItem diff --git a/ShippingEasy/OrderQuery.cs b/ShippingEasy/OrderQuery.cs index 7e9606f..52e3e75 100644 --- a/ShippingEasy/OrderQuery.cs +++ b/ShippingEasy/OrderQuery.cs @@ -5,6 +5,11 @@ namespace ShippingEasy { public class OrderQuery { + /// + /// The external_order_identifier to search for + /// Search for sales by order number + /// + public string OrderNumber { get; set; } /// /// The status of the orders you would like to return. 'shipped' or 'ready_for_shipment' /// You can specify multiple states by separating with a comma. Ex: 'shipped,ready_for_shipment' @@ -45,7 +50,13 @@ public IDictionary ToDictionary() } if (LastUpdated.HasValue) { - options.Add("last_updated_at", LastUpdated.Value.ToString("O")); + options.Add("last_updated_at", LastUpdated.Value.ToString("u")); + } + + if(!String.IsNullOrEmpty(OrderNumber)) + { + options.Clear(); + options.Add("order_number", OrderNumber); } return options; } diff --git a/ShippingEasy/OrderResponse.cs b/ShippingEasy/OrderResponse.cs new file mode 100644 index 0000000..02052e4 --- /dev/null +++ b/ShippingEasy/OrderResponse.cs @@ -0,0 +1,14 @@ +using ShippingEasy.Responses; + +namespace ShippingEasy +{ + public class OrderResponse : ApiResponse + { + private readonly Order _order = new Order(); + + public Order Order + { + get { return _order; } + } + } +} diff --git a/ShippingEasy/OriginalOrder.cs b/ShippingEasy/OriginalOrder.cs new file mode 100644 index 0000000..1bafab5 --- /dev/null +++ b/ShippingEasy/OriginalOrder.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace ShippingEasy +{ + public class OriginalOrder + { + public OriginalOrder() + { + + } + + [JsonProperty("custom_1")] + public string Custom1 { get; set; } + [JsonProperty("custom_2")] + public string Custom2 { get; set; } + [JsonProperty("custom_3")] + public string Custom3 { get; set; } + [JsonProperty("internal_notes")] + public string InternalNotes { get; set; } + } +} diff --git a/ShippingEasy/Properties/AssemblyInfo.cs b/ShippingEasy/Properties/AssemblyInfo.cs index a637d14..391056e 100644 --- a/ShippingEasy/Properties/AssemblyInfo.cs +++ b/ShippingEasy/Properties/AssemblyInfo.cs @@ -16,8 +16,8 @@ [assembly: Guid("ea7b2ec4-35c4-4c63-b7cf-ab2a5591cc54")] // AssemblyVersion should be manually updated for an official release -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.0.1.0")] internal static class AssemblyInfo { diff --git a/ShippingEasy/Responses/StoreQueryResponse.cs b/ShippingEasy/Responses/StoreQueryResponse.cs new file mode 100644 index 0000000..ae48c8f --- /dev/null +++ b/ShippingEasy/Responses/StoreQueryResponse.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace ShippingEasy.Responses +{ + public class StoreQueryResponse : ApiResponse + { + private readonly IList _stores = new List(); + + public IList Stores + { + get { return _stores; } + } + } +} diff --git a/ShippingEasy/Shipment.cs b/ShippingEasy/Shipment.cs new file mode 100644 index 0000000..ed41024 --- /dev/null +++ b/ShippingEasy/Shipment.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; +using System; + +namespace ShippingEasy +{ + public class Shipment + { + public string ID { get; set; } + [JsonProperty("tracking_number")] + public string TrackingNumber { get; set; } + [JsonProperty("carrier_key")] + public string CarrierKey { get; set; } + [JsonProperty("carrier_service_key")] + public string CarrierServiceKey { get; set; } + [JsonProperty("shipment_cost")] + public decimal? ShipmentCost { get; set; } + [JsonProperty("ship_date")] + public DateTime? ShipDate { get; set; } + [JsonProperty("workflow_state")] + public string WorkflowState { get; set; } + [JsonProperty("cloned_from_shipment_id")] + public string ClonedFromShipmentID { get; set; } + [JsonProperty("weight_in_ounces")] + public decimal? WeightInOunches { get; set; } + [JsonProperty("length_in_ounces")] + public decimal? LengthInInches { get; set; } + [JsonProperty("width_in_ounces")] + public decimal? WidthInInches { get; set; } + [JsonProperty("height_in_ounces")] + public decimal? HeightInInches { get; set; } + + } +} diff --git a/ShippingEasy/ShippingEasy.csproj b/ShippingEasy/ShippingEasy.csproj index 4d983f2..bdefd96 100644 --- a/ShippingEasy/ShippingEasy.csproj +++ b/ShippingEasy/ShippingEasy.csproj @@ -42,7 +42,8 @@ - + + @@ -53,8 +54,11 @@ + + + diff --git a/ShippingEasy/ShippingEasy.nuspec b/ShippingEasy/ShippingEasy.nuspec index ea01b4b..53d2e63 100644 --- a/ShippingEasy/ShippingEasy.nuspec +++ b/ShippingEasy/ShippingEasy.nuspec @@ -12,6 +12,6 @@ false $description$ ShippingEasy API Client - Copyright 2015 + Copyright 2015-2020 \ No newline at end of file diff --git a/ShippingEasy/Store.cs b/ShippingEasy/Store.cs new file mode 100644 index 0000000..84f7e1e --- /dev/null +++ b/ShippingEasy/Store.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace ShippingEasy +{ + public class Store + { + [JsonProperty("api_key")] + public string ApiKey { get; set; } + public string Name { get; set; } + public string Type { get; set; } + public string Url { get; set; } + } +} diff --git a/Tests/ClientTests.cs b/Tests/ClientTests.cs index f520427..6990107 100644 --- a/Tests/ClientTests.cs +++ b/Tests/ClientTests.cs @@ -20,6 +20,19 @@ public void GetOrdersReturnsAListOfOrders() Assert.AreEqual("ABC-789", response.Orders[1].ExternalOrderIdentifier); } + [Test] + public void GetOrdersReturnsAListOfOrdersShipments() + { + var client = new Client(ResponseFromFile("get_orders_success_shipment")); + + var response = client.GetOrders(); + Assert.IsTrue(response.Success); + Assert.AreEqual(1, response.Orders.Count); + Assert.AreEqual("8888888888888888888888", response.Orders[0].Shipments[0].TrackingNumber); + Assert.AreEqual("internal order notes", response.Orders[0].Recipients[0].InternalNotes); + } + + [Test] public void GetOrdersReturnsCountAndPagingDetails() { diff --git a/Tests/OrderQueryTests.cs b/Tests/OrderQueryTests.cs index 7288bfe..1c9d1e7 100644 --- a/Tests/OrderQueryTests.cs +++ b/Tests/OrderQueryTests.cs @@ -10,10 +10,11 @@ public class OrderQueryTests [Test] public void BuildsDictionaryForPropertiesWithValues() { - var orderQuery = new OrderQuery {Page = 2, Status = "shipped"}; + var orderQuery = new OrderQuery {Page = 2, Status = "shipped", OrderNumber = "1"}; var options = orderQuery.ToDictionary(); Assert.That(options.Keys, Is.EquivalentTo(new[] { "page", "status" })); Assert.AreEqual("2", options["page"]); + Assert.AreEqual("1", options["order_number"]); Assert.AreEqual("shipped", options["status"]); } diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 999e19a..bdf6fc1 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -80,6 +80,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Tests/fixtures/get_orders_success_shipment.json b/Tests/fixtures/get_orders_success_shipment.json new file mode 100644 index 0000000..b6bb0f0 --- /dev/null +++ b/Tests/fixtures/get_orders_success_shipment.json @@ -0,0 +1,191 @@ +{ + "orders": [ + { + "id": 563661771, + "external_order_identifier": "4021863772942-1", + "ext_order_reference_id": "4021863772942-1", + "owner_id": null, + "sales_channel": null, + "fulfillment_channel": null, + "ordered_at": "2018-10-29T04:00:00Z", + "order_status": "shipped", + "parent_order_id": null, + "source_order_ids": null, + "total_including_tax": "100.63", + "total_excluding_tax": "95.00", + "discount_amount": "0.00", + "coupon_discount": "0.00", + "subtotal_including_tax": "106.25", + "subtotal_excluding_tax": "100.00", + "subtotal_tax": "0.00", + "total_tax": "5.63", + "base_shipping_cost": "0.00", + "shipping_cost_including_tax": "5.00", + "shipping_cost_excluding_tax": "5.00", + "shipping_cost_tax": "0.00", + "base_handling_cost": "0.00", + "handling_cost_excluding_tax": "0.00", + "handling_cost_including_tax": "0.00", + "handling_cost_tax": "0.00", + "base_wrapping_cost": "0.00", + "wrapping_cost_excluding_tax": "0.00", + "wrapping_cost_including_tax": "0.00", + "wrapping_cost_tax": "0.00", + "billing_company": "", + "billing_first_name": "Robin", + "billing_last_name": "Aboyoun", + "billing_address": "ABOYOUN & HELLER LLC", + "billing_address2": "77 US HIGHWAY 46", + "billing_city": "PINE", + "billing_state": "BROOK", + "billing_country": null, + "billing_postal_code": null, + "billing_phone_number": null, + "billing_email": "7vfydpd5c7g8jbz@marketplace.amazon.com", + "buyer_email": "7vfydpd5c7g8jbz@marketplace.amazon.com", + "recipients": [ + { + "company": "", + "first_name": "Robin", + "last_name": "Aboyoun", + "address": "77 US HIGHWAY 46", + "address2": "ABOYOUN & HELLER LLC", + "address3": null, + "city": "PINE BROOK", + "residential": false, + "state": "NJ", + "province": null, + "country": "United States", + "postal_code": "07058", + "postal_code_plus_4": "9609", + "phone_number": "", + "email": "", + "base_cost": "0.00", + "cost_excluding_tax": "0.00", + "cost_including_tax": "0.00", + "cost_tax": "0.00", + "base_handling_cost": "0.00", + "handling_cost_excluding_tax": "0.00", + "handling_cost_including_tax": "0.00", + "handling_cost_tax": "0.00", + "shipping_zone_id": null, + "shipping_zone_name": null, + "items_total": 0, + "shipping_method": "Shipping", + "items_shipped": 0, + "ext_shipping_detail_id": null, + "line_items": [ + { + "item_name": "sjobs", + "sku": "sjobs", + "bin_picking_number": null, + "bundled_product": null, + "weight_in_ounces": "0.0", + "quantity": 1, + "total_excluding_tax": "0.00", + "price_excluding_tax": "100.00", + "unit_price": "100.00", + "ext_line_item_id": null, + "ext_product_id": null, + "product_options": null, + "uuid": "84ad9ea5-fe09-464a-b59b-8e6ab7060da0", + "order_source_id": 644161401, + "gift_message": null + } + ], + "original_order": { + "id": 563661771, + "customer_id": 340631, + "store_id": 624091, + "order_detail_id": 564098621, + "workflow_state": "shipped", + "shipment_id": null, + "destination_id": null, + "split_from_order_id": null, + "total_weight_in_ounces": "0.0", + "total_quantity": 1, + "is_international": false, + "usps_shipping_zone": null, + "created_at": "2018-11-05T19:37:50Z", + "updated_at": "2018-11-06T15:40:56Z", + "ext_shipment_confirmation_id": null, + "store_order_status": "awaiting_shipment", + "drop_ship_tracking_number": null, + "category_id": null, + "internal_notes": "internal order notes", + "line_item_name": "sjobs", + "line_item_sku": "sjobs", + "address_kind": "C", + "recipient_last_name": "aboyoun", + "recipient_requested_service": "shipping", + "gift": false, + "prime_order_id": 563661771, + "state": "NJ", + "owner_id": null, + "denormalized_ordered_at": "2018-10-29T04:00:00Z", + "grab_bag": { + + }, + "line_item_bin_picking_number": null, + "denormalized_ext_order_id": "4021863772942-1", + "packing_slip_generated": null, + "denormalized_ext_order_reference_id": "4021863772942-1", + "denormalized_alternate_order_id": null, + "denormalized_sales_channel": null, + "custom_1": "1", + "custom_2": "2", + "custom_3": "3", + "hidden": null, + "allocated": null + } + } + ], + "store_api_key": "6e86e97d7a6e1bd113d220fd32b9fa39", + "shipments": [ + { + "id": 715071081, + "tracking_number": "8888888888888888888888", + "carrier_key": "USPS", + "carrier_service_key": "First", + "shipment_cost": 279, + "ship_date": "2018-11-06", + "workflow_state": "label_ready", + "cloned_from_shipment_id": null, + "weight_in_ounces": "5.0", + "length_in_inches": null, + "width_in_inches": null, + "height_in_inches": null, + "additional_packages": [ + + ] + } + ], + "updated_at": "2018-11-06T15:40:56Z", + "internal_notes": "internal order notes", + "meta_data": null, + "prime_order_id": 563661771, + "is_prime": null, + "split_from_order_id": null, + "tags": [ + "tag1", + "tag2" + ], + "notes": "Customer comment" + } + ], + "meta": { + "current_page": 1, + "next_page": null, + "prev_page": null, + "total_pages": 1, + "total_count": 1, + "last_updated_at": "2018-10-30T15:42:04Z", + "status": [ + "ready_for_shipment", + "shipped", + "pending_shipment", + "cleared" + ], + "order_number": "4021863772942-1" + } +} \ No newline at end of file