mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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:
commit
118615d738
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
-->
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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:
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user