GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-budget.cpp
1/********************************************************************\
2 * gnc-budget.c -- Implementation of the top level Budgeting API. *
3 * Copyright (C) 04 sep 2003 Darin Willits <darin@willits.ca> *
4 * Copyright (C) 2005-2006 Chris Shoemaker <c.shoemaker@cox.net> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23\********************************************************************/
24
25#include <config.h>
26#include <qof.h>
27#include <qofbookslots.h>
28#include <qofinstance-p.h>
29#include <optional>
30#include <unordered_map>
31#include <vector>
32
33#include "Account.h"
34
35#include "guid.hpp"
36#include "gnc-budget.h"
37#include "gnc-commodity.h"
38
39static QofLogModule log_module = GNC_MOD_ENGINE;
40
41enum
42{
43 PROP_0,
44 PROP_NAME, /* Table */
45 PROP_DESCRIPTION, /* Table */
46 PROP_NUM_PERIODS, /* Table */
47 PROP_RUNTIME_0,
48 PROP_RECURRENCE, /* Cached pointer; Recurrence table holds budget guid */
49};
50
52{
53 QofInstance inst;
54};
55
56typedef struct
57{
58 QofInstanceClass parent_class;
60
62{
63 std::string note;
64 std::optional<gnc_numeric> opt_value;
65 PeriodData () = default;
66 PeriodData (const char* note, std::optional<gnc_numeric> opt_value)
67 : note (note)
68 , opt_value (opt_value) {};
69};
70
71using PeriodDataVec = std::vector<PeriodData>;
72using AcctMap = std::unordered_map<const Account*, PeriodDataVec>;
73using StringVec = std::vector<std::string>;
74
75typedef struct GncBudgetPrivate
76{
77 /* The name is an arbitrary string assigned by the user. */
78 const gchar *name;
79
80 /* The description is an arbitrary string assigned by the user. */
81 const gchar *description;
82
83 /* Recurrence (period info) for the budget */
84 Recurrence recurrence;
85
86 AcctMap acct_map;
87
88 /* Number of periods */
89 guint num_periods;
91
92#define GET_PRIVATE(o) \
93 ((GncBudgetPrivate*)gnc_budget_get_instance_private((GncBudget*)o))
94
96{
97 QofInstanceClass parent_class;
98};
99
100/* GObject Initialization */
101G_DEFINE_TYPE_WITH_PRIVATE(GncBudget, gnc_budget, QOF_TYPE_INSTANCE)
102
103static void
104gnc_budget_init(GncBudget* budget)
105{
106 GncBudgetPrivate* priv;
107 GDate *date;
108
109 priv = GET_PRIVATE(budget);
110 priv->name = CACHE_INSERT(_("Unnamed Budget"));
111 priv->description = CACHE_INSERT("");
112 new (&priv->acct_map) AcctMap ();
113
114 priv->num_periods = 12;
115 date = gnc_g_date_new_today ();
116 g_date_subtract_days(date, g_date_get_day(date) - 1);
117 recurrenceSet(&priv->recurrence, 1, PERIOD_MONTH, date, WEEKEND_ADJ_NONE);
118 g_date_free (date);
119}
120
121static void
122gnc_budget_dispose (GObject *budgetp)
123{
124 G_OBJECT_CLASS(gnc_budget_parent_class)->dispose(budgetp);
125}
126
127static void
128gnc_budget_finalize(GObject* budgetp)
129{
130 G_OBJECT_CLASS(gnc_budget_parent_class)->finalize(budgetp);
131}
132
133static void
134gnc_budget_get_property( GObject* object,
135 guint prop_id,
136 GValue* value,
137 GParamSpec* pspec)
138{
139 GncBudget* budget;
140 GncBudgetPrivate* priv;
141
142 g_return_if_fail(GNC_IS_BUDGET(object));
143
144 budget = GNC_BUDGET(object);
145 priv = GET_PRIVATE(budget);
146 switch ( prop_id )
147 {
148 case PROP_NAME:
149 g_value_set_string(value, priv->name);
150 break;
151 case PROP_DESCRIPTION:
152 g_value_set_string(value, priv->description);
153 break;
154 case PROP_NUM_PERIODS:
155 g_value_set_uint(value, priv->num_periods);
156 break;
157 case PROP_RECURRENCE:
158 /* TODO: Make this a BOXED type */
159 g_value_set_pointer(value, &priv->recurrence);
160 break;
161 default:
162 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
163 break;
164 }
165}
166
167static void
168gnc_budget_set_property( GObject* object,
169 guint prop_id,
170 const GValue* value,
171 GParamSpec* pspec)
172{
173 GncBudget* budget;
174
175 g_return_if_fail(GNC_IS_BUDGET(object));
176
177 budget = GNC_BUDGET(object);
178 if (prop_id < PROP_RUNTIME_0)
179 g_assert (qof_instance_get_editlevel(budget));
180
181 switch ( prop_id )
182 {
183 case PROP_NAME:
184 gnc_budget_set_name(budget, g_value_get_string(value));
185 break;
186 case PROP_DESCRIPTION:
187 gnc_budget_set_description(budget, g_value_get_string(value));
188 break;
189 case PROP_NUM_PERIODS:
190 gnc_budget_set_num_periods(budget, g_value_get_uint(value));
191 break;
192 case PROP_RECURRENCE:
193 gnc_budget_set_recurrence (budget, static_cast<Recurrence*>(g_value_get_pointer(value)));
194 break;
195 default:
196 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
197 break;
198 }
199}
200
201static void
202gnc_budget_class_init(GncBudgetClass* klass)
203{
204 GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
205
206 gobject_class->dispose = gnc_budget_dispose;
207 gobject_class->finalize = gnc_budget_finalize;
208 gobject_class->get_property = gnc_budget_get_property;
209 gobject_class->set_property = gnc_budget_set_property;
210
211 g_object_class_install_property(
212 gobject_class,
213 PROP_NAME,
214 g_param_spec_string( "name",
215 "Budget Name",
216 "The name is an arbitrary string "
217 "assigned by the user. It is intended "
218 "to be a short, 5 to 30 character long string "
219 "that is displayed by the GUI as the "
220 "budget mnemonic",
221 nullptr,
222 G_PARAM_READWRITE));
223
224 g_object_class_install_property(
225 gobject_class,
226 PROP_DESCRIPTION,
227 g_param_spec_string( "description",
228 "Budget Description",
229 "The description is an arbitrary string "
230 "assigned by the user. It is intended "
231 "to be a longer, 1-5 sentence description of "
232 "what the budget is all about.",
233 nullptr,
234 G_PARAM_READWRITE));
235
236 g_object_class_install_property(
237 gobject_class,
238 PROP_NUM_PERIODS,
239 g_param_spec_uint( "num-periods",
240 "Number of Periods",
241 "The number of periods for this budget.",
242 0,
243 G_MAXUINT32,
244 12,
245 G_PARAM_READWRITE));
246
247 g_object_class_install_property(
248 gobject_class,
249 PROP_RECURRENCE,
250 g_param_spec_pointer( "recurrence",
251 "Budget Recurrence",
252 "about.",
253 G_PARAM_READWRITE));
254}
255
256static void commit_err (QofInstance *inst, QofBackendError errcode)
257{
258 PERR ("Failed to commit: %d", errcode);
259 gnc_engine_signal_commit_error( errcode );
260}
261
262static void
263gnc_budget_free(QofInstance *inst)
264{
265 GncBudget *budget;
266 GncBudgetPrivate* priv;
267
268 if (inst == nullptr)
269 return;
270 g_return_if_fail(GNC_IS_BUDGET(inst));
271
272 budget = GNC_BUDGET(inst);
273 priv = GET_PRIVATE(budget);
274
275 /* We first send the message that this object is about to be
276 * destroyed so that any GUI elements can remove it before it is
277 * actually gone. */
278 qof_event_gen( &budget->inst, QOF_EVENT_DESTROY, nullptr);
279
280 CACHE_REMOVE(priv->name);
281 CACHE_REMOVE(priv->description);
282 priv->acct_map.~AcctMap();
283
284 /* qof_instance_release (&budget->inst); */
285 g_object_unref(budget);
286}
287
288static void noop (QofInstance *inst) {}
289
290void
291gnc_budget_begin_edit(GncBudget *bgt)
292{
293 qof_begin_edit(QOF_INSTANCE(bgt));
294}
295
296void
297gnc_budget_commit_edit(GncBudget *bgt)
298{
299 if (!qof_commit_edit(QOF_INSTANCE(bgt))) return;
300 qof_commit_edit_part2(QOF_INSTANCE(bgt), commit_err,
301 noop, gnc_budget_free);
302}
303
304GncBudget*
306{
307 g_return_val_if_fail(book, nullptr);
308
309 ENTER(" ");
310
311 auto budget { static_cast<GncBudget*>(g_object_new(GNC_TYPE_BUDGET, nullptr)) };
312 qof_instance_init_data (&budget->inst, GNC_ID_BUDGET, book);
313
314 qof_event_gen( &budget->inst, QOF_EVENT_CREATE , nullptr);
315
316 LEAVE(" ");
317 return budget;
318}
319
320void
321gnc_budget_destroy(GncBudget *budget)
322{
323 g_return_if_fail(GNC_IS_BUDGET(budget));
324 gnc_budget_begin_edit(budget);
325 qof_instance_set_dirty(&budget->inst);
326 qof_instance_set_destroying(budget, TRUE);
327 gnc_budget_commit_edit(budget);
328}
329
331typedef struct
332{
333 const GncBudget* old_b;
334 GncBudget* new_b;
335 guint num_periods;
337
338static void
339clone_budget_values_cb(Account* a, gpointer user_data)
340{
341 CloneBudgetData_t* data = (CloneBudgetData_t*)user_data;
342 guint i;
343
344 for ( i = 0; i < data->num_periods; ++i )
345 {
346 if ( gnc_budget_is_account_period_value_set(data->old_b, a, i) )
347 {
348 gnc_budget_set_account_period_value(data->new_b, a, i,
349 gnc_budget_get_account_period_value(data->old_b, a, i));
350 }
351 }
352}
353
354GncBudget*
355gnc_budget_clone(const GncBudget* old_b)
356{
357 GncBudget* new_b;
358 Account* root;
359 CloneBudgetData_t clone_data;
360
361 g_return_val_if_fail(old_b != nullptr, nullptr);
362
363 ENTER(" ");
364
366 gnc_budget_begin_edit(new_b);
367 gnc_budget_set_name(new_b, gnc_budget_get_name(old_b));
368 gnc_budget_set_description(new_b, gnc_budget_get_description(old_b));
369 gnc_budget_set_recurrence(new_b, gnc_budget_get_recurrence(old_b));
370 gnc_budget_set_num_periods(new_b, gnc_budget_get_num_periods(old_b));
371
372 root = gnc_book_get_root_account(qof_instance_get_book(old_b));
373 clone_data.old_b = old_b;
374 clone_data.new_b = new_b;
375 clone_data.num_periods = gnc_budget_get_num_periods(new_b);
376 gnc_account_foreach_descendant(root, clone_budget_values_cb, &clone_data);
377
378 gnc_budget_commit_edit(new_b);
379
380 LEAVE(" ");
381
382 return new_b;
383}
384
385void
386gnc_budget_set_name(GncBudget* budget, const gchar* name)
387{
388 GncBudgetPrivate* priv;
389
390 g_return_if_fail(GNC_IS_BUDGET(budget) && name);
391
392 priv = GET_PRIVATE(budget);
393 if ( name == priv->name ) return;
394
395 gnc_budget_begin_edit(budget);
396 CACHE_REPLACE(priv->name, name);
397 qof_instance_set_dirty(&budget->inst);
398 gnc_budget_commit_edit(budget);
399
400 qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, nullptr);
401}
402
403const gchar*
404gnc_budget_get_name(const GncBudget* budget)
405{
406 g_return_val_if_fail(GNC_IS_BUDGET(budget), nullptr);
407 return GET_PRIVATE(budget)->name;
408}
409
410void
411gnc_budget_set_description(GncBudget* budget, const gchar* description)
412{
413 GncBudgetPrivate* priv;
414
415 g_return_if_fail(GNC_IS_BUDGET(budget));
416 g_return_if_fail(description);
417
418 priv = GET_PRIVATE(budget);
419 if ( description == priv->description ) return;
420 gnc_budget_begin_edit(budget);
421 CACHE_REPLACE(priv->description, description);
422 qof_instance_set_dirty(&budget->inst);
423 gnc_budget_commit_edit(budget);
424
425 qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, nullptr);
426}
427
428const gchar*
429gnc_budget_get_description(const GncBudget* budget)
430{
431 g_return_val_if_fail(GNC_IS_BUDGET(budget), nullptr);
432 return GET_PRIVATE(budget)->description;
433}
434
435void
436gnc_budget_set_recurrence(GncBudget *budget, const Recurrence *r)
437{
438 GncBudgetPrivate* priv;
439
440 g_return_if_fail(budget && r);
441 priv = GET_PRIVATE(budget);
442
443 gnc_budget_begin_edit(budget);
444 priv->recurrence = *r;
445 qof_instance_set_dirty(&budget->inst);
446 gnc_budget_commit_edit(budget);
447
448 qof_event_gen(&budget->inst, QOF_EVENT_MODIFY, nullptr);
449}
450
451const Recurrence *
452gnc_budget_get_recurrence(const GncBudget *budget)
453{
454 g_return_val_if_fail(budget, nullptr);
455 return (&GET_PRIVATE(budget)->recurrence);
456}
457
458const GncGUID*
459gnc_budget_get_guid(const GncBudget* budget)
460{
461 g_return_val_if_fail(budget, nullptr);
462 g_return_val_if_fail(GNC_IS_BUDGET(budget), nullptr);
463 return qof_instance_get_guid(QOF_INSTANCE(budget));
464}
465
466void
467gnc_budget_set_num_periods(GncBudget* budget, guint num_periods)
468{
469 GncBudgetPrivate* priv;
470
471 g_return_if_fail(GNC_IS_BUDGET(budget));
472 g_return_if_fail(num_periods > 0);
473
474 priv = GET_PRIVATE(budget);
475 if ( priv->num_periods == num_periods ) return;
476
477 gnc_budget_begin_edit(budget);
478 priv->num_periods = num_periods;
479 std::for_each (priv->acct_map.begin(), priv->acct_map.end(),
480 [num_periods](auto& it){ it.second.resize(num_periods); });
481 qof_instance_set_dirty(&budget->inst);
482 gnc_budget_commit_edit(budget);
483
484 qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, nullptr);
485}
486
487guint
488gnc_budget_get_num_periods(const GncBudget* budget)
489{
490 g_return_val_if_fail(GNC_IS_BUDGET(budget), 0);
491 return GET_PRIVATE(budget)->num_periods;
492}
493
494static inline StringVec
495make_period_data_path (const Account *account, guint period_num)
496{
497 gnc::GUID acct_guid {*(xaccAccountGetGUID (account))};
498 return { acct_guid.to_string(), std::to_string (period_num) };
499}
500
501static inline StringVec
502make_period_note_path (const Account *account, guint period_num)
503{
504 StringVec path { GNC_BUDGET_NOTES_PATH };
505 StringVec data_path { make_period_data_path (account, period_num) };
506 std::move (data_path.begin(), data_path.end(), std::back_inserter (path));
507 return path;
508}
509
510static PeriodData& get_perioddata (const GncBudget *budget,
511 const Account *account,
512 guint period_num);
513
514/* period_num is zero-based */
515/* What happens when account is deleted, after we have an entry for it? */
516void
517gnc_budget_unset_account_period_value(GncBudget *budget, const Account *account,
518 guint period_num)
519{
520 g_return_if_fail (budget != nullptr);
521 g_return_if_fail (account != nullptr);
522 g_return_if_fail (period_num < GET_PRIVATE(budget)->num_periods);
523
524 auto& data = get_perioddata (budget, account, period_num);
525 data.opt_value.reset();
526
527 gnc_budget_begin_edit(budget);
528 auto path = make_period_data_path (account, period_num);
529 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
530 delete budget_kvp->set_path (path, nullptr);
531 qof_instance_set_dirty(&budget->inst);
532 gnc_budget_commit_edit(budget);
533
534 qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, nullptr);
535
536}
537
538/* period_num is zero-based */
539/* What happens when account is deleted, after we have an entry for it? */
540void
541gnc_budget_set_account_period_value(GncBudget *budget, const Account *account,
542 guint period_num, gnc_numeric val)
543{
544 g_return_if_fail (budget != nullptr);
545 g_return_if_fail (account != nullptr);
546
547 /* Watch out for an off-by-one error here:
548 * period_num starts from 0 while num_periods starts from 1 */
549 if (period_num >= GET_PRIVATE(budget)->num_periods)
550 {
551 PWARN("Period %i does not exist", period_num);
552 return;
553 }
554
555 auto& perioddata = get_perioddata (budget, account, period_num);
556 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
557 auto path = make_period_data_path (account, period_num);
558
559 gnc_budget_begin_edit(budget);
560 if (gnc_numeric_check(val))
561 {
562 delete budget_kvp->set_path (path, nullptr);
563 perioddata.opt_value.reset();
564 }
565 else
566 {
567 KvpValue* v = new KvpValue (val);
568 delete budget_kvp->set_path (path, v);
569 perioddata.opt_value = val;
570 }
571 qof_instance_set_dirty(&budget->inst);
572 gnc_budget_commit_edit(budget);
573
574 qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, nullptr);
575
576}
577
578gboolean
579gnc_budget_is_account_period_value_set (const GncBudget *budget,
580 const Account *account,
581 guint period_num)
582{
583 g_return_val_if_fail (period_num < GET_PRIVATE(budget)->num_periods, false);
584 return get_perioddata (budget, account, period_num).opt_value.has_value();
585}
586
587gnc_numeric
588gnc_budget_get_account_period_value (const GncBudget *budget,
589 const Account *account,
590 guint period_num)
591{
592 g_return_val_if_fail (period_num < GET_PRIVATE(budget)->num_periods,
593 gnc_numeric_zero());
594 auto& data = get_perioddata (budget, account, period_num);
595
596 return data.opt_value.has_value() ? data.opt_value.value() : gnc_numeric_zero();
597}
598
599void
600gnc_budget_set_account_period_note(GncBudget *budget, const Account *account,
601 guint period_num, const gchar *note)
602{
603 g_return_if_fail (budget != nullptr);
604 g_return_if_fail (account != nullptr);
605
606 /* Watch out for an off-by-one error here:
607 * period_num starts from 0 while num_periods starts from 1 */
608 if (period_num >= GET_PRIVATE(budget)->num_periods)
609 {
610 PWARN("Period %i does not exist", period_num);
611 return;
612 }
613
614 auto& perioddata = get_perioddata (budget, account, period_num);
615 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
616 auto path = make_period_note_path (account, period_num);
617
618 gnc_budget_begin_edit(budget);
619 if (note == nullptr)
620 {
621 delete budget_kvp->set_path (path, nullptr);
622 perioddata.note.clear ();
623 }
624 else
625 {
626 KvpValue* v = new KvpValue (g_strdup (note));
627
628 delete budget_kvp->set_path (path, v);
629 perioddata.note = note;
630 }
631 qof_instance_set_dirty(&budget->inst);
632 gnc_budget_commit_edit(budget);
633
634 qof_event_gen( &budget->inst, QOF_EVENT_MODIFY, nullptr);
635
636}
637
638const gchar *
639gnc_budget_get_account_period_note (const GncBudget *budget,
640 const Account *account, guint period_num)
641{
642 g_return_val_if_fail (period_num < GET_PRIVATE(budget)->num_periods, nullptr);
643 auto& data = get_perioddata (budget, account, period_num);
644 return data.note.empty () ? nullptr : data.note.c_str();
645}
646
647time64
648gnc_budget_get_period_start_date(const GncBudget *budget, guint period_num)
649{
650 g_return_val_if_fail (GNC_IS_BUDGET(budget), 0);
651 return recurrenceGetPeriodTime(&GET_PRIVATE(budget)->recurrence, period_num, FALSE);
652}
653
654time64
655gnc_budget_get_period_end_date(const GncBudget *budget, guint period_num)
656{
657 g_return_val_if_fail (GNC_IS_BUDGET(budget), 0);
658 return recurrenceGetPeriodTime(&GET_PRIVATE(budget)->recurrence, period_num, TRUE);
659}
660
661gnc_numeric
662gnc_budget_get_account_period_actual_value(
663 const GncBudget *budget, Account *acc, guint period_num)
664{
665 // FIXME: maybe zero is not best error return val.
666 g_return_val_if_fail(GNC_IS_BUDGET(budget) && acc, gnc_numeric_zero());
667 return recurrenceGetAccountPeriodValue(&GET_PRIVATE(budget)->recurrence,
668 acc, period_num);
669}
670
671static PeriodData&
672get_perioddata (const GncBudget *budget, const Account *account, guint period_num)
673{
674 GncBudgetPrivate *priv = GET_PRIVATE (budget);
675
676 if (period_num >= priv->num_periods)
677 throw std::out_of_range("period_num >= num_periods");
678
679 auto& vec = priv->acct_map[account];
680
681 if (vec.empty())
682 {
683 auto budget_kvp { QOF_INSTANCE (budget)->kvp_data };
684 vec.reserve (priv->num_periods);
685
686 for (guint i = 0; i < priv->num_periods; i++)
687 {
688 auto kval1 { budget_kvp->get_slot (make_period_data_path (account, i)) };
689 auto kval2 { budget_kvp->get_slot (make_period_note_path (account, i)) };
690
691 auto is_set = kval1 && kval1->get_type() == KvpValue::Type::NUMERIC;
692 auto num = is_set ? std::make_optional (kval1->get<gnc_numeric>()) : std::nullopt;
693 auto note = (kval2 && kval2->get_type() == KvpValue::Type::STRING) ?
694 kval2->get<const char*>() : "";
695
696 vec.emplace_back (note, num);
697 }
698 }
699
700 return vec.at(period_num);
701}
702
703GncBudget*
704gnc_budget_lookup (const GncGUID *guid, const QofBook *book)
705{
706 QofCollection *col;
707
708 g_return_val_if_fail(guid, nullptr);
709 g_return_val_if_fail(book, nullptr);
710 col = qof_book_get_collection (book, GNC_ID_BUDGET);
711 return GNC_BUDGET(qof_collection_lookup_entity (col, guid));
712}
713
714static void just_get_one(QofInstance *ent, gpointer data)
715{
716 GncBudget **bgt = (GncBudget**)data;
717 if (bgt && !*bgt) *bgt = GNC_BUDGET(ent);
718}
719
720GncBudget*
721gnc_budget_get_default (QofBook *book)
722{
723 QofCollection *col;
724 GncBudget *bgt = nullptr;
725 GncGUID *default_budget_guid = nullptr;
726
727 g_return_val_if_fail(book, nullptr);
728
729 qof_instance_get (QOF_INSTANCE (book),
730 "default-budget", &default_budget_guid,
731 nullptr);
732 if (default_budget_guid)
733 {
734 col = qof_book_get_collection(book, GNC_ID_BUDGET);
735 bgt = (GncBudget *) qof_collection_lookup_entity(col,
736 default_budget_guid);
737 }
738
739 /* Revert to 2.2.x behavior if the book has no default budget. */
740
741 if ( bgt == nullptr )
742 {
743 col = qof_book_get_collection(book, GNC_ID_BUDGET);
744 if (qof_collection_count(col) > 0)
745 {
746 qof_collection_foreach(col, just_get_one, &bgt);
747 }
748 }
749
750 guid_free (default_budget_guid);
751 return bgt;
752}
753
754static void
755destroy_budget_on_book_close(QofInstance *ent, gpointer data)
756{
757 GncBudget* bgt = GNC_BUDGET(ent);
758
760}
761
766static void
767gnc_budget_book_end(QofBook* book)
768{
769 QofCollection *col;
770
771 col = qof_book_get_collection(book, GNC_ID_BUDGET);
772 qof_collection_foreach(col, destroy_budget_on_book_close, nullptr);
773}
774
775#ifdef _MSC_VER
776/* MSVC compiler doesn't have C99 "designated initializers"
777 * so we wrap them in a macro that is empty on MSVC. */
778# define DI(x) /* */
779#else
780# define DI(x) x
781#endif
782
783/* Define the QofObject. */
784static QofObject budget_object_def =
785{
786 DI(.interface_version = ) QOF_OBJECT_VERSION,
787 DI(.e_type = ) GNC_ID_BUDGET,
788 DI(.type_label = ) "Budget",
789 DI(.create = ) (void*(*)(QofBook*)) gnc_budget_new,
790 DI(.book_begin = ) nullptr,
791 DI(.book_end = ) gnc_budget_book_end,
792 DI(.is_dirty = ) qof_collection_is_dirty,
793 DI(.mark_clean = ) qof_collection_mark_clean,
794 DI(.foreach = ) qof_collection_foreach,
795 DI(.printable = ) (const char * (*)(gpointer)) gnc_budget_get_name,
796 DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
797};
798
799
800/* Static wrapper getters for the recurrence params */
801static PeriodType gnc_budget_get_rec_pt(const GncBudget *bgt)
802{
803 return recurrenceGetPeriodType(&(GET_PRIVATE(bgt)->recurrence));
804}
805static guint gnc_budget_get_rec_mult(const GncBudget *bgt)
806{
807 return recurrenceGetMultiplier(&(GET_PRIVATE(bgt)->recurrence));
808}
809static time64 gnc_budget_get_rec_time(const GncBudget *bgt)
810{
811 return recurrenceGetTime(&(GET_PRIVATE(bgt)->recurrence));
812}
813
814/* Register ourselves with the engine. */
815gboolean gnc_budget_register (void)
816{
817 static QofParam params[] =
818 {
819 {
820 "name", QOF_TYPE_STRING,
821 (QofAccessFunc) gnc_budget_get_name,
823 },
824 {
825 "description", QOF_TYPE_STRING,
826 (QofAccessFunc) gnc_budget_get_description,
828 },
829 {
830 "recurrence_period_type", QOF_TYPE_INT32,
831 (QofAccessFunc) gnc_budget_get_rec_pt, nullptr
832 },
833 /* Signedness problem: Should be unsigned. */
834 {
835 "recurrence_multiplier", QOF_TYPE_INT32,
836 (QofAccessFunc) gnc_budget_get_rec_mult, nullptr
837 },
838 /* This is the same way that SchedXaction.c uses QOF_TYPE_DATE
839 but I don't think QOF actually supports a GDate, so I think
840 this is wrong. */
841 {
842 "recurrence_date", QOF_TYPE_DATE,
843 (QofAccessFunc) gnc_budget_get_rec_time, nullptr
844 },
845 /* Signedness problem: Should be unsigned. */
846 {
847 "num_periods", QOF_TYPE_INT32,
848 (QofAccessFunc) gnc_budget_get_num_periods,
850 },
851 {
852 QOF_PARAM_BOOK, QOF_ID_BOOK,
854 },
855 {
856 QOF_PARAM_GUID, QOF_TYPE_GUID,
858 },
859 { nullptr },
860 };
861
862 qof_class_register(GNC_ID_BUDGET, (QofSortFunc) nullptr, params);
863 return qof_object_register(&budget_object_def);
864}
Account handling public routines.
GnuCash Budgets.
Commodity handling public routines.
#define xaccAccountGetGUID(X)
Definition Account.h:252
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition qofbackend.h:58
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition qofbook.cpp:521
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:123
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition qofclass.h:130
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition qofclass.cpp:86
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition qofclass.h:168
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
GDate * gnc_g_date_new_today()
Returns a newly allocated date of the current clock time, taken from time(2).
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition qofid.cpp:209
guint qof_collection_count(const QofCollection *col)
return the number of entities in the collection.
Definition qofid.cpp:221
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of 'dirty' flag on collection.
Definition qofid.cpp:232
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition qofevent.cpp:231
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition qofid.cpp:238
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition qofobject.h:63
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition qofquery.h:108
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
part2 – deal with the backend
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
void gnc_budget_set_num_periods(GncBudget *budget, guint num_periods)
Set/Get the number of periods in the Budget.
GncBudget * gnc_budget_new(QofBook *book)
Creates and initializes a Budget.
void gnc_budget_destroy(GncBudget *budget)
Deletes the given budget object.
GncBudget * gnc_budget_clone(const GncBudget *old_b)
Clones a budget creating a copy.
void gnc_budget_set_description(GncBudget *budget, const gchar *description)
Set/Get the description of the Budget.
time64 gnc_budget_get_period_start_date(const GncBudget *budget, guint period_num)
Get the starting date of the Budget period.
void gnc_budget_set_name(GncBudget *budget, const gchar *name)
Set/Get the name of the Budget.
time64 gnc_budget_get_period_end_date(const GncBudget *budget, guint period_num)
Get the ending date of the Budget period.
STRUCTS.
Data structure for containing info while cloning budget values.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
The budget data.