Skip to content

Commit f7e2455

Browse files
authored
Merge pull request #6521 from MrEssCee/patch-4
Create add-item article
2 parents 40307d1 + 97436f6 commit f7e2455

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

13/umbraco-commerce/SUMMARY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
* [Configure SQLite support](how-to-guides/configure-sqlite-support.md)
3636
* [Limit Order Line Quantity](how-to-guides/limit-orderline-quantity.md)
3737
* [Use an Alternative Database for Umbraco Commerce Tables](how-to-guides/use-an-alternative-database-for-umbraco-commerce-tables.md)
38+
* [Add item to Cart](how-to-guides/add-item.md)
39+
* [Update Cart](how-to-guides/update-cart.md)
40+
* [Delete item in Cart](how-to-guides/delete-item.md)
3841

3942
## Key Concepts
4043

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
---
2+
description: How-To Guide to add an item to your cart.
3+
---
4+
5+
# Add item to Cart
6+
7+
To add an item to the cart, configure Umbraco with a store and add the necessary properties for interaction. Learn more by following the [Getting started with Umbraco Commerce: The Backoffice tutorial](../tutorials/getting-started-with-commerce).
8+
9+
You will need the front end to be set up to allow an item to be added to the cart. This can be done by adding a button to the front end to call the Action to add the item to the cart.
10+
11+
Create a new Document Type with the template. Call it **Product Page** with the following property aliases: `productTitle`, `productDescription`, `price`, `stock`.
12+
13+
The following property editors are recommeded to be used for the above:
14+
15+
* `productTitle`: TextString
16+
* `productDescription`: TextArea
17+
* `price`: Umbraco Commerce Price
18+
* `stock`: Umbraco Commerce Stock
19+
20+
The Product Page template can be implemented as shown below.
21+
22+
```csharp
23+
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ProductPage>
24+
@{
25+
var store = Model.Value<StoreReadOnly>("store", fallback: Fallback.ToAncestors);
26+
var product = CommerceApi.Instance.GetProduct(store.Id, Model.Key.ToString(), "en-GB");
27+
var price = product.TryCalculatePrice().ResultOrThrow("Unable to calculate product price");
28+
}
29+
```
30+
31+
The code above does the following:
32+
33+
- You need to access the store to access the relevant properties for your product, such as price. The store has a fallback property allowing you to traverse the tree to find the store.
34+
- You retrieve the product based on the store and a reference for the product. The 'productReference' comes from the Model which is a single product.
35+
- The Product is returned as a ProductSnapshot which is Umbraco Commerce obtaining the page ID and carrying out necessary processes to bring in the data for further processing.
36+
- Finally, you need to calculate the price which is then displayed without VAT. This can also be displayed with VAT.
37+
38+
To display this you need to add some markup or at least amend it to include a button to add an item. Add the following to the same file:
39+
40+
```csharp
41+
@using (Html.BeginUmbracoForm("AddToCart", "CartSurface"))
42+
{
43+
@Html.Hidden("productReference", Model.Key.ToString())
44+
<h1>@Model.Value<string>("productTitle")</h1>
45+
<h2>@Model.Value<string>("productDescription")</h2>
46+
47+
<p>Our price excluding VAT <strong>@price.WithoutTax.ToString("C0") </strong></p>
48+
49+
if (@Model.Value<int>("stock") == 0)
50+
{
51+
<p>Sorry, out of stock</p>
52+
}
53+
else
54+
{
55+
<button type="submit">Add to Basket</button>
56+
}
57+
58+
}
59+
```
60+
61+
The hidden field uses the `productReference` to be passed across to the Controller.
62+
63+
## Adding the Controller
64+
65+
For the button to work, you need to implement a controller. An example of this is shown below.
66+
67+
Create a new Controller called `CartSurfaceController.cs`.
68+
69+
{% hint style="warning" %}
70+
71+
The namespaces used in this Controller are important and need to be included.
72+
73+
```
74+
using Microsoft.AspNetCore.Mvc;
75+
using Umbraco.Cms.Core.Cache;
76+
using Umbraco.Cms.Core.Logging;
77+
using Umbraco.Cms.Core.Models.PublishedContent;
78+
using Umbraco.Cms.Core.Routing;
79+
using Umbraco.Cms.Core.Services;
80+
using Umbraco.Cms.Core.Web;
81+
using Umbraco.Cms.Infrastructure.Persistence;
82+
using Umbraco.Cms.Web.Website.Controllers;
83+
using Umbraco.Commerce.Common.Validation;
84+
using Umbraco.Commerce.Core.Api;
85+
using Umbraco.Commerce.Core.Models;
86+
using Umbraco.Commerce.Extensions;
87+
using Umbraco.Extensions;
88+
```
89+
90+
{% endhint %}
91+
92+
```csharp
93+
public class CartSurfaceController : SurfaceController
94+
{
95+
public CartSurfaceController(IUmbracoContextAccessor umbracoContextAccessor,
96+
IUmbracoDatabaseFactory databaseFactory,
97+
ServiceContext services, AppCaches appCaches,
98+
IProfilingLogger profilingLogger,
99+
IPublishedUrlProvider publishedUrlProvider,
100+
IUmbracoCommerceApi commerceApi)
101+
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
102+
{
103+
_commerceApi = commerceApi;
104+
}
105+
}
106+
```
107+
108+
Below you can see the equivalent code for having this as a Primary Constructor:
109+
110+
```csharp
111+
public class CartSurfaceController(IUmbracoContextAccessor umbracoContextAccessor,
112+
IUmbracoDatabaseFactory databaseFactory,
113+
ServiceContext services, AppCaches appCaches,
114+
IProfilingLogger profilingLogger,
115+
IPublishedUrlProvider publishedUrlProvider)
116+
: SurfaceController(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
117+
{
118+
}
119+
```
120+
121+
The CartDto class below is used to pass the `productReference` across to the Controller. This class has only one property for the `productReference`.
122+
123+
```csharp
124+
public class CartDto
125+
{
126+
public string ProductReference { get; set; }
127+
}
128+
```
129+
130+
We now need to add the Action to add the item to the cart. This action will be called when the button is clicked.
131+
132+
```csharp
133+
[HttpPost]
134+
public IActionResult AddToBasket(CartDto cart)
135+
{
136+
commerceApi.Uow.Execute(uow =>
137+
{
138+
var store = CurrentPage.Value<StoreReadOnly>("store", fallback: Fallback.ToAncestors);
139+
140+
if (store == null) return;
141+
142+
try
143+
{
144+
var order = commerceApi.GetOrCreateCurrentOrder(store.Id)
145+
.AsWritable(uow)
146+
.AddProduct(cart.ProductReference, 1);
147+
148+
commerceApi.SaveOrder(order);
149+
150+
uow.Complete();
151+
152+
TempData["SuccessFeedback"] = "Product added to cart";
153+
return RedirectToCurrentUmbracoPage();
154+
}
155+
catch (ValidationException ve)
156+
{
157+
throw new ValidationException(ve.Errors);
158+
}
159+
catch (Exception ex)
160+
{
161+
logger.Error(ex, "An error occurred.");
162+
}
163+
});
164+
}
165+
```
166+
167+
The code above does the following:
168+
169+
- The `store` variable is used to access the store to get the store ID.
170+
- A try-catch block captures any errors that may occur when adding the item to the cart, including any validation errors.
171+
- `order` is used to retrieve the current order if one exists or create a new order against the store found. In the Commerce API, everything is read-only for performance so you need to make it writable to add the product.
172+
- `AddProduct` is called and `productReference` is passed along with the quantity.
173+
- `SaveOrder` is called to save the order.
174+
- `TempData` stores a message to be displayed to the user if the product has been added to the cart.
175+
176+
{% hint style="warning" %}
177+
Umbraco Commerce uses the Unit of Work pattern to complete saving the item (`uow.Complete`). When retrieving or saving data ideally you would want the entire transaction to be committed. However, if there is an error nothing is changed on the database.
178+
{% endhint %}
179+
180+
Finally, you need to add the `TempData` to tell the user that the product has been added to the cart.
181+
182+
## Add a partial view to display the message
183+
184+
Create a new partial view called `Feedback.cshtml`.
185+
186+
```csharp
187+
@Html.ValidationSummary(true, "", new { @class = "danger" })
188+
189+
@{
190+
var success = TempData["SuccessFeedback"]?.ToString();
191+
192+
if (!string.IsNullOrWhiteSpace(success))
193+
{
194+
<div class="success">@success</div>
195+
}
196+
}
197+
```
198+
199+
You can now run the application, click the button, and see the product added to the cart with a message displayed to the user.

0 commit comments

Comments
 (0)