Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Samuel Dudík
PA165 Winery Management System
Commits
ef752cef
Commit
ef752cef
authored
May 18, 2022
by
Samuel Dudík
Browse files
Merge branch 'feature/dudik/mvc-user-orders' into 'main'
Shopping cart and orders See merge request
!44
parents
6b6a4b2b
8e539b3d
Pipeline
#141069
passed with stages
in 2 minutes and 19 seconds
Changes
12
Pipelines
1
Show whitespace changes
Inline
Side-by-side
winery/api/src/main/java/cz/muni/fi/pa165/winery/services/CartService.java
View file @
ef752cef
...
...
@@ -6,5 +6,6 @@ import cz.muni.fi.pa165.winery.dto.order.OrderDto;
public
interface
CartService
{
CartDto
loadFromCookie
();
void
saveToCookie
(
CartDto
cart
);
void
clear
();
OrderDto
convertToOrder
(
CartDto
cart
,
long
userId
);
}
winery/dao/src/main/java/cz/muni/fi/pa165/winery/persistence/dao/DaoBaseImpl.java
View file @
ef752cef
...
...
@@ -51,7 +51,7 @@ public class DaoBaseImpl<ENTITY extends EntityBase> implements DaoBase<ENTITY> {
public
ENTITY
get
(
long
id
,
boolean
useCachedResults
)
{
try
{
var
entity
=
entityManager
.
find
(
entityClass
,
id
);
if
(!
useCachedResults
)
{
if
(!
useCachedResults
&&
entity
!=
null
)
{
entityManager
.
refresh
(
entity
);
}
return
entity
;
...
...
winery/service/src/main/java/cz/muni/fi/pa165/winery/services/CartServiceImpl.java
View file @
ef752cef
...
...
@@ -53,6 +53,11 @@ public class CartServiceImpl implements CartService {
cookieService
.
setCookie
(
getCartCookieName
(),
json
);
}
@Override
public
void
clear
()
{
cookieService
.
setCookie
(
getCartCookieName
(),
"{}"
);
}
@Override
public
OrderDto
convertToOrder
(
CartDto
cart
,
long
userId
)
{
var
order
=
new
OrderDto
();
...
...
winery/webapp/src/main/java/cz/muni/fi/pa165/winery/webapp/controllers/CartController.java
View file @
ef752cef
...
...
@@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.ResponseBody
;
import
org.springframework.web.server.ResponseStatusException
;
import
org.springframework.web.servlet.ModelAndView
;
import
java.math.BigDecimal
;
...
...
@@ -24,6 +25,8 @@ import java.util.HashSet;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
static
org
.
springframework
.
http
.
HttpStatus
.
GONE
;
@Controller
@RequestMapping
(
"/cart"
)
public
class
CartController
extends
ControllerBase
{
...
...
@@ -41,7 +44,7 @@ public class CartController extends ControllerBase {
}
@GetMapping
(
""
)
public
ModelAndView
test
()
{
public
ModelAndView
index
()
{
var
viewModel
=
new
CartListingViewModel
();
initializeViewModel
(
viewModel
);
...
...
@@ -63,6 +66,9 @@ public class CartController extends ControllerBase {
@PostMapping
(
"/add"
)
@ResponseBody
public
String
add
(
long
id
,
int
count
)
{
if
(
count
<
1
)
return
"Fail"
;
var
cart
=
cartService
.
loadFromCookie
();
cart
.
add
(
id
,
count
);
cartService
.
saveToCookie
(
cart
);
...
...
@@ -90,6 +96,19 @@ public class CartController extends ControllerBase {
@PostMapping
(
"/checkout"
)
@ResponseBody
public
String
add
()
{
var
cart
=
cartService
.
loadFromCookie
();
var
cartItems
=
cart
.
getCartItems
();
for
(
Map
.
Entry
<
Long
,
Integer
>
entry
:
cartItems
.
entrySet
())
{
var
bottle
=
wineBottleService
.
get
(
entry
.
getKey
());
if
(
bottle
==
null
)
{
continue
;
}
if
(
bottle
.
getStock
()
<
entry
.
getValue
())
throw
new
ResponseStatusException
(
GONE
,
"Not enough products on stock."
);
}
var
order
=
new
OrderDto
();
order
.
setShipped
(
false
);
...
...
@@ -98,27 +117,35 @@ public class CartController extends ControllerBase {
orderService
.
create
(
order
);
var
cart
=
cartService
.
loadFromCookie
();
var
cartItems
=
cart
.
getCartItems
();
for
(
Map
.
Entry
<
Long
,
Integer
>
entry
:
cartItems
.
entrySet
())
{
var
item
=
new
OrderItemDto
();
item
.
setBottleId
(
entry
.
getKey
());
item
.
setQuantity
(
new
BigDecimal
(
entry
.
getValue
()));
item
.
setOrderId
(
order
.
getId
());
item
.
setOrderId
(
order
.
getId
());
order
.
getItems
().
add
(
item
);
orderItemService
.
create
(
item
);
cart
.
remove
(
entry
.
getKey
());
var
bottle
=
wineBottleService
.
get
(
item
.
getBottleId
());
if
(
bottle
==
null
)
{
continue
;
}
bottle
.
setStock
(
bottle
.
getStock
()
-
item
.
getQuantity
().
intValue
());
orderItemService
.
create
(
item
);
wineBottleService
.
update
(
bottle
);
}
cartService
.
saveToCookie
(
c
ar
t
);
cartService
.
cle
ar
(
);
return
"Success"
;
}
@Override
protected
<
T
extends
ViewModelBase
>
void
initializeViewModel
(
T
viewModel
)
{
super
.
initializeViewModel
(
viewModel
);
if
(
viewModel
instanceof
CartListingViewModel
)
{
var
cartViewModel
=
(
CartListingViewModel
)
viewModel
;
var
productNames
=
wineBottleService
.
getAll
().
stream
().
collect
(
Collectors
.
toMap
(
x
->
x
.
getId
(),
x
->
x
.
getName
()));
cartViewModel
.
setProductNames
(
productNames
);
}
}
}
winery/webapp/src/main/java/cz/muni/fi/pa165/winery/webapp/controllers/ControllerBase.java
View file @
ef752cef
...
...
@@ -112,7 +112,9 @@ public class ControllerBase {
private
Pair
<
String
,
String
>
getControllerAndAction
()
{
var
callerFrame
=
StackWalker
.
getInstance
(
StackWalker
.
Option
.
RETAIN_CLASS_REFERENCE
)
.
walk
(
s
->
s
.
filter
(
c
->
ControllerBase
.
class
.
isAssignableFrom
(
c
.
getDeclaringClass
())
&&
c
.
getDeclaringClass
()
!=
ControllerBase
.
class
)
s
.
filter
(
c
->
ControllerBase
.
class
.
isAssignableFrom
(
c
.
getDeclaringClass
())
&&
c
.
getDeclaringClass
()
!=
ControllerBase
.
class
&&
!
c
.
getMethodName
().
equals
(
"initializeViewModel"
))
.
findFirst
());
if
(!
callerFrame
.
isPresent
())
{
...
...
winery/webapp/src/main/java/cz/muni/fi/pa165/winery/webapp/controllers/OrderController.java
View file @
ef752cef
...
...
@@ -33,9 +33,6 @@ public class OrderController extends ControllerBase {
@GetMapping
(
""
)
@Secured
(
"ROLE_ADMIN"
)
public
ModelAndView
index
()
{
// var orders = orderService.getAll();
// TODO not pretty
var
orders
=
new
ArrayList
<
OrderDto
>();
for
(
OrderDto
order
:
orderService
.
getAll
())
{
...
...
winery/webapp/src/main/java/cz/muni/fi/pa165/winery/webapp/models/cart/CartListingViewModel.java
View file @
ef752cef
...
...
@@ -5,9 +5,11 @@ import lombok.Getter;
import
lombok.Setter
;
import
java.util.List
;
import
java.util.Map
;
@Getter
@Setter
public
class
CartListingViewModel
extends
ViewModelBase
{
private
List
<
CartItemViewModel
>
cart
;
private
Map
<
Long
,
String
>
productNames
;
}
winery/webapp/src/main/resources/static/js/scripts.js
View file @
ef752cef
...
...
@@ -24,8 +24,14 @@ function setCartAmount(itemId, count) {
function
checkout
()
{
return
fetch
(
`
${
getUrlPrefix
()}
cart/checkout`
,
{
method
:
'
POST
'
}).
then
(()
=>
{
window
.
location
.
href
=
`
${
getUrlPrefix
()}
myorder`
;
{
method
:
'
POST
'
}).
then
((
res
)
=>
{
if
(
res
.
status
==
410
)
{
document
.
getElementById
(
"
failure-alert
"
).
style
.
display
=
"
block
"
;
document
.
getElementById
(
"
success-alert
"
).
style
.
display
=
"
none
"
;
}
else
{
document
.
getElementById
(
"
success-alert
"
).
style
.
display
=
"
block
"
;
document
.
getElementById
(
"
failure-alert
"
).
style
.
display
=
"
none
"
;
}
});
}
...
...
winery/webapp/src/main/resources/templates/cart/
test
.html
→
winery/webapp/src/main/resources/templates/cart/
index
.html
View file @
ef752cef
...
...
@@ -10,22 +10,34 @@
<div
class=
"container px-4 px-lg-5"
>
<main
role=
"main"
class=
"pb-3"
>
<h4>
Cart contents:
</h4>
<div
style=
"display: none;"
id=
"success-alert"
>
<div
class=
"alert alert-success mt-2"
role=
"alert"
>
The order was sent successfully!
</div>
</div>
<div
style=
"display: none;"
id=
"failure-alert"
>
<div
class=
"alert alert-danger mt-2"
role=
"alert"
>
Not enough products on stock!
</div>
</div>
<table
class=
"table"
>
<thead>
<th>
Item ID
</th>
<th>
Product Name
</th>
<th>
Count
</th>
<th>
Delete
</th>
</thead>
<tbody>
<tr
th:each=
"item : ${model.cart}"
>
<td
th:text=
"${item.productId}"
>
ID
</td>
<td
th:text=
"${item.count}"
>
Count
</td>
<td
th:text=
"${model.productNames[__${item.productId}__]}"
>
Product Name
</td>
<td><input
th:onchange=
"'setCartAmount(' + ${item.productId} + ', document.getElementById(\'quantity\').value)'"
type=
"number"
id=
"quantity"
name=
"quantity"
min=
"1"
th:value=
"${item.count}"
/></td>
<td><a
href=
"#"
th:onclick=
"'removeFromCart(' + ${item.productId} + ').then(x => refreshPage())'"
>
Delete
</a></td>
</tr>
</tbody>
</table>
<a
class=
"btn btn-primary"
href=
"#"
onclick=
"addToCart(1, 3).then(x => refreshPage())"
>
Add to cart
</a>
<a
class=
"btn btn-primary"
href=
"#"
onclick=
"removeFromCart(1).then(x => refreshPage())"
>
Remove from cart
</a>
<a
class=
"btn btn-primary"
href=
"#"
onclick=
"setCartAmount(1, 2).then(x => refreshPage())"
>
Set cart amount
</a>
<a
class=
"btn btn-primary"
href=
"#"
onclick=
"checkout()"
>
Checkout
</a>
</main>
</div>
...
...
winery/webapp/src/main/resources/templates/fragments/header.html
View file @
ef752cef
...
...
@@ -31,7 +31,6 @@
<li
class=
"nav-item"
><a
class=
"nav-link active"
th:href=
"@{/productreview}"
>
Reviews
</a></li>
<li
class=
"nav-item"
><a
class=
"nav-link active"
th:href=
"@{/user}"
th:if=
'${model.currentUser != null && model.currentUser.hasRole("ADMIN")}'
>
Users
</a></li>
<li
class=
"nav-item"
><a
class=
"nav-link active"
th:href=
"@{/order}"
th:if=
'${model.currentUser != null && model.currentUser.hasRole("ADMIN")}'
>
Orders
</a></li>
<li
class=
"nav-item"
><a
class=
"nav-link active"
th:href=
"@{/cart}"
th:if=
'${model.currentUser != null && model.currentUser.hasRole("ADMIN")}'
>
Cart test
</a></li>
<div
class=
"vr"
th:if=
"${model.currentUser}"
></div>
<li
class=
"nav-item dropdown"
th:if=
"${model.currentUser}"
>
<a
class=
"nav-link dropdown-toggle"
href=
"#"
id=
"navbarDropdown"
role=
"button"
data-bs-toggle=
"dropdown"
aria-haspopup=
"true"
aria-expanded=
"false"
th:text=
"${model.currentUser.email}"
>
...
...
winery/webapp/src/main/resources/templates/order/edit.html
View file @
ef752cef
...
...
@@ -43,7 +43,7 @@
<h3>
Items
</h3>
<div
th:each=
"entry, stat : *{items}"
>
<span
th:text=
"*{wineNames[__${entry.bottleId}__]}"
/>
<input
type=
"number"
id=
"quantity"
name=
"quantity"
min=
"1"
max=
"5"
th:field=
"*{quantities[__${entry.id}__]}"
>
<input
type=
"number"
id=
"quantity"
name=
"quantity"
min=
"1"
th:field=
"*{quantities[__${entry.id}__]}"
>
</div>
<button
type=
"submit"
class=
"btn btn-primary"
>
Submit
</button>
</form>
...
...
winery/webapp/src/main/resources/templates/winebottle/detail.html
View file @
ef752cef
...
...
@@ -42,7 +42,7 @@
</table>
<div
class=
"mb-2"
>
<input
id=
"itemCount"
type=
"number"
value=
"1"
/>
<input
id=
"itemCount"
type=
"number"
min=
"1"
value=
"1"
/>
<a
class=
"btn btn-primary btn-sm"
href=
"#"
th:onclick=
"'addToCart(' + ${model.id} + ', document.getElementById(\'itemCount\').value).then(x => document.getElementById(\'success-alert\').style.display = \'block\')'"
>
Add to cart
</a>
</div>
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment