-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
import transaction from GnuCash database
- Loading branch information
Showing
12 changed files
with
1,517 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package gnucash | ||
|
||
import "encoding/xml" | ||
|
||
const gnucashCommodityCurrencySpace = "CURRENCY" | ||
const gnucashRootAccountType = "ROOT" | ||
const gnucashEquityAccountType = "EQUITY" | ||
const gnucashIncomeAccountType = "INCOME" | ||
const gnucashExpenseAccountType = "EXPENSE" | ||
|
||
const gnucashSlotEquityType = "equity-type" | ||
const gnucashSlotEquityTypeOpeningBalance = "opening-balance" | ||
|
||
var gnucashAssetOrLiabilityAccountTypes = map[string]bool{ | ||
"ASSET": true, | ||
"BANK": true, | ||
"CASH": true, | ||
"CREDIT": true, | ||
"LIABILITY": true, | ||
"MUTUAL": true, | ||
"PAYABLE": true, | ||
"RECEIVABLE": true, | ||
"STOCK": true, | ||
} | ||
|
||
// gnucashDatabase represents the struct of gnucash database file | ||
type gnucashDatabase struct { | ||
XMLName xml.Name `xml:"gnc-v2"` | ||
Counts []*gnucashCountData `xml:"count-data"` | ||
Books []*gnucashBookData `xml:"book"` | ||
} | ||
|
||
// gnucashCountData represents the struct of gnucash count data | ||
type gnucashCountData struct { | ||
Key string `xml:"type,attr"` | ||
Value string `xml:",chardata"` | ||
} | ||
|
||
// gnucashBookData represents the struct of gnucash book data | ||
type gnucashBookData struct { | ||
Id string `xml:"id"` | ||
Counts []*gnucashCountData `xml:"count-data"` | ||
Accounts []*gnucashAccountData `xml:"account"` | ||
Transactions []*gnucashTransactionData `xml:"transaction"` | ||
} | ||
|
||
// gnucashCommodityData represents the struct of gnucash commodity data | ||
type gnucashCommodityData struct { | ||
Space string `xml:"space"` | ||
Id string `xml:"id"` | ||
} | ||
|
||
// gnucashSlotData represents the struct of gnucash slot data | ||
type gnucashSlotData struct { | ||
Key string `xml:"key"` | ||
Value string `xml:"value"` | ||
} | ||
|
||
// gnucashAccountData represents the struct of gnucash account data | ||
type gnucashAccountData struct { | ||
Name string `xml:"name"` | ||
Id string `xml:"id"` | ||
AccountType string `xml:"type"` | ||
Description string `xml:"description"` | ||
ParentId string `xml:"parent"` | ||
Commodity *gnucashCommodityData `xml:"commodity"` | ||
Slots []*gnucashSlotData `xml:"slots>slot"` | ||
} | ||
|
||
// gnucashTransactionData represents the struct of gnucash transaction data | ||
type gnucashTransactionData struct { | ||
Id string `xml:"id"` | ||
Currency *gnucashCommodityData `xml:"currency"` | ||
PostedDate string `xml:"date-posted>date"` | ||
EnteredDate string `xml:"date-entered>date"` | ||
Description string `xml:"description"` | ||
Splits []*gnucashTransactionSplitData `xml:"splits>split"` | ||
} | ||
|
||
// gnucashTransactionSplitData represents the struct of gnucash transaction split data | ||
type gnucashTransactionSplitData struct { | ||
Id string `xml:"id"` | ||
ReconciledState string `xml:"reconciled-state"` | ||
Value string `xml:"value"` | ||
Quantity string `xml:"quantity"` | ||
Account string `xml:"account"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package gnucash | ||
|
||
import ( | ||
"bytes" | ||
"compress/gzip" | ||
"encoding/xml" | ||
|
||
"github.com/mayswind/ezbookkeeping/pkg/core" | ||
"github.com/mayswind/ezbookkeeping/pkg/errs" | ||
"github.com/mayswind/ezbookkeeping/pkg/utils" | ||
) | ||
|
||
// gnucashDatabaseReader defines the structure of gnucash database reader | ||
type gnucashDatabaseReader struct { | ||
xmlDecoder *xml.Decoder | ||
} | ||
|
||
// read returns the imported gnucash data | ||
func (r *gnucashDatabaseReader) read(ctx core.Context) (*gnucashDatabase, error) { | ||
database := &gnucashDatabase{} | ||
|
||
err := r.xmlDecoder.Decode(&database) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return database, nil | ||
} | ||
|
||
func createNewGnuCashDatabaseReader(data []byte) (*gnucashDatabaseReader, error) { | ||
if len(data) > 2 && data[0] == 0x1F && data[1] == 0x8B { // gzip magic number | ||
gzipReader, err := gzip.NewReader(bytes.NewReader(data)) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
xmlDecoder := xml.NewDecoder(gzipReader) | ||
xmlDecoder.CharsetReader = utils.IdentReader | ||
|
||
return &gnucashDatabaseReader{ | ||
xmlDecoder: xmlDecoder, | ||
}, nil | ||
} else if len(data) > 5 && data[0] == 0x3C && data[1] == 0x3F && data[2] == 0x78 && data[3] == 0x6D && data[4] == 0x6C { // <?xml | ||
xmlDecoder := xml.NewDecoder(bytes.NewReader(data)) | ||
xmlDecoder.CharsetReader = utils.IdentReader | ||
|
||
return &gnucashDatabaseReader{ | ||
xmlDecoder: xmlDecoder, | ||
}, nil | ||
} | ||
|
||
return nil, errs.ErrInvalidGnuCashFile | ||
} |
49 changes: 49 additions & 0 deletions
49
pkg/converters/gnucash/gnucash_transaction_data_file_importer.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package gnucash | ||
|
||
import ( | ||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable" | ||
"github.com/mayswind/ezbookkeeping/pkg/core" | ||
"github.com/mayswind/ezbookkeeping/pkg/models" | ||
"github.com/mayswind/ezbookkeeping/pkg/utils" | ||
) | ||
|
||
var gnucashTransactionTypeNameMapping = map[models.TransactionType]string{ | ||
models.TRANSACTION_TYPE_MODIFY_BALANCE: utils.IntToString(int(models.TRANSACTION_TYPE_MODIFY_BALANCE)), | ||
models.TRANSACTION_TYPE_INCOME: utils.IntToString(int(models.TRANSACTION_TYPE_INCOME)), | ||
models.TRANSACTION_TYPE_EXPENSE: utils.IntToString(int(models.TRANSACTION_TYPE_EXPENSE)), | ||
models.TRANSACTION_TYPE_TRANSFER: utils.IntToString(int(models.TRANSACTION_TYPE_TRANSFER)), | ||
} | ||
|
||
// gnucashTransactionDataImporter defines the structure of gnucash importer for transaction data | ||
type gnucashTransactionDataImporter struct { | ||
} | ||
|
||
// Initialize a gnucash transaction data importer singleton instance | ||
var ( | ||
GnuCashTransactionDataImporter = &gnucashTransactionDataImporter{} | ||
) | ||
|
||
// ParseImportedData returns the imported data by parsing the gnucash transaction data | ||
func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, accountMap map[string]*models.Account, expenseCategoryMap map[string]*models.TransactionCategory, incomeCategoryMap map[string]*models.TransactionCategory, transferCategoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) { | ||
gnucashDataReader, err := createNewGnuCashDatabaseReader(data) | ||
|
||
if err != nil { | ||
return nil, nil, nil, nil, nil, nil, err | ||
} | ||
|
||
gnucashData, err := gnucashDataReader.read(ctx) | ||
|
||
if err != nil { | ||
return nil, nil, nil, nil, nil, nil, err | ||
} | ||
|
||
transactionDataTable, err := createNewGnuCashTransactionDataTable(gnucashData) | ||
|
||
if err != nil { | ||
return nil, nil, nil, nil, nil, nil, err | ||
} | ||
|
||
dataTableImporter := datatable.CreateNewSimpleImporter(gnucashTransactionTypeNameMapping) | ||
|
||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap) | ||
} |
Oops, something went wrong.