2614 Commits
Author SHA1 Message Date
Christopher Lam 874207e1cc [sixtp-dom-generators.cpp] don't heap allocate 0.5KiB for date
32 bytes on stack is more than adequate for YYYY-MM-DD
and it's ASCII, no need to utf8 sanitize
2026-10-18 20:07:55 +08:00
Christopher Lam 9e39744aac [qoflog.cpp] plug GKeyFile leak on error
also prevent std::string copies
2026-10-14 07:50:11 +08:00
John Ralls b183b507f2 Merge Noah Noerr's 'price-set-source-string-warn' into stable. 2026-10-09 16:20:24 -07:00
Christopher Lam 54ee116f20 [gtest-ui-util.cpp] add test suite for gnc-ui-util.cpp 2026-10-09 07:48:56 +08:00
Christopher Lam 1f364bd9bd [gnc-ui-util.cpp] fix numeric_to_words (gnc_numeric)
no more infinite loop in some cases, no fudge, exact arithmetic
2026-10-09 07:48:52 +08:00
Christopher Lam 887dfcaad6 [gnc-ui-util.cpp] remove number_to_words (double,int64_t) 2026-10-09 07:29:01 +08:00
Brent McBride 22e9ff9a49 Use xaccAccountGetSplitsSize in cap-gains regression test
Per review: faster than g_list_length(xaccAccountGetSplitList()) and
avoids leaking the returned list.
2026-10-02 20:57:00 -07:00
Brent McBride 5a4115d370 Resolve both gains splits in xaccSplitDetermineGainStatus
Rework xaccSplitDetermineGainStatus() to resolve the gain status of
both ends of a marker/source pair in a single call, and to use the
xaccSplitGetGainsSourceSplit() accessor instead of a raw KVP lookup.

When the function resolves one split it now also resolves its partner
(the source for a marker, the marker for a source) if that partner is
still UNKNOWN. This makes gain-status resolution order-independent:
whichever split xaccSplitComputeCapGains() reaches first, the other is
already resolved, so the marker->source switch-over no longer finds an
unresolved source and never re-creates an orphaned gains split.

This supersedes the one-line switch-over patch in cap-gains.cpp, which
is reverted.
2026-10-02 15:15:00 -07:00
Brent McBride 1e27fd17dc Add regression test for cap-gains marker/source switch-over
Builds a FIFO lot (buy + sell) with a pre-existing Realized Gain/Loss
transaction and the gains-split/gains-source KVP links, then simulates
a just-loaded state where the gains marker reaches
xaccSplitComputeCapGains() before its source is resolved (the order
that reproduces on MySQL and is masked on SQLite). Asserts the existing
gains split is reused rather than duplicated into an orphan.

Fails (2 != 1) without the switch-over resolve fix, passes with it.
2026-10-02 10:40:54 -07:00
Brent McBride 872612a26b Fix mass re-orphaning of cap-gains splits during lot scrub
xaccSplitComputeCapGains() performs a marker->source switch-over when a
gains marker split is processed before its source. The switch-over did
not resolve the source's in-memory gain status, so the source was left
with gains==UNKNOWN and gains_split==nullptr even though its forward
gains-split KVP was intact. The subsequent lookup read nullptr and the
code created a brand-new gains transaction routed to Orphaned Gains,
duplicating hundreds of already-settled gains splits on SQL books whose
history contains a stock split.

Resolve the source's gain status immediately after the switch-over so
its existing gains split is reused instead of being re-created.

This latent bug (original cap-gains code, ~2003) was exposed by the
5.17 adjusted_amount work (1e654412ab, b1efe0763c) which recomputes
already-booked gains in stock-split accounts. It is order-sensitive,
which is why it reproduces on MySQL but not SQLite.
2026-10-02 00:30:39 -07:00
Christopher Lam 9414fdf546 [ScrubBusiness.c] don't reassign splits when restarting for loop
this plugs GList* leak upon restart
2026-10-02 05:51:40 +08:00
John Ralls 56ccad9a66 Bug 799821 - £ symbol across whole UI shows as £
Windows: Get UTF16 localization strings and convert them thus bypassing
the code page problem entirely.
2026-09-29 15:32:35 -07:00
Noerr 5d5cd0b758 [engine] gnc_price_set_source_string: warn on an unknown source string
The setter maps a fixed set of canonical strings (source_names) to the
PriceSource enum. On any other string it fell through the loop and returned
having changed nothing -- silently -- so callers on the XML and SQL load paths,
the GUI price editor, and (until deprecated) the bindings got no indication that
the source was dropped. Emit a PWARN so an unrecognized source string is at least
visible in the log instead of vanishing.

Kept at WARNING rather than CRITICAL: this setter is primarily a deserialization
helper fed stored data, so an unrecognized string is unexpected external data,
not a broken precondition. A garbage source in a SQL backend -- for which there
is no repair path -- should not log a CRITICAL on every open; the price still
loads and only its source label degrades to PRICE_SOURCE_INVALID.

"invalid", the string form of PRICE_SOURCE_INVALID, reaches this fall-through as
well. INVALID is only the loop sentinel, never a settable source, so it is warned
uniformly like any other non-settable string. This is a real, non-corrupt case:
the random-price test generator and existing books both hold PRICE_SOURCE_INVALID
prices that serialize as "invalid" and round-trip back through here.

The warning names the offending price -- commodity namespace:mnemonic -> currency
mnemonic and its date -- so a user who finds it in the trace log has enough to
locate the price in the price editor and correct or remove it. The commodity,
currency and date are already populated when the source is set on both load
paths (the SQL col_table and the XML element order both place source last).
2026-09-26 13:50:55 -07:00
Christopher Lam 5888a04a8e [account.cpp] use gnc_account_foreach_split_between_dates 2026-09-26 23:18:59 +08:00
Christopher Lam 3bbf74a730 [account.hpp] introduce gnc_account_foreach_split_between_dates
A templated account->splits iterator, will target splits from
start_date to end_date, inclusive of date boundaries. Also optionally
include descendants.
2026-09-26 23:18:59 +08:00
John Ralls cb304edfa6 Bug 799813 - gnucash-cli issue for price updates using Postgressql back-end
Reorder the CLI quotes get startup sequence to load GncQuotes before
loading the session so that preconfigured quote sources don't null
out other supported sources.

Make the SQL backend create a new source when an unknown one is found in
the commodities table like the XML backend does.

Thanks to  Ganesh Suriyanarayanan for diagnosing the problem and
proposing a solution.
2026-09-22 15:52:16 -07:00
John Ralls 3c9cfbb916 Merge Roy Hansen's 'improve/natural-sort-id-columns' into stable. 2026-09-19 17:08:55 -07:00
Christopher Lam fb2c773bf6 [libgnucash/app-utils/test] test shouldn't include gnc-gnome-utils 2026-09-18 18:39:36 +08:00
Roy Hansen 1969d781e4 Sort Id columns naturally in qof-query, which is used in gnucash search
dialogs.

Changed sorting to be natural (chunks), instead of sequential ascii-sort.
Number chunks are compared as whole numbers instead of one at a time.
2026-09-18 10:50:00 +02:00
Roy Hansen 06f7324e58 Sort Id columns naturally in gnc-tree-views.
Changed sorting to be natural (chunks), instead of sequential ascii-sort.
Number chunks are compared as whole numbers instead of one at a time.

After this change, customer-overview, vendor-overview and
employee-overview will naturally sort "id" columns.
2026-09-18 10:50:00 +02:00
Christopher Lam 00cc11fb05 [Transaction.cpp] use g_list_sort to partition splits
because g_list_sort is a stable sort, and can partition trans->splits
into neg < !neg efficiently
2026-09-06 23:34:46 +08:00
PRG-112 f5f133e104 Enhancement - New global properties for CHARTS (GC's level)
This one a is quite an improvement on customisation of reports/charts. User can decide now what kind of point style should be used, including size, hover range and such.

On top of that:
- some tooltip improvements were made as well, including configurable one in GC's Properties.
- Price Scatterplot - fixed colors, got rid of a superfluous markers
- global defaults to be tuned in the next batch

Settings available at: GnuCash -> Edit -> Preferences -> Reports
2026-08-31 20:34:24 +02:00
Bruce Schuck 7745f89580 Removed MorningstarUK and MorningstarCH 2026-08-10 12:23:22 -07:00
Christopher Lam a4f69f44a7 [Transaction.cpp] null check before accessing struct member 2026-08-06 22:27:34 +08:00
John Ralls 332db182f2 Document that transaction void-time invalid value is now INT64_MAX. 2026-07-18 16:49:05 -07:00
John Ralls 6e33c23815 Bug 799791 - Unvoid is not available (Bug from the mailing lists)
Use the existence of void timestamp instead of void reason to
determine if a transaction is voided. A user can void a transaction
without providing a reason.
2026-07-18 10:25:17 -07:00
Christopher Lam 36bd906b67 [gnc-euro.cpp] use GncNumeric.convert() instead of gnc_numeric_convert 2026-07-16 17:03:15 +08:00
John Ralls b766c126ee Merge Sherlock's 'stock-splits' into stable. 2026-07-14 14:24:53 -07:00
Sherlock 80211df860 Miscellaneous cleanup 2026-07-14 14:20:09 -07:00
Sherlock 4d6f19a0f9 Bug: Missing account event
An account event should be generated for the original account if a lot is moved to a different account in xaccAccountInsertLot() as it is, if the lot is removed in xaccAccountRemoveLot().
2026-07-14 14:19:24 -07:00
Sherlock b1efe0763c The lot scrubber should exclude stock-split splits. 2026-07-14 14:19:24 -07:00
Sherlock 0aac4438e7 Bug: Gain/Loss displayed in "Splits free" is not correct
The gain/loss displayed for splits in the "Splits free" is historical.  It may or may not be correct.  Instead, the gain should be calculated against the selected lot for appropriate splits.

Implements xaccSplitLotCapGain() to obtain the gain for the selected lot.
2026-07-14 14:19:12 -07:00
John Ralls 453a4fe886 Merge Noah Noerr's 'fix-qofsession-end-releases-lock' into stable. 2026-07-11 11:03:53 -07:00
Noah R f056be140c [backend/dbi] skip the libdbi integrity probe for read-only sessions
session_begin() runs dbi_library_test() (Bug #611936) on every open to
detect a libdbi/-ffast-math miscompilation that mangles 64-bit values.
The probe CREATEs, INSERTs into, SELECTs from and DROPs a temporary
table, so it needs write privileges on the database -- even for
SESSION_READ_ONLY. A least-privilege, read-only database user therefore
cannot open the book at all: the temporary-table create fails and
session_begin returns ERR_SQL_DBI_UNTESTABLE.

The defect the probe guards against is on the write side of libdbi, so it
can be neither triggered nor detected by a read-only session, which never
writes. Skip the probe when the session is opened SESSION_READ_ONLY, at
the two call sites a read-only open reaches (the SQLite session_begin and
the shared MySQL/PostgreSQL session_begin); the third call site is inside
the create branch, which read-only never enters. The write-capable modes
(NORMAL_OPEN, NEW_STORE, NEW_OVERWRITE, BREAK_LOCK) still run the probe
unchanged.

This lets a SELECT-only database user open a book read-only through the API.
2026-07-10 17:52:55 -07:00
Christopher Lam b3e8074890 [gnc-euro.cpp] store euro rates as GncNumeric
this increases euro conversion rounding accuracy
2026-07-10 17:00:48 +04:00
Noah R 5dc53303b5 [engine] qof_session_end: release the lock via the session's backend
qof_session_end() is documented to release the session lock and shut the
backend connection but it does not release the session lock in all scenarios
(BUG). qof_session_end() looked the backend up via qof_book_get_backend().
The book's backend pointer is only set by load() or a data-changing save() (an
empty book's save() early-returns before attaching it); begin() sets only the
session's own m_backend. So a session that creates a store and ends it without
loading or making a real change had a backend on the session but not on the
book: end() found none, skipped session_end(), and never released the lock --
it was only released later at destroy().

Because the fault is in backend-agnostic engine code it affects every backend
that locks at begin(): the SQL/DBI backends leave a stale row in the gnclock
table, and the XML/file backend leaves an abandoned <file>.LCK sentinel (with
no data file, since XML data is only written at save). The store then appears
locked to the next opener.

End the session's own backend (m_backend, always set at begin()) instead. It
already equals the book's backend whenever the latter is set, so the change is
a no-op for loaded/saved sessions and additionally covers the
created-but-not-attached case.

Add regression tests for both backends, each of which begins a create-mode
session, ends it without a data-changing save, and checks the lock is gone:
  - test-backend-dbi-basic.cpp (test_dbi_new_store_end_releases_lock): reopens
    the store and asserts it is not ERR_BACKEND_LOCKED.
  - test-load-backend.cpp (test_new_store_end_releases_lock): asserts the XML
    <file>.LCK lockfile has been removed.
2026-07-09 20:24:45 -07:00
Sherlock 31978c1b4d Only show the “Show stock split adjusted amounts” checkbox when there are stock splits
Added has_stock_split field to Account private.  This flag is set to true when  xaccAccountRecomputeBalance() detects a stock-split split otherwise it is false.  Defined and declared xaccAccountHasStockSplit() for use by the Lot Viewer to whether to display the check box.
2026-07-09 01:17:17 -07:00
Sherlock 28cdb77a0b Improve code reuse 2026-07-09 01:15:59 -07:00
Sherlock 1e654412ab use adjusted_amount in place of amount
impacts gains, lots, and policy
2026-07-09 01:15:59 -07:00
Sherlock b1eb12f558 Determine the adjusted_amount for each split in an account
The algorithm to determine the current adjusted_amount is implemented in xaccAccountRecomputeBalance().

If the balance or new balance is nil, the stock-split split is ignored as it isn't possible to calculate the stock-split ratio.  This means the prior split adjusted amounts will not reflect the true current adjusted amounts.  These are conditions that should be raised appropriately to the user with sufficient details for resolution.
2026-07-09 01:15:59 -07:00
Sherlock 254ec4b4d0 Improve stock-split type detection
Noted split_type field in Split exists but is not used...

Reset split_type field's data type to hold the type of the getter.
Implemented xaccSplitIsStockSplit() abstraction to limit the split type string reference to Split.cpp and propagated it's use.
2026-07-09 01:12:49 -07:00
Sherlock 0d5c74b868 Add adjusted_amount field to split
The adjusted_amount field of a split will hold the stock split adjusted amount.  The adjusted amount is initially the same as the original amount.  When the account balances are recomputed and a stock-split split type is encountered, the ratio of the stock split will be applied to the preceding splits adjusted_amounts.  If there are no stock splits in the split's account, the adjusted amount remains the original amount.
2026-07-09 00:48:41 -07:00
John Ralls dc03a84c33 Merge Christopher Lam's 'qof-ctor-dtor' into stable. 2026-06-23 16:15:03 -07:00
John Ralls 7f4e8c29e0 Merge Noah Noerr's 'online-id-engine-accessors' into stable. 2026-06-23 14:55:41 -07:00
Noah R 3e98c5d8c8 [engine] Add first-class online_id accessors for Split and Account
Promote the OFX/HBCI online_id to named engine accessors:
  xaccSplitGetOnlineID / SetOnlineID / HasOnlineID
  xaccAccountGetOnlineID / SetOnlineID
The getters return an instance-owned const char* (mirroring
xaccTransGetDocLink / xaccTransGetNotes), so the existing
add_methods_with_prefix auto-wrapper exposes them in the Python bindings
with no .i changes and no %newobject.  They write to the same engine KVP
slot ("online_id") the desktop importer uses, so there is no data or
behavior change.

With the accessors in place the gnc_import_*_online_id wrappers in
import-utilities are redundant, so replace every call site (OFX,
AqBanking, and the generic matcher/backend) with them, delete
import-utilities.cpp, and drop the online_id declarations from
import-utilities.h (its importer preference-key macros are retained).

- The engine getters return an instance-owned const char* instead of a
  g_strdup'd copy, so callers no longer free the result; the affected
  locals are retyped const and their g_free()s dropped.
  hash_account_online_ids() g_strdups before inserting, since its hash
  table owns its keys (g_free key-destructor).
- xaccAccountSetOnlineID(acc, "") clears the slot, matching the OFX
  "delete the online_id" intent (the old wrapper stored an empty string).
- Drop the two unused wrappers: gnc_import_set_trans_online_id (marked
  "Not actually used") and gnc_import_trans_has_online_id (no callers).
- Add xaccSplitGet/SetOnlineID to the Split gmock so test-import-backend
  links without import-utilities.
2026-06-21 16:43:03 -07:00
Noah R 222714d764 [engine] Remove the unused Transaction online_id property
The "online-id" GObject property on Transaction (KVP slot "online_id")
was vestigial: GnuCash records the OFX/HBCI import identifier on the
bank/asset Split, not on the Transaction.  Drop the property, its
get/set_property cases, the xaccTransClone special-case that cleared it,
and the corresponding test_trans_kvp_properties coverage.
2026-06-21 16:35:56 -07:00
John Ralls 32a6868f52 Merge Noerr-Noah's 'bug-split-setparent-kvp-slots' into stable. 2026-06-21 15:41:47 -07:00
Noah R ea93d42f58 Bug 799777 - xaccSplitSetParent: keep a reparented split's KVP slots
When an already-committed split is moved to another transaction with
xaccSplitSetParent(), the split was marked dirty *after* the old
transaction was committed.  trans_cleanup_commit() only drops a
moved-out split from the old transaction's split list when the split is
dirty at that commit, so the still-clean split was left dangling in the
old transaction's split list.

On the SQL/DBI backends, destroying the now-vacated old transaction then
deleted the moved split's KVP slots (online_id, cap-gains links, ...) by
the split's own GUID, even though the split now belongs to another
transaction.  The split's native columns survive -- they are rewritten
under the new tx_guid -- but its slots are lost; in some sequences the
save fails outright with "UNIQUE constraint failed: transactions.guid".
The XML backend is unaffected because it re-serializes the whole book.

Mark the split dirty before committing the old transaction so
trans_cleanup_commit() removes it from the old transaction's split list,
as that code already intends.  This is a no-op for split creation (the
overwhelmingly common caller), where the prior parent is NULL.

Add a DBI round-trip regression test (sqlite3, and mysql/pgsql when the
TEST_*_URL variables are set): seed a split carrying an online_id, save
and reload, reparent it onto another transaction, destroy the old
transaction, then save and reload again and assert the online_id
survived.
2026-06-21 15:23:08 -07:00
John Ralls 59f0de826b Merge Vincent Lucarelli's 'finnhub into stable. 2026-06-21 14:50:08 -07:00
Vincent Lucarelli 21d861338e Add new Finance::Quote source Finnhub.io
Free API key (personal/non-professional use) available at https://finnhub.io.
Set FINNHUB_API_KEY environment variable to API key to use this source.
As of June 2026, free tier API limit is 60 API calls/minute.
2026-06-21 14:47:09 -07:00