Skip to content

Commit

Permalink
Merge 'main' into 'feat/xbyk_k13_ecommerce_product_page'
Browse files Browse the repository at this point in the history
  • Loading branch information
BS-jiriceska committed Jul 24, 2024
2 parents 93c4a38 + 08b5d70 commit 83b81cd
Show file tree
Hide file tree
Showing 34 changed files with 948 additions and 135 deletions.
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Xperience by Kentico - KX 13 E-Commerce integration
# Xperience by Kentico - Kentico Xperience 13 E-commerce

[![Kentico Labs](https://img.shields.io/badge/Kentico_Labs-grey?labelColor=orange&logo=data:image/svg+xml;base64,PHN2ZyBjbGFzcz0ic3ZnLWljb24iIHN0eWxlPSJ3aWR0aDogMWVtOyBoZWlnaHQ6IDFlbTt2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO2ZpbGw6IGN1cnJlbnRDb2xvcjtvdmVyZmxvdzogaGlkZGVuOyIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik05NTYuMjg4IDgwNC40OEw2NDAgMjc3LjQ0VjY0aDMyYzE3LjYgMCAzMi0xNC40IDMyLTMycy0xNC40LTMyLTMyLTMyaC0zMjBjLTE3LjYgMC0zMiAxNC40LTMyIDMyczE0LjQgMzIgMzIgMzJIMzg0djIxMy40NEw2Ny43MTIgODA0LjQ4Qy00LjczNiA5MjUuMTg0IDUxLjIgMTAyNCAxOTIgMTAyNGg2NDBjMTQwLjggMCAxOTYuNzM2LTk4Ljc1MiAxMjQuMjg4LTIxOS41MnpNMjQxLjAyNCA2NDBMNDQ4IDI5NS4wNFY2NGgxMjh2MjMxLjA0TDc4Mi45NzYgNjQwSDI0MS4wMjR6IiAgLz48L3N2Zz4=)](https://github.com/Kentico/.github/blob/main/SUPPORT.md#labs-limited-support)
[![7-day bug-fix policy](https://img.shields.io/badge/-7--days_bug--fixing_policy-grey?labelColor=orange&logo=data:image/svg+xml;base64,PHN2ZyBjbGFzcz0ic3ZnLWljb24iIHN0eWxlPSJ3aWR0aDogMWVtOyBoZWlnaHQ6IDFlbTt2ZXJ0aWNhbC1hbGlnbjogbWlkZGxlO2ZpbGw6IGN1cnJlbnRDb2xvcjtvdmVyZmxvdzogaGlkZGVuOyIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik04ODguNDkgMjIyLjY4NnYtMzEuNTRsLTY1LjY3Mi0wLjk1NWgtMC4yMDVhNDY1LjcxNSA0NjUuNzE1IDAgMCAxLTE0NC4zMTUtMzEuMzM0Yy03Ny4wMDUtMzEuMTk4LTEyNi4yOTQtNjYuNzY1LTEyNi43MDMtNjcuMTA3bC0zOS44LTI4LjY3Mi0zOS4xODUgMjguNDY4Yy0yLjA0OCAxLjUwMS00OS45MDMgMzYuMDQ0LTEyNi45MDggNjcuMzFhNDQ3LjQyIDQ0Ny40MiAwIDAgMS0xNDQuNTIgMzEuMzM1bC02NS44NzcgMC45NTZ2Mzc4Ljg4YzAgODcuMDQgNDkuODM0IDE4NC42NjEgMTM3LjAxIDI2Ny44MSAzNy41NDcgMzUuODQgNzkuMjU4IDY2LjM1NSAxMjAuODMzIDg4LjIgNDMuMjggMjIuNzMzIDg0LjI0IDM0LjYxMiAxMTguODUyIDM0LjYxMiAzNC40MDYgMCA3NS43NzYtMTIuMTUyIDExOS42MDMtMzUuMTU4YTU0Ny45NzcgNTQ3Ljk3NyAwIDAgMCAxMjAuMDEzLTg3LjY1NCA1MTUuMjA5IDUxNS4yMDkgMCAwIDAgOTYuMTg4LTEyMi44OGMyNy4xMDItNDkuNTYyIDQwLjgyMy05OC4zMDQgNDAuODIzLTE0NC45OTlsLTAuMTM2LTM0Ny4yMDR6TTUxMC4wOSAxNDMuNDI4bDEuNzA2LTEuMzY1IDEuNzc1IDEuMzY1YzUuODAzIDQuMTY1IDU5LjUyOSA0MS44NDggMTQwLjM1NiA3NC43NTIgNzkuMTkgMzIuMDg2IDE1My42IDM1LjYzNSAxNjcuNjYzIDM2LjA0NWwyLjU5NCAwLjA2OCAwLjIwNSAzMTUuNzM0YzAuMTM3IDY5LjQ5NS00Mi41OTggMTUwLjE4Ni0xMTcuMDc3IDIyMS40NTdDNjQxLjU3IDg1NC4yODkgNTYzLjEzIDg5Ni40NzggNTEyIDg5Ni40NzhjLTIzLjY4OSAwLTU1LjU3LTkuODk5LTg5LjcwMi0yNy43ODVhNDc4LjgyMiA0NzguODIyIDAgMCAxLTEwNS42MDktNzcuMjc4QzI0Mi4yMSA3MjAuMjEzIDE5OS40NzUgNjM5LjUyMiAxOTkuNDc1IDU2OS44OVYyNTQuMjI1bDIuNzMtMC4xMzZjMy4yNzggMCA4Mi42MDQtMS41MDIgMTY3LjY2NC0zNS45NzdhNzM5Ljk0MiA3MzkuOTQyIDAgMCAwIDE0MC4yMi03NC42MTV2LTAuMDY5eiIgIC8+PHBhdGggZD0iTTcxMy4zMTggMzY4LjY0YTMyLjIyMiAzMi4yMjIgMCAwIDAtNDUuMzI5IDBMNDQ5LjE5NSA1ODcuNDM1bC05My4xODQtOTMuMTE2YTMyLjIyMiAzMi4yMjIgMCAwIDAtNDUuMzMgMCAzMi4yMjIgMzIuMjIyIDAgMCAwIDAgNDUuMjZsMTE1Ljg1IDExNS44NWEzMi4yOSAzMi4yOSAwIDAgMCA0NS4zMjggMEw3MTMuMzIgNDEzLjlhMzIuMjIyIDMyLjIyMiAwIDAgMCAwLTQ1LjMzeiIgIC8+PC9zdmc+)](https://github.com/Kentico/.github/blob/main/SUPPORT.md#full-support)
[![CI: Build and Test](https://github.com/Kentico/xperience-by-kentico-k13ecommerce/actions/workflows/ci.yml/badge.svg)](https://github.com/Kentico/xperience-by-kentico-k13ecommerce/actions/workflows/ci.yml)

**This integration is currently a Proof of Concept (PoC). For further details, please refer to the [Support](#support) section and the [Kentico Labs](https://github.com/Kentico/.github/blob/main/SUPPORT.md#labs-limited-support) tag associated with this feature.**

| Name | Package |
| ------------- |:-------------:|
| Kentico.Xperience.K13Ecommerce | [![NuGet Package](https://img.shields.io/nuget/v/Kentico.Xperience.K13Ecommerce.svg)](https://www.nuget.org/packages/Kentico.Xperience.K13Ecommerce) |
Expand Down Expand Up @@ -43,8 +41,10 @@ is located in [Dancing Goat XbyK example project](./examples/DancingGoat-K13Ecom
The integration provides an API with services for implementing the following scenarios:
- Listing products based on parameters, product categories, prices and inventory
- Actions with shopping cart, changing currency and order creation
- Listing of orders (currently suitable for implementing listing orders in administration)
- **Order updates and listing for specific customers are under development**
- Listing of orders in the administration
- Listing of orders on the live site for the current customer
- Updates of existing orders
- Retrieving and listing order statuses
- Listing site cultures and currencies
- Check [this part of User Guide](./docs/Usage-Guide.md#kx-13-e-commerce-integration-in-xperience-by-kentico) for more specific description

Expand Down Expand Up @@ -169,6 +169,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment environment)
"ClientId": "3ef7fe1b-696c-4afa-8b56-d3176b7bea95",
"ClientSecret": "********************",
"ProductSyncEnabled": true,
"StandaloneProductSync": true,
"ProductSyncInterval": 10
}
}
Expand Down Expand Up @@ -207,8 +208,8 @@ Distributed under the MIT License. See [`LICENSE.md`](./LICENSE.md) for more inf

## Support

This contribution has __Kentico Labs limited support__.
This contribution has __Full Support__.

See [`SUPPORT.md`](https://github.com/Kentico/.github/blob/main/SUPPORT.md#labs-limited-support) for more information.
See [`SUPPORT.md`](https://github.com/Kentico/.github/blob/main/SUPPORT.md) for more information.

For any security issues see [`SECURITY.md`](https://github.com/Kentico/.github/blob/main/SECURITY.md).
29 changes: 22 additions & 7 deletions docs/Usage-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ via API.
### Orders
- Endpoint `api/store/order/list` for retrieving list of orders for current customer based on request (supports paging)
- Endpoint `api/store/order/admin/list` for retrieving list of orders (for all customers) based on request (supports paging) to display in XbyK administration (supports paging)
- Endpoint `api/store/order/detail/{orderID}` for retrieving order details for the current customer. If the order belongs to another customer, no order is retrieved
- Endpoint `api/store/order/admin/detail/{orderID}` for retrieving order details (without verifying if the order belongs to the current customer)
- Endpoint `api/store/order/statuses/list` for retrieving all order statuses
- Endpoint `api/store/order/update` for updating orders (update order status, set order payment, etc.). Primarily intended to be used via `IOrderService` available in the [integration API](https://github.com/Kentico/xperience-by-kentico-k13ecommerce/pull/16#kx-13-e-commerce-integration-in-xperience-by-kentico)

### Customers
- Endpoint `api/store/customer/addresses` for retrieving current customer's addresses
Expand All @@ -90,7 +94,7 @@ via API.
When [member](https://docs.kentico.com/x/BIsuCw) is created on XbyK (for example when a new customer registers), this member needs to be synchronized to KX 13 as a user.
It is subsequently used for API authorization (member/user identity is generated in JWT).
Before you start using the Store API, you need to synchronize all website members between the client (XbyK) and your KX 13 application.
Complete synchronization is not part of this PoC solution.
Complete synchronization is currently not a part of this solution.

- Endpoint `api/store/synchronization/user-synchronization` can be used to create a new user in KX 13
- The client application (XbyK) should use this to ensure that all new members are synchronized to KX 13. This is necessary when client's
Expand Down Expand Up @@ -218,8 +222,12 @@ and to browser cookie (uses `IShoppingCartClientStorage`)
- Service is used e.g. in [CheckoutService in Dancing Goat example](../examples/DancingGoat-K13Ecommerce/Services/CheckoutService.cs)
where customer's addresses are retrieved in cart's second step.
- `IOrderService`
- List of orders - currently suitable for implementing listing orders in administration
- **Order updates and listing for specific customers are under development**
- List orders from all customers (for implementing order listings in the administration)
- List orders for the current customer (based on the request context)
- Retrieve order details for the current customer (only for orders that belong to the customer)
- Retrieve order details for administrators (without verifying if the order belongs to the current customer)
- List all order statuses
- Update existing orders (order status, payment, etc.)
- `ISiteStoreService`
- Use for retrieving site's [list of enabled cultures](https://github.com/Kentico/xperience-by-kentico-ecommerce/blob/main/src/Kentico.Xperience.K13Ecommerce/SiteStore/ISiteStoreService.cs#L13), e.g. for implementation of language selector
- Use for retrieving site's [list of enabled currencies](https://github.com/Kentico/xperience-by-kentico-ecommerce/blob/main/src/Kentico.Xperience.K13Ecommerce/SiteStore/ISiteStoreService.cs#L18), e.g. for implementation of currency selector
Expand All @@ -232,7 +240,7 @@ and to browser cookie (uses `IShoppingCartClientStorage`)

Library also implements product synchronization to Content hub. These are 3 entities synchronized to reusable content items:
- Products - Content type `K13Store.ProductSKU`
- All products associated with product pages are synced. **Standalone SKUs** aren't currently supported.
- All products associated with product pages are synced. **Standalone SKUs** synchronization can be set via `StandaloneProductSync` setting.
- Product variants - Content type `K13Store.ProductVariant`
- All products variant for parent products
- Product images - Content type `K13Store.ProductImage`
Expand All @@ -241,7 +249,7 @@ Library also implements product synchronization to Content hub. These are 3 enti
The synchronization runs in a background thread worker periodically and can be disabled (`ProductSyncEnabled` setting).
Interval can be set in minutes (`ProductSyncInterval` setting). Synchronized data is updated when source value
changes, so data cannot be edited in XbyK safely, but new custom or reusable fields can be added and edited
safely.
safely. You can decide, whether include [standalone SKUs](https://docs.kentico.com/x/3gqRBg) or not (`StandaloneProductSync` setting).

You can select content item folders where content items are synchronized. Content item folders can be selected independently for each content type in XbyK administration UI. Go to
**Configuration** -> **K13Ecommerce** -> **K13Ecommerce settings**. Content items are not moved if root folder is selected.
Expand Down Expand Up @@ -302,6 +310,7 @@ dotnet add package Kentico.Xperience.Store.Rcl
"ClientId": "3ef7fe1b-696c-4afa-8b56-d3176b7bea95",
"ClientSecret": "********************",
"ProductSyncEnabled": true,
"StandaloneProductSync": true,
"ProductSyncInterval": 10
}
}
Expand All @@ -314,6 +323,7 @@ dotnet add package Kentico.Xperience.Store.Rcl
| ClientId | Fill same value which is defined on KX 13 side |
| ClientSecret | Fill same value which is defined on KX 13 side |
| ProductSyncEnabled | If true, product synchronization is enabled |
| StandaloneProductSync | If this setting along with `ProductSyncEnabled` is true, [standalone SKUs](https://docs.kentico.com/x/3gqRBg) are synchronized as well (if `ProductSyncEnabled` is false, no products are synchronized). |
| ProductSyncInterval | Interval in minutes specifies how often synchronization is running |


Expand Down Expand Up @@ -420,7 +430,7 @@ Here are links for some specific parts of shopping cart:
- [Discount / Coupon codes](https://github.com/Kentico/xperience-by-kentico-ecommerce/blob/main/examples/DancingGoat-K13Ecommerce/Controllers/KStore/CheckoutController.cs#L163)
- [Delivery details + shipping](https://github.com/Kentico/xperience-by-kentico-ecommerce/blob/main/examples/DancingGoat-K13Ecommerce/Controllers/KStore/CheckoutController.cs#L194)
- [Payment](https://github.com/Kentico/xperience-by-kentico-ecommerce/blob/main/examples/DancingGoat-K13Ecommerce/Controllers/KStore/CheckoutController.cs#L330)
- Payment gateway - Is not part of this PoC solution, you need to implement integration with specific payment gateway. **API for updating orders (and their statuses) is under development**.
- Payment gateway - Is not currently part of the solution. You need to implement integration with a specific payment gateway.
- [Order creation](https://github.com/Kentico/xperience-by-kentico-ecommerce/blob/main/examples/DancingGoat-K13Ecommerce/Controllers/KStore/CheckoutController.cs#L315)

### <a name="prodpagesync"></a>How to enable automatic product page synchronization?
Expand Down Expand Up @@ -473,4 +483,9 @@ mapped e.g. in another folder or website channel:
#### Known limitations
Avoid creating rules that map the NodeAliasPath of different content items to a single product page tree path. Such rules cause the linked content item to be overwritten for particular pages.

If you change existing mapping rules, already created pages will not be moved accordingly. Instead, they will be created in the new location.
If you change existing mapping rules, already created pages will not be moved accordingly. Instead, they will be created in the new location.

### How to handle order payments?
1. Implement your own payment method.
2. Retrieve all order statuses using `IOrderService` if needed.
3. Use `UpdateOrder` method of `IOrderService` to update order status and to set `OrderIsPaid` flag according to the payment result.
38 changes: 38 additions & 0 deletions examples/DancingGoat-K13Ecommerce/Controllers/TestController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,43 @@ public async Task<IActionResult> TestSetCurrency(string currencyCode)

public async Task<JsonResult> TestOrders([FromServices] IOrderService orderService)
=> Json(await orderService.GetCurrentCustomerOrderList(new OrderListRequest { Page = 1, PageSize = 10, OrderBy = "OrderID DESC" }));

public async Task<JsonResult> TestOrderStatuses([FromServices] IOrderService orderService)
{
var statuses = await orderService.GetOrderStatuses();
return Json(statuses);
}

public async Task<IActionResult> TestUpdateOrder([FromServices] IOrderService orderService)
{
var orders =
await orderService.GetAdminOrderList(new OrderListRequest { Page = 1, PageSize = 10, OrderBy = "OrderID DESC" });

var order = orders.Orders.First(o => o.OrderId == 25);

order.OrderGrandTotal = 999;
order.OrderIsPaid = true;
var newStatus = (await orderService.GetOrderStatuses()).First(o => o.StatusName == "Completed");
order.OrderStatus = newStatus;

order.OrderBillingAddress.AddressLine1 = "123 Main St";
order.OrderBillingAddress.AddressCity = "New York";

order.OrderShippingAddress.AddressZip = "10001";

order.OrderShippingOption = new KShippingOption { ShippingOptionId = 2 };
order.OrderPaymentOption = new KPaymentOption { PaymentOptionId = 1 };

order.OrderPaymentResult = new KPaymentResult
{
PaymentIsCompleted = true,
PaymentMethodName = "Test",
PaymentStatusName = "Test status"
};

await orderService.UpdateOrder(order);

return Ok();
}
}
#endif
1 change: 1 addition & 0 deletions examples/DancingGoat-K13Ecommerce/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"ClientId": "YourUniqueClientIdentifier",
"ClientSecret": "********************",
"ProductSyncEnabled": true,
"StandaloneProductSync": true,
"ProductSyncInterval": 10
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace DancingGoat.ShopApi;
/// </summary>
public class CustomSKUConverter : ProductSKUConverter<CustomSKU>
{
public override CustomSKU Convert(SKUInfo skuInfo, string currencyCode, bool withVariants)
public override CustomSKU Convert(SKUInfo skuInfo, string currencyCode, bool withVariants, bool withLongDescription)
{
var model = base.Convert(skuInfo, currencyCode, withVariants);
var model = base.Convert(skuInfo, currencyCode, withVariants, withLongDescription);
return model;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public class KenticoStoreConfig
/// </summary>
public required string ClientSecret { get; set; } = string.Empty;

/// <summary>
/// Synchronize also standalone products without page representation.
/// </summary>
public required bool StandaloneProductSync { get; set; } = true;

/// <summary>
/// When true, product synchronization is enabled.
/// </summary>
Expand Down
27 changes: 27 additions & 0 deletions src/Kentico.Xperience.K13Ecommerce/Orders/IOrderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,31 @@ public interface IOrderService
/// <param name="request">Request parameters for order listing.</param>
/// <returns>Paged list of orders.</returns>
Task<OrderListResponse> GetAdminOrderList(OrderListRequest request);


/// <summary>
/// Get order by id for current customer.
/// </summary>
/// <param name="orderId">Order ID.</param>
Task<KOrder> GetCurrentCustomerOrder(int orderId);


/// <summary>
/// Get order by ID to display in XbyK administration.
/// </summary>
/// <param name="orderId">Order ID.</param>
Task<KOrder> GetAdminOrder(int orderId);


/// <summary>
/// Returns list of enabled order statuses.
/// </summary>
Task<ICollection<KOrderStatus>> GetOrderStatuses();


/// <summary>
/// Updates order.
/// </summary>
/// <param name="order">Order Dto, send full data for order - retrieve order data first.</param>
Task UpdateOrder(KOrder order);
}
5 changes: 5 additions & 0 deletions src/Kentico.Xperience.K13Ecommerce/Orders/OrderListRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@ public class OrderListRequest
/// Order by.
/// </summary>
public required string OrderBy { get; set; }

/// <summary>
/// Customer ID, leave null or zero for all customers.
/// </summary>
public int? CustomerId { get; set; }
}
16 changes: 16 additions & 0 deletions src/Kentico.Xperience.K13Ecommerce/Orders/OrderService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,20 @@ public async Task<OrderListResponse> GetCurrentCustomerOrderList(OrderListReques
///<inheritdoc/>
public async Task<OrderListResponse> GetAdminOrderList(OrderListRequest request)
=> await storeApiClient.AdminOrderListAsync(request.Page, request.PageSize, request.OrderBy);


/// <inheritdoc/>
public async Task<KOrder> GetCurrentCustomerOrder(int orderId) => await storeApiClient.OrderDetailAsync(orderId);


/// <inheritdoc/>
public async Task<KOrder> GetAdminOrder(int orderId) => await storeApiClient.AdminOrderDetailAsync(orderId);


/// <inheritdoc/>
public async Task<ICollection<KOrderStatus>> GetOrderStatuses() => await storeApiClient.OrderStatusesListAsync();


/// <inheritdoc/>
public async Task UpdateOrder(KOrder order) => await storeApiClient.UpdateOrderAsync(order);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,12 @@ public interface IProductService
/// <param name="skuId">SKUID for product or variant.</param>
/// <param name="currencyCode">Currency code.</param>
Task<ProductInventoryPriceInfo> GetVariantInventoryPriceInfo(int skuId, string? currencyCode = null);


/// <summary>
/// Gets all standalone products.
/// </summary>
/// <param name="request">Stanadlone product params.</param>
/// <returns></returns>
Task<ICollection<KProductSKU>> GetStandaloneProducts(ProductRequest request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,14 @@
/// <summary>
/// Model for request to filter product pages
/// </summary>
public class ProductPageRequest
public class ProductPageRequest : ProductRequest
{
/// <summary>
/// Node alias path prefix
/// </summary>
public required string Path { get; set; }


/// <summary>
/// Document culture
/// </summary>
public string? Culture { get; set; }


/// <summary>
/// Product currency
/// </summary>
public string? Currency { get; set; }


/// <summary>
/// Order by SQL expression
/// </summary>
public string? OrderBy { get; set; }


/// <summary>
/// Limit how many products to return.
/// </summary>
public int? Limit { get; set; }


/// <summary>
/// If true variants are loaded too for products with variants (default false).
/// </summary>
public bool WithVariants { get; set; }


/// <summary>
/// If true, DocumentSKUDescription is filled too (default false).
/// </summary>
Expand Down
Loading

0 comments on commit 83b81cd

Please sign in to comment.