Continue on ynab import

This commit is contained in:
Jan Bader 2021-12-02 15:56:40 +00:00
parent 7b6914e5f2
commit 1cd2eedcb8
6 changed files with 106 additions and 25 deletions

View File

@ -80,12 +80,51 @@ func (h *Handler) Serve() {
{
transaction.Use(h.verifyLoginWithRedirect)
transaction.POST("/new", h.newTransaction)
transaction.POST("/import/ynab", h.importYNAB)
}
}
router.Run(":1323")
}
func (h *Handler) importYNAB(c *gin.Context) {
transactionsFile, err := c.FormFile("transactions")
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
transactions, err := transactionsFile.Open()
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
budgetID, succ := c.GetPostForm("budget_id")
if !succ {
c.AbortWithError(http.StatusBadRequest, err)
return
}
budgetUUID, err := uuid.Parse(budgetID)
if !succ {
c.AbortWithError(http.StatusBadRequest, err)
return
}
ynab, err := NewYNABImport(h.Service.DB, budgetUUID)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
err = ynab.Import(transactions)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
func (h *Handler) verifyLoginWithRedirect(c *gin.Context) {
_, err := h.verifyLogin(c)
if err != nil {

View File

@ -3,11 +3,13 @@ package http
import (
"context"
"encoding/csv"
"fmt"
"io"
"time"
"git.javil.eu/jacob1123/budgeteer/postgres"
"github.com/google/uuid"
"github.com/jackc/pgtype"
)
type YNABImport struct {
@ -15,9 +17,10 @@ type YNABImport struct {
accounts []postgres.Account
payees []postgres.Payee
queries *postgres.Queries
budgetID uuid.UUID
}
func NewYNABImport(q *postgres.Queries) (*YNABImport, error) {
func NewYNABImport(q *postgres.Queries, budgetID uuid.UUID) (*YNABImport, error) {
accounts, err := q.GetAccounts(context.Background(), uuid.UUID{})
if err != nil {
return nil, err
@ -33,24 +36,26 @@ func NewYNABImport(q *postgres.Queries) (*YNABImport, error) {
accounts: accounts,
payees: payees,
queries: q,
budgetID: budgetID,
}, nil
}
func (ynab *YNABImport) Import(q *postgres.Queries, r io.Reader) error {
func (ynab *YNABImport) Import(r io.Reader) error {
csv := csv.NewReader(r)
csv.Comma = '\t'
csv.LazyQuotes = true
csvData, err := csv.ReadAll()
if err != nil {
return err
return fmt.Errorf("could not read from tsv: %w", err)
}
for _, record := range csvData {
accountName := record[0]
account, err := ynab.GetAccount(accountName)
if err != nil {
return err
return fmt.Errorf("could not get account %s: %w", accountName, err)
}
//flag := record[1]
@ -58,22 +63,45 @@ func (ynab *YNABImport) Import(q *postgres.Queries, r io.Reader) error {
dateString := record[2]
date, err := time.Parse("02.01.2006", dateString)
if err != nil {
return err
return fmt.Errorf("could not parse date %s: %w", dateString, err)
}
payee := record[3]
category := record[4] //also in 5 + 6 split by group/category
payeeName := record[3]
payeeID, err := ynab.GetPayee(payeeName)
if err != nil {
return fmt.Errorf("could not get payee %s: %w", payeeName, err)
}
//category := record[4] //also in 5 + 6 split by group/category
memo := record[7]
outflow := record[8]
inflow := record[9]
cleared := record[10]
amount := GetAmount(inflow, outflow)
transaction := postgres.Transaction{
//cleared := record[10]
transaction := postgres.CreateTransactionParams{
Date: date,
Memo: memo,
AccountID: account.ID,
PayeeID: payeeID,
Amount: amount,
}
ynab.queries.CreateTransaction(ynab.Context, transaction)
}
return nil
}
func GetAmount(inflow string, outflow string) pgtype.Numeric {
// Remove currency
inflow = inflow[:len(inflow)-1]
outflow = outflow[:len(outflow)-1]
num := pgtype.Numeric{}
num.Set(inflow)
return num
}
func (ynab *YNABImport) GetAccount(name string) (*postgres.Account, error) {
@ -92,18 +120,22 @@ func (ynab *YNABImport) GetAccount(name string) (*postgres.Account, error) {
return &account, nil
}
func (ynab *YNABImport) GetPayee(name string) (*postgres.Payee, error) {
func (ynab *YNABImport) GetPayee(name string) (uuid.NullUUID, error) {
if name == "" {
return uuid.NullUUID{}, nil
}
for _, pay := range ynab.payees {
if pay.Name == name {
return &pay, nil
return uuid.NullUUID{UUID: pay.ID, Valid: true}, nil
}
}
payee, err := ynab.queries.CreatePayee(ynab.Context, name)
if err != nil {
return nil, err
return uuid.NullUUID{}, err
}
ynab.payees = append(ynab.payees, payee)
return &payee, nil
return uuid.NullUUID{UUID: payee.ID, Valid: true}, nil
}

View File

@ -11,13 +11,18 @@ import (
const createAccount = `-- name: CreateAccount :one
INSERT INTO accounts
(name)
VALUES ($1)
(name, budget_id)
VALUES ($1, $2)
RETURNING id, budget_id, name
`
func (q *Queries) CreateAccount(ctx context.Context, name string) (Account, error) {
row := q.db.QueryRow(ctx, createAccount, name)
type CreateAccountParams struct {
Name string
BudgetID uuid.UUID
}
func (q *Queries) CreateAccount(ctx context.Context, arg CreateAccountParams) (Account, error) {
row := q.db.QueryRow(ctx, createAccount, arg.Name, arg.BudgetID)
var i Account
err := row.Scan(&i.ID, &i.BudgetID, &i.Name)
return i, err

View File

@ -11,13 +11,18 @@ import (
const createPayee = `-- name: CreatePayee :one
INSERT INTO payees
(name)
VALUES ($1)
(name, budget_id)
VALUES ($1, $2)
RETURNING id, budget_id, name
`
func (q *Queries) CreatePayee(ctx context.Context, name string) (Payee, error) {
row := q.db.QueryRow(ctx, createPayee, name)
type CreatePayeeParams struct {
Name string
BudgetID uuid.UUID
}
func (q *Queries) CreatePayee(ctx context.Context, arg CreatePayeeParams) (Payee, error) {
row := q.db.QueryRow(ctx, createPayee, arg.Name, arg.BudgetID)
var i Payee
err := row.Scan(&i.ID, &i.BudgetID, &i.Name)
return i, err

View File

@ -1,7 +1,7 @@
-- name: CreateAccount :one
INSERT INTO accounts
(name)
VALUES ($1)
(name, budget_id)
VALUES ($1, $2)
RETURNING *;
-- name: GetAccounts :many

View File

@ -1,7 +1,7 @@
-- name: CreatePayee :one
INSERT INTO payees
(name)
VALUES ($1)
(name, budget_id)
VALUES ($1, $2)
RETURNING *;
-- name: GetPayees :many