Skip to content

Commit 0ca03d1

Browse files
authored
fix: set Transaction Envelope ID to nil if it is the zero UUID (#798)
When a Transaction is saved with a zero UUID for the Envelope, the backend now explicitly sets the Envelope ID to nil. This prevents errors when used in combination with the Transaction Preview since the Transaction Preview returns the zero UUID for income.
1 parent f2cce6f commit 0ca03d1

File tree

4 files changed

+44
-1
lines changed

4 files changed

+44
-1
lines changed

pkg/controllers/transaction.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/envelope-zero/backend/v3/pkg/httperrors"
88
"github.com/envelope-zero/backend/v3/pkg/models"
99
"github.com/gin-gonic/gin"
10+
"github.com/google/uuid"
1011
"github.com/shopspring/decimal"
1112
)
1213

@@ -95,7 +96,7 @@ func (co Controller) checkTransaction(c *gin.Context, transaction models.Transac
9596
}
9697

9798
// Check envelope being set for transfer between on-budget accounts
98-
if transaction.EnvelopeID != nil {
99+
if transaction.EnvelopeID != nil && *transaction.EnvelopeID != uuid.Nil {
99100
if source.OnBudget && destination.OnBudget {
100101
// TODO: Verify this state in the model hooks
101102
return httperrors.ErrorStatus{Err: errors.New("transfers between two on-budget accounts must not have an envelope set. Such a transaction would be incoming and outgoing for this envelope at the same time, which is not possible"), Status: http.StatusBadRequest}

pkg/controllers/transaction_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,16 @@ func (suite *TestSuiteStandard) TestCreateTransaction() {
321321
_ = suite.createTestTransaction(models.TransactionCreate{Note: "More tests something something", Amount: decimal.NewFromFloat(1253.17)})
322322
}
323323

324+
// TestTransactionEnvelopeNilUUID is a regression test to ensure that when the API receives a
325+
// nil UUID "00000000-0000-0000-0000-000000000000" for the envelope, we do not check for the
326+
// envelopes existence in checkTransaction()
327+
//
328+
// If we did, it would always error.
329+
func (suite *TestSuiteStandard) TestCreateTransactionCheckTransactionEnvelopeNilUUID() {
330+
eID := uuid.Nil
331+
_ = suite.createTestTransaction(models.TransactionCreate{Note: "More tests something something", Amount: decimal.NewFromFloat(1253.17), EnvelopeID: &eID})
332+
}
333+
324334
func (suite *TestSuiteStandard) TestTransactionSorting() {
325335
tFebrurary := suite.createTestTransaction(models.TransactionCreate{Note: "Should be second in the list", Amount: decimal.NewFromFloat(1253.17), Date: time.Date(2022, 2, 15, 0, 0, 0, 0, time.UTC)})
326336

pkg/models/transaction.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ func (t *Transaction) links(tx *gorm.DB) {
8181
// - sets the timezone for the Date for UTC
8282
// - ensures that ReconciledSource and ReconciledDestination are set to valid values
8383
func (t *Transaction) BeforeSave(tx *gorm.DB) (err error) {
84+
// Ensure that the Envelope ID is nil and not a pointer to a nil UUID
85+
// when it is set
86+
if t.EnvelopeID != nil && *t.EnvelopeID == uuid.Nil {
87+
t.EnvelopeID = nil
88+
}
89+
8490
if t.Date.IsZero() {
8591
t.Date = time.Now().In(time.UTC)
8692
} else {

pkg/models/transaction_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,29 @@ func (suite *TestSuiteStandard) TestTransactionAvailableFromDate() {
142142
suite.Assert().NotNil(err, "Saving a transaction with an AvailableFrom date in a month before the transaction date should not be possible")
143143
suite.Assert().Contains(err.Error(), "availability month must not be earlier than the month of the transaction")
144144
}
145+
146+
// TestTransactionEnvelopeNilUUID is a regression test to ensure that when the API receives a
147+
// nil UUID "00000000-0000-0000-0000-000000000000" for the envelope,
148+
// it is set to nil for the transaction resource.
149+
//
150+
// If it were not, it would reference the envelope with the nil UUID, which does not exist.
151+
func (suite *TestSuiteStandard) TestTransactionEnvelopeNilUUID() {
152+
budget := suite.createTestBudget(models.BudgetCreate{})
153+
internalAccount := suite.createTestAccount(models.AccountCreate{External: false, BudgetID: budget.ID})
154+
externalAccount := suite.createTestAccount(models.AccountCreate{External: true, BudgetID: budget.ID})
155+
156+
eID := uuid.Nil
157+
158+
transaction := models.Transaction{
159+
TransactionCreate: models.TransactionCreate{
160+
BudgetID: budget.ID,
161+
SourceAccountID: externalAccount.ID,
162+
DestinationAccountID: internalAccount.ID,
163+
EnvelopeID: &eID,
164+
Note: "TestTransactionEnvelopeNilUUID",
165+
},
166+
}
167+
168+
err := suite.db.Save(&transaction).Error
169+
suite.Assert().Nil(err, "Saving a transaction with a nil UUID for the Envelope ID should not result in an error")
170+
}

0 commit comments

Comments
 (0)