- Migration 010: colunas yield_type e last_yield_date em accounts + source='yield' nas transações
- CDIYieldService: busca taxas BCB (serie 12) e cria transação source=yield com rendimento acumulado
- Weekends/feriados sem taxa usam última taxa disponível (AC4)
- GET /api/accounts dispara cálculo CDI on-demand antes de retornar saldos
- AccountsView: seletor yield_type (none/cdi/variable) + badge CDI/VAR na listagem
- Transações source=yield aparecem no histórico com descrição 'Rendimento CDI — {período}'
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
76 lines
2.3 KiB
Go
76 lines
2.3 KiB
Go
package service_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"financeiro-carvalho/internal/model"
|
|
"financeiro-carvalho/internal/service"
|
|
)
|
|
|
|
type mockAccountRepo struct {
|
|
items []model.Account
|
|
}
|
|
|
|
func (m *mockAccountRepo) List(_ context.Context) ([]model.Account, error) { return m.items, nil }
|
|
func (m *mockAccountRepo) GetByID(_ context.Context, id int) (*model.Account, error) {
|
|
for _, a := range m.items {
|
|
if a.ID == id {
|
|
cp := a
|
|
return &cp, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
func (m *mockAccountRepo) Create(_ context.Context, in model.AccountInput) (*model.Account, error) {
|
|
a := model.Account{ID: len(m.items) + 1, Name: in.Name, Type: in.Type, InitialBalance: in.InitialBalance, Balance: in.InitialBalance}
|
|
m.items = append(m.items, a)
|
|
return &a, nil
|
|
}
|
|
func (m *mockAccountRepo) Update(_ context.Context, id int, in model.AccountInput) (*model.Account, error) {
|
|
for i, a := range m.items {
|
|
if a.ID == id {
|
|
m.items[i].Name = in.Name
|
|
cp := m.items[i]
|
|
return &cp, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
func (m *mockAccountRepo) Delete(_ context.Context, _ int) error { return nil }
|
|
func (m *mockAccountRepo) TotalPatrimony(_ context.Context) (float64, error) { return 0, nil }
|
|
func (m *mockAccountRepo) UpdateLastYieldDate(_ context.Context, _ int, _ string) error { return nil }
|
|
|
|
func newAccountSvc() *service.AccountService {
|
|
repo := &mockAccountRepo{}
|
|
cdiSvc := service.NewCDIYieldService(repo, &mockTxRepo{})
|
|
return service.NewAccountService(repo, cdiSvc)
|
|
}
|
|
|
|
func TestCreateAccount_EmptyName(t *testing.T) {
|
|
svc := newAccountSvc()
|
|
_, err := svc.Create(context.Background(), model.AccountInput{Name: "", Type: "checking", InitialBalance: 0})
|
|
if err != service.ErrAccountEmptyName {
|
|
t.Fatalf("expected ErrAccountEmptyName, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCreateAccount_InvalidType(t *testing.T) {
|
|
svc := newAccountSvc()
|
|
_, err := svc.Create(context.Background(), model.AccountInput{Name: "Nubank", Type: "bitcoin"})
|
|
if err != service.ErrAccountInvalidType {
|
|
t.Fatalf("expected ErrAccountInvalidType, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCreateAccount_OK(t *testing.T) {
|
|
svc := newAccountSvc()
|
|
a, err := svc.Create(context.Background(), model.AccountInput{Name: "Nubank", Type: "checking", InitialBalance: 1000})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a.Name != "Nubank" || a.Balance != 1000 {
|
|
t.Errorf("unexpected account: %+v", a)
|
|
}
|
|
}
|