Line data Source code
1 : /********************************************************************\
2 : * gnc-lot.c -- AR/AP invoices; inventory lots; stock lots *
3 : * *
4 : * This program is free software; you can redistribute it and/or *
5 : * modify it under the terms of the GNU General Public License as *
6 : * published by the Free Software Foundation; either version 2 of *
7 : * the License, or (at your option) any later version. *
8 : * *
9 : * This program is distributed in the hope that it will be useful, *
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 : * GNU General Public License for more details. *
13 : * *
14 : * You should have received a copy of the GNU General Public License*
15 : * along with this program; if not, contact: *
16 : * *
17 : * Free Software Foundation Voice: +1-617-542-5942 *
18 : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19 : * Boston, MA 02110-1301, USA gnu@gnu.org *
20 : \********************************************************************/
21 :
22 : /*
23 : * FILE:
24 : * gnc-lot.c
25 : *
26 : * FUNCTION:
27 : * Lots implement the fundamental conceptual idea behind invoices,
28 : * inventory lots, and stock market investment lots. See the file
29 : * src/doc/lots.txt for implementation overview.
30 : *
31 : * XXX Lots are not currently treated in a correct transactional
32 : * manner. There's now a per-Lot dirty flag in the QofInstance, but
33 : * this code still needs to emit the correct signals when a lot has
34 : * changed. This is true both in the Scrub2.c and in
35 : * src/gnome/dialog-lot-viewer.c
36 : *
37 : * HISTORY:
38 : * Created by Linas Vepstas May 2002
39 : * Copyright (c) 2002,2003 Linas Vepstas <linas@linas.org>
40 : */
41 :
42 : #include <config.h>
43 :
44 : #include <glib.h>
45 : #include <glib/gi18n.h>
46 : #include <qofinstance-p.h>
47 :
48 : #include "Account.h"
49 : #include "AccountP.hpp"
50 : #include "gnc-lot.h"
51 : #include "gnc-lot-p.h"
52 : #include "cap-gains.h"
53 : #include "Transaction.h"
54 : #include "TransactionP.hpp"
55 : #include "gncInvoice.h"
56 :
57 : /* This static indicates the debugging module that this .o belongs to. */
58 : static QofLogModule log_module = GNC_MOD_LOT;
59 :
60 : struct gnc_lot_s
61 : {
62 : QofInstance inst;
63 : };
64 :
65 : enum
66 : {
67 : PROP_0,
68 : // PROP_ACCOUNT, /* Table */
69 : PROP_IS_CLOSED, /* Table */
70 :
71 : PROP_INVOICE, /* KVP */
72 : PROP_OWNER_TYPE, /* KVP */
73 : PROP_OWNER_GUID, /* KVP */
74 :
75 : PROP_RUNTIME_0,
76 : PROP_MARKER, /* Runtime */
77 : };
78 :
79 : typedef struct GNCLotPrivate
80 : {
81 : /* Account to which this lot applies. All splits in the lot must
82 : * belong to this account.
83 : */
84 : Account * account;
85 :
86 : /* List of splits that belong to this lot. */
87 : SplitList *splits;
88 :
89 : char *title;
90 : char *notes;
91 :
92 : GncInvoice *cached_invoice;
93 : /* Handy cached value to indicate if lot is closed. */
94 : /* If value is negative, then the cache is invalid. */
95 : signed char is_closed;
96 : #define LOT_CLOSED_UNKNOWN (-1)
97 :
98 : /* traversal marker, handy for preventing recursion */
99 : unsigned char marker;
100 : } GNCLotPrivate;
101 :
102 : #define GET_PRIVATE(o) \
103 : ((GNCLotPrivate*)gnc_lot_get_instance_private((GNCLot*)o))
104 :
105 : #define gnc_lot_set_guid(L,G) qof_instance_set_guid(QOF_INSTANCE(L),&(G))
106 :
107 : /* ============================================================= */
108 :
109 : /* GObject Initialization */
110 503711 : G_DEFINE_TYPE_WITH_PRIVATE(GNCLot, gnc_lot, QOF_TYPE_INSTANCE)
111 :
112 : static void
113 235 : gnc_lot_init(GNCLot* lot)
114 : {
115 : GNCLotPrivate* priv;
116 :
117 235 : priv = GET_PRIVATE(lot);
118 235 : priv->account = nullptr;
119 235 : priv->splits = nullptr;
120 235 : priv->cached_invoice = nullptr;
121 235 : priv->is_closed = LOT_CLOSED_UNKNOWN;
122 235 : priv->marker = 0;
123 235 : }
124 :
125 : static void
126 160 : gnc_lot_dispose(GObject *lotp)
127 : {
128 160 : G_OBJECT_CLASS(gnc_lot_parent_class)->dispose(lotp);
129 160 : }
130 :
131 : static void
132 160 : gnc_lot_finalize(GObject* lotp)
133 : {
134 160 : G_OBJECT_CLASS(gnc_lot_parent_class)->finalize(lotp);
135 160 : }
136 :
137 : static void
138 2043 : gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
139 : {
140 : GNCLot* lot;
141 : GNCLotPrivate* priv;
142 :
143 2043 : g_return_if_fail(GNC_IS_LOT(object));
144 :
145 2043 : lot = GNC_LOT(object);
146 2043 : priv = GET_PRIVATE(lot);
147 2043 : switch (prop_id)
148 : {
149 1 : case PROP_IS_CLOSED:
150 1 : g_value_set_int(value, priv->is_closed);
151 1 : break;
152 0 : case PROP_MARKER:
153 0 : g_value_set_int(value, priv->marker);
154 0 : break;
155 684 : case PROP_INVOICE:
156 684 : qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
157 684 : break;
158 679 : case PROP_OWNER_TYPE:
159 679 : qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
160 679 : break;
161 679 : case PROP_OWNER_GUID:
162 679 : qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
163 679 : break;
164 0 : default:
165 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
166 0 : break;
167 : }
168 : }
169 :
170 : static void
171 134 : gnc_lot_set_property (GObject* object,
172 : guint prop_id,
173 : const GValue* value,
174 : GParamSpec* pspec)
175 : {
176 : GNCLot* lot;
177 : GNCLotPrivate* priv;
178 :
179 134 : g_return_if_fail(GNC_IS_LOT(object));
180 :
181 134 : lot = GNC_LOT(object);
182 134 : if (prop_id < PROP_RUNTIME_0)
183 134 : g_assert (qof_instance_get_editlevel(lot));
184 :
185 134 : priv = GET_PRIVATE(lot);
186 134 : switch (prop_id)
187 : {
188 1 : case PROP_IS_CLOSED:
189 1 : priv->is_closed = g_value_get_int(value);
190 1 : break;
191 0 : case PROP_MARKER:
192 0 : priv->marker = g_value_get_int(value);
193 0 : break;
194 83 : case PROP_INVOICE:
195 83 : qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
196 83 : break;
197 25 : case PROP_OWNER_TYPE:
198 25 : qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
199 25 : break;
200 25 : case PROP_OWNER_GUID:
201 25 : qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
202 25 : break;
203 0 : default:
204 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
205 0 : break;
206 : }
207 : }
208 :
209 : static void
210 13 : gnc_lot_class_init(GNCLotClass* klass)
211 : {
212 13 : GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
213 :
214 13 : gobject_class->dispose = gnc_lot_dispose;
215 13 : gobject_class->finalize = gnc_lot_finalize;
216 13 : gobject_class->get_property = gnc_lot_get_property;
217 13 : gobject_class->set_property = gnc_lot_set_property;
218 :
219 13 : g_object_class_install_property(
220 : gobject_class,
221 : PROP_IS_CLOSED,
222 : g_param_spec_int("is-closed",
223 : "Is Lot Closed",
224 : "Indication of whether this lot is open "
225 : "or closed to further changes.",
226 : -1, 1, 0,
227 : G_PARAM_READWRITE));
228 :
229 13 : g_object_class_install_property(
230 : gobject_class,
231 : PROP_MARKER,
232 : g_param_spec_int("marker",
233 : "Lot marker",
234 : "Ipsum Lorem",
235 : 0, G_MAXINT8, 0,
236 : G_PARAM_READWRITE));
237 :
238 13 : g_object_class_install_property(
239 : gobject_class,
240 : PROP_INVOICE,
241 : g_param_spec_boxed("invoice",
242 : "Invoice attached to lot",
243 : "Used by GncInvoice",
244 : GNC_TYPE_GUID,
245 : G_PARAM_READWRITE));
246 :
247 13 : g_object_class_install_property(
248 : gobject_class,
249 : PROP_OWNER_TYPE,
250 : g_param_spec_int64("owner-type",
251 : "Owning Entity Type of lot",
252 : "Used by GncOwner",
253 : 0, G_MAXINT64, 0,
254 : G_PARAM_READWRITE));
255 :
256 13 : g_object_class_install_property(
257 : gobject_class,
258 : PROP_OWNER_GUID,
259 : g_param_spec_boxed("owner-guid",
260 : "Owner attached to lot",
261 : "Used by GncOwner",
262 : GNC_TYPE_GUID,
263 : G_PARAM_READWRITE));
264 13 : }
265 :
266 : GNCLot *
267 235 : gnc_lot_new (QofBook *book)
268 : {
269 : GNCLot *lot;
270 235 : g_return_val_if_fail (book, nullptr);
271 :
272 235 : lot = GNC_LOT(g_object_new (GNC_TYPE_LOT, nullptr));
273 235 : qof_instance_init_data(QOF_INSTANCE(lot), GNC_ID_LOT, book);
274 235 : qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_CREATE, nullptr);
275 235 : return lot;
276 : }
277 :
278 : static void
279 126 : gnc_lot_free(GNCLot* lot)
280 : {
281 : GList *node;
282 : GNCLotPrivate* priv;
283 126 : if (!lot) return;
284 :
285 126 : ENTER ("(lot=%p)", lot);
286 126 : qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_DESTROY, nullptr);
287 :
288 126 : priv = GET_PRIVATE(lot);
289 283 : for (node = priv->splits; node; node = node->next)
290 : {
291 157 : Split *s = GNC_SPLIT(node->data);
292 157 : s->lot = nullptr;
293 : }
294 126 : g_list_free (priv->splits);
295 :
296 126 : if (priv->account && !qof_instance_get_destroying(priv->account))
297 108 : xaccAccountRemoveLot (priv->account, lot);
298 :
299 126 : priv->account = nullptr;
300 126 : priv->is_closed = TRUE;
301 : /* qof_instance_release (&lot->inst); */
302 126 : g_object_unref (lot);
303 :
304 126 : LEAVE();
305 : }
306 :
307 : void
308 126 : gnc_lot_destroy (GNCLot *lot)
309 : {
310 126 : if (!lot) return;
311 :
312 126 : gnc_lot_begin_edit(lot);
313 126 : qof_instance_set_destroying(lot, TRUE);
314 126 : gnc_lot_commit_edit(lot);
315 : }
316 :
317 : /* ============================================================= */
318 :
319 : void
320 598 : gnc_lot_begin_edit (GNCLot *lot)
321 : {
322 598 : qof_begin_edit(QOF_INSTANCE(lot));
323 598 : }
324 :
325 0 : static void commit_err (QofInstance *inst, QofBackendError errcode)
326 : {
327 0 : PERR ("Failed to commit: %d", errcode);
328 0 : gnc_engine_signal_commit_error( errcode );
329 0 : }
330 :
331 126 : static void lot_free(QofInstance* inst)
332 : {
333 126 : GNCLot* lot = GNC_LOT(inst);
334 :
335 126 : gnc_lot_free(lot);
336 126 : }
337 :
338 468 : static void noop (QofInstance *inst) {}
339 :
340 : void
341 742 : gnc_lot_commit_edit (GNCLot *lot)
342 : {
343 742 : if (!qof_commit_edit (QOF_INSTANCE(lot))) return;
344 594 : qof_commit_edit_part2 (QOF_INSTANCE(lot), commit_err, noop, lot_free);
345 : }
346 :
347 : /* ============================================================= */
348 :
349 : GNCLot *
350 16 : gnc_lot_lookup (const GncGUID *guid, QofBook *book)
351 : {
352 : QofCollection *col;
353 16 : if (!guid || !book) return nullptr;
354 16 : col = qof_book_get_collection (book, GNC_ID_LOT);
355 16 : return (GNCLot *) qof_collection_lookup_entity (col, guid);
356 : }
357 :
358 : QofBook *
359 1361 : gnc_lot_get_book (GNCLot *lot)
360 : {
361 1361 : return qof_instance_get_book(QOF_INSTANCE(lot));
362 : }
363 :
364 : /* ============================================================= */
365 :
366 : gboolean
367 1044 : gnc_lot_is_closed (GNCLot *lot)
368 : {
369 : GNCLotPrivate* priv;
370 1044 : if (!lot) return TRUE;
371 1044 : priv = GET_PRIVATE(lot);
372 1044 : if (0 > priv->is_closed) gnc_lot_get_balance (lot);
373 1044 : return priv->is_closed;
374 : }
375 :
376 : Account *
377 1129 : gnc_lot_get_account (const GNCLot *lot)
378 : {
379 : GNCLotPrivate* priv;
380 1129 : if (!lot) return nullptr;
381 1129 : priv = GET_PRIVATE(lot);
382 1129 : return priv->account;
383 : }
384 :
385 1684 : GncInvoice * gnc_lot_get_cached_invoice (const GNCLot *lot)
386 : {
387 1684 : if (!lot) return nullptr;
388 : else
389 : {
390 1684 : GNCLotPrivate *priv = GET_PRIVATE(lot);
391 1684 : return priv->cached_invoice;
392 : }
393 : }
394 :
395 : void
396 765 : gnc_lot_set_cached_invoice(GNCLot* lot, GncInvoice *invoice)
397 : {
398 765 : if (!lot) return;
399 765 : GET_PRIVATE(lot)->cached_invoice = invoice;
400 : }
401 :
402 : void
403 236 : gnc_lot_set_account(GNCLot* lot, Account* account)
404 : {
405 236 : if (lot != nullptr)
406 : {
407 : GNCLotPrivate* priv;
408 236 : priv = GET_PRIVATE(lot);
409 236 : priv->account = account;
410 : }
411 236 : }
412 :
413 : void
414 232 : gnc_lot_set_closed_unknown(GNCLot* lot)
415 : {
416 : GNCLotPrivate* priv;
417 232 : if (lot != nullptr)
418 : {
419 232 : priv = GET_PRIVATE(lot);
420 232 : priv->is_closed = LOT_CLOSED_UNKNOWN;
421 : }
422 232 : }
423 :
424 : SplitList *
425 652 : gnc_lot_get_split_list (const GNCLot *lot)
426 : {
427 : GNCLotPrivate* priv;
428 652 : if (!lot) return nullptr;
429 652 : priv = GET_PRIVATE(lot);
430 652 : return priv->splits;
431 : }
432 :
433 51 : gint gnc_lot_count_splits (const GNCLot *lot)
434 : {
435 : GNCLotPrivate* priv;
436 51 : if (!lot) return 0;
437 51 : priv = GET_PRIVATE(lot);
438 51 : return g_list_length (priv->splits);
439 : }
440 :
441 : /* ============================================================== */
442 : /* Hmm, we should probably inline these. */
443 :
444 : const char *
445 27 : gnc_lot_get_title (const GNCLot *lot)
446 : {
447 27 : if (!lot) return nullptr;
448 :
449 54 : auto str{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE (lot), {"title"})};
450 27 : return str ? *str : nullptr;
451 : }
452 :
453 : const char *
454 6 : gnc_lot_get_notes (const GNCLot *lot)
455 : {
456 6 : if (!lot) return nullptr;
457 :
458 12 : auto str{qof_instance_get_path_kvp<const char*> (QOF_INSTANCE (lot), {"notes"})};
459 6 : return str ? *str : nullptr;
460 : }
461 :
462 : void
463 140 : gnc_lot_set_title (GNCLot *lot, const char *str)
464 : {
465 140 : if (!lot) return;
466 :
467 140 : qof_begin_edit(QOF_INSTANCE(lot));
468 420 : qof_instance_set_path_kvp<const char*> (QOF_INSTANCE (lot), g_strdup(str), {"title"});
469 140 : qof_instance_set_dirty(QOF_INSTANCE(lot));
470 140 : gnc_lot_commit_edit(lot);
471 : }
472 :
473 : void
474 4 : gnc_lot_set_notes (GNCLot *lot, const char *str)
475 : {
476 4 : if (!lot) return;
477 :
478 4 : qof_begin_edit(QOF_INSTANCE(lot));
479 12 : qof_instance_set_path_kvp<const char*> (QOF_INSTANCE (lot), g_strdup(str), {"notes"});
480 4 : qof_instance_set_dirty(QOF_INSTANCE(lot));
481 4 : gnc_lot_commit_edit(lot);
482 : }
483 :
484 : /* ============================================================= */
485 :
486 : gnc_numeric
487 720 : gnc_lot_get_balance (GNCLot *lot)
488 : {
489 : GNCLotPrivate* priv;
490 : GList *node;
491 720 : gnc_numeric zero = gnc_numeric_zero();
492 720 : gnc_numeric baln = zero;
493 720 : if (!lot) return zero;
494 :
495 720 : priv = GET_PRIVATE(lot);
496 720 : if (!priv->splits)
497 : {
498 55 : priv->is_closed = FALSE;
499 55 : return zero;
500 : }
501 :
502 : /* Sum over splits; because they all belong to same account
503 : * they will have same denominator.
504 : */
505 1419 : for (node = priv->splits; node; node = node->next)
506 : {
507 754 : Split *s = GNC_SPLIT(node->data);
508 754 : if (xaccSplitIsStockSplit(s)) continue;
509 754 : gnc_numeric amt = xaccSplitGetAdjustedAmount (s);
510 754 : baln = gnc_numeric_add_fixed (baln, amt);
511 754 : g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
512 : }
513 :
514 : /* cache a zero balance as a closed lot */
515 665 : if (gnc_numeric_equal (baln, zero))
516 : {
517 33 : priv->is_closed = TRUE;
518 : }
519 : else
520 : {
521 632 : priv->is_closed = FALSE;
522 : }
523 :
524 665 : return baln;
525 : }
526 :
527 : /* ============================================================= */
528 :
529 : void
530 31 : gnc_lot_get_balance_before (const GNCLot *lot, const Split *split,
531 : gnc_numeric *amount, gnc_numeric *value)
532 : {
533 : GNCLotPrivate* priv;
534 : GList *node;
535 31 : gnc_numeric zero = gnc_numeric_zero();
536 31 : gnc_numeric amt = zero;
537 31 : gnc_numeric val = zero;
538 :
539 31 : *amount = amt;
540 31 : *value = val;
541 31 : if (lot == nullptr) return;
542 :
543 31 : priv = GET_PRIVATE(lot);
544 31 : if (priv->splits)
545 : {
546 : Transaction *ta, *tb;
547 : const Split *target;
548 : /* If this is a gains split, find the source of the gains and use
549 : its transaction for the comparison. Gains splits are in separate
550 : transactions that may sort after non-gains transactions. */
551 31 : target = xaccSplitGetGainsSourceSplit (split);
552 31 : if (target == nullptr)
553 31 : target = split;
554 31 : tb = xaccSplitGetParent (target);
555 112 : for (node = priv->splits; node; node = node->next)
556 : {
557 81 : Split *s = GNC_SPLIT(node->data);
558 81 : Split *source = xaccSplitGetGainsSourceSplit (s);
559 81 : if (source == nullptr)
560 62 : source = s;
561 81 : ta = xaccSplitGetParent (source);
562 152 : if ((ta == tb && source != target) ||
563 71 : xaccTransOrder (ta, tb) < 0)
564 : {
565 31 : gnc_numeric tmpval = xaccSplitGetAdjustedAmount (s);
566 31 : amt = gnc_numeric_add_fixed (amt, tmpval);
567 31 : tmpval = xaccSplitGetValue (s);
568 31 : val = gnc_numeric_add_fixed (val, tmpval);
569 : }
570 : }
571 : }
572 :
573 31 : *amount = amt;
574 31 : *value = val;
575 : }
576 :
577 : /* ============================================================= */
578 :
579 : void
580 266 : gnc_lot_add_split (GNCLot *lot, Split *split)
581 : {
582 : GNCLotPrivate* priv;
583 : Account * acc;
584 266 : if (!lot || !split) return;
585 266 : priv = GET_PRIVATE(lot);
586 :
587 266 : ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
588 : gnc_lot_get_title (lot),
589 : gnc_num_dbg_to_string (split->amount),
590 : gnc_num_dbg_to_string (split->value));
591 266 : gnc_lot_begin_edit(lot);
592 266 : acc = xaccSplitGetAccount (split);
593 266 : qof_instance_set_dirty(QOF_INSTANCE(lot));
594 266 : if (nullptr == priv->account)
595 : {
596 189 : xaccAccountInsertLot (acc, lot);
597 : }
598 77 : else if (priv->account != acc)
599 : {
600 0 : PERR ("splits from different accounts cannot "
601 : "be added to this lot!\n"
602 : "\tlot account=\'%s\', split account=\'%s\'\n",
603 : xaccAccountGetName(priv->account), xaccAccountGetName (acc));
604 0 : gnc_lot_commit_edit(lot);
605 0 : LEAVE("different accounts");
606 0 : return;
607 : }
608 :
609 266 : if (lot == split->lot)
610 : {
611 1 : gnc_lot_commit_edit(lot);
612 1 : LEAVE("already in lot");
613 1 : return; /* handle not-uncommon no-op */
614 : }
615 265 : if (split->lot)
616 : {
617 14 : gnc_lot_remove_split (split->lot, split);
618 : }
619 265 : xaccSplitSetLot(split, lot);
620 :
621 265 : priv->splits = g_list_append (priv->splits, split);
622 :
623 : /* for recomputation of is-closed */
624 265 : priv->is_closed = LOT_CLOSED_UNKNOWN;
625 265 : gnc_lot_commit_edit(lot);
626 :
627 265 : qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, nullptr);
628 265 : LEAVE("added to lot");
629 : }
630 :
631 : void
632 25 : gnc_lot_remove_split (GNCLot *lot, Split *split)
633 : {
634 : GNCLotPrivate* priv;
635 25 : if (!lot || !split) return;
636 25 : priv = GET_PRIVATE(lot);
637 :
638 25 : ENTER ("(lot=%p, split=%p)", lot, split);
639 25 : gnc_lot_begin_edit(lot);
640 25 : qof_instance_set_dirty(QOF_INSTANCE(lot));
641 25 : priv->splits = g_list_remove (priv->splits, split);
642 25 : xaccSplitSetLot(split, nullptr);
643 25 : priv->is_closed = LOT_CLOSED_UNKNOWN; /* force an is-closed computation */
644 :
645 25 : if (!priv->splits && priv->account)
646 : {
647 22 : xaccAccountRemoveLot (priv->account, lot);
648 22 : priv->account = nullptr;
649 : }
650 25 : gnc_lot_commit_edit(lot);
651 25 : qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, nullptr);
652 25 : LEAVE("removed from lot");
653 : }
654 :
655 : /* ============================================================== */
656 : /* Utility function, get earliest split in lot */
657 :
658 : Split *
659 1023 : gnc_lot_get_earliest_split (GNCLot *lot)
660 : {
661 : GNCLotPrivate* priv;
662 1023 : if (!lot) return nullptr;
663 1023 : priv = GET_PRIVATE(lot);
664 1023 : if (! priv->splits) return nullptr;
665 1023 : priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
666 1023 : return GNC_SPLIT(priv->splits->data);
667 : }
668 :
669 : /* Utility function, get latest split in lot */
670 : Split *
671 48 : gnc_lot_get_latest_split (GNCLot *lot)
672 : {
673 : GNCLotPrivate* priv;
674 : SplitList *node;
675 :
676 48 : if (!lot) return nullptr;
677 48 : priv = GET_PRIVATE(lot);
678 48 : if (! priv->splits) return nullptr;
679 48 : priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
680 :
681 50 : for (node = priv->splits; node->next; node = node->next)
682 : ;
683 :
684 48 : return GNC_SPLIT(node->data);
685 : }
686 :
687 : /* ============================================================= */
688 :
689 : static void
690 0 : destroy_lot_on_book_close(QofInstance *ent, gpointer data)
691 : {
692 0 : GNCLot* lot = GNC_LOT(ent);
693 :
694 0 : gnc_lot_destroy(lot);
695 0 : }
696 :
697 : static void
698 179 : gnc_lot_book_end(QofBook* book)
699 : {
700 : QofCollection *col;
701 :
702 179 : col = qof_book_get_collection(book, GNC_ID_LOT);
703 179 : qof_collection_foreach(col, destroy_lot_on_book_close, nullptr);
704 179 : }
705 :
706 : #ifdef _MSC_VER
707 : /* MSVC compiler doesn't have C99 "designated initializers"
708 : * so we wrap them in a macro that is empty on MSVC. */
709 : # define DI(x) /* */
710 : #else
711 : # define DI(x) x
712 : #endif
713 : static QofObject gncLotDesc =
714 : {
715 : DI(.interface_version = ) QOF_OBJECT_VERSION,
716 : DI(.e_type = ) GNC_ID_LOT,
717 : DI(.type_label = ) "Lot",
718 : DI(.create = ) (void* (*)(QofBook*))gnc_lot_new,
719 : DI(.book_begin = ) nullptr,
720 : DI(.book_end = ) gnc_lot_book_end,
721 : DI(.is_dirty = ) qof_collection_is_dirty,
722 : DI(.mark_clean = ) qof_collection_mark_clean,
723 : DI(.foreach = ) qof_collection_foreach,
724 : DI(.printable = ) nullptr,
725 : DI(.version_cmp = ) (int (*)(gpointer, gpointer))qof_instance_version_cmp,
726 : };
727 :
728 :
729 83 : gboolean gnc_lot_register (void)
730 : {
731 : static const QofParam params[] =
732 : {
733 : {
734 : LOT_TITLE, QOF_TYPE_STRING,
735 : (QofAccessFunc) gnc_lot_get_title,
736 : (QofSetterFunc) gnc_lot_set_title
737 : },
738 : {
739 : LOT_NOTES, QOF_TYPE_STRING,
740 : (QofAccessFunc) gnc_lot_get_notes,
741 : (QofSetterFunc) gnc_lot_set_notes
742 : },
743 : {
744 : QOF_PARAM_GUID, QOF_TYPE_GUID,
745 : (QofAccessFunc) qof_entity_get_guid, nullptr
746 : },
747 : {
748 : QOF_PARAM_BOOK, QOF_ID_BOOK,
749 : (QofAccessFunc) gnc_lot_get_book, nullptr
750 : },
751 : {
752 : LOT_IS_CLOSED, QOF_TYPE_BOOLEAN,
753 : (QofAccessFunc) gnc_lot_is_closed, nullptr
754 : },
755 : {
756 : LOT_BALANCE, QOF_TYPE_NUMERIC,
757 : (QofAccessFunc) gnc_lot_get_balance, nullptr
758 : },
759 : { nullptr },
760 : };
761 :
762 83 : qof_class_register (GNC_ID_LOT, nullptr, params);
763 83 : return qof_object_register(&gncLotDesc);
764 : }
765 :
766 55 : GNCLot * gnc_lot_make_default (Account *acc)
767 : {
768 : GNCLot * lot;
769 55 : gint64 id = 0;
770 : gchar *buff;
771 :
772 55 : lot = gnc_lot_new (qof_instance_get_book(acc));
773 :
774 : /* Provide a reasonable title for the new lot */
775 55 : xaccAccountBeginEdit (acc);
776 55 : qof_instance_get (QOF_INSTANCE (acc), "lot-next-id", &id, nullptr);
777 55 : buff = g_strdup_printf ("%s %" G_GINT64_FORMAT, _("Lot"), id);
778 55 : gnc_lot_set_title (lot, buff);
779 55 : id ++;
780 55 : qof_instance_set (QOF_INSTANCE (acc), "lot-next-id", id, nullptr);
781 55 : xaccAccountCommitEdit (acc);
782 55 : g_free (buff);
783 55 : return lot;
784 : }
785 :
786 : /* ========================== END OF FILE ========================= */
|