package handler import ( "strconv" "time" "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 CashAdvanceHandler struct { cashAdvanceService service.CashAdvanceService cashAdvanceValidator validator.CashAdvanceValidator } func NewCashAdvanceHandler(cashAdvanceService service.CashAdvanceService, cashAdvanceValidator validator.CashAdvanceValidator) *CashAdvanceHandler { return &CashAdvanceHandler{ cashAdvanceService: cashAdvanceService, cashAdvanceValidator: cashAdvanceValidator, } } func (h *CashAdvanceHandler) CreateCashAdvance(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) var req contract.CreateCashAdvanceRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(ctx).WithError(err).Error("CashAdvanceHandler::CreateCashAdvance -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, err.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::CreateCashAdvance") return } validationError, validationErrorCode := h.cashAdvanceValidator.ValidateCreateCashAdvanceRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::CreateCashAdvance") return } response := h.cashAdvanceService.CreateCashAdvance(ctx, contextInfo, &req) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::CreateCashAdvance -> Failed to create cash advance from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::CreateCashAdvance") } func (h *CashAdvanceHandler) UpdateCashAdvance(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) cashAdvanceID, err := uuid.Parse(c.Param("id")) if err != nil { logger.FromContext(ctx).WithError(err).Error("CashAdvanceHandler::UpdateCashAdvance -> Invalid cash advance ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid cash advance ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::UpdateCashAdvance") return } var req contract.UpdateCashAdvanceRequest if err := c.ShouldBindJSON(&req); err != nil { logger.FromContext(ctx).WithError(err).Error("CashAdvanceHandler::UpdateCashAdvance -> request binding failed") validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Invalid request body") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::UpdateCashAdvance") return } validationError, validationErrorCode := h.cashAdvanceValidator.ValidateUpdateCashAdvanceRequest(&req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::UpdateCashAdvance") return } response := h.cashAdvanceService.UpdateCashAdvance(ctx, contextInfo, cashAdvanceID, &req) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::UpdateCashAdvance -> Failed to update cash advance from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::UpdateCashAdvance") } func (h *CashAdvanceHandler) DeleteCashAdvance(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) cashAdvanceID, err := uuid.Parse(c.Param("id")) if err != nil { logger.FromContext(ctx).WithError(err).Error("CashAdvanceHandler::DeleteCashAdvance -> Invalid cash advance ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid cash advance ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::DeleteCashAdvance") return } response := h.cashAdvanceService.DeleteCashAdvance(ctx, contextInfo, cashAdvanceID) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::DeleteCashAdvance -> Failed to delete cash advance from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::DeleteCashAdvance") } func (h *CashAdvanceHandler) GetCashAdvance(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) cashAdvanceID, err := uuid.Parse(c.Param("id")) if err != nil { logger.FromContext(ctx).WithError(err).Error("CashAdvanceHandler::GetCashAdvance -> Invalid cash advance ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid cash advance ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::GetCashAdvance") return } response := h.cashAdvanceService.GetCashAdvanceByID(ctx, contextInfo, cashAdvanceID) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::GetCashAdvance -> Failed to get cash advance from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::GetCashAdvance") } func (h *CashAdvanceHandler) ListCashAdvances(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) req := &contract.ListCashAdvancesRequest{ Page: 1, Limit: 10, } 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.Status = c.Query("status") req.SettlementStatus = c.Query("settlement_status") req.Team = c.Query("team") req.TeamScope = c.Query("team_scope") if teamCategoryIDStr := c.Query("team_category_id"); teamCategoryIDStr != "" { if teamCategoryID, err := uuid.Parse(teamCategoryIDStr); err == nil { req.TeamCategoryID = &teamCategoryID } } if startDateStr := c.Query("start_date"); startDateStr != "" { if startDate, err := time.Parse("2006-01-02", startDateStr); err == nil { req.StartDate = &startDate } } if endDateStr := c.Query("end_date"); endDateStr != "" { if endDate, err := time.Parse("2006-01-02", endDateStr); err == nil { req.EndDate = &endDate } } validationError, validationErrorCode := h.cashAdvanceValidator.ValidateListCashAdvancesRequest(req) if validationError != nil { validationResponseError := contract.NewResponseError(validationErrorCode, constants.RequestEntity, validationError.Error()) util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::ListCashAdvances") return } response := h.cashAdvanceService.ListCashAdvances(ctx, contextInfo, req) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::ListCashAdvances -> Failed to list cash advances from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::ListCashAdvances") } func (h *CashAdvanceHandler) UpdateCashAdvanceStatus(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) cashAdvanceID, err := uuid.Parse(c.Param("id")) if err != nil { logger.FromContext(ctx).WithError(err).Error("CashAdvanceHandler::UpdateCashAdvanceStatus -> Invalid cash advance ID") validationResponseError := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "Invalid cash advance ID") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::UpdateCashAdvanceStatus") return } status := c.Param("status") if status == "" { validationResponseError := contract.NewResponseError(constants.MissingFieldErrorCode, constants.RequestEntity, "Status parameter is required") util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{validationResponseError}), "CashAdvanceHandler::UpdateCashAdvanceStatus") return } response := h.cashAdvanceService.UpdateCashAdvanceStatus(ctx, contextInfo, cashAdvanceID, status) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::UpdateCashAdvanceStatus -> Failed to update cash advance status from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::UpdateCashAdvanceStatus") } // ListCashAdvanceTeams serves the team picker for the advance form: the parent // categories of the caller's outlet, plus Pusat. Same list the purchase form uses. func (h *CashAdvanceHandler) ListCashAdvanceTeams(c *gin.Context) { ctx := c.Request.Context() contextInfo := appcontext.FromGinContext(ctx) response := h.cashAdvanceService.ListCashAdvanceTeams(ctx, contextInfo) if response.HasErrors() { logger.FromContext(ctx).WithError(response.GetErrors()[0]).Error("CashAdvanceHandler::ListCashAdvanceTeams -> Failed to list cash advance teams from service") } util.HandleResponse(c.Writer, c.Request, response, "CashAdvanceHandler::ListCashAdvanceTeams") }