GnuCash  4.12-558-g06612b8434
gnc-lot.c
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.h"
50 #include "gnc-lot.h"
51 #include "gnc-lot-p.h"
52 #include "cap-gains.h"
53 #include "Transaction.h"
54 #include "TransactionP.h"
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 static char*
110 is_unset = "unset";
111 
112 /* GObject Initialization */
113 G_DEFINE_TYPE_WITH_PRIVATE(GNCLot, gnc_lot, QOF_TYPE_INSTANCE)
114 
115 static void
116 gnc_lot_init(GNCLot* lot)
117 {
118  GNCLotPrivate* priv;
119 
120  priv = GET_PRIVATE(lot);
121  priv->account = NULL;
122  priv->splits = NULL;
123  priv->cached_invoice = NULL;
124  priv->is_closed = LOT_CLOSED_UNKNOWN;
125  priv->title = is_unset;
126  priv->notes = is_unset;
127  priv->marker = 0;
128 }
129 
130 static void
131 gnc_lot_dispose(GObject *lotp)
132 {
133  G_OBJECT_CLASS(gnc_lot_parent_class)->dispose(lotp);
134 }
135 
136 static void
137 gnc_lot_finalize(GObject* lotp)
138 {
139  G_OBJECT_CLASS(gnc_lot_parent_class)->finalize(lotp);
140 }
141 
142 static void
143 gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
144 {
145  GNCLot* lot;
146  GNCLotPrivate* priv;
147  gchar *key;
148 
149  g_return_if_fail(GNC_IS_LOT(object));
150 
151  lot = GNC_LOT(object);
152  priv = GET_PRIVATE(lot);
153  switch (prop_id)
154  {
155  case PROP_IS_CLOSED:
156  g_value_set_int(value, priv->is_closed);
157  break;
158  case PROP_MARKER:
159  g_value_set_int(value, priv->marker);
160  break;
161  case PROP_INVOICE:
162  qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
163  break;
164  case PROP_OWNER_TYPE:
165  qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
166  break;
167  case PROP_OWNER_GUID:
168  qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
169  break;
170  default:
171  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
172  break;
173  }
174 }
175 
176 static void
177 gnc_lot_set_property (GObject* object,
178  guint prop_id,
179  const GValue* value,
180  GParamSpec* pspec)
181 {
182  GNCLot* lot;
183  GNCLotPrivate* priv;
184  gchar *key = NULL;
185 
186  g_return_if_fail(GNC_IS_LOT(object));
187 
188  lot = GNC_LOT(object);
189  if (prop_id < PROP_RUNTIME_0)
190  g_assert (qof_instance_get_editlevel(lot));
191 
192  priv = GET_PRIVATE(lot);
193  switch (prop_id)
194  {
195  case PROP_IS_CLOSED:
196  priv->is_closed = g_value_get_int(value);
197  break;
198  case PROP_MARKER:
199  priv->marker = g_value_get_int(value);
200  break;
201  case PROP_INVOICE:
202  qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
203  break;
204  case PROP_OWNER_TYPE:
205  qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
206  break;
207  case PROP_OWNER_GUID:
208  qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
209  break;
210  default:
211  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
212  break;
213  }
214 }
215 
216 static void
217 gnc_lot_class_init(GNCLotClass* klass)
218 {
219  GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
220 
221  gobject_class->dispose = gnc_lot_dispose;
222  gobject_class->finalize = gnc_lot_finalize;
223  gobject_class->get_property = gnc_lot_get_property;
224  gobject_class->set_property = gnc_lot_set_property;
225 
226  g_object_class_install_property(
227  gobject_class,
228  PROP_IS_CLOSED,
229  g_param_spec_int("is-closed",
230  "Is Lot Closed",
231  "Indication of whether this lot is open "
232  "or closed to further changes.",
233  -1, 1, 0,
234  G_PARAM_READWRITE));
235 
236  g_object_class_install_property(
237  gobject_class,
238  PROP_MARKER,
239  g_param_spec_int("marker",
240  "Lot marker",
241  "Ipsum Lorem",
242  0, G_MAXINT8, 0,
243  G_PARAM_READWRITE));
244 
245  g_object_class_install_property(
246  gobject_class,
247  PROP_INVOICE,
248  g_param_spec_boxed("invoice",
249  "Invoice attached to lot",
250  "Used by GncInvoice",
251  GNC_TYPE_GUID,
252  G_PARAM_READWRITE));
253 
254  g_object_class_install_property(
255  gobject_class,
256  PROP_OWNER_TYPE,
257  g_param_spec_int64("owner-type",
258  "Owning Entity Type of lot",
259  "Used by GncOwner",
260  0, G_MAXINT64, 0,
261  G_PARAM_READWRITE));
262 
263  g_object_class_install_property(
264  gobject_class,
265  PROP_OWNER_GUID,
266  g_param_spec_boxed("owner-guid",
267  "Owner attached to lot",
268  "Used by GncOwner",
269  GNC_TYPE_GUID,
270  G_PARAM_READWRITE));
271 }
272 
273 GNCLot *
274 gnc_lot_new (QofBook *book)
275 {
276  GNCLot *lot;
277  g_return_val_if_fail (book, NULL);
278 
279  lot = g_object_new (GNC_TYPE_LOT, NULL);
280  qof_instance_init_data(QOF_INSTANCE(lot), GNC_ID_LOT, book);
281  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_CREATE, NULL);
282  return lot;
283 }
284 
285 static void
286 gnc_lot_free(GNCLot* lot)
287 {
288  GList *node;
289  GNCLotPrivate* priv;
290  if (!lot) return;
291 
292  ENTER ("(lot=%p)", lot);
293  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_DESTROY, NULL);
294 
295  priv = GET_PRIVATE(lot);
296  for (node = priv->splits; node; node = node->next)
297  {
298  Split *s = node->data;
299  s->lot = NULL;
300  }
301  g_list_free (priv->splits);
302 
303  if (priv->account && !qof_instance_get_destroying(priv->account))
304  xaccAccountRemoveLot (priv->account, lot);
305 
306  if (priv->notes != is_unset)
307  g_free (priv->notes);
308 
309  if (priv->title != is_unset)
310  g_free (priv->title);
311 
312  priv->notes = NULL;
313  priv->title = NULL;
314  priv->account = NULL;
315  priv->is_closed = TRUE;
316  /* qof_instance_release (&lot->inst); */
317  g_object_unref (lot);
318 
319  LEAVE();
320 }
321 
322 void
323 gnc_lot_destroy (GNCLot *lot)
324 {
325  if (!lot) return;
326 
327  gnc_lot_begin_edit(lot);
328  qof_instance_set_destroying(lot, TRUE);
329  gnc_lot_commit_edit(lot);
330 }
331 
332 /* ============================================================= */
333 
334 void
335 gnc_lot_begin_edit (GNCLot *lot)
336 {
337  qof_begin_edit(QOF_INSTANCE(lot));
338 }
339 
340 static void commit_err (QofInstance *inst, QofBackendError errcode)
341 {
342  PERR ("Failed to commit: %d", errcode);
343  gnc_engine_signal_commit_error( errcode );
344 }
345 
346 static void lot_free(QofInstance* inst)
347 {
348  GNCLot* lot = GNC_LOT(inst);
349 
350  gnc_lot_free(lot);
351 }
352 
353 static void noop (QofInstance *inst) {}
354 
355 void
356 gnc_lot_commit_edit (GNCLot *lot)
357 {
358  if (!qof_commit_edit (QOF_INSTANCE(lot))) return;
359  qof_commit_edit_part2 (QOF_INSTANCE(lot), commit_err, noop, lot_free);
360 }
361 
362 /* ============================================================= */
363 
364 GNCLot *
365 gnc_lot_lookup (const GncGUID *guid, QofBook *book)
366 {
367  QofCollection *col;
368  if (!guid || !book) return NULL;
369  col = qof_book_get_collection (book, GNC_ID_LOT);
370  return (GNCLot *) qof_collection_lookup_entity (col, guid);
371 }
372 
373 QofBook *
374 gnc_lot_get_book (GNCLot *lot)
375 {
376  return qof_instance_get_book(QOF_INSTANCE(lot));
377 }
378 
379 /* ============================================================= */
380 
381 gboolean
382 gnc_lot_is_closed (GNCLot *lot)
383 {
384  GNCLotPrivate* priv;
385  if (!lot) return TRUE;
386  priv = GET_PRIVATE(lot);
387  if (0 > priv->is_closed) gnc_lot_get_balance (lot);
388  return priv->is_closed;
389 }
390 
391 Account *
392 gnc_lot_get_account (const GNCLot *lot)
393 {
394  GNCLotPrivate* priv;
395  if (!lot) return NULL;
396  priv = GET_PRIVATE(lot);
397  return priv->account;
398 }
399 
400 GncInvoice * gnc_lot_get_cached_invoice (const GNCLot *lot)
401 {
402  if (!lot) return NULL;
403  else
404  {
405  GNCLotPrivate *priv = GET_PRIVATE(lot);
406  return priv->cached_invoice;
407  }
408 }
409 
410 void
411 gnc_lot_set_cached_invoice(GNCLot* lot, GncInvoice *invoice)
412 {
413  if (!lot) return;
414  GET_PRIVATE(lot)->cached_invoice = invoice;
415 }
416 
417 void
418 gnc_lot_set_account(GNCLot* lot, Account* account)
419 {
420  if (lot != NULL)
421  {
422  GNCLotPrivate* priv;
423  priv = GET_PRIVATE(lot);
424  priv->account = account;
425  }
426 }
427 
428 void
430 {
431  GNCLotPrivate* priv;
432  if (lot != NULL)
433  {
434  priv = GET_PRIVATE(lot);
435  priv->is_closed = LOT_CLOSED_UNKNOWN;
436  }
437 }
438 
439 SplitList *
440 gnc_lot_get_split_list (const GNCLot *lot)
441 {
442  GNCLotPrivate* priv;
443  if (!lot) return NULL;
444  priv = GET_PRIVATE(lot);
445  return priv->splits;
446 }
447 
448 gint gnc_lot_count_splits (const GNCLot *lot)
449 {
450  GNCLotPrivate* priv;
451  if (!lot) return 0;
452  priv = GET_PRIVATE(lot);
453  return g_list_length (priv->splits);
454 }
455 
456 /* ============================================================== */
457 /* Hmm, we should probably inline these. */
458 
459 const char *
460 gnc_lot_get_title (const GNCLot *lot)
461 {
462  GNCLotPrivate* priv;
463  if (!lot) return NULL;
464  priv = GET_PRIVATE (lot);
465  if (priv->title == is_unset)
466  {
467  GNCLotPrivate* priv = GET_PRIVATE (lot);
468  GValue v = G_VALUE_INIT;
469  qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
470  priv->title = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
471  g_value_unset (&v);
472  }
473  return priv->title;
474 }
475 
476 const char *
477 gnc_lot_get_notes (const GNCLot *lot)
478 {
479  GNCLotPrivate* priv;
480  if (!lot) return NULL;
481  priv = GET_PRIVATE (lot);
482  if (priv->notes == is_unset)
483  {
484  GValue v = G_VALUE_INIT;
485  qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
486  priv->notes = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
487  g_value_unset (&v);
488  }
489  return priv->notes;
490 }
491 
492 void
493 gnc_lot_set_title (GNCLot *lot, const char *str)
494 {
495  GValue v = G_VALUE_INIT;
496  GNCLotPrivate* priv;
497  if (!lot) return;
498  priv = GET_PRIVATE (lot);
499  if (priv->title != is_unset)
500  g_free (priv->title);
501 
502  qof_begin_edit(QOF_INSTANCE(lot));
503  g_value_init (&v, G_TYPE_STRING);
504  g_value_set_string (&v, str);
505  priv->title = g_strdup (str);
506  qof_instance_set_kvp (QOF_INSTANCE (lot), &v, 1, "title");
507  qof_instance_set_dirty(QOF_INSTANCE(lot));
508  gnc_lot_commit_edit(lot);
509  g_value_unset (&v);
510 }
511 
512 void
513 gnc_lot_set_notes (GNCLot *lot, const char *str)
514 {
515  GValue v = G_VALUE_INIT;
516  GNCLotPrivate* priv;
517  if (!lot) return;
518  priv = GET_PRIVATE (lot);
519  if (priv->notes != is_unset)
520  g_free (priv->notes);
521  qof_begin_edit(QOF_INSTANCE(lot));
522  g_value_init (&v, G_TYPE_STRING);
523  g_value_set_string (&v, str);
524  priv->notes = g_strdup (str);
525  qof_instance_set_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
526  qof_instance_set_dirty(QOF_INSTANCE(lot));
527  gnc_lot_commit_edit(lot);
528  g_value_unset (&v);
529 }
530 
531 /* ============================================================= */
532 
533 gnc_numeric
534 gnc_lot_get_balance (GNCLot *lot)
535 {
536  GNCLotPrivate* priv;
537  GList *node;
538  gnc_numeric zero = gnc_numeric_zero();
539  gnc_numeric baln = zero;
540  if (!lot) return zero;
541 
542  priv = GET_PRIVATE(lot);
543  if (!priv->splits)
544  {
545  priv->is_closed = FALSE;
546  return zero;
547  }
548 
549  /* Sum over splits; because they all belong to same account
550  * they will have same denominator.
551  */
552  for (node = priv->splits; node; node = node->next)
553  {
554  Split *s = node->data;
555  gnc_numeric amt = xaccSplitGetAmount (s);
556  baln = gnc_numeric_add_fixed (baln, amt);
557  g_assert (gnc_numeric_check (baln) == GNC_ERROR_OK);
558  }
559 
560  /* cache a zero balance as a closed lot */
561  if (gnc_numeric_equal (baln, zero))
562  {
563  priv->is_closed = TRUE;
564  }
565  else
566  {
567  priv->is_closed = FALSE;
568  }
569 
570  return baln;
571 }
572 
573 /* ============================================================= */
574 
575 void
576 gnc_lot_get_balance_before (const GNCLot *lot, const Split *split,
577  gnc_numeric *amount, gnc_numeric *value)
578 {
579  GNCLotPrivate* priv;
580  GList *node;
581  gnc_numeric zero = gnc_numeric_zero();
582  gnc_numeric amt = zero;
583  gnc_numeric val = zero;
584 
585  *amount = amt;
586  *value = val;
587  if (lot == NULL) return;
588 
589  priv = GET_PRIVATE(lot);
590  if (priv->splits)
591  {
592  Transaction *ta, *tb;
593  const Split *target;
594  /* If this is a gains split, find the source of the gains and use
595  its transaction for the comparison. Gains splits are in separate
596  transactions that may sort after non-gains transactions. */
597  target = xaccSplitGetGainsSourceSplit (split);
598  if (target == NULL)
599  target = split;
600  tb = xaccSplitGetParent (target);
601  for (node = priv->splits; node; node = node->next)
602  {
603  Split *s = node->data;
604  Split *source = xaccSplitGetGainsSourceSplit (s);
605  if (source == NULL)
606  source = s;
607  ta = xaccSplitGetParent (source);
608  if ((ta == tb && source != target) ||
609  xaccTransOrder (ta, tb) < 0)
610  {
611  gnc_numeric tmpval = xaccSplitGetAmount (s);
612  amt = gnc_numeric_add_fixed (amt, tmpval);
613  tmpval = xaccSplitGetValue (s);
614  val = gnc_numeric_add_fixed (val, tmpval);
615  }
616  }
617  }
618 
619  *amount = amt;
620  *value = val;
621 }
622 
623 /* ============================================================= */
624 
625 void
626 gnc_lot_add_split (GNCLot *lot, Split *split)
627 {
628  GNCLotPrivate* priv;
629  Account * acc;
630  if (!lot || !split) return;
631  priv = GET_PRIVATE(lot);
632 
633  ENTER ("(lot=%p, split=%p) %s amt=%s val=%s", lot, split,
634  gnc_lot_get_title (lot),
635  gnc_num_dbg_to_string (split->amount),
636  gnc_num_dbg_to_string (split->value));
637  gnc_lot_begin_edit(lot);
638  acc = xaccSplitGetAccount (split);
639  qof_instance_set_dirty(QOF_INSTANCE(lot));
640  if (NULL == priv->account)
641  {
642  xaccAccountInsertLot (acc, lot);
643  }
644  else if (priv->account != acc)
645  {
646  PERR ("splits from different accounts cannot "
647  "be added to this lot!\n"
648  "\tlot account=\'%s\', split account=\'%s\'\n",
649  xaccAccountGetName(priv->account), xaccAccountGetName (acc));
650  gnc_lot_commit_edit(lot);
651  LEAVE("different accounts");
652  return;
653  }
654 
655  if (lot == split->lot)
656  {
657  gnc_lot_commit_edit(lot);
658  LEAVE("already in lot");
659  return; /* handle not-uncommon no-op */
660  }
661  if (split->lot)
662  {
663  gnc_lot_remove_split (split->lot, split);
664  }
665  xaccSplitSetLot(split, lot);
666 
667  priv->splits = g_list_append (priv->splits, split);
668 
669  /* for recomputation of is-closed */
670  priv->is_closed = LOT_CLOSED_UNKNOWN;
671  gnc_lot_commit_edit(lot);
672 
673  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
674  LEAVE("added to lot");
675 }
676 
677 void
678 gnc_lot_remove_split (GNCLot *lot, Split *split)
679 {
680  GNCLotPrivate* priv;
681  if (!lot || !split) return;
682  priv = GET_PRIVATE(lot);
683 
684  ENTER ("(lot=%p, split=%p)", lot, split);
685  gnc_lot_begin_edit(lot);
686  qof_instance_set_dirty(QOF_INSTANCE(lot));
687  priv->splits = g_list_remove (priv->splits, split);
688  xaccSplitSetLot(split, NULL);
689  priv->is_closed = LOT_CLOSED_UNKNOWN; /* force an is-closed computation */
690 
691  if (NULL == priv->splits)
692  {
693  xaccAccountRemoveLot (priv->account, lot);
694  priv->account = NULL;
695  }
696  gnc_lot_commit_edit(lot);
697  qof_event_gen (QOF_INSTANCE(lot), QOF_EVENT_MODIFY, NULL);
698  LEAVE("removed from lot");
699 }
700 
701 /* ============================================================== */
702 /* Utility function, get earliest split in lot */
703 
704 Split *
706 {
707  GNCLotPrivate* priv;
708  if (!lot) return NULL;
709  priv = GET_PRIVATE(lot);
710  if (! priv->splits) return NULL;
711  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
712  return priv->splits->data;
713 }
714 
715 /* Utility function, get latest split in lot */
716 Split *
718 {
719  GNCLotPrivate* priv;
720  SplitList *node;
721 
722  if (!lot) return NULL;
723  priv = GET_PRIVATE(lot);
724  if (! priv->splits) return NULL;
725  priv->splits = g_list_sort (priv->splits, (GCompareFunc) xaccSplitOrderDateOnly);
726 
727  for (node = priv->splits; node->next; node = node->next)
728  ;
729 
730  return node->data;
731 }
732 
733 /* ============================================================= */
734 
735 static void
736 destroy_lot_on_book_close(QofInstance *ent, gpointer data)
737 {
738  GNCLot* lot = GNC_LOT(ent);
739 
740  gnc_lot_destroy(lot);
741 }
742 
743 static void
744 gnc_lot_book_end(QofBook* book)
745 {
746  QofCollection *col;
747 
748  col = qof_book_get_collection(book, GNC_ID_LOT);
749  qof_collection_foreach(col, destroy_lot_on_book_close, NULL);
750 }
751 
752 #ifdef _MSC_VER
753 /* MSVC compiler doesn't have C99 "designated initializers"
754  * so we wrap them in a macro that is empty on MSVC. */
755 # define DI(x) /* */
756 #else
757 # define DI(x) x
758 #endif
759 static QofObject gncLotDesc =
760 {
761  DI(.interface_version = ) QOF_OBJECT_VERSION,
762  DI(.e_type = ) GNC_ID_LOT,
763  DI(.type_label = ) "Lot",
764  DI(.create = ) (gpointer)gnc_lot_new,
765  DI(.book_begin = ) NULL,
766  DI(.book_end = ) gnc_lot_book_end,
767  DI(.is_dirty = ) qof_collection_is_dirty,
768  DI(.mark_clean = ) qof_collection_mark_clean,
769  DI(.foreach = ) qof_collection_foreach,
770  DI(.printable = ) NULL,
771  DI(.version_cmp = ) (int (*)(gpointer, gpointer))qof_instance_version_cmp,
772 };
773 
774 
775 gboolean gnc_lot_register (void)
776 {
777  static const QofParam params[] =
778  {
779  {
780  LOT_TITLE, QOF_TYPE_STRING,
782  (QofSetterFunc) gnc_lot_set_title
783  },
784  {
785  LOT_NOTES, QOF_TYPE_STRING,
786  (QofAccessFunc) gnc_lot_get_notes,
787  (QofSetterFunc) gnc_lot_set_notes
788  },
789  {
790  QOF_PARAM_GUID, QOF_TYPE_GUID,
792  },
793  {
794  QOF_PARAM_BOOK, QOF_ID_BOOK,
795  (QofAccessFunc) gnc_lot_get_book, NULL
796  },
797  {
798  LOT_IS_CLOSED, QOF_TYPE_BOOLEAN,
800  },
801  {
802  LOT_BALANCE, QOF_TYPE_NUMERIC,
804  },
805  { NULL },
806  };
807 
808  qof_class_register (GNC_ID_LOT, NULL, params);
809  return qof_object_register(&gncLotDesc);
810 }
811 
813 {
814  GNCLot * lot;
815  gint64 id = 0;
816  gchar *buff;
817 
818  lot = gnc_lot_new (qof_instance_get_book(acc));
819 
820  /* Provide a reasonable title for the new lot */
821  xaccAccountBeginEdit (acc);
822  qof_instance_get (QOF_INSTANCE (acc), "lot-next-id", &id, NULL);
823  buff = g_strdup_printf ("%s %" G_GINT64_FORMAT, _("Lot"), id);
824  gnc_lot_set_title (lot, buff);
825  id ++;
826  qof_instance_set (QOF_INSTANCE (acc), "lot-next-id", id, NULL);
827  xaccAccountCommitEdit (acc);
828  g_free (buff);
829  return lot;
830 }
831 
832 /* ========================== END OF FILE ========================= */
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
void qof_instance_set_kvp(QofInstance *, GValue const *value, unsigned count,...)
Sets a KVP slot to a value from a GValue.
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
gboolean qof_collection_is_dirty(const QofCollection *col)
Return value of &#39;dirty&#39; flag on collection.
Definition: qofid.cpp:257
QofInstance * qof_collection_lookup_entity(const QofCollection *col, const GncGUID *guid)
Find the entity going only from its guid.
Definition: qofid.cpp:215
GncInvoice * gnc_lot_get_cached_invoice(const GNCLot *lot)
The gnc_lot_get_cached_invoice() routine returns the invoice with which this lot is associated...
Definition: gnc-lot.c:400
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
Identifies that something sold at one time was bought at another.
Definition: gnc-lot.c:60
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
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
void gnc_lot_add_split(GNCLot *lot, Split *split)
The gnc_lot_add_split() routine adds a split to this lot.
Definition: gnc-lot.c:626
Split * xaccSplitGetGainsSourceSplit(const Split *split)
The xaccSplitGetGainsSourceSplit() routine returns the split that is the source of the cap gains in t...
Definition: cap-gains.c:505
void xaccAccountInsertLot(Account *acc, GNCLot *lot)
The xaccAccountInsertLot() method will register the indicated lot with this account.
Definition: Account.cpp:2143
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define QOF_OBJECT_VERSION
Defines the version of the core object object registration interface.
Definition: qofobject.h:64
gboolean qof_commit_edit(QofInstance *inst)
commit_edit helpers
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:109
void gnc_lot_set_closed_unknown(GNCLot *lot)
Reset closed flag so that it will be recalculated.
Definition: gnc-lot.c:429
void qof_collection_foreach(const QofCollection *col, QofInstanceForeachCB cb_func, gpointer user_data)
Call the callback for each entity in the collection.
Definition: qofid.cpp:323
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:184
void qof_instance_get_kvp(QofInstance *, GValue *value, unsigned count,...)
Retrieves the contents of a KVP slot into a provided GValue.
Split * gnc_lot_get_earliest_split(GNCLot *lot)
The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest da...
Definition: gnc-lot.c:705
const char * gnc_lot_get_title(const GNCLot *lot)
Get and set the account title, or the account notes, or the marker.
Definition: gnc-lot.c:460
Split * gnc_lot_get_latest_split(GNCLot *lot)
The gnc_lot_get_latest_split() routine is a convenience routine that helps identify the date this lot...
Definition: gnc-lot.c:717
void qof_instance_init_data(QofInstance *inst, QofIdType type, QofBook *book)
Initialise the settings associated with an instance.
gboolean qof_begin_edit(QofInstance *inst)
begin_edit
GList SplitList
GList of Split.
Definition: gnc-engine.h:211
Account handling public routines.
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.c:440
void gnc_lot_get_balance_before(const GNCLot *lot, const Split *split, gnc_numeric *amount, gnc_numeric *value)
The gnc_lot_get_balance_before routine computes both the balance and value in the lot considering onl...
Definition: gnc-lot.c:576
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
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:263
#define GNC_INVOICE_ID
STRING CONSTANTS ********************************************** Used to declare constant KVP keys use...
Definition: gnc-engine.h:261
const GncGUID * qof_entity_get_guid(gconstpointer ent)
void xaccSplitSetLot(Split *split, GNCLot *lot)
Assigns the split to a specific Lot.
Definition: Split.c:1883
Business Invoice Interface.
GNCLot * gnc_lot_make_default(Account *acc)
XXX: Document?
Definition: gnc-lot.c:812
gboolean gnc_lot_is_closed(GNCLot *lot)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.c:382
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1449
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
This is the private header for the account structure.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
int xaccTransOrder(const Transaction *ta, const Transaction *tb)
The xaccTransOrder(ta,tb) method is useful for sorting.
Definition: Transaction.c:1896
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
QofCollection * qof_book_get_collection(const QofBook *book, QofIdType entity_type)
Return The table of entities of the given type.
Definition: qofbook.cpp:532
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:392
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:317
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3301
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
No error.
Definition: gnc-numeric.h:224
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1490
Utilities to Automatically Compute Capital Gains/Losses.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:534
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69