From b8e034d8d8fdf95c5bbcbfefa73b28bc79d79c8a Mon Sep 17 00:00:00 2001 From: "aditya.siregar" Date: Tue, 30 Jul 2024 23:51:53 +0700 Subject: [PATCH] Add Balance Api --- internal/common/mycontext/kinoscontext.go | 5 + internal/entity/balance.go | 7 + internal/entity/wallet.go | 15 +- internal/handlers/http/balance/branch.go | 56 +++++ internal/handlers/http/branch/branch.go | 264 ---------------------- internal/handlers/response/branch.go | 18 +- internal/repository/wallet/wallet.go | 4 + internal/routes/routes.go | 4 +- internal/services/balance/balance.go | 34 +++ internal/services/service.go | 7 + 10 files changed, 127 insertions(+), 287 deletions(-) create mode 100644 internal/entity/balance.go create mode 100644 internal/handlers/http/balance/branch.go delete mode 100644 internal/handlers/http/branch/branch.go create mode 100644 internal/services/balance/balance.go diff --git a/internal/common/mycontext/kinoscontext.go b/internal/common/mycontext/kinoscontext.go index f0fb057..eef7787 100644 --- a/internal/common/mycontext/kinoscontext.go +++ b/internal/common/mycontext/kinoscontext.go @@ -14,6 +14,7 @@ type Context interface { RequestedBy() int64 IsSuperAdmin() bool IsAdmin() bool + IsPartnerAdmin() bool IsCasheer() bool GetPartnerID() *int64 GetSiteID() *int64 @@ -41,6 +42,10 @@ func (m *MyContextImpl) IsAdmin() bool { return m.roleID == int(role.SuperAdmin) || m.roleID == int(role.Admin) } +func (m *MyContextImpl) IsPartnerAdmin() bool { + return m.roleID == int(role.PartnerAdmin) +} + func (m *MyContextImpl) IsCasheer() bool { return m.roleID == int(role.Casheer) } diff --git a/internal/entity/balance.go b/internal/entity/balance.go new file mode 100644 index 0000000..980e935 --- /dev/null +++ b/internal/entity/balance.go @@ -0,0 +1,7 @@ +package entity + +type Balance struct { + PartnerID int64 + Balance float64 + AuthBalance float64 +} diff --git a/internal/entity/wallet.go b/internal/entity/wallet.go index 214428a..55d7876 100644 --- a/internal/entity/wallet.go +++ b/internal/entity/wallet.go @@ -3,13 +3,14 @@ package entity import "time" type Wallet struct { - ID int64 `gorm:"primaryKey;autoIncrement;column:id"` - PartnerID int64 `gorm:"type:int;not null;column:partner_id"` - Balance float64 `gorm:"type:decimal(18,2);not null;default:0.00;column:balance"` - Currency string `gorm:"type:varchar(3);not null;column:currency"` - Status string `gorm:"type:varchar(50);column:status"` - CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"` - UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"` + ID int64 `gorm:"primaryKey;autoIncrement;column:id"` + PartnerID int64 `gorm:"type:int;not null;column:partner_id"` + Balance float64 `gorm:"type:decimal(18,2);not null;default:0.00;column:balance"` + AuthBalance float64 `gorm:"type:decimal(18,2);not null;default:0.00;column:auth_balance"` + Currency string `gorm:"type:varchar(3);not null;column:currency"` + Status string `gorm:"type:varchar(50);column:status"` + CreatedAt time.Time `gorm:"autoCreateTime;column:created_at"` + UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at"` } func (Wallet) TableName() string { diff --git a/internal/handlers/http/balance/branch.go b/internal/handlers/http/balance/branch.go new file mode 100644 index 0000000..e27175d --- /dev/null +++ b/internal/handlers/http/balance/branch.go @@ -0,0 +1,56 @@ +package balance + +import ( + "furtuna-be/internal/common/errors" + "furtuna-be/internal/entity" + "furtuna-be/internal/handlers/request" + "furtuna-be/internal/handlers/response" + "furtuna-be/internal/services" + "github.com/gin-gonic/gin" + "net/http" +) + +type Handler struct { + service services.Balance +} + +func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) { + route := group.Group("/balance") + + route.GET("/partner", jwt, h.GetPartnerBalance) +} + +func NewHandler(service services.Balance) *Handler { + return &Handler{ + service: service, + } +} + +func (h *Handler) GetPartnerBalance(c *gin.Context) { + ctx := request.GetMyContext(c) + + if !ctx.IsPartnerAdmin() { + response.ErrorWrapper(c, errors.ErrorBadRequest) + return + } + + updatedBranch, err := h.service.GetByID(ctx, *ctx.GetPartnerID()) + if err != nil { + response.ErrorWrapper(c, err) + return + } + + c.JSON(http.StatusOK, response.BaseResponse{ + Success: true, + Status: http.StatusOK, + Data: h.toBalanceResponse(updatedBranch), + }) +} + +func (h *Handler) toBalanceResponse(resp *entity.Balance) response.Balance { + return response.Balance{ + PartnerID: resp.PartnerID, + Balance: resp.Balance, + AuthBalance: resp.AuthBalance, + } +} diff --git a/internal/handlers/http/branch/branch.go b/internal/handlers/http/branch/branch.go deleted file mode 100644 index bbfae6f..0000000 --- a/internal/handlers/http/branch/branch.go +++ /dev/null @@ -1,264 +0,0 @@ -package branch - -import ( - "furtuna-be/internal/common/errors" - "furtuna-be/internal/entity" - "furtuna-be/internal/handlers/request" - "furtuna-be/internal/handlers/response" - "furtuna-be/internal/services" - "net/http" - "strconv" - "time" - - "github.com/gin-gonic/gin" - "github.com/go-playground/validator/v10" -) - -type Handler struct { - service services.Branch -} - -func (h *Handler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) { - route := group.Group("/branch") - - route.POST("/", jwt, h.Create) - route.GET("/list", jwt, h.GetAll) - route.PUT("/:id", jwt, h.Update) - route.GET("/:id", jwt, h.GetByID) - route.DELETE("/:id", jwt, h.Delete) -} - -func NewHandler(service services.Branch) *Handler { - return &Handler{ - service: service, - } -} - -// Create handles the creation of a new branch. -// @Summary Create a new branch -// @Description Create a new branch based on the provided data. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param req body request.Branch true "New branch details" -// @Success 200 {object} response.BaseResponse{data=response.Branch} "Branch created successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Router /api/v1/branch [post] -// @Tags Branch APIs -func (h *Handler) Create(c *gin.Context) { - ctx := request.GetMyContext(c) - - var req request.Branch - if err := c.ShouldBindJSON(&req); err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - validate := validator.New() - if err := validate.Struct(req); err != nil { - response.ErrorWrapper(c, err) - return - } - - res, err := h.service.Create(ctx, req.ToEntity()) - - if err != nil { - response.ErrorWrapper(c, err) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toBranchResponse(res), - }) -} - -// Update handles the update of an existing branch. -// @Summary Update an existing branch -// @Description Update the details of an existing branch based on the provided ID. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param id path int64 true "Branch ID to update" -// @Param req body request.Branch true "Updated branch details" -// @Success 200 {object} response.BaseResponse{data=response.Branch} "Branch updated successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Router /api/v1/branch/{id} [put] -// @Tags Branch APIs -func (h *Handler) Update(c *gin.Context) { - ctx := request.GetMyContext(c) - - id := c.Param("id") - - branchID, err := strconv.ParseInt(id, 10, 64) - if err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - var req request.Branch - if err := c.ShouldBindJSON(&req); err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - validate := validator.New() - if err := validate.Struct(req); err != nil { - response.ErrorWrapper(c, err) - return - } - - updatedBranch, err := h.service.Update(ctx, branchID, req.ToEntity()) - if err != nil { - response.ErrorWrapper(c, err) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toBranchResponse(updatedBranch), - }) -} - -// GetAll retrieves a list of branches. -// @Summary Get a list of branches -// @Description Get a paginated list of branches based on query parameters. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param Limit query int false "Number of items to retrieve (default 10)" -// @Param Offset query int false "Offset for pagination (default 0)" -// @Success 200 {object} response.BaseResponse{data=response.BranchList} "List of branches" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Router /api/v1/branch/list [get] -// @Tags Branch APIs -func (h *Handler) GetAll(c *gin.Context) { - var req request.BranchParam - if err := c.ShouldBindQuery(&req); err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - branchs, total, err := h.service.GetAll(c.Request.Context(), req.ToEntity()) - if err != nil { - response.ErrorWrapper(c, err) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toBranchResponseList(branchs, int64(total), req), - }) -} - -// Delete handles the deletion of a branch by ID. -// @Summary Delete a branch by ID -// @Description Delete a branch based on the provided ID. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param id path int64 true "Branch ID to delete" -// @Success 200 {object} response.BaseResponse "Branch deleted successfully" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Router /api/v1/branch/{id} [delete] -// @Tags Branch APIs -func (h *Handler) Delete(c *gin.Context) { - ctx := request.GetMyContext(c) - id := c.Param("id") - - // Parse the ID into a uint - branchID, err := strconv.ParseInt(id, 10, 64) - if err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - err = h.service.Delete(ctx, branchID) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: nil, - }) -} - -// GetByID retrieves details of a specific branch by ID. -// @Summary Get details of a branch by ID -// @Description Get details of a branch based on the provided ID. -// @Accept json -// @Produce json -// @Param Authorization header string true "JWT token" -// @Param id path int64 true "Branch ID to retrieve" -// @Success 200 {object} response.BaseResponse{data=response.Branch} "Branch details" -// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request" -// @Failure 401 {object} response.BaseResponse{data=errors.Error} "Unauthorized" -// @Router /api/v1/branch/{id} [get] -// @Tags Branch APIs -func (h *Handler) GetByID(c *gin.Context) { - id := c.Param("id") - - // Parse the ID into a uint - branchID, err := strconv.ParseInt(id, 10, 64) - if err != nil { - response.ErrorWrapper(c, errors.ErrorBadRequest) - return - } - - res, err := h.service.GetByID(c.Request.Context(), branchID) - if err != nil { - c.JSON(http.StatusInternalServerError, response.BaseResponse{ - Success: false, - Status: http.StatusInternalServerError, - Message: err.Error(), - Data: nil, - }) - return - } - - c.JSON(http.StatusOK, response.BaseResponse{ - Success: true, - Status: http.StatusOK, - Data: h.toBranchResponse(res), - }) -} - -func (h *Handler) toBranchResponse(resp *entity.Branch) response.Branch { - return response.Branch{ - ID: &resp.ID, - Name: resp.Name, - Status: string(resp.Status), - Location: resp.Location, - CreatedAt: resp.CreatedAt.Format(time.RFC3339), - UpdatedAt: resp.CreatedAt.Format(time.RFC3339), - } -} - -func (h *Handler) toBranchResponseList(resp []*entity.Branch, total int64, req request.BranchParam) response.BranchList { - var branches []response.Branch - for _, b := range resp { - branches = append(branches, h.toBranchResponse(b)) - } - - return response.BranchList{ - Branches: branches, - Total: total, - Limit: req.Limit, - Offset: req.Offset, - } -} diff --git a/internal/handlers/response/branch.go b/internal/handlers/response/branch.go index d90fbfd..03768b8 100644 --- a/internal/handlers/response/branch.go +++ b/internal/handlers/response/branch.go @@ -1,17 +1,7 @@ package response -type Branch struct { - ID *int64 `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - Location string `json:"location"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` -} - -type BranchList struct { - Branches []Branch `json:"branches"` - Total int64 `json:"total"` - Limit int `json:"limit"` - Offset int `json:"offset"` +type Balance struct { + PartnerID int64 `json:"partner_id"` + Balance float64 `json:"balance"` + AuthBalance float64 `json:"auth_balance"` } diff --git a/internal/repository/wallet/wallet.go b/internal/repository/wallet/wallet.go index df25945..c6315bd 100644 --- a/internal/repository/wallet/wallet.go +++ b/internal/repository/wallet/wallet.go @@ -37,6 +37,10 @@ func (r *WalletRepository) Update(ctx context.Context, db *gorm.DB, wallet *enti } func (r *WalletRepository) GetByPartnerID(ctx context.Context, db *gorm.DB, partnerID int64) (*entity.Wallet, error) { + if db == nil { + db = r.db + } + wallet := new(entity.Wallet) if err := db.WithContext(ctx).Where("partner_id = ?", partnerID).First(wallet).Error; err != nil { logger.ContextLogger(ctx).Error("error when finding wallet by partner ID", zap.Error(err)) diff --git a/internal/routes/routes.go b/internal/routes/routes.go index 6a8b95a..0190744 100644 --- a/internal/routes/routes.go +++ b/internal/routes/routes.go @@ -1,7 +1,7 @@ package routes import ( - "furtuna-be/internal/handlers/http/branch" + "furtuna-be/internal/handlers/http/balance" "furtuna-be/internal/handlers/http/license" mdtrns "furtuna-be/internal/handlers/http/midtrans" "furtuna-be/internal/handlers/http/order" @@ -50,7 +50,6 @@ func RegisterPrivateRoutes(app *app.Server, serviceManager *services.ServiceMana auth.NewAuthHandler(serviceManager.AuthSvc), event.NewHandler(serviceManager.EventSvc), user.NewHandler(serviceManager.UserSvc), - branch.NewHandler(serviceManager.BranchSvc), studio.NewStudioHandler(serviceManager.StudioSvc), product.NewHandler(serviceManager.ProductSvc), order.NewHandler(serviceManager.OrderSvc), @@ -60,6 +59,7 @@ func RegisterPrivateRoutes(app *app.Server, serviceManager *services.ServiceMana mdtrns.NewHandler(serviceManager.OrderSvc), license.NewHandler(serviceManager.LicenseSvc), transaction.New(serviceManager.Transaction), + balance.NewHandler(serviceManager.Balance), } for _, handler := range serverRoutes { diff --git a/internal/services/balance/balance.go b/internal/services/balance/balance.go new file mode 100644 index 0000000..c11c58a --- /dev/null +++ b/internal/services/balance/balance.go @@ -0,0 +1,34 @@ +package balance + +import ( + "context" + "furtuna-be/internal/common/logger" + "furtuna-be/internal/entity" + "furtuna-be/internal/repository" + + "go.uber.org/zap" +) + +type BalanceService struct { + repo repository.WalletRepository +} + +func NewBalanceService(repo repository.WalletRepository) *BalanceService { + return &BalanceService{ + repo: repo, + } +} + +func (s *BalanceService) GetByID(ctx context.Context, id int64) (*entity.Balance, error) { + balanceDB, err := s.repo.GetByPartnerID(ctx, nil, id) + if err != nil { + logger.ContextLogger(ctx).Error("error when get branch by id", zap.Error(err)) + return nil, err + } + + return &entity.Balance{ + PartnerID: id, + Balance: balanceDB.Balance, + AuthBalance: balanceDB.AuthBalance, + }, nil +} diff --git a/internal/services/service.go b/internal/services/service.go index af0881e..30924ab 100644 --- a/internal/services/service.go +++ b/internal/services/service.go @@ -3,6 +3,7 @@ package services import ( "context" "furtuna-be/internal/common/mycontext" + "furtuna-be/internal/services/balance" "furtuna-be/internal/services/branch" service "furtuna-be/internal/services/license" "furtuna-be/internal/services/order" @@ -36,6 +37,7 @@ type ServiceManagerImpl struct { SiteSvc Site LicenseSvc License Transaction Transaction + Balance Balance } func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) *ServiceManagerImpl { @@ -53,6 +55,7 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) SiteSvc: site.NewSiteService(repo.Site), LicenseSvc: service.NewLicenseService(repo.License), Transaction: transaction.New(repo.Transaction), + Balance: balance.NewBalanceService(repo.Wallet), } } @@ -144,3 +147,7 @@ type License interface { type Transaction interface { GetTransactionList(ctx mycontext.Context, req entity.TransactionSearch) ([]*entity.TransactionList, int, error) } + +type Balance interface { + GetByID(ctx context.Context, id int64) (*entity.Balance, error) +}