From a4b99381d36ab0aed07e071462120c24eabe46ae Mon Sep 17 00:00:00 2001 From: Aaron Lindsay Date: Sat, 10 Jun 2017 15:22:13 -0400 Subject: [PATCH] imports: Don't re-import the same transaction from the same place This is detected using the RemoteId field on Splits While we're at it, also make gnucash import check numbers --- gnucash.go | 31 ++++++++++++++++++++++++------- imports.go | 18 ++++++++++++++++-- ofx.go | 2 +- transactions.go | 5 +++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/gnucash.go b/gnucash.go index c0e408b..598747b 100644 --- a/gnucash.go +++ b/gnucash.go @@ -84,6 +84,7 @@ type GnucashAccount struct { type GnucashTransaction struct { TransactionId string `xml:"http://www.gnucash.org/XML/trn id"` Description string `xml:"http://www.gnucash.org/XML/trn description"` + Number string `xml:"http://www.gnucash.org/XML/trn num"` DatePosted GnucashDate `xml:"http://www.gnucash.org/XML/trn date-posted"` DateEntered GnucashDate `xml:"http://www.gnucash.org/XML/trn date-entered"` Commodity GnucashXMLCommodity `xml:"http://www.gnucash.org/XML/trn currency"` @@ -215,7 +216,6 @@ func ImportGnucash(r io.Reader) (*GnucashImport, error) { for j := range gt.Splits { gs := gt.Splits[j] s := new(Split) - s.Memo = gs.Memo switch gs.Status { default: // 'n', or not present @@ -238,6 +238,10 @@ func ImportGnucash(r io.Reader) (*GnucashImport, error) { } s.SecurityId = -1 + s.RemoteId = "gnucash:" + gs.SplitId + s.Number = gt.Number + s.Memo = gs.Memo + var r big.Rat _, ok = r.SetString(gs.Amount) if ok { @@ -359,6 +363,7 @@ func GnucashImportHandler(w http.ResponseWriter, r *http.Request) { // Insert transactions, fixing up account IDs to match internal ones from // above for _, transaction := range gnucashImport.Transactions { + var already_imported bool for _, split := range transaction.Splits { acctId, ok := accountMap[split.AccountId] if !ok { @@ -368,13 +373,25 @@ func GnucashImportHandler(w http.ResponseWriter, r *http.Request) { return } split.AccountId = acctId + + exists, err := split.AlreadyImportedTx(sqltransaction) + if err != nil { + sqltransaction.Rollback() + WriteError(w, 999 /*Internal Error*/) + log.Print("Error checking if split was already imported:", err) + return + } else if exists { + already_imported = true + } } - err := InsertTransactionTx(sqltransaction, &transaction, user) - if err != nil { - sqltransaction.Rollback() - WriteError(w, 999 /*Internal Error*/) - log.Print(err) - return + if !already_imported { + err := InsertTransactionTx(sqltransaction, &transaction, user) + if err != nil { + sqltransaction.Rollback() + WriteError(w, 999 /*Internal Error*/) + log.Print(err) + return + } } } diff --git a/imports.go b/imports.go index f50447f..669e73d 100644 --- a/imports.go +++ b/imports.go @@ -187,7 +187,9 @@ func ofxImportHelper(r io.Reader, w http.ResponseWriter, user *User, accountid i } // Move any splits with SecurityId but not AccountId to Imbalances - // accounts + // accounts. In the same loop, check to see if this transaction/split + // has been imported before + var already_imported bool for _, split := range transaction.Splits { if split.SecurityId != -1 || split.AccountId == -1 { imbalanced_account, err := GetImbalanceAccount(sqltransaction, user.UserId, split.SecurityId) @@ -201,9 +203,21 @@ func ofxImportHelper(r io.Reader, w http.ResponseWriter, user *User, accountid i split.AccountId = imbalanced_account.AccountId split.SecurityId = -1 } + + exists, err := split.AlreadyImportedTx(sqltransaction) + if err != nil { + sqltransaction.Rollback() + WriteError(w, 999 /*Internal Error*/) + log.Print("Error checking if split was already imported:", err) + return + } else if exists { + already_imported = true + } } - transactions = append(transactions, transaction) + if !already_imported { + transactions = append(transactions, transaction) + } } for _, transaction := range transactions { diff --git a/ofx.go b/ofx.go index 59f1ee6..19b65d2 100644 --- a/ofx.go +++ b/ofx.go @@ -80,7 +80,7 @@ func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *Account) er return errors.New("Internal error: security index not found in OFX import\n") } - s1.RemoteId = tran.FiTID.String() + s1.RemoteId = "ofx:" + tran.FiTID.String() // TODO CorrectFiTID/CorrectAction? security := i.Securities[account.SecurityId-1] diff --git a/transactions.go b/transactions.go index af4a19b..73b6f9b 100644 --- a/transactions.go +++ b/transactions.go @@ -61,6 +61,11 @@ func (s *Split) Valid() bool { return err == nil } +func (s *Split) AlreadyImportedTx(transaction *gorp.Transaction) (bool, error) { + count, err := transaction.SelectInt("SELECT COUNT(*) from splits where RemoteId=? and AccountId=?", s.RemoteId, s.AccountId) + return count == 1, err +} + type Transaction struct { TransactionId int64 UserId int64