You've already forked openaccounting-server
mirror of
https://github.com/openaccounting/oa-server.git
synced 2025-12-09 00:50:59 +13:00
initial commit
This commit is contained in:
213
core/model/transaction.go
Normal file
213
core/model/transaction.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/openaccounting/oa-server/core/model/types"
|
||||
"github.com/openaccounting/oa-server/core/ws"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TransactionInterface interface {
|
||||
CreateTransaction(*types.Transaction) error
|
||||
UpdateTransaction(string, *types.Transaction) error
|
||||
GetTransactionsByAccount(string, string, string, *types.QueryOptions) ([]*types.Transaction, error)
|
||||
GetTransactionsByOrg(string, string, *types.QueryOptions) ([]*types.Transaction, error)
|
||||
DeleteTransaction(string, string, string) error
|
||||
}
|
||||
|
||||
func (model *Model) CreateTransaction(transaction *types.Transaction) (err error) {
|
||||
err = model.checkSplits(transaction)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if transaction.Id == "" {
|
||||
return errors.New("id required")
|
||||
}
|
||||
|
||||
transaction.Inserted = time.Now()
|
||||
transaction.Updated = time.Now()
|
||||
|
||||
if transaction.Date.IsZero() {
|
||||
transaction.Date = transaction.Inserted
|
||||
}
|
||||
|
||||
err = model.db.InsertTransaction(transaction)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Notify web socket subscribers
|
||||
// TODO only get user ids that have permission to access transaction
|
||||
userIds, err2 := model.db.GetOrgUserIds(transaction.OrgId)
|
||||
|
||||
if err2 == nil {
|
||||
ws.PushTransaction(transaction, userIds, "create")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (model *Model) UpdateTransaction(oldId string, transaction *types.Transaction) (err error) {
|
||||
err = model.checkSplits(transaction)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if oldId == "" || transaction.Id == "" {
|
||||
return errors.New("id required")
|
||||
}
|
||||
|
||||
// Get original transaction
|
||||
original, err := model.getTransactionById(oldId)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
transaction.Updated = time.Now()
|
||||
transaction.Inserted = original.Inserted
|
||||
|
||||
// We used to compare splits and if they hadn't changed just do an update
|
||||
// on the transaction. The problem is then the updated field gets out of sync
|
||||
// between the tranaction and its splits.
|
||||
// It needs to be in sync for getTransactionsByOrg() to work correctly with pagination
|
||||
|
||||
// Delete old transaction and insert a new one
|
||||
transaction.Inserted = transaction.Updated
|
||||
err = model.db.DeleteAndInsertTransaction(oldId, transaction)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Notify web socket subscribers
|
||||
// TODO only get user ids that have permission to access transaction
|
||||
userIds, err2 := model.db.GetOrgUserIds(transaction.OrgId)
|
||||
|
||||
if err2 == nil {
|
||||
ws.PushTransaction(original, userIds, "delete")
|
||||
ws.PushTransaction(transaction, userIds, "create")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (model *Model) GetTransactionsByAccount(orgId string, userId string, accountId string, options *types.QueryOptions) ([]*types.Transaction, error) {
|
||||
userAccounts, err := model.GetAccounts(orgId, userId, "")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !model.accountsContainWriteAccess(userAccounts, accountId) {
|
||||
return nil, errors.New(fmt.Sprintf("%s %s", "user does not have permission to access account", accountId))
|
||||
}
|
||||
|
||||
return model.db.GetTransactionsByAccount(accountId, options)
|
||||
|
||||
}
|
||||
|
||||
func (model *Model) GetTransactionsByOrg(orgId string, userId string, options *types.QueryOptions) ([]*types.Transaction, error) {
|
||||
userAccounts, err := model.GetAccounts(orgId, userId, "")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var accountIds []string
|
||||
for _, account := range userAccounts {
|
||||
accountIds = append(accountIds, account.Id)
|
||||
}
|
||||
|
||||
return model.db.GetTransactionsByOrg(orgId, options, accountIds)
|
||||
}
|
||||
|
||||
func (model *Model) DeleteTransaction(id string, userId string, orgId string) (err error) {
|
||||
transaction, err := model.getTransactionById(id)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
userAccounts, err := model.GetAccounts(orgId, userId, "")
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, split := range transaction.Splits {
|
||||
if !model.accountsContainWriteAccess(userAccounts, split.AccountId) {
|
||||
return errors.New(fmt.Sprintf("%s %s", "user does not have permission to access account", split.AccountId))
|
||||
}
|
||||
}
|
||||
|
||||
err = model.db.DeleteTransaction(id)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Notify web socket subscribers
|
||||
// TODO only get user ids that have permission to access transaction
|
||||
userIds, err2 := model.db.GetOrgUserIds(transaction.OrgId)
|
||||
|
||||
if err2 == nil {
|
||||
ws.PushTransaction(transaction, userIds, "delete")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (model *Model) getTransactionById(id string) (*types.Transaction, error) {
|
||||
// TODO if this is made public, make a separate version that checks permission
|
||||
return model.db.GetTransactionById(id)
|
||||
}
|
||||
|
||||
func (model *Model) checkSplits(transaction *types.Transaction) (err error) {
|
||||
if len(transaction.Splits) < 2 {
|
||||
return errors.New("at least 2 splits are required")
|
||||
}
|
||||
|
||||
org, err := model.GetOrg(transaction.OrgId, transaction.UserId)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
userAccounts, err := model.GetAccounts(transaction.OrgId, transaction.UserId, "")
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var amount int64 = 0
|
||||
|
||||
for _, split := range transaction.Splits {
|
||||
if !model.accountsContainWriteAccess(userAccounts, split.AccountId) {
|
||||
return errors.New(fmt.Sprintf("%s %s", "user does not have permission to access account", split.AccountId))
|
||||
}
|
||||
|
||||
account := model.getAccountFromList(userAccounts, split.AccountId)
|
||||
|
||||
if account.HasChildren == true {
|
||||
return errors.New("Cannot use parent account for split")
|
||||
}
|
||||
|
||||
if account.Currency == org.Currency && split.NativeAmount != split.Amount {
|
||||
return errors.New("nativeAmount must equal amount for native currency splits")
|
||||
}
|
||||
|
||||
amount += split.NativeAmount
|
||||
}
|
||||
|
||||
if amount != 0 {
|
||||
return errors.New("splits must add up to 0")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user