Merge branch 'maint'

* Remove build and run of no-longer-existant intl-scm/guile-strings.
* Bug 743807 Wrong date value being used.
* Bug 743807 Stops critical error messages.
* Bug 727466 - The symbol of CNY changed to 元
* Remove explicit install of Finance::Quote dependencies.
* Updated Danish translation. From the translation project.
* Bug 649933 - Creating cash flow report takes a long time
* Bug 733685 - Fancy Date Format doesn't stick
* Fix potential infinite loop in business lot scrubbing
* Add scrubbing function to recover dangling lot links and payments
This commit is contained in:
Geert Janssens 2015-02-22 20:23:23 +01:00
commit 118615d738
10 changed files with 320 additions and 993 deletions

View File

@ -184,8 +184,6 @@ libtool: $(LIBTOOL_DEPS)
.PHONY: pot
pot: Makefile po/POTFILES.in
rm -f intl-scm/guile-strings.c
${MAKE} -C intl-scm
rm -f po/$(PACKAGE).pot
${MAKE} -C po $(PACKAGE).pot

1079
po/da.po

File diff suppressed because it is too large Load Diff

View File

@ -82,31 +82,33 @@ scrub_other_link (GNCLot *from_lot, Split *ll_from_split,
GNCLot *to_lot, Split *ll_to_split)
{
Split *real_from_split; // This refers to the split in the payment lot representing the payment itself
gnc_numeric from_val, real_from_val, to_val;
gboolean modified = FALSE;
gnc_numeric real_from_val;
gnc_numeric from_val = xaccSplitGetValue (ll_from_split);
gnc_numeric to_val = xaccSplitGetValue (ll_to_split);
Transaction *ll_txn = xaccSplitGetParent (ll_to_split);
// Per iteration we can only scrub at most max (val-doc-split, val-pay-split)
// So split the bigger one in two if needed and continue with the equal valued splits only
// The remainder is added to the lot link transaction and the lot to keep everything balanced
// and will be processed in a future iteration
modified = reduce_biggest_split (ll_from_split, ll_to_split);
// Per iteration we can only scrub at most min (val-doc-split, val-pay-split)
// So set the ceiling for finding a potential offsetting split in the lot
if (gnc_numeric_compare (gnc_numeric_abs (from_val), gnc_numeric_abs (to_val)) >= 0)
from_val = gnc_numeric_neg (to_val);
// Next we have to find the original payment split so we can
// add (part of) it to the document lot
real_from_split = gncOwnerFindOffsettingSplit (from_lot, xaccSplitGetValue (ll_from_split));
real_from_split = gncOwnerFindOffsettingSplit (from_lot, from_val);
if (!real_from_split)
return modified; // No usable split in the payment lot
return FALSE; // No usable split in the payment lot
// Here again per iteration we can only scrub at most max (val-other-pay-split, val-pay-split)
// So split the bigger one in two if needed and continue with the equal valued splits only
// We now have found 3 splits involved in the scrub action:
// 2 lot link splits which we want to reduce
// 1 other split to move into the original lot instead of the lot link split
// As said only value of the split can be offset.
// So split the bigger ones in two if needed and continue with equal valued splits only
// The remainder is added to the lot link transaction and the lot to keep everything balanced
// and will be processed in a future iteration
modified = reduce_biggest_split (real_from_split, ll_from_split);
// Once more check for max (val-doc-split, val-pay-split), and reduce if necessary.
// It may have changed while looking for the real payment split
modified = reduce_biggest_split (ll_from_split, ll_to_split);
modified |= reduce_biggest_split (real_from_split, ll_from_split);
modified |= reduce_biggest_split (ll_from_split, ll_to_split);
// At this point ll_to_split and real_from_split should have the same value
// If not, flag a warning and skip to the next iteration
@ -116,8 +118,11 @@ scrub_other_link (GNCLot *from_lot, Split *ll_from_split,
if (!gnc_numeric_equal (real_from_val, to_val))
{
// This is unexpected - write a warning message and skip this split
PWARN("real_from_val and to_val differ. "
"This is unexpected! Skip scrubbing of real_from_split %p against ll_to_split %p.", real_from_split, ll_to_split);
PWARN("real_from_val (%s) and to_val (%s) differ. "
"This is unexpected! Skip scrubbing of real_from_split %p against ll_to_split %p.",
gnc_numeric_to_string (real_from_val), // gnc_numeric_denom (real_from_val),
gnc_numeric_to_string (to_val), // gnc_numeric_denom (to_val),
real_from_split, ll_to_split);
return modified;
}
@ -185,7 +190,7 @@ scrub_start:
if (sl_split == ll_txn_split)
continue; // next lot link transaction split
// Only splits of opposite sign can be scrubbed
// Only splits of opposite signed values can be scrubbed
if (gnc_numeric_positive_p (xaccSplitGetValue (sl_split)) ==
gnc_numeric_positive_p (xaccSplitGetValue (ll_txn_split)))
continue; // next lot link transaction split
@ -251,11 +256,160 @@ scrub_start:
return modified;
}
// Note this is a recursive function. It presumes the number of splits
// in avail_splits is relatively low. With many splits the performance will
// quickly degrade.
// Careful: this function assumes all splits in avail_splits to be valid
// and with values of opposite sign of target_value
// Ignoring this can cause unexpected results!
static SplitList *
gncSLFindOffsSplits (SplitList *avail_splits, gnc_numeric target_value)
{
gint curr_recurse_level = 0;
gint max_recurse_level = g_list_length (avail_splits) - 1;
if (!avail_splits)
return NULL;
for (curr_recurse_level = 0;
curr_recurse_level <= max_recurse_level;
curr_recurse_level++)
{
SplitList *split_iter = NULL;
for (split_iter = avail_splits; split_iter; split_iter = split_iter->next)
{
Split *split = split_iter->data;
SplitList *match_splits = NULL;
gnc_numeric split_value, remaining_value;
split_value = xaccSplitGetValue (split);
// Attention: target_value and split_value are of opposite sign
// So to get the remaining target value, they should be *added*
remaining_value = gnc_numeric_add (target_value, split_value,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
if (curr_recurse_level == 0)
{
if (gnc_numeric_zero_p (remaining_value))
match_splits = g_list_prepend (NULL, split);
}
else
{
if (gnc_numeric_positive_p (target_value) ==
gnc_numeric_positive_p (remaining_value))
match_splits = gncSLFindOffsSplits (split_iter->next,
remaining_value);
}
if (match_splits)
return g_list_prepend (match_splits, split);
}
}
return NULL;
}
static gboolean
gncScrubLotDanglingPayments (GNCLot *lot)
{
SplitList * split_list, *filtered_list = NULL, *match_list = NULL, *node;
Split *ll_split = gnc_lot_get_earliest_split (lot);
Transaction *ll_trans = xaccSplitGetParent (ll_split);
gnc_numeric ll_val = xaccSplitGetValue (ll_split);
time64 ll_date = xaccTransGetDate (ll_trans);
const char *ll_desc = xaccTransGetDescription (ll_trans);
// look for free splits (i.e. not in any lot) which,
// compared to the lot link split
// - have the same date
// - have the same description
// - have an opposite sign amount
// - free split's abs value is less than or equal to ll split's abs value
split_list = xaccAccountGetSplitList(gnc_lot_get_account (lot));
for (node = split_list; node; node = node->next)
{
Split *free_split = node->data;
Transaction *free_trans;
gnc_numeric free_val;
if (NULL != xaccSplitGetLot(free_split))
continue;
free_trans = xaccSplitGetParent (free_split);
if (ll_date != xaccTransGetDate (free_trans))
continue;
if (0 != g_strcmp0 (ll_desc, xaccTransGetDescription (free_trans)))
continue;
free_val = xaccSplitGetValue (free_split);
if (gnc_numeric_positive_p (ll_val) ==
gnc_numeric_positive_p (free_val))
continue;
if (gnc_numeric_compare (gnc_numeric_abs (free_val), gnc_numeric_abs (ll_val)) > 0)
continue;
filtered_list = g_list_append(filtered_list, free_split);
}
match_list = gncSLFindOffsSplits (filtered_list, ll_val);
g_list_free (filtered_list);
for (node = match_list; node; node = node->next)
{
Split *match_split = node->data;
gnc_lot_add_split (lot, match_split);
}
if (match_list)
{
g_list_free (match_list);
return TRUE;
}
else
return FALSE;
}
static gboolean
gncScrubLotIsSingleLotLinkSplit (GNCLot *lot)
{
Split *split = NULL;
Transaction *trans = NULL;
// Lots with a single split which is also a lot link transaction split
// may be sign of a dangling payment. Let's try to fix that
// Only works for single split lots...
if (1 != gnc_lot_count_splits (lot))
return FALSE;
split = gnc_lot_get_earliest_split (lot);
trans = xaccSplitGetParent (split);
if (!trans)
{
// Ooops - the split doesn't belong to any transaction !
// This is not expected so issue a warning and continue with next split
PWARN("Encountered a split in a business lot that's not part of any transaction. "
"This is unexpected! Skipping split %p.", split);
return FALSE;
}
// Only works if single split belongs to a lot link transaction...
if (xaccTransGetTxnType (trans) != TXN_TYPE_LINK)
return FALSE;
return TRUE;
}
gboolean
gncScrubBusinessLot (GNCLot *lot)
{
gboolean splits_deleted = FALSE;
gboolean dangling_payments = FALSE;
gboolean dangling_lot_link = FALSE;
Account *acc;
gchar *lotname=NULL;
@ -272,6 +426,21 @@ gncScrubBusinessLot (GNCLot *lot)
xaccScrubMergeLotSubSplits (lot, FALSE);
splits_deleted = gncScrubLotLinks (lot);
// Look for dangling payments and repair if found
dangling_lot_link = gncScrubLotIsSingleLotLinkSplit (lot);
if (dangling_lot_link)
{
dangling_payments = gncScrubLotDanglingPayments (lot);
if (dangling_payments)
splits_deleted |= gncScrubLotLinks (lot);
else
{
Split *split = gnc_lot_get_earliest_split (lot);
Transaction *trans = xaccSplitGetParent (split);
xaccTransDestroy (trans);
}
}
// If lot is empty now, delete it
if (0 == gnc_lot_count_splits (lot))
{
@ -282,7 +451,9 @@ gncScrubBusinessLot (GNCLot *lot)
if (acc)
xaccAccountCommitEdit(acc);
LEAVE ("(lot=%s, deleted=%d)", lotname ? lotname : "(no lotname)", splits_deleted);
LEAVE ("(lot=%s, deleted=%d, dangling lot link=%d, dangling_payments=%d)",
lotname ? lotname : "(no lotname)", splits_deleted, dangling_lot_link,
dangling_payments);
g_free (lotname);
return splits_deleted;

View File

@ -674,6 +674,7 @@
local-symbol="$"
/>
<!-- "CNY" - "Yuan Renminbi"
locale-symbol has been changed from 元 to CN¥ following a discussion on bug 727466
-->
<currency
isocode="CNY"
@ -684,7 +685,7 @@
exchange-code="156"
parts-per-unit="100"
smallest-fraction="100"
local-symbol=""
local-symbol="CN¥"
/>
<!-- "COP" - "Colombian Peso"
-->
@ -1361,7 +1362,7 @@
exchange-code="392"
parts-per-unit="100"
smallest-fraction="1"
local-symbol="¥"
local-symbol="JP¥"
/>
<!-- "KES" - "Kenyan Shilling"
-->

View File

@ -254,6 +254,10 @@ gnc_handle_date_accelerator (GdkEventKey *event,
if ((tm->tm_mday <= 0) || (tm->tm_mon == -1) || (tm->tm_year == -1))
return FALSE;
// Make sure we have a valid date before we proceed
if (!g_date_valid_dmy (tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900))
return FALSE;
g_date_set_dmy (&gdate,
tm->tm_mday,
tm->tm_mon + 1,

View File

@ -345,7 +345,7 @@ gnc_date_format_get_months (GNCDateFormat *gdf)
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->months_abbrev)))
return GNCDATE_MONTH_ABBREV;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->months_name)))
return GNCDATE_MONTH_ABBREV;
return GNCDATE_MONTH_NAME;
/* We should never reach this point */
g_assert(FALSE);

View File

@ -438,7 +438,7 @@ get_filter_times (CsvExportInfo *info)
}
else
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(info->csvd.start_date_today)))
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(info->csvd.end_date_today)))
info->csvd.end_time = gnc_time64_get_today_end();
else
info->csvd.end_time = gnc_time (NULL);

View File

@ -555,6 +555,7 @@ Select the type of Export required and the separator that will be used.
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">end_date_latest</property>
<signal name="clicked" handler="csv_export_end_date_cb" swapped="no"/>
</object>
<packing>
@ -575,7 +576,7 @@ Select the type of Export required and the separator that will be used.
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">end_date_choose</property>
<property name="group">end_date_latest</property>
<signal name="clicked" handler="csv_export_end_date_cb" swapped="no"/>
</object>
<packing>
@ -597,7 +598,6 @@ Select the type of Export required and the separator that will be used.
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">end_date_choose</property>
<signal name="clicked" handler="csv_export_end_date_cb" swapped="no"/>
</object>
<packing>

View File

@ -36,11 +36,6 @@ if ($( != 0) {
exit 0 if ($input ne "y");
}
CPAN::Shell->install('Date::Manip');
CPAN::Shell->install('HTML::TableExtract');
CPAN::Shell->install('HTTP::Request::Common');
CPAN::Shell->install('Crypt::SSLeay');
CPAN::Shell->install('LWP');
CPAN::Shell->install('Finance::Quote');
## Local Variables:

View File

@ -260,7 +260,8 @@
(for-each
(lambda (split)
(set! work-done (+ 1 work-done))
(gnc:report-percent-done (* 85 (/ work-done splits-to-do)))
(if (= (modulo work-done 100) 0)
(gnc:report-percent-done (* 85 (/ work-done splits-to-do))))
(let ((parent (xaccSplitGetParent split)))
(if (and (gnc:timepair-le (gnc-transaction-get-date-posted parent) to-date-tp)
(gnc:timepair-ge (gnc-transaction-get-date-posted parent) from-date-tp))