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