Skip to content

Commit 872db08

Browse files
committed
fix: disallow transfers between two on-budget accounts with an envelope set
Transfers between two on-budget accounts must not have an envelope set. Such a transaction would be incoming and outgoing for the envelope at the same time, which is not possible.
1 parent 62b1676 commit 872db08

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

pkg/controllers/transaction.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,23 +160,27 @@ func (co Controller) CreateTransaction(c *gin.Context) {
160160
}
161161

162162
// Check the source account
163-
_, ok = co.getAccountResource(c, transaction.SourceAccountID)
163+
sourceAccount, ok := co.getAccountResource(c, transaction.SourceAccountID)
164164
if !ok {
165165
return
166166
}
167167

168168
// Check the destination account
169-
_, ok = co.getAccountResource(c, transaction.DestinationAccountID)
169+
destinationAccount, ok := co.getAccountResource(c, transaction.DestinationAccountID)
170170
if !ok {
171171
return
172172
}
173173

174-
// Check the envelope ID only if it is set.
174+
// Check the envelope only if it is set.
175175
if transaction.EnvelopeID != nil {
176176
_, ok := co.getEnvelopeResource(c, *transaction.EnvelopeID)
177177
if !ok {
178178
return
179179
}
180+
181+
if sourceAccount.OnBudget && destinationAccount.OnBudget {
182+
httperrors.New(c, http.StatusBadRequest, "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")
183+
}
180184
}
181185

182186
if !decimal.Decimal.IsPositive(transaction.Amount) {
@@ -346,7 +350,7 @@ func (co Controller) UpdateTransaction(c *gin.Context) {
346350
if data.SourceAccountID != uuid.Nil {
347351
sourceAccountID = data.SourceAccountID
348352
}
349-
_, ok = co.getAccountResource(c, sourceAccountID)
353+
sourceAccount, ok := co.getAccountResource(c, sourceAccountID)
350354
if !ok {
351355
return
352356
}
@@ -356,7 +360,7 @@ func (co Controller) UpdateTransaction(c *gin.Context) {
356360
if data.DestinationAccountID != uuid.Nil {
357361
destinationAccountID = data.DestinationAccountID
358362
}
359-
_, ok = co.getAccountResource(c, destinationAccountID)
363+
destinationAccount, ok := co.getAccountResource(c, destinationAccountID)
360364
if !ok {
361365
return
362366
}
@@ -367,6 +371,10 @@ func (co Controller) UpdateTransaction(c *gin.Context) {
367371
if !ok {
368372
return
369373
}
374+
375+
if sourceAccount.OnBudget && destinationAccount.OnBudget {
376+
httperrors.New(c, http.StatusBadRequest, "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")
377+
}
370378
}
371379

372380
if !queryWithRetry(c, co.DB.Model(&transaction).Select("", updateFields...).Updates(data)) {

pkg/controllers/transaction_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,40 @@ func (suite *TestSuiteStandard) TestCreateNoEnvelopeTransactionOutgoing() {
345345
suite.assertHTTPStatus(&recorder, http.StatusCreated)
346346
}
347347

348+
func (suite *TestSuiteStandard) TestCreateTransferOnBudgetWithEnvelope() {
349+
eID := suite.createTestEnvelope(models.EnvelopeCreate{}).Data.ID
350+
c := models.TransactionCreate{
351+
BudgetID: suite.createTestBudget(models.BudgetCreate{Name: "Testing budget for transfer"}).Data.ID,
352+
SourceAccountID: suite.createTestAccount(models.AccountCreate{Name: "Internal On-Budget Source Account", External: false, OnBudget: true}).Data.ID,
353+
DestinationAccountID: suite.createTestAccount(models.AccountCreate{Name: "Internal On-Budget destination account", External: false, OnBudget: true}).Data.ID,
354+
Amount: decimal.NewFromFloat(1337),
355+
EnvelopeID: &eID,
356+
}
357+
358+
recorder := test.Request(suite.controller, suite.T(), http.MethodPost, "http://example.com/v1/transactions", c)
359+
suite.assertHTTPStatus(&recorder, http.StatusBadRequest)
360+
}
361+
362+
func (suite *TestSuiteStandard) TestUpdateTransferOnBudgetWithEnvelope() {
363+
eID := suite.createTestEnvelope(models.EnvelopeCreate{}).Data.ID
364+
c := models.TransactionCreate{
365+
BudgetID: suite.createTestBudget(models.BudgetCreate{Name: "Testing budget for transfer"}).Data.ID,
366+
SourceAccountID: suite.createTestAccount(models.AccountCreate{Name: "Internal On-Budget Source Account", External: false, OnBudget: true}).Data.ID,
367+
DestinationAccountID: suite.createTestAccount(models.AccountCreate{Name: "Internal On-Budget destination account", External: false, OnBudget: true}).Data.ID,
368+
Amount: decimal.NewFromFloat(1337),
369+
}
370+
371+
recorder := test.Request(suite.controller, suite.T(), http.MethodPost, "http://example.com/v1/transactions", c)
372+
suite.assertHTTPStatus(&recorder, http.StatusCreated)
373+
374+
var transaction controllers.TransactionResponse
375+
suite.decodeResponse(&recorder, &transaction)
376+
377+
c.EnvelopeID = &eID
378+
recorder = test.Request(suite.controller, suite.T(), http.MethodPatch, transaction.Data.Links.Self, c)
379+
suite.assertHTTPStatus(&recorder, http.StatusBadRequest)
380+
}
381+
348382
func (suite *TestSuiteStandard) TestCreateNonExistingEnvelopeTransactionTransfer() {
349383
id := uuid.New()
350384

0 commit comments

Comments
 (0)