Update price database for imported transactions

When a transaction is added from the ledger, price database is updated properly.
But if the transaction is imported, there is no price db update.

This change adds the proper pricedb update in the import path (qfx/ofx/qif).
Tested with make check
This commit is contained in:
Dong Lin 2021-02-21 13:03:39 -08:00 committed by John Ralls
parent 228f145bba
commit 75209c024f
10 changed files with 122 additions and 83 deletions

View File

@ -421,6 +421,7 @@ void qof_book_set_string_option(QofBook* book, const char* opt_name, const char*
SET_ENUM("PRICE-SOURCE-USER-PRICE"); SET_ENUM("PRICE-SOURCE-USER-PRICE");
SET_ENUM("PRICE-SOURCE-XFER-DLG-VAL"); SET_ENUM("PRICE-SOURCE-XFER-DLG-VAL");
SET_ENUM("PRICE-SOURCE-SPLIT-REG"); SET_ENUM("PRICE-SOURCE-SPLIT-REG");
SET_ENUM("PRICE-SOURCE-SPLIT-IMPORT");
SET_ENUM("PRICE-SOURCE-STOCK-SPLIT"); SET_ENUM("PRICE-SOURCE-STOCK-SPLIT");
SET_ENUM("PRICE-SOURCE-TEMP"); SET_ENUM("PRICE-SOURCE-TEMP");
SET_ENUM("PRICE-SOURCE-INVALID"); SET_ENUM("PRICE-SOURCE-INVALID");

View File

@ -840,6 +840,7 @@ gnc_import_process_trans_item (GncImportMatchMap *matchmap,
{ {
Split * other_split; Split * other_split;
gnc_numeric imbalance_value; gnc_numeric imbalance_value;
Transaction *trans;
/* DEBUG("Begin"); */ /* DEBUG("Begin"); */
@ -894,7 +895,9 @@ gnc_import_process_trans_item (GncImportMatchMap *matchmap,
xaccSplitSetDateReconciledSecs(gnc_import_TransInfo_get_fsplit (trans_info), xaccSplitSetDateReconciledSecs(gnc_import_TransInfo_get_fsplit (trans_info),
gnc_time (NULL)); gnc_time (NULL));
/* Done editing. */ /* Done editing. */
xaccTransCommitEdit(gnc_import_TransInfo_get_trans (trans_info)); trans = gnc_import_TransInfo_get_trans (trans_info);
xaccTransCommitEdit(trans);
xaccTransRecordPrice(trans, PRICE_SOURCE_SPLIT_IMPORT);
return TRUE; return TRUE;
case GNCImport_UPDATE: case GNCImport_UPDATE:
{ {

View File

@ -444,7 +444,8 @@
progress-dialog) progress-dialog)
;; rebalance and commit everything ;; rebalance and commit everything
(xaccTransCommitEdit gnc-xtn)))) (xaccTransCommitEdit gnc-xtn)
(xaccTransRecordPrice gnc-xtn PRICE-SOURCE-SPLIT-IMPORT))))
(qif-file:xtns qif-file))) (qif-file:xtns qif-file)))
sorted-qif-files-list) sorted-qif-files-list)

View File

@ -1958,6 +1958,7 @@ gnc_split_register_save (SplitRegister* reg, gboolean do_commit)
} }
unreconcile_splits (reg); unreconcile_splits (reg);
xaccTransCommitEdit (trans); xaccTransCommitEdit (trans);
xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
} }
gnc_table_clear_current_cursor_changes (reg->table); gnc_table_clear_current_cursor_changes (reg->table);
@ -2203,79 +2204,6 @@ recalculate_value (Split* split, SplitRegister* reg,
} }
} }
static void
record_price (SplitRegister* reg, Account* account, gnc_numeric value,
PriceSource source)
{
Transaction* trans = gnc_split_register_get_current_trans (reg);
QofBook* book = qof_instance_get_book (QOF_INSTANCE (account));
GNCPriceDB* pricedb = gnc_pricedb_get_db (book);
gnc_commodity* comm = xaccAccountGetCommodity (account);
gnc_commodity* curr = xaccTransGetCurrency (trans);
GNCPrice* price;
gnc_numeric price_value;
int scu = gnc_commodity_get_fraction (curr);
time64 time;
BasicCell* cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
gboolean swap = FALSE;
/* Only record the price for account types that don't have a
* "rate" cell. They'll get handled later by
* gnc_split_register_handle_exchange.
*/
if (gnc_split_reg_has_rate_cell (reg->type))
return;
gnc_date_cell_get_date ((DateCell*)cell, &time, TRUE);
price = gnc_pricedb_lookup_day_t64 (pricedb, comm, curr, time);
if (gnc_commodity_equiv (comm, gnc_price_get_currency (price)))
swap = TRUE;
if (price)
{
price_value = gnc_price_get_value (price);
if (gnc_numeric_equal (swap ? gnc_numeric_invert (value) : value,
price_value))
{
gnc_price_unref (price);
return;
}
if (gnc_price_get_source (price) < PRICE_SOURCE_XFER_DLG_VAL)
{
/* Existing price is preferred over this one. */
gnc_price_unref (price);
return;
}
if (swap)
{
value = gnc_numeric_invert (value);
scu = gnc_commodity_get_fraction (comm);
}
value = gnc_numeric_convert (value, scu * COMMODITY_DENOM_MULT,
GNC_HOW_RND_ROUND_HALF_UP);
gnc_price_begin_edit (price);
gnc_price_set_time64 (price, time);
gnc_price_set_source (price, source);
gnc_price_set_typestr (price, PRICE_TYPE_TRN);
gnc_price_set_value (price, value);
gnc_price_commit_edit (price);
gnc_price_unref (price);
return;
}
value = gnc_numeric_convert (value, scu * COMMODITY_DENOM_MULT,
GNC_HOW_RND_ROUND_HALF_UP);
price = gnc_price_create (book);
gnc_price_begin_edit (price);
gnc_price_set_commodity (price, comm);
gnc_price_set_currency (price, curr);
gnc_price_set_time64 (price, time);
gnc_price_set_source (price, source);
gnc_price_set_typestr (price, PRICE_TYPE_TRN);
gnc_price_set_value (price, value);
gnc_pricedb_add_price (pricedb, price);
gnc_price_commit_edit (price);
}
static gboolean static gboolean
gnc_split_register_auto_calc (SplitRegister* reg, Split* split) gnc_split_register_auto_calc (SplitRegister* reg, Split* split)
{ {
@ -2447,14 +2375,6 @@ gnc_split_register_auto_calc (SplitRegister* reg, Split* split)
if (recalc_value) if (recalc_value)
recalculate_value (split, reg, price, amount, shares_changed); recalculate_value (split, reg, price, amount, shares_changed);
if (price_changed)
{
cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
PRIC_CELL);
price = gnc_price_cell_get_value (cell);
if (gnc_numeric_positive_p (price))
record_price (reg, account, price, source);
}
return TRUE; return TRUE;
} }

View File

@ -2938,6 +2938,100 @@ xaccTransFindSplitByAccount(const Transaction *trans, const Account *acc)
return NULL; return NULL;
} }
static void
record_price (Split *split,
PriceSource source)
{
Transaction *trans;
Account *account;
QofBook* book;
GNCPriceDB* pricedb;
gnc_commodity* comm;
gnc_commodity* curr;
GNCPrice* price;
gnc_numeric price_value, value, amount;
int scu;
time64 time;
gboolean swap;
account = xaccSplitGetAccount (split);
if (!xaccAccountIsPriced (account))
{
return;
}
amount = xaccSplitGetAmount (split);
if (gnc_numeric_zero_p (amount))
{
return;
}
trans = xaccSplitGetParent (split);
value = gnc_numeric_div (xaccSplitGetValue (split), amount,
GNC_DENOM_AUTO,
GNC_HOW_DENOM_EXACT);
book = qof_instance_get_book (QOF_INSTANCE (account));
pricedb = gnc_pricedb_get_db (book);
comm = xaccAccountGetCommodity (account);
curr = xaccTransGetCurrency (trans);
scu = gnc_commodity_get_fraction (curr);
swap = FALSE;
time = xaccTransGetDate (trans);
price = gnc_pricedb_lookup_day_t64 (pricedb, comm, curr, time);
if (gnc_commodity_equiv (comm, gnc_price_get_currency (price)))
swap = TRUE;
if (price)
{
price_value = gnc_price_get_value (price);
if (gnc_numeric_equal (swap ? gnc_numeric_invert (value) : value,
price_value))
{
gnc_price_unref (price);
return;
}
if (gnc_price_get_source (price) < source)
{
/* Existing price is preferred over this one. */
gnc_price_unref (price);
return;
}
if (swap)
{
value = gnc_numeric_invert (value);
scu = gnc_commodity_get_fraction (comm);
}
value = gnc_numeric_convert (value, scu * COMMODITY_DENOM_MULT,
GNC_HOW_RND_ROUND_HALF_UP);
gnc_price_begin_edit (price);
gnc_price_set_time64 (price, time);
gnc_price_set_source (price, source);
gnc_price_set_typestr (price, PRICE_TYPE_TRN);
gnc_price_set_value (price, value);
gnc_price_commit_edit (price);
gnc_price_unref (price);
return;
}
value = gnc_numeric_convert (value, scu * COMMODITY_DENOM_MULT,
GNC_HOW_RND_ROUND_HALF_UP);
price = gnc_price_create (book);
gnc_price_begin_edit (price);
gnc_price_set_commodity (price, comm);
gnc_price_set_currency (price, curr);
gnc_price_set_time64 (price, time);
gnc_price_set_source (price, source);
gnc_price_set_typestr (price, PRICE_TYPE_TRN);
gnc_price_set_value (price, value);
gnc_pricedb_add_price (pricedb, price);
gnc_price_commit_edit (price);
}
void
xaccTransRecordPrice (Transaction *trans, PriceSource source)
{
/* XXX: This should have been part of xaccSplitCommitEdit. */
for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
record_price (n->data, source);
}
/********************************************************************\ /********************************************************************\
\********************************************************************/ \********************************************************************/

View File

@ -92,6 +92,7 @@ typedef struct _TransactionClass TransactionClass;
#include "gnc-commodity.h" #include "gnc-commodity.h"
#include "gnc-engine.h" #include "gnc-engine.h"
#include "gnc-pricedb.h"
#include "Split.h" #include "Split.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -767,6 +768,15 @@ time64 xaccTransGetVoidTime(const Transaction *tr);
void xaccTransDump (const Transaction *trans, const char *tag); void xaccTransDump (const Transaction *trans, const char *tag);
#endif #endif
/** The xaccTransRecordPrice() method iterates through the splits and
* and record the non-currency equivalent prices in the price database.
*
* @param trans The transaction whose price is recorded
* @param source The price priority level
*/
void xaccTransRecordPrice (Transaction *trans, PriceSource source);
#define RECONCILED_MATCH_TYPE "reconciled-match" #define RECONCILED_MATCH_TYPE "reconciled-match"
/** \deprecated */ /** \deprecated */

View File

@ -124,6 +124,7 @@ static const char* source_names[(size_t)PRICE_SOURCE_INVALID + 1] =
/* String retained for backwards compatibility. */ /* String retained for backwards compatibility. */
"user:xfer-dialog", "user:xfer-dialog",
"user:split-register", "user:split-register",
"user:split-import",
"user:stock-split", "user:stock-split",
"user:invoice-post", /* Retained for backwards compatibility */ "user:invoice-post", /* Retained for backwards compatibility */
"temporary", "temporary",

View File

@ -173,6 +173,7 @@ typedef enum
PRICE_SOURCE_USER_PRICE, // "user:price" PRICE_SOURCE_USER_PRICE, // "user:price"
PRICE_SOURCE_XFER_DLG_VAL, // "user:xfer-dialog" PRICE_SOURCE_XFER_DLG_VAL, // "user:xfer-dialog"
PRICE_SOURCE_SPLIT_REG, // "user:split-register" PRICE_SOURCE_SPLIT_REG, // "user:split-register"
PRICE_SOURCE_SPLIT_IMPORT, // "user:split-import"
PRICE_SOURCE_STOCK_SPLIT, // "user:stock-split" PRICE_SOURCE_STOCK_SPLIT, // "user:stock-split"
PRICE_SOURCE_INVOICE, // "user:invoice-post" PRICE_SOURCE_INVOICE, // "user:invoice-post"
PRICE_SOURCE_TEMP, // "temporary" PRICE_SOURCE_TEMP, // "temporary"

View File

@ -144,3 +144,10 @@ xaccTransDestroy (Transaction *trans)
ASSERT_TRUE(GNC_IS_MOCKTRANSACTION(trans)); ASSERT_TRUE(GNC_IS_MOCKTRANSACTION(trans));
gnc_mocktransaction(trans)->destroy(); gnc_mocktransaction(trans)->destroy();
} }
void
xaccTransRecordPrice (Transaction *trans, PriceSource source)
{
g_return_if_fail(GNC_IS_MOCKTRANSACTION(trans));
((MockTransaction*)trans)->recordPrice();
}

View File

@ -66,6 +66,7 @@ public:
MOCK_CONST_METHOD0(get_num, const char *()); MOCK_CONST_METHOD0(get_num, const char *());
MOCK_CONST_METHOD0(is_open, gboolean()); MOCK_CONST_METHOD0(is_open, gboolean());
MOCK_METHOD0(destroy, void()); MOCK_METHOD0(destroy, void());
MOCK_METHOD0(recordPrice, void());
protected: protected:
// Protect destructor to avoid MockTransaction objects to be created on stack. MockTransaction // Protect destructor to avoid MockTransaction objects to be created on stack. MockTransaction