169 lines
5.0 KiB
Go
169 lines
5.0 KiB
Go
package ledger
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/tech/sendico/ledger/storage"
|
|
"github.com/tech/sendico/ledger/storage/model"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
|
|
)
|
|
|
|
type accountStoreStub struct {
|
|
createErr error
|
|
created []*model.Account
|
|
existing *model.Account
|
|
existingErr error
|
|
}
|
|
|
|
func (s *accountStoreStub) Create(_ context.Context, account *model.Account) error {
|
|
if s.createErr != nil {
|
|
return s.createErr
|
|
}
|
|
if account.GetID() == nil || account.GetID().IsZero() {
|
|
account.SetID(primitive.NewObjectID())
|
|
}
|
|
account.CreatedAt = account.CreatedAt.UTC()
|
|
account.UpdatedAt = account.UpdatedAt.UTC()
|
|
s.created = append(s.created, account)
|
|
return nil
|
|
}
|
|
|
|
func (s *accountStoreStub) GetByAccountCode(_ context.Context, _ primitive.ObjectID, _ string, _ string) (*model.Account, error) {
|
|
if s.existingErr != nil {
|
|
return nil, s.existingErr
|
|
}
|
|
return s.existing, nil
|
|
}
|
|
|
|
func (s *accountStoreStub) Get(context.Context, primitive.ObjectID) (*model.Account, error) {
|
|
return nil, storage.ErrAccountNotFound
|
|
}
|
|
|
|
func (s *accountStoreStub) GetDefaultSettlement(context.Context, primitive.ObjectID, string) (*model.Account, error) {
|
|
return nil, storage.ErrAccountNotFound
|
|
}
|
|
|
|
func (s *accountStoreStub) ListByOrganization(context.Context, primitive.ObjectID, int, int) ([]*model.Account, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (s *accountStoreStub) UpdateStatus(context.Context, primitive.ObjectID, model.AccountStatus) error {
|
|
return nil
|
|
}
|
|
|
|
type repositoryStub struct {
|
|
accounts storage.AccountsStore
|
|
}
|
|
|
|
func (r *repositoryStub) Ping(context.Context) error { return nil }
|
|
func (r *repositoryStub) Accounts() storage.AccountsStore { return r.accounts }
|
|
func (r *repositoryStub) JournalEntries() storage.JournalEntriesStore { return nil }
|
|
func (r *repositoryStub) PostingLines() storage.PostingLinesStore { return nil }
|
|
func (r *repositoryStub) Balances() storage.BalancesStore { return nil }
|
|
func (r *repositoryStub) Outbox() storage.OutboxStore { return nil }
|
|
|
|
func TestCreateAccountResponder_Success(t *testing.T) {
|
|
t.Parallel()
|
|
orgRef := primitive.NewObjectID()
|
|
|
|
accountStore := &accountStoreStub{}
|
|
svc := &Service{
|
|
logger: zap.NewNop(),
|
|
storage: &repositoryStub{accounts: accountStore},
|
|
}
|
|
|
|
req := &ledgerv1.CreateAccountRequest{
|
|
OrganizationRef: orgRef.Hex(),
|
|
AccountCode: "asset:cash:main",
|
|
AccountType: ledgerv1.AccountType_ACCOUNT_TYPE_ASSET,
|
|
Currency: "usd",
|
|
AllowNegative: false,
|
|
IsSettlement: true,
|
|
Metadata: map[string]string{"purpose": "primary"},
|
|
}
|
|
|
|
resp, err := svc.createAccountResponder(context.Background(), req)(context.Background())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp)
|
|
require.NotNil(t, resp.Account)
|
|
|
|
require.Equal(t, "asset:cash:main", resp.Account.AccountCode)
|
|
require.Equal(t, ledgerv1.AccountType_ACCOUNT_TYPE_ASSET, resp.Account.AccountType)
|
|
require.Equal(t, "USD", resp.Account.Currency)
|
|
require.True(t, resp.Account.IsSettlement)
|
|
require.Contains(t, resp.Account.Metadata, "purpose")
|
|
require.NotEmpty(t, resp.Account.LedgerAccountRef)
|
|
|
|
require.Len(t, accountStore.created, 1)
|
|
}
|
|
|
|
func TestCreateAccountResponder_DuplicateReturnsExisting(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
orgRef := primitive.NewObjectID()
|
|
existing := &model.Account{
|
|
AccountCode: "asset:cash:main",
|
|
Currency: "USD",
|
|
AccountType: model.AccountTypeAsset,
|
|
Status: model.AccountStatusActive,
|
|
AllowNegative: false,
|
|
IsSettlement: true,
|
|
Metadata: map[string]string{"purpose": "existing"},
|
|
}
|
|
existing.OrganizationRef = orgRef
|
|
existing.SetID(primitive.NewObjectID())
|
|
existing.CreatedAt = time.Now().Add(-time.Hour).UTC()
|
|
existing.UpdatedAt = time.Now().UTC()
|
|
|
|
accountStore := &accountStoreStub{
|
|
createErr: merrors.DataConflict("duplicate"),
|
|
existing: existing,
|
|
existingErr: nil,
|
|
}
|
|
|
|
svc := &Service{
|
|
logger: zap.NewNop(),
|
|
storage: &repositoryStub{accounts: accountStore},
|
|
}
|
|
|
|
req := &ledgerv1.CreateAccountRequest{
|
|
OrganizationRef: orgRef.Hex(),
|
|
AccountCode: "asset:cash:main",
|
|
AccountType: ledgerv1.AccountType_ACCOUNT_TYPE_ASSET,
|
|
Currency: "usd",
|
|
}
|
|
|
|
resp, err := svc.createAccountResponder(context.Background(), req)(context.Background())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp)
|
|
require.NotNil(t, resp.Account)
|
|
|
|
require.Equal(t, existing.GetID().Hex(), resp.Account.LedgerAccountRef)
|
|
require.Equal(t, existing.Metadata["purpose"], resp.Account.Metadata["purpose"])
|
|
}
|
|
|
|
func TestCreateAccountResponder_InvalidAccountType(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := &Service{
|
|
logger: zap.NewNop(),
|
|
storage: &repositoryStub{accounts: &accountStoreStub{}},
|
|
}
|
|
|
|
req := &ledgerv1.CreateAccountRequest{
|
|
OrganizationRef: primitive.NewObjectID().Hex(),
|
|
AccountCode: "asset:cash:main",
|
|
Currency: "USD",
|
|
}
|
|
|
|
_, err := svc.createAccountResponder(context.Background(), req)(context.Background())
|
|
require.Error(t, err)
|
|
}
|