606 lines
14 KiB
Go
606 lines
14 KiB
Go
package controllers
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
|
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
|
//"git.dynamicdiscord.de/kalipso/zineshop/services"
|
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
|
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
|
)
|
|
|
|
type CartItemController interface {
|
|
//CRUDController
|
|
CartItemView(*gin.Context)
|
|
AddItemHandler(*gin.Context)
|
|
DeleteItemHandler(*gin.Context)
|
|
EditItemHandler(*gin.Context)
|
|
CheckoutView(*gin.Context)
|
|
CheckoutHandler(*gin.Context)
|
|
OrderView(*gin.Context)
|
|
OrderHandler(*gin.Context)
|
|
OrdersView(*gin.Context)
|
|
OrdersHandler(*gin.Context)
|
|
}
|
|
|
|
type cartItemController struct{}
|
|
|
|
func NewCartItemController() CartItemController {
|
|
return &cartItemController{}
|
|
}
|
|
|
|
// getSetCookieValue retrieves the value of a cookie from the Set-Cookie header
|
|
func getSetCookieValue(c *gin.Context, cookieName string) string {
|
|
// Check the Set-Cookie headers
|
|
cookies := c.Writer.Header()["Set-Cookie"]
|
|
for _, cookie := range cookies {
|
|
if strings.HasPrefix(cookie, cookieName+"=") {
|
|
// Extract the cookie value
|
|
parts := strings.SplitN(cookie, ";", 2)
|
|
if len(parts) > 0 {
|
|
return strings.TrimPrefix(parts[0], cookieName+"=")
|
|
}
|
|
}
|
|
}
|
|
return "" // Return empty string if cookie is not found
|
|
}
|
|
|
|
func GetSessionId(ctx *gin.Context) string {
|
|
sessionId, err := ctx.Cookie("session_id")
|
|
|
|
if err != nil {
|
|
//we need to check if we already set cookie in the response so that we dont do this multiple times
|
|
responseCookie := getSetCookieValue(ctx, "session_id")
|
|
|
|
if len(responseCookie) != 0 {
|
|
return responseCookie
|
|
}
|
|
|
|
sessionId = utils.GenerateSessionId(16)
|
|
ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true)
|
|
}
|
|
|
|
return sessionId
|
|
}
|
|
|
|
func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) {
|
|
sessionId := GetSessionId(ctx)
|
|
shopItemIdStr := ctx.PostForm("ShopItemId")
|
|
shopItemId, err := strconv.Atoi(shopItemIdStr)
|
|
itemVariantIdStr := ctx.PostForm("ItemVariantId")
|
|
itemVariantId, err := strconv.Atoi(itemVariantIdStr)
|
|
|
|
if err != nil {
|
|
return models.CartItem{}, err
|
|
}
|
|
|
|
quantity := 1
|
|
|
|
shopItem, err := repositories.ShopItems.GetById(shopItemIdStr)
|
|
|
|
if err != nil {
|
|
return models.CartItem{}, err
|
|
}
|
|
|
|
itemVariant, err := repositories.ShopItems.GetVariantById(itemVariantIdStr)
|
|
|
|
cartItem := models.CartItem{
|
|
SessionId: sessionId,
|
|
ShopItemId: uint(shopItemId),
|
|
ShopItem: shopItem,
|
|
ItemVariantId: uint(itemVariantId),
|
|
ItemVariant: itemVariant,
|
|
Quantity: quantity,
|
|
}
|
|
|
|
return cartItem, nil
|
|
}
|
|
|
|
func (rc *cartItemController) NewAddressFromForm(ctx *gin.Context) (models.AddressInfo, error) {
|
|
firstName := ctx.PostForm("firstName")
|
|
lastName := ctx.PostForm("lastName")
|
|
address := ctx.PostForm("address")
|
|
postalCode := ctx.PostForm("postalCode")
|
|
city := ctx.PostForm("city")
|
|
country := ctx.PostForm("country")
|
|
|
|
if firstName == "" {
|
|
return models.AddressInfo{}, fmt.Errorf("first name missing.")
|
|
}
|
|
|
|
if lastName == "" {
|
|
return models.AddressInfo{}, fmt.Errorf("Last name missing.")
|
|
}
|
|
|
|
if address == "" {
|
|
return models.AddressInfo{}, fmt.Errorf("address missing.")
|
|
}
|
|
|
|
if postalCode == "" {
|
|
return models.AddressInfo{}, fmt.Errorf("postalCode missing.")
|
|
}
|
|
|
|
if city == "" {
|
|
return models.AddressInfo{}, fmt.Errorf("city missing.")
|
|
}
|
|
|
|
if country == "" {
|
|
return models.AddressInfo{}, fmt.Errorf("country missing.")
|
|
}
|
|
|
|
return models.AddressInfo{
|
|
FirstName: firstName,
|
|
LastName: lastName,
|
|
Address: address,
|
|
PostalCode: postalCode,
|
|
City: city,
|
|
Country: country,
|
|
}, nil
|
|
}
|
|
|
|
func (rc *cartItemController) NewOrderFromForm(ctx *gin.Context) (models.Order, error) {
|
|
sessionId := GetSessionId(ctx)
|
|
status := models.OrderStatus("AwaitingConfirmation")
|
|
token := utils.GenerateToken()
|
|
email := ctx.PostForm("email")
|
|
comment := ctx.PostForm("comment")
|
|
firstName := ctx.PostForm("firstName")
|
|
lastName := ctx.PostForm("lastName")
|
|
address := ctx.PostForm("address")
|
|
postalCode := ctx.PostForm("postalCode")
|
|
city := ctx.PostForm("city")
|
|
country := ctx.PostForm("country")
|
|
shippingStr := ctx.PostForm("shippingMethod")
|
|
|
|
//address, err := rc.NewAddressFromForm(ctx)
|
|
//if shippingStr != "pickup" {
|
|
// if err != nil {
|
|
// return models.Order{}, fmt.Errorf("Invalid address information.")
|
|
// }
|
|
//}
|
|
|
|
shipping, err := models.GetShippingMethod(shippingStr)
|
|
|
|
if err != nil {
|
|
return models.Order{}, fmt.Errorf("Invalid shipping method.")
|
|
}
|
|
|
|
cartItems, err := repositories.CartItems.GetAllBySession(sessionId)
|
|
fmt.Println(sessionId)
|
|
fmt.Println(cartItems)
|
|
|
|
if err != nil {
|
|
return models.Order{}, err
|
|
}
|
|
|
|
order := models.Order{
|
|
SessionId: sessionId,
|
|
Status: status,
|
|
Token: token,
|
|
Email: email,
|
|
Comment: comment,
|
|
FirstName: firstName,
|
|
LastName: lastName,
|
|
Address: address,
|
|
PostalCode: postalCode,
|
|
City: city,
|
|
Country: country,
|
|
Shipping: shipping.Id,
|
|
CartItems: cartItems,
|
|
}
|
|
|
|
return order, nil
|
|
}
|
|
|
|
func (rc *cartItemController) Create(c *gin.Context) {
|
|
cartItem, err := rc.NewCartItemFromForm(c)
|
|
|
|
if err != nil {
|
|
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
|
return
|
|
}
|
|
|
|
_, err = repositories.CartItems.Create(cartItem)
|
|
|
|
if err != nil {
|
|
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
|
return
|
|
}
|
|
|
|
ReplyOK(c, "cartItem was created")
|
|
}
|
|
|
|
func (rc *cartItemController) Update(c *gin.Context) {
|
|
cartItem, err := rc.NewCartItemFromForm(c)
|
|
|
|
if err != nil {
|
|
ReplyError(c, err)
|
|
return
|
|
}
|
|
|
|
_, err = repositories.CartItems.Update(cartItem)
|
|
|
|
if err != nil {
|
|
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
|
return
|
|
}
|
|
|
|
ReplyOK(c, "cartItem was updated")
|
|
}
|
|
|
|
//func (rc *cartItemController) Delete(c *gin.Context) {
|
|
// err := repositories.CartItems.DeleteBySessionId(c.Param("id"))
|
|
//
|
|
// if err != nil {
|
|
// ReplyError(c, fmt.Errorf("cartItem deletion failed: %s", err))
|
|
// return
|
|
// }
|
|
//
|
|
// ReplyOK(c, "cartItem was deleted")
|
|
//}
|
|
|
|
func (rc *cartItemController) CartItemView(c *gin.Context) {
|
|
sessionId := GetSessionId(c)
|
|
|
|
cartItems, err := repositories.CartItems.GetAllBySession(sessionId)
|
|
//cartItems, err := repositories.CartItems.GetAll()
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "cart.html", gin.H{"data": gin.H{"error": err}})
|
|
}
|
|
|
|
priceTotal := 0.0
|
|
for _, cartItem := range cartItems {
|
|
priceTotal += (float64(cartItem.Quantity) * cartItem.ItemVariant.Price)
|
|
}
|
|
|
|
fmt.Println("PRICE TOTAL", priceTotal)
|
|
|
|
data := CreateSessionData(c, gin.H{
|
|
"cartItems": cartItems,
|
|
"priceTotal": fmt.Sprintf("%.2f", priceTotal), //round 2 decimals
|
|
"shipping": models.GetShippingMethods(),
|
|
})
|
|
|
|
c.HTML(http.StatusOK, "cart.html", data)
|
|
}
|
|
|
|
func (rc *cartItemController) AddItemHandler(c *gin.Context) {
|
|
cartItem, err := rc.NewCartItemFromForm(c)
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
|
|
_, err = repositories.CartItems.Create(cartItem)
|
|
if err != nil {
|
|
data := CreateSessionData(c, gin.H{
|
|
"error": err,
|
|
"success": "",
|
|
})
|
|
|
|
c.HTML(http.StatusOK, "cart.html", data)
|
|
return
|
|
}
|
|
|
|
rc.CartItemView(c)
|
|
}
|
|
|
|
func (rc *cartItemController) DeleteItemHandler(c *gin.Context) {
|
|
err := repositories.CartItems.DeleteById(c.PostForm("id"))
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
data := CreateSessionData(c, gin.H{
|
|
"error": err,
|
|
"success": "",
|
|
})
|
|
|
|
c.HTML(http.StatusOK, "index.html", data)
|
|
}
|
|
|
|
c.Redirect(http.StatusFound, "/cart")
|
|
}
|
|
|
|
func (rc *cartItemController) EditItemHandler(c *gin.Context) {
|
|
cartItemId := c.PostForm("id")
|
|
cartItem, err := repositories.CartItems.GetById(cartItemId)
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
c.Redirect(http.StatusFound, "/cart")
|
|
return
|
|
}
|
|
|
|
action := c.PostForm("action")
|
|
|
|
if action == "setAmount" {
|
|
amountStr := c.PostForm("amount")
|
|
amount, err := strconv.Atoi(amountStr)
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
|
|
if amount < 0 {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "amount cant be negative"})
|
|
return
|
|
}
|
|
if amount > 500 {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "amount cant be over 500"})
|
|
return
|
|
}
|
|
|
|
cartItem.Quantity = amount
|
|
}
|
|
|
|
if action == "increase" {
|
|
cartItem.Quantity += 1
|
|
}
|
|
|
|
if action == "decrease" {
|
|
cartItem.Quantity -= 1
|
|
|
|
if cartItem.Quantity == 0 {
|
|
cartItem.Quantity = 1
|
|
}
|
|
}
|
|
|
|
_, err = repositories.CartItems.Update(cartItem)
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
|
|
c.Redirect(http.StatusFound, "/cart")
|
|
}
|
|
|
|
func (rc *cartItemController) CheckoutView(c *gin.Context) {
|
|
shippingMethod := c.Query("shippingMethod")
|
|
|
|
if shippingMethod == "" {
|
|
rc.CartItemView(c)
|
|
return
|
|
}
|
|
|
|
c.HTML(http.StatusOK, "checkout.html", gin.H{
|
|
"askAddress": (shippingMethod != "pickup"),
|
|
"shippingMethod": shippingMethod,
|
|
})
|
|
}
|
|
|
|
func (rc *cartItemController) CheckoutHandler(c *gin.Context) {
|
|
order, err := rc.NewOrderFromForm(c)
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
|
|
existingOrder, err := repositories.Orders.GetBySession(order.SessionId)
|
|
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
fmt.Println("Creating Order")
|
|
createdOrder, err := repositories.Orders.Create(order)
|
|
|
|
if err != nil {
|
|
data := CreateSessionData(c, gin.H{
|
|
"error": err,
|
|
"success": "",
|
|
})
|
|
|
|
c.HTML(http.StatusOK, "error.html", data)
|
|
return
|
|
}
|
|
|
|
for _, cartItem := range order.CartItems {
|
|
cartItem.OrderID = createdOrder.ID
|
|
repositories.CartItems.Update(cartItem)
|
|
}
|
|
} else if err == nil {
|
|
fmt.Println("Updating Order")
|
|
order.ID = existingOrder.ID
|
|
order.CreatedAt = existingOrder.CreatedAt
|
|
_, err := repositories.Orders.Update(order)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
}
|
|
|
|
shipping, err := models.GetShippingMethod(order.Shipping)
|
|
if err != nil {
|
|
data := CreateSessionData(c, gin.H{
|
|
"error": err,
|
|
"success": "",
|
|
})
|
|
|
|
c.HTML(http.StatusOK, "error.html", data)
|
|
return
|
|
}
|
|
|
|
priceProducts, priceTotal, err := order.CalculatePrices()
|
|
if err != nil {
|
|
data := CreateSessionData(c, gin.H{
|
|
"error": err,
|
|
"success": "",
|
|
})
|
|
|
|
c.HTML(http.StatusOK, "error.html", data)
|
|
return
|
|
}
|
|
|
|
data := CreateSessionData(c, gin.H{
|
|
"error": "",
|
|
"success": "",
|
|
"order": order,
|
|
"askAddress": (order.Shipping != "pickup"),
|
|
"isPreview": true,
|
|
"shipping": shipping,
|
|
"priceProducts": fmt.Sprintf("%.2f", priceProducts), //round 2 decimals
|
|
"priceTotal": fmt.Sprintf("%.2f", priceTotal), //round 2 decimals
|
|
})
|
|
|
|
fmt.Println(order)
|
|
c.HTML(http.StatusOK, "orderpreview.html", data)
|
|
}
|
|
|
|
func (rc *cartItemController) OrderView(c *gin.Context) {
|
|
orderToken := c.Param("token")
|
|
|
|
order, err := repositories.Orders.GetByToken(orderToken)
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Order does not exist."})
|
|
return
|
|
}
|
|
|
|
shipping, err := models.GetShippingMethod(order.Shipping)
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Could not get shipping method"})
|
|
return
|
|
}
|
|
|
|
priceProducts, priceTotal, err := order.CalculatePrices()
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Could not calculate final prices"})
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Order: %v\n", order)
|
|
fmt.Printf("PriceTotal: %v\n", priceTotal)
|
|
fmt.Printf("Amount Items: %v\n", len(order.CartItems))
|
|
|
|
for _, item := range order.CartItems {
|
|
fmt.Printf("Cartitem: %v", item)
|
|
}
|
|
|
|
c.HTML(http.StatusOK, "order.html", CreateSessionData(c, gin.H{
|
|
"error": "",
|
|
"success": "",
|
|
"order": order,
|
|
"shipping": shipping,
|
|
"priceProducts": fmt.Sprintf("%.2f", priceProducts), //round 2 decimals
|
|
"priceTotal": fmt.Sprintf("%.2f", priceTotal), //round 2 decimals
|
|
}))
|
|
}
|
|
|
|
func (rc *cartItemController) OrderHandler(c *gin.Context) {
|
|
confirmation := c.PostForm("confirm-order")
|
|
|
|
if confirmation == "" {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Something went wrong, try again later"})
|
|
return
|
|
}
|
|
|
|
if confirmation != "true" {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Order was not confirmed."})
|
|
return
|
|
}
|
|
|
|
sessionId := GetSessionId(c)
|
|
order, err := repositories.Orders.GetBySession(sessionId)
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Something went wrong, try again later"})
|
|
return
|
|
}
|
|
|
|
order.Status = models.AwaitingPayment
|
|
|
|
err = order.Validate()
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
|
|
for idx := range order.CartItems {
|
|
order.CartItems[idx].SessionId = "0"
|
|
repositories.CartItems.Update(order.CartItems[idx])
|
|
}
|
|
|
|
_, err = repositories.Orders.Update(order)
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
|
|
//TODO: cartItemRepository delete all by session - otherwise items stay in cart after completing order..
|
|
|
|
c.Redirect(http.StatusFound, fmt.Sprintf("/order/%s", order.Token))
|
|
}
|
|
|
|
func (rc *cartItemController) OrdersView(c *gin.Context) {
|
|
orders, err := repositories.Orders.GetAll()
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Orders doe not exist."})
|
|
return
|
|
}
|
|
|
|
c.HTML(http.StatusOK, "editorders.html", CreateSessionData(c, gin.H{
|
|
"error": "",
|
|
"success": "",
|
|
"orders": orders,
|
|
}))
|
|
}
|
|
|
|
func (rc *cartItemController) OrdersHandler(c *gin.Context) {
|
|
token := c.Param("token")
|
|
|
|
if token == "" {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "EmptyToken"})
|
|
return
|
|
}
|
|
|
|
action := c.PostForm("action")
|
|
|
|
if action == "update" {
|
|
order, err := repositories.Orders.GetByToken(token)
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "No order with given token found"})
|
|
return
|
|
}
|
|
|
|
status := c.PostForm("order-status")
|
|
|
|
//TODO validate status
|
|
if status == "" {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "Invalid Order Status"})
|
|
return
|
|
}
|
|
|
|
order.Status = models.OrderStatus(status)
|
|
|
|
_, err = repositories.Orders.Update(order)
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
}
|
|
|
|
if action == "delete" {
|
|
fmt.Println("Deleting Order ", token)
|
|
err := repositories.Orders.DeleteByToken(token)
|
|
|
|
if err != nil {
|
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
|
return
|
|
}
|
|
}
|
|
|
|
c.Redirect(http.StatusFound, "/orders")
|
|
}
|