This commit is contained in:
aditya.siregar
2025-07-18 20:10:29 +07:00
parent 1bceae010b
commit 4f5950543e
511 changed files with 24132 additions and 34137 deletions
+157
View File
@@ -0,0 +1,157 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/transformer"
"apskel-pos-be/internal/util"
"github.com/gin-gonic/gin"
)
type AnalyticsHandler struct {
analyticsService service.AnalyticsService
transformer transformer.Transformer
}
func NewAnalyticsHandler(
analyticsService service.AnalyticsService,
transformer transformer.Transformer,
) *AnalyticsHandler {
return &AnalyticsHandler{
analyticsService: analyticsService,
transformer: transformer,
}
}
func (h *AnalyticsHandler) GetPaymentMethodAnalytics(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.PaymentMethodAnalyticsRequest
if err := c.ShouldBindQuery(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetPaymentMethodAnalytics", err.Error())}), "AnalyticsHandler::GetPaymentMethodAnalytics")
return
}
req.OrganizationID = contextInfo.OrganizationID
modelReq := transformer.PaymentMethodAnalyticsContractToModel(&req)
response, err := h.analyticsService.GetPaymentMethodAnalytics(ctx, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetPaymentMethodAnalytics", err.Error())}), "AnalyticsHandler::GetPaymentMethodAnalytics")
return
}
// Transform model to contract
contractResp := transformer.PaymentMethodAnalyticsModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetPaymentMethodAnalytics")
}
// GetSalesAnalytics handles the request to get sales analytics
func (h *AnalyticsHandler) GetSalesAnalytics(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.SalesAnalyticsRequest
if err := c.ShouldBindQuery(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetSalesAnalytics", err.Error())}), "AnalyticsHandler::GetSalesAnalytics")
return
}
req.OrganizationID = contextInfo.OrganizationID
modelReq := transformer.SalesAnalyticsContractToModel(&req)
// Call service
response, err := h.analyticsService.GetSalesAnalytics(ctx, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetSalesAnalytics", err.Error())}), "AnalyticsHandler::GetSalesAnalytics")
return
}
// Transform model to contract
contractResp := transformer.SalesAnalyticsModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetSalesAnalytics")
}
// GetProductAnalytics handles the request to get product analytics
func (h *AnalyticsHandler) GetProductAnalytics(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.ProductAnalyticsRequest
if err := c.ShouldBindQuery(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProductAnalytics", err.Error())}), "AnalyticsHandler::GetProductAnalytics")
return
}
req.OrganizationID = contextInfo.OrganizationID
// Transform contract to model
modelReq := transformer.ProductAnalyticsContractToModel(&req)
// Call service
response, err := h.analyticsService.GetProductAnalytics(ctx, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProductAnalytics", err.Error())}), "AnalyticsHandler::GetProductAnalytics")
return
}
// Transform model to contract
contractResp := transformer.ProductAnalyticsModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProductAnalytics")
}
// GetDashboardAnalytics handles the request to get dashboard analytics
func (h *AnalyticsHandler) GetDashboardAnalytics(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.DashboardAnalyticsRequest
if err := c.ShouldBindQuery(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetDashboardAnalytics", err.Error())}), "AnalyticsHandler::GetDashboardAnalytics")
return
}
req.OrganizationID = contextInfo.OrganizationID
modelReq := transformer.DashboardAnalyticsContractToModel(&req)
response, err := h.analyticsService.GetDashboardAnalytics(ctx, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetDashboardAnalytics", err.Error())}), "AnalyticsHandler::GetDashboardAnalytics")
return
}
// Transform model to contract
contractResp := transformer.DashboardAnalyticsModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetDashboardAnalytics")
}
func (h *AnalyticsHandler) GetProfitLossAnalytics(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.ProfitLossAnalyticsRequest
if err := c.ShouldBindQuery(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProfitLossAnalytics", err.Error())}), "AnalyticsHandler::GetProfitLossAnalytics")
return
}
req.OrganizationID = contextInfo.OrganizationID
modelReq, err := transformer.ProfitLossAnalyticsContractToModel(&req)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "AnalyticsHandler::GetProfitLossAnalytics", err.Error())}), "AnalyticsHandler::GetProfitLossAnalytics")
return
}
// Call service
response, err := h.analyticsService.GetProfitLossAnalytics(ctx, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "AnalyticsHandler::GetProfitLossAnalytics", err.Error())}), "AnalyticsHandler::GetProfitLossAnalytics")
return
}
// Transform model to contract
contractResp := transformer.ProfitLossAnalyticsModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "AnalyticsHandler::GetProfitLossAnalytics")
}
+169
View File
@@ -0,0 +1,169 @@
package handler
import (
"net/http"
"strings"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/transformer"
"github.com/gin-gonic/gin"
)
type AuthHandler struct {
authService service.AuthService
}
func NewAuthHandler(authService service.AuthService) *AuthHandler {
return &AuthHandler{
authService: authService,
}
}
func (h *AuthHandler) Login(c *gin.Context) {
var req contract.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Login -> request binding failed")
h.sendValidationErrorResponse(c, "Invalid request body", constants.MissingFieldErrorCode)
return
}
if strings.TrimSpace(req.Email) == "" {
logger.FromContext(c.Request.Context()).Error("AuthHandler::Login -> email is required")
h.sendValidationErrorResponse(c, "Email is required", constants.MissingFieldErrorCode)
return
}
if strings.TrimSpace(req.Password) == "" {
logger.FromContext(c.Request.Context()).Error("AuthHandler::Login -> password is required")
h.sendValidationErrorResponse(c, "Password is required", constants.MissingFieldErrorCode)
return
}
loginResponse, err := h.authService.Login(c.Request.Context(), &req)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Login -> Failed to login")
h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
return
}
logger.FromContext(c.Request.Context()).Infof("AuthHandler::Login -> Successfully logged in user = %s", loginResponse.User.Email)
c.JSON(http.StatusOK, loginResponse)
}
func (h *AuthHandler) Logout(c *gin.Context) {
token := h.extractTokenFromHeader(c)
if token == "" {
logger.FromContext(c.Request.Context()).Error("AuthHandler::Logout -> token is required")
h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
return
}
err := h.authService.Logout(c.Request.Context(), token)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::Logout -> Failed to logout")
h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
return
}
logger.FromContext(c.Request.Context()).Info("AuthHandler::Logout -> Successfully logged out")
c.JSON(http.StatusOK, transformer.CreateSuccessResponse("Successfully logged out", nil))
}
func (h *AuthHandler) RefreshToken(c *gin.Context) {
token := h.extractTokenFromHeader(c)
if token == "" {
logger.FromContext(c.Request.Context()).Error("AuthHandler::RefreshToken -> token is required")
h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
return
}
loginResponse, err := h.authService.RefreshToken(c.Request.Context(), token)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::RefreshToken -> Failed to refresh token")
h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
return
}
logger.FromContext(c.Request.Context()).Infof("AuthHandler::RefreshToken -> Successfully refreshed token for user = %s", loginResponse.User.Email)
c.JSON(http.StatusOK, loginResponse)
}
func (h *AuthHandler) ValidateToken(c *gin.Context) {
token := h.extractTokenFromHeader(c)
if token == "" {
logger.FromContext(c.Request.Context()).Error("AuthHandler::ValidateToken -> token is required")
h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
return
}
userResponse, err := h.authService.ValidateToken(token)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::ValidateToken -> Failed to validate token")
h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
return
}
logger.FromContext(c.Request.Context()).Infof("AuthHandler::ValidateToken -> Successfully validated token for user = %s", userResponse.Email)
c.JSON(http.StatusOK, userResponse)
}
func (h *AuthHandler) GetProfile(c *gin.Context) {
token := h.extractTokenFromHeader(c)
if token == "" {
logger.FromContext(c.Request.Context()).Error("AuthHandler::GetProfile -> token is required")
h.sendErrorResponse(c, "Token is required", http.StatusUnauthorized)
return
}
userResponse, err := h.authService.ValidateToken(token)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("AuthHandler::GetProfile -> Failed to get profile")
h.sendErrorResponse(c, err.Error(), http.StatusUnauthorized)
return
}
logger.FromContext(c.Request.Context()).Infof("AuthHandler::GetProfile -> Successfully retrieved profile for user = %s", userResponse.Email)
c.JSON(http.StatusOK, userResponse)
}
// Helper methods
func (h *AuthHandler) extractTokenFromHeader(c *gin.Context) string {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
return ""
}
// Expected format: "Bearer <token>"
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
return ""
}
return parts[1]
}
func (h *AuthHandler) sendErrorResponse(c *gin.Context, message string, statusCode int) {
errorResponse := &contract.ErrorResponse{
Error: "error",
Message: message,
Code: statusCode,
}
c.JSON(statusCode, errorResponse)
}
func (h *AuthHandler) sendValidationErrorResponse(c *gin.Context, message string, errorCode string) {
errorResponse := &contract.ErrorResponse{
Error: "validation_error",
Message: message,
Code: http.StatusBadRequest,
Details: map[string]interface{}{
"error_code": errorCode,
"entity": constants.AuthHandlerEntity,
},
}
c.JSON(http.StatusBadRequest, errorResponse)
}
+189
View File
@@ -0,0 +1,189 @@
package handler
import (
"strconv"
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type CategoryHandler struct {
categoryService service.CategoryService
categoryValidator validator.CategoryValidator
}
func NewCategoryHandler(
categoryService service.CategoryService,
categoryValidator validator.CategoryValidator,
) *CategoryHandler {
return &CategoryHandler{
categoryService: categoryService,
categoryValidator: categoryValidator,
}
}
func (h *CategoryHandler) CreateCategory(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateCategoryRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("CategoryHandler::CreateCategory -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::CreateCategory")
return
}
validationError, validationErrorCode := h.categoryValidator.ValidateCreateCategoryRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::CreateCategory")
return
}
categoryResponse := h.categoryService.CreateCategory(ctx, contextInfo, &req)
if categoryResponse.HasErrors() {
errorResp := categoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("CategoryHandler::CreateCategory -> Failed to create category from service")
}
util.HandleResponse(c.Writer, c.Request, categoryResponse, "CategoryHandler::CreateCategory")
}
func (h *CategoryHandler) UpdateCategory(c *gin.Context) {
ctx := c.Request.Context()
categoryIDStr := c.Param("id")
categoryID, err := uuid.Parse(categoryIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::UpdateCategory -> Invalid category ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid category ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::UpdateCategory")
return
}
var req contract.UpdateCategoryRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::UpdateCategory -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::UpdateCategory")
return
}
validationError, validationErrorCode := h.categoryValidator.ValidateUpdateCategoryRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::UpdateCategory")
return
}
categoryResponse := h.categoryService.UpdateCategory(ctx, categoryID, &req)
if categoryResponse.HasErrors() {
errorResp := categoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("CategoryHandler::UpdateCategory -> Failed to update category from service")
}
util.HandleResponse(c.Writer, c.Request, categoryResponse, "CategoryHandler::UpdateCategory")
}
func (h *CategoryHandler) DeleteCategory(c *gin.Context) {
ctx := c.Request.Context()
categoryIDStr := c.Param("id")
categoryID, err := uuid.Parse(categoryIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::DeleteCategory -> Invalid category ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid category ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::DeleteCategory")
return
}
categoryResponse := h.categoryService.DeleteCategory(ctx, categoryID)
if categoryResponse.HasErrors() {
errorResp := categoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("CategoryHandler::DeleteCategory -> Failed to delete category from service")
}
util.HandleResponse(c.Writer, c.Request, categoryResponse, "CategoryHandler::DeleteCategory")
}
func (h *CategoryHandler) GetCategory(c *gin.Context) {
ctx := c.Request.Context()
categoryIDStr := c.Param("id")
categoryID, err := uuid.Parse(categoryIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CategoryHandler::GetCategory -> Invalid category ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid category ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::GetCategory")
return
}
categoryResponse := h.categoryService.GetCategoryByID(ctx, categoryID)
if categoryResponse.HasErrors() {
errorResp := categoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("CategoryHandler::GetCategory -> Failed to get category from service")
}
util.HandleResponse(c.Writer, c.Request, categoryResponse, "CategoryHandler::GetCategory")
}
func (h *CategoryHandler) ListCategories(c *gin.Context) {
ctx := c.Request.Context()
req := &contract.ListCategoriesRequest{
Page: 1,
Limit: 10,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
if search := c.Query("search"); search != "" {
req.Search = search
}
if businessType := c.Query("business_type"); businessType != "" {
req.BusinessType = businessType
}
if organizationIDStr := c.Query("organization_id"); organizationIDStr != "" {
if organizationID, err := uuid.Parse(organizationIDStr); err == nil {
req.OrganizationID = &organizationID
}
}
validationError, validationErrorCode := h.categoryValidator.ValidateListCategoriesRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("CategoryHandler::ListCategories -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CategoryHandler::ListCategories")
return
}
categoriesResponse := h.categoryService.ListCategories(ctx, req)
if categoriesResponse.HasErrors() {
errorResp := categoriesResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("CategoryHandler::ListCategories -> Failed to list categories from service")
}
util.HandleResponse(c.Writer, c.Request, categoriesResponse, "CategoryHandler::ListCategories")
}
+57
View File
@@ -0,0 +1,57 @@
package handler
import (
"net/http"
"time"
)
type CommonMiddleware struct{}
func NewCommonMiddleware() *CommonMiddleware {
return &CommonMiddleware{}
}
func (m *CommonMiddleware) CORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
func (m *CommonMiddleware) ContentType(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
next.ServeHTTP(w, r)
})
}
func (m *CommonMiddleware) Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
_ = time.Since(start)
})
}
func (m *CommonMiddleware) Recovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
}()
next.ServeHTTP(w, r)
})
}
+257
View File
@@ -0,0 +1,257 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type CustomerHandler struct {
customerService service.CustomerService
customerValidator validator.CustomerValidator
}
func NewCustomerHandler(
customerService service.CustomerService,
customerValidator validator.CustomerValidator,
) *CustomerHandler {
return &CustomerHandler{
customerService: customerService,
customerValidator: customerValidator,
}
}
func (h *CustomerHandler) CreateCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateCustomerRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerHandler::CreateCustomer -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::CreateCustomer")
return
}
validationError, validationErrorCode := h.customerValidator.ValidateCreateCustomerRequest(&req)
if validationError != nil {
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerHandler::CreateCustomer -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::CreateCustomer")
return
}
organizationID := contextInfo.OrganizationID
customerResponse, err := h.customerService.CreateCustomer(c.Request.Context(), &req, organizationID)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerHandler::CreateCustomer -> Failed to create customer from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::CreateCustomer")
return
}
logger.FromContext(c.Request.Context()).Infof("CustomerHandler::CreateCustomer -> Successfully created customer = %+v", customerResponse)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(customerResponse), "CustomerHandler::CreateCustomer")
}
func (h *CustomerHandler) GetCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
customerID, err := uuid.Parse(c.Param("id"))
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::GetCustomer -> Invalid customer ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid customer ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::GetCustomer")
return
}
organizationID := contextInfo.OrganizationID
customerResponse, err := h.customerService.GetCustomer(c.Request.Context(), customerID, organizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::GetCustomer -> Failed to get customer from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::GetCustomer")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(customerResponse), "CustomerHandler::GetCustomer")
}
func (h *CustomerHandler) ListCustomers(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
req := &contract.ListCustomersRequest{
Page: 1,
Limit: 10,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
req.Search = c.Query("search")
req.SortBy = c.Query("sort_by")
req.SortOrder = c.Query("sort_order")
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
req.IsActive = &isActive
}
}
if isDefaultStr := c.Query("is_default"); isDefaultStr != "" {
if isDefault, err := strconv.ParseBool(isDefaultStr); err == nil {
req.IsDefault = &isDefault
}
}
validationError, validationErrorCode := h.customerValidator.ValidateListCustomersRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("CustomerHandler::ListCustomers -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::ListCustomers")
return
}
organizationID := contextInfo.OrganizationID
customersResponse, err := h.customerService.ListCustomers(c.Request.Context(), req, organizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::ListCustomers -> Failed to list customers from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::ListCustomers")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(customersResponse), "CustomerHandler::ListCustomers")
}
func (h *CustomerHandler) UpdateCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
customerID, err := uuid.Parse(c.Param("id"))
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::UpdateCustomer -> Invalid customer ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid customer ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::UpdateCustomer")
return
}
var req contract.UpdateCustomerRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerHandler::UpdateCustomer -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::UpdateCustomer")
return
}
validationError, validationErrorCode := h.customerValidator.ValidateUpdateCustomerRequest(&req)
if validationError != nil {
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerHandler::UpdateCustomer -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::UpdateCustomer")
return
}
organizationID := contextInfo.OrganizationID
customerResponse, err := h.customerService.UpdateCustomer(c.Request.Context(), customerID, organizationID, &req)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::UpdateCustomer -> Failed to update customer from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::UpdateCustomer")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(customerResponse), "CustomerHandler::UpdateCustomer")
}
func (h *CustomerHandler) DeleteCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
customerID, err := uuid.Parse(c.Param("id"))
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::DeleteCustomer -> Invalid customer ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid customer ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::DeleteCustomer")
return
}
organizationID := contextInfo.OrganizationID
err = h.customerService.DeleteCustomer(c.Request.Context(), customerID, organizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::DeleteCustomer -> Failed to delete customer from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::DeleteCustomer")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(gin.H{"message": "Customer deleted successfully"}), "CustomerHandler::DeleteCustomer")
}
func (h *CustomerHandler) SetDefaultCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.SetDefaultCustomerRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("CustomerHandler::SetDefaultCustomer -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::SetDefaultCustomer")
return
}
validationError, validationErrorCode := h.customerValidator.ValidateSetDefaultCustomerRequest(&req)
if validationError != nil {
logger.FromContext(c.Request.Context()).WithError(validationError).Error("CustomerHandler::SetDefaultCustomer -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CustomerHandler::SetDefaultCustomer")
return
}
organizationID := contextInfo.OrganizationID
customerResponse, err := h.customerService.SetDefaultCustomer(c.Request.Context(), req.CustomerID, organizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::SetDefaultCustomer -> Failed to set default customer from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::SetDefaultCustomer")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(customerResponse), "CustomerHandler::SetDefaultCustomer")
}
func (h *CustomerHandler) GetDefaultCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
organizationID := contextInfo.OrganizationID
customerResponse, err := h.customerService.GetDefaultCustomer(c.Request.Context(), organizationID)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("CustomerHandler::GetDefaultCustomer -> Failed to get default customer from service")
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CustomerServiceEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{errorResp}), "CustomerHandler::GetDefaultCustomer")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(customerResponse), "CustomerHandler::GetDefaultCustomer")
}
+181
View File
@@ -0,0 +1,181 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/transformer"
"apskel-pos-be/internal/validator"
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type FileHandler struct {
fileService service.FileService
validator validator.FileValidator
transformer transformer.Transformer
}
func NewFileHandler(
fileService service.FileService,
validator validator.FileValidator,
transformer transformer.Transformer,
) *FileHandler {
return &FileHandler{
fileService: fileService,
validator: validator,
transformer: transformer,
}
}
func (h *FileHandler) UploadFile(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
file, err := c.FormFile("file")
if err != nil {
h.transformer.Error(c, http.StatusBadRequest, "File is required", err)
return
}
var req contract.UploadFileRequest
if fileType := c.PostForm("file_type"); fileType != "" {
req.FileType = fileType
}
if isPublicStr := c.PostForm("is_public"); isPublicStr != "" {
if isPublic, err := strconv.ParseBool(isPublicStr); err == nil {
req.IsPublic = &isPublic
}
}
if err := h.validator.Validate(&req); err != nil {
h.transformer.Error(c, http.StatusBadRequest, "Validation failed", err)
return
}
organizationID := contextInfo.OrganizationID
userID := contextInfo.UserID
// Transform contract to model
modelReq := transformer.UploadFileContractToModel(&req)
response, err := h.fileService.UploadFile(ctx, file, modelReq, organizationID, userID)
if err != nil {
h.transformer.Error(c, http.StatusInternalServerError, "Failed to upload file", err)
return
}
// Transform model to contract
contractResp := transformer.FileModelToContract(response)
h.transformer.Success(c, http.StatusCreated, "File uploaded successfully", contractResp)
}
func (h *FileHandler) GetFileByID(c *gin.Context) {
idStr := c.Param("id")
id, err := uuid.Parse(idStr)
if err != nil {
h.transformer.Error(c, http.StatusBadRequest, "Invalid file ID", err)
return
}
response, err := h.fileService.GetFileByID(c.Request.Context(), id)
if err != nil {
h.transformer.Error(c, http.StatusInternalServerError, "Failed to get file", err)
return
}
// Transform model to contract
contractResp := transformer.FileModelToContract(response)
h.transformer.Success(c, http.StatusOK, "File retrieved successfully", contractResp)
}
func (h *FileHandler) UpdateFile(c *gin.Context) {
idStr := c.Param("id")
id, err := uuid.Parse(idStr)
if err != nil {
h.transformer.Error(c, http.StatusBadRequest, "Invalid file ID", err)
return
}
var req contract.UpdateFileRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.transformer.Error(c, http.StatusBadRequest, "Invalid request body", err)
return
}
if err := h.validator.Validate(&req); err != nil {
h.transformer.Error(c, http.StatusBadRequest, "Validation failed", err)
return
}
// Transform contract to model
modelReq := transformer.UpdateFileContractToModel(&req)
response, err := h.fileService.UpdateFile(c.Request.Context(), id, modelReq)
if err != nil {
h.transformer.Error(c, http.StatusInternalServerError, "Failed to update file", err)
return
}
// Transform model to contract
contractResp := transformer.FileModelToContract(response)
h.transformer.Success(c, http.StatusOK, "File updated successfully", contractResp)
}
func (h *FileHandler) GetFilesByOrganization(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
organizationID := contextInfo.OrganizationID
response, err := h.fileService.GetFileByOrganizationID(ctx, organizationID)
if err != nil {
h.transformer.Error(c, http.StatusInternalServerError, "Failed to get files by organization", err)
return
}
// Transform model to contract
contractFiles := make([]*contract.FileResponse, len(response))
for i, file := range response {
contractFiles[i] = transformer.FileModelToContract(file)
}
contractResp := &contract.ListFilesResponse{
Files: contractFiles,
TotalCount: len(response),
Page: 1,
Limit: len(response),
TotalPages: 1,
}
h.transformer.Success(c, http.StatusOK, "Files retrieved successfully", contractResp)
}
func (h *FileHandler) GetFilesByUser(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
userID := contextInfo.UserID
response, err := h.fileService.GetFileByUserID(ctx, userID)
if err != nil {
h.transformer.Error(c, http.StatusInternalServerError, "Failed to get files by user", err)
return
}
// Transform model to contract
contractFiles := make([]*contract.FileResponse, len(response))
for i, file := range response {
contractFiles[i] = transformer.FileModelToContract(file)
}
contractResp := &contract.ListFilesResponse{
Files: contractFiles,
TotalCount: len(response),
Page: 1,
Limit: len(response),
TotalPages: 1,
}
h.transformer.Success(c, http.StatusOK, "Files retrieved successfully", contractResp)
}
+23
View File
@@ -0,0 +1,23 @@
package handler
import (
"apskel-pos-be/internal/logger"
"net/http"
"github.com/gin-gonic/gin"
)
type HealthHandler struct {
}
func NewHealthHandler() *HealthHandler {
return &HealthHandler{}
}
func (hh *HealthHandler) HealthCheck(c *gin.Context) {
log := logger.NewContextLogger(c, "healthCheck")
log.Info("Health Check success")
c.JSON(http.StatusOK, gin.H{
"status": "Healthy!!",
})
}
+278
View File
@@ -0,0 +1,278 @@
package handler
import (
"strconv"
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type InventoryHandler struct {
inventoryService service.InventoryService
inventoryValidator validator.InventoryValidator
}
func NewInventoryHandler(
inventoryService service.InventoryService,
inventoryValidator validator.InventoryValidator,
) *InventoryHandler {
return &InventoryHandler{
inventoryService: inventoryService,
inventoryValidator: inventoryValidator,
}
}
func (h *InventoryHandler) CreateInventory(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateInventoryRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("InventoryHandler::CreateInventory -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::CreateInventory")
return
}
validationError, validationErrorCode := h.inventoryValidator.ValidateCreateInventoryRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::CreateInventory")
return
}
inventoryResponse := h.inventoryService.CreateInventory(ctx, contextInfo, &req)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::CreateInventory -> Failed to create inventory from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::CreateInventory")
}
func (h *InventoryHandler) UpdateInventory(c *gin.Context) {
ctx := c.Request.Context()
inventoryIDStr := c.Param("id")
inventoryID, err := uuid.Parse(inventoryIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::UpdateInventory -> Invalid inventory ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid inventory ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::UpdateInventory")
return
}
var req contract.UpdateInventoryRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::UpdateInventory -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::UpdateInventory")
return
}
validationError, validationErrorCode := h.inventoryValidator.ValidateUpdateInventoryRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::UpdateInventory")
return
}
inventoryResponse := h.inventoryService.UpdateInventory(ctx, inventoryID, &req)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::UpdateInventory -> Failed to update inventory from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::UpdateInventory")
}
func (h *InventoryHandler) DeleteInventory(c *gin.Context) {
ctx := c.Request.Context()
inventoryIDStr := c.Param("id")
inventoryID, err := uuid.Parse(inventoryIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::DeleteInventory -> Invalid inventory ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid inventory ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::DeleteInventory")
return
}
inventoryResponse := h.inventoryService.DeleteInventory(ctx, inventoryID)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::DeleteInventory -> Failed to delete inventory from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::DeleteInventory")
}
func (h *InventoryHandler) GetInventory(c *gin.Context) {
ctx := c.Request.Context()
inventoryIDStr := c.Param("id")
inventoryID, err := uuid.Parse(inventoryIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetInventory -> Invalid inventory ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid inventory ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetInventory")
return
}
inventoryResponse := h.inventoryService.GetInventoryByID(ctx, inventoryID)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::GetInventory -> Failed to get inventory from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetInventory")
}
func (h *InventoryHandler) ListInventory(c *gin.Context) {
ctx := c.Request.Context()
req := &contract.ListInventoryRequest{
Page: 1,
Limit: 10,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
if search := c.Query("search"); search != "" {
req.Search = search
}
if outletIDStr := c.Query("outlet_id"); outletIDStr != "" {
if outletID, err := uuid.Parse(outletIDStr); err == nil {
req.OutletID = &outletID
}
}
if productIDStr := c.Query("product_id"); productIDStr != "" {
if productID, err := uuid.Parse(productIDStr); err == nil {
req.ProductID = &productID
}
}
if categoryIDStr := c.Query("category_id"); categoryIDStr != "" {
if categoryID, err := uuid.Parse(categoryIDStr); err == nil {
req.CategoryID = &categoryID
}
}
if lowStockStr := c.Query("low_stock_only"); lowStockStr != "" {
if lowStock, err := strconv.ParseBool(lowStockStr); err == nil {
req.LowStockOnly = &lowStock
}
}
if zeroStockStr := c.Query("zero_stock_only"); zeroStockStr != "" {
if zeroStock, err := strconv.ParseBool(zeroStockStr); err == nil {
req.ZeroStockOnly = &zeroStock
}
}
validationError, validationErrorCode := h.inventoryValidator.ValidateListInventoryRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("InventoryHandler::ListInventory -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::ListInventory")
return
}
inventoryResponse := h.inventoryService.ListInventory(ctx, req)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::ListInventory -> Failed to list inventory from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::ListInventory")
}
func (h *InventoryHandler) AdjustInventory(c *gin.Context) {
ctx := c.Request.Context()
var req contract.AdjustInventoryRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::AdjustInventory -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::AdjustInventory")
return
}
validationError, validationErrorCode := h.inventoryValidator.ValidateAdjustInventoryRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::AdjustInventory")
return
}
inventoryResponse := h.inventoryService.AdjustInventory(ctx, &req)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::AdjustInventory -> Failed to adjust inventory from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::AdjustInventory")
}
func (h *InventoryHandler) GetLowStockItems(c *gin.Context) {
ctx := c.Request.Context()
outletIDStr := c.Param("outlet_id")
outletID, err := uuid.Parse(outletIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetLowStockItems -> Invalid outlet ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetLowStockItems")
return
}
inventoryResponse := h.inventoryService.GetLowStockItems(ctx, outletID)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::GetLowStockItems -> Failed to get low stock items from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetLowStockItems")
}
func (h *InventoryHandler) GetZeroStockItems(c *gin.Context) {
ctx := c.Request.Context()
outletIDStr := c.Param("outlet_id")
outletID, err := uuid.Parse(outletIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("InventoryHandler::GetZeroStockItems -> Invalid outlet ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "InventoryHandler::GetZeroStockItems")
return
}
inventoryResponse := h.inventoryService.GetZeroStockItems(ctx, outletID)
if inventoryResponse.HasErrors() {
errorResp := inventoryResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("InventoryHandler::GetZeroStockItems -> Failed to get zero stock items from service")
}
util.HandleResponse(c.Writer, c.Request, inventoryResponse, "InventoryHandler::GetZeroStockItems")
}
+296
View File
@@ -0,0 +1,296 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/transformer"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type OrderHandler struct {
orderService service.OrderService
validator validator.OrderValidator
transformer transformer.Transformer
}
func NewOrderHandler(
orderService service.OrderService,
validator validator.OrderValidator,
transformer transformer.Transformer,
) *OrderHandler {
return &OrderHandler{
orderService: orderService,
validator: validator,
transformer: transformer,
}
}
func (h *OrderHandler) CreateOrder(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::CreateOrder", err.Error())}), "OrderHandler::CreateOrder")
return
}
req.UserID = contextInfo.UserID
modelReq := transformer.CreateOrderContractToModel(&req)
response, err := h.orderService.CreateOrder(ctx, modelReq, contextInfo.OrganizationID)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::CreateOrder", err.Error())}), "OrderHandler::CreateOrder")
return
}
contractResp := transformer.OrderModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::CreateOrder")
}
func (h *OrderHandler) GetOrderByID(c *gin.Context) {
idStr := c.Param("id")
id, err := uuid.Parse(idStr)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_id", "OrderHandler::GetOrderByID", err.Error())}), "OrderHandler::GetOrderByID")
return
}
response, err := h.orderService.GetOrderByID(c.Request.Context(), id)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::GetOrderByID", err.Error())}), "OrderHandler::GetOrderByID")
return
}
contractResp := transformer.OrderModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::GetOrderByID")
}
func (h *OrderHandler) UpdateOrder(c *gin.Context) {
idStr := c.Param("id")
id, err := uuid.Parse(idStr)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_id", "OrderHandler::UpdateOrder", err.Error())}), "OrderHandler::UpdateOrder")
return
}
var req contract.UpdateOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::UpdateOrder", err.Error())}), "OrderHandler::UpdateOrder")
return
}
modelReq := transformer.UpdateOrderContractToModel(&req)
response, err := h.orderService.UpdateOrder(c.Request.Context(), id, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::UpdateOrder", err.Error())}), "OrderHandler::UpdateOrder")
return
}
contractResp := transformer.OrderModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::UpdateOrder")
}
func (h *OrderHandler) AddToOrder(c *gin.Context) {
idStr := c.Param("id")
id, err := uuid.Parse(idStr)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_id", "OrderHandler::AddToOrder", err.Error())}), "OrderHandler::AddToOrder")
return
}
var req contract.AddToOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::AddToOrder", err.Error())}), "OrderHandler::AddToOrder")
return
}
modelReq := transformer.AddToOrderContractToModel(&req)
response, err := h.orderService.AddToOrder(c.Request.Context(), id, modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::AddToOrder", err.Error())}), "OrderHandler::AddToOrder")
return
}
contractResp := transformer.AddToOrderModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::AddToOrder")
}
func (h *OrderHandler) ListOrders(c *gin.Context) {
var query contract.ListOrdersQuery
if err := c.ShouldBindQuery(&query); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_query_parameters", "OrderHandler::ListOrders", err.Error())}), "OrderHandler::ListOrders")
return
}
modelReq := transformer.ListOrdersQueryToModel(&query)
if err := h.validator.Validate(modelReq); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("validation_failed", "OrderHandler::ListOrders", err.Error())}), "OrderHandler::ListOrders")
return
}
response, err := h.orderService.ListOrders(c.Request.Context(), modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::ListOrders", err.Error())}), "OrderHandler::ListOrders")
return
}
contractResp := transformer.ListOrdersModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::ListOrders")
}
func (h *OrderHandler) VoidOrder(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.VoidOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::VoidOrder", err.Error())}), "OrderHandler::VoidOrder")
return
}
userID := contextInfo.UserID
if err := h.validator.Validate(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("validation_failed", "OrderHandler::VoidOrder", err.Error())}), "OrderHandler::VoidOrder")
return
}
modelReq := transformer.VoidOrderContractToModel(&req)
if err := h.orderService.VoidOrder(ctx, modelReq, userID); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::VoidOrder", err.Error())}), "OrderHandler::VoidOrder")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(map[string]string{"message": "Order voided successfully"}), "OrderHandler::VoidOrder")
}
func (h *OrderHandler) RefundOrder(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
idStr := c.Param("id")
id, err := uuid.Parse(idStr)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_id", "OrderHandler::RefundOrder", err.Error())}), "OrderHandler::RefundOrder")
return
}
var req contract.RefundOrderRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::RefundOrder", err.Error())}), "OrderHandler::RefundOrder")
return
}
userID := contextInfo.UserID
modelReq := transformer.RefundOrderContractToModel(&req)
if err := h.validator.Validate(modelReq); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("validation_failed", "OrderHandler::RefundOrder", err.Error())}), "OrderHandler::RefundOrder")
return
}
if err := h.orderService.RefundOrder(ctx, id, modelReq, userID); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::RefundOrder", err.Error())}), "OrderHandler::RefundOrder")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "OrderHandler::RefundOrder")
}
func (h *OrderHandler) CreatePayment(c *gin.Context) {
var req contract.CreatePaymentRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::CreatePayment", err.Error())}), "OrderHandler::CreatePayment")
return
}
if err := h.validator.Validate(req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("validation_failed", "OrderHandler::CreatePayment", err.Error())}), "OrderHandler::CreatePayment")
return
}
modelReq := transformer.CreatePaymentContractToModel(&req)
response, err := h.orderService.CreatePayment(c.Request.Context(), modelReq)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::CreatePayment", err.Error())}), "OrderHandler::CreatePayment")
return
}
contractResp := transformer.PaymentModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::CreatePayment")
}
func (h *OrderHandler) RefundPayment(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
idStr := c.Param("id")
paymentID, err := uuid.Parse(idStr)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_id", "OrderHandler::RefundPayment", err.Error())}), "OrderHandler::RefundPayment")
return
}
var req contract.RefundPaymentRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::RefundPayment", err.Error())}), "OrderHandler::RefundPayment")
return
}
userID := contextInfo.UserID
if userID == uuid.Nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("unauthorized", "OrderHandler::RefundPayment", "Invalid User ID in context")}), "OrderHandler::RefundPayment")
return
}
if err := h.validator.Validate(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("validation_failed", "OrderHandler::RefundPayment", err.Error())}), "OrderHandler::RefundPayment")
return
}
if err := h.orderService.RefundPayment(ctx, paymentID, req.RefundAmount, req.Reason, userID); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::RefundPayment", err.Error())}), "OrderHandler::RefundPayment")
return
}
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(nil), "OrderHandler::RefundPayment")
}
func (h *OrderHandler) SetOrderCustomer(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
// Parse order ID from URL parameter
orderIDStr := c.Param("id")
orderID, err := uuid.Parse(orderIDStr)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_id", "OrderHandler::SetOrderCustomer", "Invalid order ID")}), "OrderHandler::SetOrderCustomer")
return
}
// Parse request body
var req contract.SetOrderCustomerRequest
if err := c.ShouldBindJSON(&req); err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("invalid_request", "OrderHandler::SetOrderCustomer", err.Error())}), "OrderHandler::SetOrderCustomer")
return
}
// Transform contract to model
modelReq := transformer.SetOrderCustomerContractToModel(&req)
// Call service
response, err := h.orderService.SetOrderCustomer(ctx, orderID, modelReq, contextInfo.OrganizationID)
if err != nil {
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{contract.NewResponseError("internal_error", "OrderHandler::SetOrderCustomer", err.Error())}), "OrderHandler::SetOrderCustomer")
return
}
// Transform model to contract
contractResp := transformer.SetOrderCustomerModelToContract(response)
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(contractResp), "OrderHandler::SetOrderCustomer")
}
+185
View File
@@ -0,0 +1,185 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/util"
"strconv"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type OrganizationHandler struct {
organizationService service.OrganizationService
organizationValidator validator.OrganizationValidator
}
func NewOrganizationHandler(
organizationService service.OrganizationService,
organizationValidator validator.OrganizationValidator,
) *OrganizationHandler {
return &OrganizationHandler{
organizationService: organizationService,
organizationValidator: organizationValidator,
}
}
func (h *OrganizationHandler) CreateOrganization(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateOrganizationRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("OrganizationHandler::CreateOrganization -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::CreateOrganization")
return
}
validationError, validationErrorCode := h.organizationValidator.ValidateCreateOrganizationRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::CreateOrganization")
return
}
organizationResponse := h.organizationService.CreateOrganization(ctx, contextInfo, &req)
if organizationResponse.HasErrors() {
errorResp := organizationResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::CreateOrganization -> Failed to create organization from service")
}
util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::CreateOrganization")
}
func (h *OrganizationHandler) UpdateOrganization(c *gin.Context) {
ctx := c.Request.Context()
organizationIDStr := c.Param("id")
organizationID, err := uuid.Parse(organizationIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::UpdateOrganization -> Invalid organization ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::UpdateOrganization")
return
}
var req contract.UpdateOrganizationRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::UpdateOrganization -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::UpdateOrganization")
return
}
validationError, validationErrorCode := h.organizationValidator.ValidateUpdateOrganizationRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::UpdateOrganization")
return
}
organizationResponse := h.organizationService.UpdateOrganization(ctx, organizationID, &req)
if organizationResponse.HasErrors() {
errorResp := organizationResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::UpdateOrganization -> Failed to update organization from service")
}
util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::UpdateOrganization")
}
func (h *OrganizationHandler) DeleteOrganization(c *gin.Context) {
ctx := c.Request.Context()
organizationIDStr := c.Param("id")
organizationID, err := uuid.Parse(organizationIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::DeleteOrganization -> Invalid organization ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::DeleteOrganization")
return
}
organizationResponse := h.organizationService.DeleteOrganization(ctx, organizationID)
if organizationResponse.HasErrors() {
errorResp := organizationResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::DeleteOrganization -> Failed to delete organization from service")
}
util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::DeleteOrganization")
}
func (h *OrganizationHandler) GetOrganization(c *gin.Context) {
ctx := c.Request.Context()
organizationIDStr := c.Param("id")
organizationID, err := uuid.Parse(organizationIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("OrganizationHandler::GetOrganization -> Invalid organization ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::GetOrganization")
return
}
organizationResponse := h.organizationService.GetOrganizationByID(ctx, organizationID)
if organizationResponse.HasErrors() {
errorResp := organizationResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::GetOrganization -> Failed to get organization from service")
}
util.HandleResponse(c.Writer, c.Request, organizationResponse, "OrganizationHandler::GetOrganization")
}
func (h *OrganizationHandler) ListOrganizations(c *gin.Context) {
ctx := c.Request.Context()
req := &contract.ListOrganizationsRequest{
Page: 1,
Limit: 10,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
if search := c.Query("search"); search != "" {
req.Search = search
}
if planType := c.Query("plan_type"); planType != "" {
req.PlanType = planType
}
validationError, validationErrorCode := h.organizationValidator.ValidateListOrganizationsRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("OrganizationHandler::ListOrganizations -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OrganizationHandler::ListOrganizations")
return
}
organizationsResponse := h.organizationService.ListOrganizations(ctx, req)
if organizationsResponse.HasErrors() {
errorResp := organizationsResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OrganizationHandler::ListOrganizations -> Failed to list organizations from service")
}
util.HandleResponse(c.Writer, c.Request, organizationsResponse, "OrganizationHandler::ListOrganizations")
}
// Old error response methods removed - now using util.HandleResponse pattern
+144
View File
@@ -0,0 +1,144 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type OutletHandler struct {
outletService service.OutletService
outletValidator validator.OutletValidator
}
func NewOutletHandler(outletService service.OutletService, outletValidator validator.OutletValidator) *OutletHandler {
return &OutletHandler{
outletService: outletService,
outletValidator: outletValidator,
}
}
func (h *OutletHandler) ListOutlets(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
req := &contract.ListOutletsRequest{
Page: 1,
Limit: 10,
OrganizationID: contextInfo.OrganizationID,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
if search := c.Query("search"); search != "" {
req.Search = search
}
if businessType := c.Query("business_type"); businessType != "" {
req.BusinessType = &businessType
}
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
req.IsActive = &isActive
}
}
validationError, validationErrorCode := h.outletValidator.ValidateListOutletsRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("OutletHandler::ListOutlets -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::ListOutlets")
return
}
outletsResponse := h.outletService.ListOutlets(ctx, req)
if outletsResponse.HasErrors() {
errorResp := outletsResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::ListOutlets -> Failed to list outlets from service")
}
util.HandleResponse(c.Writer, c.Request, outletsResponse, "OutletHandler::ListOutlets")
}
func (h *OutletHandler) GetOutlet(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
outletIDStr := c.Param("id")
outletID, err := uuid.Parse(outletIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("OutletHandler::GetOutlet -> Invalid outlet ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::GetOutlet")
return
}
outletResponse := h.outletService.GetOutletByID(ctx, contextInfo.OrganizationID, outletID)
if outletResponse.HasErrors() {
errorResp := outletResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::GetOutlet -> Failed to get outlet from service")
}
util.HandleResponse(c.Writer, c.Request, outletResponse, "OutletHandler::GetOutlet")
}
func (h *OutletHandler) UpdateOutlet(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
outletIDStr := c.Param("id")
outletID, err := uuid.Parse(outletIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("OutletHandler::UpdateOutlet -> Invalid outlet ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid outlet ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::UpdateOutlet")
return
}
var req contract.UpdateOutletRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("OutletHandler::UpdateOutlet -> Failed to bind JSON")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::UpdateOutlet")
return
}
req.OrganizationID = contextInfo.OrganizationID
validationError, validationErrorCode := h.outletValidator.ValidateUpdateOutletRequest(&req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("OutletHandler::UpdateOutlet -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "OutletHandler::UpdateOutlet")
return
}
outletResponse := h.outletService.UpdateOutlet(ctx, outletID, &req)
if outletResponse.HasErrors() {
errorResp := outletResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("OutletHandler::UpdateOutlet -> Failed to update outlet from service")
}
util.HandleResponse(c.Writer, c.Request, outletResponse, "OutletHandler::UpdateOutlet")
}
+226
View File
@@ -0,0 +1,226 @@
package handler
import (
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/service"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type OutletSettingHandlerImpl struct {
outletSettingService service.OutletSettingService
}
func NewOutletSettingHandlerImpl(outletSettingService service.OutletSettingService) *OutletSettingHandlerImpl {
return &OutletSettingHandlerImpl{
outletSettingService: outletSettingService,
}
}
func (h *OutletSettingHandlerImpl) CreateSetting(c *gin.Context) {
var req models.CreateOutletSettingRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid request body",
Message: err.Error(),
})
return
}
outletID, err := uuid.Parse(c.Param("outlet_id"))
if err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid outlet ID",
Message: "Outlet ID must be a valid UUID",
})
return
}
req.OutletID = outletID
setting, err := h.outletSettingService.CreateSetting(c.Request.Context(), &req)
if err != nil {
c.JSON(http.StatusInternalServerError, contract.ErrorResponse{
Error: "Failed to create setting",
Message: err.Error(),
})
return
}
c.JSON(http.StatusCreated, contract.SuccessResponse{
Data: setting,
})
}
func (h *OutletSettingHandlerImpl) UpdateSetting(c *gin.Context) {
var req models.UpdateOutletSettingRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid request body",
Message: err.Error(),
})
return
}
// Validate outlet ID from URL
outletID, err := uuid.Parse(c.Param("outlet_id"))
if err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid outlet ID",
Message: "Outlet ID must be a valid UUID",
})
return
}
// Get key from URL
key := c.Param("key")
if key == "" {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Missing setting key",
Message: "Setting key is required",
})
return
}
setting, err := h.outletSettingService.UpdateSetting(c.Request.Context(), outletID, key, &req)
if err != nil {
c.JSON(http.StatusInternalServerError, contract.ErrorResponse{
Error: "Failed to update setting",
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, contract.SuccessResponse{
Data: setting,
})
}
func (h *OutletSettingHandlerImpl) GetSetting(c *gin.Context) {
outletID, err := uuid.Parse(c.Param("outlet_id"))
if err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid outlet ID",
Message: "Outlet ID must be a valid UUID",
})
return
}
// Get key from URL
key := c.Param("key")
if key == "" {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Missing setting key",
Message: "Setting key is required",
})
return
}
setting, err := h.outletSettingService.GetSetting(c.Request.Context(), outletID, key)
if err != nil {
c.JSON(http.StatusNotFound, contract.ErrorResponse{
Error: "Setting not found",
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, contract.SuccessResponse{
Data: setting,
})
}
func (h *OutletSettingHandlerImpl) GetPrinterSettings(c *gin.Context) {
outletID, err := uuid.Parse(c.Param("outlet_id"))
if err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid outlet ID",
Message: "Outlet ID must be a valid UUID",
})
return
}
settings, err := h.outletSettingService.GetPrinterSettings(c.Request.Context(), outletID)
if err != nil {
c.JSON(http.StatusInternalServerError, contract.ErrorResponse{
Error: "Failed to get printer settings",
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, contract.SuccessResponse{
Data: settings,
})
}
func (h *OutletSettingHandlerImpl) UpdatePrinterSettings(c *gin.Context) {
var req models.UpdateOutletPrinterSettingsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid request body",
Message: err.Error(),
})
return
}
outletID, err := uuid.Parse(c.Param("outlet_id"))
if err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid outlet ID",
Message: "Outlet ID must be a valid UUID",
})
return
}
settings, err := h.outletSettingService.UpdatePrinterSettings(c.Request.Context(), outletID, &req)
if err != nil {
c.JSON(http.StatusInternalServerError, contract.ErrorResponse{
Error: "Failed to update printer settings",
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, contract.SuccessResponse{
Data: settings,
})
}
// DeleteSetting deletes a specific outlet setting
func (h *OutletSettingHandlerImpl) DeleteSetting(c *gin.Context) {
// Validate outlet ID from URL
outletID, err := uuid.Parse(c.Param("outlet_id"))
if err != nil {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Invalid outlet ID",
Message: "Outlet ID must be a valid UUID",
})
return
}
// Get key from URL
key := c.Param("key")
if key == "" {
c.JSON(http.StatusBadRequest, contract.ErrorResponse{
Error: "Missing setting key",
Message: "Setting key is required",
})
return
}
err = h.outletSettingService.DeleteSetting(c.Request.Context(), outletID, key)
if err != nil {
c.JSON(http.StatusInternalServerError, contract.ErrorResponse{
Error: "Failed to delete setting",
Message: err.Error(),
})
return
}
c.JSON(http.StatusOK, contract.SuccessResponse{
Message: "Setting deleted successfully",
})
}
+216
View File
@@ -0,0 +1,216 @@
package handler
import (
"strconv"
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type PaymentMethodHandler struct {
paymentMethodService service.PaymentMethodService
paymentMethodValidator validator.PaymentMethodValidator
}
func NewPaymentMethodHandler(
paymentMethodService service.PaymentMethodService,
paymentMethodValidator validator.PaymentMethodValidator,
) *PaymentMethodHandler {
return &PaymentMethodHandler{
paymentMethodService: paymentMethodService,
paymentMethodValidator: paymentMethodValidator,
}
}
func (h *PaymentMethodHandler) CreatePaymentMethod(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreatePaymentMethodRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("PaymentMethodHandler::CreatePaymentMethod -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::CreatePaymentMethod")
return
}
validationError, validationErrorCode := h.paymentMethodValidator.ValidateCreatePaymentMethodRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::CreatePaymentMethod")
return
}
paymentMethodResponse := h.paymentMethodService.CreatePaymentMethod(ctx, contextInfo, &req)
if paymentMethodResponse.HasErrors() {
errorResp := paymentMethodResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("PaymentMethodHandler::CreatePaymentMethod -> Failed to create payment method from service")
}
util.HandleResponse(c.Writer, c.Request, paymentMethodResponse, "PaymentMethodHandler::CreatePaymentMethod")
}
func (h *PaymentMethodHandler) GetPaymentMethod(c *gin.Context) {
ctx := c.Request.Context()
paymentMethodIDStr := c.Param("id")
paymentMethodID, err := uuid.Parse(paymentMethodIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("PaymentMethodHandler::GetPaymentMethod -> Invalid payment method ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid payment method ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::GetPaymentMethod")
return
}
paymentMethodResponse := h.paymentMethodService.GetPaymentMethodByID(ctx, paymentMethodID)
if paymentMethodResponse.HasErrors() {
errorResp := paymentMethodResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("PaymentMethodHandler::GetPaymentMethod -> Failed to get payment method from service")
}
util.HandleResponse(c.Writer, c.Request, paymentMethodResponse, "PaymentMethodHandler::GetPaymentMethod")
}
func (h *PaymentMethodHandler) ListPaymentMethods(c *gin.Context) {
ctx := c.Request.Context()
req := &contract.ListPaymentMethodsRequest{
Page: 1,
Limit: 10,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
if search := c.Query("search"); search != "" {
req.Search = search
}
if paymentMethodType := c.Query("type"); paymentMethodType != "" {
req.Type = &paymentMethodType
}
if organizationIDStr := c.Query("organization_id"); organizationIDStr != "" {
if organizationID, err := uuid.Parse(organizationIDStr); err == nil {
req.OrganizationID = &organizationID
}
}
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
req.IsActive = &isActive
}
}
validationError, validationErrorCode := h.paymentMethodValidator.ValidateListPaymentMethodsRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("PaymentMethodHandler::ListPaymentMethods -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::ListPaymentMethods")
return
}
paymentMethodsResponse := h.paymentMethodService.ListPaymentMethods(ctx, req)
if paymentMethodsResponse.HasErrors() {
errorResp := paymentMethodsResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("PaymentMethodHandler::ListPaymentMethods -> Failed to list payment methods from service")
}
util.HandleResponse(c.Writer, c.Request, paymentMethodsResponse, "PaymentMethodHandler::ListPaymentMethods")
}
func (h *PaymentMethodHandler) UpdatePaymentMethod(c *gin.Context) {
ctx := c.Request.Context()
paymentMethodIDStr := c.Param("id")
paymentMethodID, err := uuid.Parse(paymentMethodIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("PaymentMethodHandler::UpdatePaymentMethod -> Invalid payment method ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid payment method ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::UpdatePaymentMethod")
return
}
var req contract.UpdatePaymentMethodRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("PaymentMethodHandler::UpdatePaymentMethod -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::UpdatePaymentMethod")
return
}
validationError, validationErrorCode := h.paymentMethodValidator.ValidateUpdatePaymentMethodRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::UpdatePaymentMethod")
return
}
paymentMethodResponse := h.paymentMethodService.UpdatePaymentMethod(ctx, paymentMethodID, &req)
if paymentMethodResponse.HasErrors() {
errorResp := paymentMethodResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("PaymentMethodHandler::UpdatePaymentMethod -> Failed to update payment method from service")
}
util.HandleResponse(c.Writer, c.Request, paymentMethodResponse, "PaymentMethodHandler::UpdatePaymentMethod")
}
func (h *PaymentMethodHandler) DeletePaymentMethod(c *gin.Context) {
ctx := c.Request.Context()
paymentMethodIDStr := c.Param("id")
paymentMethodID, err := uuid.Parse(paymentMethodIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("PaymentMethodHandler::DeletePaymentMethod -> Invalid payment method ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid payment method ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::DeletePaymentMethod")
return
}
paymentMethodResponse := h.paymentMethodService.DeletePaymentMethod(ctx, paymentMethodID)
if paymentMethodResponse.HasErrors() {
errorResp := paymentMethodResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("PaymentMethodHandler::DeletePaymentMethod -> Failed to delete payment method from service")
}
util.HandleResponse(c.Writer, c.Request, paymentMethodResponse, "PaymentMethodHandler::DeletePaymentMethod")
}
func (h *PaymentMethodHandler) GetActivePaymentMethodsByOrganization(c *gin.Context) {
ctx := c.Request.Context()
organizationIDStr := c.Param("organization_id")
organizationID, err := uuid.Parse(organizationIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("PaymentMethodHandler::GetActivePaymentMethodsByOrganization -> Invalid organization ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid organization ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "PaymentMethodHandler::GetActivePaymentMethodsByOrganization")
return
}
paymentMethodsResponse := h.paymentMethodService.GetActivePaymentMethodsByOrganization(ctx, organizationID)
if paymentMethodsResponse.HasErrors() {
errorResp := paymentMethodsResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("PaymentMethodHandler::GetActivePaymentMethodsByOrganization -> Failed to get active payment methods from service")
}
util.HandleResponse(c.Writer, c.Request, paymentMethodsResponse, "PaymentMethodHandler::GetActivePaymentMethodsByOrganization")
}
+213
View File
@@ -0,0 +1,213 @@
package handler
import (
"strconv"
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type ProductHandler struct {
productService service.ProductService
productValidator validator.ProductValidator
}
func NewProductHandler(
productService service.ProductService,
productValidator validator.ProductValidator,
) *ProductHandler {
return &ProductHandler{
productService: productService,
productValidator: productValidator,
}
}
func (h *ProductHandler) CreateProduct(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateProductRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("ProductHandler::CreateProduct -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::CreateProduct")
return
}
validationError, validationErrorCode := h.productValidator.ValidateCreateProductRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::CreateProduct")
return
}
productResponse := h.productService.CreateProduct(ctx, contextInfo, &req)
if productResponse.HasErrors() {
errorResp := productResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::CreateProduct -> Failed to create product from service")
}
util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::CreateProduct")
}
func (h *ProductHandler) UpdateProduct(c *gin.Context) {
ctx := c.Request.Context()
productIDStr := c.Param("id")
productID, err := uuid.Parse(productIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductHandler::UpdateProduct -> Invalid product ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::UpdateProduct")
return
}
var req contract.UpdateProductRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductHandler::UpdateProduct -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::UpdateProduct")
return
}
validationError, validationErrorCode := h.productValidator.ValidateUpdateProductRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::UpdateProduct")
return
}
productResponse := h.productService.UpdateProduct(ctx, productID, &req)
if productResponse.HasErrors() {
errorResp := productResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::UpdateProduct -> Failed to update product from service")
}
util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::UpdateProduct")
}
func (h *ProductHandler) DeleteProduct(c *gin.Context) {
ctx := c.Request.Context()
productIDStr := c.Param("id")
productID, err := uuid.Parse(productIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductHandler::DeleteProduct -> Invalid product ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::DeleteProduct")
return
}
productResponse := h.productService.DeleteProduct(ctx, productID)
if productResponse.HasErrors() {
errorResp := productResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::DeleteProduct -> Failed to delete product from service")
}
util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::DeleteProduct")
}
func (h *ProductHandler) GetProduct(c *gin.Context) {
ctx := c.Request.Context()
productIDStr := c.Param("id")
productID, err := uuid.Parse(productIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductHandler::GetProduct -> Invalid product ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::GetProduct")
return
}
productResponse := h.productService.GetProductByID(ctx, productID)
if productResponse.HasErrors() {
errorResp := productResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::GetProduct -> Failed to get product from service")
}
util.HandleResponse(c.Writer, c.Request, productResponse, "ProductHandler::GetProduct")
}
func (h *ProductHandler) ListProducts(c *gin.Context) {
ctx := c.Request.Context()
req := &contract.ListProductsRequest{
Page: 1,
Limit: 10,
}
// Parse query parameters
if pageStr := c.Query("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil {
req.Page = page
}
}
if limitStr := c.Query("limit"); limitStr != "" {
if limit, err := strconv.Atoi(limitStr); err == nil {
req.Limit = limit
}
}
if search := c.Query("search"); search != "" {
req.Search = search
}
if businessType := c.Query("business_type"); businessType != "" {
req.BusinessType = businessType
}
if organizationIDStr := c.Query("organization_id"); organizationIDStr != "" {
if organizationID, err := uuid.Parse(organizationIDStr); err == nil {
req.OrganizationID = &organizationID
}
}
if categoryIDStr := c.Query("category_id"); categoryIDStr != "" {
if categoryID, err := uuid.Parse(categoryIDStr); err == nil {
req.CategoryID = &categoryID
}
}
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
req.IsActive = &isActive
}
}
if minPriceStr := c.Query("min_price"); minPriceStr != "" {
if minPrice, err := strconv.ParseFloat(minPriceStr, 64); err == nil {
req.MinPrice = &minPrice
}
}
if maxPriceStr := c.Query("max_price"); maxPriceStr != "" {
if maxPrice, err := strconv.ParseFloat(maxPriceStr, 64); err == nil {
req.MaxPrice = &maxPrice
}
}
validationError, validationErrorCode := h.productValidator.ValidateListProductsRequest(req)
if validationError != nil {
logger.FromContext(ctx).WithError(validationError).Error("ProductHandler::ListProducts -> request validation failed")
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductHandler::ListProducts")
return
}
productsResponse := h.productService.ListProducts(ctx, req)
if productsResponse.HasErrors() {
errorResp := productsResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductHandler::ListProducts -> Failed to list products from service")
}
util.HandleResponse(c.Writer, c.Request, productsResponse, "ProductHandler::ListProducts")
}
+156
View File
@@ -0,0 +1,156 @@
package handler
import (
"apskel-pos-be/internal/appcontext"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/service"
"apskel-pos-be/internal/util"
"apskel-pos-be/internal/validator"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type ProductVariantHandler struct {
productVariantService service.ProductVariantService
productVariantValidator validator.ProductVariantValidator
}
func NewProductVariantHandler(
productVariantService service.ProductVariantService,
productVariantValidator validator.ProductVariantValidator,
) *ProductVariantHandler {
return &ProductVariantHandler{
productVariantService: productVariantService,
productVariantValidator: productVariantValidator,
}
}
func (h *ProductVariantHandler) CreateProductVariant(c *gin.Context) {
ctx := c.Request.Context()
contextInfo := appcontext.FromGinContext(ctx)
var req contract.CreateProductVariantRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("ProductVariantHandler::CreateProductVariant -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::CreateProductVariant")
return
}
validationError, validationErrorCode := h.productVariantValidator.ValidateCreateProductVariantRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::CreateProductVariant")
return
}
variantResponse := h.productVariantService.CreateProductVariant(ctx, contextInfo, &req)
if variantResponse.HasErrors() {
errorResp := variantResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductVariantHandler::CreateProductVariant -> Failed to create product variant from service")
}
util.HandleResponse(c.Writer, c.Request, variantResponse, "ProductVariantHandler::CreateProductVariant")
}
func (h *ProductVariantHandler) UpdateProductVariant(c *gin.Context) {
ctx := c.Request.Context()
variantIDStr := c.Param("id")
variantID, err := uuid.Parse(variantIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductVariantHandler::UpdateProductVariant -> Invalid variant ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid variant ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::UpdateProductVariant")
return
}
var req contract.UpdateProductVariantRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductVariantHandler::UpdateProductVariant -> request binding failed")
validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::UpdateProductVariant")
return
}
validationError, validationErrorCode := h.productVariantValidator.ValidateUpdateProductVariantRequest(&req)
if validationError != nil {
validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error())
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::UpdateProductVariant")
return
}
variantResponse := h.productVariantService.UpdateProductVariant(ctx, variantID, &req)
if variantResponse.HasErrors() {
errorResp := variantResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductVariantHandler::UpdateProductVariant -> Failed to update product variant from service")
}
util.HandleResponse(c.Writer, c.Request, variantResponse, "ProductVariantHandler::UpdateProductVariant")
}
func (h *ProductVariantHandler) DeleteProductVariant(c *gin.Context) {
ctx := c.Request.Context()
variantIDStr := c.Param("id")
variantID, err := uuid.Parse(variantIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductVariantHandler::DeleteProductVariant -> Invalid variant ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid variant ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::DeleteProductVariant")
return
}
variantResponse := h.productVariantService.DeleteProductVariant(ctx, variantID)
if variantResponse.HasErrors() {
errorResp := variantResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductVariantHandler::DeleteProductVariant -> Failed to delete product variant from service")
}
util.HandleResponse(c.Writer, c.Request, variantResponse, "ProductVariantHandler::DeleteProductVariant")
}
func (h *ProductVariantHandler) GetProductVariant(c *gin.Context) {
ctx := c.Request.Context()
variantIDStr := c.Param("id")
variantID, err := uuid.Parse(variantIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductVariantHandler::GetProductVariant -> Invalid variant ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid variant ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::GetProductVariant")
return
}
variantResponse := h.productVariantService.GetProductVariantByID(ctx, variantID)
if variantResponse.HasErrors() {
errorResp := variantResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductVariantHandler::GetProductVariant -> Failed to get product variant from service")
}
util.HandleResponse(c.Writer, c.Request, variantResponse, "ProductVariantHandler::GetProductVariant")
}
func (h *ProductVariantHandler) GetProductVariantsByProduct(c *gin.Context) {
ctx := c.Request.Context()
productIDStr := c.Param("product_id")
productID, err := uuid.Parse(productIDStr)
if err != nil {
logger.FromContext(ctx).WithError(err).Error("ProductVariantHandler::GetProductVariantsByProduct -> Invalid product ID")
validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid product ID")
util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "ProductVariantHandler::GetProductVariantsByProduct")
return
}
variantsResponse := h.productVariantService.GetProductVariantsByProductID(ctx, productID)
if variantsResponse.HasErrors() {
errorResp := variantsResponse.GetErrors()[0]
logger.FromContext(ctx).WithError(errorResp).Error("ProductVariantHandler::GetProductVariantsByProduct -> Failed to get product variants from service")
}
util.HandleResponse(c.Writer, c.Request, variantsResponse, "ProductVariantHandler::GetProductVariantsByProduct")
}
+319
View File
@@ -0,0 +1,319 @@
package handler
import (
"net/http"
"strconv"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/logger"
"apskel-pos-be/internal/transformer"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type UserHandler struct {
userService UserService
userValidator UserValidator
}
func NewUserHandler(userService UserService, userValidator UserValidator) *UserHandler {
return &UserHandler{
userService: userService,
userValidator: userValidator,
}
}
func (h *UserHandler) CreateUser(c *gin.Context) {
var req contract.CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::CreateUser -> request binding failed")
h.sendValidationErrorResponse(c, "Invalid request body", constants.MissingFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateCreateUserRequest(&req)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::CreateUser -> request validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
userResponse, err := h.userService.CreateUser(c.Request.Context(), &req)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::CreateUser -> Failed to create user from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Infof("UserHandler::CreateUser -> Successfully created user = %+v", userResponse)
c.JSON(http.StatusCreated, userResponse)
}
func (h *UserHandler) UpdateUser(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::UpdateUser -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::UpdateUser -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
var req contract.UpdateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::UpdateUser -> request binding failed")
h.sendValidationErrorResponse(c, "Invalid request body", constants.MissingFieldErrorCode)
return
}
validationError, validationErrorCode = h.userValidator.ValidateUpdateUserRequest(&req)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::UpdateUser -> request validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
userResponse, err := h.userService.UpdateUser(c.Request.Context(), userID, &req)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::UpdateUser -> Failed to update user from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Infof("UserHandler::UpdateUser -> Successfully updated user = %+v", userResponse)
c.JSON(http.StatusOK, userResponse)
}
func (h *UserHandler) DeleteUser(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::DeleteUser -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::DeleteUser -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
err = h.userService.DeleteUser(c.Request.Context(), userID)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::DeleteUser -> Failed to delete user from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Info("UserHandler::DeleteUser -> Successfully deleted user")
c.JSON(http.StatusOK, transformer.CreateSuccessResponse("User deleted successfully", nil))
}
func (h *UserHandler) GetUser(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::GetUser -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::GetUser -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
userResponse, err := h.userService.GetUserByID(c.Request.Context(), userID)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::GetUser -> Failed to get user from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Infof("UserHandler::GetUser -> Successfully retrieved user = %+v", userResponse)
c.JSON(http.StatusOK, userResponse)
}
func (h *UserHandler) ListUsers(c *gin.Context) {
req := &contract.ListUsersRequest{
Page: 1,
Limit: 10,
}
if page := c.Query("page"); page != "" {
if p, err := strconv.Atoi(page); err == nil {
req.Page = p
}
}
if limit := c.Query("limit"); limit != "" {
if l, err := strconv.Atoi(limit); err == nil {
req.Limit = l
}
}
if role := c.Query("role"); role != "" {
req.Role = &role
}
if outletIDStr := c.Query("outlet_id"); outletIDStr != "" {
if outletID, err := uuid.Parse(outletIDStr); err == nil {
req.OutletID = &outletID
}
}
if isActiveStr := c.Query("is_active"); isActiveStr != "" {
if isActive, err := strconv.ParseBool(isActiveStr); err == nil {
req.IsActive = &isActive
}
}
validationError, validationErrorCode := h.userValidator.ValidateListUsersRequest(req)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::ListUsers -> request validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
usersResponse, err := h.userService.ListUsers(c.Request.Context(), req)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::ListUsers -> Failed to list users from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Infof("UserHandler::ListUsers -> Successfully listed users = %+v", usersResponse)
c.JSON(http.StatusOK, contract.BuildSuccessResponse(usersResponse))
}
func (h *UserHandler) ChangePassword(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::ChangePassword -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::ChangePassword -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
var req contract.ChangePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::ChangePassword -> request binding failed")
h.sendValidationErrorResponse(c, "Invalid request body", constants.MissingFieldErrorCode)
return
}
validationError, validationErrorCode = h.userValidator.ValidateChangePasswordRequest(&req)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::ChangePassword -> request validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
err = h.userService.ChangePassword(c.Request.Context(), userID, &req)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::ChangePassword -> Failed to change password from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Info("UserHandler::ChangePassword -> Successfully changed password")
c.JSON(http.StatusOK, transformer.CreateSuccessResponse("Password changed successfully", nil))
}
func (h *UserHandler) ActivateUser(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::ActivateUser -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::ActivateUser -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
err = h.userService.ActivateUser(c.Request.Context(), userID)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::ActivateUser -> Failed to activate user from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Info("UserHandler::ActivateUser -> Successfully activated user")
c.JSON(http.StatusOK, transformer.CreateSuccessResponse("User activated successfully", nil))
}
func (h *UserHandler) DeactivateUser(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := uuid.Parse(userIDStr)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::DeactivateUser -> Invalid user ID")
h.sendValidationErrorResponse(c, "Invalid user ID", constants.MalformedFieldErrorCode)
return
}
validationError, validationErrorCode := h.userValidator.ValidateUserID(userID)
if validationError != nil {
logger.FromContext(c).WithError(validationError).Error("UserHandler::DeactivateUser -> user ID validation failed")
h.sendValidationErrorResponse(c, validationError.Error(), validationErrorCode)
return
}
err = h.userService.DeactivateUser(c.Request.Context(), userID)
if err != nil {
logger.FromContext(c).WithError(err).Error("UserHandler::DeactivateUser -> Failed to deactivate user from service")
h.sendErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
logger.FromContext(c).Info("UserHandler::DeactivateUser -> Successfully deactivated user")
c.JSON(http.StatusOK, transformer.CreateSuccessResponse("User deactivated successfully", nil))
}
func (h *UserHandler) sendErrorResponse(c *gin.Context, message string, statusCode int) {
errorResponse := &contract.ErrorResponse{
Error: message,
Code: statusCode,
Details: map[string]interface{}{},
}
c.JSON(statusCode, errorResponse)
}
func (h *UserHandler) sendValidationErrorResponse(c *gin.Context, message string, errorCode string) {
statusCode := constants.HttpErrorMap[errorCode]
if statusCode == 0 {
statusCode = http.StatusBadRequest
}
errorResponse := &contract.ErrorResponse{
Error: message,
Code: statusCode,
Details: map[string]interface{}{
"error_code": errorCode,
"entity": constants.UserValidatorEntity,
},
}
c.JSON(statusCode, errorResponse)
}
+19
View File
@@ -0,0 +1,19 @@
package handler
import (
"apskel-pos-be/internal/contract"
"context"
"github.com/google/uuid"
)
type UserService interface {
CreateUser(ctx context.Context, req *contract.CreateUserRequest) (*contract.UserResponse, error)
UpdateUser(ctx context.Context, id uuid.UUID, req *contract.UpdateUserRequest) (*contract.UserResponse, error)
DeleteUser(ctx context.Context, id uuid.UUID) error
GetUserByID(ctx context.Context, id uuid.UUID) (*contract.UserResponse, error)
GetUserByEmail(ctx context.Context, email string) (*contract.UserResponse, error)
ListUsers(ctx context.Context, req *contract.ListUsersRequest) (*contract.ListUsersResponse, error)
ChangePassword(ctx context.Context, userID uuid.UUID, req *contract.ChangePasswordRequest) error
ActivateUser(ctx context.Context, userID uuid.UUID) error
DeactivateUser(ctx context.Context, userID uuid.UUID) error
}
+14
View File
@@ -0,0 +1,14 @@
package handler
import (
"apskel-pos-be/internal/contract"
"github.com/google/uuid"
)
type UserValidator interface {
ValidateCreateUserRequest(req *contract.CreateUserRequest) (error, string)
ValidateUpdateUserRequest(req *contract.UpdateUserRequest) (error, string)
ValidateListUsersRequest(req *contract.ListUsersRequest) (error, string)
ValidateChangePasswordRequest(req *contract.ChangePasswordRequest) (error, string)
ValidateUserID(userID uuid.UUID) (error, string)
}