Compare commits
33 Commits
1efc5417be
...
countries_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fd9472db1 | ||
| 80a1314dc0 | |||
|
|
100a9f57d4 | ||
| 773e7d3c20 | |||
| 03a0e5ea64 | |||
| ce8c19f715 | |||
| 4edcb0a852 | |||
| a4120dafa2 | |||
| 5e1a8e898c | |||
|
|
c610ce38cc | ||
| 8e3e41d6fe | |||
| b33da9d072 | |||
|
|
604247b7c8 | ||
| e5988a85f3 | |||
|
|
0cb5cc47bb | ||
| ab783b599d | |||
| d173af29fe | |||
| f14d60d67b | |||
| 967b101f9b | |||
| 97ca510b99 | |||
| 26cbdeec0a | |||
| 83b7cd49dd | |||
|
|
1f6d5ecb72 | ||
|
|
d4d55e2757 | ||
|
|
80d26bba12 | ||
|
|
33e9d016e9 | ||
|
|
a03a2b461f | ||
|
|
134bc4ea53 | ||
|
|
8595969c6e | ||
|
|
a6aa06faa0 | ||
|
|
4f4b32b131 | ||
|
|
dfdf8b4db9 | ||
|
|
438a13c04c |
@@ -7,17 +7,18 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/config"
|
"git.ma-al.com/goc_daniel/b2b/app/config"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
|
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
|
||||||
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthMiddleware creates authentication middleware
|
// AuthMiddleware creates authentication middleware
|
||||||
func AuthMiddleware() fiber.Handler {
|
func Authenticate() fiber.Handler {
|
||||||
authService := authService.NewAuthService()
|
authService := authService.NewAuthService()
|
||||||
|
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
// Get token from Authorization header
|
// Get token from Authorization header
|
||||||
authHeader := c.Get("Authorization")
|
authHeader := c.Get("Authorization")
|
||||||
@@ -25,17 +26,13 @@ func AuthMiddleware() fiber.Handler {
|
|||||||
// Try to get from cookie
|
// Try to get from cookie
|
||||||
authHeader = c.Cookies("access_token")
|
authHeader = c.Cookies("access_token")
|
||||||
if authHeader == "" {
|
if authHeader == "" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Next()
|
||||||
"error": "authorization token required",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Extract token from "Bearer <token>"
|
// Extract token from "Bearer <token>"
|
||||||
parts := strings.Split(authHeader, " ")
|
parts := strings.Split(authHeader, " ")
|
||||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Next()
|
||||||
"error": "invalid authorization header format",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
authHeader = parts[1]
|
authHeader = parts[1]
|
||||||
}
|
}
|
||||||
@@ -43,24 +40,18 @@ func AuthMiddleware() fiber.Handler {
|
|||||||
// Validate token
|
// Validate token
|
||||||
claims, err := authService.ValidateToken(authHeader)
|
claims, err := authService.ValidateToken(authHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Next()
|
||||||
"error": "invalid or expired token",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get user from database
|
// Get user from database
|
||||||
user, err := authService.GetUserByID(claims.UserID)
|
user, err := authService.GetUserByID(claims.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
return c.Next()
|
||||||
"error": "user not found",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user is active
|
// Check if user is active
|
||||||
if !user.IsActive {
|
if !user.IsActive {
|
||||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
return c.Next()
|
||||||
"error": "user account is inactive",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create locale. LangID is overwritten by auth Token
|
// Create locale. LangID is overwritten by auth Token
|
||||||
@@ -78,10 +69,8 @@ func AuthMiddleware() fiber.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We now populate the target user
|
// We now populate the target user
|
||||||
if model.CustomerRole(user.Role.Name) != model.RoleAdmin {
|
if !userLocale.OriginalUser.HasPermission(perms.Teleport) {
|
||||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
return c.Next()
|
||||||
"error": "admin access required",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
targetUserID, err := strconv.Atoi(targetUserIDAttribute)
|
targetUserID, err := strconv.Atoi(targetUserIDAttribute)
|
||||||
@@ -114,6 +103,18 @@ func AuthMiddleware() fiber.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Authorize() fiber.Handler {
|
||||||
|
return func(c fiber.Ctx) error {
|
||||||
|
_, ok := localeExtractor.GetUserID(c)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"error": "not authenticated",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Webdav
|
// Webdav
|
||||||
func Webdav() fiber.Handler {
|
func Webdav() fiber.Handler {
|
||||||
authService := authService.NewAuthService()
|
authService := authService.NewAuthService()
|
||||||
|
|||||||
@@ -12,4 +12,7 @@ const (
|
|||||||
ProductTranslationSave Permission = "product_translation.save"
|
ProductTranslationSave Permission = "product_translation.save"
|
||||||
ProductTranslationTranslate Permission = "product_translation.translate"
|
ProductTranslationTranslate Permission = "product_translation.translate"
|
||||||
SearchCreateIndex Permission = "search.create_index"
|
SearchCreateIndex Permission = "search.create_index"
|
||||||
|
OrdersViewAll Permission = "orders.view_all"
|
||||||
|
OrdersModifyAll Permission = "orders.modify_all"
|
||||||
|
Teleport Permission = "teleport"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func AuthHandlerRoutes(r fiber.Router) fiber.Router {
|
|||||||
r.Get("/google", handler.GoogleLogin)
|
r.Get("/google", handler.GoogleLogin)
|
||||||
r.Get("/google/callback", handler.GoogleCallback)
|
r.Get("/google/callback", handler.GoogleCallback)
|
||||||
|
|
||||||
authProtected := r.Group("", middleware.AuthMiddleware())
|
authProtected := r.Group("", middleware.Authorize())
|
||||||
authProtected.Get("/me", handler.Me)
|
authProtected.Get("/me", handler.Me)
|
||||||
authProtected.Post("/update-choice", handler.UpdateJWTToken)
|
authProtected.Post("/update-choice", handler.UpdateJWTToken)
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package public
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/service/menuService"
|
"git.ma-al.com/goc_daniel/b2b/app/service/menuService"
|
||||||
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
||||||
@@ -31,12 +32,21 @@ func RoutingHandlerRoutes(r fiber.Router) fiber.Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *RoutingHandler) GetRouting(c fiber.Ctx) error {
|
func (h *RoutingHandler) GetRouting(c fiber.Ctx) error {
|
||||||
lang_id, ok := localeExtractor.GetLangID(c)
|
langId, ok := localeExtractor.GetLangID(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
}
|
}
|
||||||
menu, err := h.menuService.GetRoutes(lang_id)
|
|
||||||
|
var roleId uint
|
||||||
|
customer, ok := localeExtractor.GetCustomer(c)
|
||||||
|
if !ok {
|
||||||
|
roleId = constdata.UNLOGGED_USER_ROLE_ID
|
||||||
|
} else {
|
||||||
|
roleId = customer.RoleID
|
||||||
|
}
|
||||||
|
|
||||||
|
menu, err := h.menuService.GetRoutes(langId, roleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(responseErrors.GetErrorStatus(err)).
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
|||||||
@@ -124,13 +124,13 @@ func (h *AddressesHandler) RetrieveAddressesInfo(c fiber.Ctx) error {
|
|||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
}
|
}
|
||||||
|
|
||||||
addresses_info, err := h.addressesService.RetrieveAddressesInfo(userID)
|
addresses, err := h.addressesService.RetrieveAddresses(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(responseErrors.GetErrorStatus(err)).
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.JSON(response.Make(&addresses_info, 0, i18n.T_(c, response.Message_OK)))
|
return c.JSON(response.Make(addresses, 0, i18n.T_(c, response.Message_OK)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AddressesHandler) DeleteAddress(c fiber.Ctx) error {
|
func (h *AddressesHandler) DeleteAddress(c fiber.Ctx) error {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package restricted
|
|||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
|
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/service/customerService"
|
"git.ma-al.com/goc_daniel/b2b/app/service/customerService"
|
||||||
@@ -30,7 +31,7 @@ func CustomerHandlerRoutes(r fiber.Router) fiber.Router {
|
|||||||
handler := NewCustomerHandler()
|
handler := NewCustomerHandler()
|
||||||
|
|
||||||
r.Get("", handler.customerData)
|
r.Get("", handler.customerData)
|
||||||
r.Get("/list", handler.listCustomers)
|
r.Get("/list", middleware.Require(perms.UserReadAny), handler.listCustomers)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,10 +76,6 @@ func (h *customerHandler) listCustomers(fc fiber.Ctx) error {
|
|||||||
return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
return fc.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrBadAttribute)))
|
||||||
}
|
}
|
||||||
if !user.HasPermission(perms.UserReadAny) {
|
|
||||||
return fc.Status(fiber.StatusForbidden).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
|
|
||||||
}
|
|
||||||
|
|
||||||
p, filt, err := query_params.ParseFilters[model.Customer](fc, columnMappingListUsers)
|
p, filt, err := query_params.ParseFilters[model.Customer](fc, columnMappingListUsers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -87,12 +84,6 @@ func (h *customerHandler) listCustomers(fc fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
search := fc.Query("search")
|
search := fc.Query("search")
|
||||||
if search != "" {
|
|
||||||
if !user.HasPermission(perms.UserReadAny) {
|
|
||||||
return fc.Status(fiber.StatusForbidden).
|
|
||||||
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(fc, responseErrors.ErrForbidden)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customer, err := h.service.Find(user.LangID, p, filt, search)
|
customer, err := h.service.Find(user.LangID, p, filt, search)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
171
app/delivery/web/api/restricted/orders.go
Normal file
171
app/delivery/web/api/restricted/orders.go
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
package restricted
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/service/orderService"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/nullable"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/query_params"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/response"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
||||||
|
"github.com/gofiber/fiber/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrdersHandler struct {
|
||||||
|
ordersService *orderService.OrderService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOrdersHandler() *OrdersHandler {
|
||||||
|
ordersService := orderService.New()
|
||||||
|
return &OrdersHandler{
|
||||||
|
ordersService: ordersService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func OrdersHandlerRoutes(r fiber.Router) fiber.Router {
|
||||||
|
handler := NewOrdersHandler()
|
||||||
|
|
||||||
|
r.Get("/list", handler.ListOrders)
|
||||||
|
r.Post("/place-new-order", handler.PlaceNewOrder)
|
||||||
|
r.Post("/change-order-address", handler.ChangeOrderAddress)
|
||||||
|
r.Get("/change-order-status", handler.ChangeOrderStatus)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// when a user (not admin) wants to list orders, we automatically append filter to only view his orders.
|
||||||
|
// we base permissions and user based on target user only.
|
||||||
|
func (h *OrdersHandler) ListOrders(c fiber.Ctx) error {
|
||||||
|
user, ok := localeExtractor.GetCustomer(c)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
paging, filters, err := query_params.ParseFilters[model.CustomerOrder](c, columnMappingListOrders)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := h.ordersService.Find(user, paging, filters)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(&list.Items, int(list.Count), i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var columnMappingListOrders map[string]string = map[string]string{
|
||||||
|
"order_id": "b2b_customer_orders.order_id",
|
||||||
|
"user_id": "b2b_customer_orders.user_id",
|
||||||
|
"name": "b2b_customer_orders.name",
|
||||||
|
"country_id": "b2b_customer_orders.country_id",
|
||||||
|
"status": "b2b_customer_orders.status",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *OrdersHandler) PlaceNewOrder(c fiber.Ctx) error {
|
||||||
|
userID, ok := localeExtractor.GetUserID(c)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
cart_id_attribute := c.Query("cart_id")
|
||||||
|
cart_id, err := strconv.Atoi(cart_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
country_id_attribute := c.Query("country_id")
|
||||||
|
country_id, err := strconv.Atoi(country_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
address_info := string(c.Body())
|
||||||
|
if address_info == "" {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
name := c.Query("name")
|
||||||
|
|
||||||
|
err = h.ordersService.PlaceNewOrder(userID, uint(cart_id), name, uint(country_id), address_info)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// we base permissions and user based on target user only.
|
||||||
|
func (h *OrdersHandler) ChangeOrderAddress(c fiber.Ctx) error {
|
||||||
|
user, ok := localeExtractor.GetCustomer(c)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
order_id_attribute := c.Query("order_id")
|
||||||
|
order_id, err := strconv.Atoi(order_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
country_id_attribute := c.Query("country_id")
|
||||||
|
country_id, err := strconv.Atoi(country_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
address_info := string(c.Body())
|
||||||
|
if address_info == "" {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.ordersService.ChangeOrderAddress(user, uint(order_id), uint(country_id), address_info)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// we base permissions and user based on target user only.
|
||||||
|
// TODO: well, permissions and all that.
|
||||||
|
func (h *OrdersHandler) ChangeOrderStatus(c fiber.Ctx) error {
|
||||||
|
user, ok := localeExtractor.GetCustomer(c)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
|
||||||
|
}
|
||||||
|
|
||||||
|
order_id_attribute := c.Query("order_id")
|
||||||
|
order_id, err := strconv.Atoi(order_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
status := c.Query("status")
|
||||||
|
|
||||||
|
err = h.ordersService.ChangeOrderStatus(user, uint(order_id), status)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(nullable.GetNil(""), 0, i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
@@ -86,9 +86,10 @@ func (s *Server) Setup() error {
|
|||||||
|
|
||||||
// API routes
|
// API routes
|
||||||
s.api = s.app.Group("/api/v1")
|
s.api = s.app.Group("/api/v1")
|
||||||
|
s.api.Use(middleware.Authenticate())
|
||||||
s.public = s.api.Group("/public")
|
s.public = s.api.Group("/public")
|
||||||
s.restricted = s.api.Group("/restricted")
|
s.restricted = s.api.Group("/restricted")
|
||||||
s.restricted.Use(middleware.AuthMiddleware())
|
s.restricted.Use(middleware.Authorize())
|
||||||
s.webdav = s.api.Group("/webdav")
|
s.webdav = s.api.Group("/webdav")
|
||||||
s.webdav.Use(middleware.Webdav())
|
s.webdav.Use(middleware.Webdav())
|
||||||
|
|
||||||
@@ -132,8 +133,13 @@ func (s *Server) Setup() error {
|
|||||||
carts := s.restricted.Group("/carts")
|
carts := s.restricted.Group("/carts")
|
||||||
restricted.CartsHandlerRoutes(carts)
|
restricted.CartsHandlerRoutes(carts)
|
||||||
|
|
||||||
|
// orders (restricted)
|
||||||
|
orders := s.restricted.Group("/orders")
|
||||||
|
restricted.OrdersHandlerRoutes(orders)
|
||||||
|
|
||||||
specificPrice := s.restricted.Group("/specific-price")
|
specificPrice := s.restricted.Group("/specific-price")
|
||||||
restricted.SpecificPriceHandlerRoutes(specificPrice)
|
restricted.SpecificPriceHandlerRoutes(specificPrice)
|
||||||
|
|
||||||
// addresses (restricted)
|
// addresses (restricted)
|
||||||
addresses := s.restricted.Group("/addresses")
|
addresses := s.restricted.Group("/addresses")
|
||||||
restricted.AddressesHandlerRoutes(addresses)
|
restricted.AddressesHandlerRoutes(addresses)
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
type Address struct {
|
type Address struct {
|
||||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||||
CustomerID uint `gorm:"column:b2b_customer_id;not null;index" json:"customer_id"`
|
CustomerID uint `gorm:"column:b2b_customer_id;not null;index" json:"customer_id"`
|
||||||
AddressInfo string `gorm:"column:address_info;not null" json:"address_info"`
|
AddressString string `gorm:"column:address_string;not null" json:"address_string"`
|
||||||
CountryID uint `gorm:"column:b2b_country_id;not null" json:"country_id"`
|
AddressUnparsed *AddressUnparsed `gorm:"-" json:"address_unparsed"`
|
||||||
|
CountryID uint `gorm:"column:b2b_country_id;not null" json:"country_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Address) TableName() string {
|
func (Address) TableName() string {
|
||||||
return "b2b_addresses"
|
return "b2b_addresses"
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddressUnparsed struct {
|
type AddressUnparsed interface{}
|
||||||
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
|
||||||
CustomerID uint `gorm:"column:b2b_customer_id;not null;index" json:"customer_id"`
|
|
||||||
AddressInfo AddressField `gorm:"column:address_info;not null" json:"address_info"`
|
|
||||||
CountryID uint `gorm:"column:b2b_country_id;not null" json:"country_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddressField interface {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Address template in Poland
|
// Address template in Poland
|
||||||
type AddressPL struct {
|
type AddressPL struct {
|
||||||
|
|||||||
27
app/model/order.go
Normal file
27
app/model/order.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type CustomerOrder struct {
|
||||||
|
OrderID uint `gorm:"column:order_id;primaryKey;autoIncrement" json:"order_id"`
|
||||||
|
UserID uint `gorm:"column:user_id;not null;index" json:"user_id"`
|
||||||
|
Name string `gorm:"column:name;not null" json:"name"`
|
||||||
|
CountryID uint `gorm:"column:country_id;not null" json:"country_id"`
|
||||||
|
AddressString string `gorm:"column:address_string;not null" json:"address_string"`
|
||||||
|
AddressUnparsed *AddressUnparsed `gorm:"-" json:"address_unparsed"`
|
||||||
|
Status string `gorm:"column:status;size:50;not null" json:"status"`
|
||||||
|
Products []OrderProduct `gorm:"foreignKey:OrderID;references:OrderID" json:"products"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (CustomerOrder) TableName() string {
|
||||||
|
return "b2b_customer_orders"
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderProduct struct {
|
||||||
|
OrderID uint `gorm:"column:order_id;not null;index" json:"-"`
|
||||||
|
ProductID uint `gorm:"column:product_id;not null" json:"product_id"`
|
||||||
|
ProductAttributeID *uint `gorm:"column:product_attribute_id" json:"product_attribute_id,omitempty"`
|
||||||
|
Amount uint `gorm:"column:amount;not null" json:"amount"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (OrderProduct) TableName() string {
|
||||||
|
return "b2b_orders_products"
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ type Route struct {
|
|||||||
Component string `gorm:"type:varchar(255);not null;comment:path to component file" json:"component"`
|
Component string `gorm:"type:varchar(255);not null;comment:path to component file" json:"component"`
|
||||||
Meta *string `gorm:"type:longtext;default:'{}'" json:"meta,omitempty"`
|
Meta *string `gorm:"type:longtext;default:'{}'" json:"meta,omitempty"`
|
||||||
Active *bool `gorm:"type:tinyint;default:1" json:"active,omitempty"`
|
Active *bool `gorm:"type:tinyint;default:1" json:"active,omitempty"`
|
||||||
SortOrder *int `gorm:"type:int;default:0" json:"sort_order,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Route) TableName() string {
|
func (Route) TableName() string {
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ func (repo *AddressesRepo) UserAddressesAmt(user_id uint) (uint, error) {
|
|||||||
|
|
||||||
func (repo *AddressesRepo) AddNewAddress(user_id uint, address_info string, country_id uint) error {
|
func (repo *AddressesRepo) AddNewAddress(user_id uint, address_info string, country_id uint) error {
|
||||||
address := model.Address{
|
address := model.Address{
|
||||||
CustomerID: user_id,
|
CustomerID: user_id,
|
||||||
AddressInfo: address_info,
|
AddressString: address_info,
|
||||||
CountryID: country_id,
|
CountryID: country_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.DB.
|
return db.DB.
|
||||||
@@ -60,10 +60,10 @@ func (repo *AddressesRepo) AddNewAddress(user_id uint, address_info string, coun
|
|||||||
|
|
||||||
func (repo *AddressesRepo) UpdateAddress(user_id uint, address_id uint, address_info string, country_id uint) error {
|
func (repo *AddressesRepo) UpdateAddress(user_id uint, address_id uint, address_info string, country_id uint) error {
|
||||||
address := model.Address{
|
address := model.Address{
|
||||||
ID: address_id,
|
ID: address_id,
|
||||||
CustomerID: user_id,
|
CustomerID: user_id,
|
||||||
AddressInfo: address_info,
|
AddressString: address_info,
|
||||||
CountryID: country_id,
|
CountryID: country_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.DB.
|
return db.DB.
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ import (
|
|||||||
type UICartsRepo interface {
|
type UICartsRepo interface {
|
||||||
CartsAmount(user_id uint) (uint, error)
|
CartsAmount(user_id uint) (uint, error)
|
||||||
CreateNewCart(user_id uint) (model.CustomerCart, error)
|
CreateNewCart(user_id uint) (model.CustomerCart, error)
|
||||||
UserHasCart(user_id uint, cart_id uint) (uint, error)
|
RemoveCart(user_id uint, cart_id uint) error
|
||||||
|
UserHasCart(user_id uint, cart_id uint) (bool, error)
|
||||||
UpdateCartName(user_id uint, cart_id uint, new_name string) error
|
UpdateCartName(user_id uint, cart_id uint, new_name string) error
|
||||||
RetrieveCartsInfo(user_id uint) ([]model.CustomerCart, error)
|
RetrieveCartsInfo(user_id uint) ([]model.CustomerCart, error)
|
||||||
RetrieveCart(user_id uint, cart_id uint) (*model.CustomerCart, error)
|
RetrieveCart(user_id uint, cart_id uint) (*model.CustomerCart, error)
|
||||||
CheckProductExists(product_id uint, product_attribute_id *uint) (uint, error)
|
CheckProductExists(product_id uint, product_attribute_id *uint) (bool, error)
|
||||||
AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error
|
AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +50,15 @@ func (repo *CartsRepo) CreateNewCart(user_id uint) (model.CustomerCart, error) {
|
|||||||
return cart, err
|
return cart, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *CartsRepo) UserHasCart(user_id uint, cart_id uint) (uint, error) {
|
func (repo *CartsRepo) RemoveCart(user_id uint, cart_id uint) error {
|
||||||
|
return db.DB.
|
||||||
|
Table("b2b_customer_carts").
|
||||||
|
Where("cart_id = ? AND user_id = ?", cart_id, user_id).
|
||||||
|
Delete(nil).
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *CartsRepo) UserHasCart(user_id uint, cart_id uint) (bool, error) {
|
||||||
var amt uint
|
var amt uint
|
||||||
|
|
||||||
err := db.DB.
|
err := db.DB.
|
||||||
@@ -59,7 +68,7 @@ func (repo *CartsRepo) UserHasCart(user_id uint, cart_id uint) (uint, error) {
|
|||||||
Scan(&amt).
|
Scan(&amt).
|
||||||
Error
|
Error
|
||||||
|
|
||||||
return amt, err
|
return amt >= 1, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *CartsRepo) UpdateCartName(user_id uint, cart_id uint, new_name string) error {
|
func (repo *CartsRepo) UpdateCartName(user_id uint, cart_id uint, new_name string) error {
|
||||||
@@ -96,7 +105,7 @@ func (repo *CartsRepo) RetrieveCart(user_id uint, cart_id uint) (*model.Customer
|
|||||||
return &cart, err
|
return &cart, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *CartsRepo) CheckProductExists(product_id uint, product_attribute_id *uint) (uint, error) {
|
func (repo *CartsRepo) CheckProductExists(product_id uint, product_attribute_id *uint) (bool, error) {
|
||||||
var amt uint
|
var amt uint
|
||||||
|
|
||||||
if product_attribute_id == nil {
|
if product_attribute_id == nil {
|
||||||
@@ -106,7 +115,7 @@ func (repo *CartsRepo) CheckProductExists(product_id uint, product_attribute_id
|
|||||||
Where("id_product = ?", product_id).
|
Where("id_product = ?", product_id).
|
||||||
Scan(&amt).
|
Scan(&amt).
|
||||||
Error
|
Error
|
||||||
return amt, err
|
return amt >= 1, err
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
err := db.DB.
|
err := db.DB.
|
||||||
@@ -116,7 +125,7 @@ func (repo *CartsRepo) CheckProductExists(product_id uint, product_attribute_id
|
|||||||
Where("ps.id_product = ? AND pas.id_product_attribute = ?", product_id, *product_attribute_id).
|
Where("ps.id_product = ? AND pas.id_product_attribute = ?", product_id, *product_attribute_id).
|
||||||
Scan(&amt).
|
Scan(&amt).
|
||||||
Error
|
Error
|
||||||
return amt, err
|
return amt >= 1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package customerRepo
|
package customerRepo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/db"
|
"git.ma-al.com/goc_daniel/b2b/app/db"
|
||||||
@@ -80,13 +81,16 @@ func (repo *CustomerRepo) Find(langId uint, p find.Paging, filt *filters.Filters
|
|||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
|
|
||||||
conditions = append(conditions, `
|
conditions = append(conditions, `
|
||||||
(LOWER(first_name) LIKE ? OR
|
(
|
||||||
|
id = ? OR
|
||||||
|
LOWER(first_name) LIKE ? OR
|
||||||
LOWER(last_name) LIKE ? OR
|
LOWER(last_name) LIKE ? OR
|
||||||
LOWER(email) LIKE ?)
|
LOWER(email) LIKE ?)
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
args = append(args, strings.ToLower(word))
|
||||||
for range 3 {
|
for range 3 {
|
||||||
args = append(args, "%"+strings.ToLower(word)+"%")
|
args = append(args, fmt.Sprintf("%%%s%%", strings.ToLower(word)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,88 +114,3 @@ func (repo *CustomerRepo) Save(customer *model.Customer) error {
|
|||||||
func (repo *CustomerRepo) Create(customer *model.Customer) error {
|
func (repo *CustomerRepo) Create(customer *model.Customer) error {
|
||||||
return db.DB.Create(customer).Error
|
return db.DB.Create(customer).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (repo *CustomerRepo) Search(
|
|
||||||
// customerId uint,
|
|
||||||
// partnerCode string,
|
|
||||||
// p find.Paging,
|
|
||||||
// filt *filters.FiltersList,
|
|
||||||
// search string,
|
|
||||||
// ) (found find.Found[model.UserInList], err error) {
|
|
||||||
// words := strings.Fields(search)
|
|
||||||
// if len(words) > 5 {
|
|
||||||
// words = words[:5]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// query := ctx.DB().
|
|
||||||
// Model(&model.Customer{}).
|
|
||||||
// Select("customer.id AS id, customer.first_name as first_name, customer.last_name as last_name, customer.phone_number AS phone_number, customer.email AS email, count(distinct investment_plan_contract.id) as iiplan_purchases, count(distinct `order`.id) as single_purchases, entity.name as entity_name").
|
|
||||||
// Where("customer.id <> ?", customerId).
|
|
||||||
// Where("(customer.id IN (SELECT id FROM customer WHERE partner_code IN (WITH RECURSIVE partners AS (SELECT code AS dst FROM partner WHERE code = ? UNION SELECT code FROM partner JOIN partners ON partners.dst = partner.superior_code) SELECT dst FROM partners)) OR customer.recommender_code = ?)", partnerCode, partnerCode).
|
|
||||||
// Scopes(view.CustomerListQuery())
|
|
||||||
|
|
||||||
// var conditions []string
|
|
||||||
// var args []interface{}
|
|
||||||
// for _, word := range words {
|
|
||||||
|
|
||||||
// conditions = append(conditions, `
|
|
||||||
// (LOWER(first_name) LIKE ? OR
|
|
||||||
// LOWER(last_name) LIKE ? OR
|
|
||||||
// phone_number LIKE ? OR
|
|
||||||
// LOWER(email) LIKE ?)
|
|
||||||
// `)
|
|
||||||
|
|
||||||
// for i := 0; i < 4; i++ {
|
|
||||||
// args = append(args, "%"+strings.ToLower(word)+"%")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// finalQuery := strings.Join(conditions, " AND ")
|
|
||||||
|
|
||||||
// query = query.Where(finalQuery, args...).
|
|
||||||
// Scopes(filt.All()...)
|
|
||||||
|
|
||||||
// found, err = find.Paginate[V](ctx, p, query)
|
|
||||||
|
|
||||||
// return found, errs.Recorded(span, err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (repo *ListRepo) ListUsers(id_lang uint, p find.Paging, filt *filters.FiltersList) (find.Found[model.UserInList], error) {
|
|
||||||
// var list []model.UserInList
|
|
||||||
// var total int64
|
|
||||||
|
|
||||||
// query := db.Get().
|
|
||||||
// Table("b2b_customers AS users").
|
|
||||||
// Select(`
|
|
||||||
// users.id AS id,
|
|
||||||
// users.email AS email,
|
|
||||||
// users.first_name AS first_name,
|
|
||||||
// users.last_name AS last_name,
|
|
||||||
// users.role AS role
|
|
||||||
// `)
|
|
||||||
|
|
||||||
// // Apply all filters
|
|
||||||
// if filt != nil {
|
|
||||||
// filt.ApplyAll(query)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // run counter first as query is without limit and offset
|
|
||||||
// err := query.Count(&total).Error
|
|
||||||
// if err != nil {
|
|
||||||
// return find.Found[model.UserInList]{}, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = query.
|
|
||||||
// Order("users.id DESC").
|
|
||||||
// Limit(p.Limit()).
|
|
||||||
// Offset(p.Offset()).
|
|
||||||
// Find(&list).Error
|
|
||||||
// if err != nil {
|
|
||||||
// return find.Found[model.UserInList]{}, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return find.Found[model.UserInList]{
|
|
||||||
// Items: list,
|
|
||||||
// Count: uint(total),
|
|
||||||
// }, nil
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package localeSelectorRepo
|
|||||||
import (
|
import (
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/db"
|
"git.ma-al.com/goc_daniel/b2b/app/db"
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UILocaleSelectorRepo interface {
|
type UILocaleSelectorRepo interface {
|
||||||
@@ -25,7 +26,9 @@ func (r *LocaleSelectorRepo) GetLanguages() ([]model.Language, error) {
|
|||||||
func (r *LocaleSelectorRepo) GetCountriesAndCurrencies() ([]model.Country, error) {
|
func (r *LocaleSelectorRepo) GetCountriesAndCurrencies() ([]model.Country, error) {
|
||||||
var countries []model.Country
|
var countries []model.Country
|
||||||
err := db.Get().
|
err := db.Get().
|
||||||
Preload("PSCurrency").
|
Select("*").
|
||||||
|
Preload("Currency").
|
||||||
|
Joins("LEFT JOIN " + dbmodel.TableNamePsCountryLang + " AS cl ON cl." + dbmodel.PsCountryLangCols.IDCountry.Col() + " = b2b_countries.ps_id_country AND cl." + dbmodel.PsCountryLangCols.IDLang.Col() + " = 2").
|
||||||
Find(&countries).Error
|
Find(&countries).Error
|
||||||
return countries, err
|
return countries, err
|
||||||
}
|
}
|
||||||
|
|||||||
110
app/repos/ordersRepo/ordersRepo.go
Normal file
110
app/repos/ordersRepo/ordersRepo.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package ordersRepo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/db"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UIOrdersRepo interface {
|
||||||
|
UserHasOrder(user_id uint, order_id uint) (bool, error)
|
||||||
|
Find(user_id uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error)
|
||||||
|
PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string) error
|
||||||
|
ChangeOrderAddress(order_id uint, country_id uint, address_info string) error
|
||||||
|
ChangeOrderStatus(order_id uint, status string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrdersRepo struct{}
|
||||||
|
|
||||||
|
func New() UIOrdersRepo {
|
||||||
|
return &OrdersRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *OrdersRepo) UserHasOrder(user_id uint, order_id uint) (bool, error) {
|
||||||
|
var amt uint
|
||||||
|
|
||||||
|
err := db.DB.
|
||||||
|
Table("b2b_customer_orders").
|
||||||
|
Select("COUNT(*) AS amt").
|
||||||
|
Where("user_id = ? AND order_id = ?", user_id, order_id).
|
||||||
|
Scan(&amt).
|
||||||
|
Error
|
||||||
|
|
||||||
|
return amt >= 1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *OrdersRepo) Find(user_id uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error) {
|
||||||
|
var list []model.CustomerOrder
|
||||||
|
var total int64
|
||||||
|
|
||||||
|
query := db.Get().
|
||||||
|
Model(&model.CustomerOrder{}).
|
||||||
|
Preload("Products").
|
||||||
|
Order("b2b_customer_orders.order_id DESC")
|
||||||
|
|
||||||
|
// Apply all filters
|
||||||
|
if filt != nil {
|
||||||
|
filt.ApplyAll(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run counter first as query is without limit and offset
|
||||||
|
err := query.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return &find.Found[model.CustomerOrder]{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = query.
|
||||||
|
Limit(p.Limit()).
|
||||||
|
Offset(p.Offset()).
|
||||||
|
Find(&list).Error
|
||||||
|
if err != nil {
|
||||||
|
return &find.Found[model.CustomerOrder]{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &find.Found[model.CustomerOrder]{
|
||||||
|
Items: list,
|
||||||
|
Count: uint(total),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *OrdersRepo) PlaceNewOrder(cart *model.CustomerCart, name string, country_id uint, address_info string) error {
|
||||||
|
order := model.CustomerOrder{
|
||||||
|
UserID: cart.UserID,
|
||||||
|
Name: name,
|
||||||
|
CountryID: country_id,
|
||||||
|
AddressString: address_info,
|
||||||
|
Status: constdata.NEW_ORDER_STATUS,
|
||||||
|
Products: make([]model.OrderProduct, 0, len(cart.Products)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, product := range cart.Products {
|
||||||
|
order.Products = append(order.Products, model.OrderProduct{
|
||||||
|
ProductID: product.ProductID,
|
||||||
|
ProductAttributeID: product.ProductAttributeID,
|
||||||
|
Amount: product.Amount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.DB.Create(&order).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *OrdersRepo) ChangeOrderAddress(order_id uint, country_id uint, address_info string) error {
|
||||||
|
return db.DB.
|
||||||
|
Table("b2b_customer_orders").
|
||||||
|
Where("order_id = ?", order_id).
|
||||||
|
Updates(map[string]interface{}{
|
||||||
|
"country_id": country_id,
|
||||||
|
"address_string": address_info,
|
||||||
|
}).
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *OrdersRepo) ChangeOrderStatus(order_id uint, status string) error {
|
||||||
|
return db.DB.
|
||||||
|
Table("b2b_customer_orders").
|
||||||
|
Where("order_id = ?", order_id).
|
||||||
|
Update("status", status).
|
||||||
|
Error
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ type UIProductsRepo interface {
|
|||||||
// GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error)
|
// GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error)
|
||||||
Find(id_lang uint, userID uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.ProductInList], error)
|
Find(id_lang uint, userID uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.ProductInList], error)
|
||||||
GetProductVariants(langID uint, productID uint, shopID uint, customerID uint, countryID uint, quantity uint) ([]view.ProductAttribute, error)
|
GetProductVariants(langID uint, productID uint, shopID uint, customerID uint, countryID uint, quantity uint) ([]view.ProductAttribute, error)
|
||||||
GetBase(p_id_product, p_id_shop, p_id_lang uint) (view.Product, error)
|
GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error)
|
||||||
GetPrice(p_id_product uint, productAttributeID *uint, p_id_shop uint, p_id_customer uint, p_id_country uint, p_quantity uint) (view.Price, error)
|
GetPrice(p_id_product uint, productAttributeID *uint, p_id_shop uint, p_id_customer uint, p_id_country uint, p_quantity uint) (view.Price, error)
|
||||||
GetVariants(p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity uint) ([]view.ProductAttribute, error)
|
GetVariants(p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity uint) ([]view.ProductAttribute, error)
|
||||||
AddToFavorites(userID uint, productID uint) error
|
AddToFavorites(userID uint, productID uint) error
|
||||||
@@ -33,11 +33,11 @@ func New() UIProductsRepo {
|
|||||||
return &ProductsRepo{}
|
return &ProductsRepo{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang uint) (view.Product, error) {
|
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error) {
|
||||||
var result view.Product
|
var result view.Product
|
||||||
|
|
||||||
err := db.DB.Raw(`CALL get_product_base(?,?,?)`,
|
err := db.DB.Raw(`CALL get_product_base(?,?,?,?)`,
|
||||||
p_id_product, p_id_shop, p_id_lang).
|
p_id_product, p_id_shop, p_id_lang, p_id_customer).
|
||||||
Scan(&result).Error
|
Scan(&result).Error
|
||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UIRoutesRepo interface {
|
type UIRoutesRepo interface {
|
||||||
GetRoutes(langId uint) ([]model.Route, error)
|
GetRoutes(langId uint, roleId uint) ([]model.Route, error)
|
||||||
GetTopMenu(id uint, roleId uint) ([]model.B2BTopMenu, error)
|
GetTopMenu(id uint, roleId uint) ([]model.B2BTopMenu, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,13 +17,18 @@ func New() UIRoutesRepo {
|
|||||||
return &RoutesRepo{}
|
return &RoutesRepo{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RoutesRepo) GetRoutes(langId uint) ([]model.Route, error) {
|
func (p *RoutesRepo) GetRoutes(langId uint, roleId uint) ([]model.Route, error) {
|
||||||
routes := []model.Route{}
|
routes := []model.Route{}
|
||||||
err := db.DB.Find(&routes, model.Route{Active: nullable.GetNil(true)}).Error
|
|
||||||
if err != nil {
|
err := db.
|
||||||
return nil, err
|
Get().
|
||||||
}
|
Model(model.Route{}).
|
||||||
return routes, nil
|
Joins("JOIN b2b_route_roles rr ON rr.route_id = b2b_routes.id").
|
||||||
|
Where(model.Route{Active: nullable.GetNil(true)}).
|
||||||
|
Where("rr.role_id = ?", roleId).
|
||||||
|
Find(&routes).Error
|
||||||
|
|
||||||
|
return routes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RoutesRepo) GetTopMenu(langId uint, roleId uint) ([]model.B2BTopMenu, error) {
|
func (p *RoutesRepo) GetTopMenu(langId uint, roleId uint) ([]model.B2BTopMenu, error) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func New() *AddressesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AddressesService) GetTemplate(country_id uint) (model.AddressField, error) {
|
func (s *AddressesService) GetTemplate(country_id uint) (model.AddressUnparsed, error) {
|
||||||
switch country_id {
|
switch country_id {
|
||||||
|
|
||||||
case 1: // Poland
|
case 1: // Poland
|
||||||
@@ -49,7 +49,7 @@ func (s *AddressesService) AddNewAddress(user_id uint, address_info string, coun
|
|||||||
return responseErrors.ErrMaxAmtOfAddressesReached
|
return responseErrors.ErrMaxAmtOfAddressesReached
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.validateAddressJson(address_info, country_id)
|
_, err = s.ValidateAddressJson(address_info, country_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func (s *AddressesService) ModifyAddress(user_id uint, address_id uint, address_
|
|||||||
return responseErrors.ErrUserHasNoSuchAddress
|
return responseErrors.ErrUserHasNoSuchAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.validateAddressJson(address_info, country_id)
|
_, err = s.ValidateAddressJson(address_info, country_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -74,30 +74,23 @@ func (s *AddressesService) ModifyAddress(user_id uint, address_id uint, address_
|
|||||||
return s.repo.UpdateAddress(user_id, address_id, address_info, country_id)
|
return s.repo.UpdateAddress(user_id, address_id, address_info, country_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AddressesService) RetrieveAddressesInfo(user_id uint) (*[]model.AddressUnparsed, error) {
|
func (s *AddressesService) RetrieveAddresses(user_id uint) (*[]model.Address, error) {
|
||||||
parsed_addresses, err := s.repo.RetrieveAddresses(user_id)
|
addresses, err := s.repo.RetrieveAddresses(user_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var unparsed_addresses []model.AddressUnparsed
|
for i := 0; i < len(*addresses); i++ {
|
||||||
|
address_unparsed, err := s.ValidateAddressJson((*addresses)[i].AddressString, (*addresses)[i].CountryID)
|
||||||
for i := 0; i < len(*parsed_addresses); i++ {
|
|
||||||
var next_address model.AddressUnparsed
|
|
||||||
next_address.ID = (*parsed_addresses)[i].ID
|
|
||||||
next_address.CustomerID = (*parsed_addresses)[i].CustomerID
|
|
||||||
next_address.CountryID = (*parsed_addresses)[i].CountryID
|
|
||||||
|
|
||||||
next_address.AddressInfo, err = s.validateAddressJson((*parsed_addresses)[i].AddressInfo, next_address.CountryID)
|
|
||||||
// log such errors
|
// log such errors
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("err: %v\n", err)
|
fmt.Printf("err: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
unparsed_addresses = append(unparsed_addresses, next_address)
|
(*addresses)[i].AddressUnparsed = &address_unparsed
|
||||||
}
|
}
|
||||||
|
|
||||||
return &unparsed_addresses, nil
|
return addresses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AddressesService) DeleteAddress(user_id uint, address_id uint) error {
|
func (s *AddressesService) DeleteAddress(user_id uint, address_id uint) error {
|
||||||
@@ -112,7 +105,7 @@ func (s *AddressesService) DeleteAddress(user_id uint, address_id uint) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validateAddressJson makes sure that the info string represents a valid json of address in given country
|
// validateAddressJson makes sure that the info string represents a valid json of address in given country
|
||||||
func (s *AddressesService) validateAddressJson(info string, country_id uint) (model.AddressField, error) {
|
func (s *AddressesService) ValidateAddressJson(info string, country_id uint) (model.AddressUnparsed, error) {
|
||||||
dec := json.NewDecoder(strings.NewReader(info))
|
dec := json.NewDecoder(strings.NewReader(info))
|
||||||
dec.DisallowUnknownFields()
|
dec.DisallowUnknownFields()
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,24 @@ func (s *CartsService) CreateNewCart(user_id uint) (model.CustomerCart, error) {
|
|||||||
return cart, nil
|
return cart, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CartsService) UpdateCartName(user_id uint, cart_id uint, new_name string) error {
|
func (s *CartsService) RemoveCart(user_id uint, cart_id uint) error {
|
||||||
amt, err := s.repo.UserHasCart(user_id, cart_id)
|
exists, err := s.repo.UserHasCart(user_id, cart_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if amt != 1 {
|
if !exists {
|
||||||
|
return responseErrors.ErrUserHasNoSuchCart
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.repo.RemoveCart(user_id, cart_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *CartsService) UpdateCartName(user_id uint, cart_id uint, new_name string) error {
|
||||||
|
exists, err := s.repo.UserHasCart(user_id, cart_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
return responseErrors.ErrUserHasNoSuchCart
|
return responseErrors.ErrUserHasNoSuchCart
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,11 +63,11 @@ func (s *CartsService) RetrieveCartsInfo(user_id uint) ([]model.CustomerCart, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *CartsService) RetrieveCart(user_id uint, cart_id uint) (*model.CustomerCart, error) {
|
func (s *CartsService) RetrieveCart(user_id uint, cart_id uint) (*model.CustomerCart, error) {
|
||||||
amt, err := s.repo.UserHasCart(user_id, cart_id)
|
exists, err := s.repo.UserHasCart(user_id, cart_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if amt != 1 {
|
if !exists {
|
||||||
return nil, responseErrors.ErrUserHasNoSuchCart
|
return nil, responseErrors.ErrUserHasNoSuchCart
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,19 +75,19 @@ func (s *CartsService) RetrieveCart(user_id uint, cart_id uint) (*model.Customer
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *CartsService) AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error {
|
func (s *CartsService) AddProduct(user_id uint, cart_id uint, product_id uint, product_attribute_id *uint, amount uint) error {
|
||||||
amt, err := s.repo.UserHasCart(user_id, cart_id)
|
exists, err := s.repo.UserHasCart(user_id, cart_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if amt != 1 {
|
if !exists {
|
||||||
return responseErrors.ErrUserHasNoSuchCart
|
return responseErrors.ErrUserHasNoSuchCart
|
||||||
}
|
}
|
||||||
|
|
||||||
amt, err = s.repo.CheckProductExists(product_id, product_attribute_id)
|
exists, err = s.repo.CheckProductExists(product_id, product_attribute_id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if amt != 1 {
|
if !exists {
|
||||||
return responseErrors.ErrProductOrItsVariationDoesNotExist
|
return responseErrors.ErrProductOrItsVariationDoesNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,18 @@ func (s *EmailService) SendNewUserAdminNotification(userEmail, userName, baseURL
|
|||||||
return s.SendEmail(s.config.AdminEmail, subject, body)
|
return s.SendEmail(s.config.AdminEmail, subject, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendNewOrderPlacedNotification sends an email to admin when new order is placed
|
||||||
|
func (s *EmailService) SendNewOrderPlacedNotification(userID uint) error {
|
||||||
|
if s.config.AdminEmail == "" {
|
||||||
|
return nil // No admin email configured
|
||||||
|
}
|
||||||
|
|
||||||
|
subject := "New Order Created"
|
||||||
|
body := s.newOrderPlacedTemplate(userID)
|
||||||
|
|
||||||
|
return s.SendEmail(s.config.AdminEmail, subject, body)
|
||||||
|
}
|
||||||
|
|
||||||
// verificationEmailTemplate returns the HTML template for email verification
|
// verificationEmailTemplate returns the HTML template for email verification
|
||||||
func (s *EmailService) verificationEmailTemplate(name, verificationURL string, langID uint) string {
|
func (s *EmailService) verificationEmailTemplate(name, verificationURL string, langID uint) string {
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
@@ -137,3 +149,10 @@ func (s *EmailService) newUserAdminNotificationTemplate(userEmail, userName, bas
|
|||||||
emails.EmailAdminNotificationWrapper(view.EmailLayout[view.EmailAdminNotificationData]{LangID: constdata.ADMIN_NOTIFICATION_LANGUAGE, Data: view.EmailAdminNotificationData{UserEmail: userEmail, UserName: userName, BaseURL: baseURL}}).Render(context.Background(), &buf)
|
emails.EmailAdminNotificationWrapper(view.EmailLayout[view.EmailAdminNotificationData]{LangID: constdata.ADMIN_NOTIFICATION_LANGUAGE, Data: view.EmailAdminNotificationData{UserEmail: userEmail, UserName: userName, BaseURL: baseURL}}).Render(context.Background(), &buf)
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newUserAdminNotificationTemplate returns the HTML template for admin notification
|
||||||
|
func (s *EmailService) newOrderPlacedTemplate(userID uint) string {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
emails.EmailNewOrderPlacedWrapper(view.EmailLayout[view.EmailNewOrderPlacedData]{LangID: constdata.ADMIN_NOTIFICATION_LANGUAGE, Data: view.EmailNewOrderPlacedData{UserID: userID}}).Render(context.Background(), &buf)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ func (s *MenuService) createTree(index int, all_categories *([]model.ScannedCate
|
|||||||
return node, true
|
return node, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MenuService) GetRoutes(id_lang uint) ([]model.Route, error) {
|
func (s *MenuService) GetRoutes(id_lang, roleId uint) ([]model.Route, error) {
|
||||||
return s.routesRepo.GetRoutes(id_lang)
|
return s.routesRepo.GetRoutes(id_lang, roleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MenuService) scannedToNormalCategory(scanned model.ScannedCategory) model.Category {
|
func (s *MenuService) scannedToNormalCategory(scanned model.ScannedCategory) model.Category {
|
||||||
|
|||||||
145
app/service/orderService/orderService.go
Normal file
145
app/service/orderService/orderService.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package orderService
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/delivery/middleware/perms"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/repos/cartsRepo"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/repos/ordersRepo"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/service/addressesService"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/service/emailService"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/filters"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/query/find"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderService struct {
|
||||||
|
ordersRepo ordersRepo.UIOrdersRepo
|
||||||
|
cartsRepo cartsRepo.UICartsRepo
|
||||||
|
addressesService *addressesService.AddressesService
|
||||||
|
emailService *emailService.EmailService
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *OrderService {
|
||||||
|
return &OrderService{
|
||||||
|
ordersRepo: ordersRepo.New(),
|
||||||
|
cartsRepo: cartsRepo.New(),
|
||||||
|
addressesService: addressesService.New(),
|
||||||
|
emailService: emailService.NewEmailService(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) Find(user *model.Customer, p find.Paging, filt *filters.FiltersList) (*find.Found[model.CustomerOrder], error) {
|
||||||
|
if !user.HasPermission(perms.OrdersViewAll) {
|
||||||
|
// append filter to view only this user's orders
|
||||||
|
idStr := strconv.FormatUint(uint64(user.ID), 10)
|
||||||
|
filt.Append(filters.Where("b2b_customer_orders.user_id = " + idStr))
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := s.ordersRepo.Find(user.ID, p, filt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(list.Items); i++ {
|
||||||
|
address_unparsed, err := s.addressesService.ValidateAddressJson(list.Items[i].AddressString, list.Items[i].CountryID)
|
||||||
|
// log such errors
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("err: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Items[i].AddressUnparsed = &address_unparsed
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) PlaceNewOrder(user_id uint, cart_id uint, name string, country_id uint, address_info string) error {
|
||||||
|
_, err := s.addressesService.ValidateAddressJson(address_info, country_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, err := s.cartsRepo.UserHasCart(user_id, cart_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return responseErrors.ErrUserHasNoSuchCart
|
||||||
|
}
|
||||||
|
|
||||||
|
cart, err := s.cartsRepo.RetrieveCart(user_id, cart_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(cart.Products) == 0 {
|
||||||
|
return responseErrors.ErrEmptyCart
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "" && cart.Name != nil {
|
||||||
|
name = *cart.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// all checks passed
|
||||||
|
err = s.ordersRepo.PlaceNewOrder(cart, name, country_id, address_info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// from this point onward we do not cancel this order.
|
||||||
|
|
||||||
|
// if no error is returned, remove the cart. This should be smooth
|
||||||
|
err = s.cartsRepo.RemoveCart(user_id, cart_id)
|
||||||
|
if err != nil {
|
||||||
|
// Log error but don't fail placing order
|
||||||
|
_ = err
|
||||||
|
}
|
||||||
|
|
||||||
|
// send email to admin
|
||||||
|
go func(user_id uint) {
|
||||||
|
err := s.emailService.SendNewOrderPlacedNotification(user_id)
|
||||||
|
if err != nil {
|
||||||
|
// Log error but don't fail placing order
|
||||||
|
_ = err
|
||||||
|
}
|
||||||
|
}(user_id)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OrderService) ChangeOrderAddress(user *model.Customer, order_id uint, country_id uint, address_info string) error {
|
||||||
|
_, err := s.addressesService.ValidateAddressJson(address_info, country_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.HasPermission(perms.OrdersModifyAll) {
|
||||||
|
exists, err := s.ordersRepo.UserHasOrder(user.ID, order_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return responseErrors.ErrUserHasNoSuchOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.ordersRepo.ChangeOrderAddress(order_id, country_id, address_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is obiously just an initial version of this function
|
||||||
|
func (s *OrderService) ChangeOrderStatus(user *model.Customer, order_id uint, status string) error {
|
||||||
|
if !user.HasPermission(perms.OrdersModifyAll) {
|
||||||
|
exists, err := s.ordersRepo.UserHasOrder(user.ID, order_id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return responseErrors.ErrUserHasNoSuchOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.ordersRepo.ChangeOrderStatus(order_id, status)
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ func (s *ProductService) Get(
|
|||||||
p_id_product, p_id_lang, p_id_customer, b2b_id_country, p_quantity uint,
|
p_id_product, p_id_lang, p_id_customer, b2b_id_country, p_quantity uint,
|
||||||
) (*json.RawMessage, error) {
|
) (*json.RawMessage, error) {
|
||||||
|
|
||||||
product, err := s.productsRepo.GetBase(p_id_product, constdata.SHOP_ID, p_id_lang)
|
product, err := s.productsRepo.GetBase(p_id_product, constdata.SHOP_ID, p_id_lang, p_id_customer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
26
app/templ/emails/emailNewOrderPlacedNotification.templ
Normal file
26
app/templ/emails/emailNewOrderPlacedNotification.templ
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package emails
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/templ/layout"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/view"
|
||||||
|
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
|
||||||
|
)
|
||||||
|
|
||||||
|
templ EmailNewOrderPlacedWrapper(data view.EmailLayout[view.EmailNewOrderPlacedData]) {
|
||||||
|
@layout.Base( i18n.T___(data.LangID, "email.email_new_order_placed_notification_title")) {
|
||||||
|
<div class="container">
|
||||||
|
<div class="email-wrapper">
|
||||||
|
<div class="email-header">
|
||||||
|
<h1>New Order Placed</h1>
|
||||||
|
</div>
|
||||||
|
<div class="email-body">
|
||||||
|
<p>Hello Administrator,</p>
|
||||||
|
<p>User with id { data.Data.UserID } has placed a new order. </p>
|
||||||
|
</div>
|
||||||
|
<div class="email-footer">
|
||||||
|
<p>© 2024 Gitea Manager. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,9 @@ const MAX_AMOUNT_OF_ADDRESSES_PER_USER = 10
|
|||||||
|
|
||||||
const USER_LOCALE = "user"
|
const USER_LOCALE = "user"
|
||||||
|
|
||||||
|
// ORDERS
|
||||||
|
const NEW_ORDER_STATUS = "PENDING"
|
||||||
|
|
||||||
// WEBDAV
|
// WEBDAV
|
||||||
const NBYTES_IN_WEBDAV_TOKEN = 32
|
const NBYTES_IN_WEBDAV_TOKEN = 32
|
||||||
const WEBDAV_HREF_ROOT = "http://localhost:3000/api/v1/webdav/storage"
|
const WEBDAV_HREF_ROOT = "http://localhost:3000/api/v1/webdav/storage"
|
||||||
@@ -29,3 +32,5 @@ const WEBDAV_TRIMMED_ROOT = "localhost:3000/api/v1/webdav/storage"
|
|||||||
const NON_ALNUM_REGEX = `[^a-z0-9]+`
|
const NON_ALNUM_REGEX = `[^a-z0-9]+`
|
||||||
const MULTI_DASH_REGEX = `-+`
|
const MULTI_DASH_REGEX = `-+`
|
||||||
const SLUG_REGEX = `^[a-z0-9]+(?:-[a-z0-9]+)*$`
|
const SLUG_REGEX = `^[a-z0-9]+(?:-[a-z0-9]+)*$`
|
||||||
|
|
||||||
|
const UNLOGGED_USER_ROLE_ID = 4
|
||||||
|
|||||||
@@ -66,11 +66,16 @@ var (
|
|||||||
ErrUserHasNoSuchCart = errors.New("user does not have cart with given id")
|
ErrUserHasNoSuchCart = errors.New("user does not have cart with given id")
|
||||||
ErrProductOrItsVariationDoesNotExist = errors.New("product or its variation with given ids does not exist")
|
ErrProductOrItsVariationDoesNotExist = errors.New("product or its variation with given ids does not exist")
|
||||||
|
|
||||||
|
// Typed errors for orders handler
|
||||||
|
ErrEmptyCart = errors.New("the cart is empty")
|
||||||
|
ErrUserHasNoSuchOrder = errors.New("user does not have order with given id")
|
||||||
|
|
||||||
// Typed errors for price reduction handler
|
// Typed errors for price reduction handler
|
||||||
ErrInvalidReductionType = errors.New("invalid reduction type: must be 'amount' or 'percentage'")
|
ErrInvalidReductionType = errors.New("invalid reduction type: must be 'amount' or 'percentage'")
|
||||||
ErrPercentageRequired = errors.New("percentage_reduction required when reduction_type is percentage")
|
ErrPercentageRequired = errors.New("percentage_reduction required when reduction_type is percentage")
|
||||||
ErrPriceRequired = errors.New("price required when reduction_type is amount")
|
ErrPriceRequired = errors.New("price required when reduction_type is amount")
|
||||||
ErrSpecificPriceNotFound = errors.New("price reduction not found")
|
ErrSpecificPriceNotFound = errors.New("price reduction not found")
|
||||||
|
|
||||||
// Typed errors for storage
|
// Typed errors for storage
|
||||||
ErrAccessDenied = errors.New("access denied!")
|
ErrAccessDenied = errors.New("access denied!")
|
||||||
ErrFolderDoesNotExist = errors.New("folder does not exist")
|
ErrFolderDoesNotExist = errors.New("folder does not exist")
|
||||||
@@ -201,6 +206,11 @@ func GetErrorCode(c fiber.Ctx, err error) string {
|
|||||||
case errors.Is(err, ErrProductOrItsVariationDoesNotExist):
|
case errors.Is(err, ErrProductOrItsVariationDoesNotExist):
|
||||||
return i18n.T_(c, "error.err_product_or_its_variation_does_not_exist")
|
return i18n.T_(c, "error.err_product_or_its_variation_does_not_exist")
|
||||||
|
|
||||||
|
case errors.Is(err, ErrEmptyCart):
|
||||||
|
return i18n.T_(c, "error.err_cart_is_empty")
|
||||||
|
case errors.Is(err, ErrUserHasNoSuchOrder):
|
||||||
|
return i18n.T_(c, "error.err_user_has_no_such_order")
|
||||||
|
|
||||||
case errors.Is(err, ErrAccessDenied):
|
case errors.Is(err, ErrAccessDenied):
|
||||||
return i18n.T_(c, "error.err_access_denied")
|
return i18n.T_(c, "error.err_access_denied")
|
||||||
case errors.Is(err, ErrFolderDoesNotExist):
|
case errors.Is(err, ErrFolderDoesNotExist):
|
||||||
@@ -282,6 +292,8 @@ func GetErrorStatus(err error) int {
|
|||||||
errors.Is(err, ErrMaxAmtOfCartsReached),
|
errors.Is(err, ErrMaxAmtOfCartsReached),
|
||||||
errors.Is(err, ErrUserHasNoSuchCart),
|
errors.Is(err, ErrUserHasNoSuchCart),
|
||||||
errors.Is(err, ErrProductOrItsVariationDoesNotExist),
|
errors.Is(err, ErrProductOrItsVariationDoesNotExist),
|
||||||
|
errors.Is(err, ErrEmptyCart),
|
||||||
|
errors.Is(err, ErrUserHasNoSuchOrder),
|
||||||
errors.Is(err, ErrInvalidReductionType),
|
errors.Is(err, ErrInvalidReductionType),
|
||||||
errors.Is(err, ErrPercentageRequired),
|
errors.Is(err, ErrPercentageRequired),
|
||||||
errors.Is(err, ErrPriceRequired),
|
errors.Is(err, ErrPriceRequired),
|
||||||
|
|||||||
@@ -18,3 +18,7 @@ type EmailAdminNotificationData struct {
|
|||||||
type EmailPasswordResetData struct {
|
type EmailPasswordResetData struct {
|
||||||
ResetURL string
|
ResetURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EmailNewOrderPlacedData struct {
|
||||||
|
UserID uint
|
||||||
|
}
|
||||||
|
|||||||
15
bruno/api_v1/routes/Routes.yml
Normal file
15
bruno/api_v1/routes/Routes.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
info:
|
||||||
|
name: Routes
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: ""
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
7
bruno/api_v1/routes/folder.yml
Normal file
7
bruno/api_v1/routes/folder.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
info:
|
||||||
|
name: routes
|
||||||
|
type: folder
|
||||||
|
seq: 10
|
||||||
|
|
||||||
|
request:
|
||||||
|
auth: inherit
|
||||||
@@ -5,10 +5,10 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: http://localhost:3000/api/v1/restricted/carts/retrieve-cart?cart_id=3
|
url: http://localhost:3000/api/v1/restricted/carts/retrieve-cart?cart_id=1
|
||||||
params:
|
params:
|
||||||
- name: cart_id
|
- name: cart_id
|
||||||
value: "3"
|
value: "1"
|
||||||
type: query
|
type: query
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
|
|||||||
33
bruno/b2b_daniel/orders/change-order-address.yml
Normal file
33
bruno/b2b_daniel/orders/change-order-address.yml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
info:
|
||||||
|
name: change-order-address
|
||||||
|
type: http
|
||||||
|
seq: 3
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/orders/change-order-address?order_id=1&country_id=1
|
||||||
|
params:
|
||||||
|
- name: order_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: country_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: |-
|
||||||
|
{
|
||||||
|
"postal_code": "31-154",
|
||||||
|
"city": "Kraków",
|
||||||
|
"voivodeship": "śląskie",
|
||||||
|
"street": "Długa",
|
||||||
|
"building_no": "5",
|
||||||
|
"recipient": "Adam Adamowicz"
|
||||||
|
}
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
22
bruno/b2b_daniel/orders/change-order-status.yml
Normal file
22
bruno/b2b_daniel/orders/change-order-status.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
info:
|
||||||
|
name: change-order-status
|
||||||
|
type: http
|
||||||
|
seq: 4
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/orders/change-order-status?order_id=1&status=PAID
|
||||||
|
params:
|
||||||
|
- name: order_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: status
|
||||||
|
value: PAID
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
7
bruno/b2b_daniel/orders/folder.yml
Normal file
7
bruno/b2b_daniel/orders/folder.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
info:
|
||||||
|
name: orders
|
||||||
|
type: folder
|
||||||
|
seq: 11
|
||||||
|
|
||||||
|
request:
|
||||||
|
auth: inherit
|
||||||
31
bruno/b2b_daniel/orders/list.yml
Normal file
31
bruno/b2b_daniel/orders/list.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
info:
|
||||||
|
name: list
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/orders/list?p=1&elems=30&sort=product_id,asc&user_id=2&name=~sdj
|
||||||
|
params:
|
||||||
|
- name: p
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: elems
|
||||||
|
value: "30"
|
||||||
|
type: query
|
||||||
|
- name: sort
|
||||||
|
value: product_id,asc
|
||||||
|
type: query
|
||||||
|
- name: user_id
|
||||||
|
value: "2"
|
||||||
|
type: query
|
||||||
|
- name: name
|
||||||
|
value: ~sdj
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
37
bruno/b2b_daniel/orders/place-new-order.yml
Normal file
37
bruno/b2b_daniel/orders/place-new-order.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
info:
|
||||||
|
name: place-new-order
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: POST
|
||||||
|
url: http://localhost:3000/api/v1/restricted/orders/place-new-order?cart_id=1&name=sdjalksd&country_id=1
|
||||||
|
params:
|
||||||
|
- name: cart_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
- name: name
|
||||||
|
value: sdjalksd
|
||||||
|
type: query
|
||||||
|
- name: country_id
|
||||||
|
value: "1"
|
||||||
|
type: query
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: |-
|
||||||
|
{
|
||||||
|
"postal_code": "31-154",
|
||||||
|
"city": "Kraków",
|
||||||
|
"voivodeship": "małopolskie",
|
||||||
|
"street": "Długa",
|
||||||
|
"building_no": "5",
|
||||||
|
"apartment_no": "7",
|
||||||
|
"recipient": "Jan Kowalski"
|
||||||
|
}
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -43,7 +43,6 @@ INSERT IGNORE INTO `b2b_top_menu` (`menu_id`, `label`, `parent_id`, `params`, `a
|
|||||||
(9, JSON_COMPACT('{"name":"carts","trans":{"pl":{"label":"Koszyki"},"en":{"label":"Carts"},"de":{"label":"Warenkörbe"}}}'),3,JSON_COMPACT('{"route": {"name": "home", "params":{"locale": ""}}}'),1,1);
|
(9, JSON_COMPACT('{"name":"carts","trans":{"pl":{"label":"Koszyki"},"en":{"label":"Carts"},"de":{"label":"Warenkörbe"}}}'),3,JSON_COMPACT('{"route": {"name": "home", "params":{"locale": ""}}}'),1,1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
|
|
||||||
DROP TABLE IF EXISTS b2b_routes;
|
DROP TABLE IF EXISTS b2b_routes;
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ FOREIGN KEY (role_id) REFERENCES b2b_roles(id);
|
|||||||
|
|
||||||
-- customer_carts
|
-- customer_carts
|
||||||
CREATE TABLE IF NOT EXISTS b2b_customer_carts (
|
CREATE TABLE IF NOT EXISTS b2b_customer_carts (
|
||||||
cart_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
cart_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
user_id BIGINT UNSIGNED NOT NULL,
|
user_id BIGINT UNSIGNED NOT NULL,
|
||||||
name VARCHAR(255) NULL,
|
name VARCHAR(255) NULL,
|
||||||
CONSTRAINT fk_customer_carts_customers FOREIGN KEY (user_id) REFERENCES b2b_customers(id) ON DELETE CASCADE ON UPDATE CASCADE
|
CONSTRAINT fk_customer_carts_customers FOREIGN KEY (user_id) REFERENCES b2b_customers(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
@@ -140,8 +140,8 @@ CREATE INDEX IF NOT EXISTS idx_customer_carts_user_id ON b2b_customer_carts (use
|
|||||||
|
|
||||||
-- carts_products
|
-- carts_products
|
||||||
CREATE TABLE IF NOT EXISTS b2b_carts_products (
|
CREATE TABLE IF NOT EXISTS b2b_carts_products (
|
||||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
cart_id INT UNSIGNED NOT NULL,
|
cart_id BIGINT UNSIGNED NOT NULL,
|
||||||
product_id INT UNSIGNED NOT NULL,
|
product_id INT UNSIGNED NOT NULL,
|
||||||
product_attribute_id INT NULL,
|
product_attribute_id INT NULL,
|
||||||
amount INT UNSIGNED NOT NULL,
|
amount INT UNSIGNED NOT NULL,
|
||||||
@@ -224,7 +224,7 @@ ON `b2b_countries` (
|
|||||||
CREATE TABLE IF NOT EXISTS b2b_addresses (
|
CREATE TABLE IF NOT EXISTS b2b_addresses (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
|
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
|
||||||
b2b_customer_id BIGINT UNSIGNED NOT NULL,
|
b2b_customer_id BIGINT UNSIGNED NOT NULL,
|
||||||
address_info TEXT NOT NULL,
|
address_string TEXT NOT NULL,
|
||||||
b2b_country_id BIGINT UNSIGNED NOT NULL,
|
b2b_country_id BIGINT UNSIGNED NOT NULL,
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
CONSTRAINT fk_b2b_addresses_b2b_customers FOREIGN KEY (b2b_customer_id) REFERENCES b2b_customers (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
CONSTRAINT fk_b2b_addresses_b2b_customers FOREIGN KEY (b2b_customer_id) REFERENCES b2b_customers (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
@@ -232,6 +232,34 @@ CREATE TABLE IF NOT EXISTS b2b_addresses (
|
|||||||
) ENGINE = InnoDB;
|
) ENGINE = InnoDB;
|
||||||
|
|
||||||
|
|
||||||
|
-- customer_orders
|
||||||
|
CREATE TABLE IF NOT EXISTS b2b_customer_orders (
|
||||||
|
order_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
user_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
country_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
address_string TEXT NOT NULL,
|
||||||
|
status VARCHAR(50) NOT NULL,
|
||||||
|
CONSTRAINT fk_customer_orders_customers FOREIGN KEY (user_id) REFERENCES b2b_customers(id) ON DELETE NO ACTION ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT fk_customer_orders_countries FOREIGN KEY (country_id) REFERENCES b2b_countries(id) ON DELETE NO ACTION ON UPDATE CASCADE
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
|
||||||
|
CREATE INDEX idx_customer_orders_user_id ON b2b_customer_orders (user_id);
|
||||||
|
CREATE INDEX idx_customer_orders_country_id ON b2b_customer_orders (country_id);
|
||||||
|
|
||||||
|
|
||||||
|
-- orders_products
|
||||||
|
CREATE TABLE IF NOT EXISTS b2b_orders_products (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
order_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
product_id INT UNSIGNED NOT NULL,
|
||||||
|
product_attribute_id INT NULL,
|
||||||
|
amount INT UNSIGNED NOT NULL,
|
||||||
|
CONSTRAINT fk_orders_products_customer_orders FOREIGN KEY (order_id) REFERENCES b2b_customer_orders (order_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT fk_orders_products_product FOREIGN KEY (product_id) REFERENCES ps_product (id_product) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_orders_products_order_id ON b2b_orders_products (order_id);
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE b2b_specific_price (
|
CREATE TABLE b2b_specific_price (
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
@@ -310,6 +338,24 @@ ON b2b_specific_price_customer (b2b_id_customer);
|
|||||||
CREATE INDEX idx_bsp_country_rel
|
CREATE INDEX idx_bsp_country_rel
|
||||||
ON b2b_specific_price_country (b2b_id_country);
|
ON b2b_specific_price_country (b2b_id_country);
|
||||||
|
|
||||||
|
CREATE TABLE b2b_route_roles (
|
||||||
|
route_id INT NOT NULL,
|
||||||
|
role_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY (route_id, role_id),
|
||||||
|
INDEX idx_role_id (role_id),
|
||||||
|
INDEX idx_route_id (route_id),
|
||||||
|
CONSTRAINT FK_b2b_route_roles_route_id
|
||||||
|
FOREIGN KEY (route_id)
|
||||||
|
REFERENCES b2b_routes (id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT FK_b2b_route_roles_role_id
|
||||||
|
FOREIGN KEY (role_id)
|
||||||
|
REFERENCES b2b_roles (id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
DELIMITER //
|
DELIMITER //
|
||||||
|
|
||||||
CREATE FUNCTION IF NOT EXISTS slugify_eu(input TEXT)
|
CREATE FUNCTION IF NOT EXISTS slugify_eu(input TEXT)
|
||||||
@@ -410,6 +456,7 @@ DROP TABLE IF EXISTS b2b_customer_carts;
|
|||||||
DROP TABLE IF EXISTS b2b_specific_price_country;
|
DROP TABLE IF EXISTS b2b_specific_price_country;
|
||||||
DROP TABLE IF EXISTS b2b_specific_price_customer;
|
DROP TABLE IF EXISTS b2b_specific_price_customer;
|
||||||
DROP TABLE IF EXISTS b2b_specific_price_product_attribute;
|
DROP TABLE IF EXISTS b2b_specific_price_product_attribute;
|
||||||
|
DROP TABLE IF EXISTS b2b_route_roles;
|
||||||
DROP TABLE IF EXISTS b2b_specific_price_category;
|
DROP TABLE IF EXISTS b2b_specific_price_category;
|
||||||
DROP TABLE IF EXISTS b2b_specific_price_product;
|
DROP TABLE IF EXISTS b2b_specific_price_product;
|
||||||
DROP TABLE IF EXISTS b2b_specific_price;
|
DROP TABLE IF EXISTS b2b_specific_price;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ VALUES
|
|||||||
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('user','1');
|
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('user','1');
|
||||||
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('admin','2');
|
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('admin','2');
|
||||||
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('super_admin','3');
|
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('super_admin','3');
|
||||||
|
INSERT INTO `b2b_roles` (`name`, `id`) VALUES ('unlogged','4');
|
||||||
|
|
||||||
|
|
||||||
-- insert sample admin user admin@ma-al.com/Maal12345678
|
-- insert sample admin user admin@ma-al.com/Maal12345678
|
||||||
@@ -39,6 +40,9 @@ INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('6', 'webdav.create_token')
|
|||||||
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('7', 'product_translation.save');
|
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('7', 'product_translation.save');
|
||||||
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('8', 'product_translation.translate');
|
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('8', 'product_translation.translate');
|
||||||
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('9', 'search.create_index');
|
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('9', 'search.create_index');
|
||||||
|
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('10', 'orders.view_all');
|
||||||
|
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('11', 'orders.modify_all');
|
||||||
|
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('12', 'teleport');
|
||||||
|
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '1');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '1');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '2');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '2');
|
||||||
@@ -49,6 +53,9 @@ INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '6'
|
|||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '7');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '7');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '8');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '8');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '9');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '9');
|
||||||
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '10');
|
||||||
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '11');
|
||||||
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '12');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '1');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '1');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '2');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '2');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '3');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '3');
|
||||||
@@ -58,4 +65,35 @@ INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '6'
|
|||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '7');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '7');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '8');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '8');
|
||||||
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '9');
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '9');
|
||||||
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '10');
|
||||||
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '11');
|
||||||
|
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '12');
|
||||||
|
|
||||||
|
INSERT INTO `b2b_route_roles` (`route_id`, `role_id`) VALUES
|
||||||
|
(1, '1'),
|
||||||
|
(1, '2'),
|
||||||
|
(1, '3'),
|
||||||
|
(2, '1'),
|
||||||
|
(2, '2'),
|
||||||
|
(2, '3'),
|
||||||
|
(3, '1'),
|
||||||
|
(3, '2'),
|
||||||
|
(3, '3'),
|
||||||
|
(3, '4'),
|
||||||
|
(4, '1'),
|
||||||
|
(4, '2'),
|
||||||
|
(4, '3'),
|
||||||
|
(4, '4'),
|
||||||
|
(5, '1'),
|
||||||
|
(5, '2'),
|
||||||
|
(5, '3'),
|
||||||
|
(5, '4'),
|
||||||
|
(6, '1'),
|
||||||
|
(6, '2'),
|
||||||
|
(6, '3'),
|
||||||
|
(6, '4'),
|
||||||
|
(7, '1'),
|
||||||
|
(7, '2'),
|
||||||
|
(7, '3'),
|
||||||
|
(7, '4');
|
||||||
-- +goose Down
|
-- +goose Down
|
||||||
@@ -319,7 +319,8 @@ DROP PROCEDURE IF EXISTS get_product_base //
|
|||||||
CREATE PROCEDURE get_product_base(
|
CREATE PROCEDURE get_product_base(
|
||||||
IN p_id_product INT,
|
IN p_id_product INT,
|
||||||
IN p_id_shop INT,
|
IN p_id_shop INT,
|
||||||
IN p_id_lang INT
|
IN p_id_lang INT,
|
||||||
|
IN p_id_customer INT
|
||||||
)
|
)
|
||||||
BEGIN
|
BEGIN
|
||||||
SELECT
|
SELECT
|
||||||
@@ -376,14 +377,12 @@ BEGIN
|
|||||||
|
|
||||||
-- Relations
|
-- Relations
|
||||||
m.name AS manufacturer,
|
m.name AS manufacturer,
|
||||||
cl.name AS category
|
cl.name AS category,
|
||||||
|
|
||||||
-- This doesn't fit to base product, I'll add proper is_favorite to product later
|
EXISTS(
|
||||||
|
SELECT 1 FROM b2b_favorites f
|
||||||
-- EXISTS(
|
WHERE f.user_id = p_id_customer AND f.product_id = p_id_product
|
||||||
-- SELECT 1 FROM b2b_favorites f
|
) AS is_favorite
|
||||||
-- WHERE f.user_id = p_id_customer AND f.product_id = p_id_product
|
|
||||||
-- ) AS is_favorite
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user