package service import ( "context" "errors" "financeiro-carvalho/internal/model" "financeiro-carvalho/internal/repository" ) var ( ErrAccountEmptyName = errors.New("account name cannot be empty") ErrAccountInvalidType = errors.New("account type must be checking, savings, investment, or credit") ) var validAccountTypes = map[string]bool{ "checking": true, "savings": true, "investment": true, "credit": true, } type AccountRepo interface { List(ctx context.Context) ([]model.Account, error) GetByID(ctx context.Context, id int) (*model.Account, error) Create(ctx context.Context, in model.AccountInput) (*model.Account, error) Update(ctx context.Context, id int, in model.AccountInput) (*model.Account, error) Delete(ctx context.Context, id int) error TotalPatrimony(ctx context.Context) (float64, error) } type AccountService struct { repo repository.AccountRepoWithYield cdiSvc *CDIYieldService billSvc *CreditBillService } func NewAccountService(repo repository.AccountRepoWithYield, cdiSvc *CDIYieldService, billSvc *CreditBillService) *AccountService { return &AccountService{repo: repo, cdiSvc: cdiSvc, billSvc: billSvc} } func (s *AccountService) validate(in model.AccountInput) error { if in.Name == "" { return ErrAccountEmptyName } if !validAccountTypes[in.Type] { return ErrAccountInvalidType } return nil } // List returns accounts, applying CDI yield on-demand and attaching current bill for credit accounts. func (s *AccountService) List(ctx context.Context) ([]model.Account, error) { accounts, err := s.repo.List(ctx) if err != nil { return nil, err } yieldApplied := false for i := range accounts { if accounts[i].YieldType == "cdi" { _ = s.cdiSvc.ApplyYield(ctx, &accounts[i]) yieldApplied = true } } if yieldApplied { accounts, err = s.repo.List(ctx) if err != nil { return nil, err } } for i := range accounts { if accounts[i].Type == "credit" { closing, due := 1, 10 if accounts[i].ClosingDay != nil { closing = *accounts[i].ClosingDay } if accounts[i].DueDay != nil { due = *accounts[i].DueDay } _ = s.billSvc.EnsureCurrentBill(ctx, accounts[i].ID, closing, due) bill, _ := s.billSvc.GetCurrent(ctx, accounts[i].ID) accounts[i].CurrentBill = bill } } return accounts, nil } func (s *AccountService) Create(ctx context.Context, in model.AccountInput) (*model.Account, error) { if err := s.validate(in); err != nil { return nil, err } return s.repo.Create(ctx, in) } func (s *AccountService) Update(ctx context.Context, id int, in model.AccountInput) (*model.Account, error) { if err := s.validate(in); err != nil { return nil, err } return s.repo.Update(ctx, id, in) } func (s *AccountService) Delete(ctx context.Context, id int) error { return s.repo.Delete(ctx, id) } func (s *AccountService) TotalPatrimony(ctx context.Context) (float64, error) { return s.repo.TotalPatrimony(ctx) }