Skip to content

Commit

Permalink
Unificate categories handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Bishop committed Apr 6, 2022
1 parent 2f26e93 commit 1679ca9
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 118 deletions.
95 changes: 68 additions & 27 deletions ability_cash/converter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ability_cash

import (
"math"
"sort"
"strings"
"time"
Expand All @@ -12,9 +13,17 @@ import (
type LedgerConverter struct {
GenerateEquity bool
Db schema.Database
Categories map[string]string
accounts map[string]string
}

type Tags struct {
Payee string
ItemPayee string
Account string
Tags map[string]string
}

func (c *LedgerConverter) Transactions() <-chan ledger.Transaction {
c.accounts = make(map[string]string)

Expand Down Expand Up @@ -54,49 +63,63 @@ func (c *LedgerConverter) transactions(txs chan<- ledger.Transaction) {
}

for _, tx := range *c.Db.GetTransactions() {
if tx.Payee == "" && tx.Metadata[schema.PayeeClassifier] != "" {
tx.Payee = c.lastPart(tx.Metadata[schema.PayeeClassifier])
delete(tx.Metadata, schema.PayeeClassifier)
tags := c.createTags(tx.Tags)
tx.Tags = nil
tx.Metadata = tags.Tags

if tx.Payee == "" {
tx.Payee = tags.Payee
}

if tx.Payee == "" && len(tx.Items) == 2 {
if tx.Items[0].Currency == tx.Items[1].Currency {
tx.Payee = "Transfer"

if math.Abs(tx.Items[0].Amount) == math.Abs(tx.Items[1].Amount) {
index := 0
if tx.Items[1].Amount < 0 {
index = 1
}
tx.Items[index].Amount = 0
tx.Items[index].Currency = ""
}
} else {
tx.Payee = "Exchange"
}
}

if tx.Metadata[schema.ExpensesClassifier] != "" {
account := tx.Metadata[schema.ExpensesClassifier]
delete(tx.Metadata, schema.ExpensesClassifier)

if tx.Payee == "" && strings.Count(account, "\\") == 3 {
tx.Payee = c.lastPart(account)
account = strings.Replace(account, "\\"+tx.Payee, "", 1)
}

tx.Items = append(tx.Items, ledger.TxItem{Account: account})
if tags.Account != "" {
tx.Items = append(tx.Items, ledger.TxItem{Account: tags.Account})

if tx.Items[0].Amount < 0 {
tx.Items[1].Amount = -tx.Items[0].Amount
tx.Items[0].Amount = 0
tx.Items[1].Currency = tx.Items[0].Currency
tx.Items[0].Currency = ""
tx.Items[1].Amount, tx.Items[0].Amount = -tx.Items[0].Amount, 0
tx.Items[1].Currency, tx.Items[0].Currency = tx.Items[0].Currency, ""
}
}

if tx.Payee == "" {
tx.Payee = tags.ItemPayee
} else {
tx.Items[1].Payee = tags.ItemPayee
}

tx.Items[0].Account = c.account(tx.Items[0].Account)
tx.Items[1].Account = c.account(tx.Items[1].Account)

txs <- tx
}
}

func (c *LedgerConverter) lastPart(account string) string {
parts := strings.Split(account, "\\")
func (c *LedgerConverter) Accounts() []string {
list := make([]string, 0, len(c.accounts))

return parts[len(parts)-1]
for _, account := range c.accounts {
list = append(list, account)
}

sort.Strings(list)

return list
}

func (c *LedgerConverter) account(s string) string {
Expand All @@ -111,14 +134,32 @@ func (c *LedgerConverter) account(s string) string {
return a
}

func (c *LedgerConverter) Accounts() []string {
list := make([]string, 0, len(c.accounts))

for _, account := range c.accounts {
list = append(list, account)
func (c *LedgerConverter) createTags(tags []string) *Tags {
t := new(Tags)
t.Tags = make(map[string]string)

for _, tag := range tags {
parts := strings.SplitN(tag, "\\", 2)
switch c.Categories[parts[0]] {
case "payee":
t.Payee = c.lastPart(tag)
case "account":
t.Account = tag

if strings.Count(t.Account, "\\") == 3 {
t.ItemPayee = c.lastPart(t.Account)
t.Account = t.Account[0 : len(t.Account)-len(t.ItemPayee)-1]
}
default:
t.Tags[parts[0]] = c.lastPart(tag)
}
}

sort.Strings(list)
return t
}

return list
func (c *LedgerConverter) lastPart(account string) string {
parts := strings.Split(account, "\\")

return parts[len(parts)-1]
}
7 changes: 3 additions & 4 deletions ability_cash/csv_schema/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,13 @@ func (d *Database) AddTx(record []string) {
Note: record[9],
Executed: record[0] == "+",
Cleared: record[1] == "+",
Metadata: make(map[string]string),
Tags: make([]string, 0),
Items: []ledger.TxItem{},
}

for _, category := range []string{record[10], record[11], record[12]} {
for _, category := range record[10:] {
if category != "" {
category = category[1:]
tx.Metadata[schema.CategoryClassifier(category)] = category
tx.Tags = append(tx.Tags, category[1:])
}
}

Expand Down
21 changes: 0 additions & 21 deletions ability_cash/schema/types.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
package schema

import (
"strings"
"time"

"github.com/Bishop/abilitycash2ledger/ledger"
)

const (
PayeeClassifier = "Provider"
ExpensesClassifier = "Category"
)

type Database interface {
GetAccounts() *[]Account
GetTransactions() *[]ledger.Transaction
Expand All @@ -33,18 +27,3 @@ type Rate struct {
}

type AccountsMap map[string]string

func CategoryClassifier(category string) string {
parts := strings.SplitN(category, "\\", 2)

switch parts[0] {
case "Income", "Expenses":
return ExpensesClassifier
case "Payee":
return PayeeClassifier
case "Agents":
return "Agent"
default:
return ""
}
}
13 changes: 6 additions & 7 deletions ability_cash/sql_schema/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ func (d *Database) readTxs(uid int, fetch FetchFunc) error {
}

tx := ledger.Transaction{
Date: time.Unix(date, 0),
Note: comment,
Cleared: locked,
Metadata: make(map[string]string),
Items: []ledger.TxItem{},
Date: time.Unix(date, 0),
Note: comment,
Cleared: locked,
Tags: make([]string, 0),
Items: []ledger.TxItem{},
}

if iaccout.Valid {
Expand All @@ -173,8 +173,7 @@ func (d *Database) readTxs(uid int, fetch FetchFunc) error {

if categories, ok := d.txCategoriesIndex[uid]; ok {
for _, category := range categories {
name := d.categoriesIndex[category]
tx.Metadata[schema.CategoryClassifier(name)] = name
tx.Tags = append(tx.Tags, d.categoriesIndex[category])
}
}

Expand Down
39 changes: 4 additions & 35 deletions ability_cash/xml_schema/classifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,13 @@ func (t *txCategory) Flatten() (string, string) {
return t.Classifier, name
}

func (t txCategories) Map() map[string]string {
result := make(map[string]string)
func (t txCategories) List() []string {
result := make([]string, 0)

for _, c := range t {
classifier, name := c.Flatten()
result[classifier] = name
_, name := c.Flatten()
result = append(result, name)
}

return result
}

func (c *Classifier) Categories() <-chan string {
result := make(chan string)

go func() {
for _, category := range c.Income {
category.iterateCategories("", result)
}
for _, category := range c.Expense {
category.iterateCategories("", result)
}
for _, category := range c.Single {
category.iterateCategories("", result)
}
close(result)
}()

return result
}

func (c *txCategoryTI) iterateCategories(prefix string, ch chan<- string) {
fullName := prefix + "\\" + c.Name

ch <- fullName[1:]

if c.Categories != nil {
for _, category := range *c.Categories {
category.iterateCategories(fullName, ch)
}
}
}
29 changes: 9 additions & 20 deletions ability_cash/xml_schema/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Transfer struct {
txItem
txIncome
txExpense
Categories txCategories `xml:"category"`
}

type Income struct {
Expand Down Expand Up @@ -183,44 +184,36 @@ func (d *Database) GetTransactions() *[]ledger.Transaction {

switch {
case source.Transfer != nil:
tx.Tags = source.Transfer.Categories.List()
tx.Items = []ledger.TxItem{
{
Account: d.account(source.Transfer.ExpenseAccount.Name),
Account: d.account(source.Transfer.ExpenseAccount.Name),
Currency: source.Transfer.ExpenseAccount.Currency,
Amount: source.Transfer.ExpenseAmount,
},
{
Account: d.account(source.Transfer.IncomeAccount.Name),
Currency: source.Transfer.IncomeAccount.Currency,
Amount: source.Transfer.IncomeAmount,
},
}

if source.Transfer.IncomeAccount.Currency != source.Transfer.ExpenseAccount.Currency {
tx.Items[0].Currency = source.Transfer.ExpenseAccount.Currency
tx.Items[0].Amount = source.Transfer.ExpenseAmount
}
case source.Expense != nil:
tx.Metadata = source.Expense.Categories.Map()
tx.Tags = source.Expense.Categories.List()
tx.Items = []ledger.TxItem{
{
Account: d.account(source.Expense.ExpenseAccount.Name),
},
{
Account: d.accountFromCategories(tx.Metadata),
Account: d.account(source.Expense.ExpenseAccount.Name),
Currency: source.Expense.ExpenseAccount.Currency,
Amount: -source.Expense.ExpenseAmount,
Amount: source.Expense.ExpenseAmount,
},
}
case source.Income != nil:
tx.Metadata = source.Income.Categories.Map()
tx.Tags = source.Income.Categories.List()
tx.Items = []ledger.TxItem{
{
Account: d.account(source.Income.IncomeAccount.Name),
Currency: source.Income.IncomeAccount.Currency,
Amount: source.Income.IncomeAmount,
},
{
Account: d.accountFromCategories(tx.Metadata),
},
}
case source.Balance != nil:
tx.Items = []ledger.TxItem{
Expand Down Expand Up @@ -250,10 +243,6 @@ func (d *Database) account(a string) string {
}
}

func (d *Database) accountFromCategories(classifier map[string]string) string {
return classifier["Статья"]
}

func (d *Database) cacheAccountsMap() {
if d.AccountsMap != nil {
return
Expand Down
3 changes: 2 additions & 1 deletion scope/datafile.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ func (d *datafile) format() string {
return path.Ext(d.Path)
}

func (d *datafile) export() (err error) {
func (d *datafile) export(categories map[string]string) (err error) {
if err = d.exportEntity("rates", d.db.GetRates()); err != nil {
return
}

converter := &ability_cash.LedgerConverter{
GenerateEquity: d.Equity,
Db: d.db,
Categories: categories,
}

err = d.exportEntity("txs", converter.Transactions())
Expand Down
11 changes: 8 additions & 3 deletions scope/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ import (
)

func NewScope() *scope {
return new(scope)
s := new(scope)

s.Categories = map[string]string{"Payee": "payee", "Expenses": "account", "Income": "account"}

return s
}

type scope struct {
Datafiles []*datafile `json:"datafiles"`
Datafiles []*datafile `json:"datafiles"`
Categories map[string]string `json:"categories"`
}

func (s *scope) AddFile(name string) error {
Expand Down Expand Up @@ -48,7 +53,7 @@ func (s *scope) Validate() ([]string, error) {

func (s *scope) Export() error {
return s.iterateDatafiles(func(d *datafile) error {
return d.export()
return d.export(s.Categories)
})
}

Expand Down
Loading

0 comments on commit 1679ca9

Please sign in to comment.