From 8a1f19e31947ae40e5a8333e8eca9bd6eca80f5f Mon Sep 17 00:00:00 2001 From: Dmitry Mamontov Date: Thu, 23 Jul 2015 13:37:17 +0300 Subject: [PATCH] new version && upload nuget --- README.md | 13 ++- RetailCrm/ApiClient.cs | 235 +++++++++++++++++++++++++++++++++++++---- lib/RetailCrm.dll | Bin 19456 -> 0 bytes 3 files changed, 229 insertions(+), 19 deletions(-) delete mode 100644 lib/RetailCrm.dll diff --git a/README.md b/README.md index 6a517a9..cc3b641 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,23 @@ ============================= .NET-клиент для работы с [RetailCRM API](http://www.retailcrm.ru/docs/rest-api/index.html). -version: 3.0.0 + +version: 3.0.2 Обязательные требования ----------------------- * [Newtonsoft.Json](http://james.newtonking.com/json) +Установка через NuGet +--------------------- + +Для начала требуется скачать и установить сам [NuGet](http://docs.nuget.org/consume/installing-nuget). + +После этого для установки клиента требуется запустить комманду в [Package Manager Console](http://docs.nuget.org/docs/start-here/using-the-package-manager-console) +``` bash +PM> Install-Package RetailCRM.ApiClient +``` + Примеры использования --------------------- diff --git a/RetailCrm/ApiClient.cs b/RetailCrm/ApiClient.cs index dce708a..12dda5c 100644 --- a/RetailCrm/ApiClient.cs +++ b/RetailCrm/ApiClient.cs @@ -55,8 +55,8 @@ namespace RetailCrm "/orders/create", Client.METHOD_POST, this.fillSite( - site, - new Dictionary() { + site, + new Dictionary() { { "order", JsonConvert.SerializeObject(order) } } ) @@ -90,7 +90,7 @@ namespace RetailCrm Client.METHOD_POST, this.fillSite( site, - new Dictionary() { + new Dictionary() { { "order", JsonConvert.SerializeObject(order) }, { "by", by } } @@ -116,7 +116,7 @@ namespace RetailCrm Client.METHOD_POST, this.fillSite( site, - new Dictionary() { + new Dictionary() { { "orders", JsonConvert.SerializeObject(orders) } } ) @@ -277,7 +277,7 @@ namespace RetailCrm Client.METHOD_POST, this.fillSite( site, - new Dictionary() { + new Dictionary() { { "customer", JsonConvert.SerializeObject(customer) } } ) @@ -311,7 +311,7 @@ namespace RetailCrm Client.METHOD_POST, this.fillSite( site, - new Dictionary() { + new Dictionary() { { "customer", JsonConvert.SerializeObject(customer) }, { "by", by } } @@ -337,7 +337,7 @@ namespace RetailCrm Client.METHOD_POST, this.fillSite( site, - new Dictionary() { + new Dictionary() { { "customers", JsonConvert.SerializeObject(customers) } } ) @@ -414,6 +414,175 @@ namespace RetailCrm ); } + /// + /// Returns filtered orders packs list + /// + /// + /// + /// + /// ApiResponse + public ApiResponse packsList(Dictionary filter = null, int page = 0, int limit = 0) + { + Dictionary parameters = new Dictionary(); + + if (filter.Count > 0) + { + parameters.Add("filter", filter); + } + if (page > 0) + { + parameters.Add("page", page); + } + if (limit > 0) + { + parameters.Add("limit", limit); + } + + return client.makeRequest("/orders/packs", Client.METHOD_GET, parameters); + } + + /// + /// Create a order pack + /// + /// + /// ApiResponse + public ApiResponse packsCreate(Dictionary pack) + { + if (pack.Count < 1) + { + throw new ArgumentException("Parameter `pack` must contains a data"); + } + + return client.makeRequest( + "/orders/packs/create", + Client.METHOD_POST, + new Dictionary() { + { "pack", JsonConvert.SerializeObject(pack) } + } + ); + } + + /// + /// Returns a orders history + /// + /// + /// + /// + /// ApiResponse + public ApiResponse packsHistory(Dictionary filter = null, int page = 0, int limit = 0) + { + Dictionary parameters = new Dictionary(); + + if (filter.Count > 0) + { + parameters.Add("filter", filter); + } + if (page > 0) + { + parameters.Add("page", page); + } + if (limit > 0) + { + parameters.Add("limit", limit); + } + + return client.makeRequest("/orders/packs/history", Client.METHOD_GET, parameters); + } + + /// + /// Get order packs by id + /// + /// + /// ApiResponse + public ApiResponse packsGet(string id) + { + return client.makeRequest("/orders/packs/" + id, Client.METHOD_GET); + } + + /// + /// Delete order packs by id + /// + /// + /// ApiResponse + public ApiResponse packsDelete(string id) + { + return client.makeRequest("/orders/packs/" + id + "/delete", Client.METHOD_POST); + } + + /// + /// Edit a order packs + /// + /// + /// + /// ApiResponse + public ApiResponse packsEdit(string id, Dictionary pack) + { + if (pack.Count < 1) + { + throw new ArgumentException("Parameter `pack` must contains a data"); + } + + return client.makeRequest( + "/orders/packs/" + id + "/edit", + Client.METHOD_POST, + new Dictionary() { + { "pack", JsonConvert.SerializeObject(pack) } + } + ); + } + + /// + /// Returns filtered store inventories list + /// + /// + /// + /// + /// ApiResponse + public ApiResponse inventoriesList(Dictionary filter = null, int page = 0, int limit = 0) + { + Dictionary parameters = new Dictionary(); + + if (filter.Count > 0) + { + parameters.Add("filter", filter); + } + if (page > 0) + { + parameters.Add("page", page); + } + if (limit > 0) + { + parameters.Add("limit", limit); + } + + return client.makeRequest("/store/inventories", Client.METHOD_GET, parameters); + } + + /// + /// Upload array of the store inventories + /// + /// + /// + /// ApiResponse + public ApiResponse inventoriesUpload(Dictionary offers, string site = "") + { + if (offers.Count < 1) + { + throw new ArgumentException("Parameter `offers` must contains a data"); + } + + return client.makeRequest( + "/store/inventories/upload", + Client.METHOD_POST, + this.fillSite( + site, + new Dictionary() { + { "offers", JsonConvert.SerializeObject(offers) } + } + ) + ); + } + /// /// Returns deliveryServices list /// @@ -504,6 +673,15 @@ namespace RetailCrm return client.makeRequest("/reference/sites", Client.METHOD_GET); } + /// + /// Returns stores list + /// + /// ApiResponse + public ApiResponse storesList() + { + return client.makeRequest("/reference/stores", Client.METHOD_GET); + } + /// /// Edit deliveryService /// @@ -519,7 +697,7 @@ namespace RetailCrm return client.makeRequest( "/reference/delivery-services/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "deliveryService", JsonConvert.SerializeObject(data) } } ); @@ -540,7 +718,7 @@ namespace RetailCrm return client.makeRequest( "/reference/delivery-types/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "deliveryType", JsonConvert.SerializeObject(data) } } ); @@ -561,7 +739,7 @@ namespace RetailCrm return client.makeRequest( "/reference/order-methods/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "orderMethod", JsonConvert.SerializeObject(data) } } ); @@ -582,7 +760,7 @@ namespace RetailCrm return client.makeRequest( "/reference/order-types/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "orderType", JsonConvert.SerializeObject(data) } } ); @@ -603,7 +781,7 @@ namespace RetailCrm return client.makeRequest( "/reference/payment-statuses/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "paymentStatus", JsonConvert.SerializeObject(data) } } ); @@ -624,7 +802,7 @@ namespace RetailCrm return client.makeRequest( "/reference/payment-types/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "paymentType", JsonConvert.SerializeObject(data) } } ); @@ -645,7 +823,7 @@ namespace RetailCrm return client.makeRequest( "/reference/product-statuses/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "productStatus", JsonConvert.SerializeObject(data) } } ); @@ -666,7 +844,7 @@ namespace RetailCrm return client.makeRequest( "/reference/statuses/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "status", JsonConvert.SerializeObject(data) } } ); @@ -687,12 +865,33 @@ namespace RetailCrm return client.makeRequest( "/reference/sites/" + data["code"] + "/edit", Client.METHOD_POST, - new Dictionary() { + new Dictionary() { { "site", JsonConvert.SerializeObject(data) } } ); } + /// + /// Edit stores + /// + /// + /// ApiResponse + public ApiResponse storesEdit(Dictionary store) + { + if (store.ContainsKey("code") == false) + { + throw new ArgumentException("Data must contain \"code\" parameter"); + } + + return client.makeRequest( + "/reference/stores/" + store["code"] + "/edit", + Client.METHOD_POST, + new Dictionary() { + { "store", JsonConvert.SerializeObject(store) } + } + ); + } + /// /// Update CRM basic statistic /// @@ -725,7 +924,7 @@ namespace RetailCrm /// protected void checkIdParameter(string by) { - string[] allowedForBy = new string[]{"externalId", "id"}; + string[] allowedForBy = new string[] { "externalId", "id" }; if (allowedForBy.Contains(by) == false) { throw new ArgumentException("Value \"" + by + "\" for parameter \"by\" is not valid. Allowed values are " + String.Join(", ", allowedForBy)); @@ -743,7 +942,7 @@ namespace RetailCrm if (site.Length > 1) { param.Add("site", site); - } + } else if (siteCode.Length > 1) { param.Add("site", siteCode); diff --git a/lib/RetailCrm.dll b/lib/RetailCrm.dll deleted file mode 100644 index 147cbaad32b446904e2fdd9a374d8999ad269582..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19456 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