update
This commit is contained in:
parent
09c9a4d59d
commit
06d7b4764f
@ -82,5 +82,9 @@ func (c *Config) Auth() *AuthConfig {
|
||||
secret: c.Jwt.TokenWithdraw.Secret,
|
||||
expireTTL: c.Jwt.TokenWithdraw.ExpiresTTL,
|
||||
},
|
||||
jwtCustomer: JWT{
|
||||
secret: c.Jwt.TokenCustomer.Secret,
|
||||
expireTTL: c.Jwt.TokenCustomer.ExpiresTTL,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ type AuthConfig struct {
|
||||
jwtOrderExpiresTTL int
|
||||
jwtSecretResetPassword JWT
|
||||
jwtWithdraw JWT
|
||||
jwtCustomer JWT
|
||||
}
|
||||
|
||||
type JWT struct {
|
||||
@ -24,6 +25,10 @@ func (c *AuthConfig) AccessTokenOrderSecret() string {
|
||||
return c.jwtOrderSecret
|
||||
}
|
||||
|
||||
func (c *AuthConfig) AccessTokenCustomerSecret() string {
|
||||
return c.jwtCustomer.secret
|
||||
}
|
||||
|
||||
func (c *AuthConfig) AccessTokenWithdrawSecret() string {
|
||||
return c.jwtWithdraw.secret
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ type Jwt struct {
|
||||
TokenOrder Token `mapstructure:"token-order"`
|
||||
TokenResetPassword Token `mapstructure:"token-reset-password"`
|
||||
TokenWithdraw Token `mapstructure:"token-withdraw"`
|
||||
TokenCustomer Token `mapstructure:"token-customer"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
|
||||
@ -13,6 +13,9 @@ jwt:
|
||||
token-withdraw:
|
||||
expires-ttl: 2
|
||||
secret: "909Lm25V3Qd7aut8dr4QUxm5PZUrSFs"
|
||||
token-customer:
|
||||
expires-ttl: 1400
|
||||
secret: "WakLm25V3Qd7aut8dr4QUxm5PZUrWa#"
|
||||
|
||||
postgresql:
|
||||
host: 62.72.45.250
|
||||
|
||||
@ -81,6 +81,14 @@ func NewMyContext(parent context.Context, claims *entity.JWTAuthClaims) (*MyCont
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewMyContextCustomer(parent context.Context, claims *entity.JWTAuthClaimsCustomer) (*MyContextImpl, error) {
|
||||
return &MyContextImpl{
|
||||
Context: parent,
|
||||
requestedBy: claims.UserID,
|
||||
name: claims.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewContext(parent context.Context) *MyContextImpl {
|
||||
return &MyContextImpl{
|
||||
Context: parent,
|
||||
|
||||
@ -13,6 +13,13 @@ type JWTAuthClaims struct {
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
type JWTAuthClaimsCustomer struct {
|
||||
UserID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
type JWTOrderClaims struct {
|
||||
PartnerID int64 `json:"id"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
|
||||
@ -87,6 +87,7 @@ type OrderItem struct {
|
||||
UpdatedBy int64 `gorm:"type:int;column:updated_by"`
|
||||
Product *Product `gorm:"foreignKey:ItemID;references:ID"`
|
||||
ItemName string `gorm:"type:varchar;column:item_name"`
|
||||
Description string `gorm:"type:varchar;column:description"`
|
||||
}
|
||||
|
||||
func (OrderItem) TableName() string {
|
||||
@ -112,6 +113,7 @@ type OrderRequest struct {
|
||||
type OrderItemRequest struct {
|
||||
ProductID int64 `json:"product_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type OrderExecuteRequest struct {
|
||||
|
||||
@ -30,6 +30,7 @@ type ProductSearch struct {
|
||||
Name string
|
||||
Type product.ProductType
|
||||
BranchID int64
|
||||
PartnerID int64
|
||||
Available product.ProductStock
|
||||
Limit int
|
||||
Offset int
|
||||
|
||||
@ -125,3 +125,12 @@ func (c Customer) HashedPassword() string {
|
||||
|
||||
return string(hashedPassword)
|
||||
}
|
||||
|
||||
func (u *Customer) ToUserAuthenticate(signedToken string) *AuthenticateUser {
|
||||
return &AuthenticateUser{
|
||||
ID: u.ID,
|
||||
Token: signedToken,
|
||||
Name: u.Name,
|
||||
UserType: u.UserType,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@ package customerauth
|
||||
|
||||
import (
|
||||
auth2 "enaklo-pos-be/internal/handlers/request"
|
||||
"enaklo-pos-be/internal/services/v2/auth"
|
||||
"enaklo-pos-be/internal/services/v2/customer"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type AuthHandler struct {
|
||||
service services.Auth
|
||||
service auth.Service
|
||||
userService services.User
|
||||
customerSvc customer.Service
|
||||
}
|
||||
@ -23,49 +23,29 @@ type AuthHandler struct {
|
||||
func (a *AuthHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||
authRoute := group.Group("/auth")
|
||||
authRoute.POST("/login", a.AuthLogin)
|
||||
authRoute.POST("/forgot-password", a.ForgotPassword)
|
||||
authRoute.POST("/reset-password", jwt, a.ResetPassword)
|
||||
authRoute.POST("/register", a.Register)
|
||||
authRoute.POST("/verify", a.VerifyRegistration)
|
||||
}
|
||||
|
||||
func NewAuthHandler(service services.Auth, userService services.User, customerSvc customer.Service) *AuthHandler {
|
||||
func NewAuthHandler(service auth.Service) *AuthHandler {
|
||||
return &AuthHandler{
|
||||
service: service,
|
||||
userService: userService,
|
||||
customerSvc: customerSvc,
|
||||
}
|
||||
}
|
||||
|
||||
// AuthLogin handles the authentication process for user login.
|
||||
// @Summary User login
|
||||
// @Description Authenticates a user based on the provided credentials and returns a JWT token.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param bodyParam body auth2.LoginRequest true "User login credentials"
|
||||
// @Success 200 {object} response.BaseResponse{data=response.LoginResponse} "Login successful"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized"
|
||||
// @Router /api/v1/auth/login [post]
|
||||
// @Tags Auth Login API's
|
||||
func (h *AuthHandler) AuthLogin(c *gin.Context) {
|
||||
ctx := auth2.GetMyContext(c)
|
||||
|
||||
var bodyParam auth2.LoginRequest
|
||||
if err := c.ShouldBindJSON(&bodyParam); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
email := strings.ToLower(bodyParam.Email)
|
||||
authUser, err := h.service.AuthenticateUser(c, email, bodyParam.Password)
|
||||
authUser, err := h.service.AuthCustomer(ctx, email, bodyParam.Password)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if authUser.UserType != "CUSTOMER" {
|
||||
response.ErrorWrapper(c, errors.ErrorUserIsNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
resp := response.LoginResponseCustoemr{
|
||||
ID: authUser.ID,
|
||||
Token: authUser.Token,
|
||||
@ -80,118 +60,3 @@ func (h *AuthHandler) AuthLogin(c *gin.Context) {
|
||||
Data: resp,
|
||||
})
|
||||
}
|
||||
|
||||
// ForgotPassword handles the request for password reset.
|
||||
// @Summary Request password reset
|
||||
// @Description Sends a password reset link to the user's email.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param bodyParam body auth2.ForgotPasswordRequest true "User email"
|
||||
// @Success 200 {object} response.BaseResponse "Password reset link sent"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Router /api/v1/auth/forgot-password [post]
|
||||
// @Tags Auth Password API's
|
||||
func (h *AuthHandler) ForgotPassword(c *gin.Context) {
|
||||
var bodyParam auth2.ResetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&bodyParam); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.service.SendPasswordResetLink(c, bodyParam.Email)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Message: "Password reset link sent",
|
||||
})
|
||||
}
|
||||
|
||||
// ResetPassword handles the password reset process.
|
||||
// @Summary Reset user password
|
||||
// @Description Resets the user's password using the provided token.
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param bodyParam body auth2.ResetPasswordRequest true "Reset password details"
|
||||
// @Success 200 {object} response.BaseResponse "Password reset successful"
|
||||
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
|
||||
// @Router /api/v1/auth/reset-password [post]
|
||||
// @Tags Auth Password API's
|
||||
func (h *AuthHandler) ResetPassword(c *gin.Context) {
|
||||
ctx := auth2.GetMyContext(c)
|
||||
|
||||
var req auth2.ResetPasswordChangeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := req.Validate(); err != nil {
|
||||
response.ErrorWrapper(c, errors.NewError(
|
||||
errors.ErrorBadRequest.ErrorType(),
|
||||
fmt.Sprintf("invalid request %v", err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
err := h.service.ResetPassword(ctx, req.OldPassword, req.NewPassword)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Message: "Password reset successful",
|
||||
})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) Register(c *gin.Context) {
|
||||
var req auth2.CustomerRegister
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := auth2.GetMyContext(c)
|
||||
customer, err := h.customerSvc.RegistrationMember(ctx, req.ToEntity())
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: response.CustomerRegistrationResp{
|
||||
EmailVerificationRequired: true,
|
||||
PhoneVerificationRequired: false,
|
||||
VerificationID: customer.VerificationID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (h *AuthHandler) VerifyRegistration(c *gin.Context) {
|
||||
var req auth2.VerifyEmailRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := auth2.GetMyContext(c)
|
||||
err := h.customerSvc.VerifyOTP(ctx, req.VerificationID, req.OTPCode)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Message: "Email verification successful",
|
||||
})
|
||||
}
|
||||
|
||||
213
internal/handlers/http/menu.go
Normal file
213
internal/handlers/http/menu.go
Normal file
@ -0,0 +1,213 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"enaklo-pos-be/internal/common/errors"
|
||||
"enaklo-pos-be/internal/entity"
|
||||
"enaklo-pos-be/internal/handlers/request"
|
||||
"enaklo-pos-be/internal/handlers/response"
|
||||
"enaklo-pos-be/internal/services/v2/inprogress_order"
|
||||
"enaklo-pos-be/internal/services/v2/product"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type MenuHandler struct {
|
||||
service product.Service
|
||||
orderService inprogress_order.InProgressOrderService
|
||||
}
|
||||
|
||||
func NewMenuHandler(service product.Service, orderService inprogress_order.InProgressOrderService,
|
||||
) *MenuHandler {
|
||||
return &MenuHandler{
|
||||
service: service,
|
||||
orderService: orderService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *MenuHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||
route := group.Group("/menu")
|
||||
|
||||
route.GET("/:partner_id", h.GetProducts)
|
||||
route.POST("/order/create", h.OrderCreate)
|
||||
route.POST("/order/member/create", jwt, h.OrderMemberCreate)
|
||||
route.GET("/order", h.GetOrderID)
|
||||
}
|
||||
|
||||
func (h *MenuHandler) GetProducts(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
partnerIDParam := c.Param("partner_id")
|
||||
partnerID, err := strconv.ParseInt(partnerIDParam, 10, 64)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if partnerID <= 0 {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var req request.ProductParam
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
searchParam := req.ToEntity()
|
||||
searchParam.PartnerID = partnerID
|
||||
|
||||
products, total, err := h.service.GetProductsByPartnerID(ctx, searchParam)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: h.toProductResponseList(products, int64(total), req),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *MenuHandler) toProductResponseList(resp []*entity.Product, total int64, req request.ProductParam) response.ProductList {
|
||||
var products []response.Product
|
||||
for _, b := range resp {
|
||||
products = append(products, h.toProductResponse(b))
|
||||
}
|
||||
|
||||
return response.ProductList{
|
||||
Products: products,
|
||||
Total: total,
|
||||
Limit: req.Limit,
|
||||
Offset: req.Offset,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *MenuHandler) toProductResponse(resp *entity.Product) response.Product {
|
||||
return response.Product{
|
||||
ID: resp.ID,
|
||||
Name: resp.Name,
|
||||
Type: resp.Type,
|
||||
Price: resp.Price,
|
||||
Status: resp.Status,
|
||||
Description: resp.Description,
|
||||
Image: resp.Image,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *MenuHandler) OrderCreate(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req request.OrderCustomer
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if req.PartnerID == 0 {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
orderRequest := req.ToEntity(req.PartnerID, 0)
|
||||
|
||||
order, err := h.orderService.Save(ctx, orderRequest)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: MapToOrderCreateResponse(order),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *MenuHandler) OrderMemberCreate(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req request.OrderCustomer
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(req); err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if req.PartnerID == 0 {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
userID := ctx.RequestedBy()
|
||||
orderRequest := req.ToEntity(req.PartnerID, userID)
|
||||
orderRequest.CustomerID = &userID
|
||||
|
||||
order, err := h.orderService.Save(ctx, orderRequest)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: MapToOrderCreateResponse(order),
|
||||
})
|
||||
}
|
||||
|
||||
type GetOrderParam struct {
|
||||
PartnerID int64 `form:"partner_id" json:"partner_id"`
|
||||
OrderID int64 `form:"order_id" json:"order_id"`
|
||||
}
|
||||
|
||||
func (h *MenuHandler) GetOrderID(c *gin.Context) {
|
||||
ctx := request.GetMyContext(c)
|
||||
|
||||
var req GetOrderParam
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
response.ErrorWrapper(c, errors.ErrorBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
order, err := h.orderService.GetOrderByOrderAndPartnerID(ctx, req.PartnerID, req.OrderID)
|
||||
if err != nil {
|
||||
response.ErrorWrapper(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, response.BaseResponse{
|
||||
Success: true,
|
||||
Status: http.StatusOK,
|
||||
Data: MapToOrderCreateResponse(order),
|
||||
})
|
||||
}
|
||||
|
||||
func MapToOrderCreateResponse(result *entity.Order) response.OrderResponse {
|
||||
resp := response.OrderResponse{
|
||||
ID: result.ID,
|
||||
Status: result.Status,
|
||||
Amount: result.Amount,
|
||||
Tax: result.Tax,
|
||||
Total: result.Total,
|
||||
PaymentType: result.PaymentType,
|
||||
CreatedAt: result.CreatedAt,
|
||||
Items: response.MapToOrderItemResponses(result.OrderItems),
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
@ -22,7 +22,7 @@ type OssHandler struct {
|
||||
func (h *OssHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
|
||||
route := group.Group("/file")
|
||||
|
||||
route.POST("/upload", h.UploadFile)
|
||||
route.POST("/upload", jwt, h.UploadFile)
|
||||
}
|
||||
|
||||
func NewOssHandler(ossService services.OSSService) *OssHandler {
|
||||
|
||||
@ -6,12 +6,10 @@ import (
|
||||
"enaklo-pos-be/internal/handlers/request"
|
||||
"enaklo-pos-be/internal/handlers/response"
|
||||
"enaklo-pos-be/internal/services"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
@ -275,9 +273,6 @@ func (h *Handler) toProductResponse(resp *entity.Product) response.Product {
|
||||
Price: resp.Price,
|
||||
Status: resp.Status,
|
||||
Description: resp.Description,
|
||||
CreatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: resp.CreatedAt.Format(time.RFC3339),
|
||||
PartnerID: resp.PartnerID,
|
||||
Image: resp.Image,
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,14 +313,11 @@ func (h *Handler) toProductResponseList(products []entity.Product) []response.Pr
|
||||
for _, product := range products {
|
||||
res = append(res, response.Product{
|
||||
ID: product.ID,
|
||||
PartnerID: product.PartnerID,
|
||||
Name: product.Name,
|
||||
Type: product.Type,
|
||||
Price: product.Price,
|
||||
Status: product.Status,
|
||||
Description: product.Description,
|
||||
CreatedAt: product.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: product.UpdatedAt.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
return res
|
||||
|
||||
@ -8,7 +8,6 @@ import (
|
||||
func GetMyContext(c *gin.Context) mycontext.Context {
|
||||
rawCtx, exists := c.Get("myCtx")
|
||||
if !exists {
|
||||
// handle missing context
|
||||
return mycontext.NewContext(c)
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,16 @@ type Order struct {
|
||||
PaymentProvider string `json:"payment_provider"`
|
||||
TableNumber string `json:"table_number"`
|
||||
OrderItems []OrderItem `json:"order_items"`
|
||||
PartnerID int64 `json:"partner_id"`
|
||||
}
|
||||
|
||||
type OrderCustomer struct {
|
||||
CustomerName string `json:"customer_name" validate:"required"`
|
||||
CustomerPhone string `json:"customer_phone"`
|
||||
CustomerEmail string `json:"customer_email"`
|
||||
TableNumber string `json:"table_number" validate:"required"`
|
||||
OrderItems []OrderItem `json:"order_items" validate:"required"`
|
||||
PartnerID int64 `json:"partner_id" validate:"required"`
|
||||
}
|
||||
|
||||
type CustomerOrder struct {
|
||||
@ -84,6 +94,7 @@ func (o *OrderParam) ToOrderEntity(ctx mycontext.Context) entity.OrderSearch {
|
||||
type OrderItem struct {
|
||||
ProductID int64 `json:"product_id" validate:"required"`
|
||||
Quantity int `json:"quantity" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (o *Order) ToEntity(partnerID, createdBy int64) *entity.OrderRequest {
|
||||
@ -143,3 +154,23 @@ func (o *OrderParamCustomer) ToOrderEntity(ctx mycontext.Context) entity.OrderSe
|
||||
type OrderPrintDetail struct {
|
||||
ID int64 `form:"id" json:"id" example:"10"`
|
||||
}
|
||||
|
||||
func (o *OrderCustomer) ToEntity(partnerID, createdBy int64) *entity.OrderRequest {
|
||||
orderItems := make([]entity.OrderItemRequest, len(o.OrderItems))
|
||||
for i, item := range o.OrderItems {
|
||||
orderItems[i] = entity.OrderItemRequest{
|
||||
ProductID: item.ProductID,
|
||||
Quantity: item.Quantity,
|
||||
Description: item.Description,
|
||||
}
|
||||
}
|
||||
|
||||
return &entity.OrderRequest{
|
||||
PartnerID: partnerID,
|
||||
OrderItems: orderItems,
|
||||
CreatedBy: createdBy,
|
||||
Source: "ONLINE_ORDER",
|
||||
CustomerName: o.CustomerName,
|
||||
TableNumber: o.TableNumber,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,14 +2,11 @@ package response
|
||||
|
||||
type Product struct {
|
||||
ID int64 `json:"id"`
|
||||
PartnerID int64 `json:"partner_id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Price float64 `json:"price"`
|
||||
Status string `json:"status"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Image string `json:"image"`
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +41,37 @@ func AuthorizationMiddleware(cryp repository.Crypto) gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func CustomerAuthorizationMiddleware(cryp repository.Crypto) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
tokenString := c.GetHeader("Authorization")
|
||||
if tokenString == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header is required"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
tokenString = strings.TrimPrefix(tokenString, "Bearer ")
|
||||
|
||||
claims, err := cryp.ParseAndValidateJWTCustomer(tokenString)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid JWT token"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
customCtx, err := mycontext.NewMyContextCustomer(c.Request.Context(), claims)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "error initialize context"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("myCtx", customCtx)
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func SuperAdminMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
ctx, exists := c.Get("myCtx")
|
||||
|
||||
@ -27,6 +27,7 @@ type CryptoConfig interface {
|
||||
AccessTokenResetPasswordExpire() time.Time
|
||||
AccessTokenWithdrawSecret() string
|
||||
AccessTokenWithdrawExpire() time.Time
|
||||
AccessTokenCustomerSecret() string
|
||||
}
|
||||
|
||||
type CryptoImpl struct {
|
||||
@ -126,6 +127,21 @@ func (c *CryptoImpl) ParseAndValidateJWT(tokenString string) (*entity.JWTAuthCla
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CryptoImpl) ParseAndValidateJWTCustomer(tokenString string) (*entity.JWTAuthClaimsCustomer, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &entity.JWTAuthClaimsCustomer{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(c.Config.AccessTokenCustomerSecret()), nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(*entity.JWTAuthClaimsCustomer); ok && token.Valid {
|
||||
return claims, nil
|
||||
} else {
|
||||
return nil, errors.ErrorUnauthorized
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CryptoImpl) GenerateJWTOrder(order *entity.Order) (string, error) {
|
||||
claims := &entity.JWTOrderClaims{
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
@ -282,3 +298,27 @@ func (c *CryptoImpl) ValidateJWTWithdraw(tokenString string) (*entity.WalletWith
|
||||
Fee: claims.Fee,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CryptoImpl) GenerateJWTCustomer(user *entity.Customer) (string, error) {
|
||||
claims := &entity.JWTAuthClaimsCustomer{
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
Subject: strconv.FormatInt(user.ID, 10),
|
||||
ExpiresAt: c.Config.AccessTokenExpiresDate().Unix(),
|
||||
IssuedAt: time.Now().Unix(),
|
||||
NotBefore: time.Now().Unix(),
|
||||
},
|
||||
UserID: user.ID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
}
|
||||
|
||||
token, err := jwt.
|
||||
NewWithClaims(jwt.SigningMethodHS256, claims).
|
||||
SignedString([]byte(c.Config.AccessTokenCustomerSecret()))
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ func (r *customerRepository) AddPoints(ctx mycontext.Context, customerID int64,
|
||||
Reference: reference,
|
||||
PointsEarned: points,
|
||||
TransactionDate: time.Now(),
|
||||
Status: "SUCCESS",
|
||||
Status: "active",
|
||||
}
|
||||
|
||||
if err := tx.Create(&pointTransaction).Error; err != nil {
|
||||
@ -255,6 +255,7 @@ func (r *customerRepository) toDomainCustomerModel(dbModel *models.CustomerDB) *
|
||||
UpdatedAt: dbModel.UpdatedAt,
|
||||
CustomerID: dbModel.CustomerID,
|
||||
BirthDate: dbModel.BirthDate,
|
||||
Password: dbModel.Password,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ func (CustomerPointsDB) TableName() string {
|
||||
type CustomerPointTransactionDB struct {
|
||||
ID uint64 `gorm:"column:id;primaryKey;autoIncrement"`
|
||||
CustomerID int64 `gorm:"column:customer_id;not null"`
|
||||
Reference string `gorm:"column:transaction_id"`
|
||||
Reference string `gorm:"column:reference"`
|
||||
PointsEarned int `gorm:"column:points_earned;not null"`
|
||||
TransactionDate time.Time `gorm:"column:transaction_date;not null"`
|
||||
ExpirationDate *time.Time `gorm:"column:expiration_date"`
|
||||
|
||||
@ -37,6 +37,7 @@ type OrderRepository interface {
|
||||
ctx mycontext.Context,
|
||||
req entity.PopularProductsRequest,
|
||||
) ([]entity.PopularProductItem, error)
|
||||
FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error)
|
||||
}
|
||||
|
||||
type orderRepository struct {
|
||||
@ -60,16 +61,32 @@ func (r *orderRepository) Create(ctx mycontext.Context, order *entity.Order) (*e
|
||||
}
|
||||
}()
|
||||
|
||||
if order.InProgressOrderID != 0 {
|
||||
orderDB.ID = order.InProgressOrderID
|
||||
|
||||
if err := tx.Omit("customer_id", "partner_id", "customer_name", "created_by").Save(&orderDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to update in-progress order")
|
||||
}
|
||||
|
||||
order.ID = order.InProgressOrderID
|
||||
|
||||
if err := tx.Where("order_id = ?", order.ID).Delete(&models.OrderItemDB{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to delete existing order items")
|
||||
}
|
||||
} else {
|
||||
if err := tx.Create(&orderDB).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to insert order")
|
||||
}
|
||||
|
||||
order.ID = orderDB.ID
|
||||
}
|
||||
|
||||
for i := range order.OrderItems {
|
||||
item := &order.OrderItems[i]
|
||||
item.OrderID = orderDB.ID
|
||||
item.OrderID = order.ID
|
||||
|
||||
itemDB := r.toOrderItemDBModel(item)
|
||||
|
||||
@ -81,23 +98,19 @@ func (r *orderRepository) Create(ctx mycontext.Context, order *entity.Order) (*e
|
||||
item.ID = itemDB.ID
|
||||
}
|
||||
|
||||
if order.InProgressOrderID != 0 {
|
||||
if err := tx.Where("order_id = ?", order.InProgressOrderID).Delete(&models.OrderItemDB{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to delete in-progress order items")
|
||||
}
|
||||
|
||||
if err := tx.Where("id = ?", order.InProgressOrderID).Delete(&models.OrderDB{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return nil, errors.Wrap(err, "failed to delete in-progress order")
|
||||
}
|
||||
}
|
||||
|
||||
// Commit the transaction
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to commit transaction")
|
||||
}
|
||||
|
||||
return order, nil
|
||||
var updatedOrderDB models.OrderDB
|
||||
if err := r.db.Preload("OrderItems").First(&updatedOrderDB, order.ID).Error; err != nil {
|
||||
return nil, errors.Wrap(err, "failed to fetch updated order")
|
||||
}
|
||||
|
||||
updatedOrder := r.toDomainOrderModel(&updatedOrderDB)
|
||||
|
||||
return updatedOrder, nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) FindByID(ctx mycontext.Context, id int64) (*entity.Order, error) {
|
||||
@ -690,7 +703,7 @@ func (r *orderRepository) GetSalesByCategory(
|
||||
ctx mycontext.Context,
|
||||
req entity.SalesByCategoryRequest,
|
||||
) ([]entity.SalesByCategoryItem, error) {
|
||||
var salesByCategory []entity.SalesByCategoryItem
|
||||
salesByCategory := []entity.SalesByCategoryItem{}
|
||||
|
||||
baseQuery := r.db.Model(&models.OrderItemDB{}).
|
||||
Joins("JOIN orders ON order_items.order_id = orders.id").
|
||||
@ -792,8 +805,7 @@ func (r *orderRepository) GetPopularProducts(
|
||||
return nil, errors.Wrap(err, "failed to calculate total sales")
|
||||
}
|
||||
|
||||
// Prepare the query for popular products
|
||||
var popularProducts []entity.PopularProductItem
|
||||
popularProducts := []entity.PopularProductItem{}
|
||||
orderClause := "total_sales DESC"
|
||||
if req.SortBy == "revenue" {
|
||||
orderClause = "total_revenue DESC"
|
||||
@ -824,3 +836,23 @@ func (r *orderRepository) GetPopularProducts(
|
||||
|
||||
return popularProducts, nil
|
||||
}
|
||||
|
||||
func (r *orderRepository) FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error) {
|
||||
var orderDB models.OrderDB
|
||||
|
||||
if err := r.db.Preload("OrderItems").Where("id = ? AND partner_id = ?", id, partnerID).First(&orderDB).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.New("order not found")
|
||||
}
|
||||
return nil, errors.Wrap(err, "failed to find order")
|
||||
}
|
||||
|
||||
order := r.toDomainOrderModel(&orderDB)
|
||||
|
||||
for _, itemDB := range orderDB.OrderItems {
|
||||
item := r.toDomainOrderItemModel(&itemDB)
|
||||
order.OrderItems = append(order.OrderItems, *item)
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
type ProductRepository interface {
|
||||
GetProductsByIDs(ctx mycontext.Context, ids []int64, partnerID int64) ([]*entity.Product, error)
|
||||
GetProductDetails(ctx mycontext.Context, productIDs []int64, partnerID int64) (*entity.ProductDetails, error)
|
||||
GetProductsByPartnerID(ctx mycontext.Context, req entity.ProductSearch) ([]*entity.Product, int64, error)
|
||||
}
|
||||
|
||||
type productRepository struct {
|
||||
@ -78,5 +79,40 @@ func (r *productRepository) toDomainProductModel(dbModel *models.ProductDB) *ent
|
||||
Status: dbModel.Status,
|
||||
CreatedAt: dbModel.CreatedAt,
|
||||
UpdatedAt: dbModel.UpdatedAt,
|
||||
Image: dbModel.Image,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *productRepository) GetProductsByPartnerID(ctx mycontext.Context, req entity.ProductSearch) ([]*entity.Product, int64, error) {
|
||||
if req.PartnerID == 0 {
|
||||
return nil, 0, nil
|
||||
}
|
||||
query := r.db.Where("partner_id = ?", req.PartnerID)
|
||||
|
||||
if req.Type != "" {
|
||||
query = query.Where("type = ?", req.Type)
|
||||
}
|
||||
|
||||
if req.Name != "" {
|
||||
query = query.Where("name ILIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := query.Model(&models.ProductDB{}).Count(&total).Error; err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to count products")
|
||||
}
|
||||
|
||||
var productsDB []models.ProductDB
|
||||
|
||||
if err := query.Find(&productsDB).Error; err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to find products")
|
||||
}
|
||||
|
||||
products := make([]*entity.Product, 0, len(productsDB))
|
||||
for i := range productsDB {
|
||||
product := r.toDomainProductModel(&productsDB[i])
|
||||
products = append(products, product)
|
||||
}
|
||||
|
||||
return products, total, nil
|
||||
}
|
||||
|
||||
@ -120,6 +120,8 @@ type Crypto interface {
|
||||
ParseAndValidateJWT(token string) (*entity.JWTAuthClaims, error)
|
||||
GenerateJWTWithdraw(req *entity.WalletWithdrawRequest) (string, error)
|
||||
ValidateJWTWithdraw(tokenString string) (*entity.WalletWithdrawRequest, error)
|
||||
GenerateJWTCustomer(user *entity.Customer) (string, error)
|
||||
ParseAndValidateJWTCustomer(tokenString string) (*entity.JWTAuthClaimsCustomer, error)
|
||||
}
|
||||
|
||||
type User interface {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"enaklo-pos-be/internal/handlers/http"
|
||||
"enaklo-pos-be/internal/handlers/http/customerauth"
|
||||
"enaklo-pos-be/internal/handlers/http/discovery"
|
||||
"enaklo-pos-be/internal/middlewares"
|
||||
@ -14,11 +15,12 @@ func RegisterCustomerRoutes(app *app.Server, serviceManager *services.ServiceMan
|
||||
repoManager *repository.RepoManagerImpl) {
|
||||
approute := app.Group("/api/v1/customer")
|
||||
|
||||
authMiddleware := middlewares.AuthorizationMiddleware(repoManager.Crypto)
|
||||
authMiddleware := middlewares.CustomerAuthorizationMiddleware(repoManager.Crypto)
|
||||
|
||||
serverRoutes := []HTTPHandlerRoutes{
|
||||
discovery.NewHandler(serviceManager.DiscoverService),
|
||||
customerauth.NewAuthHandler(serviceManager.AuthSvc, serviceManager.UserSvc, serviceManager.CustomerV2Svc),
|
||||
customerauth.NewAuthHandler(serviceManager.AuthV2Svc),
|
||||
http.NewMenuHandler(serviceManager.ProductV2Svc, serviceManager.InProgressSvc),
|
||||
}
|
||||
|
||||
for _, handler := range serverRoutes {
|
||||
|
||||
@ -14,9 +14,11 @@ import (
|
||||
"enaklo-pos-be/internal/services/studio"
|
||||
"enaklo-pos-be/internal/services/transaction"
|
||||
"enaklo-pos-be/internal/services/users"
|
||||
authSvc "enaklo-pos-be/internal/services/v2/auth"
|
||||
customerSvc "enaklo-pos-be/internal/services/v2/customer"
|
||||
"enaklo-pos-be/internal/services/v2/inprogress_order"
|
||||
orderSvc "enaklo-pos-be/internal/services/v2/order"
|
||||
|
||||
"enaklo-pos-be/internal/services/v2/partner_settings"
|
||||
productSvc "enaklo-pos-be/internal/services/v2/product"
|
||||
|
||||
@ -48,6 +50,7 @@ type ServiceManagerImpl struct {
|
||||
ProductV2Svc productSvc.Service
|
||||
MemberRegistrationSvc member.RegistrationService
|
||||
InProgressSvc inprogress_order.InProgressOrderService
|
||||
AuthV2Svc authSvc.Service
|
||||
}
|
||||
|
||||
func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) *ServiceManagerImpl {
|
||||
@ -76,6 +79,8 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl)
|
||||
MemberRegistrationSvc: member.NewMemberRegistrationService(repo.MemberRepository, repo.EmailService, custSvcV2),
|
||||
CustomerV2Svc: custSvcV2,
|
||||
InProgressSvc: inprogressOrder,
|
||||
ProductV2Svc: productSvcV2,
|
||||
AuthV2Svc: authSvc.New(repo.CustomerRepo, repo.Crypto),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
58
internal/services/v2/auth/auth.go
Normal file
58
internal/services/v2/auth/auth.go
Normal file
@ -0,0 +1,58 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"enaklo-pos-be/internal/common/errors"
|
||||
"enaklo-pos-be/internal/common/logger"
|
||||
"enaklo-pos-be/internal/common/mycontext"
|
||||
"enaklo-pos-be/internal/entity"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
FindByEmail(ctx mycontext.Context, email string) (*entity.Customer, error)
|
||||
}
|
||||
|
||||
type CryptoSvc interface {
|
||||
GenerateJWTCustomer(user *entity.Customer) (string, error)
|
||||
CompareHashAndPassword(hash string, password string) bool
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
AuthCustomer(ctx mycontext.Context, email, password string) (*entity.AuthenticateUser, error)
|
||||
}
|
||||
|
||||
type authSvc struct {
|
||||
repo Repository
|
||||
crypt CryptoSvc
|
||||
}
|
||||
|
||||
func New(repo Repository, cryptSvc CryptoSvc) Service {
|
||||
return &authSvc{
|
||||
repo: repo,
|
||||
crypt: cryptSvc,
|
||||
}
|
||||
}
|
||||
|
||||
func (a authSvc) AuthCustomer(ctx mycontext.Context, email, password string) (*entity.AuthenticateUser, error) {
|
||||
user, err := a.repo.FindByEmail(ctx, email)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("error when get user", zap.Error(err))
|
||||
return nil, errors.ErrorInternalServer
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return nil, errors.ErrorUserIsNotFound
|
||||
}
|
||||
|
||||
if ok := a.crypt.CompareHashAndPassword(user.Password, password); !ok {
|
||||
return nil, errors.ErrorUserInvalidLogin
|
||||
}
|
||||
|
||||
signedToken, err := a.crypt.GenerateJWTCustomer(user)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user.ToUserAuthenticate(signedToken), nil
|
||||
}
|
||||
@ -13,11 +13,13 @@ import (
|
||||
type InProgressOrderService interface {
|
||||
Save(ctx mycontext.Context, order *entity.OrderRequest) (*entity.Order, error)
|
||||
GetOrdersByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int) ([]*entity.Order, error)
|
||||
GetOrderByOrderAndPartnerID(ctx mycontext.Context, partnerID int64, orderID int64) (*entity.Order, error)
|
||||
}
|
||||
|
||||
type OrderRepository interface {
|
||||
CreateOrUpdate(ctx mycontext.Context, order *entity.Order) (*entity.Order, error)
|
||||
GetListByPartnerID(ctx mycontext.Context, partnerID int64, limit, offset int, status string) ([]*entity.Order, error)
|
||||
FindByIDAndPartnerID(ctx mycontext.Context, id int64, partnerID int64) (*entity.Order, error)
|
||||
}
|
||||
|
||||
type OrderCalculator interface {
|
||||
@ -26,6 +28,7 @@ type OrderCalculator interface {
|
||||
items []entity.OrderItemRequest,
|
||||
productDetails *entity.ProductDetails,
|
||||
source string,
|
||||
partnerID int64,
|
||||
) (*entity.OrderCalculation, error)
|
||||
ValidateOrderItems(ctx mycontext.Context, items []entity.OrderItemRequest) ([]int64, []entity.OrderItemRequest, error)
|
||||
}
|
||||
@ -57,7 +60,7 @@ func (s *inProgressOrderSvc) Save(ctx mycontext.Context, req *entity.OrderReques
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderCalculation, err := s.orderCalculator.CalculateOrderTotals(ctx, req.OrderItems, productDetails, req.Source)
|
||||
orderCalculation, err := s.orderCalculator.CalculateOrderTotals(ctx, req.OrderItems, productDetails, req.Source, req.PartnerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -76,6 +79,7 @@ func (s *inProgressOrderSvc) Save(ctx mycontext.Context, req *entity.OrderReques
|
||||
Quantity: item.Quantity,
|
||||
Price: product.Price,
|
||||
ItemType: product.Type,
|
||||
Description: product.Description,
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,3 +123,15 @@ func (s *inProgressOrderSvc) GetOrdersByPartnerID(ctx mycontext.Context, partner
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
func (s *inProgressOrderSvc) GetOrderByOrderAndPartnerID(ctx mycontext.Context, partnerID int64, orderID int64) (*entity.Order, error) {
|
||||
orders, err := s.repo.FindByIDAndPartnerID(ctx, orderID, partnerID)
|
||||
if err != nil {
|
||||
logger.ContextLogger(ctx).Error("failed to get in-progress orders by partner ID",
|
||||
zap.Error(err),
|
||||
zap.Int64("partnerID", partnerID))
|
||||
return nil, errors.Wrap(err, "failed to get order")
|
||||
}
|
||||
|
||||
return orders, nil
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ func (s *orderSvc) CreateOrderInquiry(ctx mycontext.Context,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
orderCalculation, err := s.CalculateOrderTotals(ctx, req.OrderItems, productDetails, req.Source)
|
||||
orderCalculation, err := s.CalculateOrderTotals(ctx, req.OrderItems, productDetails, req.Source, req.PartnerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -104,6 +104,7 @@ func (s *orderSvc) CalculateOrderTotals(
|
||||
items []entity.OrderItemRequest,
|
||||
productDetails *entity.ProductDetails,
|
||||
source string,
|
||||
partnerID int64,
|
||||
) (*entity.OrderCalculation, error) {
|
||||
subtotal := 0.0
|
||||
|
||||
@ -115,8 +116,7 @@ func (s *orderSvc) CalculateOrderTotals(
|
||||
subtotal += product.Price * float64(item.Quantity)
|
||||
}
|
||||
|
||||
partnerID := ctx.GetPartnerID()
|
||||
setting, err := s.partnerSetting.GetSettings(ctx, *partnerID)
|
||||
setting, err := s.partnerSetting.GetSettings(ctx, partnerID)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.NewError(errors.ErrorInvalidRequest.ErrorType(), "failed to get partner settings")
|
||||
|
||||
@ -67,6 +67,7 @@ type Service interface {
|
||||
items []entity.OrderItemRequest,
|
||||
productDetails *entity.ProductDetails,
|
||||
source string,
|
||||
partnerID int64,
|
||||
) (*entity.OrderCalculation, error)
|
||||
ValidateOrderItems(ctx mycontext.Context, items []entity.OrderItemRequest) ([]int64, []entity.OrderItemRequest, error)
|
||||
GetOrderPaymentAnalysis(
|
||||
|
||||
@ -31,3 +31,13 @@ func (s *productSvc) GetProductsByIDs(ctx mycontext.Context, ids []int64, partne
|
||||
|
||||
return products, nil
|
||||
}
|
||||
|
||||
func (s *productSvc) GetProductsByPartnerID(ctx mycontext.Context, search entity.ProductSearch) ([]*entity.Product, int64, error) {
|
||||
products, total, err := s.repo.GetProductsByPartnerID(ctx, search)
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrap(err, "failed to get products by partner ID")
|
||||
}
|
||||
|
||||
return products, total, nil
|
||||
}
|
||||
|
||||
@ -8,11 +8,13 @@ import (
|
||||
type Repository interface {
|
||||
GetProductsByIDs(ctx mycontext.Context, ids []int64, partnerID int64) ([]*entity.Product, error)
|
||||
GetProductDetails(ctx mycontext.Context, productIDs []int64, partnerID int64) (*entity.ProductDetails, error)
|
||||
GetProductsByPartnerID(ctx mycontext.Context, req entity.ProductSearch) ([]*entity.Product, int64, error)
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
GetProductsByIDs(ctx mycontext.Context, ids []int64, partnerID int64) ([]*entity.Product, error)
|
||||
GetProductDetails(ctx mycontext.Context, productIDs []int64, partnerID int64) (*entity.ProductDetails, error)
|
||||
GetProductsByPartnerID(ctx mycontext.Context, search entity.ProductSearch) ([]*entity.Product, int64, error)
|
||||
}
|
||||
|
||||
type productSvc struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user