Allow to bulk-move transactions to today

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2024-01-20 23:08:28 +01:00
parent ec4290c4ff
commit 270546823f
Signed by: luzifer
SSH key fingerprint: SHA256:/xtE5lCgiRDQr8SLxHMS92ZBlACmATUmF1crK16Ks4E
4 changed files with 97 additions and 0 deletions

View file

@ -67,6 +67,16 @@
<span class="visually-hidden">Toggle Dropdown</span> <span class="visually-hidden">Toggle Dropdown</span>
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li>
<button
class="dropdown-item"
:disabled="selectedTx.length < 1"
@click="moveToToday"
>
<i class="fas fa-fw fa-calendar-days mr-1" />
Move to Today
</button>
</li>
<li> <li>
<button <button
class="dropdown-item text-danger" class="dropdown-item text-danger"
@ -435,6 +445,29 @@ export default {
.then(() => this.fetchTransactions()) .then(() => this.fetchTransactions())
}, },
moveToToday() {
const actions = []
for (const id of this.selectedTx) {
actions.push(fetch(`/api/transactions/${id}`, {
body: JSON.stringify([
{
op: 'replace',
path: '/time',
value: new Date(new Date().toISOString()
.split('T')[0]),
},
]),
method: 'PATCH',
}))
}
Promise.all(actions)
.then(() => {
this.$emit('update-accounts')
this.fetchTransactions()
})
},
transferMoney() { transferMoney() {
const params = new URLSearchParams() const params = new URLSearchParams()
params.set('amount', this.modals.createTransfer.amount.toFixed(2)) params.set('amount', this.modals.createTransfer.amount.toFixed(2))

1
go.mod
View file

@ -11,6 +11,7 @@ require (
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.8.4 github.com/stretchr/testify v1.8.4
gopkg.in/evanphx/json-patch.v5 v5.8.1
gorm.io/driver/postgres v1.5.4 gorm.io/driver/postgres v1.5.4
gorm.io/gorm v1.25.5 gorm.io/gorm v1.25.5
) )

2
go.sum
View file

@ -65,6 +65,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v5 v5.8.1 h1:BVxXj2YS+4i9fttNkVvDKi4Pg1pVMpVE8tdEwaKeQY0=
gopkg.in/evanphx/json-patch.v5 v5.8.1/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY= gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY=
gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8= gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -1,14 +1,17 @@
package api package api
import ( import (
"bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"io"
"net/http" "net/http"
"time" "time"
"git.luzifer.io/luzifer/accounting/pkg/database" "git.luzifer.io/luzifer/accounting/pkg/database"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/gorilla/mux" "github.com/gorilla/mux"
jsonpatch "gopkg.in/evanphx/json-patch.v5"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -179,5 +182,63 @@ func (a apiServer) handleUpdateTransaction(w http.ResponseWriter, r *http.Reques
} }
} }
a.handleTransactionJSONPatch(txID, w, r)
}
func (a apiServer) handleTransactionJSONPatch(txID uuid.UUID, w http.ResponseWriter, r *http.Request) {
var (
err error
reqBody = new(bytes.Buffer)
)
if _, err = io.Copy(reqBody, r.Body); err != nil {
a.errorResponse(w, err, "reading request body", http.StatusBadRequest)
return
}
if reqBody.Len() < 2 { //nolint:gomnd
w.WriteHeader(http.StatusNoContent)
return
}
var patch jsonpatch.Patch
if err = json.NewDecoder(reqBody).Decode(&patch); err != nil {
a.errorResponse(w, err, "parsing json-patch body", http.StatusBadRequest)
return
}
if len(patch) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}
tx, err := a.dbc.GetTransactionByID(txID)
if err != nil {
a.errorResponse(w, err, "getting transaction", http.StatusInternalServerError)
return
}
txdoc, err := json.Marshal(tx)
if err != nil {
a.errorResponse(w, err, "marshalling transaction", http.StatusInternalServerError)
return
}
if txdoc, err = patch.Apply(txdoc); err != nil {
a.errorResponse(w, err, "applying patch", http.StatusInternalServerError)
return
}
var updTx database.Transaction
if err = json.Unmarshal(txdoc, &updTx); err != nil {
a.errorResponse(w, err, "unmarshalling transaction", http.StatusInternalServerError)
return
}
if err = a.dbc.UpdateTransaction(txID, updTx); err != nil {
a.errorResponse(w, err, "updating transaction", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }