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

Feat/xbyk k13 ecommerce product page #15

Merged
merged 23 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
87e28cf
Hotfix 29.2.0
BS-jiriceska Jul 2, 2024
365d954
Move product page to library.
BS-jiriceska Jul 17, 2024
f7d20bb
Product page synchronization.
BS-jiriceska Jul 17, 2024
1d5eb5d
Add admin module.
BS-jiriceska Jul 17, 2024
19bdb12
Create all required folders. Remove unused code.
BS-jiriceska Jul 18, 2024
3d9a381
Update packaghe locks.
BS-jiriceska Jul 18, 2024
93cf46d
Synchronize content items to content item folder.
BS-jiriceska Jul 18, 2024
26c8906
Fix error message for node alias path.
BS-jiriceska Jul 22, 2024
135e4dc
Add admin module for synchronization to content item folder.
BS-jiriceska Jul 22, 2024
8482b5c
Move only required content items.
BS-jiriceska Jul 22, 2024
336952a
Fix display name of content folder options provider.
BS-jiriceska Jul 22, 2024
9a2f3ff
Update version matrix. Update usage guide for synchronizing content i…
BS-jiriceska Jul 22, 2024
62521db
Fix creating folders as root children.
BS-jiriceska Jul 22, 2024
9a5beb6
Content item moved to folder only when in root (on creation).
BS-jiriceska Jul 22, 2024
10a0abd
Merge pull request #17 from Kentico/feat/xbyk_k13_ecommerce_contentIt…
BS-jiriceska Jul 22, 2024
d415720
Update using after moving of ProductPage page type.
BS-jiriceska Jul 22, 2024
828271c
Allow disabling product page synchronization.
BS-jiriceska Jul 22, 2024
7fd3d0c
Update documentation for product page synchronization.
BS-jiriceska Jul 22, 2024
e2cad06
Update docs.
BS-jiriceska Jul 23, 2024
5a4dd67
Update docs. Add screenshots for module.
BS-jiriceska Jul 24, 2024
ea29a20
Update docs.
BS-jiriceska Jul 24, 2024
93c4a38
Fix typo.
BS-jiriceska Jul 24, 2024
83b81cd
Merge 'main' into 'feat/xbyk_k13_ecommerce_product_page'
BS-jiriceska Jul 24, 2024
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ is located in [Dancing Goat XbyK example project](./examples/DancingGoat-K13Ecom
- Product listing, detail and checkout process are placed on XbyK (shopping cart is saved and calculated still on KX 13).
![Cart content](./images/screenshots/cart_content.png "Cart content")
- Orders are created from cart, order related data is saved on KX 13 side.
- Products need to be manually linked from Content hub to pages in website channel applications. You can use CI to restore examples of content types for pages that display products.
- Products need to be linked from Content hub to pages in website channel applications. This can either be done manually or using automatic product page synchronization. You can use CI to restore examples of content types for pages that display products.
See [this section of User Guide](./docs/Usage-Guide.md#dancing-goat-example---setup) for detailed information.
![Store pages](./images/screenshots/store_pages.png "Store pages")
- [Sample XbyK Dancing Goat site](./examples/DancingGoat-K13Ecommerce) implements store functionality and can be used as an example of migration of existing e-commerce projects to new XbyK.
Expand Down Expand Up @@ -81,8 +81,8 @@ Summary of libraries which are supported by the following versions Xperience by
| Library | Xperience Version | Library Version |
|------------------------------------|-------------------| --------------- |
| Kentico.Xperience.Ecommerce.Common | \>= 29.0.1 | 1.0.0 |
| Kentico.Xperience.K13Ecommerce | \>= 29.0.1 | 1.0.0 |
| Kentico.Xperience.Store.Rcl | \>= 29.0.1 | 1.0.0 |
| Kentico.Xperience.K13Ecommerce | \>= 29.2.0 | 1.0.0 |
| Kentico.Xperience.Store.Rcl | \>= 29.2.0 | 1.0.0 |
| Kentico.Xperience.StoreApi | \>= 13.0.131 | 1.0.0 |

### Dependencies
Expand Down
65 changes: 62 additions & 3 deletions docs/Usage-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,14 @@ Interval can be set in minutes (`ProductSyncInterval` setting). Synchronized dat
changes, so data cannot be edited in XbyK safely, but new custom or reusable fields can be added and edited
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.

![XbyK K13Ecommerce settings](../images/screenshots/module_settings.png "XbyK K13Ecommerce settings")

With enabled product page synchronization (see [How to enable automatic product page synchronization?](#prodpagesync)) content type `K13Store.ProductPage` (in chosen website channel)
is created for every content item of type `K13Store.ProductSKU`.

No price data is synced, because catalog prices need
calculator evaluation in context of user's cart and standalone requests via `IProductService` are required.

Expand Down Expand Up @@ -343,8 +351,8 @@ dotnet run --kxp-ci-restore
| Library | Xperience Version | Library Version |
|------------------------------------|-------------------| --------------- |
| Kentico.Xperience.Ecommerce.Common | \>= 29.0.1 | 1.0.0 |
| Kentico.Xperience.K13Ecommerce | \>= 29.0.1 | 1.0.0 |
| Kentico.Xperience.Store.Rcl | \>= 29.0.1 | 1.0.0 |
| Kentico.Xperience.K13Ecommerce | \>= 29.2.0 | 1.0.0 |
| Kentico.Xperience.Store.Rcl | \>= 29.2.0 | 1.0.0 |


## Dancing Goat example - setup
Expand Down Expand Up @@ -376,7 +384,7 @@ For checkout process these content types (for pages) are restored:
Let the product synchronization finish. Check `K13-Store product synchronization done.` in debug console or check Event log for errors.
4. Create pages for Store:
1. Store page (of type `K13Store - Store page`)
2. Product pages (of type `K13Store - Product page`) - for each page select corresponding Product SKU from content hub.
2. Product pages (of type `K13Store - Product page`) - for each page select corresponding Product SKU from content hub (or use automatic synchronization as described [here](#prodpagesync)).
2. Categories pages (of type `K13Store - Category page`) - for each page select product pages in category
3. Cart/Checkout steps pages
1. Cart content page
Expand Down Expand Up @@ -425,6 +433,57 @@ Here are links for some specific parts of shopping cart:
- 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?
In XbyK administration UI go to **Configuration** -> **K13Ecommerce** -> **Page Path mapping rules**. Here you can manage rules for automatic creating product pages (`K13Store.ProductPage`)
from synchronized content items of type `K13Store.ProductSKU`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, please describe where this UI is located (XbyK administration I assume). Use bold formatting for the application / tab name. If possible, show a screenshot highlighting the relevant mapping rule settings (because there are also other settings for the content folder, which could be confusing).


Synchronization is disabled when rules are empty.

![XbyK mapping rules](../images/screenshots/XbK_mapping_rules.png "XbyK mapping rules")

By creating mapping rule you can specify how KX 13 NodeAliasPath (stored in content item) should be mapped into XbyK page path.
Rules are ordered. The first rule that matches NodeAliasPath will be used. You can use wildcards when creating mapping rules.
Each rule can contain any number of wildcards (with arbitrary names). See the examples below for details.

The synchronization automatically creates all required folders in the website channel content tree to achieve the desired XbyK page path structure.

Examples:

1. Direct structure copying from KX 13 to XbyK:
- Mapping rule:
- K13 NodeAliasPath: /\{Product\}
- XbK Page path: /\{Product\}
- Channel name: Dancing Goat Pages
- The `Product` wildcard will store the whole NodeAliasPath and as such will be mapped to tree path of created product page. E.g.:
- /DancingGoatStore/Coffee/Arabica -> /DancingGoatStore/Coffee/Arabica
- /DancingGoatStore/Grinders/Electric/Grinder_GAGGIA_MD_15 -> /DancingGoatStore/Grinders/Electric/Grinder_GAGGIA_MD_15

2. Copying only items which are placed in the category folder as a subfolder of DancingGoatStore. Items which are not placed in DancingGoatStore could be
mapped e.g. in another folder or website channel:
- Mapping rule:
- K13 NodeAliasPath: /DancingGoatStore/\{Category\}/\{Product\}
- XbK Page path: /Store/Products/\{Category\}/\{Product\}
- Channel name: Dancing Goat Pages
- The `Category` wildcard will store the first folder after "DancingGoatStore", `Product` will be rest of path. E.g.:
- /DancingGoatStore/Coffee/Arabica -> /Store/Products/Coffee/Arabica
- /DancingGoatStore/Grinders/Electric/Grinder_GAGGIA_MD_15 -> /Store/Products/Grinders/Electric/Grinder_GAGGIA_MD_15
- /DancingGoatStore/Paper_Filter would not be matched (as the path is not compound from at least two parts of path after "DancingGoatStore")
- /AnotherStore/Coffee/Robusta would not be matched (as the path does not start with "DancingGoatStore")

3. When creating a flattened structure, it is possible to omit part of the NodeAliasPath (only once):
- Mapping rule:
- K13 NodeAliasPath: /.../\{Product\}
- XbK Page path: /Store/\{Product\}
- Channel name: Dancing Goat Pages
- The `Product` wildcard will store only the last part of the NodeAliasPath (product name) and be mapped to the folder "Store" in XbyK website channel:
- /DancingGoatStore/Coffee/Arabica -> /Store/Arabica
- /DancingGoatStore/Paper_Filter -> /Store/Paper_Filter
- /AnotherStore/Coffee/Robusta -> /Store/Robusta

#### 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.

### How to handle order payments?
1. Implement your own payment method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using Kentico.Content.Web.Mvc;
using Kentico.Content.Web.Mvc.Routing;
using Kentico.Xperience.K13Ecommerce.ProductPages;
using Kentico.Xperience.K13Ecommerce.Products;

using Microsoft.AspNetCore.Mvc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using Kentico.Content.Web.Mvc;
using Kentico.Content.Web.Mvc.Routing;
using Kentico.Xperience.K13Ecommerce.ProductPages;
using Kentico.Xperience.K13Ecommerce.Products;
using Kentico.Xperience.K13Ecommerce.StoreApi;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using CMS.Websites;
using CMS.Websites.Routing;

using Kentico.Xperience.K13Ecommerce.ProductPages;

namespace DancingGoat.Models;

public class CategoryPageRepository : StoreContentRepositoryBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using K13Store;

using Kentico.Xperience.K13Ecommerce.ProductPages;
using Kentico.Xperience.K13Ecommerce.StoreApi;

namespace DancingGoat.Models;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using CMS.Websites;
using CMS.Websites.Routing;

using Kentico.Xperience.K13Ecommerce.ProductPages;

namespace DancingGoat.Models;

public class StoreProductPageRepository : StoreContentRepositoryBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

using K13Store;

using Kentico.Xperience.K13Ecommerce.ProductPages;

namespace DancingGoat.Models;

public class StorePageRepository : StoreContentRepositoryBase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using CMS.Websites;
using CMS.Websites.Routing;

using Kentico.Xperience.K13Ecommerce.ProductPages;

namespace DancingGoat.Models
{
/// <summary>
Expand Down
1 change: 1 addition & 0 deletions examples/DancingGoat-K13Ecommerce/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,7 @@
"type": "Project",
"dependencies": {
"Duende.AccessTokenManagement.OpenIdConnect": "[2.1.0, )",
"Kentico.Xperience.Admin": "[29.2.0, )",
"Kentico.Xperience.Ecommerce.Common": "[1.0.0-prerelease-1, )",
"Kentico.Xperience.WebApp": "[29.2.0, )",
"Scrutor": "[4.2.2, )"
Expand Down
Binary file added images/screenshots/XbK_mapping_rules.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/screenshots/module_settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System.Data;
using System.Runtime.Serialization;

using CMS;
using CMS.DataEngine;
using CMS.Helpers;
using CMS.Integration.K13Ecommerce;

[assembly: RegisterObjectType(typeof(K13EcommerceSettingsInfo), K13EcommerceSettingsInfo.OBJECT_TYPE)]

namespace CMS.Integration.K13Ecommerce
{
/// <summary>
/// Data container class for <see cref="K13EcommerceSettingsInfo"/>.
/// </summary>
[Serializable]
public partial class K13EcommerceSettingsInfo : AbstractInfo<K13EcommerceSettingsInfo, IInfoProvider<K13EcommerceSettingsInfo>>, IInfoWithId
{
/// <summary>
/// Object type.
/// </summary>
public const string OBJECT_TYPE = "kenticok13ecommerce.settings";


/// <summary>
/// Type information.
/// </summary>
public static readonly ObjectTypeInfo TYPEINFO = new(typeof(IInfoProvider<K13EcommerceSettingsInfo>), OBJECT_TYPE, "KenticoK13ecommerce.Settings", nameof(K13EcommerceSettingsID), null, null, null, null, null, null, null)
{
TouchCacheDependencies = true
};


/// <summary>
/// K13 ecommerce settings ID.
/// </summary>
[DatabaseField]
public virtual int K13EcommerceSettingsID
{
get => ValidationHelper.GetInteger(GetValue(nameof(K13EcommerceSettingsID)), 0);
set => SetValue(nameof(K13EcommerceSettingsID), value);
}


/// <summary>
/// K13 ecommerce settings product SKU folder ID.
/// </summary>
[DatabaseField]
public virtual int K13EcommerceSettingsProductSKUFolderID
{
get => ValidationHelper.GetInteger(GetValue(nameof(K13EcommerceSettingsProductSKUFolderID)), 0);
set => SetValue(nameof(K13EcommerceSettingsProductSKUFolderID), value);
}


/// <summary>
/// K13 ecommerce settings product variant folder ID.
/// </summary>
[DatabaseField]
public virtual int K13EcommerceSettingsProductVariantFolderID
{
get => ValidationHelper.GetInteger(GetValue(nameof(K13EcommerceSettingsProductVariantFolderID)), 0);
set => SetValue(nameof(K13EcommerceSettingsProductVariantFolderID), value);
}


/// <summary>
/// K13 ecommerce settings product image folder ID.
/// </summary>
[DatabaseField]
public virtual int K13EcommerceSettingsProductImageFolderID
{
get => ValidationHelper.GetInteger(GetValue(nameof(K13EcommerceSettingsProductImageFolderID)), 0);
set => SetValue(nameof(K13EcommerceSettingsProductImageFolderID), value);
}


/// <summary>
/// Deletes the object using appropriate provider.
/// </summary>
protected override void DeleteObject()
{
Provider.Delete(this);
}


/// <summary>
/// Updates the object using appropriate provider.
/// </summary>
protected override void SetObject()
{
Provider.Set(this);
}


/// <summary>
/// Constructor for de-serialization.
/// </summary>
/// <param name="info">Serialization info.</param>
/// <param name="context">Streaming context.</param>
protected K13EcommerceSettingsInfo(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}


/// <summary>
/// Creates an empty instance of the <see cref="K13EcommerceSettingsInfo"/> class.
/// </summary>
public K13EcommerceSettingsInfo()
: base(TYPEINFO)
{
}


/// <summary>
/// Creates a new instances of the <see cref="K13EcommerceSettingsInfo"/> class from the given <see cref="DataRow"/>.
/// </summary>
/// <param name="dr">DataRow with the object data.</param>
public K13EcommerceSettingsInfo(DataRow dr)
: base(TYPEINFO, dr)
{
}
}
}
Loading
Loading