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