diff --git a/Nop.Plugin.Api.Client/App.config b/Nop.Plugin.Api.Client/App.config new file mode 100644 index 0000000..62c8f44 --- /dev/null +++ b/Nop.Plugin.Api.Client/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/Nop.Plugin.Api.Client/Clients/BaseRestClient.cs b/Nop.Plugin.Api.Client/Clients/BaseRestClient.cs new file mode 100644 index 0000000..eba5b18 --- /dev/null +++ b/Nop.Plugin.Api.Client/Clients/BaseRestClient.cs @@ -0,0 +1,217 @@ +using System; +using System.Globalization; +using System.Net; +using System.Text; +using Nop.Plugin.Api.Client.Exceptions; +using Nop.Plugin.Api.Client.Security; +using Nop.Plugin.Api.Client.Serialization; +using Polly; +using RestSharp; +using RestSharp.Authenticators; +using RestSharp.Deserializers; +using RestSharp.Extensions; +using RestSharp.Serializers; + +namespace Nop.Plugin.Api.Client.Clients +{ + public abstract class BaseRestClient + { + private readonly NopApiClient _parent; + + private const int DefaultRetryAttempts = 10; + + private const int DefaultDelayBetweenRetryAttemptsInMs = 250; + + private Token _currentToken; + + private IDeserializer _deserializer; + + private ISerializer _serializer; + + + protected BaseRestClient(NopApiClient parent) + { + _parent = parent; + } + + protected RestRequest GetRequest(string resource, Method method = Method.GET) + { + return new RestRequest(resource, method) { RequestFormat = DataFormat.Json }; + } + + protected IRestResponse Execute( + IRestRequest request, + bool throwIfError = true, + int retryAttempts = DefaultRetryAttempts, + int waitTimeBetweenAttempts = DefaultDelayBetweenRetryAttemptsInMs) + where T : new() + { + InitRequest(request); + + var policy = GetPolicy>(retryAttempts, waitTimeBetweenAttempts); + + return policy.Execute( + () => + { + var response = GetClient().Execute(request); + + if (throwIfError) + { + Process(request, response); + } + + return response; + }); + } + + protected ISerializer Serializer + { + get => _serializer ?? (_serializer = new NewtonsoftSerializer()); + + set => _serializer = value; + } + + protected IDeserializer Deserializer + { + get => _deserializer ?? (_deserializer = new NewtonsoftSerializer()); + + set => _deserializer = value; + } + + private void Process(IRestRequest request, IRestResponse response) + { + if (response.ResponseStatus == ResponseStatus.Error && response.ErrorException != null) + { + // This is likely a transport issue such as the underlying connection was closed + throw new NopApiClientException( + $"Request to {request.Method}:{response.ResponseUri} {response.StatusCode} failed with exception", + true); + } + + if (response.ResponseStatus == ResponseStatus.Error) + { + throw new NopApiClientException( + $"Failed to connect to REST API {request.Resource}, status: {response.StatusCode}", + true); + } + + ThrowErrorIfAny(response); + } + + protected bool HasError(IRestResponse response) + { + if (response?.Request == null) + { + return false; + } + + return response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Accepted + && response.StatusCode != HttpStatusCode.Created + && response.StatusCode != HttpStatusCode.Continue + && response.StatusCode != HttpStatusCode.NoContent; + } + + protected void ThrowErrorIfAny(IRestResponse response, string message = null) + { + if (response?.Request == null) + { + throw new NopApiClientException("null response"); + } + + if (HasError(response)) + { + NopApiClientExceptionDetails exceptionDetails = null; + + if (response.Request.RequestFormat == DataFormat.Json) + { + if (!JsonSerializationUtility.TryDeserialize(response.Content, out exceptionDetails)) + { + if (exceptionDetails == null && response.ErrorException != null) + { + exceptionDetails = new NopApiClientExceptionDetails + { + Message = response.ErrorException.Message, + ExceptionType = response.ErrorException.GetType().Name, + //ExceptionMessage = response.ErrorException.Message, + StackTrace = response.ErrorException.StackTrace + }; + } + } + } + + throw new NopApiClientException( + response.StatusCode, + response.ResponseUri != null ? response.ResponseUri.ToString() : string.Empty, + response.Request.Method.ToString(), + message, + exceptionDetails); + } + + if (response.ErrorException != null) + { + throw new NopApiClientException( + response.StatusCode, + response.ResponseUri != null ? response.ResponseUri.ToString() : string.Empty, + response.Request.Method.ToString(), + response.ErrorException); + } + } + + private RestClient GetClient() + { + var client = new RestClient(_parent.ServerUrl); + + ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; + + // Override with Newtonsoft JSON Handler + client.AddHandler("application/json", Deserializer); + client.AddHandler("text/json", Deserializer); + client.AddHandler("text/x-json", Deserializer); + client.AddHandler("text/javascript", Deserializer); + client.AddHandler("*+json", Deserializer); + + client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator( + CurrentToken.AccessToken, + CurrentToken.TokenType); + + return client; + } + + protected Token CurrentToken => _currentToken ?? (_currentToken = GetToken()); + + private Token GetToken() + { + var client = new TokenClient(new Uri(_parent.ServerUrl)); + + return client.GetToken(_parent.ClientId, _parent.Secret); + } + + private void InitRequest(IRestRequest request) + { + request.OnBeforeDeserialization = resp => + { + // for individual resources when there's an error to make + // sure that RestException props are populated + if ((int)resp.StatusCode >= 400) + { + // have to read the bytes so .Content doesn't get populated + const string restException = "{{ \"RestException\" : {0} }}"; + var content = resp.RawBytes.AsString(); //get the response content + var newJson = string.Format(restException, content); + + resp.Content = null; + resp.RawBytes = Encoding.UTF8.GetBytes(newJson.ToString(CultureInfo.InvariantCulture)); + } + }; + } + + private static Policy GetPolicy(int retryAttempts, int waitTimeBetweenAttempts) + { + return Policy.Handle(ex => ex.CanRetry).WaitAndRetry( + retryAttempts, + attempt => TimeSpan.FromMilliseconds(waitTimeBetweenAttempts)); + } + } +} + + diff --git a/Nop.Plugin.Api.Client/Clients/OrdersClient.cs b/Nop.Plugin.Api.Client/Clients/OrdersClient.cs new file mode 100644 index 0000000..cd36db5 --- /dev/null +++ b/Nop.Plugin.Api.Client/Clients/OrdersClient.cs @@ -0,0 +1,73 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Lindell Technologies All Rights Reserved. +// Information Contained Herein is Proprietary and Confidential. +// +// ----------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Nop.Plugin.Api.Client.DTOs.Orders; + +namespace Nop.Plugin.Api.Client.Clients +{ + public class OrdersClient : BaseRestClient + { + internal OrdersClient(NopApiClient parent) : base(parent) + { + } + + public IList GetOrders(int sinceId = 0, DateTime? createdAtMin = null, DateTime? createdAtMax = null, int? customerId = null, int page = 1, int limit = 50) + { + var request = GetRequest("api/orders"); + + + if (sinceId > 0) + { + request.AddQueryParameter("sinceId", sinceId.ToString()); + } + + if (createdAtMin.HasValue) + { + request.AddQueryParameter("createdAtMin", createdAtMin.Value.ToString(CultureInfo.InvariantCulture)); + } + + if (createdAtMax.HasValue) + { + request.AddQueryParameter("createdAtMax", createdAtMax.Value.ToString(CultureInfo.InvariantCulture)); + } + + if (customerId.GetValueOrDefault() > 0) + { + request.AddQueryParameter("customerId", customerId.GetValueOrDefault().ToString()); + } + + if (page > 0) + { + request.AddQueryParameter("page", page.ToString()); + } + + if (limit > 0) + { + request.AddQueryParameter("limit", Math.Min(250, limit).ToString()); + } + + + return Execute(request).Data.Orders; + } + + public IList GetOrders(IEnumerable ids) + { + var request = GetRequest("api/orders"); + + if (ids != null) + { + request.AddQueryParameter("ids", string.Join(",", ids.Select(s => s.ToString()))); + } + + return Execute(request).Data.Orders; + } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/AddressDto.cs b/Nop.Plugin.Api.Client/DTOs/AddressDto.cs new file mode 100644 index 0000000..1fb8600 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/AddressDto.cs @@ -0,0 +1,80 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs +{ + [JsonObject(Title = "address")] + public class AddressDto + { + /// + /// Gets or sets the first name + /// + [JsonProperty("first_name")] + public string FirstName { get; set; } + + /// + /// Gets or sets the last name + /// + [JsonProperty("last_name")] + public string LastName { get; set; } + + /// + /// Gets or sets the email + /// + [JsonProperty("email")] + public string Email { get; set; } + + /// + /// Gets or sets the company + /// + [JsonProperty("company")] + public string Company { get; set; } + + /// + /// Gets or sets the country name + /// + [JsonProperty("country")] + public string CountryName { get; set; } + + /// + /// Gets or sets the city + /// + [JsonProperty("city")] + public string City { get; set; } + + /// + /// Gets or sets the address 1 + /// + [JsonProperty("address1")] + public string Address1 { get; set; } + + /// + /// Gets or sets the address 2 + /// + [JsonProperty("address2")] + public string Address2 { get; set; } + + /// + /// Gets or sets the zip/postal code + /// + [JsonProperty("zip_postal_code")] + public string ZipPostalCode { get; set; } + + /// + /// Gets or sets the phone number + /// + [JsonProperty("phone_number")] + public string PhoneNumber { get; set; } + + /// + /// Gets or sets the fax number + /// + [JsonProperty("fax_number")] + public string FaxNumber { get; set; } + + /// + /// Gets or sets the state/province + /// + [JsonProperty("province")] + public string StateProvinceName { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Categories/CategoriesCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Categories/CategoriesCountRootObject.cs new file mode 100644 index 0000000..408053e --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Categories/CategoriesCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Categories +{ + public class CategoriesCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Categories/CategoriesRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Categories/CategoriesRootObject.cs new file mode 100644 index 0000000..ddd4ba8 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Categories/CategoriesRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Categories +{ + public class CategoriesRootObject + { + public CategoriesRootObject() + { + Categories = new List(); + } + + [JsonProperty("categories")] + public IList Categories { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Categories/CategoryDto.cs b/Nop.Plugin.Api.Client/DTOs/Categories/CategoryDto.cs new file mode 100644 index 0000000..6bae5df --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Categories/CategoryDto.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.Images; +using Nop.Plugin.Api.Client.DTOs.Languages; + +namespace Nop.Plugin.Api.Client.DTOs.Categories +{ + [JsonObject(Title = "category")] + public class CategoryDto + { + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the localized names + /// + [JsonProperty("localized_names")] + public List LocalizedNames { get; set; } + + /// + /// Gets or sets the description + /// + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Gets or sets a value of used category template identifier + /// + [JsonProperty("category_template_id")] + public int? CategoryTemplateId { get; set; } + + /// + /// Gets or sets the meta keywords + /// + [JsonProperty("meta_keywords")] + public string MetaKeywords { get; set; } + + /// + /// Gets or sets the meta description + /// + [JsonProperty("meta_description")] + public string MetaDescription { get; set; } + + /// + /// Gets or sets the meta title + /// + [JsonProperty("meta_title")] + public string MetaTitle { get; set; } + + /// + /// Gets or sets the parent category identifier + /// + [JsonProperty("parent_category_id")] + public int? ParentCategoryId { get; set; } + + /// + /// Gets or sets the page size + /// + [JsonProperty("page_size")] + public int? PageSize { get; set; } + + /// + /// Gets or sets the available customer selectable page size options + /// + [JsonProperty("page_size_options")] + public string PageSizeOptions { get; set; } + + /// + /// Gets or sets the available price ranges + /// + [JsonProperty("price_ranges")] + public string PriceRanges { get; set; } + + /// + /// Gets or sets a value indicating whether to show the category on home page + /// + [JsonProperty("show_on_home_page")] + public bool? ShowOnHomePage { get; set; } + + /// + /// Gets or sets a value indicating whether to include this category in the top menu + /// + [JsonProperty("include_in_top_menu")] + public bool? IncludeInTopMenu { get; set; } + + /// + /// Gets or sets a value indicating whether this category has discounts applied + /// The same as if we run category.AppliedDiscounts.Count > 0 + /// We use this property for performance optimization: + /// if this property is set to false, then we do not need to load Applied Discounts navigation property + /// + /// + [JsonProperty("has_discounts_applied")] + public bool? HasDiscountsApplied { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is published + /// + [JsonProperty("published")] + public bool? Published { get; set; } + + /// + /// Gets or sets a value indicating whether the entity has been deleted + /// + [JsonProperty("deleted")] + public bool? Deleted { get; set; } + + /// + /// Gets or sets the display order + /// + [JsonProperty("display_order")] + public int? DisplayOrder { get; set; } + + /// + /// Gets or sets the date and time of instance creation + /// + [JsonProperty("created_on_utc")] + public DateTime? CreatedOnUtc { get; set; } + + /// + /// Gets or sets the date and time of instance update + /// + [JsonProperty("updated_on_utc")] + public DateTime? UpdatedOnUtc { get; set; } + + [JsonProperty("role_ids")] + public List RoleIds { get; set; } + + [JsonProperty("discount_ids")] + public List DiscountIds { get; set; } + + [JsonProperty("store_ids")] + public List StoreIds { get; set; } + + [JsonProperty("image")] + public ImageDto Image { get; set; } + + [JsonProperty("se_name")] + public string SeName { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/CustomerRoles/CustomerRoleDto.cs b/Nop.Plugin.Api.Client/DTOs/CustomerRoles/CustomerRoleDto.cs new file mode 100644 index 0000000..d1670aa --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/CustomerRoles/CustomerRoleDto.cs @@ -0,0 +1,64 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.CustomerRoles +{ + [JsonObject(Title = "customer_role")] + public class CustomerRoleDto + { + /// + /// Gets or sets the store ID + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the customer role name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets a value indicating whether the customer role is marked as free shiping + /// + [JsonProperty("free_shipping")] + public bool? FreeShipping { get; set; } + + /// + /// Gets or sets a value indicating whether the customer role is marked as tax exempt + /// + [JsonProperty("tax_exempt")] + + public bool? TaxExempt { get; set; } + + /// + /// Gets or sets a value indicating whether the customer role is active + /// + [JsonProperty("active")] + public bool? Active { get; set; } + + /// + /// Gets or sets a value indicating whether the customer role is system + /// + [JsonProperty("is_system_role")] + public bool? IsSystemRole { get; set; } + + /// + /// Gets or sets the customer role system name + /// + [JsonProperty("system_name")] + public string SystemName { get; set; } + + /// + /// Gets or sets a value indicating whether the customers must change passwords after a specified time + /// + [JsonProperty("enable_password_lifetime")] + public bool? EnablePasswordLifetime { get; set; } + + /// + /// Gets or sets a product identifier that is required by this customer role. + /// A customer is added to this customer role once a specified product is purchased. + /// + [JsonProperty("purchased_with_product_id")] + public int? PurchasedWithProductId { get; set; } + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/CustomerRoles/CustomerRolesRootObject.cs b/Nop.Plugin.Api.Client/DTOs/CustomerRoles/CustomerRolesRootObject.cs new file mode 100644 index 0000000..5f2c46f --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/CustomerRoles/CustomerRolesRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.CustomerRoles +{ + public class CustomerRolesRootObject + { + public CustomerRolesRootObject() + { + CustomerRoles = new List(); + } + + [JsonProperty("customer_roles")] + public IList CustomerRoles { get; set; } + + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Customers/BaseCustomerDto.cs b/Nop.Plugin.Api.Client/DTOs/Customers/BaseCustomerDto.cs new file mode 100644 index 0000000..81bd9b3 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Customers/BaseCustomerDto.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Customers +{ + public class BaseCustomerDto + { + private List _roleIds; + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("username")] + public string Username { get; set; } + /// + /// Gets or sets the email + /// + [JsonProperty("email")] + public string Email { get; set; } + + [JsonProperty("first_name")] + public string FirstName { get; set; } + + [JsonProperty("last_name")] + public string LastName { get; set; } + + [JsonProperty("language_id")] + public string LanguageId { get; set; } + + [JsonProperty("date_of_birth")] + public DateTime? DateOfBirth { get; set; } + + [JsonProperty("gender")] + public string Gender { get; set; } + + /// + /// Gets or sets the admin comment + /// + [JsonProperty("admin_comment")] + public string AdminComment { get; set; } + + /// + /// Gets or sets a value indicating whether the customer is tax exempt + /// + [JsonProperty("is_tax_exempt")] + public bool? IsTaxExempt { get; set; } + + /// + /// Gets or sets a value indicating whether this customer has some products in the shopping cart + /// The same as if we run this.ShoppingCartItems.Count > 0 + /// We use this property for performance optimization: + /// if this property is set to false, then we do not need to load "ShoppingCartItems" navigation property for each page load + /// It's used only in a couple of places in the presentation layer + /// + /// + [JsonProperty("has_shopping_cart_items")] + public bool? HasShoppingCartItems { get; set; } + + /// + /// Gets or sets a value indicating whether the customer is active + /// + [JsonProperty("active")] + public bool? Active { get; set; } + + /// + /// Gets or sets a value indicating whether the customer has been deleted + /// + [JsonProperty("deleted")] + public bool? Deleted { get; set; } + + /// + /// Gets or sets a value indicating whether the customer account is system + /// + [JsonProperty("is_system_account")] + public bool? IsSystemAccount { get; set; } + + /// + /// Gets or sets the customer system name + /// + [JsonProperty("system_name")] + public string SystemName { get; set; } + + /// + /// Gets or sets the last IP address + /// + [JsonProperty("last_ip_address")] + public string LastIpAddress { get; set; } + + /// + /// Gets or sets the date and time of entity creation + /// + [JsonProperty("created_on_utc")] + public DateTime? CreatedOnUtc { get; set; } + + /// + /// Gets or sets the date and time of last login + /// + [JsonProperty("last_login_date_utc")] + public DateTime? LastLoginDateUtc { get; set; } + + /// + /// Gets or sets the date and time of last activity + /// + [JsonProperty("last_activity_date_utc")] + public DateTime? LastActivityDateUtc { get; set; } + + /// + /// Gets or sets the store identifier in which customer registered + /// + [JsonProperty("registered_in_store_id")] + public int? RegisteredInStoreId { get; set; } + + /// + /// Gets or sets the subscribed to newsletter property + /// + [JsonProperty("subscribed_to_newsletter")] + public bool SubscribedToNewsletter { get; set; } + + [JsonProperty("role_ids")] + public List RoleIds + { + get => _roleIds ?? (_roleIds = new List()); + set => _roleIds = value; + } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Customers/CustomerDto.cs b/Nop.Plugin.Api.Client/DTOs/Customers/CustomerDto.cs new file mode 100644 index 0000000..de7bf1f --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Customers/CustomerDto.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.ShoppingCarts; + +namespace Nop.Plugin.Api.Client.DTOs.Customers +{ + [JsonObject(Title = "customer")] + public class CustomerDto : BaseCustomerDto + { + private ICollection _shoppingCartItems; + private ICollection _addresses; + + [JsonIgnore] + [JsonProperty("password")] + public string Password { get; set; } + + #region Navigation properties + + /// + /// Gets or sets shopping cart items + /// + [JsonProperty("shopping_cart_items")] + public ICollection ShoppingCartItems + { + get => _shoppingCartItems ?? (_shoppingCartItems = new List()); + set => _shoppingCartItems = value; + } + + /// + /// Default billing address + /// + [JsonProperty("billing_address")] + public AddressDto BillingAddress { get; set; } + + /// + /// Default shipping address + /// + [JsonProperty("shipping_address")] + public AddressDto ShippingAddress { get; set; } + + /// + /// Gets or sets customer addresses + /// + [JsonProperty("addresses")] + public ICollection CustomerAddresses + { + get + { + if (_addresses == null) + { + _addresses = new List(); + } + + return _addresses; + } + set => _addresses = value; + } + #endregion + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Customers/CustomerForShoppingCartItemDto.cs b/Nop.Plugin.Api.Client/DTOs/Customers/CustomerForShoppingCartItemDto.cs new file mode 100644 index 0000000..f37275a --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Customers/CustomerForShoppingCartItemDto.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Customers +{ + // We need this DTO object to avoid loop in the entity to dto mappings. The difference is the missing ShoppingCartItems collection. + [JsonObject(Title = "customers")] + public class CustomerForShoppingCartItemDto : BaseCustomerDto + { + #region Navigation properties + + /// + /// Default billing address + /// + [JsonProperty("billing_address")] + public AddressDto BillingAddress { get; set; } + + /// + /// Default shipping address + /// + [JsonProperty("shipping_address")] + public AddressDto ShippingAddress { get; set; } + + /// + /// Gets or sets customer addresses + /// + [JsonProperty("addresses")] + public ICollection Addresses { get; set; } + + #endregion + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Customers/CustomersCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Customers/CustomersCountRootObject.cs new file mode 100644 index 0000000..3e027a9 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Customers/CustomersCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Customers +{ + public class CustomersCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Customers/CustomersRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Customers/CustomersRootObject.cs new file mode 100644 index 0000000..7ba6248 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Customers/CustomersRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Customers +{ + public class CustomersRootObject + { + public CustomersRootObject() + { + Customers = new List(); + } + + [JsonProperty("customers")] + public IList Customers { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Customers/OrderCustomerDto.cs b/Nop.Plugin.Api.Client/DTOs/Customers/OrderCustomerDto.cs new file mode 100644 index 0000000..246ee9a --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Customers/OrderCustomerDto.cs @@ -0,0 +1,7 @@ +namespace Nop.Plugin.Api.Client.DTOs.Customers +{ + public class OrderCustomerDto : BaseCustomerDto + { + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Errors/ErrorsRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Errors/ErrorsRootObject.cs new file mode 100644 index 0000000..93e66da --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Errors/ErrorsRootObject.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Errors +{ + public class ErrorsRootObject + { + [JsonProperty("errors")] + public Dictionary> Errors { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Images/ImageDto.cs b/Nop.Plugin.Api.Client/DTOs/Images/ImageDto.cs new file mode 100644 index 0000000..4a1ac68 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Images/ImageDto.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Images +{ + public class ImageDto + { + [JsonProperty("src")] + public string Src { get; set; } + + [JsonProperty("attachment")] + public string Attachment { get; set; } + + [JsonIgnore] + public byte[] Binary { get; set; } + + [JsonIgnore] + public string MimeType { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Images/ImageMappingDto.cs b/Nop.Plugin.Api.Client/DTOs/Images/ImageMappingDto.cs new file mode 100644 index 0000000..48c74b6 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Images/ImageMappingDto.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Images +{ + public class ImageMappingDto : ImageDto + { + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("position")] + public int Position { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Languages/LanguageDto.cs b/Nop.Plugin.Api.Client/DTOs/Languages/LanguageDto.cs new file mode 100644 index 0000000..982d2b9 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Languages/LanguageDto.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Languages +{ + [JsonObject(Title = "language")] + public class LanguageDto + { + /// + /// Gets or sets the store ID + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the language culture + /// + [JsonProperty("language_culture")] + public string LanguageCulture { get; set; } + + /// + /// Gets or sets the unique SEO code + /// + [JsonProperty("unique_seo_code")] + public string UniqueSeoCode { get; set; } + + /// + /// Gets or sets the flag image file name + /// + [JsonProperty("flag_image_file_name")] + public string FlagImageFileName { get; set; } + + /// + /// Gets or sets a value indicating whether the language supports "Right-to-left" + /// + [JsonProperty("rtl")] + public bool? Rtl { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is limited/restricted to certain stores + /// + [JsonProperty("limited_to_stores")] + public bool? LimitedToStores { get; set; } + + /// + /// Gets or sets the identifier of the default currency for this language; 0 is set when we use the default currency display order + /// + [JsonProperty("default_currency_id")] + public int? DefaultCurrencyId { get; set; } + + /// + /// Gets or sets a value indicating whether the language is published + /// + [JsonProperty("published")] + public bool? Published { get; set; } + + /// + /// Gets or sets the display order + /// + [JsonProperty("display_order")] + public int? DisplayOrder { get; set; } + + /// + /// Gets or sets the store ids in which the language is enabled + /// + [JsonProperty("store_ids")] + public List StoreIds { get; set; } + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Languages/LanguagesRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Languages/LanguagesRootObject.cs new file mode 100644 index 0000000..09109ca --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Languages/LanguagesRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Languages +{ + public class LanguagesRootObject + { + public LanguagesRootObject() + { + Languages = new List(); + } + + [JsonProperty("languages")] + public IList Languages { get; set; } + + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Languages/LocalizedNameDto.cs b/Nop.Plugin.Api.Client/DTOs/Languages/LocalizedNameDto.cs new file mode 100644 index 0000000..9ad7e22 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Languages/LocalizedNameDto.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Languages +{ + public class LocalizedNameDto + { + /// + /// Gets or sets the language identifier + /// + [JsonProperty("language_id")] + public int? LanguageId { get; set; } + + /// + /// Gets or sets the localized name + /// + [JsonProperty("localized_name")] + public string LocalizedName { get; set; } + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/NewsLetterSubscriptions/NewsLetterSubscriptionDto.cs b/Nop.Plugin.Api.Client/DTOs/NewsLetterSubscriptions/NewsLetterSubscriptionDto.cs new file mode 100644 index 0000000..1a5710b --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/NewsLetterSubscriptions/NewsLetterSubscriptionDto.cs @@ -0,0 +1,39 @@ +using System; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.NewsLetterSubscriptions +{ + [JsonObject(Title = "news_letter_subscription")] + public class NewsLetterSubscriptionDto + { + /// + /// Gets or sets the id + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the email + /// + [JsonProperty("email")] + public string Email { get; set; } + + /// + /// Gets or sets whether the subscription is active + /// + [JsonProperty("active")] + public bool Active { get; set; } + + /// + /// Gets or sets whether the subscription is active + /// + [JsonProperty("store_id")] + public int StoreId { get; set; } + + /// + /// Gets or sets created on utc date + /// + [JsonProperty("created_on_utc")] + public DateTime? CreatedOnUtc { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/NewsLetterSubscriptions/NewsLetterSubscriptionsRootObject.cs b/Nop.Plugin.Api.Client/DTOs/NewsLetterSubscriptions/NewsLetterSubscriptionsRootObject.cs new file mode 100644 index 0000000..eba36fb --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/NewsLetterSubscriptions/NewsLetterSubscriptionsRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.NewsLetterSubscriptions +{ + public class NewsLetterSubscriptionsRootObject + { + public NewsLetterSubscriptionsRootObject() + { + NewsLetterSubscriptions = new List(); + } + + [JsonProperty("news_letter_subscriptions")] + public IList NewsLetterSubscriptions { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemDto.cs b/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemDto.cs new file mode 100644 index 0000000..bccad1f --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemDto.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.Products; + +namespace Nop.Plugin.Api.Client.DTOs.OrderItems +{ + [JsonObject(Title = "order_item")] + public class OrderItemDto + { + /// + /// Gets or sets the id + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the selected attributes + /// + [JsonProperty("product_attributes")] + public List Attributes { get; set; } + + /// + /// Gets or sets the quantity + /// + [JsonProperty("quantity")] + public int? Quantity { get; set; } + + /// + /// Gets or sets the unit price in primary store currency (incl tax) + /// + [JsonProperty("unit_price_incl_tax")] + public decimal? UnitPriceInclTax { get; set; } + + /// + /// Gets or sets the unit price in primary store currency (excl tax) + /// + [JsonProperty("unit_price_excl_tax")] + public decimal? UnitPriceExclTax { get; set; } + + /// + /// Gets or sets the price in primary store currency (incl tax) + /// + [JsonProperty("price_incl_tax")] + public decimal? PriceInclTax { get; set; } + + /// + /// Gets or sets the price in primary store currency (excl tax) + /// + [JsonProperty("price_excl_tax")] + public decimal? PriceExclTax { get; set; } + + /// + /// Gets or sets the discount amount (incl tax) + /// + [JsonProperty("discount_amount_incl_tax")] + public decimal? DiscountAmountInclTax { get; set; } + + /// + /// Gets or sets the discount amount (excl tax) + /// + [JsonProperty("discount_amount_excl_tax")] + public decimal? DiscountAmountExclTax { get; set; } + + /// + /// Gets or sets the original cost of this order item (when an order was placed), qty 1 + /// + [JsonProperty("original_product_cost")] + public decimal? OriginalProductCost { get; set; } + + /// + /// Gets or sets the attribute description + /// + [JsonProperty("attribute_description")] + public string AttributeDescription { get; set; } + + /// + /// Gets or sets the download count + /// + [JsonProperty("download_count")] + public int? DownloadCount { get; set; } + + /// + /// Gets or sets a value indicating whether download is activated + /// + [JsonProperty("isDownload_activated")] + public bool? IsDownloadActivated { get; set; } + + /// + /// Gets or sets a license download identifier (in case this is a downloadable product) + /// + [JsonProperty("license_download_id")] + public int? LicenseDownloadId { get; set; } + + /// + /// Gets or sets the total weight of one item + /// It's nullable for compatibility with the previous version of nopCommerce where was no such property + /// + [JsonProperty("item_weight")] + public decimal? ItemWeight { get; set; } + + /// + /// Gets or sets the rental product start date (null if it's not a rental product) + /// + [JsonProperty("rental_start_date_utc")] + public DateTime? RentalStartDateUtc { get; set; } + + /// + /// Gets or sets the rental product end date (null if it's not a rental product) + /// + [JsonProperty("rental_end_date_utc")] + public DateTime? RentalEndDateUtc { get; set; } + + /// + /// Gets the product + /// + [JsonProperty("product")] + public ProductDto Product { get; set; } + + [JsonProperty("product_id")] + public int? ProductId { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemsCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemsCountRootObject.cs new file mode 100644 index 0000000..e949562 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemsCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.OrderItems +{ + public class OrderItemsCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemsRootObject.cs b/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemsRootObject.cs new file mode 100644 index 0000000..eab7835 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/OrderItems/OrderItemsRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.OrderItems +{ + public class OrderItemsRootObject + { + public OrderItemsRootObject() + { + OrderItems = new List(); + } + + [JsonProperty("order_items")] + public IList OrderItems { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Orders/OrderDto.cs b/Nop.Plugin.Api.Client/DTOs/Orders/OrderDto.cs new file mode 100644 index 0000000..7ee014d --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Orders/OrderDto.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.Customers; +using Nop.Plugin.Api.Client.DTOs.OrderItems; + +namespace Nop.Plugin.Api.Client.DTOs.Orders +{ + [JsonObject(Title = "order")] + public class OrderDto + { + /// + /// Gets or sets a value indicating the order id + /// + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("store_id")] + public int? StoreId { get; set; } + + /// + /// Gets or sets the payment method system name + /// + [JsonProperty("payment_method_system_name")] + public string PaymentMethodSystemName { get; set; } + + /// + /// Gets or sets the customer currency code (at the moment of order placing) + /// + [JsonProperty("customer_currency_code")] + public string CustomerCurrencyCode { get; set; } + + /// + /// Gets or sets the currency rate + /// + [JsonProperty("currency_rate")] + public decimal? CurrencyRate { get; set; } + + /// + /// Gets or sets the customer tax display type identifier + /// + [JsonProperty("customer_tax_display_type_id")] + public int? CustomerTaxDisplayTypeId { get; set; } + + /// + /// Gets or sets the VAT number (the European Union Value Added Tax) + /// + [JsonProperty("vat_number")] + public string VatNumber { get; set; } + + /// + /// Gets or sets the order subtotal (incl tax) + /// + [JsonProperty("order_subtotal_incl_tax")] + public decimal? OrderSubtotalInclTax { get; set; } + + /// + /// Gets or sets the order subtotal (excl tax) + /// + [JsonProperty("order_subtotal_excl_tax")] + public decimal? OrderSubtotalExclTax { get; set; } + + /// + /// Gets or sets the order subtotal discount (incl tax) + /// + [JsonProperty("order_sub_total_discount_incl_tax")] + public decimal? OrderSubTotalDiscountInclTax { get; set; } + + /// + /// Gets or sets the order subtotal discount (excl tax) + /// + [JsonProperty("order_sub_total_discount_excl_tax")] + public decimal? OrderSubTotalDiscountExclTax { get; set; } + + /// + /// Gets or sets the order shipping (incl tax) + /// + [JsonProperty("order_shipping_incl_tax")] + public decimal? OrderShippingInclTax { get; set; } + + /// + /// Gets or sets the order shipping (excl tax) + /// + [JsonProperty("order_shipping_excl_tax")] + public decimal? OrderShippingExclTax { get; set; } + + /// + /// Gets or sets the payment method additional fee (incl tax) + /// + [JsonProperty("payment_method_additional_fee_incl_tax")] + public decimal? PaymentMethodAdditionalFeeInclTax { get; set; } + + /// + /// Gets or sets the payment method additional fee (excl tax) + /// + [JsonProperty("payment_method_additional_fee_excl_tax")] + public decimal? PaymentMethodAdditionalFeeExclTax { get; set; } + + /// + /// Gets or sets the tax rates + /// + [JsonProperty("tax_rates")] + public string TaxRates { get; set; } + + /// + /// Gets or sets the order tax + /// + [JsonProperty("order_tax")] + public decimal? OrderTax { get; set; } + + /// + /// Gets or sets the order discount (applied to order total) + /// + [JsonProperty("order_discount")] + public decimal? OrderDiscount { get; set; } + + /// + /// Gets or sets the order total + /// + [JsonProperty("order_total")] + public decimal? OrderTotal { get; set; } + + /// + /// Gets or sets the refunded amount + /// + [JsonProperty("refunded_amount")] + public decimal? RefundedAmount { get; set; } + + /// + /// Gets or sets the value indicating whether reward points were earned for this order + /// + [JsonProperty("reward_points_were_added")] + public bool? RewardPointsWereAdded { get; set; } + + /// + /// Gets or sets the checkout attribute description + /// + [JsonProperty("checkout_attribute_description")] + public string CheckoutAttributeDescription { get; set; } + + /// + /// Gets or sets the customer language identifier + /// + [JsonProperty("customer_language_id")] + public int? CustomerLanguageId { get; set; } + + /// + /// Gets or sets the affiliate identifier + /// + [JsonProperty("affiliate_id")] + public int? AffiliateId { get; set; } + + /// + /// Gets or sets the customer IP address + /// + [JsonProperty("customer_ip")] + public string CustomerIp { get; set; } + + /// + /// Gets or sets the authorization transaction identifier + /// + [JsonProperty("authorization_transaction_id")] + public string AuthorizationTransactionId { get; set; } + + /// + /// Gets or sets the authorization transaction code + /// + [JsonProperty("authorization_transaction_code")] + public string AuthorizationTransactionCode { get; set; } + + /// + /// Gets or sets the authorization transaction result + /// + [JsonProperty("authorization_transaction_result")] + public string AuthorizationTransactionResult { get; set; } + + /// + /// Gets or sets the capture transaction identifier + /// + [JsonProperty("capture_transaction_id")] + public string CaptureTransactionId { get; set; } + + /// + /// Gets or sets the capture transaction result + /// + [JsonProperty("capture_transaction_result")] + public string CaptureTransactionResult { get; set; } + + /// + /// Gets or sets the subscription transaction identifier + /// + [JsonProperty("subscription_transaction_id")] + public string SubscriptionTransactionId { get; set; } + + /// + /// Gets or sets the paid date and time + /// + [JsonProperty("paid_date_utc")] + public DateTime? PaidDateUtc { get; set; } + + /// + /// Gets or sets the shipping method + /// + [JsonProperty("shipping_method")] + public string ShippingMethod { get; set; } + + /// + /// Gets or sets the shipping rate computation method identifier + /// + [JsonProperty("shipping_rate_computation_method_system_name")] + public string ShippingRateComputationMethodSystemName { get; set; } + + /// + /// Gets or sets the serialized CustomValues (values from ProcessPaymentRequest) + /// + [JsonProperty("custom_values_xml")] + public string CustomValuesXml { get; set; } + + /// + /// Gets or sets a value indicating whether the entity has been deleted + /// + [JsonProperty("deleted")] + public bool? Deleted { get; set; } + + /// + /// Gets or sets the date and time of order creation + /// + [JsonProperty("created_on_utc")] + public DateTime? CreatedOnUtc { get; set; } + + /// + /// Gets or sets the customer + /// + [JsonProperty("customer")] + public OrderCustomerDto Customer { get; set; } + + [JsonProperty("customer_id")] + public int? CustomerId { get; set; } + + /// + /// Gets or sets the billing address + /// + [JsonProperty("billing_address")] + public AddressDto BillingAddress { get; set; } + + /// + /// Gets or sets the shipping address + /// + [JsonProperty("shipping_address")] + public AddressDto ShippingAddress { get; set; } + + /// + /// Gets or sets order items + /// + [JsonProperty("order_items")] + public ICollection OrderItemDtos { get; set; } + + /// + /// Gets or sets the order status + /// + [JsonProperty("order_status")] + public string OrderStatus { get; set; } + + /// + /// Gets or sets the payment status + /// + [JsonProperty("payment_status")] + public string PaymentStatus { get; set; } + + /// + /// Gets or sets the shipping status + /// + [JsonProperty("shipping_status")] + public string ShippingStatus { get; set; } + /// + /// Gets or sets the customer tax display type + /// + [JsonProperty("customer_tax_display_type")] + public string CustomerTaxDisplayType { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Orders/OrdersCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Orders/OrdersCountRootObject.cs new file mode 100644 index 0000000..ebfea1b --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Orders/OrdersCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Orders +{ + public class OrdersCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Orders/OrdersRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Orders/OrdersRootObject.cs new file mode 100644 index 0000000..01e806f --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Orders/OrdersRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Orders +{ + public class OrdersRootObject + { + public OrdersRootObject() + { + Orders = new List(); + } + + [JsonProperty("orders")] + public List Orders { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Orders/SingleOrderRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Orders/SingleOrderRootObject.cs new file mode 100644 index 0000000..f930edb --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Orders/SingleOrderRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Orders +{ + public class SingleOrderRootObject + { + [JsonProperty("order")] + public OrderDto Order { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributeDto.cs b/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributeDto.cs new file mode 100644 index 0000000..b30269b --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributeDto.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ProductAttributes +{ + [JsonObject(Title = "product_attribute")] + public class ProductAttributeDto + { + /// + /// Gets or sets the product attribute id + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the description + /// + [JsonProperty("description")] + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributesCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributesCountRootObject.cs new file mode 100644 index 0000000..871b67c --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributesCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ProductAttributes +{ + public class ProductAttributesCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributesRootObjectDto.cs b/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributesRootObjectDto.cs new file mode 100644 index 0000000..eb303da --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductAttributes/ProductAttributesRootObjectDto.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ProductAttributes +{ + public class ProductAttributesRootObjectDto + { + public ProductAttributesRootObjectDto() + { + ProductAttributes = new List(); + } + + [JsonProperty("product_attributes")] + public IList ProductAttributes { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsCountRootObject.cs new file mode 100644 index 0000000..c6b76e6 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ProductCategoryMappings +{ + public class ProductCategoryMappingsCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsDto.cs b/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsDto.cs new file mode 100644 index 0000000..4dd54b6 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsDto.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ProductCategoryMappings +{ + [JsonObject(Title = "product_category_mapping")] + public class ProductCategoryMappingDto + { + [JsonProperty("id")] + public int Id { get; set; } + + /// + /// Gets or sets the product identifier + /// + [JsonProperty("product_id")] + public int? ProductId { get; set; } + + /// + /// Gets or sets the category identifier + /// + [JsonProperty("category_id")] + public int? CategoryId { get; set; } + + /// + /// Gets or sets a value indicating whether the product is featured + /// + [JsonProperty("is_featured_product")] + public bool? IsFeaturedProduct { get; set; } + + /// + /// Gets or sets the display order + /// + [JsonProperty("display_order")] + public int? DisplayOrder { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsRootObject.cs b/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsRootObject.cs new file mode 100644 index 0000000..e017c4e --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductCategoryMappings/ProductCategoryMappingsRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ProductCategoryMappings +{ + public class ProductCategoryMappingsRootObject + { + public ProductCategoryMappingsRootObject() + { + ProductCategoryMappingDtos = new List(); + } + + [JsonProperty("product_category_mappings")] + public IList ProductCategoryMappingDtos { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ProductItemAttributeDto.cs b/Nop.Plugin.Api.Client/DTOs/ProductItemAttributeDto.cs new file mode 100644 index 0000000..90520b6 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ProductItemAttributeDto.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs +{ + [JsonObject(Title = "attribute")] + public class ProductItemAttributeDto + { + [JsonProperty("id")] + public int Id { get; set; } + + [JsonProperty("value")] + public string Value { get; set; } + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Products/ProductAttributeMappingDto.cs b/Nop.Plugin.Api.Client/DTOs/Products/ProductAttributeMappingDto.cs new file mode 100644 index 0000000..b79be42 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Products/ProductAttributeMappingDto.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Products +{ + [JsonObject(Title = "attribute")] + public class ProductAttributeMappingDto + { + /// + /// Gets or sets the product attribute identifier + /// + [JsonProperty("id")] + public int Id { get; set; } + + /// + /// Gets or sets the product attribute identifier + /// + [JsonProperty("product_attribute_id")] + public int ProductAttributeId { get; set; } + + [JsonProperty("product_attribute_name")] + public string ProductAttributeName { get; set; } + + /// + /// Gets or sets a value a text prompt + /// + [JsonProperty("text_prompt")] + public string TextPrompt { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is required + /// + [JsonProperty("is_required")] + public bool IsRequired { get; set; } + + /// + /// Gets or sets the attribute control type identifier + /// + [JsonProperty("attribute_control_type_id")] + public int AttributeControlTypeId { get; set; } + + /// + /// Gets or sets the display order + /// + [JsonProperty("display_order")] + public int DisplayOrder { get; set; } + + /// + /// Gets or sets the default value (for textbox and multiline textbox) + /// + [JsonProperty("default_value")] + public string DefaultValue { get; set; } + + /// + /// Gets the attribute control type + /// + [JsonProperty("attribute_control_type_name")] + public string AttributeControlType { get; set; } + + + /// + /// Gets the product attribute values + /// + [JsonProperty("attribute_values")] + public List ProductAttributeValues { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Products/ProductAttributeValueDto.cs b/Nop.Plugin.Api.Client/DTOs/Products/ProductAttributeValueDto.cs new file mode 100644 index 0000000..a7af63a --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Products/ProductAttributeValueDto.cs @@ -0,0 +1,96 @@ +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.Images; + +namespace Nop.Plugin.Api.Client.DTOs.Products +{ + [JsonObject(Title = "attribute_value")] + public class ProductAttributeValueDto + { + /// + /// Gets or sets the product attribute value id + /// + [JsonProperty("id")] + public int Id { get; set; } + + /// + /// Gets or sets the attribute value type identifier + /// + [JsonProperty("type_id")] + public int? AttributeValueTypeId { get; set; } + + /// + /// Gets or sets the associated product identifier (used only with AttributeValueType.AssociatedToProduct) + /// + [JsonProperty("associated_product_id")] + public int? AssociatedProductId { get; set; } + + /// + /// Gets or sets the product attribute name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the color RGB value (used with "Color squares" attribute type) + /// + [JsonProperty("color_squares_rgb")] + public string ColorSquaresRgb { get; set; } + + /// + /// Gets or sets the picture ID for image square (used with "Image squares" attribute type) + /// + [JsonProperty("image_squares_image")] + public ImageDto ImageSquaresImage { get; set; } + + /// + /// Gets or sets the price adjustment (used only with AttributeValueType.Simple) + /// + [JsonProperty("price_adjustment")] + public decimal? PriceAdjustment { get; set; } + + /// + /// Gets or sets the weight adjustment (used only with AttributeValueType.Simple) + /// + [JsonProperty("weight_adjustment")] + public decimal? WeightAdjustment { get; set; } + + /// + /// Gets or sets the attibute value cost (used only with AttributeValueType.Simple) + /// + [JsonProperty("cost")] + public decimal? Cost { get; set; } + + /// + /// Gets or sets the quantity of associated product (used only with AttributeValueType.AssociatedToProduct) + /// + [JsonProperty("quantity")] + public int? Quantity { get; set; } + + /// + /// Gets or sets a value indicating whether the value is pre-selected + /// + [JsonProperty("is_pre_selected")] + public bool? IsPreSelected { get; set; } + + /// + /// Gets or sets the display order + /// + [JsonProperty("display_order")] + public int? DisplayOrder { get; set; } + + /// + /// Gets or sets the picture (identifier) associated with this value. This picture should replace a product main picture once clicked (selected). + /// + [JsonIgnore] + public int? PictureId { get; set; } + + [JsonProperty("product_image_id")] + public int? ProductPictureId { get; set; } + + /// + /// Gets or sets the attribute value type + /// + [JsonProperty("type")] + public string AttributeValueType { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Products/ProductDto.cs b/Nop.Plugin.Api.Client/DTOs/Products/ProductDto.cs new file mode 100644 index 0000000..657e118 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Products/ProductDto.cs @@ -0,0 +1,502 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.Images; +using Nop.Plugin.Api.Client.DTOs.Languages; + +namespace Nop.Plugin.Api.Client.DTOs.Products +{ + [JsonObject(Title = "product")] + public class ProductDto + { + /// + /// Gets or sets the product id + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the values indicating whether this product is visible in catalog or search results. + /// It's used when this product is associated to some "grouped" one + /// This way associated products could be accessed/added/etc only from a grouped product details page + /// + [JsonProperty("visible_individually")] + public bool? VisibleIndividually { get; set; } + + /// + /// Gets or sets the name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the localized names + /// + [JsonProperty("localized_names")] + public List LocalizedNames { get; set; } + + /// + /// Gets or sets the short description + /// + [JsonProperty("short_description")] + public string ShortDescription { get; set; } + /// + /// Gets or sets the full description + /// + [JsonProperty("full_description")] + public string FullDescription { get; set; } + + /// + /// Gets or sets a value indicating whether to show the product on home page + /// + [JsonProperty("show_on_home_page")] + public bool? ShowOnHomePage { get; set; } + + /// + /// Gets or sets the meta keywords + /// + [JsonProperty("meta_keywords")] + public string MetaKeywords { get; set; } + /// + /// Gets or sets the meta description + /// + [JsonProperty("meta_description")] + public string MetaDescription { get; set; } + /// + /// Gets or sets the meta title + /// + [JsonProperty("meta_title")] + public string MetaTitle { get; set; } + + /// + /// Gets or sets a value indicating whether the product allows customer reviews + /// + [JsonProperty("allow_customer_reviews")] + public bool? AllowCustomerReviews { get; set; } + /// + /// Gets or sets the rating sum (approved reviews) + /// + [JsonProperty("approved_rating_sum")] + public int? ApprovedRatingSum { get; set; } + /// + /// Gets or sets the rating sum (not approved reviews) + /// + [JsonProperty("not_approved_rating_sum")] + public int? NotApprovedRatingSum { get; set; } + /// + /// Gets or sets the total rating votes (approved reviews) + /// + [JsonProperty("approved_total_reviews")] + public int? ApprovedTotalReviews { get; set; } + /// + /// Gets or sets the total rating votes (not approved reviews) + /// + [JsonProperty("not_approved_total_reviews")] + public int? NotApprovedTotalReviews { get; set; } + + /// + /// Gets or sets the SKU + /// + [JsonProperty("sku")] + public string Sku { get; set; } + /// + /// Gets or sets the manufacturer part number + /// + [JsonProperty("manufacturer_part_number")] + public string ManufacturerPartNumber { get; set; } + /// + /// Gets or sets the Global Trade Item Number (GTIN). These identifiers include UPC (in North America), EAN (in Europe), JAN (in Japan), and ISBN (for books). + /// + [JsonProperty("gtin")] + public string Gtin { get; set; } + + /// + /// Gets or sets a value indicating whether the product is gift card + /// + [JsonProperty("is_gift_card")] + public bool? IsGiftCard { get; set; } + + /// + /// Gets or sets a value indicating whether the product requires that other products are added to the cart (Product X requires Product Y) + /// + [JsonProperty("require_other_products")] + public bool? RequireOtherProducts { get; set; } + + /// + /// Gets or sets a value indicating whether required products are automatically added to the cart + /// + [JsonProperty("automatically_add_required_products")] + public bool? AutomaticallyAddRequiredProducts { get; set; } + + /// + /// Gets or sets a value indicating whether the product is download + /// + [JsonProperty("is_download")] + public bool? IsDownload { get; set; } + + /// + /// Gets or sets a value indicating whether this downloadable product can be downloaded unlimited number of times + /// + [JsonProperty("unlimited_downloads")] + public bool? UnlimitedDownloads { get; set; } + /// + /// Gets or sets the maximum number of downloads + /// + [JsonProperty("max_number_of_downloads")] + public int? MaxNumberOfDownloads { get; set; } + /// + /// Gets or sets the number of days during customers keeps access to the file. + /// + [JsonProperty("download_expiration_days")] + public int? DownloadExpirationDays { get; set; } + + /// + /// Gets or sets a value indicating whether the product has a sample download file + /// + [JsonProperty("has_sample_download")] + public bool? HasSampleDownload { get; set; } + + /// + /// Gets or sets a value indicating whether the product has user agreement + /// + [JsonProperty("has_user_agreement")] + public bool? HasUserAgreement { get; set; } + + /// + /// Gets or sets a value indicating whether the product is recurring + /// + [JsonProperty("is_recurring")] + public bool? IsRecurring { get; set; } + /// + /// Gets or sets the cycle length + /// + [JsonProperty("recurring_cycle_length")] + public int? RecurringCycleLength { get; set; } + + /// + /// Gets or sets the total cycles + /// + [JsonProperty("recurring_total_cycles")] + public int? RecurringTotalCycles { get; set; } + + /// + /// Gets or sets a value indicating whether the product is rental + /// + [JsonProperty("is_rental")] + public bool? IsRental { get; set; } + /// + /// Gets or sets the rental length for some period (price for this period) + /// + [JsonProperty("rental_price_length")] + public int? RentalPriceLength { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is ship enabled + /// + [JsonProperty("is_ship_enabled")] + public bool? IsShipEnabled { get; set; } + /// + /// Gets or sets a value indicating whether the entity is free shipping + /// + [JsonProperty("is_free_shipping")] + public bool? IsFreeShipping { get; set; } + /// + /// Gets or sets a value this product should be shipped separately (each item) + /// + [JsonProperty("ship_separately")] + public bool? ShipSeparately { get; set; } + /// + /// Gets or sets the additional shipping charge + /// + [JsonProperty("additional_shipping_charge")] + public decimal? AdditionalShippingCharge { get; set; } + + /// + /// Gets or sets a value indicating whether the product is marked as tax exempt + /// + [JsonProperty("is_tax_exempt")] + public bool? IsTaxExempt { get; set; } + + /// + /// Gets or sets a value indicating whether the product is telecommunications or broadcasting or electronic services + /// + [JsonProperty("is_telecommunications_or_broadcasting_or_electronic_services")] + public bool? IsTelecommunicationsOrBroadcastingOrElectronicServices { get; set; } + + /// + /// Gets or sets a value indicating whether multiple warehouses are used for this product + /// + [JsonProperty("use_multiple_warehouses")] + public bool? UseMultipleWarehouses { get; set; } + + /// + /// Gets or sets a value indicating how to manage inventory. + /// 0 - do not track inventory + /// 1 - track inventory + /// 2 - track invetory by attributes + /// + [JsonProperty("manage_inventory_method_id")] + public int? ManageInventoryMethodId { get; set; } + + /// + /// Gets or sets the stock quantity + /// + [JsonProperty("stock_quantity")] + public int? StockQuantity { get; set; } + /// + /// Gets or sets a value indicating whether to display stock availability + /// + [JsonProperty("display_stock_availability")] + public bool? DisplayStockAvailability { get; set; } + /// + /// Gets or sets a value indicating whether to display stock quantity + /// + [JsonProperty("display_stock_quantity")] + public bool? DisplayStockQuantity { get; set; } + /// + /// Gets or sets the minimum stock quantity + /// + [JsonProperty("min_stock_quantity")] + public int? MinStockQuantity { get; set; } + + /// + /// Gets or sets the quantity when admin should be notified + /// + [JsonProperty("notify_admin_for_quantity_below")] + public int? NotifyAdminForQuantityBelow { get; set; } + + /// + /// Gets or sets a value indicating whether to back in stock subscriptions are allowed + /// + [JsonProperty("allow_back_in_stock_subscriptions")] + public bool? AllowBackInStockSubscriptions { get; set; } + /// + /// Gets or sets the order minimum quantity + /// + [JsonProperty("order_minimum_quantity")] + public int? OrderMinimumQuantity { get; set; } + /// + /// Gets or sets the order maximum quantity + /// + [JsonProperty("order_maximum_quantity")] + public int? OrderMaximumQuantity { get; set; } + /// + /// Gets or sets the comma seperated list of allowed quantities. null or empty if any quantity is allowed + /// + [JsonProperty("allowed_quantities")] + public string AllowedQuantities { get; set; } + /// + /// Gets or sets a value indicating whether we allow adding to the cart/wishlist only attribute combinations that exist and have stock greater than zero. + /// This option is used only when we have "manage inventory" set to "track inventory by product attributes" + /// + [JsonProperty("allow_adding_only_existing_attribute_combinations")] + public bool? AllowAddingOnlyExistingAttributeCombinations { get; set; } + + /// + /// Gets or sets a value indicating whether to disable buy (Add to cart) button + /// + [JsonProperty("disable_buy_button")] + public bool? DisableBuyButton { get; set; } + /// + /// Gets or sets a value indicating whether to disable "Add to wishlist" button + /// + [JsonProperty("disable_wishlist_button")] + public bool? DisableWishlistButton { get; set; } + /// + /// Gets or sets a value indicating whether this item is available for Pre-Order + /// + [JsonProperty("available_for_pre_order")] + public bool? AvailableForPreOrder { get; set; } + /// + /// Gets or sets the start date and time of the product availability (for pre-order products) + /// + [JsonProperty("pre_order_availability_start_date_time_utc")] + public DateTime? PreOrderAvailabilityStartDateTimeUtc { get; set; } + /// + /// Gets or sets a value indicating whether to show "Call for Pricing" or "Call for quote" instead of price + /// + [JsonProperty("call_for_price")] + public bool? CallForPrice { get; set; } + /// + /// Gets or sets the price + /// + [JsonProperty("price")] + public decimal? Price { get; set; } + /// + /// Gets or sets the old price + /// + [JsonProperty("old_price")] + public decimal? OldPrice { get; set; } + /// + /// Gets or sets the product cost + /// + [JsonProperty("product_cost")] + public decimal? ProductCost { get; set; } + /// + /// Gets or sets the product special price + /// + [JsonProperty("special_price")] + public decimal? SpecialPrice { get; set; } + /// + /// Gets or sets the start date and time of the special price + /// + [JsonProperty("special_price_start_date_time_utc")] + public DateTime? SpecialPriceStartDateTimeUtc { get; set; } + /// + /// Gets or sets the end date and time of the special price + /// + [JsonProperty("special_price_end_date_time_utc")] + public DateTime? SpecialPriceEndDateTimeUtc { get; set; } + /// + /// Gets or sets a value indicating whether a customer enters price + /// + [JsonProperty("customer_enters_price")] + public bool? CustomerEntersPrice { get; set; } + /// + /// Gets or sets the minimum price entered by a customer + /// + [JsonProperty("minimum_customer_entered_price")] + public decimal? MinimumCustomerEnteredPrice { get; set; } + /// + /// Gets or sets the maximum price entered by a customer + /// + [JsonProperty("maximum_customer_entered_price")] + public decimal? MaximumCustomerEnteredPrice { get; set; } + + /// + /// Gets or sets a value indicating whether base price (PAngV) is enabled. Used by German users. + /// + [JsonProperty("baseprice_enabled")] + public bool? BasePriceEnabled { get; set; } + /// + /// Gets or sets an amount in product for PAngV + /// + [JsonProperty("baseprice_amount")] + public decimal? BasePriceAmount { get; set; } + + /// + /// Gets or sets a reference amount for PAngV + /// + [JsonProperty("baseprice_base_amount")] + public decimal? BasePriceBaseAmount { get; set; } + + /// + /// Gets or sets a value indicating whether this product has tier prices configured + /// The same as if we run this.TierPrices.Count > 0 + /// We use this property for performance optimization: + /// if this property is set to false, then we do not need to load tier prices navigation property + /// + /// + [JsonProperty("has_tier_prices")] + public bool? HasTierPrices { get; set; } + /// + /// Gets or sets a value indicating whether this product has discounts applied + /// The same as if we run this.AppliedDiscounts.Count > 0 + /// We use this property for performance optimization: + /// if this property is set to false, then we do not need to load Applied Discounts navigation property + /// + /// + [JsonProperty("has_discounts_applied")] + public bool? HasDiscountsApplied { get; set; } + + /// + /// Gets or sets the weight + /// + [JsonProperty("weight")] + public decimal? Weight { get; set; } + /// + /// Gets or sets the length + /// + [JsonProperty("length")] + public decimal? Length { get; set; } + /// + /// Gets or sets the width + /// + [JsonProperty("width")] + public decimal? Width { get; set; } + /// + /// Gets or sets the height + /// + [JsonProperty("height")] + public decimal? Height { get; set; } + + /// + /// Gets or sets the available start date and time + /// + [JsonProperty("available_start_date_time_utc")] + public DateTime? AvailableStartDateTimeUtc { get; set; } + /// + /// Gets or sets the available end date and time + /// + [JsonProperty("available_end_date_time_utc")] + public DateTime? AvailableEndDateTimeUtc { get; set; } + + /// + /// Gets or sets a display order. + /// This value is used when sorting associated products (used with "grouped" products) + /// This value is used when sorting home page products + /// + [JsonProperty("display_order")] + public int? DisplayOrder { get; set; } + /// + /// Gets or sets a value indicating whether the entity is published + /// + [JsonProperty("published")] + public bool? Published { get; set; } + /// + /// Gets or sets a value indicating whether the entity has been deleted + /// + [JsonProperty("deleted")] + public bool? Deleted { get; set; } + + /// + /// Gets or sets the date and time of product creation + /// + [JsonProperty("created_on_utc")] + public DateTime? CreatedOnUtc { get; set; } + /// + /// Gets or sets the date and time of product update + /// + [JsonProperty("updated_on_utc")] + public DateTime? UpdatedOnUtc { get; set; } + + /// + /// Gets or sets the product type + /// + [JsonProperty("product_type")] + public string ProductType { get; set; } + + [JsonProperty("parent_grouped_product_id")] + public int? ParentGroupedProductId { get; set; } + + [JsonProperty("role_ids")] + public List RoleIds { get; set; } + + [JsonProperty("discount_ids")] + public List DiscountIds { get; set; } + + [JsonProperty("store_ids")] + public List StoreIds { get; set; } + + [JsonProperty("manufacturer_ids")] + public List ManufacturerIds { get; set; } + + [JsonProperty("images")] + public List Images { get; set; } + + [JsonProperty("attributes")] + public List ProductAttributeMappings { get; set; } + + [JsonProperty("associated_product_ids")] + public List AssociatedProductIds { get; set; } + + [JsonProperty("tags")] + public List Tags { get; set; } + + [JsonProperty("vendor_id")] + public int? VendorId { get; set; } + + [JsonProperty("se_name")] + public string SeName { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Products/ProductsCountRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Products/ProductsCountRootObject.cs new file mode 100644 index 0000000..30e8e9c --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Products/ProductsCountRootObject.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Products +{ + public class ProductsCountRootObject + { + [JsonProperty("count")] + public int Count { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Products/ProductsRootObjectDto.cs b/Nop.Plugin.Api.Client/DTOs/Products/ProductsRootObjectDto.cs new file mode 100644 index 0000000..5a8a360 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Products/ProductsRootObjectDto.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Products +{ + public class ProductsRootObjectDto + { + public ProductsRootObjectDto() + { + Products = new List(); + } + + [JsonProperty("products")] + public IList Products { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ShoppingCarts/ShoppingCartItemDto.cs b/Nop.Plugin.Api.Client/DTOs/ShoppingCarts/ShoppingCartItemDto.cs new file mode 100644 index 0000000..597b293 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ShoppingCarts/ShoppingCartItemDto.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Nop.Plugin.Api.Client.DTOs.Customers; +using Nop.Plugin.Api.Client.DTOs.Products; + +namespace Nop.Plugin.Api.Client.DTOs.ShoppingCarts +{ + [JsonObject(Title = "shopping_cart_item")] + public class ShoppingCartItemDto + { + /// + /// Gets or sets the id + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the selected attributes + /// + [JsonProperty("product_attributes")] + public List Attributes { get; set; } + + /// + /// Gets or sets the price enter by a customer + /// + [JsonProperty("customer_entered_price")] + public decimal? CustomerEnteredPrice { get; set; } + + /// + /// Gets or sets the quantity + /// + [JsonProperty("quantity")] + public int? Quantity { get; set; } + + /// + /// Gets or sets the rental product start date (null if it's not a rental product) + /// + [JsonProperty("rental_start_date_utc")] + public DateTime? RentalStartDateUtc { get; set; } + + /// + /// Gets or sets the rental product end date (null if it's not a rental product) + /// + [JsonProperty("rental_end_date_utc")] + public DateTime? RentalEndDateUtc { get; set; } + + /// + /// Gets or sets the date and time of instance creation + /// + [JsonProperty("created_on_utc")] + public DateTime? CreatedOnUtc { get; set; } + + /// + /// Gets or sets the date and time of instance update + /// + [JsonProperty("updated_on_utc")] + public DateTime? UpdatedOnUtc { get; set; } + + /// + /// Gets the log type + /// + [JsonProperty("shopping_cart_type")] + public string ShoppingCartType { get; set; } + + + [JsonProperty("product_id")] + public int? ProductId { get; set; } + + /// + /// Gets or sets the product + /// + [JsonProperty("product")] + public ProductDto ProductDto { get; set; } + + [JsonProperty("customer_id")] + public int? CustomerId { get; set; } + + /// + /// Gets or sets the customer + /// + [JsonProperty("customer")] + public CustomerForShoppingCartItemDto CustomerDto { get; set; } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/ShoppingCarts/ShoppingCartItemsRootObject.cs b/Nop.Plugin.Api.Client/DTOs/ShoppingCarts/ShoppingCartItemsRootObject.cs new file mode 100644 index 0000000..673a627 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/ShoppingCarts/ShoppingCartItemsRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.ShoppingCarts +{ + public class ShoppingCartItemsRootObject + { + public ShoppingCartItemsRootObject() + { + ShoppingCartItems = new List(); + } + + [JsonProperty("shopping_carts")] + public IList ShoppingCartItems { get; set; } + + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/DTOs/Stores/StoreDto.cs b/Nop.Plugin.Api.Client/DTOs/Stores/StoreDto.cs new file mode 100644 index 0000000..1551d73 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Stores/StoreDto.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Stores +{ + [JsonObject(Title = "store")] + public class StoreDto + { + /// + /// Gets or sets the store ID + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Gets or sets the store name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the store URL + /// + [JsonProperty("url")] + public string Url { get; set; } + + /// + /// Gets or sets a value indicating whether SSL is enabled + /// + [JsonProperty("ssl_enabled")] + public bool? SslEnabled { get; set; } + + /// + /// Gets or sets the store secure URL (HTTPS) + /// + [JsonProperty("secure_url")] + public string SecureUrl { get; set; } + + /// + /// Gets or sets the comma separated list of possible HTTP_HOST values + /// + [JsonProperty("hosts")] + public string Hosts { get; set; } + + /// + /// Gets or sets the identifier of the default language for this store; 0 is set when we use the default language display order + /// + [JsonProperty("default_language_id")] + public int? DefaultLanguageId { get; set; } + + /// + /// Gets or sets the identifier of the language IDs for this store + /// + [JsonProperty("language_ids")] + public List LanguageIds { get; set; } + + /// + /// Gets or sets the display order + /// + [JsonProperty("display_order")] + public int? DisplayOrder { get; set; } + + /// + /// Gets or sets the company name + /// + [JsonProperty("company_name")] + public string CompanyName { get; set; } + + /// + /// Gets or sets the company address + /// + [JsonProperty("company_address")] + public string CompanyAddress { get; set; } + + /// + /// Gets or sets the store phone number + /// + [JsonProperty("company_phone_number")] + public string CompanyPhoneNumber { get; set; } + + /// + /// Gets or sets the company VAT (used in Europe Union countries) + /// + [JsonProperty("company_vat")] + public string CompanyVat { get; set; } + + /// + /// Get or set the currency format + /// + [JsonProperty("primary_currency_display_locale")] + public string PrimaryCurrencyDisplayLocale { get; set; } + } +} diff --git a/Nop.Plugin.Api.Client/DTOs/Stores/StoresRootObject.cs b/Nop.Plugin.Api.Client/DTOs/Stores/StoresRootObject.cs new file mode 100644 index 0000000..cff9698 --- /dev/null +++ b/Nop.Plugin.Api.Client/DTOs/Stores/StoresRootObject.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.DTOs.Stores +{ + public class StoresRootObject + { + public StoresRootObject() + { + Stores = new List(); + } + + [JsonProperty("stores")] + public IList Stores { get; set; } + + } +} diff --git a/Nop.Plugin.Api.Client/Exceptions/NopApiClientException.cs b/Nop.Plugin.Api.Client/Exceptions/NopApiClientException.cs new file mode 100644 index 0000000..7b110d4 --- /dev/null +++ b/Nop.Plugin.Api.Client/Exceptions/NopApiClientException.cs @@ -0,0 +1,94 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Lindell Technologies All Rights Reserved. +// Information Contained Herein is Proprietary and Confidential. +// +// ----------------------------------------------------------------------- + +using System; +using System.Net; +using System.Runtime.Serialization; +using System.Security.Permissions; + +namespace Nop.Plugin.Api.Client.Exceptions +{ + public class NopApiClientException : ApplicationException + { + public NopApiClientException() + : this(null, null) + { + } + + public NopApiClientException(string message, bool canRetry = false) + : this(HttpStatusCode.BadRequest, null, null, message, canRetry) + { + } + + public NopApiClientException(string resourceUrl, string method, bool canRetry = false) + : this(HttpStatusCode.ServiceUnavailable, resourceUrl, method, "No Response", canRetry) + { + } + + public NopApiClientException( + HttpStatusCode statusCode, + string resourceUrl, + string method, + string message, + bool canRetry = false) + : this(statusCode, resourceUrl, method, message, null, canRetry) + { + } + + public NopApiClientException( + HttpStatusCode statusCode, + string resourceUrl, + string method, + string message, + NopApiClientExceptionDetails exceptionDetails, + bool canRetry = false) + : base(message ?? (exceptionDetails != null ? exceptionDetails.Message : statusCode.ToString())) + { + ResourceUrl = resourceUrl; + StatusCode = statusCode; + Method = method; + ExceptionDetails = exceptionDetails; + CanRetry = canRetry; + } + + public NopApiClientException( + HttpStatusCode statusCode, + string resourceUrl, + string method, + Exception exception, + bool canRetry = false) + : base(exception.Message, exception) + { + ResourceUrl = resourceUrl; + StatusCode = statusCode; + Method = method; + CanRetry = canRetry; + } + + public bool CanRetry { get; } + + public string ResourceUrl { get; } + + public HttpStatusCode StatusCode { get; } + + public string Method { get; } + + public NopApiClientExceptionDetails ExceptionDetails { get; } + + public override string Message => + $"{Method} request for '{ResourceUrl}' returned [{StatusCode}] {base.Message} "; + + [SecurityPermission( + SecurityAction.Demand, + Flags = SecurityPermissionFlag.SerializationFormatter, + SerializationFormatter = true)] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/Exceptions/NopApiClientExceptionDetails.cs b/Nop.Plugin.Api.Client/Exceptions/NopApiClientExceptionDetails.cs new file mode 100644 index 0000000..7259876 --- /dev/null +++ b/Nop.Plugin.Api.Client/Exceptions/NopApiClientExceptionDetails.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.Exceptions +{ + public class NopApiClientExceptionDetails + { + public string Content { get; set; } + + public string Message { get; set; } + + [JsonProperty("errors")] public dynamic Errors { get; set; } + + public string ExceptionType { get; set; } + + public string StackTrace { get; set; } + + public override string ToString() + { + return Message; + } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/Nop.Plugin.Api.Client.csproj b/Nop.Plugin.Api.Client/Nop.Plugin.Api.Client.csproj new file mode 100644 index 0000000..f5d6dbe --- /dev/null +++ b/Nop.Plugin.Api.Client/Nop.Plugin.Api.Client.csproj @@ -0,0 +1,120 @@ + + + + + Debug + AnyCPU + {42CDBA4C-A9B0-4C9E-A1E5-932D6025D768} + Exe + Nop.Plugin.Api.Client + ApiClient + v4.7.1 + 512 + true + SAK + SAK + SAK + SAK + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\..\packages\Polly.6.1.0\lib\netstandard2.0\Polly.dll + + + ..\..\packages\RestSharp.106.3.1\lib\net452\RestSharp.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/NopApiClient.cs b/Nop.Plugin.Api.Client/NopApiClient.cs new file mode 100644 index 0000000..4e6c672 --- /dev/null +++ b/Nop.Plugin.Api.Client/NopApiClient.cs @@ -0,0 +1,32 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Lindell Technologies All Rights Reserved. +// Information Contained Herein is Proprietary and Confidential. +// +// ----------------------------------------------------------------------- + + +using Nop.Plugin.Api.Client.Clients; + +namespace Nop.Plugin.Api.Client +{ + public class NopApiClient + { + private OrdersClient _ordersClient; + + public NopApiClient(string serverUrl, string clientId, string secret) + { + ServerUrl = serverUrl; + ClientId = clientId; + Secret = secret; + } + + public string ServerUrl { get; } + + public string ClientId { get; } + + public string Secret { get; } + + public OrdersClient Orders => _ordersClient ?? (_ordersClient = new OrdersClient(this)); + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/Program.cs b/Nop.Plugin.Api.Client/Program.cs new file mode 100644 index 0000000..b6ba3dd --- /dev/null +++ b/Nop.Plugin.Api.Client/Program.cs @@ -0,0 +1,54 @@ +using System; +using System.Linq; + + +namespace Nop.Plugin.Api.Client +{ + class Program + { + static void Main(string[] args) + { + + // TODO: Change to match your environment + var url = "http://localhost:15536"; + var clientId = "ea0204cd-5bbd-49ae-9810-d24735581f43"; + var clientSecret = "80a14949-8549-4d60-9d3a-864473b7a93a"; + + + + var client = new NopApiClient(url, clientId, clientSecret); + + Console.Write("Fetching Orders..."); + var orders = client.Orders.GetOrders(); + + Console.WriteLine($"received {orders.Count} orders."); + + + /////////////////////////////////////////// + // Example of how to go through each order + /////////////////////////////////////////// + + var start = 0; + + while (true) + { + orders = client.Orders.GetOrders(start, limit: 1); + + var order = orders.LastOrDefault(); + if (order == null) + { + break; + } + + start = int.Parse(order.Id); + } + + // now at this point we should store the 'start' variable + + + Console.WriteLine("Hit any key to continue..."); + Console.ReadKey(); + + } + } +} diff --git a/Nop.Plugin.Api.Client/Properties/AssemblyInfo.cs b/Nop.Plugin.Api.Client/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..382ea70 --- /dev/null +++ b/Nop.Plugin.Api.Client/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Nop.Plugin.Api.Client")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Nop.Plugin.Api.Client")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("42cdba4c-a9b0-4c9e-a1e5-932d6025d768")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Nop.Plugin.Api.Client/Security/Token.cs b/Nop.Plugin.Api.Client/Security/Token.cs new file mode 100644 index 0000000..76d039a --- /dev/null +++ b/Nop.Plugin.Api.Client/Security/Token.cs @@ -0,0 +1,33 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Lindell Technologies All Rights Reserved. +// Information Contained Herein is Proprietary and Confidential. +// +// ----------------------------------------------------------------------- + +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.Security +{ + public class Token + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } + + [JsonProperty("refresh_token")] + public string RefreshToken { get; set; } + + /// + public override string ToString() + { + return AccessToken; + } + } + +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/Security/TokenClient.cs b/Nop.Plugin.Api.Client/Security/TokenClient.cs new file mode 100644 index 0000000..c2ee1e2 --- /dev/null +++ b/Nop.Plugin.Api.Client/Security/TokenClient.cs @@ -0,0 +1,68 @@ +using System; +using Nop.Plugin.Api.Client.Exceptions; +using RestSharp; + +namespace Nop.Plugin.Api.Client.Security +{ + public class TokenClient + { + private readonly Uri _serverUrl; + + public TokenClient(Uri serverUrl) + { + _serverUrl = serverUrl; + } + + public Token GetToken(string clientId, string secret) + { + return GetTokenInternal(clientId, secret, GetAuthCode(clientId)); + } + + private string GetAuthCode(string clientId) + { + var restClient = new RestClient(_serverUrl.ToString()); + var request = new RestRequest("oauth/authorize") { Method = Method.GET }; + request.AddHeader("Accept", "application/json"); + request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); + request.AddParameter("client_id", clientId); + request.AddParameter("redirect_uri", $"{_serverUrl}token"); + request.AddParameter("response_type", "code"); + + var response = restClient.Execute(request); + if (response.ResponseUri != null) + { + var parameters = response.ResponseUri.Query.Replace("?", "").Split(new[] {'&'}, StringSplitOptions.RemoveEmptyEntries); + foreach (var p in parameters) + { + var parts = p.Split('='); + if (parts.Length == 2) + { + if (parts[0].ToLower() == "code") + { + return parts[1]; + } + } + } + } + + throw new NopApiClientException("Could not fetch auth code."); + } + + private Token GetTokenInternal(string clientId, string secret, string code) + { + var restClient = new RestClient(_serverUrl.ToString()); + var request = new RestRequest("connect/token") { Method = Method.POST }; + request.AddHeader("Accept", "application/json"); + request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); + request.AddParameter("client_id", clientId); + request.AddParameter("client_secret", secret); + request.AddParameter("code", code); + request.AddParameter("grant_type", "authorization_code"); + request.AddParameter("redirect_uri", $"{_serverUrl}token"); + + var tokenResponse = restClient.Execute(request); + + return tokenResponse.Data; + } + } +} diff --git a/Nop.Plugin.Api.Client/Serialization/JsonSeriailzationUtility.cs b/Nop.Plugin.Api.Client/Serialization/JsonSeriailzationUtility.cs new file mode 100644 index 0000000..864d4ee --- /dev/null +++ b/Nop.Plugin.Api.Client/Serialization/JsonSeriailzationUtility.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Text; +using Newtonsoft.Json; + +namespace Nop.Plugin.Api.Client.Serialization +{ + public static class JsonSerializationUtility + { + public static bool TryDeserialize(string json, out T result) + { + try + { + result = Deserialize(json); + return true; + } + catch + { + result = default(T); + } + + return false; + } + + public static T Deserialize(string json) + { + return JsonConvert.DeserializeObject(json); + } + + public static object Deserialize(string json, Type objectType) + { + return JsonConvert.DeserializeObject(json, objectType); + } + + public static string Serialize(T obj, bool indent = false, JsonConverter converter = null) + { + var sb = new StringBuilder(); + var settings = new JsonSerializerSettings(); + + if (indent) + { + settings.Formatting = Formatting.Indented; + } + + if (converter != null) + { + settings.Converters.Add(converter); + } + + JsonSerializer.CreateDefault(settings).Serialize(new JsonTextWriter(new StringWriter(sb)), obj); + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/Serialization/NewtonsoftSerializer.cs b/Nop.Plugin.Api.Client/Serialization/NewtonsoftSerializer.cs new file mode 100644 index 0000000..0deede6 --- /dev/null +++ b/Nop.Plugin.Api.Client/Serialization/NewtonsoftSerializer.cs @@ -0,0 +1,140 @@ +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using RestSharp; +using RestSharp.Deserializers; +using RestSharp.Serializers; +using JsonSerializer = Newtonsoft.Json.JsonSerializer; + +namespace Nop.Plugin.Api.Client.Serialization +{ + public class NewtonsoftSerializer : ISerializer, IDeserializer + { + /// + /// Encoding to use to convert string to byte[] and the other way around. + /// + /// + /// StackExchange.Redis uses Encoding.UTF8 to convert strings to bytes, + /// hence we do same here. + /// + private static readonly Encoding s_encoding = Encoding.UTF8; + + private readonly JsonSerializer _serializer; + + private readonly JsonSerializerSettings _settings; + + public NewtonsoftSerializer() + { + _serializer = new JsonSerializer + { + MissingMemberHandling = MissingMemberHandling.Ignore, + NullValueHandling = NullValueHandling.Ignore, + DefaultValueHandling = DefaultValueHandling.Include + }; + + _settings = new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Ignore, + NullValueHandling = NullValueHandling.Ignore, + DefaultValueHandling = DefaultValueHandling.Include + }; + } + + public NewtonsoftSerializer(JsonSerializer serializer, JsonSerializerSettings settings) + { + _serializer = serializer; + _settings = settings; + } + + public T Deserialize(IRestResponse response) + { + var content = response.Content; + + using (var stringReader = new StringReader(content)) + { + using (var jsonTextReader = new JsonTextReader(stringReader)) + { + return _serializer.Deserialize(jsonTextReader); + } + } + } + + public byte[] Serialize(object item) + { + var jsonString = JsonConvert.SerializeObject(item, _settings); + return s_encoding.GetBytes(jsonString); + } + + public async Task SerializeAsync(object item) + { + var jsonString = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(item, _settings)); + + return s_encoding.GetBytes(jsonString); + } + + public object Deserialize(byte[] serializedObject) + { + var jsonString = s_encoding.GetString(serializedObject); + return JsonConvert.DeserializeObject(jsonString, typeof(object), _settings); + } + + public Task DeserializeAsync(byte[] serializedObject) + { + return Task.Factory.StartNew(() => Deserialize(serializedObject)); + } + + public T Deserialize(byte[] serializedObject) + where T : class + { + var jsonString = s_encoding.GetString(serializedObject); + return JsonConvert.DeserializeObject(jsonString, _settings); + } + + public Task DeserializeAsync(byte[] serializedObject) + where T : class + { + return Task.Factory.StartNew(() => Deserialize(serializedObject)); + } + + string ISerializer.Serialize(object obj) + { + using (var stringWriter = new StringWriter()) + { + var jsonTextWriter = + new JsonTextWriter(stringWriter) { Formatting = Formatting.Indented, QuoteChar = '"' }; + + _serializer.Serialize(jsonTextWriter, obj); + + var result = stringWriter.ToString(); + return result; + } + } + + /// + /// Unused for JSON Serialization + /// + public string DateFormat { get; set; } + + /// + /// Unused for JSON Serialization + /// + public string RootElement { get; set; } + + /// + /// Unused for JSON Serialization + /// + public string Namespace { get; set; } + + /// + /// Content type for serialized content + /// + public string ContentType + { + get => "application/json"; + set + { + } + } + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api.Client/packages.config b/Nop.Plugin.Api.Client/packages.config new file mode 100644 index 0000000..3427091 --- /dev/null +++ b/Nop.Plugin.Api.Client/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Nop.Plugin.Api/ApiPlugin.cs b/Nop.Plugin.Api/ApiPlugin.cs index 450f753..a4daf2a 100644 --- a/Nop.Plugin.Api/ApiPlugin.cs +++ b/Nop.Plugin.Api/ApiPlugin.cs @@ -11,6 +11,7 @@ using Nop.Core; using Nop.Core.Infrastructure; using Nop.Core.Plugins; +using Nop.Plugin.Api.Data; using Nop.Plugin.Api.Domain; using Nop.Services.Configuration; using Nop.Services.Localization; @@ -20,14 +21,16 @@ namespace Nop.Plugin.Api { public class ApiPlugin : BasePlugin, IAdminMenuPlugin { + private readonly ApiObjectContext _objectContext; private readonly ILocalizationService _localizationService; private readonly ISettingService _settingService; private readonly IWebHelper _webHelper; private readonly IWorkContext _workContext; - public ApiPlugin(ISettingService settingService, IWorkContext workContext, + public ApiPlugin(ApiObjectContext objectContext, ISettingService settingService, IWorkContext workContext, ILocalizationService localizationService, IWebHelper webHelper) { + _objectContext = objectContext; _settingService = settingService; _workContext = workContext; _localizationService = localizationService; @@ -36,6 +39,7 @@ public ApiPlugin(ISettingService settingService, IWorkContext workContext, public override void Install() { + //locales _localizationService.AddOrUpdatePluginLocaleResource("Plugins.Api", "Api plugin"); _localizationService.AddOrUpdatePluginLocaleResource("Plugins.Api.Admin.Menu.ManageClients", @@ -129,6 +133,7 @@ public override void Install() public override void Uninstall() { + var persistedGrantMigrator = EngineContext.Current.Resolve().GetService(); persistedGrantMigrator.Migrate("0"); diff --git a/Nop.Plugin.Api/ApiStartup.cs b/Nop.Plugin.Api/ApiStartup.cs index e76540e..15a45f6 100644 --- a/Nop.Plugin.Api/ApiStartup.cs +++ b/Nop.Plugin.Api/ApiStartup.cs @@ -17,16 +17,19 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Nop.Core.Configuration; using Nop.Core.Data; using Nop.Core.Infrastructure; using Nop.Plugin.Api.Authorization.Policies; using Nop.Plugin.Api.Authorization.Requirements; using Nop.Plugin.Api.Constants; +using Nop.Plugin.Api.Data; using Nop.Plugin.Api.Helpers; using Nop.Plugin.Api.IdentityServer.Endpoints; using Nop.Plugin.Api.IdentityServer.Generators; using Nop.Plugin.Api.IdentityServer.Middlewares; using Nop.Web.Framework.Infrastructure; +using Nop.Web.Framework.Infrastructure.Extensions; using ApiResource = IdentityServer4.EntityFramework.Entities.ApiResource; namespace Nop.Plugin.Api @@ -46,6 +49,30 @@ public void ConfigureServices(IServiceCollection services, IConfiguration config AddTokenGenerationPipeline(services); AddAuthorizationPipeline(services); + + //add object context + services.AddDbContext(optionsBuilder => + { + var nopConfig = services.BuildServiceProvider().GetRequiredService(); + var dataSettings = DataSettingsManager.LoadSettings(); + if (!dataSettings?.IsValid ?? true) + { + return; + } + + optionsBuilder.UseSqlServerWithLazyLoading(services); + + //optionsBuilder.UseSqlServer(dataSettings.DataConnectionString, + // providerOptions => providerOptions.CommandTimeout(60)); + + //optionsBuilder.UseLazyLoadingProxies(false); + //optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); + + if (nopConfig.UseRowNumberForPaging) + optionsBuilder.UseSqlServer(dataSettings.DataConnectionString, option => option.UseRowNumberForPaging()); + else + optionsBuilder.UseSqlServer(dataSettings.DataConnectionString); + }); } public void Configure(IApplicationBuilder app) diff --git a/Nop.Plugin.Api/AutoMapper/AutoMapperApiConfiguration.cs b/Nop.Plugin.Api/AutoMapper/AutoMapperApiConfiguration.cs index 4da7c09..9cad1ce 100644 --- a/Nop.Plugin.Api/AutoMapper/AutoMapperApiConfiguration.cs +++ b/Nop.Plugin.Api/AutoMapper/AutoMapperApiConfiguration.cs @@ -12,7 +12,7 @@ public static class AutoMapperApiConfiguration public static MapperConfigurationExpression MapperConfigurationExpression => s_mapperConfigurationExpression ?? (s_mapperConfigurationExpression = new MapperConfigurationExpression()); - public static IMapper Mapper + private static IMapper Mapper { get { diff --git a/Nop.Plugin.Api/DTOs/Products/ProductDto.cs b/Nop.Plugin.Api/DTOs/Products/ProductDto.cs index 7edf2b9..390aa61 100644 --- a/Nop.Plugin.Api/DTOs/Products/ProductDto.cs +++ b/Nop.Plugin.Api/DTOs/Products/ProductDto.cs @@ -4,15 +4,18 @@ using Newtonsoft.Json; using Nop.Core.Domain.Catalog; using Nop.Plugin.Api.Attributes; +using Nop.Plugin.Api.DTOs.Base; +using Nop.Plugin.Api.DTOs.Categories; using Nop.Plugin.Api.DTOs.Images; using Nop.Plugin.Api.DTOs.Languages; +using Nop.Plugin.Api.DTOs.SpecificationAttributes; using Nop.Plugin.Api.Validators; namespace Nop.Plugin.Api.DTOs.Products { [JsonObject(Title = "product")] [Validator(typeof(ProductDtoValidator))] - public class ProductDto + public class ProductDto : BaseDto { private int? _productTypeId; private List _storeIds; @@ -22,14 +25,11 @@ public class ProductDto private List _localizedNames; private List _images; private List _productAttributeMappings; + private List _productAttributeCombinations; + private List _productSpecificationAttributes; private List _associatedProductIds; private List _tags; - - /// - /// Gets or sets the product id - /// - [JsonProperty("id")] - public string Id { get; set; } + private List _categories; /// /// Gets or sets the values indicating whether this product is visible in catalog or search results. @@ -593,6 +593,33 @@ public List ProductAttributeMappings } } + [JsonProperty("product_attribute_combinations")] + public List ProductAttributeCombinations + { + get + { + return _productAttributeCombinations; + } + set + { + _productAttributeCombinations = value; + } + } + + + [JsonProperty("product_specification_attributes")] + public List ProductSpecificationAttributes + { + get + { + return _productSpecificationAttributes; + } + set + { + _productSpecificationAttributes = value; + } + } + [JsonProperty("associated_product_ids")] public List AssociatedProductIds { @@ -619,6 +646,19 @@ public List Tags } } + [JsonProperty("categories")] + public List Categories + { + get + { + return _categories; + } + set + { + _categories = value; + } + } + [ValidateVendor] [JsonProperty("vendor_id")] public int? VendorId { get; set; } diff --git a/Nop.Plugin.Api/Data/ApiObjectContext.cs b/Nop.Plugin.Api/Data/ApiObjectContext.cs new file mode 100644 index 0000000..b83cf44 --- /dev/null +++ b/Nop.Plugin.Api/Data/ApiObjectContext.cs @@ -0,0 +1,182 @@ +using System; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Nop.Core; +using Nop.Data; +using Nop.Data.Mapping; + +namespace Nop.Plugin.Api.Data +{ + public class ApiObjectContext : DbContext, IDbContext + { + #region Ctor + + + public ApiObjectContext(DbContextOptions options) : base(options) + { + } + + #endregion + + #region Utilities + + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + options.ConfigureWarnings(a => a.Ignore(CoreEventId.DetachedLazyLoadingWarning)); + + base.OnConfiguring(options); + } + + /// + /// Further configuration the model + /// + /// The builder being used to construct the model for this context + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + var nopDataAssembly = Assembly.GetAssembly(typeof(NopObjectContext)); + + //dynamically load all entity and query type configurations + var typeConfigurations = nopDataAssembly.GetTypes().Where(type => + (type.BaseType?.IsGenericType ?? false) + && (type.BaseType.GetGenericTypeDefinition() == typeof(NopEntityTypeConfiguration<>) + || type.BaseType.GetGenericTypeDefinition() == typeof(NopQueryTypeConfiguration<>))); + + foreach (var typeConfiguration in typeConfigurations) + { + var configuration = (IMappingConfiguration)Activator.CreateInstance(typeConfiguration); + configuration.ApplyConfiguration(modelBuilder); + } + + base.OnModelCreating(modelBuilder); + } + + /// + /// Modify the input SQL query by adding passed parameters + /// + /// The raw SQL query + /// The values to be assigned to parameters + /// Modified raw SQL query + protected virtual string CreateSqlWithParameters(string sql, params object[] parameters) + { + //add parameters to sql + for (var i = 0; i <= (parameters?.Length ?? 0) - 1; i++) + { + if (parameters == null || !(parameters[i] is DbParameter parameter)) + { + continue; + } + + sql = $"{sql}{(i > 0 ? "," : string.Empty)} @{parameter.ParameterName}"; + + //whether parameter is output + if (parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Output) + sql = $"{sql} output"; + } + + return sql; + } + + #endregion + + #region Methods + + /// + /// Creates a DbSet that can be used to query and save instances of entity + /// + /// Entity type + /// A set for the given entity type + public new virtual DbSet Set() where TEntity : BaseEntity + { + return base.Set(); + } + + /// + /// Generate a script to create all tables for the current model + /// + /// A SQL script + public virtual string GenerateCreateScript() + { + return Database.GenerateCreateScript(); + } + + /// + /// Creates a LINQ query for the query type based on a raw SQL query + /// + /// Query type + /// The raw SQL query + /// An IQueryable representing the raw SQL query + public virtual IQueryable QueryFromSql(string sql) where TQuery : class + { + return Query().FromSql(sql); + } + + /// + /// Creates a LINQ query for the entity based on a raw SQL query + /// + /// Entity type + /// The raw SQL query + /// The values to be assigned to parameters + /// An IQueryable representing the raw SQL query + public virtual IQueryable EntityFromSql(string sql, params object[] parameters) where TEntity : BaseEntity + { + return Set().FromSql(CreateSqlWithParameters(sql, parameters), parameters); + } + + /// + /// Executes the given SQL against the database + /// + /// The SQL to execute + /// true - the transaction creation is not ensured; false - the transaction creation is ensured. + /// The timeout to use for command. Note that the command timeout is distinct from the connection timeout, which is commonly set on the database connection string + /// Parameters to use with the SQL + /// The number of rows affected + public virtual int ExecuteSqlCommand(RawSqlString sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters) + { + //set specific command timeout + var previousTimeout = Database.GetCommandTimeout(); + Database.SetCommandTimeout(timeout); + + int result; + if (!doNotEnsureTransaction) + { + //use with transaction + using (var transaction = Database.BeginTransaction()) + { + result = Database.ExecuteSqlCommand(sql, parameters); + transaction.Commit(); + } + } + else + result = Database.ExecuteSqlCommand(sql, parameters); + + //return previous timeout back + Database.SetCommandTimeout(previousTimeout); + + return result; + } + + /// + /// Detach an entity from the context + /// + /// Entity type + /// Entity + public virtual void Detach(TEntity entity) where TEntity : BaseEntity + { + if (entity == null) + throw new ArgumentNullException(nameof(entity)); + + var entityEntry = Entry(entity); + if (entityEntry == null) + return; + + //set the entity is not being tracked by the context + entityEntry.State = EntityState.Detached; + } + + #endregion + } +} \ No newline at end of file diff --git a/Nop.Plugin.Api/Helpers/DTOHelper.cs b/Nop.Plugin.Api/Helpers/DTOHelper.cs index 009ac87..a14c054 100644 --- a/Nop.Plugin.Api/Helpers/DTOHelper.cs +++ b/Nop.Plugin.Api/Helpers/DTOHelper.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using Nop.Core.Domain.Catalog; +using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Directory; using Nop.Core.Domain.Localization; using Nop.Core.Domain.Media; @@ -11,9 +9,11 @@ using Nop.Plugin.Api.DTOs.Languages; using Nop.Plugin.Api.DTOs.OrderItems; using Nop.Plugin.Api.DTOs.Orders; +using Nop.Plugin.Api.DTOs.Manufacturers; using Nop.Plugin.Api.DTOs.ProductAttributes; using Nop.Plugin.Api.DTOs.Products; using Nop.Plugin.Api.DTOs.ShoppingCarts; +using Nop.Plugin.Api.DTOs.SpecificationAttributes; using Nop.Plugin.Api.DTOs.Stores; using Nop.Plugin.Api.MappingExtensions; using Nop.Plugin.Api.Services; @@ -24,6 +24,8 @@ using Nop.Services.Security; using Nop.Services.Seo; using Nop.Services.Stores; +using System.Collections.Generic; +using System.Linq; namespace Nop.Plugin.Api.Helpers { @@ -80,7 +82,6 @@ public ProductDto PrepareProductDTO(Product product) var productDto = product.ToDto(); PrepareProductImages(product.ProductPictures, productDto); - PrepareProductAttributes(product.ProductAttributeMappings, productDto); productDto.SeName = _urlRecordService.GetSeName(product); productDto.DiscountIds = product.AppliedDiscounts.Select(discount => discount.Id).ToList(); @@ -90,7 +91,8 @@ public ProductDto PrepareProductDTO(Product product) .ToList(); productDto.Tags = _productTagService.GetAllProductTagsByProductId(product.Id).Select(tag => tag.Name) .ToList(); - + productDto.Categories = product.ProductCategories.Select(c => PrepareCategoryDTO(c.Category)).ToList(); + productDto.AssociatedProductIds = _productService.GetAssociatedProducts(product.Id, showHidden: true) .Select(associatedProduct => associatedProduct.Id) @@ -105,7 +107,7 @@ public ProductDto PrepareProductDTO(Product product) var localizedNameDto = new LocalizedNameDto { LanguageId = language.Id, - LocalizedName = _localizationService.GetLocalized(product, x => x.Name, language.Id, false, false) + LocalizedName = _localizationService.GetLocalized(product, x => x.Name, language.Id) }; productDto.LocalizedNames.Add(localizedNameDto); @@ -141,7 +143,7 @@ public CategoryDto PrepareCategoryDTO(Category category) var localizedNameDto = new LocalizedNameDto { LanguageId = language.Id, - LocalizedName = _localizationService.GetLocalized(category, x => x.Name, language.Id, false, false) + LocalizedName = _localizationService.GetLocalized(category, x => x.Name, language.Id) }; categoryDto.LocalizedNames.Add(localizedNameDto); @@ -154,7 +156,7 @@ public OrderDto PrepareOrderDTO(Order order) { var orderDto = order.ToDto(); - orderDto.OrderItemDtos = order.OrderItems.Select(PrepareOrderItemDTO).ToList(); + orderDto.OrderItems = order.OrderItems.Select(PrepareOrderItemDTO).ToList(); var customerDto = _customerApiService.GetCustomerById(order.Customer.Id); @@ -236,6 +238,7 @@ private void PrepareProductImages(IEnumerable productPictures, P var productImageDto = new ImageMappingDto { Id = productPicture.Id, + PictureId = productPicture.PictureId, Position = productPicture.DisplayOrder, Src = imageDto.Src, Attachment = imageDto.Attachment @@ -342,5 +345,87 @@ private ProductAttributeValueDto PrepareProductAttributeValueDto(ProductAttribut return productAttributeValueDto; } + + private void PrepareProductAttributeCombinations(IEnumerable productAttributeCombinations, + ProductDto productDto) + { + productDto.ProductAttributeCombinations = productDto.ProductAttributeCombinations ?? new List(); + + foreach (var productAttributeCombination in productAttributeCombinations) + { + var productAttributeCombinationDto = PrepareProductAttributeCombinationDto(productAttributeCombination); + if (productAttributeCombinationDto != null) + { + productDto.ProductAttributeCombinations.Add(productAttributeCombinationDto); + } + } + } + + private ProductAttributeCombinationDto PrepareProductAttributeCombinationDto(ProductAttributeCombination productAttributeCombination) + { + return productAttributeCombination.ToDto(); + } + + public void PrepareProductSpecificationAttributes(IEnumerable productSpecificationAttributes, ProductDto productDto) + { + if (productDto.ProductSpecificationAttributes == null) + productDto.ProductSpecificationAttributes = new List(); + + foreach (var productSpecificationAttribute in productSpecificationAttributes) + { + ProductSpecificationAttributeDto productSpecificationAttributeDto = PrepareProductSpecificationAttributeDto(productSpecificationAttribute); + + if (productSpecificationAttributeDto != null) + { + productDto.ProductSpecificationAttributes.Add(productSpecificationAttributeDto); + } + } + } + + public ProductSpecificationAttributeDto PrepareProductSpecificationAttributeDto(ProductSpecificationAttribute productSpecificationAttribute) + { + return productSpecificationAttribute.ToDto(); + } + + public SpecificationAttributeDto PrepareSpecificationAttributeDto(SpecificationAttribute specificationAttribute) + { + return specificationAttribute.ToDto(); + } + + public ManufacturerDto PrepareManufacturerDto(Manufacturer manufacturer) + { + var manufacturerDto = manufacturer.ToDto(); + + var picture = _pictureService.GetPictureById(manufacturer.PictureId); + var imageDto = PrepareImageDto(picture); + + if (imageDto != null) + { + manufacturerDto.Image = imageDto; + } + + manufacturerDto.SeName = _urlRecordService.GetSeName(manufacturer); + manufacturerDto.DiscountIds = manufacturer.AppliedDiscounts.Select(discount => discount.Id).ToList(); + manufacturerDto.RoleIds = _aclService.GetAclRecords(manufacturer).Select(acl => acl.CustomerRoleId).ToList(); + manufacturerDto.StoreIds = _storeMappingService.GetStoreMappings(manufacturer).Select(mapping => mapping.StoreId) + .ToList(); + + var allLanguages = _languageService.GetAllLanguages(); + + manufacturerDto.LocalizedNames = new List(); + + foreach (var language in allLanguages) + { + var localizedNameDto = new LocalizedNameDto + { + LanguageId = language.Id, + LocalizedName = _localizationService.GetLocalized(manufacturer, x => x.Name, language.Id) + }; + + manufacturerDto.LocalizedNames.Add(localizedNameDto); + } + + return manufacturerDto; + } } } \ No newline at end of file diff --git a/Nop.Plugin.Api/Infrastructure/DependencyRegister.cs b/Nop.Plugin.Api/Infrastructure/DependencyRegister.cs index 8fcb864..04f781f 100644 --- a/Nop.Plugin.Api/Infrastructure/DependencyRegister.cs +++ b/Nop.Plugin.Api/Infrastructure/DependencyRegister.cs @@ -1,26 +1,36 @@ -using Autofac; +using System; +using Autofac; +using Autofac.Core; +using Microsoft.EntityFrameworkCore; using Nop.Core.Configuration; +using Nop.Core.Data; +using Nop.Core.Domain.Catalog; +using Nop.Core.Domain.Common; +using Nop.Core.Domain.Customers; +using Nop.Core.Domain.Messages; +using Nop.Core.Domain.Orders; +using Nop.Core.Domain.Vendors; using Nop.Core.Infrastructure; using Nop.Core.Infrastructure.DependencyManagement; +using Nop.Data; +using Nop.Plugin.Api.Converters; +using Nop.Plugin.Api.Data; +using Nop.Plugin.Api.Factories; +using Nop.Plugin.Api.Helpers; +using Nop.Plugin.Api.JSON.Serializers; +using Nop.Plugin.Api.Maps; +using Nop.Plugin.Api.ModelBinders; using Nop.Plugin.Api.Services; +using Nop.Plugin.Api.Validators; +using Nop.Web.Framework.Infrastructure.Extensions; + namespace Nop.Plugin.Api.Infrastructure { - using System; - using Nop.Core.Domain.Catalog; - using Nop.Core.Domain.Common; - using Nop.Core.Domain.Customers; - using Nop.Core.Domain.Orders; - using Converters; - using Factories; - using Helpers; - using JSON.Serializers; - using ModelBinders; - using Validators; - - public class DependencyRegister : IDependencyRegistrar { + private const string ObjectContextName = "nop_object_context_web_api"; + public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config) { RegisterPluginServices(builder); @@ -28,6 +38,8 @@ public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig RegisterModelBinders(builder); } + public virtual int Order => 1; + private void RegisterModelBinders(ContainerBuilder builder) { builder.RegisterGeneric(typeof(ParametersModelBinder<>)).InstancePerLifetimeScope(); @@ -40,14 +52,19 @@ private void RegisterPluginServices(ContainerBuilder builder) builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As() + .InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As() + .InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As() + .InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As() + .InstancePerLifetimeScope(); + builder.RegisterType().As() + .InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); @@ -59,7 +76,7 @@ private void RegisterPluginServices(ContainerBuilder builder) builder.RegisterType().As().InstancePerLifetimeScope(); - + builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); @@ -70,12 +87,57 @@ private void RegisterPluginServices(ContainerBuilder builder) builder.RegisterType().As>().InstancePerLifetimeScope(); builder.RegisterType().As>().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); - } + builder.RegisterType().As().InstancePerLifetimeScope(); + + // data access + + builder.RegisterPluginDataContext(ObjectContextName); + + + // Repositories + + builder.RegisterType>() + .WithParameter(ResolvedParameter.ForNamed(ObjectContextName)) + .InstancePerLifetimeScope() + .Named>(ObjectContextName); + + builder.RegisterType>() + .WithParameter(ResolvedParameter.ForNamed(ObjectContextName)) + .InstancePerLifetimeScope() + .Named>(ObjectContextName); + + builder.RegisterType>() + .WithParameter(ResolvedParameter.ForNamed(ObjectContextName)) + .InstancePerLifetimeScope() + .Named>(ObjectContextName); + + builder.RegisterType>() + .WithParameter(ResolvedParameter.ForNamed(ObjectContextName)) + .InstancePerLifetimeScope() + .Named>(ObjectContextName); + + //TODO: Add the others + + + // Services + builder.RegisterType() + .As() + .WithParameter(ResolvedParameter.ForNamed>(ObjectContextName)) + .InstancePerLifetimeScope(); + + builder.RegisterType() + .As() + .WithParameter(ResolvedParameter.ForNamed>(ObjectContextName)) + .WithParameter(ResolvedParameter.ForNamed>(ObjectContextName)) + .WithParameter(ResolvedParameter.ForNamed>(ObjectContextName)) + .InstancePerLifetimeScope(); + + + //TODO: Add the others + + - public virtual int Order - { - get { return Int16.MaxValue; } } + } } \ No newline at end of file diff --git a/Nop.Plugin.Api/Services/CustomerApiService.cs b/Nop.Plugin.Api/Services/CustomerApiService.cs index a4de76b..42c9c58 100644 --- a/Nop.Plugin.Api/Services/CustomerApiService.cs +++ b/Nop.Plugin.Api/Services/CustomerApiService.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Linq.Dynamic.Core; using System.Text.RegularExpressions; +using Microsoft.EntityFrameworkCore; using Nop.Core; using Nop.Core.Domain.Common; using Nop.Plugin.Api.Constants; @@ -82,7 +83,7 @@ public IList Search(string queryParams = "", string order = Configu if (searchParams != null) { - var query = _customerRepository.Table.Where(customer => !customer.Deleted); + var query = GetQuery().Where(customer => !customer.Deleted); foreach (var searchParam in searchParams) { @@ -116,7 +117,7 @@ public Dictionary GetFirstAndLastNameByCustomerId(int customerId public Customer GetCustomerEntityById(int id) { - var customer = _customerRepository.Table.FirstOrDefault(c => c.Id == id && !c.Deleted); + var customer = GetQuery().FirstOrDefault(c => c.Id == id && !c.Deleted); return customer; } @@ -125,9 +126,9 @@ public CustomerDto GetCustomerById(int id, bool showDeleted = false) { if (id == 0) return null; - + // Here we expect to get two records, one for the first name and one for the last name. - var customerAttributeMappings = (from customer in _customerRepository.Table //NoTracking + var customerAttributeMappings = (from customer in GetQuery() join attribute in _genericAttributeRepository.Table//NoTracking on customer.Id equals attribute.EntityId where customer.Id == id && @@ -207,7 +208,7 @@ on customer.Id equals attribute.EntityId else { // This is when we do not have first and last name set. - var currentCustomer = _customerRepository.Table.FirstOrDefault(customer => customer.Id == id); + var currentCustomer = GetQuery().FirstOrDefault(customer => customer.Id == id); if (currentCustomer != null) { @@ -222,7 +223,22 @@ on customer.Id equals attribute.EntityId return customerDto; } - + + private IQueryable GetQuery() + { + var query = _customerRepository.TableNoTracking; + + query = query.Include(c => c.BillingAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.BillingAddress).ThenInclude(m => m.StateProvince); + query = query.Include(c => c.ShippingAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.ShippingAddress).ThenInclude(m => m.StateProvince); + query = query.Include(c => c.CustomerCustomerRoleMappings).ThenInclude(m => m.CustomerRole); + query = query.Include(c => c.ShoppingCartItems).ThenInclude(m => m.Product); + query = query.Include(c => c.ReturnRequests); + query = query.Include(c => c.CustomerAddressMappings); + + return query; + } private Dictionary EnsureSearchQueryIsValid(string query, Func> parseSearchQuery) { if (!string.IsNullOrEmpty(query)) @@ -427,8 +443,7 @@ where @group.Select(x => x.Attribute) private IQueryable GetCustomersQuery(DateTime? createdAtMin = null, DateTime? createdAtMax = null, int sinceId = 0) { - var query = _customerRepository.Table //NoTracking - .Where(customer => !customer.Deleted && !customer.IsSystemAccount && customer.Active); + var query = GetQuery().Where(customer => !customer.Deleted && !customer.IsSystemAccount && customer.Active); query = query.Where(customer => !customer.CustomerRoles.Any(cr => (cr.Active) && (cr.SystemName == NopCustomerDefaults.GuestsRoleName)) && (customer.RegisteredInStoreId == 0 || customer.RegisteredInStoreId == _storeContext.CurrentStore.Id)); @@ -518,7 +533,7 @@ private IEnumerable GetAllNewsletterCustomersEmails() { return _cacheManager.Get(Configurations.NEWSLETTER_SUBSCRIBERS_KEY, () => { - IEnumerable subscriberEmails = (from nls in _subscriptionRepository.TableNoTracking + IEnumerable subscriberEmails = (from nls in _subscriptionRepository.Table where nls.StoreId == _storeContext.CurrentStore.Id && nls.Active select nls.Email).ToList(); diff --git a/Nop.Plugin.Api/Services/OrderApiService.cs b/Nop.Plugin.Api/Services/OrderApiService.cs index 9c4c03c..1f74866 100644 --- a/Nop.Plugin.Api/Services/OrderApiService.cs +++ b/Nop.Plugin.Api/Services/OrderApiService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.EntityFrameworkCore; using Nop.Core.Data; using Nop.Core.Domain.Orders; using Nop.Core.Domain.Payments; @@ -21,7 +22,7 @@ public OrderApiService(IRepository orderRepository) public IList GetOrdersByCustomerId(int customerId) { - var query = from order in _orderRepository.Table + var query = from order in GetQuery() where order.CustomerId == customerId && !order.Deleted orderby order.Id select order; @@ -49,7 +50,7 @@ public Order GetOrderById(int orderId) if (orderId <= 0) return null; - return _orderRepository.Table.FirstOrDefault(order => order.Id == orderId && !order.Deleted); + return GetQuery().FirstOrDefault(order => order.Id == orderId && !order.Deleted); } public int GetOrdersCount(DateTime? createdAtMin = null, DateTime? createdAtMax = null, OrderStatus? status = null, @@ -61,11 +62,51 @@ public int GetOrdersCount(DateTime? createdAtMin = null, DateTime? createdAtMax return query.Count(); } + private IQueryable GetQuery() + { + var query = _orderRepository.TableNoTracking; + + query = query.Include(c => c.Customer).ThenInclude(c => c.BillingAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.Customer).ThenInclude(c => c.BillingAddress).ThenInclude(m => m.StateProvince); + query = query.Include(c => c.Customer).ThenInclude(c => c.ShippingAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.Customer).ThenInclude(c => c.ShippingAddress) + .ThenInclude(m => m.StateProvince); + + + query = query.Include(c => c.BillingAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.BillingAddress).ThenInclude(m => m.StateProvince); + + query = query.Include(c => c.ShippingAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.ShippingAddress).ThenInclude(m => m.StateProvince); + + query = query.Include(c => c.PickupAddress).ThenInclude(m => m.Country); + query = query.Include(c => c.PickupAddress).ThenInclude(m => m.StateProvince); + + + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product); + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product) + .ThenInclude(m => m.ProductProductTagMappings); + query = query.Include(c => c.OrderItems) + .ThenInclude(m => m.Product) + .ThenInclude(m => m.ProductProductTagMappings) + .ThenInclude(m => m.ProductTag); + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product).ThenInclude(m => m.ProductCategories); + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product).ThenInclude(m => m.ProductManufacturers); + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product).ThenInclude(m => m.ProductPictures).ThenInclude(m => m.Picture); + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product).ThenInclude(m => m.ProductSpecificationAttributes); + query = query.Include(c => c.OrderItems).ThenInclude(m => m.Product).ThenInclude(m => m.ProductAttributeMappings); + + + query = query.Include(c => c.Shipments).ThenInclude(m => m.ShipmentItems).ThenInclude(m => m.Shipment); + + return query; + } + private IQueryable GetOrdersQuery(DateTime? createdAtMin = null, DateTime? createdAtMax = null, OrderStatus? status = null, PaymentStatus? paymentStatus = null, ShippingStatus? shippingStatus = null, IList ids = null, int? customerId = null, int? storeId = null) { - var query = _orderRepository.Table; + var query = GetQuery(); if (customerId != null) { @@ -110,17 +151,7 @@ private IQueryable GetOrdersQuery(DateTime? createdAtMin = null, DateTime } query = query.OrderBy(order => order.Id); - - //query = query.Include(c => c.Customer); - //query = query.Include(c => c.BillingAddress); - //query = query.Include(c => c.ShippingAddress); - //query = query.Include(c => c.PickupAddress); - //query = query.Include(c => c.RedeemedRewardPointsEntry); - //query = query.Include(c => c.DiscountUsageHistory); - //query = query.Include(c => c.GiftCardUsageHistory); - //query = query.Include(c => c.OrderNotes); - //query = query.Include(c => c.OrderItems); - //query = query.Include(c => c.Shipments); + return query; }