add budget feature

This commit is contained in:
Patrick Nagurny
2020-01-14 14:14:16 -05:00
parent ef3a825dab
commit 0a91b19b5c
11 changed files with 460 additions and 1 deletions

58
core/model/budget.go Normal file
View File

@@ -0,0 +1,58 @@
package model
import (
"errors"
"github.com/openaccounting/oa-server/core/model/types"
)
type BudgetInterface interface {
GetBudget(string, string) (*types.Budget, error)
CreateBudget(*types.Budget, string) error
DeleteBudget(string, string) error
}
func (model *Model) GetBudget(orgId string, userId string) (*types.Budget, error) {
belongs, err := model.UserBelongsToOrg(userId, orgId)
if err != nil {
return nil, err
}
if belongs == false {
return nil, errors.New("User does not belong to org")
}
return model.db.GetBudget(orgId)
}
func (model *Model) CreateBudget(budget *types.Budget, userId string) error {
belongs, err := model.UserBelongsToOrg(userId, budget.OrgId)
if err != nil {
return err
}
if belongs == false {
return errors.New("User does not belong to org")
}
if budget.OrgId == "" {
return errors.New("orgId required")
}
return model.db.InsertAndReplaceBudget(budget)
}
func (model *Model) DeleteBudget(orgId string, userId string) error {
belongs, err := model.UserBelongsToOrg(userId, orgId)
if err != nil {
return err
}
if belongs == false {
return errors.New("User does not belong to org")
}
return model.db.DeleteBudget(orgId)
}

117
core/model/db/budget.go Normal file
View File

@@ -0,0 +1,117 @@
package db
import (
"errors"
"github.com/openaccounting/oa-server/core/model/types"
"github.com/openaccounting/oa-server/core/util"
"time"
)
type BudgetInterface interface {
GetBudget(string) (*types.Budget, error)
InsertAndReplaceBudget(*types.Budget) error
DeleteBudget(string) error
}
const budgetFields = "LOWER(HEX(accountId)),inserted,amount"
func (db *DB) GetBudget(orgId string) (*types.Budget, error) {
var budget types.Budget
var inserted int64
rows, err := db.Query("SELECT "+budgetFields+" FROM budgetitem WHERE orgId = UNHEX(?) ORDER BY HEX(accountId)", orgId)
if err != nil {
return nil, err
}
defer rows.Close()
items := make([]*types.BudgetItem, 0)
for rows.Next() {
i := new(types.BudgetItem)
err := rows.Scan(&i.AccountId, &inserted, &i.Amount)
if err != nil {
return nil, err
}
items = append(items, i)
}
err = rows.Err()
if err != nil {
return nil, err
}
if len(items) == 0 {
return nil, errors.New("Budget not found")
}
budget.OrgId = orgId
budget.Inserted = util.MsToTime(inserted)
budget.Items = items
return &budget, nil
}
func (db *DB) InsertAndReplaceBudget(budget *types.Budget) (err error) {
budget.Inserted = time.Now()
// Save to db
dbTx, err := db.Begin()
if err != nil {
return
}
defer func() {
if p := recover(); p != nil {
dbTx.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
dbTx.Rollback()
} else {
err = dbTx.Commit()
}
}()
// delete previous budget
query1 := "DELETE FROM budgetitem WHERE orgId = UNHEX(?)"
_, err = dbTx.Exec(
query1,
budget.OrgId,
)
if err != nil {
return
}
// save items
for _, item := range budget.Items {
query := "INSERT INTO budgetitem(orgId,accountId,inserted,amount) VALUES (UNHEX(?),UNHEX(?),?,?)"
_, err = dbTx.Exec(
query,
budget.OrgId,
item.AccountId,
util.TimeToMs(budget.Inserted),
item.Amount)
if err != nil {
return
}
}
return
}
func (db *DB) DeleteBudget(orgId string) error {
query := "DELETE FROM budgetitem WHERE orgId = UNHEX(?)"
_, err := db.Exec(query, orgId)
return err
}

View File

@@ -19,6 +19,7 @@ type Datastore interface {
SessionInterface
ApiKeyInterface
SystemHealthInteface
BudgetInterface
}
func NewDB(dataSourceName string) (*DB, error) {

View File

@@ -23,6 +23,7 @@ type Interface interface {
SessionInterface
ApiKeyInterface
SystemHealthInteface
BudgetInterface
}
func NewModel(db db.Datastore, bcrypt util.Bcrypt, config types.Config) *Model {

View File

@@ -0,0 +1,17 @@
package types
import (
"time"
)
type Budget struct {
OrgId string `json:"orgId"`
Inserted time.Time `json:"inserted"`
Items []*BudgetItem `json:"items"`
}
type BudgetItem struct {
OrgId string `json:"-"`
AccountId string `json:"accountId"`
Amount int64 `json:"amount"`
}