diff --git a/Nop.Plugin.Api/Controllers/CustomersController.cs b/Nop.Plugin.Api/Controllers/CustomersController.cs index 0b9a81c..f3e2622 100644 --- a/Nop.Plugin.Api/Controllers/CustomersController.cs +++ b/Nop.Plugin.Api/Controllers/CustomersController.cs @@ -306,7 +306,7 @@ public IActionResult CreateCustomer([ModelBinder(typeof(JsonModelBinder _factory; + private readonly IEncryptionService _encryptionService; // We resolve the order settings this way because of the tests. // The auto mocking does not support concreate types as dependencies. It supports only interfaces. @@ -78,10 +78,10 @@ public OrdersController(IOrderApiService orderApiService, IStoreContext storeContext, IShippingService shippingService, IPictureService pictureService, - IDTOHelper dtoHelper, - IProductAttributeConverter productAttributeConverter) + IEncryptionService encryptionService, + IDTOHelper dtoHelper) : base(jsonFieldsSerializer, aclService, customerService, storeMappingService, - storeService, discountService, customerActivityService, localizationService,pictureService) + storeService, discountService, customerActivityService, localizationService, pictureService) { _orderApiService = orderApiService; _factory = factory; @@ -93,7 +93,7 @@ public OrdersController(IOrderApiService orderApiService, _shippingService = shippingService; _dtoHelper = dtoHelper; _productService = productService; - _productAttributeConverter = productAttributeConverter; + _encryptionService = encryptionService; } /// @@ -197,6 +197,12 @@ public IActionResult GetOrderById(int id, string fields = "") var ordersRootObject = new OrdersRootObject(); + string decryptedCardNumber = _encryptionService.DecryptText(order.MaskedCreditCardNumber); + if (!string.IsNullOrWhiteSpace(decryptedCardNumber)) + { + order.CardNumber = decryptedCardNumber; + } + var orderDto = _dtoHelper.PrepareOrderDTO(order); ordersRootObject.Orders.Add(orderDto); @@ -212,7 +218,7 @@ public IActionResult GetOrderById(int id, string fields = "") /// OK /// Unauthorized [HttpGet] - [Route("/api/orders/customer/{customer_id}")] + [Route("/api/orders/customer/{customerid}")] [ProducesResponseType(typeof(OrdersRootObject), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)] [GetRequestsErrorInterceptorActionFilter] @@ -250,7 +256,7 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder)) // We doesn't have to check for value because this is done by the order validator. var customer = CustomerService.GetCustomerById(orderDelta.Dto.CustomerId.Value); - + if (customer == null) { return Error(HttpStatusCode.NotFound, "customer", "not found"); @@ -276,9 +282,9 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder)) isValid &= SetShippingOption(orderDelta.Dto.ShippingRateComputationMethodSystemName, orderDelta.Dto.ShippingMethod, orderDelta.Dto.StoreId ?? _storeContext.CurrentStore.Id, - customer, - BuildShoppingCartItemsFromOrderItemDtos(orderDelta.Dto.OrderItems.ToList(), - customer.Id, + customer, + BuildShoppingCartItemsFromOrderItemDtos(orderDelta.Dto.OrderItems.ToList(), + customer.Id, orderDelta.Dto.StoreId ?? _storeContext.CurrentStore.Id)); if (!isValid) @@ -290,8 +296,11 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder)) var newOrder = _factory.Initialize(); orderDelta.Merge(newOrder); - customer.BillingAddress = newOrder.BillingAddress; - customer.ShippingAddress = newOrder.ShippingAddress; + if (newOrder.BillingAddress != null) + customer.BillingAddressId = newOrder.BillingAddress.Id; + if (newOrder.ShippingAddress != null) + customer.ShippingAddressId = newOrder.ShippingAddress.Id; + CustomerService.UpdateCustomer(customer); // If the customer has something in the cart it will be added too. Should we clear the cart first? newOrder.Customer = customer; @@ -301,7 +310,7 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder)) { newOrder.StoreId = _storeContext.CurrentStore.Id; } - + var placeOrderResult = PlaceOrder(newOrder, customer); if (!placeOrderResult.Success) @@ -342,7 +351,7 @@ public IActionResult DeleteOrder(int id) { return Error(HttpStatusCode.BadRequest, "id", "invalid id"); } - + var orderToDelete = _orderApiService.GetOrderById(id); if (orderToDelete == null) @@ -394,7 +403,7 @@ public IActionResult UpdateOrder([ModelBinder(typeof(JsonModelBinder)) var storeId = orderDelta.Dto.StoreId ?? _storeContext.CurrentStore.Id; isValid &= SetShippingOption(orderDelta.Dto.ShippingRateComputationMethodSystemName ?? currentOrder.ShippingRateComputationMethodSystemName, - orderDelta.Dto.ShippingMethod, + orderDelta.Dto.ShippingMethod, storeId, customer, BuildShoppingCartItemsFromOrderItems(currentOrder.OrderItems.ToList(), customer.Id, storeId)); } @@ -410,7 +419,7 @@ public IActionResult UpdateOrder([ModelBinder(typeof(JsonModelBinder)) } orderDelta.Merge(currentOrder); - + customer.BillingAddress = currentOrder.BillingAddress; customer.ShippingAddress = currentOrder.ShippingAddress; @@ -431,6 +440,43 @@ public IActionResult UpdateOrder([ModelBinder(typeof(JsonModelBinder)) return new RawJsonActionResult(json); } + [HttpGet] + [Route("/api/order/{orderGuid}")] + [ProducesResponseType(typeof(OrdersRootObject), (int)HttpStatusCode.OK)] + [ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)] + [ProducesResponseType(typeof(ErrorsRootObject), (int)HttpStatusCode.BadRequest)] + [ProducesResponseType(typeof(string), (int)HttpStatusCode.NotFound)] + [GetRequestsErrorInterceptorActionFilter] + public IActionResult GetOrderByOrderGuid(string orderGuid, string fields = "") + { + if (string.IsNullOrWhiteSpace(orderGuid)) + { + return Error(HttpStatusCode.BadRequest, "orderGuid", "orderGuid"); + } + + var order = _orderApiService.GetOrderByOrderGuid(orderGuid); + + if (order == null) + { + return Error(HttpStatusCode.NotFound, "order", "not found"); + } + + var ordersRootObject = new OrdersRootObject(); + + string decryptedCardNumber = _encryptionService.DecryptText(order.MaskedCreditCardNumber); + if (!string.IsNullOrWhiteSpace(decryptedCardNumber)) + { + order.CardNumber = decryptedCardNumber; + } + + var orderDto = _dtoHelper.PrepareOrderDTO(order); + ordersRootObject.Orders.Add(orderDto); + + var json = JsonFieldsSerializer.Serialize(ordersRootObject,fields); + + return new RawJsonActionResult(json); + } + private bool SetShippingOption(string shippingRateComputationMethodSystemName, string shippingOptionName, int storeId, Customer customer, List shoppingCartItems) { var isValid = true; @@ -459,7 +505,7 @@ private bool SetShippingOption(string shippingRateComputationMethodSystemName, s var shippingOption = shippingOptions .Find(so => !string.IsNullOrEmpty(so.Name) && so.Name.Equals(shippingOptionName, StringComparison.InvariantCultureIgnoreCase)); - + _genericAttributeService.SaveAttribute(customer, NopCustomerDefaults.SelectedShippingOptionAttribute, shippingOption, storeId); @@ -527,11 +573,22 @@ private List BuildShoppingCartItemsFromOrderItemDtos(List orderItems, Customer var attributesXml = _productAttributeConverter.ConvertToXml(orderItem.Attributes.ToList(), product.Id); - var errors = _shoppingCartService.AddToCart(customer, product, - ShoppingCartType.ShoppingCart, storeId,attributesXml, - 0M, orderItem.RentalStartDateUtc, orderItem.RentalEndDateUtc, - orderItem.Quantity ?? 1); + var errors = new List(); + + if (existingItem != null) + { + if (orderItem.Quantity.HasValue + && existingItem.Quantity != orderItem.Quantity) + { + existingItem.Quantity = orderItem.Quantity.Value; + existingItem.RentalStartDateUtc, + existingItem.RentalEndDateUtc)); + } + } + else + { + errors.AddRange(_shoppingCartService.AddToCart(customer, product, + ShoppingCartType.ShoppingCart, storeId, orderItem.AttributesXml, + 0M, orderItem.RentalStartDateUtc, orderItem.RentalEndDateUtc, + orderItem.Quantity ?? 1)); + } if (errors.Count > 0) { @@ -594,5 +666,5 @@ private bool AddOrderItemsToCart(ICollection orderItems, Customer return shouldReturnError; } - } + } } \ No newline at end of file diff --git a/Nop.Plugin.Api/Controllers/ProductsController.cs b/Nop.Plugin.Api/Controllers/ProductsController.cs index 8b1914e..2f635b7 100644 --- a/Nop.Plugin.Api/Controllers/ProductsController.cs +++ b/Nop.Plugin.Api/Controllers/ProductsController.cs @@ -96,8 +96,8 @@ public IActionResult GetProducts(ProductsParametersModel parameters) return Error(HttpStatusCode.BadRequest, "page", "invalid page parameter"); } - var allProducts = _productApiService.GetProducts(parameters.Ids, parameters.CreatedAtMin, parameters.CreatedAtMax, parameters.UpdatedAtMin, - parameters.UpdatedAtMax, parameters.Limit, parameters.Page, parameters.SinceId, parameters.CategoryId, + var allProducts = _productApiService.GetProducts(parameters.Ids, parameters.Skus, parameters.CreatedAtMin, parameters.CreatedAtMax, parameters.UpdatedAtMin, + parameters.UpdatedAtMax, parameters.Limit, parameters.Page, parameters.SinceId, parameters.CategoryId, parameters.IncludeChildren, parameters.VendorName, parameters.PublishedStatus) .Where(p => StoreMappingService.Authorize(p)); diff --git a/Nop.Plugin.Api/Converters/ApiTypeConverter.cs b/Nop.Plugin.Api/Converters/ApiTypeConverter.cs index b27c343..8b697a1 100644 --- a/Nop.Plugin.Api/Converters/ApiTypeConverter.cs +++ b/Nop.Plugin.Api/Converters/ApiTypeConverter.cs @@ -88,6 +88,16 @@ public IList ToListOfInts(string value) return null; } + public IList ToListOfStrings(string value) + { + if (string.IsNullOrEmpty(value)) + { + return null; + } + + return value.Split(",").ToList(); //TODO: this will break if we have commas in the strings + } + public bool? ToStatus(string value) { if (!string.IsNullOrEmpty(value)) diff --git a/Nop.Plugin.Api/Converters/IApiTypeConverter.cs b/Nop.Plugin.Api/Converters/IApiTypeConverter.cs index d1304a1..5a0855a 100644 --- a/Nop.Plugin.Api/Converters/IApiTypeConverter.cs +++ b/Nop.Plugin.Api/Converters/IApiTypeConverter.cs @@ -9,6 +9,7 @@ public interface IApiTypeConverter int ToInt(string value); int? ToIntNullable(string value); IList ToListOfInts(string value); + IList ToListOfStrings(string value); bool? ToStatus(string value); object ToEnumNullable(string value, Type type); } diff --git a/Nop.Plugin.Api/Converters/ObjectConverter.cs b/Nop.Plugin.Api/Converters/ObjectConverter.cs index 0d3c2a3..6515c5f 100644 --- a/Nop.Plugin.Api/Converters/ObjectConverter.cs +++ b/Nop.Plugin.Api/Converters/ObjectConverter.cs @@ -55,6 +55,10 @@ private object To(string value, Type type) { return _apiTypeConverter.ToListOfInts(value); } + else if (type == typeof(List)) + { + return _apiTypeConverter.ToListOfStrings(value); + } else if(type == typeof(bool?)) { // Because currently status is the only boolean and we need to accept published and unpublished statuses. diff --git a/Nop.Plugin.Api/DTOs/Orders/OrderDto.cs b/Nop.Plugin.Api/DTOs/Orders/OrderDto.cs index 317853a..d56463c 100644 --- a/Nop.Plugin.Api/DTOs/Orders/OrderDto.cs +++ b/Nop.Plugin.Api/DTOs/Orders/OrderDto.cs @@ -295,5 +295,28 @@ public ICollection OrderItems /// [JsonProperty("customer_tax_display_type")] public string CustomerTaxDisplayType { get; set; } + + + [JsonProperty("card_type")] + public string CardType { get; set; } + + [JsonProperty("card_name")] + public string CardName { get; set; } + + [JsonProperty("card_number")] + public string CardNumber { get; set; } + + [JsonProperty("card_cvv2")] + public string CardCvv2 { get; set; } + + [JsonProperty("card_expritation_month")] + public string CardExpirationMonth { get; set; } + + [JsonProperty("card_expiration_year")] + public string CardExpirationYear { get; set; } + + [JsonProperty("order_guid")] + public string OrderGuid { get; set; } + } } \ No newline at end of file diff --git a/Nop.Plugin.Api/Models/ProductsParameters/ProductsParametersModel.cs b/Nop.Plugin.Api/Models/ProductsParameters/ProductsParametersModel.cs index 081580f..28ef46e 100644 --- a/Nop.Plugin.Api/Models/ProductsParameters/ProductsParametersModel.cs +++ b/Nop.Plugin.Api/Models/ProductsParameters/ProductsParametersModel.cs @@ -26,6 +26,18 @@ public ProductsParametersModel() [JsonProperty("ids")] public List Ids { get; set; } + /// + /// A list of SKUs + /// + [JsonProperty("skus")] + public List Skus { get; set; } + + /// + /// A list of SKUs + /// + [JsonProperty("include_children")] + public bool IncludeChildren { get; set; } + /// /// Amount of results (default: 50) (maximum: 250) /// diff --git a/Nop.Plugin.Api/Services/IOrderApiService.cs b/Nop.Plugin.Api/Services/IOrderApiService.cs index 8d4684e..b5c9ec7 100644 --- a/Nop.Plugin.Api/Services/IOrderApiService.cs +++ b/Nop.Plugin.Api/Services/IOrderApiService.cs @@ -21,5 +21,6 @@ IList GetOrders(IList ids = null, DateTime? createdAtMin = null, Dat int GetOrdersCount(DateTime? createdAtMin = null, DateTime? createdAtMax = null, OrderStatus? status = null, PaymentStatus? paymentStatus = null, ShippingStatus? shippingStatus = null, int? customerId = null, int? storeId = null); + Order GetOrderByOrderGuid(string orderGuid); } } \ No newline at end of file diff --git a/Nop.Plugin.Api/Services/IProductApiService.cs b/Nop.Plugin.Api/Services/IProductApiService.cs index 6d0f005..30ae5c4 100644 --- a/Nop.Plugin.Api/Services/IProductApiService.cs +++ b/Nop.Plugin.Api/Services/IProductApiService.cs @@ -8,9 +8,10 @@ namespace Nop.Plugin.Api.Services public interface IProductApiService { IList GetProducts(IList ids = null, + IList skus = null, DateTime? createdAtMin = null, DateTime? createdAtMax = null, DateTime? updatedAtMin = null, DateTime? updatedAtMax = null, int limit = Configurations.DefaultLimit, int page = Configurations.DefaultPageValue, int sinceId = Configurations.DefaultSinceId, - int? categoryId = null, string vendorName = null, bool? publishedStatus = null); + int? categoryId = null, bool includeChildren = false, string vendorName = null, bool? publishedStatus = null); int GetProductsCount(DateTime? createdAtMin = null, DateTime? createdAtMax = null, DateTime? updatedAtMin = null, DateTime? updatedAtMax = null, bool? publishedStatus = null, diff --git a/Nop.Plugin.Api/Services/OrderApiService.cs b/Nop.Plugin.Api/Services/OrderApiService.cs index 56b2d9b..be3c418 100644 --- a/Nop.Plugin.Api/Services/OrderApiService.cs +++ b/Nop.Plugin.Api/Services/OrderApiService.cs @@ -124,5 +124,16 @@ private IQueryable GetOrdersQuery(DateTime? createdAtMin = null, DateTime return query; } + + public Order GetOrderByOrderGuid(string orderGuid) + { + Guid ordrGuid; + if (!string.IsNullOrWhiteSpace(orderGuid) + && (Guid.TryParse(orderGuid,out ordrGuid))) + { + return _orderRepository.Table.FirstOrDefault(order => order.OrderGuid == ordrGuid); + } + return null; + } } } \ No newline at end of file diff --git a/Nop.Plugin.Api/Services/ProductApiService.cs b/Nop.Plugin.Api/Services/ProductApiService.cs index 0a55e9e..f44b0de 100644 --- a/Nop.Plugin.Api/Services/ProductApiService.cs +++ b/Nop.Plugin.Api/Services/ProductApiService.cs @@ -29,11 +29,12 @@ public ProductApiService(IRepository productRepository, } public IList GetProducts(IList ids = null, + IList skus = null, DateTime? createdAtMin = null, DateTime? createdAtMax = null, DateTime? updatedAtMin = null, DateTime? updatedAtMax = null, - int limit = Configurations.DefaultLimit, int page = Configurations.DefaultPageValue, int sinceId = Configurations.DefaultSinceId, - int? categoryId = null, string vendorName = null, bool? publishedStatus = null) + int limit = Configurations.DefaultLimit, int page = Configurations.DefaultPageValue, int sinceId = Configurations.DefaultSinceId, + int? categoryId = null, bool includeChildren = false, string vendorName = null, bool? publishedStatus = null) { - var query = GetProductsQuery(createdAtMin, createdAtMax, updatedAtMin, updatedAtMax, vendorName, publishedStatus, ids, categoryId); + var query = GetProductsQuery(createdAtMin, createdAtMax, updatedAtMin, updatedAtMax, vendorName, publishedStatus, ids, skus, categoryId, includeChildren); if (sinceId > 0) { @@ -71,8 +72,7 @@ public Product GetProductByIdNoTracking(int productId) private IQueryable GetProductsQuery(DateTime? createdAtMin = null, DateTime? createdAtMax = null, DateTime? updatedAtMin = null, DateTime? updatedAtMax = null, string vendorName = null, - bool? publishedStatus = null, IList ids = null, int? categoryId = null) - + bool? publishedStatus = null, IList ids = null, IList skus = null, int? categoryId = null, bool includeChildren = false) { var query = _productRepository.Table; @@ -81,6 +81,11 @@ private IQueryable GetProductsQuery(DateTime? createdAtMin = null, Date query = query.Where(c => ids.Contains(c.Id)); } + if (skus != null && skus.Count > 0) + { + query = query.Where(x => skus.Contains(x.Sku)); + } + if (publishedStatus != null) { query = query.Where(c => c.Published == publishedStatus.Value); @@ -128,6 +133,15 @@ join productCategoryMapping in categoryMappingsForProduct on product.Id equals p select product; } + if(includeChildren) + { + var childrenProducts = from childProduct in _productRepository.Table + join product in query on childProduct.ParentGroupedProductId equals product.Id + select childProduct; + + query = query.Union(childrenProducts); + } + query = query.OrderBy(product => product.Id); return query;