ledger accounts improvement

This commit is contained in:
Stephan D
2026-01-30 15:54:45 +01:00
parent 51f5b0804a
commit 17dde423f6
40 changed files with 3355 additions and 570 deletions

View File

@@ -8,9 +8,9 @@ import (
"github.com/tech/sendico/ledger/storage"
"github.com/tech/sendico/ledger/storage/model"
storageMongo "github.com/tech/sendico/ledger/storage/mongo"
"github.com/tech/sendico/pkg/api/routers/gsresponse"
"github.com/tech/sendico/pkg/merrors"
pmodel "github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/mutil/mzap"
ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1"
"go.mongodb.org/mongo-driver/bson/primitive"
@@ -28,8 +28,18 @@ func (s *Service) postCreditResponder(_ context.Context, req *ledgerv1.PostCredi
if req.OrganizationRef == "" {
return nil, merrors.InvalidArgument("organization_ref is required")
}
if req.LedgerAccountRef == "" {
return nil, merrors.InvalidArgument("ledger_account_ref is required")
roleModel := pmodel.AccountRole("")
if req.Role != ledgerv1.AccountRole_ACCOUNT_ROLE_UNSPECIFIED {
var err error
roleModel, err = protoAccountRoleToModel(req.Role)
if err != nil {
return nil, err
}
} else if strings.TrimSpace(req.LedgerAccountRef) == "" {
roleModel = pmodel.AccountRoleOperating
}
if strings.TrimSpace(req.LedgerAccountRef) == "" && roleModel == "" {
return nil, merrors.InvalidArgument("ledger_account_ref or role is required")
}
if err := validateMoney(req.Money, "money"); err != nil {
return nil, err
@@ -39,16 +49,15 @@ func (s *Service) postCreditResponder(_ context.Context, req *ledgerv1.PostCredi
if err != nil {
return nil, err
}
accountRef, err := parseObjectID(req.LedgerAccountRef)
if err != nil {
return nil, err
}
logger := s.logger.With(
zap.String("idempotency_key", req.IdempotencyKey),
mzap.ObjRef("organization_ref", orgRef),
mzap.ObjRef("ledger_account_ref", accountRef),
zap.String("ledger_account_ref", strings.TrimSpace(req.LedgerAccountRef)),
zap.String("currency", req.Money.Currency),
)
if roleModel != "" {
logger = logger.With(zap.String("role", string(roleModel)))
}
if strings.TrimSpace(req.ContraLedgerAccountRef) != "" {
logger = logger.With(zap.String("contra_ledger_account_ref", strings.TrimSpace(req.ContraLedgerAccountRef)))
}
@@ -70,22 +79,17 @@ func (s *Service) postCreditResponder(_ context.Context, req *ledgerv1.PostCredi
return nil, merrors.Internal("failed to check idempotency")
}
account, err := s.storage.Accounts().Get(ctx, accountRef)
account, accountRef, err := s.resolveAccount(ctx, strings.TrimSpace(req.LedgerAccountRef), roleModel, orgRef, req.Money.Currency, "account")
if err != nil {
if err == storage.ErrAccountNotFound {
recordJournalEntryError("credit", "account_not_found")
return nil, merrors.NoData("account not found")
}
recordJournalEntryError("credit", "account_lookup_failed")
logger.Warn("failed to get account", zap.Error(err))
return nil, merrors.Internal("failed to get account")
recordJournalEntryError("credit", "account_resolve_failed")
return nil, err
}
if err := validateAccountForOrg(account, orgRef, req.Money.Currency); err != nil {
recordJournalEntryError("credit", "account_invalid")
return nil, err
}
accountsByRef := map[primitive.ObjectID]*model.Account{accountRef: account}
accountsByRef := map[primitive.ObjectID]*pmodel.LedgerAccount{accountRef: account}
eventTime := getEventTime(req.EventTime)
creditAmount, _ := parseDecimal(req.Money.Amount)
@@ -182,12 +186,7 @@ func (s *Service) postCreditResponder(_ context.Context, req *ledgerv1.PostCredi
return nil, merrors.Internal("failed to balance journal entry")
}
mongoStore, ok := s.storage.(*storageMongo.Store)
if !ok {
return nil, merrors.Internal("storage does not support transactions")
}
result, err := mongoStore.TransactionFactory().CreateTransaction().Execute(ctx, func(txCtx context.Context) (any, error) {
result, err := s.executeTransaction(ctx, func(txCtx context.Context) (any, error) {
entry := &model.JournalEntry{
IdempotencyKey: req.IdempotencyKey,
EventTime: eventTime,