2026-06-03 14:56:27 +07:00

151 lines
6.1 KiB
Go

package service
import (
"apskel-pos-be/internal/appcontext"
"context"
"time"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/processor"
"apskel-pos-be/internal/transformer"
"github.com/google/uuid"
)
type ExpenseService interface {
CreateExpense(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateExpenseRequest) *contract.Response
UpdateExpense(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateExpenseRequest) *contract.Response
DeleteExpense(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
GetExpenseByID(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
ListExpenses(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListExpenseRequest) *contract.Response
GetExpenseAnalytics(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ExpenseAnalyticsRequest) *contract.Response
}
type ExpenseServiceImpl struct {
expenseProcessor processor.ExpenseProcessor
}
func NewExpenseService(expenseProcessor processor.ExpenseProcessor) *ExpenseServiceImpl {
return &ExpenseServiceImpl{
expenseProcessor: expenseProcessor,
}
}
func (s *ExpenseServiceImpl) CreateExpense(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateExpenseRequest) *contract.Response {
modelReq := transformer.CreateExpenseRequestToModel(req)
expenseResponse, err := s.expenseProcessor.CreateExpense(ctx, apctx.OrganizationID, modelReq)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponse := transformer.ExpenseModelResponseToResponse(expenseResponse)
return contract.BuildSuccessResponse(contractResponse)
}
func (s *ExpenseServiceImpl) UpdateExpense(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateExpenseRequest) *contract.Response {
modelReq := transformer.UpdateExpenseRequestToModel(req)
expenseResponse, err := s.expenseProcessor.UpdateExpense(ctx, id, apctx.OrganizationID, modelReq)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponse := transformer.ExpenseModelResponseToResponse(expenseResponse)
return contract.BuildSuccessResponse(contractResponse)
}
func (s *ExpenseServiceImpl) DeleteExpense(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
err := s.expenseProcessor.DeleteExpense(ctx, id, apctx.OrganizationID)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
return contract.BuildSuccessResponse(map[string]interface{}{
"message": "Expense deleted successfully",
})
}
func (s *ExpenseServiceImpl) GetExpenseByID(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
expenseResponse, err := s.expenseProcessor.GetExpenseByID(ctx, id, apctx.OrganizationID)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponse := transformer.ExpenseModelResponseToResponse(expenseResponse)
return contract.BuildSuccessResponse(contractResponse)
}
func (s *ExpenseServiceImpl) ListExpenses(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListExpenseRequest) *contract.Response {
modelReq := transformer.ListExpenseRequestToModel(req)
filters := make(map[string]interface{})
if modelReq.Search != "" {
filters["search"] = modelReq.Search
}
if modelReq.Status != "" {
filters["status"] = modelReq.Status
}
if modelReq.OutletID != "" {
outletID, err := uuid.Parse(modelReq.OutletID)
if err == nil {
filters["outlet_id"] = outletID
}
}
if modelReq.StartDate != "" {
if startDate, err := time.Parse("2006-01-02", modelReq.StartDate); err == nil {
filters["start_date"] = startDate
}
}
if modelReq.EndDate != "" {
if endDate, err := time.Parse("2006-01-02", modelReq.EndDate); err == nil {
// include the full end date day
filters["end_date"] = endDate.Add(24*time.Hour - time.Nanosecond)
}
}
expenses, totalPages, err := s.expenseProcessor.ListExpenses(ctx, apctx.OrganizationID, filters, modelReq.Page, modelReq.Limit)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
contractResponses := transformer.ExpenseModelResponsesToResponses(expenses)
response := contract.ListExpenseResponse{
Expenses: contractResponses,
TotalCount: len(contractResponses),
Page: modelReq.Page,
Limit: modelReq.Limit,
TotalPages: totalPages,
}
return contract.BuildSuccessResponse(response)
}
func (s *ExpenseServiceImpl) GetExpenseAnalytics(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ExpenseAnalyticsRequest) *contract.Response {
modelReq, err := transformer.ExpenseAnalyticsRequestToModel(req)
if err != nil {
errorResp := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
modelReq.OrganizationID = apctx.OrganizationID
if apctx.OutletID != uuid.Nil {
modelReq.OutletID = &apctx.OutletID
}
response, err := s.expenseProcessor.GetExpenseAnalytics(ctx, modelReq)
if err != nil {
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.ExpenseServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
}
return contract.BuildSuccessResponse(transformer.ExpenseAnalyticsModelToContract(response))
}