GnuCash  4.13-74-g66d9f1383e+
gncOwner.c
1 /********************************************************************\
2  * gncOwner.c -- Business Interface: Object OWNERs *
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 Derek Atkins
25  * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
26  * Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
27  * Copyright (c) 2006 David Hampton <hampton@employees.org>
28  * Copyright (c) 2011 Geert Janssens <geert@kobaltwit.be>
29  * Author: Derek Atkins <warlord@MIT.EDU>
30  */
31 
32 #include <config.h>
33 
34 #include <glib.h>
35 #include <glib/gi18n.h>
36 #include <string.h> /* for memcpy() */
37 #include <qofinstance-p.h>
38 
39 #include "gncCustomerP.h"
40 #include "gncEmployeeP.h"
41 #include "gncJobP.h"
42 #include "gncOwner.h"
43 #include "gncOwnerP.h"
44 #include "gncVendorP.h"
45 #include "gncInvoice.h"
46 #include "gnc-commodity.h"
47 #include "Scrub2.h"
48 #include "Split.h"
49 #include "Transaction.h"
50 #include "engine-helpers.h"
51 
52 #define _GNC_MOD_NAME GNC_ID_OWNER
53 
54 #define GNC_OWNER_ID "gncOwner"
55 
56 static QofLogModule log_module = GNC_MOD_ENGINE;
57 
59 {
60  GncOwner *o;
61 
62  o = g_new0 (GncOwner, 1);
63  o->type = GNC_OWNER_NONE;
64  return o;
65 }
66 
67 void gncOwnerFree (GncOwner *owner)
68 {
69  if (!owner) return;
70  g_free (owner);
71 }
72 
74 {
75  if (!owner) return;
76  switch (owner->type)
77  {
78  case GNC_OWNER_NONE :
79  case GNC_OWNER_UNDEFINED :
80  break;
81  case GNC_OWNER_CUSTOMER :
82  {
83  gncCustomerBeginEdit(owner->owner.customer);
84  break;
85  }
86  case GNC_OWNER_JOB :
87  {
88  gncJobBeginEdit(owner->owner.job);
89  break;
90  }
91  case GNC_OWNER_VENDOR :
92  {
93  gncVendorBeginEdit(owner->owner.vendor);
94  break;
95  }
96  case GNC_OWNER_EMPLOYEE :
97  {
98  gncEmployeeBeginEdit(owner->owner.employee);
99  break;
100  }
101  }
102 }
103 
104 void gncOwnerCommitEdit (GncOwner *owner)
105 {
106  if (!owner) return;
107  switch (owner->type)
108  {
109  case GNC_OWNER_NONE :
110  case GNC_OWNER_UNDEFINED :
111  break;
112  case GNC_OWNER_CUSTOMER :
113  {
114  gncCustomerCommitEdit(owner->owner.customer);
115  break;
116  }
117  case GNC_OWNER_JOB :
118  {
119  gncJobCommitEdit(owner->owner.job);
120  break;
121  }
122  case GNC_OWNER_VENDOR :
123  {
124  gncVendorCommitEdit(owner->owner.vendor);
125  break;
126  }
127  case GNC_OWNER_EMPLOYEE :
128  {
129  gncEmployeeCommitEdit(owner->owner.employee);
130  break;
131  }
132  }
133 }
134 
135 void gncOwnerDestroy (GncOwner *owner)
136 {
137  if (!owner) return;
138  switch (owner->type)
139  {
140  case GNC_OWNER_NONE :
141  case GNC_OWNER_UNDEFINED :
142  break;
143  case GNC_OWNER_CUSTOMER :
144  {
145  gncCustomerDestroy(owner->owner.customer);
146  break;
147  }
148  case GNC_OWNER_JOB :
149  {
150  gncJobDestroy(owner->owner.job);
151  break;
152  }
153  case GNC_OWNER_VENDOR :
154  {
155  gncVendorDestroy(owner->owner.vendor);
156  break;
157  }
158  case GNC_OWNER_EMPLOYEE :
159  {
160  gncEmployeeDestroy(owner->owner.employee);
161  break;
162  }
163  }
164 }
165 
166 void gncOwnerInitUndefined (GncOwner *owner, gpointer obj)
167 {
168  if (!owner) return;
169  owner->type = GNC_OWNER_UNDEFINED;
170  owner->owner.undefined = obj;
171 }
172 
173 void gncOwnerInitCustomer (GncOwner *owner, GncCustomer *customer)
174 {
175  if (!owner) return;
176  owner->type = GNC_OWNER_CUSTOMER;
177  owner->owner.customer = customer;
178 }
179 
180 void gncOwnerInitJob (GncOwner *owner, GncJob *job)
181 {
182  if (!owner) return;
183  owner->type = GNC_OWNER_JOB;
184  owner->owner.job = job;
185 }
186 
187 void gncOwnerInitVendor (GncOwner *owner, GncVendor *vendor)
188 {
189  if (!owner) return;
190  owner->type = GNC_OWNER_VENDOR;
191  owner->owner.vendor = vendor;
192 }
193 
194 void gncOwnerInitEmployee (GncOwner *owner, GncEmployee *employee)
195 {
196  if (!owner) return;
197  owner->type = GNC_OWNER_EMPLOYEE;
198  owner->owner.employee = employee;
199 }
200 
201 GncOwnerType gncOwnerGetType (const GncOwner *owner)
202 {
203  if (!owner) return GNC_OWNER_NONE;
204  return owner->type;
205 }
206 
207 const char * gncOwnerGetTypeString (const GncOwner *owner)
208 {
209  GncOwnerType type = gncOwnerGetType(owner);
210  switch (type)
211  {
212  case GNC_OWNER_NONE:
213  return N_("None");
214  case GNC_OWNER_UNDEFINED:
215  return N_("Undefined");
216  case GNC_OWNER_CUSTOMER:
217  return N_("Customer");
218  case GNC_OWNER_JOB:
219  return N_("Job");
220  case GNC_OWNER_VENDOR:
221  return N_("Vendor");
222  case GNC_OWNER_EMPLOYEE:
223  return N_("Employee");
224  default:
225  PWARN ("Unknown owner type");
226  return NULL;
227  }
228 }
229 
232 {
233  return gncOwnerTypeToQofIdType(owner->type);
234 }
235 
237 {
238  QofIdTypeConst type = NULL;
239  switch (t)
240  {
241  case GNC_OWNER_NONE :
242  {
243  type = NULL;
244  break;
245  }
246  case GNC_OWNER_UNDEFINED :
247  {
248  type = NULL;
249  break;
250  }
251  case GNC_OWNER_CUSTOMER :
252  {
253  type = GNC_ID_CUSTOMER;
254  break;
255  }
256  case GNC_OWNER_JOB :
257  {
258  type = GNC_ID_JOB;
259  break;
260  }
261  case GNC_OWNER_VENDOR :
262  {
263  type = GNC_ID_VENDOR;
264  break;
265  }
266  case GNC_OWNER_EMPLOYEE :
267  {
268  type = GNC_ID_EMPLOYEE;
269  break;
270  }
271  }
272  return type;
273 }
274 
275 QofInstance*
277 {
278  QofInstance *ent;
279 
280  if (!owner)
281  {
282  return NULL;
283  }
284  ent = NULL;
285  switch (owner->type)
286  {
287  case GNC_OWNER_NONE :
288  {
289  break;
290  }
291  case GNC_OWNER_UNDEFINED :
292  {
293  break;
294  }
295  case GNC_OWNER_CUSTOMER :
296  {
297  ent = QOF_INSTANCE(owner->owner.customer);
298  break;
299  }
300  case GNC_OWNER_JOB :
301  {
302  ent = QOF_INSTANCE(owner->owner.job);
303  break;
304  }
305  case GNC_OWNER_VENDOR :
306  {
307  ent = QOF_INSTANCE(owner->owner.vendor);
308  break;
309  }
310  case GNC_OWNER_EMPLOYEE :
311  {
312  ent = QOF_INSTANCE(owner->owner.employee);
313  break;
314  }
315  }
316  return ent;
317 }
318 
319 void
320 qofOwnerSetEntity (GncOwner *owner, QofInstance *ent)
321 {
322  if (!owner || !ent)
323  {
324  return;
325  }
326  if (0 == g_strcmp0(ent->e_type, GNC_ID_CUSTOMER))
327  {
328  owner->type = GNC_OWNER_CUSTOMER;
329  gncOwnerInitCustomer(owner, (GncCustomer*)ent);
330  }
331  else if (0 == g_strcmp0(ent->e_type, GNC_ID_JOB))
332  {
333  owner->type = GNC_OWNER_JOB;
334  gncOwnerInitJob(owner, (GncJob*)ent);
335  }
336  else if (0 == g_strcmp0(ent->e_type, GNC_ID_VENDOR))
337  {
338  owner->type = GNC_OWNER_VENDOR;
339  gncOwnerInitVendor(owner, (GncVendor*)ent);
340  }
341  else if (0 == g_strcmp0(ent->e_type, GNC_ID_EMPLOYEE))
342  {
343  owner->type = GNC_OWNER_EMPLOYEE;
344  gncOwnerInitEmployee(owner, (GncEmployee*)ent);
345  }
346  else
347  {
348  owner->type = GNC_OWNER_NONE;
349  owner->owner.undefined = NULL;
350  }
351 }
352 
353 gboolean GNC_IS_OWNER (QofInstance *ent)
354 {
355  if (!ent)
356  return FALSE;
357 
358  return (GNC_IS_VENDOR(ent) ||
359  GNC_IS_CUSTOMER(ent) ||
360  GNC_IS_EMPLOYEE(ent) ||
361  GNC_IS_JOB(ent));
362 }
363 gpointer gncOwnerGetUndefined (const GncOwner *owner)
364 {
365  if (!owner) return NULL;
366  if (owner->type != GNC_OWNER_UNDEFINED) return NULL;
367  return owner->owner.undefined;
368 }
369 
371 {
372  if (!owner) return NULL;
373  if (owner->type != GNC_OWNER_CUSTOMER) return NULL;
374  return owner->owner.customer;
375 }
376 
377 GncJob * gncOwnerGetJob (const GncOwner *owner)
378 {
379  if (!owner) return NULL;
380  if (owner->type != GNC_OWNER_JOB) return NULL;
381  return owner->owner.job;
382 }
383 
384 GncVendor * gncOwnerGetVendor (const GncOwner *owner)
385 {
386  if (!owner) return NULL;
387  if (owner->type != GNC_OWNER_VENDOR) return NULL;
388  return owner->owner.vendor;
389 }
390 
391 GncEmployee * gncOwnerGetEmployee (const GncOwner *owner)
392 {
393  if (!owner) return NULL;
394  if (owner->type != GNC_OWNER_EMPLOYEE) return NULL;
395  return owner->owner.employee;
396 }
397 
398 void gncOwnerCopy (const GncOwner *src, GncOwner *dest)
399 {
400  if (!src || !dest) return;
401  if (src == dest) return;
402  memcpy (dest, src, sizeof (*dest));
403 }
404 
405 gboolean gncOwnerEqual (const GncOwner *a, const GncOwner *b)
406 {
407  if (!a || !b) return FALSE;
408  if (gncOwnerGetType (a) != gncOwnerGetType (b)) return FALSE;
409  return (a->owner.undefined == b->owner.undefined);
410 }
411 
412 int gncOwnerGCompareFunc (const GncOwner *a, const GncOwner *b)
413 {
414  if (gncOwnerEqual (a, b))
415  return 0;
416  else
417  return 1;
418 }
419 
420 const char * gncOwnerGetID (const GncOwner *owner)
421 {
422  if (!owner) return NULL;
423  switch (owner->type)
424  {
425  case GNC_OWNER_NONE:
426  case GNC_OWNER_UNDEFINED:
427  default:
428  return NULL;
429  case GNC_OWNER_CUSTOMER:
430  return gncCustomerGetID (owner->owner.customer);
431  case GNC_OWNER_JOB:
432  return gncJobGetID (owner->owner.job);
433  case GNC_OWNER_VENDOR:
434  return gncVendorGetID (owner->owner.vendor);
435  case GNC_OWNER_EMPLOYEE:
436  return gncEmployeeGetID (owner->owner.employee);
437  }
438 }
439 
440 const char * gncOwnerGetName (const GncOwner *owner)
441 {
442  if (!owner) return NULL;
443  switch (owner->type)
444  {
445  case GNC_OWNER_NONE:
446  case GNC_OWNER_UNDEFINED:
447  default:
448  return NULL;
449  case GNC_OWNER_CUSTOMER:
450  return gncCustomerGetName (owner->owner.customer);
451  case GNC_OWNER_JOB:
452  return gncJobGetName (owner->owner.job);
453  case GNC_OWNER_VENDOR:
454  return gncVendorGetName (owner->owner.vendor);
455  case GNC_OWNER_EMPLOYEE:
456  return gncEmployeeGetName (owner->owner.employee);
457  }
458 }
459 
460 GncAddress * gncOwnerGetAddr (const GncOwner *owner)
461 {
462  if (!owner) return NULL;
463  switch (owner->type)
464  {
465  case GNC_OWNER_NONE:
466  case GNC_OWNER_UNDEFINED:
467  case GNC_OWNER_JOB:
468  default:
469  return NULL;
470  case GNC_OWNER_CUSTOMER:
471  return gncCustomerGetAddr (owner->owner.customer);
472  case GNC_OWNER_VENDOR:
473  return gncVendorGetAddr (owner->owner.vendor);
474  case GNC_OWNER_EMPLOYEE:
475  return gncEmployeeGetAddr (owner->owner.employee);
476  }
477 }
478 
479 gnc_commodity * gncOwnerGetCurrency (const GncOwner *owner)
480 {
481  if (!owner) return NULL;
482  switch (owner->type)
483  {
484  case GNC_OWNER_NONE:
485  case GNC_OWNER_UNDEFINED:
486  default:
487  return NULL;
488  case GNC_OWNER_CUSTOMER:
489  return gncCustomerGetCurrency (owner->owner.customer);
490  case GNC_OWNER_VENDOR:
491  return gncVendorGetCurrency (owner->owner.vendor);
492  case GNC_OWNER_EMPLOYEE:
493  return gncEmployeeGetCurrency (owner->owner.employee);
494  case GNC_OWNER_JOB:
495  return gncOwnerGetCurrency (gncJobGetOwner (owner->owner.job));
496  }
497 }
498 
499 gboolean gncOwnerGetActive (const GncOwner *owner)
500 {
501  if (!owner) return FALSE;
502  switch (owner->type)
503  {
504  case GNC_OWNER_NONE:
505  case GNC_OWNER_UNDEFINED:
506  default:
507  return FALSE;
508  case GNC_OWNER_CUSTOMER:
509  return gncCustomerGetActive (owner->owner.customer);
510  case GNC_OWNER_VENDOR:
511  return gncVendorGetActive (owner->owner.vendor);
512  case GNC_OWNER_EMPLOYEE:
513  return gncEmployeeGetActive (owner->owner.employee);
514  case GNC_OWNER_JOB:
515  return gncJobGetActive (owner->owner.job);
516  }
517 }
518 
519 const GncGUID * gncOwnerGetGUID (const GncOwner *owner)
520 {
521  if (!owner) return NULL;
522 
523  switch (owner->type)
524  {
525  case GNC_OWNER_NONE:
526  case GNC_OWNER_UNDEFINED:
527  default:
528  return NULL;
529  case GNC_OWNER_CUSTOMER:
530  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.customer));
531  case GNC_OWNER_JOB:
532  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.job));
533  case GNC_OWNER_VENDOR:
534  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.vendor));
535  case GNC_OWNER_EMPLOYEE:
536  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.employee));
537  }
538 }
539 
540 void
541 gncOwnerSetActive (const GncOwner *owner, gboolean active)
542 {
543  if (!owner) return;
544  switch (owner->type)
545  {
546  case GNC_OWNER_CUSTOMER:
547  gncCustomerSetActive (owner->owner.customer, active);
548  break;
549  case GNC_OWNER_VENDOR:
550  gncVendorSetActive (owner->owner.vendor, active);
551  break;
552  case GNC_OWNER_EMPLOYEE:
553  gncEmployeeSetActive (owner->owner.employee, active);
554  break;
555  case GNC_OWNER_JOB:
556  gncJobSetActive (owner->owner.job, active);
557  break;
558  case GNC_OWNER_NONE:
559  case GNC_OWNER_UNDEFINED:
560  default:
561  break;
562  }
563 }
564 
565 GncGUID gncOwnerRetGUID (GncOwner *owner)
566 {
567  const GncGUID *guid = gncOwnerGetGUID (owner);
568  if (guid)
569  return *guid;
570  return *guid_null ();
571 }
572 
573 const GncOwner * gncOwnerGetEndOwner (const GncOwner *owner)
574 {
575  if (!owner) return NULL;
576  switch (owner->type)
577  {
578  case GNC_OWNER_NONE:
579  case GNC_OWNER_UNDEFINED:
580  default:
581  return NULL;
582  case GNC_OWNER_CUSTOMER:
583  case GNC_OWNER_VENDOR:
584  case GNC_OWNER_EMPLOYEE:
585  return owner;
586  case GNC_OWNER_JOB:
587  return gncJobGetOwner (owner->owner.job);
588  }
589 }
590 
591 int gncOwnerCompare (const GncOwner *a, const GncOwner *b)
592 {
593  if (!a && !b) return 0;
594  if (!a && b) return 1;
595  if (a && !b) return -1;
596 
597  if (a->type != b->type)
598  return (a->type - b->type);
599 
600  switch (a->type)
601  {
602  case GNC_OWNER_NONE:
603  case GNC_OWNER_UNDEFINED:
604  default:
605  return 0;
606  case GNC_OWNER_CUSTOMER:
607  return gncCustomerCompare (a->owner.customer, b->owner.customer);
608  case GNC_OWNER_VENDOR:
609  return gncVendorCompare (a->owner.vendor, b->owner.vendor);
610  case GNC_OWNER_EMPLOYEE:
611  return gncEmployeeCompare (a->owner.employee, b->owner.employee);
612  case GNC_OWNER_JOB:
613  return gncJobCompare (a->owner.job, b->owner.job);
614  }
615 }
616 
617 const GncGUID * gncOwnerGetEndGUID (const GncOwner *owner)
618 {
619  if (!owner) return NULL;
620  return gncOwnerGetGUID (gncOwnerGetEndOwner (owner));
621 }
622 
623 void gncOwnerAttachToLot (const GncOwner *owner, GNCLot *lot)
624 {
625  if (!owner || !lot)
626  return;
627 
628  gnc_lot_begin_edit (lot);
629 
630  qof_instance_set (QOF_INSTANCE (lot),
631  GNC_OWNER_TYPE, (gint64)gncOwnerGetType (owner),
632  GNC_OWNER_GUID, gncOwnerGetGUID (owner),
633  NULL);
634  gnc_lot_commit_edit (lot);
635 }
636 
637 gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner)
638 {
639  GncGUID *guid = NULL;
640  QofBook *book;
641  GncOwnerType type = GNC_OWNER_NONE;
642  guint64 type64 = 0;
643 
644  if (!lot || !owner) return FALSE;
645 
646  book = gnc_lot_get_book (lot);
647  qof_instance_get (QOF_INSTANCE (lot),
648  GNC_OWNER_TYPE, &type64,
649  GNC_OWNER_GUID, &guid,
650  NULL);
651  type = (GncOwnerType) type64;
652  switch (type)
653  {
654  case GNC_OWNER_CUSTOMER:
655  gncOwnerInitCustomer (owner, gncCustomerLookup (book, guid));
656  break;
657  case GNC_OWNER_VENDOR:
658  gncOwnerInitVendor (owner, gncVendorLookup (book, guid));
659  break;
660  case GNC_OWNER_EMPLOYEE:
661  gncOwnerInitEmployee (owner, gncEmployeeLookup (book, guid));
662  break;
663  case GNC_OWNER_JOB:
664  gncOwnerInitJob (owner, gncJobLookup (book, guid));
665  break;
666  default:
667  guid_free (guid);
668  return FALSE;
669  }
670 
671  guid_free (guid);
672  return (owner->owner.undefined != NULL);
673 }
674 
675 gboolean gncOwnerGetOwnerFromTxn (Transaction *txn, GncOwner *owner)
676 {
677  Split *apar_split = NULL;
678 
679  if (!txn || !owner) return FALSE;
680 
681  if (xaccTransGetTxnType (txn) == TXN_TYPE_NONE)
682  return FALSE;
683 
684  apar_split = xaccTransGetFirstAPARAcctSplit (txn, TRUE);
685  if (apar_split)
686  {
687  GNCLot *lot = xaccSplitGetLot (apar_split);
688  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
689  if (invoice)
690  gncOwnerCopy (gncInvoiceGetOwner (invoice), owner);
691  else if (!gncOwnerGetOwnerFromLot (lot, owner))
692  return FALSE;
693 
694  return TRUE; // Got owner from either invoice or lot
695  }
696 
697  return FALSE;
698 }
699 
700 gboolean gncOwnerIsValid (const GncOwner *owner)
701 {
702  if (!owner) return FALSE;
703  return (owner->owner.undefined != NULL);
704 }
705 
706 gboolean
707 gncOwnerLotMatchOwnerFunc (GNCLot *lot, gpointer user_data)
708 {
709  const GncOwner *req_owner = user_data;
710  GncOwner lot_owner;
711  const GncOwner *end_owner;
712  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
713 
714  /* Determine the owner associated to the lot */
715  if (invoice)
716  /* Invoice lots */
717  end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
718  else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
719  /* Pre-payment lots */
720  end_owner = gncOwnerGetEndOwner (&lot_owner);
721  else
722  return FALSE;
723 
724  /* Is this a lot for the requested owner ? */
725  return gncOwnerEqual (end_owner, req_owner);
726 }
727 
728 gint
729 gncOwnerLotsSortFunc (GNCLot *lotA, GNCLot *lotB)
730 {
731  GncInvoice *ia, *ib;
732  time64 da, db;
733 
734  ia = gncInvoiceGetInvoiceFromLot (lotA);
735  ib = gncInvoiceGetInvoiceFromLot (lotB);
736 
737  if (ia)
738  da = gncInvoiceGetDateDue (ia);
739  else
741 
742  if (ib)
743  db = gncInvoiceGetDateDue (ib);
744  else
746 
747  return (da > db) - (da < db);
748 }
749 
750 GNCLot *
751 gncOwnerCreatePaymentLotSecs (const GncOwner *owner, Transaction **preset_txn,
752  Account *posted_acc, Account *xfer_acc,
753  gnc_numeric amount, gnc_numeric exch, time64 date,
754  const char *memo, const char *num)
755 {
756  QofBook *book;
757  Split *split;
758  const char *name;
759  gnc_commodity *post_comm, *xfer_comm;
760  Split *xfer_split = NULL;
761  Transaction *txn = NULL;
762  GNCLot *payment_lot;
763  gnc_numeric xfer_amount = gnc_numeric_zero();
764  gnc_numeric txn_value = gnc_numeric_zero();
765 
766  /* Verify our arguments */
767  if (!owner || !posted_acc || !xfer_acc) return NULL;
768  g_return_val_if_fail (owner->owner.undefined != NULL, NULL);
769 
770  /* Compute the ancillary data */
771  book = gnc_account_get_book (posted_acc);
772  name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
773  post_comm = xaccAccountGetCommodity (posted_acc);
774  xfer_comm = xaccAccountGetCommodity (xfer_acc);
775 
776 // reverse = use_reversed_payment_amounts(owner);
777 
778  if (preset_txn && *preset_txn)
779  txn = *preset_txn;
780 
781  if (txn)
782  {
783  int i = 0;
784 
785  /* Pre-existing transaction was specified. We completely clear it,
786  * except for a pre-existing transfer split. We're very conservative
787  * in preserving that one as it may have been reconciled already. */
788  xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
789  xaccTransBeginEdit (txn);
790  while (i < xaccTransCountSplits(txn))
791  {
792  Split *split = xaccTransGetSplit (txn, i);
793  if (split == xfer_split)
794  ++i;
795  else
796  xaccSplitDestroy(split);
797  }
798  /* Note: don't commit transaction now - that would insert an imbalance split.*/
799  }
800  else
801  {
802  txn = xaccMallocTransaction (book);
803  xaccTransBeginEdit (txn);
804  }
805 
806  /* Complete transaction setup */
807  xaccTransSetDescription (txn, name ? name : "");
808  if (!gnc_commodity_equal(xaccTransGetCurrency (txn), post_comm) &&
809  !gnc_commodity_equal (xaccTransGetCurrency (txn), xfer_comm))
810  xaccTransSetCurrency (txn, xfer_comm);
811 
812  /* With all commodities involved known, define split amounts and txn value.
813  * - post amount (amount passed in as parameter) is always in post_acct commodity,
814  * - xfer amount requires conversion if the xfer account has a different
815  * commodity than the post account.
816  * - txn value requires conversion if the post account has a different
817  * commodity than the transaction */
818  if (gnc_commodity_equal(post_comm, xfer_comm))
819  xfer_amount = amount;
820  else
821  xfer_amount = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
823 
824  if (gnc_commodity_equal(post_comm, xaccTransGetCurrency (txn)))
825  txn_value = amount;
826  else
827  txn_value = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
829 
830  /* Insert a split for the transfer account if we don't have one yet */
831  if (!xfer_split)
832  {
833  /* The split for the transfer account */
834  xfer_split = xaccMallocSplit (book);
835  xaccSplitSetMemo (xfer_split, memo);
836  /* set per book option */
837  gnc_set_num_action (NULL, xfer_split, num, _("Payment"));
838  xaccAccountBeginEdit (xfer_acc);
839  xaccAccountInsertSplit (xfer_acc, xfer_split);
840  xaccAccountCommitEdit (xfer_acc);
841  xaccTransAppendSplit (txn, xfer_split);
842 
843  xaccSplitSetAmount(xfer_split, xfer_amount); /* Payment in xfer account currency */
844  xaccSplitSetValue(xfer_split, txn_value); /* Payment in transaction currency */
845  }
846  /* For a pre-existing xfer split, let's check if the amount and value
847  * have changed. If so, update them and unreconcile. */
848  else if (!gnc_numeric_equal (xaccSplitGetAmount (xfer_split), xfer_amount) ||
849  !gnc_numeric_equal (xaccSplitGetValue (xfer_split), txn_value))
850  {
851  xaccSplitSetAmount (xfer_split, xfer_amount);
852  xaccSplitSetValue (xfer_split, txn_value);
853  xaccSplitSetReconcile (xfer_split, NREC);
854  }
855 
856  /* Add a split in the post account */
857  split = xaccMallocSplit (book);
858  xaccSplitSetMemo (split, memo);
859  /* set per book option */
860  xaccSplitSetAction (split, _("Payment"));
861  xaccAccountBeginEdit (posted_acc);
862  xaccAccountInsertSplit (posted_acc, split);
863  xaccAccountCommitEdit (posted_acc);
864  xaccTransAppendSplit (txn, split);
865  xaccSplitSetAmount (split, gnc_numeric_neg (amount));
866  xaccSplitSetValue (split, gnc_numeric_neg (txn_value));
867 
868  /* Create a new lot for the payment */
869  payment_lot = gnc_lot_new (book);
870  gncOwnerAttachToLot (owner, payment_lot);
871  gnc_lot_add_split (payment_lot, split);
872 
873  /* Mark the transaction as a payment */
874  xaccTransSetNum (txn, num);
876 
877  /* Set date for transaction */
879  xaccTransSetDatePostedSecs (txn, date);
880 
881  /* Commit this new transaction */
882  xaccTransCommitEdit (txn);
883  if (preset_txn)
884  *preset_txn = txn;
885 
886  return payment_lot;
887 }
888 
889 typedef enum
890 {
891  is_equal = 8,
892  is_more = 4,
893  is_less = 2,
894  is_pay_split = 1
895 } split_flags;
896 
897 Split *gncOwnerFindOffsettingSplit (GNCLot *lot, gnc_numeric target_value)
898 {
899  SplitList *ls_iter = NULL;
900  Split *best_split = NULL;
901  gnc_numeric best_val = { 0, 1};
902  gint best_flags = 0;
903 
904  if (!lot)
905  return NULL;
906 
907  for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
908  {
909  Split *split = ls_iter->data;
910  Transaction *txn;
911  gnc_numeric split_value;
912  gint new_flags = 0;
913  gint val_cmp = 0;
914 
915  if (!split)
916  continue;
917 
918 
919  txn = xaccSplitGetParent (split);
920  if (!txn)
921  {
922  // Ooops - the split doesn't belong to any transaction !
923  // This is not expected so issue a warning and continue with next split
924  PWARN("Encountered a split in a payment lot that's not part of any transaction. "
925  "This is unexpected! Skipping split %p.", split);
926  continue;
927  }
928 
929  // Check if this split has the opposite sign of the target value we want to offset
930  split_value = xaccSplitGetValue (split);
931  if (gnc_numeric_positive_p (target_value) == gnc_numeric_positive_p (split_value))
932  continue;
933 
934  // Ok we have found a split that potentially can offset the target value
935  // Let's see if it's better than what we have found already.
936  val_cmp = gnc_numeric_compare (gnc_numeric_abs (split_value),
937  gnc_numeric_abs (target_value));
938  if (val_cmp == 0)
939  new_flags += is_equal;
940  else if (val_cmp > 0)
941  new_flags += is_more;
942  else
943  new_flags += is_less;
944 
945  if (xaccTransGetTxnType (txn) != TXN_TYPE_LINK)
946  new_flags += is_pay_split;
947 
948  if ((new_flags >= best_flags) &&
949  (gnc_numeric_compare (gnc_numeric_abs (split_value),
950  gnc_numeric_abs (best_val)) > 0))
951  {
952  // The new split is a better match than what we found so far
953  best_split = split;
954  best_flags = new_flags;
955  best_val = split_value;
956  }
957  }
958 
959  return best_split;
960 }
961 
962 gboolean
963 gncOwnerReduceSplitTo (Split *split, gnc_numeric target_value)
964 {
965  gnc_numeric split_val = xaccSplitGetValue (split);
966  gnc_numeric rem_val;
967  Split *rem_split;
968  Transaction *txn;
969  GNCLot *lot;
970 
971  if (gnc_numeric_positive_p (split_val) != gnc_numeric_positive_p (target_value))
972  return FALSE; // Split and target value have to be of the same sign
973 
974  if (gnc_numeric_equal (split_val, target_value))
975  return FALSE; // Split already has the target value
976 
977  rem_val = gnc_numeric_sub (split_val, target_value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); // note: values are of opposite sign
978  rem_split = xaccMallocSplit (xaccSplitGetBook (split));
979  xaccSplitCopyOnto (split, rem_split);
980  xaccSplitSetAmount (rem_split, rem_val);
981  xaccSplitSetValue (rem_split, rem_val);
982 
983  txn = xaccSplitGetParent (split);
984  xaccTransBeginEdit (txn);
985  xaccSplitSetAmount (split, target_value);
986  xaccSplitSetValue (split, target_value);
987  xaccSplitSetParent (rem_split, txn);
988  xaccTransCommitEdit (txn);
989 
990  lot = xaccSplitGetLot (split);
991  gnc_lot_add_split (lot, rem_split);
992 
993  return TRUE;
994 }
995 
996 void
997 gncOwnerSetLotLinkMemo (Transaction *ll_txn)
998 {
999  gchar *memo_prefix = _("Offset between documents: ");
1000  gchar *new_memo;
1001  SplitList *lts_iter;
1002  SplitList *splits = NULL, *siter;
1003  GList *titles = NULL, *titer;
1004 
1005  if (!ll_txn)
1006  return;
1007 
1008  if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
1009  return;
1010 
1011  // Find all splits in the lot link transaction that are also in a document lot
1012  for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
1013  {
1014  Split *split = lts_iter->data;
1015  GNCLot *lot;
1016  GncInvoice *invoice;
1017  gchar *title;
1018 
1019  if (!split)
1020  continue;
1021 
1022  lot = xaccSplitGetLot (split);
1023  if (!lot)
1024  continue;
1025 
1026  invoice = gncInvoiceGetInvoiceFromLot (lot);
1027  if (!invoice)
1028  continue;
1029 
1030  title = g_strdup_printf ("%s %s", gncInvoiceGetTypeString (invoice), gncInvoiceGetID (invoice));
1031 
1032  titles = g_list_prepend (titles, title);
1033  splits = g_list_prepend (splits, split); // splits don't need to be sorted
1034  }
1035 
1036  if (!titles)
1037  return; // We didn't find document lots
1038 
1039  titles = g_list_sort (titles, (GCompareFunc)g_strcmp0);
1040 
1041  // Create the memo as we'd want it to be
1042  new_memo = g_strconcat (memo_prefix, titles->data, NULL);
1043  for (titer = titles->next; titer; titer = titer->next)
1044  {
1045  gchar *tmp_memo = g_strconcat (new_memo, " - ", titer->data, NULL);
1046  g_free (new_memo);
1047  new_memo = tmp_memo;
1048  }
1049  g_list_free_full (titles, g_free);
1050 
1051  // Update the memos of all the splits we found previously (if needed)
1052  for (siter = splits; siter; siter = siter->next)
1053  {
1054  if (g_strcmp0 (xaccSplitGetMemo (siter->data), new_memo) != 0)
1055  xaccSplitSetMemo (siter->data, new_memo);
1056  }
1057 
1058  g_list_free (splits);
1059  g_free (new_memo);
1060 }
1061 
1062 /* Find an existing lot link transaction in the given lot
1063  * Only use a lot link that already links at least two
1064  * documents (to avoid perpetuating the lot link proliferation
1065  * that happened in 2.6.0-2.6.3).
1066  */
1067 static Transaction *
1068 get_ll_transaction_from_lot (GNCLot *lot)
1069 {
1070  SplitList *ls_iter;
1071 
1072  /* This should really only be called on a document lot */
1073  if (!gncInvoiceGetInvoiceFromLot (lot))
1074  return NULL;
1075 
1076  /* The given lot is a valid document lot. Now iterate over all
1077  * other lot links in this lot to find one more document lot.
1078  */
1079  for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
1080  {
1081  Split *ls = ls_iter->data;
1082  Transaction *ll_txn = xaccSplitGetParent (ls);
1083  SplitList *ts_iter;
1084 
1085  if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
1086  continue;
1087 
1088  for (ts_iter = xaccTransGetSplitList (ll_txn); ts_iter; ts_iter = ts_iter->next)
1089  {
1090  Split *ts = ts_iter->data;
1091  GNCLot *tslot = xaccSplitGetLot (ts);
1092 
1093  if (!tslot)
1094  continue;
1095 
1096  if (tslot == lot)
1097  continue;
1098 
1099  if (gncInvoiceGetInvoiceFromLot (lot))
1100  return ll_txn; /* Got one more document lot - mission accomplished */
1101  }
1102  }
1103 
1104  /* The lot doesn't have an ll_txn with the requested criteria... */
1105  return NULL;
1106 }
1107 
1108 static void
1109 gncOwnerCreateLotLink (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
1110 {
1111  const gchar *action = _("Lot Link");
1112  Account *acct = gnc_lot_get_account (from_lot);
1113  const gchar *name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
1114  Transaction *ll_txn = NULL;
1115  gnc_numeric from_lot_bal, to_lot_bal;
1116  time64 from_time, to_time;
1117  time64 time_posted;
1118  Split *split;
1119 
1120  /* Sanity check */
1121  if (!gncInvoiceGetInvoiceFromLot (from_lot) ||
1122  !gncInvoiceGetInvoiceFromLot (to_lot))
1123  return;
1124 
1125  /* Determine transaction date based on lot splits */
1128  if (from_time >= to_time)
1129  time_posted = from_time;
1130  else
1131  time_posted = to_time;
1132 
1133  /* Figure out how much we can offset between the lots */
1134  from_lot_bal = gnc_lot_get_balance (from_lot);
1135  to_lot_bal = gnc_lot_get_balance (to_lot);
1136  if (gnc_numeric_compare (gnc_numeric_abs (from_lot_bal),
1137  gnc_numeric_abs (to_lot_bal)) > 0)
1138  from_lot_bal = gnc_numeric_neg (to_lot_bal);
1139  else
1140  to_lot_bal = gnc_numeric_neg (from_lot_bal);
1141 
1142  xaccAccountBeginEdit (acct);
1143 
1144  /* Look for a pre-existing lot link we can extend */
1145  ll_txn = get_ll_transaction_from_lot (from_lot);
1146 
1147  if (!ll_txn)
1148  ll_txn = get_ll_transaction_from_lot (to_lot);
1149 
1150  if (!ll_txn)
1151  {
1152  /* No pre-existing lot link. Create one. */
1153  ll_txn = xaccMallocTransaction (gnc_lot_get_book (from_lot));
1154  xaccTransBeginEdit (ll_txn);
1155  xaccTransSetDescription (ll_txn, name ? name : "(Unknown)");
1157  xaccTransSetDateEnteredSecs (ll_txn, gnc_time (NULL));
1158  xaccTransSetDatePostedSecs (ll_txn, time_posted);
1160  }
1161  else
1162  {
1163  time64 time = xaccTransRetDatePosted (ll_txn);
1164  xaccTransBeginEdit (ll_txn);
1165 
1166  /* Maybe we need to update the post date of the transaction ? */
1167  if (time_posted > time)
1168  xaccTransSetDatePostedSecs (ll_txn, time_posted);
1169  }
1170 
1171  /* Create a split for the from_lot */
1172  split = xaccMallocSplit (gnc_lot_get_book (from_lot));
1173  /* set Action using utility function */
1174  gnc_set_num_action (NULL, split, NULL, action);
1175  xaccAccountInsertSplit (acct, split);
1176  xaccTransAppendSplit (ll_txn, split);
1177  /* To offset the lot balance, the split must be of the opposite sign */
1178  xaccSplitSetBaseValue (split, gnc_numeric_neg (from_lot_bal), xaccAccountGetCommodity(acct));
1179  gnc_lot_add_split (from_lot, split);
1180 
1181  /* Create a split for the to_lot */
1182  split = xaccMallocSplit (gnc_lot_get_book (to_lot));
1183  /* set Action using utility function */
1184  gnc_set_num_action (NULL, split, NULL, action);
1185  xaccAccountInsertSplit (acct, split);
1186  xaccTransAppendSplit (ll_txn, split);
1187  /* To offset the lot balance, the split must be of the opposite sign */
1188  xaccSplitSetBaseValue (split, gnc_numeric_neg (to_lot_bal), xaccAccountGetCommodity(acct));
1189  gnc_lot_add_split (to_lot, split);
1190 
1191  xaccTransCommitEdit (ll_txn);
1192 
1193 
1194  /* Do some post-cleaning on the lots
1195  * The above actions may have created splits that are
1196  * in the same transaction and lot. These can be merged.
1197  */
1198  xaccScrubMergeLotSubSplits (to_lot, FALSE);
1199  xaccScrubMergeLotSubSplits (from_lot, FALSE);
1200  /* And finally set the same memo for all remaining splits
1201  * It's a convenience for the users to identify all documents
1202  * involved in the link.
1203  */
1204  gncOwnerSetLotLinkMemo (ll_txn);
1205  xaccAccountCommitEdit (acct);
1206 }
1207 
1208 static void gncOwnerOffsetLots (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
1209 {
1210  gnc_numeric target_offset;
1211  Split *split;
1212 
1213  /* from lot should not be a document lot because we're removing a split from there ! */
1214  if (gncInvoiceGetInvoiceFromLot (from_lot))
1215  {
1216  PWARN ("from_lot %p is a document lot. That is not allowed in gncOwnerOffsetLots", from_lot);
1217  return;
1218  }
1219 
1220  /* Get best matching split from from_lot to offset to_lot */
1221  target_offset = gnc_lot_get_balance (to_lot);
1222  if (gnc_numeric_zero_p (target_offset))
1223  return; // to_lot is already balanced, nothing more to do
1224 
1225  split = gncOwnerFindOffsettingSplit (from_lot, target_offset);
1226  if (!split)
1227  return; // No suitable offsetting split found, nothing more to do
1228 
1229  /* If the offsetting split is bigger than the amount needed to balance
1230  * to_lot, reduce the split so its reduced value closes to_lot exactly.
1231  * Note the negation in the reduction function. The split must be of
1232  * opposite sign of to_lot's balance in order to be able to close it.
1233  */
1235  gnc_numeric_abs (target_offset)) > 0)
1236  gncOwnerReduceSplitTo (split, gnc_numeric_neg (target_offset));
1237 
1238  /* Move the reduced split from from_lot to to_lot */
1239  gnc_lot_add_split (to_lot, split);
1240 
1241 }
1242 
1243 void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
1244 {
1245  GList *left_iter;
1246 
1247  /* General note: in the code below the term "payment" can
1248  * both mean a true payment or a document of
1249  * the opposite sign (invoice vs credit note) relative to
1250  * the lot being processed. In general this function will
1251  * perform a balancing action on a set of lots, so you
1252  * will also find frequent references to balancing instead. */
1253 
1254  /* Payments can only be applied when at least an owner
1255  * and a list of lots to use are given */
1256  if (!owner) return;
1257  if (!lots) return;
1258 
1259  for (left_iter = lots; left_iter; left_iter = left_iter->next)
1260  {
1261  GNCLot *left_lot = left_iter->data;
1262  gnc_numeric left_lot_bal;
1263  gboolean left_lot_has_doc;
1264  gboolean left_modified = FALSE;
1265  Account *acct;
1266  GList *right_iter;
1267 
1268  /* Only attempt to apply payments to open lots.
1269  * Note that due to the iterative nature of this function lots
1270  * in the list may become empty/closed before they are evaluated as
1271  * base lot, so we should check this for each lot. */
1272  if (!left_lot)
1273  continue;
1274  if (gnc_lot_count_splits (left_lot) == 0)
1275  {
1276  gnc_lot_destroy (left_lot);
1277  left_iter->data = NULL;
1278  continue;
1279  }
1280  if (gnc_lot_is_closed (left_lot))
1281  continue;
1282 
1283  acct = gnc_lot_get_account (left_lot);
1284  xaccAccountBeginEdit (acct);
1285 
1286  left_lot_bal = gnc_lot_get_balance (left_lot);
1287  left_lot_has_doc = (gncInvoiceGetInvoiceFromLot (left_lot) != NULL);
1288 
1289  /* Attempt to offset left_lot with any of the remaining lots. To do so
1290  * iterate over the remaining lots adding lot links or moving payments
1291  * around.
1292  */
1293  for (right_iter = left_iter->next; right_iter; right_iter = right_iter->next)
1294  {
1295  GNCLot *right_lot = right_iter->data;
1296  gnc_numeric right_lot_bal;
1297  gboolean right_lot_has_doc;
1298 
1299  /* Only attempt to use open lots to balance the base lot.
1300  * Note that due to the iterative nature of this function lots
1301  * in the list may become empty/closed before they are evaluated as
1302  * base lot, so we should check this for each lot. */
1303  if (!right_lot)
1304  continue;
1305  if (gnc_lot_count_splits (right_lot) == 0)
1306  {
1307  gnc_lot_destroy (right_lot);
1308  right_iter->data = NULL;
1309  continue;
1310  }
1311  if (gnc_lot_is_closed (right_lot))
1312  continue;
1313 
1314  /* Balancing transactions for invoice/payments can only happen
1315  * in the same account. */
1316  if (acct != gnc_lot_get_account (right_lot))
1317  continue;
1318 
1319 
1320  /* Only attempt to balance if the base lot and balancing lot are
1321  * of the opposite sign. (Otherwise we would increase the balance
1322  * of the lot - Duh */
1323  right_lot_bal = gnc_lot_get_balance (right_lot);
1324  if (gnc_numeric_positive_p (left_lot_bal) == gnc_numeric_positive_p (right_lot_bal))
1325  continue;
1326 
1327  /* Ok we found two lots than can (partly) offset each other.
1328  * Depending on the lot types, a different action is needed to accomplish this.
1329  * 1. Both lots are document lots (invoices/credit notes)
1330  * -> Create a lot linking transaction between the lots
1331  * 2. Both lots are payment lots (lots without a document attached)
1332  * -> Use part of the bigger lot to the close the smaller lot
1333  * 3. One document lot with one payment lot
1334  * -> Use (part of) the payment to offset (part of) the document lot,
1335  * Which one will be closed depends on which is the bigger one
1336  */
1337  right_lot_has_doc = (gncInvoiceGetInvoiceFromLot (right_lot) != NULL);
1338  if (left_lot_has_doc && right_lot_has_doc)
1339  gncOwnerCreateLotLink (left_lot, right_lot, owner);
1340  else if (!left_lot_has_doc && !right_lot_has_doc)
1341  {
1342  gint cmp = gnc_numeric_compare (gnc_numeric_abs (left_lot_bal),
1343  gnc_numeric_abs (right_lot_bal));
1344  if (cmp >= 0)
1345  gncOwnerOffsetLots (left_lot, right_lot, owner);
1346  else
1347  gncOwnerOffsetLots (right_lot, left_lot, owner);
1348  }
1349  else
1350  {
1351  GNCLot *doc_lot = left_lot_has_doc ? left_lot : right_lot;
1352  GNCLot *pay_lot = left_lot_has_doc ? right_lot : left_lot;
1353  // Ok, let's try to move a payment from pay_lot to doc_lot
1354  gncOwnerOffsetLots (pay_lot, doc_lot, owner);
1355  }
1356 
1357  /* If we get here, then right_lot was modified
1358  * If the lot has a document, send an event for send an event for it as well
1359  * so it gets potentially updated as paid */
1360 
1361  {
1362  GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(right_lot);
1363  if (this_invoice)
1364  qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
1365  }
1366  left_modified = TRUE;
1367  }
1368 
1369  /* If left_lot was modified and the lot has a document,
1370  * send an event for send an event for it as well
1371  * so it gets potentially updated as paid */
1372  if (left_modified)
1373  {
1374  GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(left_lot);
1375  if (this_invoice)
1376  qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
1377  }
1378  xaccAccountCommitEdit (acct);
1379 
1380  }
1381 }
1382 
1383 /*
1384  * Create a payment of "amount" for the owner and match it with
1385  * the set of lots passed in.
1386  * If
1387  * - no lots were given
1388  * - auto_pay is true
1389  * then all open lots for the owner are considered.
1390  */
1391 void
1392 gncOwnerApplyPaymentSecs (const GncOwner *owner, Transaction **preset_txn,
1393  GList *lots, Account *posted_acc, Account *xfer_acc,
1394  gnc_numeric amount, gnc_numeric exch, time64 date,
1395  const char *memo, const char *num, gboolean auto_pay)
1396 {
1397  GNCLot *payment_lot = NULL;
1398  GList *selected_lots = NULL;
1399 
1400  /* Verify our arguments */
1401  if (!owner || !posted_acc
1402  || (!xfer_acc && !gnc_numeric_zero_p (amount)) ) return;
1403  g_return_if_fail (owner->owner.undefined);
1404 
1405  /* If there's a real amount to transfer create a lot for this payment */
1406  if (!gnc_numeric_zero_p (amount))
1407  payment_lot = gncOwnerCreatePaymentLotSecs (owner, preset_txn,
1408  posted_acc, xfer_acc,
1409  amount, exch, date, memo,
1410  num);
1411 
1412  if (lots)
1413  selected_lots = lots;
1414  else if (auto_pay)
1415  selected_lots = xaccAccountFindOpenLots (posted_acc, gncOwnerLotMatchOwnerFunc,
1416  (gpointer)owner, NULL);
1417 
1418  /* And link the selected lots and the payment lot together as well as possible.
1419  * If the payment was bigger than the selected documents/overpayments, only
1420  * part of the payment will be used. Similarly if more documents were selected
1421  * than the payment value set, not all documents will be marked as paid. */
1422  if (payment_lot)
1423  selected_lots = g_list_prepend (selected_lots, payment_lot);
1424  gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots);
1425  g_list_free (selected_lots);
1426 }
1427 
1428 GList *
1430 {
1431  g_return_val_if_fail (owner, NULL);
1432 
1433  switch (gncOwnerGetType (owner))
1434  {
1435  case GNC_OWNER_CUSTOMER:
1436  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_RECEIVABLE));
1437  case GNC_OWNER_VENDOR:
1438  case GNC_OWNER_EMPLOYEE:
1439  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_PAYABLE));
1440  break;
1441  default:
1442  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_NONE));
1443  }
1444 }
1445 
1446 GList *
1448 {
1449  g_return_val_if_fail (owner, NULL);
1450  g_return_val_if_fail (gncOwnerGetCurrency(owner), NULL);
1451 
1452  return (g_list_prepend (NULL, gncOwnerGetCurrency(owner)));
1453 }
1454 
1455 /*********************************************************************/
1456 /* Owner balance calculation routines */
1457 
1458 /*
1459  * Given an owner, extract the open balance from the owner and then
1460  * convert it to the desired currency.
1461  */
1462 gnc_numeric
1464  const gnc_commodity *report_currency)
1465 {
1466  gnc_numeric balance = gnc_numeric_zero ();
1467  QofBook *book;
1468  gnc_commodity *owner_currency;
1469  GNCPriceDB *pdb;
1470  const gnc_numeric *cached_balance = NULL;
1471 
1472  g_return_val_if_fail (owner, gnc_numeric_zero ());
1473 
1474  book = qof_instance_get_book (qofOwnerGetOwner (owner));
1475  owner_currency = gncOwnerGetCurrency (owner);
1476 
1477  cached_balance = gncOwnerGetCachedBalance (owner);
1478  if (cached_balance)
1479  balance = *cached_balance;
1480  else
1481  {
1482  /* No valid cache value found for balance. Let's recalculate */
1483  GList *acct_list = gnc_account_get_descendants (gnc_book_get_root_account (book));
1484  GList *acct_types = gncOwnerGetAccountTypesList (owner);
1485  GList *acct_node;
1486 
1487  /* For each account */
1488  for (acct_node = acct_list; acct_node; acct_node = acct_node->next)
1489  {
1490  Account *account = acct_node->data;
1491  GList *lot_list = NULL, *lot_node;
1492 
1493  /* Check if this account can have lots for the owner, otherwise skip to next */
1494  if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account))
1495  == -1)
1496  continue;
1497 
1498 
1499  if (!gnc_commodity_equal (owner_currency, xaccAccountGetCommodity (account)))
1500  continue;
1501 
1502  /* Get a list of open lots for this owner and account */
1504  (gpointer)owner, NULL);
1505  /* For each lot */
1506  for (lot_node = lot_list; lot_node; lot_node = lot_node->next)
1507  {
1508  GNCLot *lot = lot_node->data;
1509  gnc_numeric lot_balance = gnc_lot_get_balance (lot);
1510  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot(lot);
1511  if (invoice)
1512  balance = gnc_numeric_add (balance, lot_balance,
1514  }
1515  g_list_free (lot_list);
1516  }
1517  g_list_free (acct_list);
1518  g_list_free (acct_types);
1519 
1520  gncOwnerSetCachedBalance (owner, &balance);
1521  }
1522 
1523  pdb = gnc_pricedb_get_db (book);
1524 
1525  if (report_currency)
1527  pdb, balance, owner_currency, report_currency);
1528 
1529  return balance;
1530 }
1531 
1532 
1533 /* XXX: Yea, this is broken, but it should work fine for Queries.
1534  * We're single-threaded, right?
1535  */
1536 static GncOwner *
1537 owner_from_lot (GNCLot *lot)
1538 {
1539  static GncOwner owner;
1540 
1541  if (!lot) return NULL;
1542  if (gncOwnerGetOwnerFromLot (lot, &owner))
1543  return &owner;
1544 
1545  return NULL;
1546 }
1547 
1548 static void
1549 reg_lot (void)
1550 {
1551  static QofParam params[] =
1552  {
1553  { OWNER_FROM_LOT, _GNC_MOD_NAME, (QofAccessFunc)owner_from_lot, NULL },
1554  { NULL },
1555  };
1556 
1557  qof_class_register (GNC_ID_LOT, NULL, params);
1558 }
1559 
1560 gboolean gncOwnerGetOwnerFromTypeGuid (QofBook *book, GncOwner *owner, QofIdType type, GncGUID *guid)
1561 {
1562  if (!book || !owner || !type || !guid) return FALSE;
1563 
1564  if (0 == g_strcmp0(type, GNC_ID_CUSTOMER))
1565  {
1566  GncCustomer *customer = gncCustomerLookup(book, guid);
1567  gncOwnerInitCustomer(owner, customer);
1568  return (NULL != customer);
1569  }
1570  else if (0 == g_strcmp0(type, GNC_ID_JOB))
1571  {
1572  GncJob *job = gncJobLookup(book, guid);
1573  gncOwnerInitJob(owner, job);
1574  return (NULL != job);
1575  }
1576  else if (0 == g_strcmp0(type, GNC_ID_VENDOR))
1577  {
1578  GncVendor *vendor = gncVendorLookup(book, guid);
1579  gncOwnerInitVendor(owner, vendor);
1580  return (NULL != vendor);
1581  }
1582  else if (0 == g_strcmp0(type, GNC_ID_EMPLOYEE))
1583  {
1584  GncEmployee *employee = gncEmployeeLookup(book, guid);
1585  gncOwnerInitEmployee(owner, employee);
1586  return (NULL != employee);
1587  }
1588  return 0;
1589 }
1590 
1591 gboolean gncOwnerRegister (void)
1592 {
1593  static QofParam params[] =
1594  {
1595  { OWNER_TYPE, QOF_TYPE_INT64, (QofAccessFunc)gncOwnerGetType, NULL },
1596  { OWNER_CUSTOMER, GNC_ID_CUSTOMER, (QofAccessFunc)gncOwnerGetCustomer, NULL },
1597  { OWNER_JOB, GNC_ID_JOB, (QofAccessFunc)gncOwnerGetJob, NULL },
1598  { OWNER_VENDOR, GNC_ID_VENDOR, (QofAccessFunc)gncOwnerGetVendor, NULL },
1599  { OWNER_EMPLOYEE, GNC_ID_EMPLOYEE, (QofAccessFunc)gncOwnerGetEmployee, NULL },
1600  { OWNER_PARENT, GNC_ID_OWNER, (QofAccessFunc)gncOwnerGetEndOwner, NULL },
1601  { OWNER_PARENTG, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetEndGUID, NULL },
1602  { OWNER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncOwnerGetName, NULL },
1603  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetGUID, NULL },
1604  { NULL },
1605  };
1606 
1607  qof_class_register (GNC_ID_OWNER, (QofSortFunc)gncOwnerCompare, params);
1608  reg_lot ();
1609 
1610  return TRUE;
1611 }
1612 
1613 const gnc_numeric*
1614 gncOwnerGetCachedBalance (const GncOwner *owner)
1615 {
1616  if (!owner) return NULL;
1617 
1618  if (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER)
1619  return gncCustomerGetCachedBalance (gncOwnerGetCustomer (owner));
1620  else if (gncOwnerGetType (owner) == GNC_OWNER_VENDOR)
1621  return gncVendorGetCachedBalance (gncOwnerGetVendor (owner));
1622  else if (gncOwnerGetType (owner) == GNC_OWNER_EMPLOYEE)
1623  return gncEmployeeGetCachedBalance (gncOwnerGetEmployee (owner));
1624 
1625  return NULL;
1626 }
1627 
1628 void gncOwnerSetCachedBalance (const GncOwner *owner, const gnc_numeric *new_bal)
1629 {
1630  if (!owner) return;
1631 
1632  if (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER)
1633  gncCustomerSetCachedBalance (gncOwnerGetCustomer (owner), new_bal);
1634  else if (gncOwnerGetType (owner) == GNC_OWNER_VENDOR)
1635  gncVendorSetCachedBalance (gncOwnerGetVendor (owner), new_bal);
1636  else if (gncOwnerGetType (owner) == GNC_OWNER_EMPLOYEE)
1637  gncEmployeeSetCachedBalance (gncOwnerGetEmployee (owner), new_bal);
1638 }
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
GList * gncOwnerGetCommoditiesList(const GncOwner *owner)
Returns a GList of currencies associated with the owner.
Definition: gncOwner.c:1447
#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:1317
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits, except that it does it for all of the splits in the lot.
Definition: Scrub2.c:383
const GncGUID * gncOwnerGetGUID(const GncOwner *owner)
Get the GncGUID of the immediate owner.
Definition: gncOwner.c:519
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition: Split.c:1745
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Business Interface: Object OWNERs.
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.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gboolean gncOwnerGetOwnerFromTxn(Transaction *txn, GncOwner *owner)
Convenience function to get the owner from a transaction.
Definition: gncOwner.c:675
GList * gncOwnerGetAccountTypesList(const GncOwner *owner)
Returns a GList of account-types based on the owner type.
Definition: gncOwner.c:1429
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits...
Definition: Transaction.c:2562
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3279
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1468
Utilities to Convert Stock Accounts to use Lots.
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition: qofid.h:87
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
This is really a helper for xaccTransCopyOnto.
Definition: Split.c:641
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
void qof_class_register(QofIdTypeConst obj_name, QofSortFunc default_sort_function, const QofParam *params)
This function registers a new object class with the Qof subsystem.
Definition: qofclass.cpp:86
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 xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly, see &#39;gnc_set_num_action&#39; in engine/engine-helpers.c & .h which takes a user-set book option for selecting the source for the num-cell (the transaction-number or the split-action field) in registers/reports into account automatically.
Definition: Transaction.c:2186
const char * gncOwnerGetTypeString(const GncOwner *owner)
return the type for the owner as an untranslated string.
Definition: gncOwner.c:207
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
API for Transactions and Splits (journal entries)
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition: qofclass.h:222
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b.
QofBook * xaccSplitGetBook(const Split *split)
Returns the book of this split, i.e.
Definition: gmock-Split.cpp:45
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
void gncOwnerBeginEdit(GncOwner *owner)
These are convenience wrappers around gnc{Vendor,Customer,Job,Employee}* functions.
Definition: gncOwner.c:73
gboolean gncOwnerIsValid(const GncOwner *owner)
Returns TRUE if the given owner is one of the valid objects.
Definition: gncOwner.c:700
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
Definition: gnc-pricedb.c:967
Split * gnc_lot_get_earliest_split(GNCLot *lot)
The gnc_lot_get_earliest_split() routine is a convenience routine that helps identify the earliest da...
Definition: gnc-lot.c:705
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition: gncOwner.c:276
gnc_numeric gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency)
Convert a balance from one currency to another using the most recent price between the two...
Definition: gnc-pricedb.c:2662
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1429
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:1243
Split * gnc_lot_get_latest_split(GNCLot *lot)
The gnc_lot_get_latest_split() routine is a convenience routine that helps identify the date this lot...
Definition: gnc-lot.c:717
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:85
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2410
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:2117
int gncOwnerGCompareFunc(const GncOwner *a, const GncOwner *b)
Same as gncOwnerEqual, but returns 0 if equal to be used as a GList custom compare function...
Definition: gncOwner.c:412
#define TXN_TYPE_NONE
No transaction type.
Definition: Transaction.h:125
void gncOwnerApplyPaymentSecs(const GncOwner *owner, Transaction **preset_txn, GList *lots, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, time64 date, const char *memo, const char *num, gboolean auto_pay)
A convenience function to apply a payment to the owner.
Definition: gncOwner.c:1392
GList SplitList
GList of Split.
Definition: gnc-engine.h:211
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
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1726
gint gncOwnerLotsSortFunc(GNCLot *lotA, GNCLot *lotB)
Helper function used to sort lots by date.
Definition: gncOwner.c:729
gboolean gncOwnerReduceSplitTo(Split *split, gnc_numeric target_value)
Helper function to reduce the value of a split to target_value.
Definition: gncOwner.c:963
gnc_numeric gncOwnerGetBalanceInCurrency(const GncOwner *owner, const gnc_commodity *report_currency)
Given an owner, extract the open balance from the owner and then convert it to the desired currency...
Definition: gncOwner.c:1463
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
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2498
QofIdTypeConst qofOwnerGetType(const GncOwner *owner)
return the type for the collection.
Definition: gncOwner.c:231
int gncOwnerCompare(const GncOwner *a, const GncOwner *b)
Sort on name.
Definition: gncOwner.c:591
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Definition: gncOwner.c:320
void gncOwnerAttachToLot(const GncOwner *owner, GNCLot *lot)
Attach an owner to a lot.
Definition: gncOwner.c:623
QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
Returns the QofIdType of the given GncOwnerType, or NULL if no suitable one exists.
Definition: gncOwner.c:236
gpointer gncOwnerGetUndefined(const GncOwner *owner)
If the given owner is of type GNC_OWNER_UNDEFINED, returns the undefined pointer, which is usually NU...
Definition: gncOwner.c:363
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
A/P account type.
Definition: Account.h:154
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
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...
#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...
int gncVendorCompare(const GncVendor *a, const GncVendor *b)
XXX should be renamed to RetJobList to be consistent with other usage, since caller must free the cop...
Definition: gncVendor.c:797
#define TXN_TYPE_PAYMENT
Transaction is a payment.
Definition: Transaction.h:127
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
credit, discount and shipaddr are unique to GncCustomer id, name, notes, terms, addr, currency, taxtable, taxtable_override taxincluded, active and jobs are identical to ::GncVendor.
gboolean GNC_IS_OWNER(QofInstance *ent)
Check if entity is an owner kind.
Definition: gncOwner.c:353
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
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:3036
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1314
Business Invoice Interface.
GncJob * gncOwnerGetJob(const GncOwner *owner)
If the given owner is of type GNC_OWNER_JOB, returns the pointer to the job object.
Definition: gncOwner.c:377
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction, specified by a time64 (see ctime(3)).
Definition: Transaction.c:2025
Split * xaccTransGetFirstAPARAcctSplit(const Transaction *trans, gboolean strict)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
Definition: Transaction.c:2386
gboolean gncOwnerLotMatchOwnerFunc(GNCLot *lot, gpointer user_data)
Helper function used to filter a list of lots by owner.
Definition: gncOwner.c:707
gboolean gnc_lot_is_closed(GNCLot *lot)
The gnc_lot_is_closed() routine returns a boolean flag: is this lot closed? A lot is closed if its ba...
Definition: gnc-lot.c:382
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition: Account.cpp:1449
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1370
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
A/R account type.
Definition: Account.h:152
Split * gncOwnerFindOffsettingSplit(GNCLot *lot, gnc_numeric target_value)
Helper function to find a split in lot that best offsets target_value Obviously it should be of oppos...
Definition: gncOwner.c:897
GncVendor * gncOwnerGetVendor(const GncOwner *owner)
If the given owner is of type GNC_OWNER_VENDOR, returns the pointer to the vendor object...
Definition: gncOwner.c:384
GncCustomer * gncOwnerGetCustomer(const GncOwner *owner)
If the given owner is of type GNC_OWNER_CUSTOMER, returns the pointer to the customer object...
Definition: gncOwner.c:370
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
void gncOwnerSetLotLinkMemo(Transaction *ll_txn)
To help a user understand what a lot link transaction does, we set the memo to name all documents inv...
Definition: gncOwner.c:997
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
Account * gnc_lot_get_account(const GNCLot *lot)
The gnc_lot_get_account() routine returns the account with which this lot is associated.
Definition: gnc-lot.c:392
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
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2060
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
Not a type.
Definition: Account.h:108
#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
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition: Account.cpp:1490
GncOwner * gncOwnerNew(void)
These two functions are mainly for the convenience of scheme code.
Definition: gncOwner.c:58
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
Commodity handling public routines.
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:1879
#define NREC
not reconciled or cleared
Definition: Split.h:74
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69