diff --git a/gnucash.go b/gnucash.go index 7c61298..2549400 100644 --- a/gnucash.go +++ b/gnucash.go @@ -92,6 +92,7 @@ type GnucashTransaction struct { type GnucashSplit struct { SplitId string `xml:"http://www.gnucash.org/XML/split id"` + Status string `xml:"http://www.gnucash.org/XML/split reconciled-state"` AccountId string `xml:"http://www.gnucash.org/XML/split account"` Memo string `xml:"http://www.gnucash.org/XML/split memo"` Amount string `xml:"http://www.gnucash.org/XML/split quantity"` @@ -211,11 +212,20 @@ func ImportGnucash(r io.Reader) (*GnucashImport, error) { t := new(Transaction) t.Description = gt.Description t.Date = gt.DatePosted.Date.Time - t.Status = Imported for j := range gt.Splits { gs := gt.Splits[j] s := new(Split) s.Memo = gs.Memo + + switch gs.Status { + default: // 'n', or not present + s.Status = Imported + case "c": + s.Status = Cleared + case "y": + s.Status = Reconciled + } + account, ok := accountMap[gs.AccountId] if !ok { return nil, fmt.Errorf("Unable to find account: %s", gs.AccountId) diff --git a/imports.go b/imports.go index 5ad544d..6d1c2ad 100644 --- a/imports.go +++ b/imports.go @@ -109,7 +109,6 @@ func AccountImportHandler(w http.ResponseWriter, r *http.Request, user *User, ac var transactions []Transaction for _, transaction := range itl.Transactions { transaction.UserId = user.UserId - transaction.Status = Imported if !transaction.Valid() { sqltransaction.Rollback() @@ -122,6 +121,7 @@ func AccountImportHandler(w http.ResponseWriter, r *http.Request, user *User, ac // and fixup the SecurityId to be a valid one for this user's actual // securities instead of a placeholder from the import for _, split := range transaction.Splits { + split.Status = Imported if split.AccountId != -1 { if split.AccountId != importedAccount.AccountId { sqltransaction.Rollback() diff --git a/js/components/AccountRegister.js b/js/components/AccountRegister.js index a8f4e1c..d31dc46 100644 --- a/js/components/AccountRegister.js +++ b/js/components/AccountRegister.js @@ -35,11 +35,11 @@ var Big = require('big.js'); var models = require('../models'); var Security = models.Security; var Account = models.Account; +var SplitStatus = models.SplitStatus; +var SplitStatusList = models.SplitStatusList; +var SplitStatusMap = models.SplitStatusMap; var Split = models.Split; var Transaction = models.Transaction; -var TransactionStatus = models.TransactionStatus; -var TransactionStatusList = models.TransactionStatusList; -var TransactionStatusMap = models.TransactionStatusMap; var Error = models.Error; var getAccountDisplayName = require('../utils').getAccountDisplayName; @@ -70,6 +70,7 @@ const TransactionRow = React.createClass({ for (var i = 0; i < this.props.transaction.Splits.length; i++) { if (this.props.transaction.Splits[i].AccountId == this.props.account.AccountId) { thisAccountSplit = this.props.transaction.Splits[i]; + status = SplitStatusMap[this.props.transaction.Splits[i].Status]; break; } } @@ -89,7 +90,6 @@ const TransactionRow = React.createClass({ var amount = security.Symbol + " " + thisAccountSplit.Amount.toFixed(security.Precision); if (this.props.transaction.hasOwnProperty("Balance")) balance = security.Symbol + " " + this.props.transaction.Balance.toFixed(security.Precision); - status = TransactionStatusMap[this.props.transaction.Status]; number = thisAccountSplit.Number; } else { var amount = security.Symbol + " " + (new Big(0.0)).toFixed(security.Precision); @@ -216,19 +216,12 @@ const AddEditTransactionModal = React.createClass({ }) }); }, - handleStatusChange: function(status) { - if (status.hasOwnProperty('StatusId')) { - this.setState({ - transaction: react_update(this.state.transaction, { - Status: {$set: status.StatusId} - }) - }); - } - }, handleAddSplit: function() { + var split = new Split(); + split.Status = SplitStatus.Entered; this.setState({ transaction: react_update(this.state.transaction, { - Splits: {$push: [new Split()]} + Splits: {$push: [split]} }) }); }, @@ -248,6 +241,15 @@ const AddEditTransactionModal = React.createClass({ transaction: transaction }); }, + handleUpdateStatus: function(status, split) { + var transaction = this.state.transaction; + transaction.Splits[split] = react_update(transaction.Splits[split], { + Status: {$set: status.StatusId} + }); + this.setState({ + transaction: transaction + }); + }, handleUpdateMemo: function(split) { var transaction = this.state.transaction; transaction.Splits[split] = react_update(transaction.Splits[split], { @@ -345,6 +347,10 @@ const AddEditTransactionModal = React.createClass({ var j = i; return function() {self.handleUpdateNumber(j);}; })(); + var updateStatusFn = (function() { + var j = i; + return function(status) {self.handleUpdateStatus(status, j);}; + })(); var updateMemoFn = (function() { var j = i; return function() {self.handleUpdateMemo(j);}; @@ -374,7 +380,17 @@ const AddEditTransactionModal = React.createClass({ value={s.Number} onChange={updateNumberFn} ref={"number-"+i} /> - + + + - - Status - - - - # - Memo + Status + Memo Account Amount @@ -680,10 +684,11 @@ module.exports = React.createClass({ }, handleNewTransactionClicked: function() { var newTransaction = new Transaction(); - newTransaction.Status = TransactionStatus.Entered; newTransaction.Date = new Date(); newTransaction.Splits.push(new Split()); newTransaction.Splits.push(new Split()); + newTransaction.Splits[0].Status = SplitStatus.Entered; + newTransaction.Splits[1].Status = SplitStatus.Entered; newTransaction.Splits[0].AccountId = this.props.accounts[this.props.selectedAccount].AccountId; this.setState({ diff --git a/js/models.js b/js/models.js index 2e51657..8487dd3 100644 --- a/js/models.js +++ b/js/models.js @@ -202,11 +202,32 @@ Account.prototype.isRootAccount = function() { return this.ParentAccountId == empty_account.ParentAccountId; } +const SplitStatus = { + Imported: 1, + Entered: 2, + Cleared: 3, + Reconciled: 4, + Voided: 5 +} +var SplitStatusList = []; +for (var type in SplitStatus) { + if (SplitStatus.hasOwnProperty(type)) { + SplitStatusList.push({'StatusId': SplitStatus[type], 'Name': type}); + } +} +var SplitStatusMap = {}; +for (var status in SplitStatus) { + if (SplitStatus.hasOwnProperty(status)) { + SplitStatusMap[SplitStatus[status]] = status; + } +} + function Split() { this.SplitId = -1; this.TransactionId = -1; this.AccountId = -1; this.SecurityId = -1; + this.Status = -1; this.Number = ""; this.Memo = ""; this.Amount = new Big(0.0); @@ -219,6 +240,7 @@ Split.prototype.toJSONobj = function() { json_obj.TransactionId = this.TransactionId; json_obj.AccountId = this.AccountId; json_obj.SecurityId = this.SecurityId; + json_obj.Status = this.Status; json_obj.Number = this.Number; json_obj.Memo = this.Memo; json_obj.Amount = this.Amount.toFixed(); @@ -235,6 +257,8 @@ Split.prototype.fromJSONobj = function(json_obj) { this.AccountId = json_obj.AccountId; if (json_obj.hasOwnProperty("SecurityId")) this.SecurityId = json_obj.SecurityId; + if (json_obj.hasOwnProperty("Status")) + this.Status = json_obj.Status; if (json_obj.hasOwnProperty("Number")) this.Number = json_obj.Number; if (json_obj.hasOwnProperty("Memo")) @@ -253,31 +277,10 @@ Split.prototype.isSplit = function() { this.SecurityId != empty_split.SecurityId; } -const TransactionStatus = { - Imported: 1, - Entered: 2, - Cleared: 3, - Reconciled: 4, - Voided: 5 -} -var TransactionStatusList = []; -for (var type in TransactionStatus) { - if (TransactionStatus.hasOwnProperty(type)) { - TransactionStatusList.push({'StatusId': TransactionStatus[type], 'Name': type}); - } -} -var TransactionStatusMap = {}; -for (var status in TransactionStatus) { - if (TransactionStatus.hasOwnProperty(status)) { - TransactionStatusMap[TransactionStatus[status]] = status; - } -} - function Transaction() { this.TransactionId = -1; this.UserId = -1; this.Description = ""; - this.Status = -1; this.Date = new Date(); this.Splits = []; } @@ -287,7 +290,6 @@ Transaction.prototype.toJSON = function() { json_obj.TransactionId = this.TransactionId; json_obj.UserId = this.UserId; json_obj.Description = this.Description; - json_obj.Status = this.Status; json_obj.Date = this.Date.toJSON(); json_obj.Splits = []; for (var i = 0; i < this.Splits.length; i++) @@ -304,8 +306,6 @@ Transaction.prototype.fromJSON = function(json_input) { this.UserId = json_obj.UserId; if (json_obj.hasOwnProperty("Description")) this.Description = json_obj.Description; - if (json_obj.hasOwnProperty("Status")) - this.Status = json_obj.Status; if (json_obj.hasOwnProperty("Date")) { this.Date = json_obj.Date if (typeof this.Date === 'string') { @@ -541,9 +541,9 @@ module.exports = models = { AccountTypeList: AccountTypeList, SecurityType: SecurityType, SecurityTypeList: SecurityTypeList, - TransactionStatus: TransactionStatus, - TransactionStatusList: TransactionStatusList, - TransactionStatusMap: TransactionStatusMap, + SplitStatus: SplitStatus, + SplitStatusList: SplitStatusList, + SplitStatusMap: SplitStatusMap, // Constants BogusPassword: "password" diff --git a/ofx.go b/ofx.go index b072e3f..8408da2 100644 --- a/ofx.go +++ b/ofx.go @@ -43,7 +43,6 @@ func (i *OFXImport) GetAddCurrency(isoname string) (*Security, error) { func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *Account) error { var t Transaction - t.Status = Imported t.Date = tran.DtPosted.UTC() t.RemoteId = tran.FiTID.String() // TODO CorrectFiTID/CorrectAction? @@ -85,6 +84,9 @@ func (i *OFXImport) AddTransaction(tran *ofxgo.Transaction, account *Account) er s1.Amount = amt.FloatString(security.Precision) s2.Amount = amt.Neg(amt).FloatString(security.Precision) + s1.Status = Imported + s2.Status = Imported + s1.AccountId = account.AccountId s2.AccountId = -1 s1.SecurityId = -1 diff --git a/transactions.go b/transactions.go index f6731af..c7e68f8 100644 --- a/transactions.go +++ b/transactions.go @@ -14,9 +14,18 @@ import ( "time" ) +const ( + Imported int64 = 1 + Entered = 2 + Cleared = 3 + Reconciled = 4 + Voided = 5 +) + type Split struct { SplitId int64 TransactionId int64 + Status int64 // One of AccountId and SecurityId must be -1 // In normal splits, AccountId will be valid and SecurityId will be -1. The @@ -51,20 +60,11 @@ func (s *Split) Valid() bool { return err == nil } -const ( - Imported int64 = 1 - Entered = 2 - Cleared = 3 - Reconciled = 4 - Voided = 5 -) - type Transaction struct { TransactionId int64 UserId int64 RemoteId string // unique ID from server, for detecting duplicates Description string - Status int64 Date time.Time Splits []*Split `db:"-"` }