Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Product API Enhancements, Order API Bugfix #174

Open
wants to merge 14 commits into
base: nopCommerce_4.10
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Nop.Plugin.Api/Controllers/CustomersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ public IActionResult CreateCustomer([ModelBinder(typeof(JsonModelBinder<Customer

return new RawJsonActionResult(json);
}

[HttpPut]
[Route("/api/customers/{id}")]
[ProducesResponseType(typeof(CustomersRootObject), (int)HttpStatusCode.OK)]
Expand Down
122 changes: 97 additions & 25 deletions Nop.Plugin.Api/Controllers/OrdersController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
Expand Down Expand Up @@ -49,10 +49,10 @@ public class OrdersController : BaseApiController
private readonly IShoppingCartService _shoppingCartService;
private readonly IGenericAttributeService _genericAttributeService;
private readonly IShippingService _shippingService;
private readonly IDTOHelper _dtoHelper;
private readonly IProductAttributeConverter _productAttributeConverter;
private readonly IDTOHelper _dtoHelper;
private readonly IStoreContext _storeContext;
private readonly IFactory<Order> _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.
Expand All @@ -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;
Expand All @@ -93,7 +93,7 @@ public OrdersController(IOrderApiService orderApiService,
_shippingService = shippingService;
_dtoHelper = dtoHelper;
_productService = productService;
_productAttributeConverter = productAttributeConverter;
_encryptionService = encryptionService;
}

/// <summary>
Expand Down Expand Up @@ -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);

Expand All @@ -212,7 +218,7 @@ public IActionResult GetOrderById(int id, string fields = "")
/// <response code="200">OK</response>
/// <response code="401">Unauthorized</response>
[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]
Expand Down Expand Up @@ -250,7 +256,7 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))

// 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");
Expand All @@ -276,9 +282,9 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))
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)
Expand All @@ -290,8 +296,11 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))
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;
Expand All @@ -301,7 +310,7 @@ public IActionResult CreateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))
{
newOrder.StoreId = _storeContext.CurrentStore.Id;
}

var placeOrderResult = PlaceOrder(newOrder, customer);

if (!placeOrderResult.Success)
Expand Down Expand Up @@ -342,7 +351,7 @@ public IActionResult DeleteOrder(int id)
{
return Error(HttpStatusCode.BadRequest, "id", "invalid id");
}

var orderToDelete = _orderApiService.GetOrderById(id);

if (orderToDelete == null)
Expand Down Expand Up @@ -394,7 +403,7 @@ public IActionResult UpdateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))
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));
}
Expand All @@ -410,7 +419,7 @@ public IActionResult UpdateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))
}

orderDelta.Merge(currentOrder);

customer.BillingAddress = currentOrder.BillingAddress;
customer.ShippingAddress = currentOrder.ShippingAddress;

Expand All @@ -431,6 +440,43 @@ public IActionResult UpdateOrder([ModelBinder(typeof(JsonModelBinder<OrderDto>))
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<ShoppingCartItem> shoppingCartItems)
{
var isValid = true;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -527,11 +573,22 @@ private List<ShoppingCartItem> BuildShoppingCartItemsFromOrderItemDtos(List<Orde

private PlaceOrderResult PlaceOrder(Order newOrder, Customer customer)
{
int cardExpirationMonth = 0;
int cardExpirationYear = 0;
int.TryParse(newOrder.CardExpirationMonth, out cardExpirationMonth);
int.TryParse(newOrder.CardExpirationYear, out cardExpirationYear);

var processPaymentRequest = new ProcessPaymentRequest
{
StoreId = newOrder.StoreId,
CustomerId = customer.Id,
PaymentMethodSystemName = newOrder.PaymentMethodSystemName
PaymentMethodSystemName = newOrder.PaymentMethodSystemName,
CreditCardName = newOrder.CardName,
CreditCardNumber = newOrder.CardNumber,
CreditCardType = newOrder.CardType,
CreditCardExpireMonth = cardExpirationMonth,
CreditCardExpireYear = cardExpirationYear,
CreditCardCvv2 = newOrder.CardCvv2,
};


Expand Down Expand Up @@ -575,10 +632,25 @@ private bool AddOrderItemsToCart(ICollection<OrderItemDto> 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<string>();

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)
{
Expand All @@ -594,5 +666,5 @@ private bool AddOrderItemsToCart(ICollection<OrderItemDto> orderItems, Customer

return shouldReturnError;
}
}
}
}
4 changes: 2 additions & 2 deletions Nop.Plugin.Api/Controllers/ProductsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
10 changes: 10 additions & 0 deletions Nop.Plugin.Api/Converters/ApiTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ public IList<int> ToListOfInts(string value)
return null;
}

public IList<string> 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))
Expand Down
1 change: 1 addition & 0 deletions Nop.Plugin.Api/Converters/IApiTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public interface IApiTypeConverter
int ToInt(string value);
int? ToIntNullable(string value);
IList<int> ToListOfInts(string value);
IList<string> ToListOfStrings(string value);
bool? ToStatus(string value);
object ToEnumNullable(string value, Type type);
}
Expand Down
4 changes: 4 additions & 0 deletions Nop.Plugin.Api/Converters/ObjectConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ private object To(string value, Type type)
{
return _apiTypeConverter.ToListOfInts(value);
}
else if (type == typeof(List<string>))
{
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.
Expand Down
23 changes: 23 additions & 0 deletions Nop.Plugin.Api/DTOs/Orders/OrderDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,5 +295,28 @@ public ICollection<OrderItemDto> OrderItems
/// </summary>
[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; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ public ProductsParametersModel()
[JsonProperty("ids")]
public List<int> Ids { get; set; }

/// <summary>
/// A list of SKUs
/// </summary>
[JsonProperty("skus")]
public List<string> Skus { get; set; }

/// <summary>
/// A list of SKUs
/// </summary>
[JsonProperty("include_children")]
public bool IncludeChildren { get; set; }

/// <summary>
/// Amount of results (default: 50) (maximum: 250)
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions Nop.Plugin.Api/Services/IOrderApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ IList<Order> GetOrders(IList<int> 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);
}
}
3 changes: 2 additions & 1 deletion Nop.Plugin.Api/Services/IProductApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ namespace Nop.Plugin.Api.Services
public interface IProductApiService
{
IList<Product> GetProducts(IList<int> ids = null,
IList<string> 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,
Expand Down
11 changes: 11 additions & 0 deletions Nop.Plugin.Api/Services/OrderApiService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,16 @@ private IQueryable<Order> 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;
}
}
}
Loading