GnuCash  4.8a-132-gcdaeb421d+
gncInvoice.c
1 /********************************************************************\
2  * gncInvoice.c -- the Core Business Invoice *
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 /*
24  * Copyright (C) 2001,2002,2006 Derek Atkins
25  * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
26  * Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
27  * Author: Derek Atkins <warlord@MIT.EDU>
28  */
29 
30 #include <config.h>
31 
32 #include <stdint.h>
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <qofinstance-p.h>
36 
37 #include "Transaction.h"
38 #include "Account.h"
39 #include "gncBillTermP.h"
40 #include "gncEntry.h"
41 #include "gncEntryP.h"
42 #include "gnc-features.h"
43 #include "gncJobP.h"
44 #include "gncInvoice.h"
45 #include "gncInvoiceP.h"
46 #include "gncOwnerP.h"
47 #include "engine-helpers.h"
48 
50 {
51  QofInstance inst;
52 
53  const char *id;
54  const char *notes;
55  gboolean active;
56 
57  const char *billing_id;
58  char *printname;
59  GncBillTerm *terms;
60  GList *entries;
61  GList *prices;
62  GncOwner owner;
63  GncOwner billto;
64  GncJob *job;
65  time64 date_opened;
66  time64 date_posted;
67 
68  char *doclink;
69 
70  gnc_numeric to_charge_amount;
71 
72  gnc_commodity *currency;
73 
74  Account *posted_acc;
75  Transaction *posted_txn;
76  GNCLot *posted_lot;
77 };
78 
80 {
81  QofInstanceClass parent_class;
82 };
83 
84 static QofLogModule log_module = GNC_MOD_BUSINESS;
85 
86 #define _GNC_MOD_NAME GNC_ID_INVOICE
87 
88 #define GNC_INVOICE_IS_CN "credit-note"
89 #define GNC_INVOICE_DOCLINK "assoc_uri" // this is the old name for the document link, kept for compatibility
90 
91 #define SET_STR(obj, member, str) { \
92  if (!g_strcmp0 (member, str)) return; \
93  gncInvoiceBeginEdit (obj); \
94  CACHE_REPLACE (member, str); \
95  }
96 
97 static void mark_invoice (GncInvoice *invoice);
98 static void
99 mark_invoice (GncInvoice *invoice)
100 {
101  qof_instance_set_dirty (&invoice->inst);
102  qof_event_gen (&invoice->inst, QOF_EVENT_MODIFY, NULL);
103 }
104 
105 QofBook * gncInvoiceGetBook (GncInvoice *x)
106 {
107  return qof_instance_get_book (QOF_INSTANCE(x));
108 }
109 
110 /* ================================================================== */
111 
112 enum
113 {
114  PROP_0,
115 // PROP_ID, /* Table */
116 // PROP_DATE_OPENED, /* Table */
117 // PROP_DATE_POSTED, /* Table */
118  PROP_NOTES, /* Table */
119 // PROP_ACTIVE, /* Table */
120 // PROP_CURRENCY, /* Table */
121 // PROP_OWNER_TYPE, /* Table */
122 // PROP_OWNER, /* Table */
123 // PROP_TERMS, /* Table */
124 // PROP_BILLING_ID, /* Table */
125 // PROP_POST_TXN, /* Table */
126 // PROP_POST_LOT, /* Table */
127 // PROP_POST_ACCOUNT, /* Table */
128 // PROP_BILLTO_TYPE, /* Table */
129 // PROP_BILLTO, /* Table */
130 // PROP_CHARGE_AMOUNT, /* Table, (numeric) */
131 };
132 
133 /* GObject Initialization */
134 G_DEFINE_TYPE(GncInvoice, gnc_invoice, QOF_TYPE_INSTANCE);
135 
136 static void
137 gnc_invoice_init (GncInvoice* inv)
138 {
139  inv->date_posted = INT64_MAX;
140  inv->date_opened = INT64_MAX;
141 }
142 
143 static void
144 gnc_invoice_dispose (GObject *invp)
145 {
146  G_OBJECT_CLASS(gnc_invoice_parent_class)->dispose(invp);
147 }
148 
149 static void
150 gnc_invoice_finalize (GObject* invp)
151 {
152  G_OBJECT_CLASS(gnc_invoice_parent_class)->finalize(invp);
153 }
154 
155 static void
156 gnc_invoice_get_property (GObject *object,
157  guint prop_id,
158  GValue *value,
159  GParamSpec *pspec)
160 {
161  GncInvoice *inv;
162 
163  g_return_if_fail (GNC_IS_INVOICE(object));
164 
165  inv = GNC_INVOICE(object);
166  switch (prop_id)
167  {
168  case PROP_NOTES:
169  g_value_set_string (value, inv->notes);
170  break;
171  default:
172  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
173  break;
174  }
175 }
176 
177 static void
178 gnc_invoice_set_property (GObject *object,
179  guint prop_id,
180  const GValue *value,
181  GParamSpec *pspec)
182 {
183  GncInvoice *inv;
184 
185  g_return_if_fail (GNC_IS_INVOICE(object));
186 
187  inv = GNC_INVOICE(object);
188  g_assert (qof_instance_get_editlevel (inv));
189 
190  switch (prop_id)
191  {
192  case PROP_NOTES:
193  gncInvoiceSetNotes (inv, g_value_get_string (value));
194  break;
195  default:
196  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
197  break;
198  }
199 }
200 
202 static gchar*
203 impl_get_display_name (const QofInstance* inst)
204 {
205  GncInvoice* inv;
206  QofInstance* owner;
207  gchar* s;
208 
209  g_return_val_if_fail (inst != NULL, FALSE);
210  g_return_val_if_fail (GNC_IS_INVOICE(inst), FALSE);
211 
212  inv = GNC_INVOICE(inst);
213  owner = qofOwnerGetOwner (&inv->owner);
214  if (owner != NULL)
215  {
216  gchar* display_name;
217 
218  display_name = qof_instance_get_display_name (owner);
219  s = g_strdup_printf ("Invoice %s (%s)", inv->id, display_name);
220  g_free (display_name);
221  }
222  else
223  {
224  s = g_strdup_printf ("Invoice %s", inv->id);
225  }
226 
227  return s;
228 }
229 
231 static gboolean
232 impl_refers_to_object (const QofInstance* inst, const QofInstance* ref)
233 {
234  GncInvoice* inv;
235 
236  g_return_val_if_fail (inst != NULL, FALSE);
237  g_return_val_if_fail (GNC_IS_INVOICE(inst), FALSE);
238 
239  inv = GNC_INVOICE(inst);
240 
241  if (GNC_IS_BILLTERM(ref))
242  {
243  return (inv->terms == GNC_BILLTERM(ref));
244  }
245  else if (GNC_IS_JOB(ref))
246  {
247  return (inv->job == GNC_JOB(ref));
248  }
249  else if (GNC_IS_COMMODITY(ref))
250  {
251  return (inv->currency == GNC_COMMODITY(ref));
252  }
253  else if (GNC_IS_ACCOUNT(ref))
254  {
255  return (inv->posted_acc == GNC_ACCOUNT(ref));
256  }
257  else if (GNC_IS_TRANSACTION(ref))
258  {
259  return (inv->posted_txn == GNC_TRANSACTION(ref));
260  }
261  else if (GNC_IS_LOT(ref))
262  {
263  return (inv->posted_lot == GNC_LOT(ref));
264  }
265 
266  return FALSE;
267 }
268 
275 static GList*
276 impl_get_typed_referring_object_list (const QofInstance* inst, const QofInstance* ref)
277 {
278  if (!GNC_IS_BILLTERM(ref) && !GNC_IS_JOB(ref) && !GNC_IS_COMMODITY(ref) && !GNC_IS_ACCOUNT(ref)
279  && !GNC_IS_TRANSACTION(ref) && !GNC_IS_LOT(ref))
280  {
281  return NULL;
282  }
283 
285 }
286 
287 static const char*
288 is_unset = "unset";
289 
290 static void
291 gnc_invoice_class_init (GncInvoiceClass *klass)
292 {
293  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
294  QofInstanceClass* qof_class = QOF_INSTANCE_CLASS(klass);
295 
296  gobject_class->dispose = gnc_invoice_dispose;
297  gobject_class->finalize = gnc_invoice_finalize;
298  gobject_class->set_property = gnc_invoice_set_property;
299  gobject_class->get_property = gnc_invoice_get_property;
300 
301  qof_class->get_display_name = impl_get_display_name;
302  qof_class->refers_to_object = impl_refers_to_object;
303  qof_class->get_typed_referring_object_list = impl_get_typed_referring_object_list;
304 
305  g_object_class_install_property
306  (gobject_class,
307  PROP_NOTES,
308  g_param_spec_string ("notes",
309  "Invoice Notes",
310  "The invoice notes is an arbitrary string "
311  "assigned by the user to provide notes regarding "
312  "this invoice.",
313  NULL,
314  G_PARAM_READWRITE));
315 }
316 
317 /* Create/Destroy Functions */
318 GncInvoice *gncInvoiceCreate (QofBook *book)
319 {
320  GncInvoice *invoice;
321 
322  if (!book) return NULL;
323 
324  invoice = g_object_new (GNC_TYPE_INVOICE, NULL);
325  qof_instance_init_data (&invoice->inst, _GNC_MOD_NAME, book);
326 
327  invoice->id = CACHE_INSERT ("");
328  invoice->notes = CACHE_INSERT ("");
329  invoice->billing_id = CACHE_INSERT ("");
330 
331  invoice->billto.type = GNC_OWNER_CUSTOMER;
332  invoice->active = TRUE;
333 
334  invoice->to_charge_amount = gnc_numeric_zero ();
335  invoice->doclink = (char*) is_unset;
336 
337  qof_event_gen (&invoice->inst, QOF_EVENT_CREATE, NULL);
338 
339  return invoice;
340 }
341 
342 GncInvoice *gncInvoiceCopy (const GncInvoice *from)
343 {
344  GncInvoice *invoice;
345  QofBook* book;
346  GList *node;
347  GValue v = G_VALUE_INIT;
348 
349  g_assert (from);
350  book = qof_instance_get_book (from);
351  g_assert (book);
352 
353  invoice = g_object_new (GNC_TYPE_INVOICE, NULL);
354  qof_instance_init_data (&invoice->inst, _GNC_MOD_NAME, book);
355 
356  gncInvoiceBeginEdit (invoice);
357 
358  invoice->id = CACHE_INSERT (from->id);
359  invoice->notes = CACHE_INSERT (from->notes);
360  invoice->billing_id = CACHE_INSERT (from->billing_id);
361  invoice->active = from->active;
362 
363  qof_instance_get_kvp (QOF_INSTANCE (from), &v, 1, GNC_INVOICE_IS_CN);
364  if (G_VALUE_HOLDS_INT64 (&v))
365  qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
366  g_value_unset (&v);
367 
368  invoice->terms = from->terms;
369  gncBillTermIncRef (invoice->terms);
370 
371  gncOwnerCopy (&from->billto, &invoice->billto);
372  gncOwnerCopy (&from->owner, &invoice->owner);
373  invoice->job = from->job; // FIXME: Need IncRef or similar here?!?
374 
375  invoice->to_charge_amount = from->to_charge_amount;
376  invoice->date_opened = from->date_opened;
377 
378  // Oops. Do not forget to copy the pointer to the correct currency here.
379  invoice->currency = from->currency;
380 
381  invoice->doclink = from->doclink;
382 
383  // Copy all invoice->entries
384  for (node = from->entries; node; node = node->next)
385  {
386  GncEntry *from_entry = node->data;
387  GncEntry *to_entry = gncEntryCreate (book);
388  gncEntryCopy (from_entry, to_entry, FALSE);
389 
390  switch (gncInvoiceGetOwnerType (invoice))
391  {
392  case GNC_OWNER_VENDOR:
393  case GNC_OWNER_EMPLOYEE:
394  // this is a vendor bill, or an expense voucher
395  gncBillAddEntry (invoice, to_entry);
396  break;
397  case GNC_OWNER_CUSTOMER:
398  default:
399  // this is an invoice
400  gncInvoiceAddEntry (invoice, to_entry);
401  break;
402  }
403  }
404 
405  // FIXME: The prices are not (yet) copied; is this a problem?
406 
407  // Posted-date and the posted Txn is intentionally not copied; the
408  // copy isn't "posted" but needs to be posted by the user.
409  mark_invoice (invoice);
410  gncInvoiceCommitEdit (invoice);
411 
412  return invoice;
413 }
414 
415 void gncInvoiceDestroy (GncInvoice *invoice)
416 {
417  if (!invoice) return;
418  qof_instance_set_destroying (invoice, TRUE);
419  gncInvoiceCommitEdit (invoice);
420 }
421 
422 static void gncInvoiceFree (GncInvoice *invoice)
423 {
424  if (!invoice) return;
425 
426  qof_event_gen (&invoice->inst, QOF_EVENT_DESTROY, NULL);
427 
428  CACHE_REMOVE (invoice->id);
429  CACHE_REMOVE (invoice->notes);
430  CACHE_REMOVE (invoice->billing_id);
431  g_list_free (invoice->entries);
432  g_list_free (invoice->prices);
433 
434  if (invoice->printname) g_free (invoice->printname);
435 
436  if (invoice->terms)
437  gncBillTermDecRef (invoice->terms);
438 
439  if (invoice->doclink != is_unset)
440  g_free (invoice->doclink);
441 
442  /* qof_instance_release (&invoice->inst); */
443  g_object_unref (invoice);
444 }
445 
446 /* ================================================================== */
447 /* Set Functions */
448 
449 void gncInvoiceSetID (GncInvoice *invoice, const char *id)
450 {
451  if (!invoice || !id) return;
452  SET_STR (invoice, invoice->id, id);
453  mark_invoice (invoice);
454  gncInvoiceCommitEdit (invoice);
455 }
456 
457 void gncInvoiceSetOwner (GncInvoice *invoice, GncOwner *owner)
458 {
459  if (!invoice || !owner) return;
460  if (gncOwnerEqual (&invoice->owner, owner)) return;
461  gncInvoiceBeginEdit (invoice);
462  gncOwnerCopy (owner, &invoice->owner);
463  mark_invoice (invoice);
464  gncInvoiceCommitEdit (invoice);
465 }
466 
467 static void
468 qofInvoiceSetOwner (GncInvoice *invoice, QofInstance *ent)
469 {
470  if (!invoice || !ent)
471  {
472  return;
473  }
474  gncInvoiceBeginEdit (invoice);
475  qofOwnerSetEntity (&invoice->owner, ent);
476  mark_invoice (invoice);
477  gncInvoiceCommitEdit (invoice);
478 }
479 
480 static void
481 qofInvoiceSetBillTo (GncInvoice *invoice, QofInstance *ent)
482 {
483  if (!invoice || !ent)
484  {
485  return;
486  }
487  gncInvoiceBeginEdit (invoice);
488  qofOwnerSetEntity (&invoice->billto, ent);
489  mark_invoice (invoice);
490  gncInvoiceCommitEdit (invoice);
491 }
492 
493 void gncInvoiceSetDateOpenedGDate (GncInvoice *invoice, const GDate *date)
494 {
495  g_assert (date);
496  gncInvoiceSetDateOpened(invoice, time64CanonicalDayTime (gdate_to_time64 (*date)));
497 }
498 
499 void gncInvoiceSetDateOpened (GncInvoice *invoice, time64 date)
500 {
501  if (!invoice) return;
502  if (date == invoice->date_opened) return;
503  gncInvoiceBeginEdit (invoice);
504  invoice->date_opened = date;
505  mark_invoice (invoice);
506  gncInvoiceCommitEdit (invoice);
507 }
508 
509 void gncInvoiceSetDatePosted (GncInvoice *invoice, time64 date)
510 {
511  if (!invoice) return;
512  if (date == invoice->date_posted) return;
513  gncInvoiceBeginEdit (invoice);
514  invoice->date_posted = date;
515  mark_invoice (invoice);
516  gncInvoiceCommitEdit (invoice);
517 }
518 
519 void gncInvoiceSetTerms (GncInvoice *invoice, GncBillTerm *terms)
520 {
521  if (!invoice) return;
522  if (invoice->terms == terms) return;
523  gncInvoiceBeginEdit (invoice);
524  if (invoice->terms)
525  gncBillTermDecRef (invoice->terms);
526  invoice->terms = terms;
527  if (invoice->terms)
528  gncBillTermIncRef (invoice->terms);
529  mark_invoice (invoice);
530  gncInvoiceCommitEdit (invoice);
531 }
532 
533 void gncInvoiceSetBillingID (GncInvoice *invoice, const char *billing_id)
534 {
535  if (!invoice) return;
536  SET_STR (invoice, invoice->billing_id, billing_id);
537  mark_invoice (invoice);
538  gncInvoiceCommitEdit (invoice);
539 }
540 
541 void gncInvoiceSetNotes (GncInvoice *invoice, const char *notes)
542 {
543  if (!invoice || !notes) return;
544  SET_STR (invoice, invoice->notes, notes);
545  mark_invoice (invoice);
546  gncInvoiceCommitEdit (invoice);
547 }
548 
549 void gncInvoiceSetDocLink (GncInvoice *invoice, const char *doclink)
550 {
551  if (!invoice || !doclink) return;
552 
553  if (invoice->doclink != is_unset)
554  {
555  if (!g_strcmp0 (doclink, invoice->doclink))
556  return;
557 
558  g_free (invoice->doclink);
559  }
560 
561  gncInvoiceBeginEdit (invoice);
562 
563  if (doclink[0] == '\0')
564  {
565  invoice->doclink = NULL;
566  qof_instance_set_kvp (QOF_INSTANCE (invoice), NULL, 1, GNC_INVOICE_DOCLINK);
567  }
568  else
569  {
570  GValue v = G_VALUE_INIT;
571  g_value_init (&v, G_TYPE_STRING);
572  g_value_set_string (&v, doclink);
573  qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_DOCLINK);
574  invoice->doclink = g_strdup (doclink);
575  g_value_unset (&v);
576  }
577  qof_instance_set_dirty (QOF_INSTANCE(invoice));
578  gncInvoiceCommitEdit (invoice);
579 }
580 
581 void gncInvoiceSetActive (GncInvoice *invoice, gboolean active)
582 {
583  if (!invoice) return;
584  if (invoice->active == active) return;
585  gncInvoiceBeginEdit (invoice);
586  invoice->active = active;
587  mark_invoice (invoice);
588  gncInvoiceCommitEdit (invoice);
589 }
590 
591 void gncInvoiceSetIsCreditNote (GncInvoice *invoice, gboolean credit_note)
592 {
593  GValue v = G_VALUE_INIT;
594  if (!invoice) return;
595  gncInvoiceBeginEdit (invoice);
596  g_value_init (&v, G_TYPE_INT64);
597  g_value_set_int64 (&v, credit_note ? 1 : 0);
598  qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
599  g_value_unset (&v);
600  mark_invoice (invoice);
601  gncInvoiceCommitEdit (invoice);
602 
603  /* If this is a credit note, set a feature flag for it in the book
604  * This will prevent older GnuCash versions that don't support
605  * credit notes to open this file. */
606  if (credit_note)
607  gnc_features_set_used (gncInvoiceGetBook (invoice), GNC_FEATURE_CREDIT_NOTES);
608 }
609 
610 void gncInvoiceSetCurrency (GncInvoice *invoice, gnc_commodity *currency)
611 {
612  if (!invoice || !currency) return;
613  if (invoice->currency &&
614  gnc_commodity_equal (invoice->currency, currency))
615  return;
616  gncInvoiceBeginEdit (invoice);
617  invoice->currency = currency;
618  mark_invoice (invoice);
619  gncInvoiceCommitEdit (invoice);
620 }
621 
622 void gncInvoiceSetBillTo (GncInvoice *invoice, GncOwner *billto)
623 {
624  if (!invoice || !billto) return;
625  if (gncOwnerEqual (&invoice->billto, billto)) return;
626 
627  gncInvoiceBeginEdit (invoice);
628  gncOwnerCopy (billto, &invoice->billto);
629  mark_invoice (invoice);
630  gncInvoiceCommitEdit (invoice);
631 }
632 
633 void gncInvoiceSetToChargeAmount (GncInvoice *invoice, gnc_numeric amount)
634 {
635  if (!invoice) return;
636  if (gnc_numeric_equal (invoice->to_charge_amount, amount)) return;
637  gncInvoiceBeginEdit (invoice);
638  invoice->to_charge_amount = amount;
639  mark_invoice (invoice);
640  gncInvoiceCommitEdit (invoice);
641 }
642 
643 void gncInvoiceSetPostedTxn (GncInvoice *invoice, Transaction *txn)
644 {
645  if (!invoice) return;
646  g_return_if_fail (invoice->posted_txn == NULL);
647 
648  gncInvoiceBeginEdit (invoice);
649  invoice->posted_txn = txn;
650  mark_invoice (invoice);
651  gncInvoiceCommitEdit (invoice);
652 }
653 
654 void gncInvoiceSetPostedLot (GncInvoice *invoice, GNCLot *lot)
655 {
656  if (!invoice) return;
657  g_return_if_fail (invoice->posted_lot == NULL);
658 
659  gncInvoiceBeginEdit (invoice);
660  invoice->posted_lot = lot;
661  mark_invoice (invoice);
662  gncInvoiceCommitEdit (invoice);
663 }
664 
665 void gncInvoiceSetPostedAcc (GncInvoice *invoice, Account *acc)
666 {
667  if (!invoice) return;
668  g_return_if_fail (invoice->posted_acc == NULL);
669 
670  gncInvoiceBeginEdit (invoice);
671  invoice->posted_acc = acc;
672  mark_invoice (invoice);
673  gncInvoiceCommitEdit (invoice);
674 }
675 
676 void gncInvoiceAddEntry (GncInvoice *invoice, GncEntry *entry)
677 {
678  GncInvoice *old;
679 
680  g_assert (invoice);
681  g_assert (entry);
682  if (!invoice || !entry) return;
683 
684  old = gncEntryGetInvoice (entry);
685  if (old == invoice) return; /* I already own this one */
686  if (old) gncInvoiceRemoveEntry (old, entry);
687 
688  gncInvoiceBeginEdit (invoice);
689  gncEntrySetInvoice (entry, invoice);
690  invoice->entries = g_list_insert_sorted (invoice->entries, entry,
691  (GCompareFunc)gncEntryCompare);
692  mark_invoice (invoice);
693  gncInvoiceCommitEdit (invoice);
694 }
695 
696 void gncInvoiceRemoveEntry (GncInvoice *invoice, GncEntry *entry)
697 {
698  if (!invoice || !entry) return;
699 
700  gncInvoiceBeginEdit (invoice);
701  gncEntrySetInvoice (entry, NULL);
702  invoice->entries = g_list_remove (invoice->entries, entry);
703  mark_invoice (invoice);
704  gncInvoiceCommitEdit (invoice);
705 }
706 
707 void gncInvoiceAddPrice (GncInvoice *invoice, GNCPrice *price)
708 {
709  GList *node;
710  gnc_commodity *commodity;
711 
712  if (!invoice || !price) return;
713 
714  /* Keep only one price per commodity per invoice
715  * So if a price was set previously remove it first */
716  node = g_list_first (invoice->prices);
717  commodity = gnc_price_get_commodity (price);
718  while (node != NULL)
719  {
720  GNCPrice *curr = (GNCPrice*)node->data;
721  if (gnc_commodity_equal (commodity, gnc_price_get_commodity (curr)))
722  break;
723  node = g_list_next (node);
724  }
725 
726  gncInvoiceBeginEdit (invoice);
727  if (node)
728  invoice->prices = g_list_delete_link (invoice->prices, node);
729  invoice->prices = g_list_prepend (invoice->prices, price);
730  mark_invoice (invoice);
731  gncInvoiceCommitEdit (invoice);
732 }
733 
734 void gncBillAddEntry (GncInvoice *bill, GncEntry *entry)
735 {
736  GncInvoice *old;
737 
738  g_assert (bill);
739  g_assert (entry);
740  if (!bill || !entry) return;
741 
742  old = gncEntryGetBill (entry);
743  if (old == bill) return; /* I already own this one */
744  if (old) gncBillRemoveEntry (old, entry);
745 
746  gncInvoiceBeginEdit (bill);
747  gncEntrySetBill (entry, bill);
748  bill->entries = g_list_insert_sorted (bill->entries, entry,
749  (GCompareFunc)gncEntryCompare);
750  mark_invoice (bill);
751  gncInvoiceCommitEdit (bill);
752 }
753 
754 void gncBillRemoveEntry (GncInvoice *bill, GncEntry *entry)
755 {
756  if (!bill || !entry) return;
757 
758  gncInvoiceBeginEdit (bill);
759  gncEntrySetBill (entry, NULL);
760  bill->entries = g_list_remove (bill->entries, entry);
761  mark_invoice (bill);
762  gncInvoiceCommitEdit (bill);
763 }
764 
765 void gncInvoiceSortEntries (GncInvoice *invoice)
766 {
767  if (!invoice) return;
768  invoice->entries = g_list_sort (invoice->entries,
769  (GCompareFunc)gncEntryCompare);
770  gncInvoiceBeginEdit (invoice);
771  mark_invoice (invoice);
772  gncInvoiceCommitEdit (invoice);
773 }
774 
775 void gncInvoiceRemoveEntries (GncInvoice *invoice)
776 {
777  GList *node;
778 
779  if (!invoice) return;
780 
781  for (node = invoice->entries; node; node = node->next)
782  {
783  GncEntry *entry = node->data;
784 
785  switch (gncInvoiceGetOwnerType (invoice))
786  {
787  case GNC_OWNER_VENDOR:
788  case GNC_OWNER_EMPLOYEE:
789  // this is a vendor bill, or an expense voucher
790  gncBillRemoveEntry (invoice, entry);
791  break;
792  case GNC_OWNER_CUSTOMER:
793  default:
794  // this is an invoice
795  gncInvoiceRemoveEntry (invoice, entry);
796  break;
797  }
798 
799  /* If the entry is no longer referenced by any document,
800  * remove it.
801  */
802  if (!(gncEntryGetInvoice (entry) ||
803  gncEntryGetBill (entry) ||
804  gncEntryGetOrder (entry)))
805  {
806  gncEntryBeginEdit (entry);
807  gncEntryDestroy (entry);
808  }
809  }
810 }
811 
812 /* ================================================================== */
813 /* Get Functions */
814 
815 const char * gncInvoiceGetID (const GncInvoice *invoice)
816 {
817  if (!invoice) return NULL;
818  return invoice->id;
819 }
820 
821 const GncOwner * gncInvoiceGetOwner (const GncInvoice *invoice)
822 {
823  if (!invoice) return NULL;
824  return &invoice->owner;
825 }
826 
827 static QofInstance * qofInvoiceGetOwner (GncInvoice *invoice)
828 {
829  GncOwner *owner;
830 
831  if (!invoice)
832  {
833  return NULL;
834  }
835  owner = &invoice->owner;
836  return QOF_INSTANCE(owner);
837 }
838 
839 static QofInstance * qofInvoiceGetBillTo (GncInvoice *invoice)
840 {
841  GncOwner *billto;
842 
843  if (!invoice)
844  {
845  return NULL;
846  }
847  billto = &invoice->billto;
848  return QOF_INSTANCE(billto);
849 }
850 
851 time64 gncInvoiceGetDateOpened (const GncInvoice *invoice)
852 {
853  if (!invoice) return INT64_MAX;
854  return invoice->date_opened;
855 }
856 
857 time64 gncInvoiceGetDatePosted (const GncInvoice *invoice)
858 {
859  if (!invoice) return INT64_MAX;
860  return invoice->date_posted;
861 }
862 
863 time64 gncInvoiceGetDateDue (const GncInvoice *invoice)
864 {
865  Transaction *txn;
866  if (!invoice) return INT64_MAX;
867  txn = gncInvoiceGetPostedTxn (invoice);
868  if (!txn) return INT64_MAX;
869  return xaccTransRetDateDue (txn);
870 }
871 
872 GncBillTerm * gncInvoiceGetTerms (const GncInvoice *invoice)
873 {
874  if (!invoice) return NULL;
875  return invoice->terms;
876 }
877 
878 const char * gncInvoiceGetBillingID (const GncInvoice *invoice)
879 {
880  if (!invoice) return NULL;
881  return invoice->billing_id;
882 }
883 
884 const char * gncInvoiceGetNotes (const GncInvoice *invoice)
885 {
886  if (!invoice) return NULL;
887  return invoice->notes;
888 }
889 
890 const char * gncInvoiceGetDocLink (const GncInvoice *invoice)
891 {
892  if (!invoice) return NULL;
893  if (invoice->doclink == is_unset)
894  {
895  GValue v = G_VALUE_INIT;
896  GncInvoice *inv = (GncInvoice*) invoice;
897  qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
898  inv->doclink = G_VALUE_HOLDS_STRING(&v) ? g_value_dup_string (&v) : NULL;
899  g_value_unset (&v);
900  }
901  return invoice->doclink;
902 }
903 
904 GncOwnerType gncInvoiceGetOwnerType (const GncInvoice *invoice)
905 {
906  const GncOwner *owner;
907  g_return_val_if_fail (invoice, GNC_OWNER_NONE);
908 
909  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
910  return (gncOwnerGetType (owner));
911 }
912 
913 static gnc_numeric gncInvoiceSumTaxesInternal (AccountValueList *taxes)
914 {
915  gnc_numeric tt = gnc_numeric_zero ();
916 
917  if (taxes)
918  {
919  GList *node;
920  // Note we can use GNC_DENOM_AUTO below for rounding because
921  // the values passed to this function should already have been rounded
922  // to the desired denom and addition will just preserve it in that case.
923  for (node = taxes; node; node=node->next)
924  {
925  GncAccountValue *acc_val = node->data;
926  tt = gnc_numeric_add (tt, acc_val->value, GNC_DENOM_AUTO,
928  }
929  }
930  return tt;
931 }
932 
933 static gnc_numeric gncInvoiceGetNetAndTaxesInternal (GncInvoice *invoice, gboolean use_value,
934  AccountValueList **taxes,
935  gboolean use_payment_type,
936  GncEntryPaymentType type)
937 {
938  GList *node;
939  gnc_numeric net_total = gnc_numeric_zero ();
940  gboolean is_cust_doc, is_cn;
941  AccountValueList *tv_list = NULL;
942  int denom = gnc_commodity_get_fraction (gncInvoiceGetCurrency (invoice));
943 
944  g_return_val_if_fail (invoice, net_total);
945 
946  /* Is the current document an invoice/credit note related to a customer or a vendor/employee ?
947  * The GncEntry code needs to know to return the proper entry amounts
948  */
949  is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
950  is_cn = gncInvoiceGetIsCreditNote (invoice);
951 
952 
953  for (node = gncInvoiceGetEntries (invoice); node; node = node->next)
954  {
955  GncEntry *entry = node->data;
956  gnc_numeric value, tax;
957 
958  if (use_payment_type && gncEntryGetBillPayment (entry) != type)
959  continue;
960 
961  if (use_value)
962  {
963  // Always use rounded net values to prevent creating imbalanced transactions on posting
964  // https://bugs.gnucash.org/show_bug.cgi?id=628903
965  value = gncEntryGetDocValue (entry, TRUE, is_cust_doc, is_cn);
966  if (gnc_numeric_check (value) == GNC_ERROR_OK)
967  net_total = gnc_numeric_add (net_total, value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
968  else
969  g_warning ("bad value in our entry");
970  }
971 
972  if (taxes)
973  {
974  AccountValueList *entrytaxes = gncEntryGetDocTaxValues (entry, is_cust_doc, is_cn);
975  tv_list = gncAccountValueAddList (tv_list, entrytaxes);
976  gncAccountValueDestroy (entrytaxes);
977  }
978  }
979 
980  if (taxes)
981  {
982  GList *node;
983  // Round tax totals (accumulated per tax account) to prevent creating imbalanced transactions on posting
984  // which could otherwise happen when using a tax table with multiple tax rates
985  for (node = tv_list; node; node=node->next)
986  {
987  GncAccountValue *acc_val = node->data;
988  acc_val->value = gnc_numeric_convert (acc_val->value,
990  }
991  *taxes = tv_list;
992  }
993 
994  return net_total;
995 }
996 
997 static gnc_numeric gncInvoiceGetTotalInternal (GncInvoice *invoice, gboolean use_value,
998  gboolean use_tax,
999  gboolean use_payment_type, GncEntryPaymentType type)
1000 {
1001  AccountValueList *taxes;
1002  gnc_numeric total;
1003  int denom;
1004 
1005  if (!invoice) return gnc_numeric_zero ();
1006 
1007  total = gncInvoiceGetNetAndTaxesInternal (invoice, use_value, use_tax? &taxes : NULL, use_payment_type, type);
1008 
1009  if (use_tax)
1010  {
1011  // Note we can use GNC_DENOM_AUTO below for rounding because
1012  // the values passed to this function should already have been rounded
1013  // to the desired denom and addition will just preserve it in that case.
1014  total = gnc_numeric_add (total, gncInvoiceSumTaxesInternal (taxes),
1016  gncAccountValueDestroy (taxes);
1017  }
1018  return total;
1019 }
1020 
1021 gnc_numeric gncInvoiceGetTotal (GncInvoice *invoice)
1022 {
1023  if (!invoice) return gnc_numeric_zero ();
1024  return gncInvoiceGetTotalInternal (invoice, TRUE, TRUE, FALSE, 0);
1025 }
1026 
1027 gnc_numeric gncInvoiceGetTotalSubtotal (GncInvoice *invoice)
1028 {
1029  if (!invoice) return gnc_numeric_zero ();
1030  return gncInvoiceGetTotalInternal (invoice, TRUE, FALSE, FALSE, 0);
1031 }
1032 
1033 gnc_numeric gncInvoiceGetTotalTax (GncInvoice *invoice)
1034 {
1035  if (!invoice) return gnc_numeric_zero ();
1036  return gncInvoiceGetTotalInternal (invoice, FALSE, TRUE, FALSE, 0);
1037 }
1038 
1039 gnc_numeric gncInvoiceGetTotalOf (GncInvoice *invoice, GncEntryPaymentType type)
1040 {
1041  if (!invoice) return gnc_numeric_zero ();
1042  return gncInvoiceGetTotalInternal (invoice, TRUE, TRUE, TRUE, type);
1043 }
1044 
1045 AccountValueList *gncInvoiceGetTotalTaxList (GncInvoice *invoice)
1046 {
1047  gnc_numeric unused;
1048  AccountValueList *taxes;
1049  if (!invoice) return NULL;
1050 
1051  gncInvoiceGetNetAndTaxesInternal (invoice, FALSE, &taxes, FALSE, 0);
1052  return taxes;
1053 }
1054 
1055 GList * gncInvoiceGetTypeListForOwnerType (GncOwnerType type)
1056 {
1057  GList *type_list = NULL;
1058  switch (type)
1059  {
1060  case GNC_OWNER_CUSTOMER:
1061  type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_CUST_INVOICE));
1062  type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_CUST_CREDIT_NOTE));
1063  return type_list;
1064  case GNC_OWNER_VENDOR:
1065  type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_VEND_INVOICE));
1066  type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_VEND_CREDIT_NOTE));
1067  return type_list;
1068  case GNC_OWNER_EMPLOYEE:
1069  type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_EMPL_INVOICE));
1070  type_list = g_list_append (type_list, GINT_TO_POINTER(GNC_INVOICE_EMPL_CREDIT_NOTE));
1071  return type_list;
1072  default:
1073  return NULL;
1074  }
1075 
1076 }
1077 
1078 GncInvoiceType gncInvoiceGetType (const GncInvoice *invoice)
1079 {
1080  if (!invoice) return GNC_INVOICE_UNDEFINED;
1081  switch (gncInvoiceGetOwnerType (invoice))
1082  {
1083  case GNC_OWNER_CUSTOMER:
1084  return (gncInvoiceGetIsCreditNote (invoice) ?
1085  GNC_INVOICE_CUST_CREDIT_NOTE :
1086  GNC_INVOICE_CUST_INVOICE);
1087  case GNC_OWNER_VENDOR:
1088  return (gncInvoiceGetIsCreditNote (invoice) ?
1089  GNC_INVOICE_VEND_CREDIT_NOTE :
1090  GNC_INVOICE_VEND_INVOICE);
1091  case GNC_OWNER_EMPLOYEE:
1092  return (gncInvoiceGetIsCreditNote (invoice) ?
1093  GNC_INVOICE_EMPL_CREDIT_NOTE :
1094  GNC_INVOICE_EMPL_INVOICE);
1095  default:
1096  PWARN ("No invoice types defined for owner %d",
1097  gncInvoiceGetOwnerType (invoice));
1098  return GNC_INVOICE_UNDEFINED;
1099  }
1100 }
1101 
1102 const char * gncInvoiceGetTypeString (const GncInvoice *invoice)
1103 {
1104  GncInvoiceType type = gncInvoiceGetType (invoice);
1105  switch (type)
1106  {
1107  case GNC_INVOICE_CUST_INVOICE:
1108  return _("Invoice");
1109  case GNC_INVOICE_VEND_INVOICE:
1110  return _("Bill");
1111  case GNC_INVOICE_EMPL_INVOICE:
1112  return _("Expense");
1113  case GNC_INVOICE_CUST_CREDIT_NOTE:
1114  case GNC_INVOICE_VEND_CREDIT_NOTE:
1115  case GNC_INVOICE_EMPL_CREDIT_NOTE:
1116  return _("Credit Note");
1117  default:
1118  PWARN("Unknown invoice type");
1119  return NULL;
1120  }
1121 }
1122 
1123 gnc_commodity * gncInvoiceGetCurrency (const GncInvoice *invoice)
1124 {
1125  if (!invoice) return NULL;
1126  return invoice->currency;
1127 }
1128 
1129 GncOwner * gncInvoiceGetBillTo (GncInvoice *invoice)
1130 {
1131  if (!invoice) return NULL;
1132  return &invoice->billto;
1133 }
1134 
1135 GNCLot * gncInvoiceGetPostedLot (const GncInvoice *invoice)
1136 {
1137  if (!invoice) return NULL;
1138  return invoice->posted_lot;
1139 }
1140 
1141 Transaction * gncInvoiceGetPostedTxn (const GncInvoice *invoice)
1142 {
1143  if (!invoice) return NULL;
1144  return invoice->posted_txn;
1145 }
1146 
1147 Account * gncInvoiceGetPostedAcc (const GncInvoice *invoice)
1148 {
1149  if (!invoice) return NULL;
1150  return invoice->posted_acc;
1151 }
1152 
1153 gboolean gncInvoiceGetActive (const GncInvoice *invoice)
1154 {
1155  if (!invoice) return FALSE;
1156  return invoice->active;
1157 }
1158 
1159 gboolean gncInvoiceGetIsCreditNote (const GncInvoice *invoice)
1160 {
1161  GValue v = G_VALUE_INIT;
1162  gboolean retval;
1163  if (!invoice) return FALSE;
1164  qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_IS_CN);
1165  retval = G_VALUE_HOLDS_INT64(&v) && g_value_get_int64 (&v);
1166  g_value_unset (&v);
1167  return retval;
1168 }
1169 
1170 
1171 gnc_numeric gncInvoiceGetToChargeAmount (const GncInvoice *invoice)
1172 {
1173  if (!invoice) return gnc_numeric_zero ();
1174  return invoice->to_charge_amount;
1175 }
1176 
1177 EntryList * gncInvoiceGetEntries (GncInvoice *invoice)
1178 {
1179  if (!invoice) return NULL;
1180  return invoice->entries;
1181 }
1182 
1183 GNCPrice * gncInvoiceGetPrice (GncInvoice *invoice, gnc_commodity *commodity)
1184 {
1185  GList *node = g_list_first (invoice->prices);
1186 
1187  while (node != NULL)
1188  {
1189  GNCPrice *curr = (GNCPrice*)node->data;
1190 
1191  if (gnc_commodity_equal (commodity, gnc_price_get_commodity (curr)))
1192  return curr;
1193 
1194  node = g_list_next (node);
1195  }
1196 
1197  return NULL;
1198 }
1199 
1200 static QofCollection*
1201 qofInvoiceGetEntries (GncInvoice *invoice)
1202 {
1203  QofCollection *entry_coll;
1204  GList *list;
1205  QofInstance *entry;
1206 
1207  entry_coll = qof_collection_new (GNC_ID_ENTRY);
1208  for (list = gncInvoiceGetEntries (invoice); list != NULL; list = list->next)
1209  {
1210  entry = QOF_INSTANCE(list->data);
1211  qof_collection_add_entity (entry_coll, entry);
1212  }
1213  return entry_coll;
1214 }
1215 
1216 static void
1217 qofInvoiceEntryCB (QofInstance *ent, gpointer user_data)
1218 {
1219  GncInvoice *invoice;
1220 
1221  invoice = (GncInvoice*)user_data;
1222  if (!invoice || !ent)
1223  {
1224  return;
1225  }
1226  switch (gncInvoiceGetOwnerType (invoice))
1227  {
1228  case GNC_OWNER_VENDOR:
1229  {
1230  gncBillAddEntry (invoice, (GncEntry*) ent);
1231  break;
1232  }
1233  default :
1234  {
1235  gncInvoiceAddEntry (invoice, (GncEntry*)ent);
1236  break;
1237  }
1238  }
1239 }
1240 
1241 static void
1242 qofInvoiceSetEntries (GncInvoice *invoice, QofCollection *entry_coll)
1243 {
1244  if (!entry_coll)
1245  {
1246  return;
1247  }
1248  if (0 == g_strcmp0 (qof_collection_get_type (entry_coll), GNC_ID_ENTRY))
1249  {
1250  qof_collection_foreach (entry_coll, qofInvoiceEntryCB, invoice);
1251  }
1252 }
1253 
1254 static GncJob*
1255 qofInvoiceGetJob (const GncInvoice *invoice)
1256 {
1257  if (!invoice)
1258  {
1259  return NULL;
1260  }
1261  return invoice->job;
1262 }
1263 
1264 static void
1265 qofInvoiceSetJob (GncInvoice *invoice, GncJob *job)
1266 {
1267  if (!invoice)
1268  {
1269  return;
1270  }
1271  invoice->job = job;
1272 }
1273 
1274 void
1275 gncInvoiceDetachFromLot (GNCLot *lot)
1276 {
1277  if (!lot) return;
1278 
1279  gnc_lot_begin_edit (lot);
1280  qof_instance_set (QOF_INSTANCE (lot), "invoice", NULL, NULL);
1281  gnc_lot_commit_edit (lot);
1282  gnc_lot_set_cached_invoice (lot, NULL);
1283 }
1284 
1285 void
1286 gncInvoiceAttachToLot (GncInvoice *invoice, GNCLot *lot)
1287 {
1288  GncGUID *guid;
1289  if (!invoice || !lot)
1290  return;
1291 
1292  if (invoice->posted_lot) return; /* Cannot reset invoice's lot */
1293  guid = (GncGUID*)qof_instance_get_guid (QOF_INSTANCE(invoice));
1294  gnc_lot_begin_edit (lot);
1295  qof_instance_set (QOF_INSTANCE (lot), "invoice", guid, NULL);
1296  gnc_lot_commit_edit (lot);
1297  gnc_lot_set_cached_invoice (lot, invoice);
1298  gncInvoiceSetPostedLot (invoice, lot);
1299 }
1300 
1301 GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot)
1302 {
1303  GncGUID *guid = NULL;
1304  QofBook *book;
1305  GncInvoice *invoice = NULL;
1306 
1307  if (!lot) return NULL;
1308 
1309  invoice = gnc_lot_get_cached_invoice (lot);
1310  if (!invoice)
1311  {
1312  book = gnc_lot_get_book (lot);
1313  qof_instance_get (QOF_INSTANCE(lot), "invoice", &guid, NULL);
1314  invoice = gncInvoiceLookup (book, guid);
1315  guid_free (guid);
1316  gnc_lot_set_cached_invoice (lot, invoice);
1317  }
1318 
1319  return invoice;
1320 }
1321 
1322 void
1323 gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn)
1324 {
1325  if (!invoice || !txn)
1326  return;
1327 
1328  if (invoice->posted_txn) return; /* Cannot reset invoice's txn */
1329 
1330  xaccTransBeginEdit (txn);
1331  qof_instance_set (QOF_INSTANCE (txn), "invoice", //Prop INVOICE
1332  qof_instance_get_guid (QOF_INSTANCE (invoice)), NULL);
1334  xaccTransCommitEdit (txn);
1335  gncInvoiceSetPostedTxn (invoice, txn);
1336 }
1337 
1338 GncInvoice *
1339 gncInvoiceGetInvoiceFromTxn (const Transaction *txn)
1340 {
1341  GncGUID *guid = NULL;
1342  QofBook *book;
1343  GncInvoice *invoice = NULL;
1344 
1345  if (!txn) return NULL;
1346 
1347  book = xaccTransGetBook (txn);
1348  qof_instance_get (QOF_INSTANCE (txn), "invoice", &guid, NULL);
1349  invoice = gncInvoiceLookup (book, guid);
1350  guid_free (guid);
1351  return invoice;
1352 }
1353 
1354 gboolean gncInvoiceAmountPositive (const GncInvoice *invoice)
1355 {
1356  switch (gncInvoiceGetType (invoice))
1357  {
1358  case GNC_INVOICE_CUST_INVOICE:
1359  case GNC_INVOICE_VEND_CREDIT_NOTE:
1360  case GNC_INVOICE_EMPL_CREDIT_NOTE:
1361  return TRUE;
1362  case GNC_INVOICE_CUST_CREDIT_NOTE:
1363  case GNC_INVOICE_VEND_INVOICE:
1364  case GNC_INVOICE_EMPL_INVOICE:
1365  return FALSE;
1366  case GNC_INVOICE_UNDEFINED:
1367  default:
1368  /* Should never be reached.
1369  * If it is, perhaps a new value is added to GncInvoiceType ? */
1370  g_assert_not_reached ();
1371  return FALSE;
1372  }
1373 }
1374 
1375 GHashTable *gncInvoiceGetForeignCurrencies (const GncInvoice *invoice)
1376 {
1377  EntryList *entries_iter;
1378  gboolean is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
1379  gboolean is_cn = gncInvoiceGetIsCreditNote (invoice);
1380  GHashTable *amt_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1381  NULL, g_free);
1382 
1383  for (entries_iter = invoice->entries; entries_iter != NULL; entries_iter = g_list_next(entries_iter))
1384  {
1385  GncEntry *entry = (GncEntry*)entries_iter->data;
1386  Account *this_acc;
1387  gnc_commodity *account_currency;
1388  AccountValueList *tt_amts = NULL, *tt_iter;
1389 
1390  /* Check entry's account currency */
1391  this_acc = (is_cust_doc ? gncEntryGetInvAccount (entry) :
1392  gncEntryGetBillAccount (entry));
1393  account_currency = xaccAccountGetCommodity (this_acc);
1394 
1395  if (this_acc &&
1396  !gnc_commodity_equal (gncInvoiceGetCurrency (invoice), account_currency))
1397  {
1398  gnc_numeric *curr_amt = (gnc_numeric*) g_hash_table_lookup (amt_hash, account_currency);
1399  gnc_numeric *entry_amt = (gnc_numeric*) g_new0 (gnc_numeric, 1);
1400  *entry_amt = gncEntryGetDocValue (entry, FALSE, is_cust_doc, is_cn);
1401  if (curr_amt)
1402  *entry_amt = gnc_numeric_add (*entry_amt, *curr_amt, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
1403  g_hash_table_insert (amt_hash, account_currency, entry_amt);
1404  }
1405 
1406  /* Check currencies of each account in the tax table linked
1407  * to the current entry */
1408  tt_amts = gncEntryGetDocTaxValues (entry, is_cust_doc, is_cn);
1409 
1410  if (!tt_amts)
1411  continue;
1412 
1413  for (tt_iter = tt_amts; tt_iter != NULL; tt_iter = g_list_next(tt_iter))
1414  {
1415  GncAccountValue *tt_amt_val = (GncAccountValue*)tt_iter->data;
1416  Account *tt_acc = tt_amt_val->account;
1417  gnc_commodity *tt_acc_currency = xaccAccountGetCommodity (tt_acc);
1418 
1419  if (tt_acc &&
1420  !gnc_commodity_equal (gncInvoiceGetCurrency (invoice), tt_acc_currency))
1421  {
1422  gnc_numeric *curr_amt = (gnc_numeric*) g_hash_table_lookup (amt_hash, tt_acc_currency);
1423  gnc_numeric *tt_acc_amt = (gnc_numeric*) g_new0 (gnc_numeric, 1);
1424  *tt_acc_amt = tt_amt_val->value;
1425  if (curr_amt)
1426  *tt_acc_amt = gnc_numeric_add (*tt_acc_amt, *curr_amt, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
1427  g_hash_table_insert (amt_hash, tt_acc_currency, tt_acc_amt);
1428  }
1429  }
1430  gncAccountValueDestroy (tt_amts);
1431  }
1432  return amt_hash;
1433 }
1434 
1435 static gboolean gncInvoicePostAddSplit (QofBook *book,
1436  Account *acc,
1437  Transaction *txn,
1438  gnc_numeric value,
1439  const gchar *memo,
1440  const gchar *type,
1441  GncInvoice *invoice)
1442 {
1443  Split *split;
1444 
1445  split = xaccMallocSplit (book);
1446  /* set action and memo? */
1447 
1448  xaccSplitSetMemo (split, memo);
1449  /* set per book option */
1450  gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
1451 
1452  /* Need to insert this split into the account AND txn before
1453  * we set the Base Value. Otherwise SetBaseValue complains
1454  * that we don't have an account and fails to set the value.
1455  */
1456  xaccAccountBeginEdit (acc);
1457  xaccAccountInsertSplit (acc, split);
1458  xaccAccountCommitEdit (acc);
1459  xaccTransAppendSplit (txn, split);
1460 
1461  /* General note on the split creations below:
1462  * Invoice and bill amounts are always stored as positive values in entries
1463  * So to convert them to proper splits, the amounts may have to be reverted
1464  * to have the proper effect on the account balance.
1465  * Credit notes have the opposite effect of invoices/bills, but their amounts
1466  * are stored as negative values as well. So to convert them into splits
1467  * they can be treated exactly the same as their invoice/bill counter parts.
1468  * The net effect is that the owner type is sufficient to determine whether a
1469  * value has to be reverted when converting an invoice/bill/cn amount to a split.
1470  */
1471  if (gnc_commodity_equal (xaccAccountGetCommodity (acc), invoice->currency))
1472  {
1473  xaccSplitSetBaseValue (split, value,
1474  invoice->currency);
1475  }
1476  else
1477  {
1478  /*need to do conversion */
1479  GNCPrice *price = gncInvoiceGetPrice (invoice, xaccAccountGetCommodity (acc));
1480 
1481  if (price == NULL)
1482  {
1483  /*This is an error, which shouldn't even be able to happen.
1484  We can't really do anything sensible about it, and this is
1485  a user-interface free zone so we can't try asking the user
1486  again either, have to return NULL*/
1487  return FALSE;
1488  }
1489  else
1490  {
1491  gnc_numeric converted_amount;
1492  xaccSplitSetValue (split, value);
1493  converted_amount = gnc_numeric_div (value, gnc_price_get_value (price), GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
1494  DEBUG("converting from %f to %f\n", gnc_numeric_to_double (value), gnc_numeric_to_double (converted_amount));
1495  xaccSplitSetAmount (split, converted_amount);
1496  }
1497  }
1498 
1499  return TRUE;
1500 }
1501 
1502 Transaction * gncInvoicePostToAccount (GncInvoice *invoice, Account *acc,
1503  time64 post_date, time64 due_date,
1504  const char * memo, gboolean accumulatesplits,
1505  gboolean autopay)
1506 {
1507  Transaction *txn;
1508  QofBook *book;
1509  GNCLot *lot = NULL;
1510  GList *iter;
1511  GList *splitinfo = NULL;
1512  gnc_numeric total;
1513  gboolean is_cust_doc;
1514  gboolean is_cn;
1515  const char *name, *type;
1516  char *lot_title;
1517  Account *ccard_acct = NULL;
1518  const GncOwner *owner;
1519  int denom = xaccAccountGetCommoditySCU (acc);
1520  AccountValueList *taxes;
1521 
1522  if (!invoice || !acc) return NULL;
1523  if (gncInvoiceIsPosted (invoice)) return NULL;
1524 
1525  gncInvoiceBeginEdit (invoice);
1526  book = qof_instance_get_book (invoice);
1527 
1528  /* Stabilize the Billing Terms of this invoice */
1529  if (invoice->terms)
1530  gncInvoiceSetTerms (invoice,
1531  gncBillTermReturnChild (invoice->terms, TRUE));
1532 
1533  /* GncEntry functions need to know if the invoice/credit note is for a customer or a vendor/employee. */
1534  is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
1535  is_cn = gncInvoiceGetIsCreditNote (invoice);
1536 
1537  /* Figure out if we need to separate out "credit-card" items */
1538  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
1539  if (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_EMPLOYEE)
1540  ccard_acct = gncEmployeeGetCCard (gncOwnerGetEmployee (owner));
1541 
1542  /* Create a new lot for this invoice */
1543  lot = gnc_lot_new (book);
1544  gncInvoiceAttachToLot (invoice, lot);
1545  gnc_lot_begin_edit (lot);
1546 
1547  type = gncInvoiceGetTypeString (invoice);
1548 
1549  /* Set the lot title */
1550  lot_title = g_strdup_printf ("%s %s", type, gncInvoiceGetID (invoice));
1551  gnc_lot_set_title (lot, lot_title);
1552  g_free (lot_title);
1553 
1554  /* Create a new transaction */
1555  txn = xaccMallocTransaction (book);
1556  xaccTransBeginEdit (txn);
1557 
1558  name = gncOwnerGetName (gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice)));
1559 
1560  /* Set Transaction Description (Owner Name) , Num (invoice ID or type, based
1561  * on book option), Currency */
1562  xaccTransSetDescription (txn, name ? name : "");
1563  gnc_set_num_action (txn, NULL, gncInvoiceGetID (invoice), type);
1564  xaccTransSetCurrency (txn, invoice->currency);
1565 
1566  /* Entered and Posted at date */
1567  xaccTransSetDateEnteredSecs (txn, gnc_time (NULL));
1568  xaccTransSetDatePostedSecsNormalized (txn, post_date);
1569  gncInvoiceSetDatePosted (invoice, xaccTransRetDatePosted(txn));
1570 
1571  xaccTransSetDateDue (txn, due_date);
1572 
1573  /* Get invoice total and taxes. */
1574  total = gncInvoiceGetTotal (invoice);
1575  taxes = gncInvoiceGetTotalTaxList (invoice);
1576  /* The two functions above return signs relative to the document
1577  * We need to convert them to balance values before we can use them here
1578  * Note the odd construct comparing two booleans is to xor them
1579  * that is, only evaluate true if both are different.
1580  */
1581  if (is_cust_doc != is_cn)
1582  {
1583  GList *node;
1584  total = gnc_numeric_neg (total);
1585  for (node = taxes; node; node = node->next)
1586  {
1587  GncAccountValue *acc_val = node->data;
1588  acc_val->value = gnc_numeric_neg (acc_val->value);
1589  }
1590  }
1591 
1592  /* Iterate through the entries; sum up everything for each account.
1593  * then create the appropriate splits in this txn.
1594  */
1595 
1596  for (iter = gncInvoiceGetEntries (invoice); iter; iter = iter->next)
1597  {
1598  gnc_numeric value, tax;
1599  GncEntry * entry = iter->data;
1600  Account *this_acc;
1601 
1602  /* Stabilize the TaxTable in this entry */
1603  gncEntryBeginEdit (entry);
1604  if (is_cust_doc)
1605  gncEntrySetInvTaxTable
1606  (entry, gncTaxTableReturnChild (gncEntryGetInvTaxTable (entry), TRUE));
1607  else
1608  {
1609  gncEntrySetBillTaxTable
1610  (entry, gncTaxTableReturnChild (gncEntryGetBillTaxTable (entry), TRUE));
1611 
1612  /* If this is a bill, and the entry came from an invoice originally, copy the price */
1613  if (gncEntryGetBillable (entry))
1614  {
1615  /* We need to set the net price since it may be another tax rate for invoices than bills */
1616  gncEntrySetInvPrice (entry, gncEntryGetPrice (entry, FALSE, TRUE));
1617  gncEntrySetInvTaxIncluded (entry, FALSE);
1618  }
1619  }
1620  gncEntryCommitEdit (entry);
1621 
1622  /* Obtain the Entry's Value and TaxValues
1623  Note we use rounded values here and below to prevent creating an imbalanced transaction */
1624  value = gncEntryGetBalValue (entry, TRUE, is_cust_doc);
1625  tax = gncEntryGetBalTaxValue (entry, TRUE, is_cust_doc);
1626 
1627  /* add the value for the account split */
1628  this_acc = (is_cust_doc ? gncEntryGetInvAccount (entry) :
1629  gncEntryGetBillAccount (entry));
1630  if (this_acc)
1631  {
1632  if (gnc_numeric_check (value) == GNC_ERROR_OK)
1633  {
1634  if (accumulatesplits)
1635  splitinfo = gncAccountValueAdd (splitinfo, this_acc, value);
1636  /* Adding to total in case of accumulatesplits will be deferred to later when each split is effectively added */
1637  else if (!gncInvoicePostAddSplit (book, this_acc, txn, value,
1638  gncEntryGetDescription (entry),
1639  type, invoice))
1640  {
1641  /*This is an error, which shouldn't even be able to happen.
1642  We can't really do anything sensible about it, and this is
1643  a user-interface free zone so we can't try asking the user
1644  again either, have to return NULL*/
1645  return NULL;
1646  }
1647 
1648  /* If there is a credit-card account, and this is a CCard
1649  * payment type, subtract it from the total, and instead
1650  * create a split to the CC Acct with a memo of the entry
1651  * description instead of the provided memo. Note that the
1652  * value reversal is the same as the post account.
1653  *
1654  * Note: we don't have to worry about the tax values --
1655  * expense vouchers don't have them.
1656  */
1657  if (ccard_acct && gncEntryGetBillPayment (entry) == GNC_PAYMENT_CARD)
1658  {
1659  Split *split;
1660 
1661  total = gnc_numeric_sub (total, value, denom,
1663 
1664  split = xaccMallocSplit (book);
1665  xaccSplitSetMemo (split, gncEntryGetDescription (entry));
1666  /* set action based on book option */
1667  gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
1668  xaccAccountBeginEdit (ccard_acct);
1669  xaccAccountInsertSplit (ccard_acct, split);
1670  xaccAccountCommitEdit (ccard_acct);
1671  xaccTransAppendSplit (txn, split);
1672  xaccSplitSetBaseValue (split, gnc_numeric_neg (value),
1673  invoice->currency);
1674 
1675  }
1676 
1677  }
1678  else
1679  g_warning ("bad value in our entry");
1680  }
1681 
1682  /* check the taxes */
1683  if (gnc_numeric_check (tax) != GNC_ERROR_OK)
1684  g_warning ("bad tax in our entry");
1685 
1686  } /* for */
1687 
1688 
1689  /* now merge in the TaxValues */
1690  splitinfo = gncAccountValueAddList (splitinfo, taxes);
1691  gncAccountValueDestroy (taxes);
1692 
1693  /* Iterate through the splitinfo list and generate the splits */
1694  for (iter = splitinfo; iter; iter = iter->next)
1695  {
1696  GncAccountValue *acc_val = iter->data;
1697 
1698  //gnc_numeric amt_rounded = gnc_numeric_convert(acc_val->value,
1699  // denom, GNC_HOW_DENOM_EXACT | GNC_HOW_RND_ROUND_HALF_UP);
1700  if (!gncInvoicePostAddSplit (book, acc_val->account, txn, acc_val->value,
1701  memo, type, invoice))
1702  {
1703  /*This is an error, which shouldn't even be able to happen.
1704  We can't really do anything sensible about it, and this is
1705  a user-interface free zone so we can't try asking the user
1706  again either, have to return NULL*/
1707  return NULL;
1708  }
1709  }
1710 
1711  /* If there is a ccard account, we may have an additional "to_card" payment.
1712  * we should make that now.
1713  */
1714  if (ccard_acct && !gnc_numeric_zero_p (invoice->to_charge_amount))
1715  {
1716  Split *split = xaccMallocSplit (book);
1717 
1718  /* To charge amount is stored in document value. We need balance value here
1719  * so convert if necessary. */
1720  gnc_numeric to_charge_bal_amount = (is_cn ? gnc_numeric_neg (invoice->to_charge_amount)
1721  : invoice->to_charge_amount);
1722 
1723  /* Set memo. */
1724  xaccSplitSetMemo (split, _("Extra to Charge Card"));
1725  /* Set action based on book option */
1726  gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
1727 
1728  xaccAccountBeginEdit (ccard_acct);
1729  xaccAccountInsertSplit (ccard_acct, split);
1730  xaccAccountCommitEdit (ccard_acct);
1731  xaccTransAppendSplit (txn, split);
1732  xaccSplitSetBaseValue (split, gnc_numeric_neg (to_charge_bal_amount),
1733  invoice->currency);
1734 
1735  total = gnc_numeric_sub (total, to_charge_bal_amount, denom,
1737  }
1738 
1739  /* Now create the Posted split (which is the opposite sign of the above splits) */
1740  {
1741  Split *split = xaccMallocSplit (book);
1742 
1743  /* Set memo */
1744  xaccSplitSetMemo (split, memo);
1745  /* Set action based on book option */
1746  gnc_set_num_action (NULL, split, gncInvoiceGetID (invoice), type);
1747 
1748  xaccAccountBeginEdit (acc);
1749  xaccAccountInsertSplit (acc, split);
1750  xaccAccountCommitEdit (acc);
1751  xaccTransAppendSplit (txn, split);
1752  xaccSplitSetBaseValue (split, gnc_numeric_neg (total),
1753  invoice->currency);
1754 
1755  /* add this split to the lot */
1756  gnc_lot_add_split (lot, split);
1757  }
1758 
1759  /* Now attach this invoice to the txn and account */
1760  gncInvoiceAttachToTxn (invoice, txn);
1761  gncInvoiceSetPostedAcc (invoice, acc);
1762 
1763  xaccTransSetReadOnly (txn, _("Generated from an invoice. Try unposting the invoice."));
1764  xaccTransCommitEdit (txn);
1765 
1766  gncAccountValueDestroy (splitinfo);
1767 
1768  gnc_lot_commit_edit (lot);
1769  /* Not strictly necessary, since it was done by the Set calls
1770  * above, but good insurance. */
1771  DEBUG("Committing Invoice %s", invoice->id);
1772  mark_invoice (invoice);
1773  gncInvoiceCommitEdit (invoice);
1774 
1775  /* If requested, attempt to automatically apply open payments
1776  * and reverse documents to this lot to close it (or at least
1777  * reduce its balance) */
1778  if (autopay)
1779  gncInvoiceAutoApplyPayments (invoice);
1780 
1781  return txn;
1782 }
1783 
1784 gboolean
1785 gncInvoiceUnpost (GncInvoice *invoice, gboolean reset_tax_tables)
1786 {
1787  Transaction *txn;
1788  GNCLot *lot;
1789  GList *lot_split_list, *lot_split_iter;
1790 
1791  if (!invoice) return FALSE;
1792  if (!gncInvoiceIsPosted (invoice)) return FALSE;
1793 
1794  txn = gncInvoiceGetPostedTxn (invoice);
1795  g_return_val_if_fail (txn, FALSE);
1796 
1797  lot = gncInvoiceGetPostedLot (invoice);
1798  g_return_val_if_fail (lot, FALSE);
1799 
1800  /* Destroy the Posted Transaction */
1801  xaccTransClearReadOnly (txn);
1802  xaccTransBeginEdit (txn);
1803  xaccTransDestroy (txn);
1804  xaccTransCommitEdit (txn);
1805 
1806  /* Disconnect the lot from the invoice; re-attach to the invoice owner */
1807  gncInvoiceDetachFromLot (lot);
1808  gncOwnerAttachToLot (&invoice->owner, lot);
1809 
1810  /* Check if this invoice was linked to other lots (payments/inverse signed
1811  * invoices).
1812  * If this is the case, recreate the link transaction between all the remaining lots.
1813  *
1814  * Note that before GnuCash 2.6 payments were not stored in separate lots, but
1815  * always ended up in invoice lots when matched to an invoice. Over-payments
1816  * were copied to a new lot, to which later an invoice was added again and so on.
1817  * These over-payments were handled with automatic payment forward transactions.
1818  * You could consider these transactions to be links between lots as well, but
1819  * to avoid some unexpected behavior, these will not be altered here.
1820  */
1821 
1822  // Note: make a copy of the lot list here, when splits are deleted from the lot,
1823  // the original list may be destroyed by the lot code.
1824  lot_split_list = g_list_copy (gnc_lot_get_split_list (lot));
1825  for (lot_split_iter = lot_split_list; lot_split_iter; lot_split_iter = lot_split_iter->next)
1826  {
1827  Split *split = lot_split_iter->data;
1828  GList *other_split_list, *list_iter;
1829  Transaction *other_txn = xaccSplitGetParent (split);
1830  GList *lot_list = NULL;
1831 
1832  /* Only work with transactions that link invoices and payments.
1833  * Note: this check also catches the possible case of NULL splits. */
1834  if (xaccTransGetTxnType (other_txn) != TXN_TYPE_LINK)
1835  continue;
1836 
1837  /* Save a list of lots this linking transaction linked to */
1838  other_split_list = xaccTransGetSplitList (other_txn);
1839  for (list_iter = other_split_list; list_iter; list_iter = list_iter->next)
1840  {
1841  Split *other_split = list_iter->data;
1842  GNCLot *other_lot = xaccSplitGetLot (other_split);
1843 
1844  /* Omit the lot we are about to delete */
1845  if (other_lot == lot)
1846  continue;
1847 
1848  lot_list = g_list_prepend (lot_list, other_lot);
1849  }
1850  /* Maintain original split order */
1851  lot_list = g_list_reverse (lot_list);
1852 
1853  /* Now remove this link transaction. */
1854  xaccTransClearReadOnly (other_txn);
1855  xaccTransBeginEdit (other_txn);
1856  xaccTransDestroy (other_txn);
1857  xaccTransCommitEdit (other_txn);
1858 
1859  /* Re-balance the saved lots as well as is possible */
1860  gncOwnerAutoApplyPaymentsWithLots (&invoice->owner, lot_list);
1861 
1862  /* If any of the saved lots has no more splits, then destroy it.
1863  * Otherwise if any has an invoice associated with it,
1864  * send it a modified event to reset its paid status */
1865  for (list_iter = lot_list; list_iter; list_iter = list_iter->next)
1866  {
1867  GNCLot *other_lot = list_iter->data;
1868  GncInvoice *other_invoice = gncInvoiceGetInvoiceFromLot (other_lot);
1869 
1870  if (!gnc_lot_count_splits (other_lot))
1871  gnc_lot_destroy (other_lot);
1872  else if (other_invoice)
1873  qof_event_gen (QOF_INSTANCE(other_invoice), QOF_EVENT_MODIFY, NULL);
1874  }
1875  g_list_free (lot_list);
1876  }
1877  g_list_free (lot_split_list);
1878 
1879  /* If the lot has no splits, then destroy it */
1880  if (!gnc_lot_count_splits (lot))
1881  gnc_lot_destroy (lot);
1882 
1883  /* Clear out the invoice posted information */
1884  gncInvoiceBeginEdit (invoice);
1885 
1886  invoice->posted_acc = NULL;
1887  invoice->posted_txn = NULL;
1888  invoice->posted_lot = NULL;
1889  invoice->date_posted = INT64_MAX;
1890 
1891  /* if we've been asked to reset the tax tables, then do so */
1892  if (reset_tax_tables)
1893  {
1894  gboolean is_cust_doc = (gncInvoiceGetOwnerType (invoice) == GNC_OWNER_CUSTOMER);
1895  GList *iter;
1896 
1897  for (iter = gncInvoiceGetEntries (invoice); iter; iter = iter->next)
1898  {
1899  GncEntry *entry = iter->data;
1900 
1901  gncEntryBeginEdit (entry);
1902  if (is_cust_doc)
1903  gncEntrySetInvTaxTable (entry,
1904  gncTaxTableGetParent (gncEntryGetInvTaxTable( entry)));
1905  else
1906  gncEntrySetBillTaxTable (entry,
1907  gncTaxTableGetParent (gncEntryGetBillTaxTable (entry)));
1908  gncEntryCommitEdit (entry);
1909  }
1910  }
1911 
1912  mark_invoice (invoice);
1913  gncInvoiceCommitEdit (invoice);
1914 
1915  return TRUE;
1916 }
1917 
1918 struct lotmatch
1919 {
1920  const GncOwner *owner;
1921  gboolean positive_balance;
1922 };
1923 
1924 static gboolean
1925 gnc_lot_match_owner_balancing (GNCLot *lot, gpointer user_data)
1926 {
1927  struct lotmatch *lm = user_data;
1928  GncOwner owner_def;
1929  const GncOwner *owner;
1930  gnc_numeric balance = gnc_lot_get_balance (lot);
1931 
1932  /* Could (part of) this lot serve to balance the lot
1933  * for which this query was run ?*/
1934  if (lm->positive_balance == gnc_numeric_positive_p (balance))
1935  return FALSE;
1936 
1937  /* Is it ours? Either the lot owner or the lot invoice owner should match */
1938  if (!gncOwnerGetOwnerFromLot (lot, &owner_def))
1939  {
1940  const GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
1941  if (!invoice)
1942  return FALSE;
1943  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
1944  }
1945  else
1946  owner = gncOwnerGetEndOwner (&owner_def);
1947 
1948  return gncOwnerEqual (owner, lm->owner);
1949 }
1950 
1951 void gncInvoiceAutoApplyPayments (GncInvoice *invoice)
1952 {
1953  GNCLot *inv_lot;
1954  Account *acct;
1955  const GncOwner *owner;
1956  GList *lot_list;
1957  struct lotmatch lm;
1958 
1959  /* General note: "paying" in this context means balancing
1960  * a lot, by linking opposite signed lots together. So below the term
1961  * "payment" can both mean a true payment or it can mean a document of
1962  * the opposite sign (invoice vs credit note). It just
1963  * depends on what type of document was given as parameter
1964  * to this function. */
1965 
1966  /* Payments can only be applied to posted invoices */
1967  g_return_if_fail (invoice);
1968  g_return_if_fail (invoice->posted_lot);
1969 
1970  inv_lot = invoice->posted_lot;
1971  acct = invoice->posted_acc;
1972  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
1973 
1974  /* Find all lots whose balance (or part of their balance) could be
1975  * used to close this lot.
1976  * To be eligible, the lots have to have an opposite signed balance
1977  * and be for the same owner.
1978  * For example, for an invoice lot, payment lots and credit note lots
1979  * could be used. */
1980  lm.positive_balance = gnc_numeric_positive_p (gnc_lot_get_balance (inv_lot));
1981  lm.owner = owner;
1982  lot_list = xaccAccountFindOpenLots (acct, gnc_lot_match_owner_balancing,
1983  &lm, NULL);
1984 
1985  lot_list = g_list_prepend (lot_list, inv_lot);
1986  gncOwnerAutoApplyPaymentsWithLots (owner, lot_list);
1987  g_list_free (lot_list);
1988 }
1989 
1990 /*
1991  * Create a payment of "amount" for the invoice owner and attempt
1992  * to balance it with the given invoice.
1993  */
1994 void
1995 gncInvoiceApplyPayment (const GncInvoice *invoice, Transaction *txn,
1996  Account *xfer_acc, gnc_numeric amount,
1997  gnc_numeric exch, time64 date,
1998  const char *memo, const char *num)
1999 {
2000  GNCLot *payment_lot;
2001  GList *selected_lots = NULL;
2002  const GncOwner *owner;
2003 
2004  /* Verify our arguments */
2005  if (!invoice || !gncInvoiceIsPosted (invoice) || !xfer_acc) return;
2006 
2007  owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
2008  g_return_if_fail (owner->owner.undefined);
2009 
2010  /* Create a lot for this payment */
2011  payment_lot = gncOwnerCreatePaymentLotSecs (owner, &txn,
2012  invoice->posted_acc,
2013  xfer_acc, amount, exch,
2014  date, memo, num);
2015 
2016  /* Select the invoice as only payment candidate */
2017  selected_lots = g_list_prepend (selected_lots, invoice->posted_lot);
2018 
2019  /* And link the invoice lot and the payment lot together as well as possible. */
2020  if (payment_lot)
2021  selected_lots = g_list_prepend (selected_lots, payment_lot);
2022  gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots);
2023 }
2024 
2025 gboolean gncInvoiceIsPosted (const GncInvoice *invoice)
2026 {
2027  if (!invoice) return FALSE;
2028  return GNC_IS_TRANSACTION(gncInvoiceGetPostedTxn (invoice));
2029 }
2030 
2031 gboolean gncInvoiceIsPaid (const GncInvoice *invoice)
2032 {
2033  if (!invoice) return FALSE;
2034  if (!invoice->posted_lot) return FALSE;
2035  return gnc_lot_is_closed (invoice->posted_lot);
2036 }
2037 
2038 /* ================================================================== */
2039 
2040 void gncInvoiceBeginEdit (GncInvoice *invoice)
2041 {
2042  qof_begin_edit (&invoice->inst);
2043 }
2044 
2045 static void gncInvoiceOnError (QofInstance *inst, QofBackendError errcode)
2046 {
2047  PERR("Invoice QofBackend Failure: %d", errcode);
2048  gnc_engine_signal_commit_error (errcode);
2049 }
2050 
2051 static void gncInvoiceOnDone (QofInstance *invoice) { }
2052 
2053 static void invoice_free (QofInstance *inst)
2054 {
2055  GncInvoice *invoice = (GncInvoice *) inst;
2056  gncInvoiceFree (invoice);
2057 }
2058 
2059 void gncInvoiceCommitEdit (GncInvoice *invoice)
2060 {
2061  if (!qof_commit_edit (QOF_INSTANCE(invoice))) return;
2062  qof_commit_edit_part2 (&invoice->inst, gncInvoiceOnError,
2063  gncInvoiceOnDone, invoice_free);
2064 }
2065 
2066 int gncInvoiceCompare (const GncInvoice *a, const GncInvoice *b)
2067 {
2068  int compare;
2069 
2070  if (a == b) return 0;
2071  if (!a) return -1;
2072  if (!b) return 1;
2073 
2074  compare = g_strcmp0 (a->id, b->id);
2075  if (compare) return compare;
2076  if (a->date_opened != b->date_opened) return a->date_opened - b->date_opened;
2077  if (a->date_posted != b->date_posted) return a->date_posted - b->date_posted;
2078  return qof_instance_guid_compare(a, b);
2079 }
2080 
2081 gboolean gncInvoiceEqual(const GncInvoice *a, const GncInvoice *b)
2082 {
2083  if (a == NULL && b == NULL) return TRUE;
2084  if (a == NULL || b == NULL) return FALSE;
2085 
2086  g_return_val_if_fail (GNC_IS_INVOICE(a), FALSE);
2087  g_return_val_if_fail (GNC_IS_INVOICE(b), FALSE);
2088 
2089  if (g_strcmp0 (a->id, b->id) != 0)
2090  {
2091  PWARN("IDs differ: %s vs %s", a->id, b->id);
2092  return FALSE;
2093  }
2094 
2095  if (g_strcmp0 (a->notes, b->notes) != 0)
2096  {
2097  PWARN("Notes differ: %s vs %s", a->notes, b->notes);
2098  return FALSE;
2099  }
2100 
2101  if (g_strcmp0 (a->billing_id, b->billing_id) != 0)
2102  {
2103  PWARN("Billing IDs differ: %s vs %s", a->billing_id, b->billing_id);
2104  return FALSE;
2105  }
2106 
2107  if (g_strcmp0 (a->printname, b->printname) != 0)
2108  {
2109  PWARN("Printnames differ: %s vs %s", a->printname, b->printname);
2110  return FALSE;
2111  }
2112 
2113  if (a->active != b->active)
2114  {
2115  PWARN("Active flags differ");
2116  return FALSE;
2117  }
2118 
2119  if (!gncBillTermEqual (a->terms, b->terms))
2120  {
2121  PWARN("Billterms differ");
2122  return FALSE;
2123  }
2124 
2125  if (!gncJobEqual (a->job, b->job))
2126  {
2127  PWARN("Jobs differ");
2128  return FALSE;
2129  }
2130 
2131  if (!gnc_commodity_equal (a->currency, b->currency))
2132  {
2133  PWARN("Currencies differ");
2134  return FALSE;
2135  }
2136 
2137  if (!xaccAccountEqual (a->posted_acc, b->posted_acc, TRUE))
2138  {
2139  PWARN("Posted accounts differ");
2140  return FALSE;
2141  }
2142 
2143  if (!xaccTransEqual (a->posted_txn, b->posted_txn, TRUE, TRUE, TRUE, FALSE))
2144  {
2145  PWARN("Posted tx differ");
2146  return FALSE;
2147  }
2148 
2149 #if 0
2150  if (!gncLotEqual (a->posted_lot, b->posted_lot))
2151  {
2152  PWARN("Posted lots differ");
2153  return FALSE;
2154  }
2155 #endif
2156 
2157  /* FIXME: Need real checks */
2158 #if 0
2159  GList *entries;
2160  GList *prices;
2161  GncOwner owner;
2162  GncOwner billto;
2163  time64 date_opened;
2164  time64 date_posted;
2165 
2166  gnc_numeric to_charge_amount;
2167 #endif
2168 
2169  return TRUE;
2170 }
2171 
2172 /* ============================================================= */
2173 /* Package-Private functions */
2174 
2175 static const char * _gncInvoicePrintable (gpointer obj)
2176 {
2177  GncInvoice *invoice = obj;
2178 
2179  g_return_val_if_fail (invoice, NULL);
2180 
2181  if (qof_instance_get_dirty_flag (invoice) || invoice->printname == NULL)
2182  {
2183  if (invoice->printname) g_free (invoice->printname);
2184 
2185  invoice->printname =
2186  g_strdup_printf ("%s%s", invoice->id,
2187  gncInvoiceIsPosted (invoice) ? _(" (posted)") : "");
2188  }
2189 
2190  return invoice->printname;
2191 }
2192 
2193 static void
2194 destroy_invoice_on_book_close (QofInstance *ent, gpointer data)
2195 {
2196  GncInvoice* invoice = GNC_INVOICE(ent);
2197 
2198  gncInvoiceBeginEdit (invoice);
2199  gncInvoiceDestroy (invoice);
2200 }
2201 
2202 static void
2203 gnc_invoice_book_end (QofBook* book)
2204 {
2205  QofCollection *col;
2206 
2207  col = qof_book_get_collection (book, GNC_ID_INVOICE);
2208  qof_collection_foreach (col, destroy_invoice_on_book_close, NULL);
2209 }
2210 
2211 static QofObject gncInvoiceDesc =
2212 {
2213  DI(.interface_version = ) QOF_OBJECT_VERSION,
2214  DI(.e_type = ) _GNC_MOD_NAME,
2215  DI(.type_label = ) "Invoice",
2216  DI(.create = ) (gpointer)gncInvoiceCreate,
2217  DI(.book_begin = ) NULL,
2218  DI(.book_end = ) gnc_invoice_book_end,
2219  DI(.is_dirty = ) qof_collection_is_dirty,
2220  DI(.mark_clean = ) qof_collection_mark_clean,
2221  DI(.foreach = ) qof_collection_foreach,
2222  DI(.printable = ) _gncInvoicePrintable,
2223  DI(.version_cmp = ) (int (*)(gpointer, gpointer)) qof_instance_version_cmp,
2224 };
2225 
2226 static void
2227 reg_lot (void)
2228 {
2229  static QofParam params[] =
2230  {
2231  {
2232  INVOICE_FROM_LOT, _GNC_MOD_NAME,
2234  },
2235  { NULL },
2236  };
2237 
2238  qof_class_register (GNC_ID_LOT, NULL, params);
2239 }
2240 
2241 static void
2242 reg_txn (void)
2243 {
2244  static QofParam params[] =
2245  {
2246  {
2247  INVOICE_FROM_TXN, _GNC_MOD_NAME,
2249  },
2250  { NULL },
2251  };
2252 
2253  qof_class_register (GNC_ID_TRANS, NULL, params);
2254 }
2255 
2256 gboolean gncInvoiceRegister (void)
2257 {
2258  static QofParam params[] =
2259  {
2260  { INVOICE_ID, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetID, (QofSetterFunc)gncInvoiceSetID },
2261  { INVOICE_OWNER, GNC_ID_OWNER, (QofAccessFunc)gncInvoiceGetOwner, NULL },
2262  { INVOICE_OPENED, QOF_TYPE_DATE, (QofAccessFunc)gncInvoiceGetDateOpened, (QofSetterFunc)gncInvoiceSetDateOpened },
2263  { INVOICE_DUE, QOF_TYPE_DATE, (QofAccessFunc)gncInvoiceGetDateDue, NULL },
2264  { INVOICE_POSTED, QOF_TYPE_DATE, (QofAccessFunc)gncInvoiceGetDatePosted, (QofSetterFunc)gncInvoiceSetDatePosted },
2265  { INVOICE_IS_POSTED, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceIsPosted, NULL },
2266  { INVOICE_IS_PAID, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceIsPaid, NULL },
2267  { INVOICE_BILLINGID, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetBillingID, (QofSetterFunc)gncInvoiceSetBillingID },
2268  { INVOICE_NOTES, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetNotes, (QofSetterFunc)gncInvoiceSetNotes },
2269  { INVOICE_DOCLINK, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetDocLink, (QofSetterFunc)gncInvoiceSetDocLink },
2270  { INVOICE_ACC, GNC_ID_ACCOUNT, (QofAccessFunc)gncInvoiceGetPostedAcc, (QofSetterFunc)gncInvoiceSetPostedAcc },
2271  { INVOICE_POST_TXN, GNC_ID_TRANS, (QofAccessFunc)gncInvoiceGetPostedTxn, (QofSetterFunc)gncInvoiceSetPostedTxn },
2272  { INVOICE_POST_LOT, GNC_ID_LOT, (QofAccessFunc)gncInvoiceGetPostedLot, NULL/*(QofSetterFunc)gncInvoiceSetPostedLot*/ },
2273  { INVOICE_TYPE, QOF_TYPE_INT32, (QofAccessFunc)gncInvoiceGetType, NULL },
2274  { INVOICE_TYPE_STRING, QOF_TYPE_STRING, (QofAccessFunc)gncInvoiceGetTypeString, NULL },
2275  { INVOICE_TERMS, GNC_ID_BILLTERM, (QofAccessFunc)gncInvoiceGetTerms, (QofSetterFunc)gncInvoiceSetTerms },
2276  { INVOICE_BILLTO, GNC_ID_OWNER, (QofAccessFunc)gncInvoiceGetBillTo, NULL },
2277  { INVOICE_ENTRIES, QOF_TYPE_COLLECT, (QofAccessFunc)qofInvoiceGetEntries, (QofSetterFunc)qofInvoiceSetEntries },
2278  { INVOICE_JOB, GNC_ID_JOB, (QofAccessFunc)qofInvoiceGetJob, (QofSetterFunc)qofInvoiceSetJob },
2279  { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceGetActive, (QofSetterFunc)gncInvoiceSetActive },
2280  { INVOICE_IS_CN, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncInvoiceGetIsCreditNote, (QofSetterFunc)gncInvoiceSetIsCreditNote },
2281  { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
2282  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
2283  { NULL },
2284  };
2285 
2286  qof_class_register (_GNC_MOD_NAME, (QofSortFunc)gncInvoiceCompare, params);
2287  reg_lot ();
2288  reg_txn ();
2289 
2290  /* Make the compiler happy... */
2291  if (0)
2292  {
2293  qofInvoiceSetEntries (NULL, NULL);
2294  qofInvoiceGetEntries (NULL);
2295  qofInvoiceSetOwner (NULL, NULL);
2296  qofInvoiceGetOwner (NULL);
2297  qofInvoiceSetBillTo (NULL, NULL);
2298  qofInvoiceGetBillTo (NULL);
2299  }
2300  if (!qof_choice_create (GNC_ID_INVOICE))
2301  {
2302  return FALSE;
2303  }
2304  return qof_object_register (&gncInvoiceDesc);
2305 }
2306 
2307 gchar *gncInvoiceNextID (QofBook *book, const GncOwner *owner)
2308 {
2309  gchar *nextID;
2310  switch (gncOwnerGetType (gncOwnerGetEndOwner (owner)))
2311  {
2312  case GNC_OWNER_CUSTOMER:
2313  nextID = qof_book_increment_and_format_counter (book, "gncInvoice");
2314  break;
2315  case GNC_OWNER_VENDOR:
2316  nextID = qof_book_increment_and_format_counter (book, "gncBill");
2317  break;
2318  case GNC_OWNER_EMPLOYEE:
2319  nextID = qof_book_increment_and_format_counter (book, "gncExpVoucher");
2320  break;
2321  default:
2322  nextID = qof_book_increment_and_format_counter (book, _GNC_MOD_NAME);
2323  break;
2324  }
2325  return nextID;
2326 }
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
Compare two instances, based on their last update times.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:362
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:510
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
Definition: Split.c:1319
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
char xaccTransGetTxnType(const Transaction *trans)
Returns the Transaction Type.
Definition: Transaction.c:2548
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
#define QOF_TYPE_COLLECT
secondary collections are used for one-to-many references between entities and are implemented using ...
Definition: qofclass.h:101
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
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
#define TXN_TYPE_INVOICE
Transaction is an invoice.
Definition: Transaction.h:125
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
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2682
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
gchar * qof_book_increment_and_format_counter(QofBook *book, const char *counter_name)
This will increment the named counter for this book and format it.
Definition: qofbook.cpp:703
GList * qof_instance_get_referring_object_list_from_collection(const QofCollection *coll, const QofInstance *ref)
Returns a list of objects from the collection which refer to the specific object. ...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
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 gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
Definition: gnc-features.c:135
AccountValueList * gncEntryGetDocTaxValues(GncEntry *entry, gboolean is_cust_doc, gboolean is_cn)
Careful: the returned list is NOT owned by the entry and should be freed by the caller.
Definition: gncEntry.c:1492
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
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
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:622
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition: gncOwner.c:405
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
void gncInvoiceRemoveEntries(GncInvoice *invoice)
Remove all entries from an invoice.
Definition: gncInvoice.c:775
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:189
Transaction * gncInvoicePostToAccount(GncInvoice *invoice, Account *acc, time64 post_date, time64 due_date, const char *memo, gboolean accumulatesplits, gboolean autopay)
Post this invoice to an account.
Definition: gncInvoice.c:1502
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
QofCollection * qof_instance_get_collection(gconstpointer ptr)
Return the collection this instance belongs to.
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:222
GHashTable * gncInvoiceGetForeignCurrencies(const GncInvoice *invoice)
Return an overview of amounts on this invoice that will be posted to accounts in currencies that are ...
Definition: gncInvoice.c:1375
void gncInvoiceSortEntries(GncInvoice *invoice)
Call this function when an Entry is changed and you want to re-sort the list of entries.
Definition: gncInvoice.c:765
#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
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
#define QOF_PARAM_BOOK
"Known" Object Parameters – all objects must support these
Definition: qofquery.h:109
gnc_numeric gncInvoiceGetTotal(GncInvoice *invoice)
Return the "total" amount of the invoice as seen on the document (and shown to the user in the report...
Definition: gncInvoice.c:1021
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.
gboolean gncBillTermEqual(const GncBillTerm *a, const GncBillTerm *b)
Check if all internal fields of a and b match.
Definition: gncBillTerm.c:643
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition: gncOwner.c:276
void gncInvoiceAutoApplyPayments(GncInvoice *invoice)
Attempt to pay the invoice using open payment lots and lots for documents of the opposite sign (credi...
Definition: gncInvoice.c:1951
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1425
void gncOwnerAutoApplyPaymentsWithLots(const GncOwner *owner, GList *lots)
Given a list of lots, try to balance as many of them as possible by creating balancing transactions b...
Definition: gncOwner.c:1259
GncInvoice * gncInvoiceGetInvoiceFromTxn(const Transaction *txn)
Given a transaction, find and return the Invoice.
Definition: gncInvoice.c:1339
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
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
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type.
Definition: Transaction.c:2109
double gnc_numeric_to_double(gnc_numeric in)
Convert numeric to floating-point value.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Equality.
Definition: Transaction.c:874
Account handling public routines.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
Change the denominator of a gnc_numeric value to the specified denominator under standard arguments &#39;...
void xaccTransSetReadOnly(Transaction *trans, const char *reason)
Set the transaction to be ReadOnly by setting a non-NULL value as "reason".
Definition: Transaction.c:2139
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1728
gboolean qof_instance_get_dirty_flag(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object has been modified.
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:436
void gncBillAddEntry(GncInvoice *bill, GncEntry *entry)
Call this function when adding an entry to a bill instead of an invoice.
Definition: gncInvoice.c:734
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2484
gboolean qof_choice_create(char *type)
Set an object as using QOF_TYPE_CHOICE.
Definition: qofchoice.cpp:67
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Definition: gncOwner.c:320
void gncInvoiceApplyPayment(const GncInvoice *invoice, Transaction *txn, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, time64 date, const char *memo, const char *num)
A convenience function to apply a payment to an invoice.
Definition: gncInvoice.c:1995
void gncOwnerAttachToLot(const GncOwner *owner, GNCLot *lot)
Attach an owner to a lot.
Definition: gncOwner.c:623
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1256
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 gncOwnerGetOwnerFromLot(GNCLot *lot, GncOwner *owner)
Get the owner from the lot.
Definition: gncOwner.c:637
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:177
#define xaccTransGetBook(X)
Definition: Transaction.h:783
void qof_collection_mark_clean(QofCollection *)
reset value of dirty flag
Definition: qofid.cpp:263
void xaccTransSetDateDue(Transaction *trans, time64 time)
Dates and txn-type for A/R and A/P "invoice" postings.
Definition: Transaction.c:2095
Find the least common multiple of the arguments&#39; denominators and use that as the denominator of the ...
Definition: gnc-numeric.h:201
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
void gncAccountValueDestroy(GList *list)
Destroy a list of accountvalues.
Definition: gncTaxTable.c:997
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Compare two accounts for equality - this is a deep compare.
Definition: Account.cpp:1625
#define TXN_TYPE_LINK
Transaction is a link between (invoice and payment) lots.
Definition: Transaction.h:127
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
GNCLot * gncOwnerCreatePaymentLotSecs(const GncOwner *owner, Transaction **preset_txn, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, time64 date, const char *memo, const char *num)
Create a lot for a payment to the owner using the other parameters passed in.
Definition: gncOwner.c:751
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
void gncInvoiceSetDateOpenedGDate(GncInvoice *invoice, const GDate *date)
Set the DateOpened using a GDate argument.
Definition: gncInvoice.c:493
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition: gncOwner.c:201
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Get the "parent" Owner or GncGUID thereof.
Definition: gncOwner.c:573
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1301
Business Invoice Interface.
QofIdType qof_collection_get_type(const QofCollection *col)
return the type that the collection stores
Definition: qofid.cpp:76
gboolean gncInvoiceUnpost(GncInvoice *invoice, gboolean reset_tax_tables)
Unpost this invoice.
Definition: gncInvoice.c:1785
gboolean qof_collection_add_entity(QofCollection *coll, QofInstance *ent)
Add an entity to a QOF_TYPE_COLLECT.
Definition: qofid.cpp:112
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
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1430
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3405
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
gint qof_instance_guid_compare(gconstpointer ptr1, gconstpointer ptr2)
Compare the GncGUID values of two instances.
GList * gncAccountValueAddList(GList *l1, GList *l2)
Merge l2 into l1.
Definition: gncTaxTable.c:970
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
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:604
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
gboolean qof_object_register(const QofObject *object)
Register new types of object objects.
Definition: qofobject.cpp:317
GList * gncAccountValueAdd(GList *list, Account *acc, gnc_numeric value)
This will add value to the account-value for acc, creating a new list object if necessary.
Definition: gncTaxTable.c:942
LotList * xaccAccountFindOpenLots(const Account *acc, gboolean(*match_func)(GNCLot *lot, gpointer user_data), gpointer user_data, GCompareFunc sort_func)
Find a list of open lots that match the match_func.
Definition: Account.cpp:4015
Business Entry Interface.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2052
gboolean gncInvoiceEqual(const GncInvoice *a, const GncInvoice *b)
Test support function used by test-dbi-business-stuff.c.
Definition: gncInvoice.c:2081
time64 time64CanonicalDayTime(time64 t)
convert a time64 on a certain day (localtime) to the time64 representing midday on that day...
Definition: gnc-date.cpp:413
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
GncEmployee * gncOwnerGetEmployee(const GncOwner *owner)
If the given owner is of type GNC_OWNER_EMPLOYEE, returns the pointer to the employee object...
Definition: gncOwner.c:391
No error.
Definition: gnc-numeric.h:224
AccountValueList * gncInvoiceGetTotalTaxList(GncInvoice *invoice)
Return a list of tax totals accumulated per tax account.
Definition: gncInvoice.c:1045
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
GncInvoice * gncInvoiceCopy(const GncInvoice *from)
Create a new GncInvoice object as a deep copy of the given other invoice.
Definition: gncInvoice.c:342
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1471
time64 xaccTransRetDateDue(const Transaction *trans)
Dates and txn-type for A/R and A/P "invoice" postings.
Definition: Transaction.c:2531
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean gncInvoiceAmountPositive(const GncInvoice *invoice)
Depending on the invoice type, invoices have a different effect on the balance.
Definition: gncInvoice.c:1354
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
The gnc_lot_get_balance() routine returns the balance of the lot.
Definition: gnc-lot.c:530
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.c:1881
QofCollection * qof_collection_new(QofIdType type)
create a new collection of entities of type
Definition: qofid.cpp:51
gchar * qof_instance_get_display_name(const QofInstance *inst)
Returns a displayable name for this object.
Utility functions for file access.