donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit c601d1cc47eea447d15c7dec6c62d99a0be89cc9
parent a13d30ecd89da7cf234f6a2bab9d16d5a785d553
Author: Christian Grothoff <christian@grothoff.org>
Date:   Fri,  7 Aug 2026 00:18:53 +0200

properly track annual totals in history

Diffstat:
Msrc/donaudb/do_insert_receipt_issued.sql | 21++++++++++++++++++++-
Msrc/donaudb/test_donaudb.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 129 insertions(+), 1 deletion(-)

diff --git a/src/donaudb/do_insert_receipt_issued.sql b/src/donaudb/do_insert_receipt_issued.sql @@ -28,8 +28,10 @@ AS $$ DECLARE old_receipts_to_date taler_amount; new_receipts_to_date taler_amount; + prior_receipts_to_date taler_amount; max_per_year taler_amount; my_year INT4; + rolled_over BOOLEAN DEFAULT FALSE; BEGIN -- Get charity values SELECT @@ -62,7 +64,12 @@ BEGIN END IF; IF (my_year < in_year) THEN - -- bump current year + -- bump current year; the closing total of the year we are leaving + -- must be preserved in `history' before it is reset (see the comment + -- on charities.receipts_to_date). The row is only written if the + -- request actually succeeds, see below. + rolled_over = TRUE; + prior_receipts_to_date = old_receipts_to_date; old_receipts_to_date.val = 0; old_receipts_to_date.frac = 0; END IF; @@ -77,6 +84,18 @@ BEGIN (max_per_year.frac >= new_receipts_to_date.frac) ) ) THEN out_smaller_than_max_per_year=TRUE; + IF (rolled_over) + THEN + INSERT INTO history + (charity_id + ,final_amount + ,donation_year + ) VALUES ( + in_charity_id + ,prior_receipts_to_date + ,my_year + ) ON CONFLICT (charity_id, donation_year) DO NOTHING; + END IF; UPDATE charities SET receipts_to_date=new_receipts_to_date, current_year=in_year diff --git a/src/donaudb/test_donaudb.c b/src/donaudb/test_donaudb.c @@ -168,6 +168,59 @@ iterate_active_signkeys_cb ( /** + * Closure for #collect_history_cb(). + */ +struct HistoryCheck +{ + /** + * Charity we are interested in. + */ + unsigned long long charity_id; + + /** + * Year we expect a history entry for. + */ + uint64_t donation_year; + + /** + * Amount we expect that entry to carry. + */ + struct TALER_Amount expected; + + /** + * Set to true if the expected entry was found. + */ + bool found; +}; + + +/** + * Look for the history entry described by @a cls. + * + * @param cls a `struct HistoryCheck *` + * @param charity_id charity of this entry + * @param final_amount closing total of that year + * @param donation_year year of this entry + * @return #GNUNET_OK to continue + */ +static enum GNUNET_GenericReturnValue +collect_history_cb (void *cls, + unsigned long long charity_id, + struct TALER_Amount final_amount, + uint64_t donation_year) +{ + struct HistoryCheck *hc = cls; + + if ( (charity_id == hc->charity_id) && + (donation_year == hc->donation_year) && + (0 == TALER_amount_cmp (&final_amount, + &hc->expected)) ) + hc->found = true; + return GNUNET_OK; +} + + +/** * Main function that will be run by the scheduler. * * @param cls closure with config @@ -510,6 +563,62 @@ run (void *cls) 2027)); } + /* D-4: the first request of a new year resets receipts_to_date; the + closing total of the year being left must be preserved in `history' + rather than discarded. */ + { + uint64_t rollover_charity_id; + struct DONAUDB_CharityMetaData rollover_meta; + struct HistoryCheck hc; + struct TALER_Amount zero; + bool under_limit = false; + uint32_t this_year = GNUNET_TIME_get_current_year (); + + FAILIF (GNUNET_OK != + make_charity (CURRENCY ":1000", + &rollover_charity_id)); + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + issue_receipt (rollover_charity_id, + this_year, + CURRENCY ":90", + &under_limit)); + FAILIF (! under_limit); + /* First request of the following year. */ + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + issue_receipt (rollover_charity_id, + this_year + 1, + CURRENCY ":5", + &under_limit)); + FAILIF (! under_limit); + + memset (&hc, + 0, + sizeof (hc)); + hc.charity_id = (unsigned long long) rollover_charity_id; + hc.donation_year = this_year; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":90", + &hc.expected)); + FAILIF (0 > + DONAUDB_iterate_history_entries (ctx, + &collect_history_cb, + &hc)); + FAILIF (! hc.found); + + /* ... and the new year did start from zero. */ + FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + DONAUDB_get_charity (ctx, + rollover_charity_id, + &rollover_meta)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (CURRENCY ":5", + &zero)); + FAILIF (0 != TALER_amount_cmp (&rollover_meta.receipts_to_date, + &zero)); + GNUNET_free (rollover_meta.charity_name); + GNUNET_free (rollover_meta.charity_url); + } + result = 0; drop: