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