feat: cash advance
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"apskel-pos-be/internal/appcontext"
|
||||
"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 CashAdvanceService interface {
|
||||
CreateCashAdvance(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateCashAdvanceRequest) *contract.Response
|
||||
UpdateCashAdvance(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateCashAdvanceRequest) *contract.Response
|
||||
DeleteCashAdvance(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
|
||||
GetCashAdvanceByID(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response
|
||||
ListCashAdvances(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListCashAdvancesRequest) *contract.Response
|
||||
UpdateCashAdvanceStatus(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, status string) *contract.Response
|
||||
ListCashAdvanceTeams(ctx context.Context, apctx *appcontext.ContextInfo) *contract.Response
|
||||
}
|
||||
|
||||
type CashAdvanceServiceImpl struct {
|
||||
cashAdvanceProcessor processor.CashAdvanceProcessor
|
||||
}
|
||||
|
||||
func NewCashAdvanceService(cashAdvanceProcessor processor.CashAdvanceProcessor) *CashAdvanceServiceImpl {
|
||||
return &CashAdvanceServiceImpl{cashAdvanceProcessor: cashAdvanceProcessor}
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) CreateCashAdvance(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.CreateCashAdvanceRequest) *contract.Response {
|
||||
modelReq, err := transformer.CreateCashAdvanceRequestToModel(req)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.CashAdvanceServiceEntity, "Invalid date format. Use YYYY-MM-DD format")
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
cashAdvance, err := s.cashAdvanceProcessor.CreateCashAdvance(ctx, apctx.OrganizationID, outletFromContext(apctx), modelReq)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(transformer.CashAdvanceModelResponseToResponse(cashAdvance))
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) UpdateCashAdvance(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, req *contract.UpdateCashAdvanceRequest) *contract.Response {
|
||||
modelReq, err := transformer.UpdateCashAdvanceRequestToModel(req)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.MalformedFieldErrorCode, constants.CashAdvanceServiceEntity, "Invalid date format. Use YYYY-MM-DD format")
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
cashAdvance, err := s.cashAdvanceProcessor.UpdateCashAdvance(ctx, id, apctx.OrganizationID, modelReq)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(transformer.CashAdvanceModelResponseToResponse(cashAdvance))
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) DeleteCashAdvance(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
|
||||
if err := s.cashAdvanceProcessor.DeleteCashAdvance(ctx, id, apctx.OrganizationID); err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(map[string]interface{}{
|
||||
"message": "Cash advance deleted successfully",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) GetCashAdvanceByID(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID) *contract.Response {
|
||||
cashAdvance, err := s.cashAdvanceProcessor.GetCashAdvanceByID(ctx, id, apctx.OrganizationID)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(transformer.CashAdvanceModelResponseToResponse(cashAdvance))
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) ListCashAdvances(ctx context.Context, apctx *appcontext.ContextInfo, req *contract.ListCashAdvancesRequest) *contract.Response {
|
||||
modelReq := transformer.ListCashAdvancesRequestToModel(req)
|
||||
|
||||
filters := make(map[string]interface{})
|
||||
if modelReq.Search != "" {
|
||||
filters["search"] = modelReq.Search
|
||||
}
|
||||
if modelReq.Status != "" {
|
||||
filters["status"] = modelReq.Status
|
||||
}
|
||||
if modelReq.SettlementStatus != "" {
|
||||
filters["settlement_status"] = modelReq.SettlementStatus
|
||||
}
|
||||
if modelReq.TeamScope != "" {
|
||||
filters["team_scope"] = modelReq.TeamScope
|
||||
}
|
||||
if modelReq.TeamCategoryID != nil {
|
||||
filters["team_category_id"] = *modelReq.TeamCategoryID
|
||||
}
|
||||
// team spells out the same two filters in one value; the validator has already
|
||||
// ruled out sending it together with them.
|
||||
switch modelReq.Team {
|
||||
case "":
|
||||
case constants.PurchaseTeamScopeCentral:
|
||||
filters["team_scope"] = constants.PurchaseTeamScopeCentral
|
||||
default:
|
||||
if teamCategoryID, err := uuid.Parse(modelReq.Team); err == nil {
|
||||
filters["team_scope"] = constants.PurchaseTeamScopeCategory
|
||||
filters["team_category_id"] = teamCategoryID
|
||||
}
|
||||
}
|
||||
if modelReq.StartDate != nil {
|
||||
filters["start_date"] = *modelReq.StartDate
|
||||
}
|
||||
if modelReq.EndDate != nil {
|
||||
filters["end_date"] = *modelReq.EndDate
|
||||
}
|
||||
// Cash belongs to the drawer it came out of, so a user signed in to one outlet
|
||||
// only sees that outlet's cash advances.
|
||||
if outletID := outletFromContext(apctx); outletID != nil {
|
||||
filters["outlet_id"] = *outletID
|
||||
}
|
||||
|
||||
cashAdvances, totalPages, err := s.cashAdvanceProcessor.ListCashAdvances(ctx, apctx.OrganizationID, filters, modelReq.Page, modelReq.Limit)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
responses := make([]contract.CashAdvanceResponse, len(cashAdvances))
|
||||
for i, cashAdvance := range cashAdvances {
|
||||
if response := transformer.CashAdvanceModelResponseToResponse(cashAdvance); response != nil {
|
||||
responses[i] = *response
|
||||
}
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(contract.ListCashAdvancesResponse{
|
||||
CashAdvances: responses,
|
||||
TotalCount: len(responses),
|
||||
Page: modelReq.Page,
|
||||
Limit: modelReq.Limit,
|
||||
TotalPages: totalPages,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) UpdateCashAdvanceStatus(ctx context.Context, apctx *appcontext.ContextInfo, id uuid.UUID, status string) *contract.Response {
|
||||
cashAdvance, err := s.cashAdvanceProcessor.UpdateCashAdvanceStatus(ctx, id, apctx.OrganizationID, status)
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(transformer.CashAdvanceModelResponseToResponse(cashAdvance))
|
||||
}
|
||||
|
||||
func (s *CashAdvanceServiceImpl) ListCashAdvanceTeams(ctx context.Context, apctx *appcontext.ContextInfo) *contract.Response {
|
||||
teams, err := s.cashAdvanceProcessor.ListCashAdvanceTeams(ctx, apctx.OrganizationID, outletFromContext(apctx))
|
||||
if err != nil {
|
||||
errorResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.CashAdvanceServiceEntity, err.Error())
|
||||
return contract.BuildErrorResponse([]*contract.ResponseError{errorResp})
|
||||
}
|
||||
|
||||
return contract.BuildSuccessResponse(transformer.ListPurchaseTeamsModelResponseToResponse(teams))
|
||||
}
|
||||
|
||||
// outletFromContext reads the caller's outlet as an optional value: an organization
|
||||
// level user has none, and uuid.Nil is how that arrives on the context.
|
||||
func outletFromContext(apctx *appcontext.ContextInfo) *uuid.UUID {
|
||||
if apctx.OutletID == uuid.Nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
outletID := apctx.OutletID
|
||||
return &outletID
|
||||
}
|
||||
Reference in New Issue
Block a user