GnuCash  4.8a-176-g88ecf8dd1
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 *commodity;
760  Split *xfer_split = NULL;
761  Transaction *txn = NULL;
762  GNCLot *payment_lot;
763 
764  /* Verify our arguments */
765  if (!owner || !posted_acc || !xfer_acc) return NULL;
766  g_return_val_if_fail (owner->owner.undefined != NULL, NULL);
767 
768  /* Compute the ancillary data */
769  book = gnc_account_get_book (posted_acc);
770  name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
771  commodity = gncOwnerGetCurrency (owner);
772 // reverse = use_reversed_payment_amounts(owner);
773 
774  if (preset_txn && *preset_txn)
775  txn = *preset_txn;
776 
777  if (txn)
778  {
779  xaccTransSetDescription (txn, name ? name : "");
780 
781  /* Pre-existing transaction was specified. We completely clear it,
782  * except for the split in the transfer account, unless the
783  * transaction can't be reused (wrong currency, wrong transfer account).
784  * In that case, the transaction is simply removed and an new
785  * one created. */
786 
787  xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
788 
789  if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
790  {
791  PINFO("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
792  xfer_split = NULL;
793  }
794 
795  if (!xfer_split)
796  {
797  PINFO("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");
798 
799  xaccTransBeginEdit (txn);
800  xaccTransDestroy (txn);
801  xaccTransCommitEdit (txn);
802 
803  txn = NULL;
804  }
805  else
806  {
807  int i = 0;
808  xaccTransBeginEdit (txn);
809  while (i < xaccTransCountSplits(txn))
810  {
811  Split *split = xaccTransGetSplit (txn, i);
812  if (split == xfer_split)
813  {
814  gnc_set_num_action (NULL, split, num, _("Payment"));
815  ++i;
816  }
817  else
818  {
819  xaccSplitDestroy(split);
820  }
821  }
822  /* Note: don't commit transaction now - that would insert an imbalance split.*/
823  }
824  }
825 
826  /* Create the transaction if we don't have one yet */
827  if (!txn)
828  {
829  txn = xaccMallocTransaction (book);
830  xaccTransBeginEdit (txn);
831  }
832 
833  /* Insert a split for the transfer account if we don't have one yet */
834  if (!xfer_split)
835  {
836 
837  /* Set up the transaction */
838  xaccTransSetDescription (txn, name ? name : "");
839  /* set per book option */
840  xaccTransSetCurrency (txn, commodity);
841 
842 
843  /* The split for the transfer account */
844  split = xaccMallocSplit (book);
845  xaccSplitSetMemo (split, memo);
846  /* set per book option */
847  gnc_set_num_action (NULL, split, num, _("Payment"));
848  xaccAccountBeginEdit (xfer_acc);
849  xaccAccountInsertSplit (xfer_acc, split);
850  xaccAccountCommitEdit (xfer_acc);
851  xaccTransAppendSplit (txn, split);
852 
853  if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
854  {
855  xaccSplitSetBaseValue (split, amount, commodity);
856  }
857  else
858  {
859  /* This will be a multi-currency transaction. The amount passed to this
860  * function is in the owner commodity (also used by the post account).
861  * For the xfer split we also need to value the payment in the xfer account's
862  * commodity.
863  * exch is from post account to xfer account so that can be used directly
864  * to calculate the equivalent amount in the xfer account's commodity. */
865  gnc_numeric xfer_amount = gnc_numeric_mul (amount, exch, GNC_DENOM_AUTO,
867 
868  xaccSplitSetAmount(split, xfer_amount); /* Payment in xfer account currency */
869  xaccSplitSetValue(split, amount); /* Payment in transaction currency */
870  }
871  }
872 
873  /* Add a split in the post account */
874  split = xaccMallocSplit (book);
875  xaccSplitSetMemo (split, memo);
876  /* set per book option */
877  gnc_set_num_action (NULL, split, num, _("Payment"));
878  xaccAccountBeginEdit (posted_acc);
879  xaccAccountInsertSplit (posted_acc, split);
880  xaccAccountCommitEdit (posted_acc);
881  xaccTransAppendSplit (txn, split);
882  xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);
883 
884  /* Create a new lot for the payment */
885  payment_lot = gnc_lot_new (book);
886  gncOwnerAttachToLot (owner, payment_lot);
887  gnc_lot_add_split (payment_lot, split);
888 
889  /* Mark the transaction as a payment */
890  gnc_set_num_action (txn, NULL, num, _("Payment"));
892 
893  /* Set date for transaction */
895  xaccTransSetDatePostedSecs (txn, date);
896 
897  /* Commit this new transaction */
898  xaccTransCommitEdit (txn);
899  if (preset_txn)
900  *preset_txn = txn;
901 
902  return payment_lot;
903 }
904 
905 typedef enum
906 {
907  is_equal = 8,
908  is_more = 4,
909  is_less = 2,
910  is_pay_split = 1
911 } split_flags;
912 
913 Split *gncOwnerFindOffsettingSplit (GNCLot *lot, gnc_numeric target_value)
914 {
915  SplitList *ls_iter = NULL;
916  Split *best_split = NULL;
917  gnc_numeric best_val = { 0, 1};
918  gint best_flags = 0;
919 
920  if (!lot)
921  return NULL;
922 
923  for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
924  {
925  Split *split = ls_iter->data;
926  Transaction *txn;
927  gnc_numeric split_value;
928  gint new_flags = 0;
929  gint val_cmp = 0;
930 
931  if (!split)
932  continue;
933 
934 
935  txn = xaccSplitGetParent (split);
936  if (!txn)
937  {
938  // Ooops - the split doesn't belong to any transaction !
939  // This is not expected so issue a warning and continue with next split
940  PWARN("Encountered a split in a payment lot that's not part of any transaction. "
941  "This is unexpected! Skipping split %p.", split);
942  continue;
943  }
944 
945  // Check if this split has the opposite sign of the target value we want to offset
946  split_value = xaccSplitGetValue (split);
947  if (gnc_numeric_positive_p (target_value) == gnc_numeric_positive_p (split_value))
948  continue;
949 
950  // Ok we have found a split that potentially can offset the target value
951  // Let's see if it's better than what we have found already.
952  val_cmp = gnc_numeric_compare (gnc_numeric_abs (split_value),
953  gnc_numeric_abs (target_value));
954  if (val_cmp == 0)
955  new_flags += is_equal;
956  else if (val_cmp > 0)
957  new_flags += is_more;
958  else
959  new_flags += is_less;
960 
961  if (xaccTransGetTxnType (txn) != TXN_TYPE_LINK)
962  new_flags += is_pay_split;
963 
964  if ((new_flags >= best_flags) &&
965  (gnc_numeric_compare (gnc_numeric_abs (split_value),
966  gnc_numeric_abs (best_val)) > 0))
967  {
968  // The new split is a better match than what we found so far
969  best_split = split;
970  best_flags = new_flags;
971  best_val = split_value;
972  }
973  }
974 
975  return best_split;
976 }
977 
978 gboolean
979 gncOwnerReduceSplitTo (Split *split, gnc_numeric target_value)
980 {
981  gnc_numeric split_val = xaccSplitGetValue (split);
982  gnc_numeric rem_val;
983  Split *rem_split;
984  Transaction *txn;
985  GNCLot *lot;
986 
987  if (gnc_numeric_positive_p (split_val) != gnc_numeric_positive_p (target_value))
988  return FALSE; // Split and target value have to be of the same sign
989 
990  if (gnc_numeric_equal (split_val, target_value))
991  return FALSE; // Split already has the target value
992 
993  rem_val = gnc_numeric_sub (split_val, target_value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); // note: values are of opposite sign
994  rem_split = xaccMallocSplit (xaccSplitGetBook (split));
995  xaccSplitCopyOnto (split, rem_split);
996  xaccSplitSetAmount (rem_split, rem_val);
997  xaccSplitSetValue (rem_split, rem_val);
998 
999  txn = xaccSplitGetParent (split);
1000  xaccTransBeginEdit (txn);
1001  xaccSplitSetAmount (split, target_value);
1002  xaccSplitSetValue (split, target_value);
1003  xaccSplitSetParent (rem_split, txn);
1004  xaccTransCommitEdit (txn);
1005 
1006  lot = xaccSplitGetLot (split);
1007  gnc_lot_add_split (lot, rem_split);
1008 
1009  return TRUE;
1010 }
1011 
1012 void
1013 gncOwnerSetLotLinkMemo (Transaction *ll_txn)
1014 {
1015  gchar *memo_prefix = _("Offset between documents: ");
1016  gchar *new_memo;
1017  SplitList *lts_iter;
1018  SplitList *splits = NULL, *siter;
1019  GList *titles = NULL, *titer;
1020 
1021  if (!ll_txn)
1022  return;
1023 
1024  if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
1025  return;
1026 
1027  // Find all splits in the lot link transaction that are also in a document lot
1028  for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
1029  {
1030  Split *split = lts_iter->data;
1031  GNCLot *lot;
1032  GncInvoice *invoice;
1033  gchar *title;
1034 
1035  if (!split)
1036  continue;
1037 
1038  lot = xaccSplitGetLot (split);
1039  if (!lot)
1040  continue;
1041 
1042  invoice = gncInvoiceGetInvoiceFromLot (lot);
1043  if (!invoice)
1044  continue;
1045 
1046  title = g_strdup_printf ("%s %s", gncInvoiceGetTypeString (invoice), gncInvoiceGetID (invoice));
1047 
1048  titles = g_list_prepend (titles, title);
1049  splits = g_list_prepend (splits, split); // splits don't need to be sorted
1050  }
1051 
1052  if (!titles)
1053  return; // We didn't find document lots
1054 
1055  titles = g_list_sort (titles, (GCompareFunc)g_strcmp0);
1056 
1057  // Create the memo as we'd want it to be
1058  new_memo = g_strconcat (memo_prefix, titles->data, NULL);
1059  for (titer = titles->next; titer; titer = titer->next)
1060  {
1061  gchar *tmp_memo = g_strconcat (new_memo, " - ", titer->data, NULL);
1062  g_free (new_memo);
1063  new_memo = tmp_memo;
1064  }
1065  g_list_free_full (titles, g_free);
1066 
1067  // Update the memos of all the splits we found previously (if needed)
1068  for (siter = splits; siter; siter = siter->next)
1069  {
1070  if (g_strcmp0 (xaccSplitGetMemo (siter->data), new_memo) != 0)
1071  xaccSplitSetMemo (siter->data, new_memo);
1072  }
1073 
1074  g_list_free (splits);
1075  g_free (new_memo);
1076 }
1077 
1078 /* Find an existing lot link transaction in the given lot
1079  * Only use a lot link that already links at least two
1080  * documents (to avoid perpetuating the lot link proliferation
1081  * that happened in 2.6.0-2.6.3).
1082  */
1083 static Transaction *
1084 get_ll_transaction_from_lot (GNCLot *lot)
1085 {
1086  SplitList *ls_iter;
1087 
1088  /* This should really only be called on a document lot */
1089  if (!gncInvoiceGetInvoiceFromLot (lot))
1090  return NULL;
1091 
1092  /* The given lot is a valid document lot. Now iterate over all
1093  * other lot links in this lot to find one more document lot.
1094  */
1095  for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
1096  {
1097  Split *ls = ls_iter->data;
1098  Transaction *ll_txn = xaccSplitGetParent (ls);
1099  SplitList *ts_iter;
1100 
1101  if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
1102  continue;
1103 
1104  for (ts_iter = xaccTransGetSplitList (ll_txn); ts_iter; ts_iter = ts_iter->next)
1105  {
1106  Split *ts = ts_iter->data;
1107  GNCLot *tslot = xaccSplitGetLot (ts);
1108 
1109  if (!tslot)
1110  continue;
1111 
1112  if (tslot == lot)
1113  continue;
1114 
1115  if (gncInvoiceGetInvoiceFromLot (lot))
1116  return ll_txn; /* Got one more document lot - mission accomplished */
1117  }
1118  }
1119 
1120  /* The lot doesn't have an ll_txn with the requested criteria... */
1121  return NULL;
1122 }
1123 
1124 static void
1125 gncOwnerCreateLotLink (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
1126 {
1127  const gchar *action = _("Lot Link");
1128  Account *acct = gnc_lot_get_account (from_lot);
1129  const gchar *name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
1130  Transaction *ll_txn = NULL;
1131  gnc_numeric from_lot_bal, to_lot_bal;
1132  time64 from_time, to_time;
1133  time64 time_posted;
1134  Split *split;
1135 
1136  /* Sanity check */
1137  if (!gncInvoiceGetInvoiceFromLot (from_lot) ||
1138  !gncInvoiceGetInvoiceFromLot (to_lot))
1139  return;
1140 
1141  /* Determine transaction date based on lot splits */
1144  if (from_time >= to_time)
1145  time_posted = from_time;
1146  else
1147  time_posted = to_time;
1148 
1149  /* Figure out how much we can offset between the lots */
1150  from_lot_bal = gnc_lot_get_balance (from_lot);
1151  to_lot_bal = gnc_lot_get_balance (to_lot);
1152  if (gnc_numeric_compare (gnc_numeric_abs (from_lot_bal),
1153  gnc_numeric_abs (to_lot_bal)) > 0)
1154  from_lot_bal = gnc_numeric_neg (to_lot_bal);
1155  else
1156  to_lot_bal = gnc_numeric_neg (from_lot_bal);
1157 
1158  xaccAccountBeginEdit (acct);
1159 
1160  /* Look for a pre-existing lot link we can extend */
1161  ll_txn = get_ll_transaction_from_lot (from_lot);
1162 
1163  if (!ll_txn)
1164  ll_txn = get_ll_transaction_from_lot (to_lot);
1165 
1166  if (!ll_txn)
1167  {
1168  /* No pre-existing lot link. Create one. */
1169  ll_txn = xaccMallocTransaction (gnc_lot_get_book (from_lot));
1170  xaccTransBeginEdit (ll_txn);
1171  xaccTransSetDescription (ll_txn, name ? name : "(Unknown)");
1173  xaccTransSetDateEnteredSecs (ll_txn, gnc_time (NULL));
1174  xaccTransSetDatePostedSecs (ll_txn, time_posted);
1176  }
1177  else
1178  {
1179  time64 time = xaccTransRetDatePosted (ll_txn);
1180  xaccTransBeginEdit (ll_txn);
1181 
1182  /* Maybe we need to update the post date of the transaction ? */
1183  if (time_posted > time)
1184  xaccTransSetDatePostedSecs (ll_txn, time_posted);
1185  }
1186 
1187  /* Create a split for the from_lot */
1188  split = xaccMallocSplit (gnc_lot_get_book (from_lot));
1189  /* set Action using utility function */
1190  gnc_set_num_action (NULL, split, NULL, action);
1191  xaccAccountInsertSplit (acct, split);
1192  xaccTransAppendSplit (ll_txn, split);
1193  /* To offset the lot balance, the split must be of the opposite sign */
1194  xaccSplitSetBaseValue (split, gnc_numeric_neg (from_lot_bal), xaccAccountGetCommodity(acct));
1195  gnc_lot_add_split (from_lot, split);
1196 
1197  /* Create a split for the to_lot */
1198  split = xaccMallocSplit (gnc_lot_get_book (to_lot));
1199  /* set Action using utility function */
1200  gnc_set_num_action (NULL, split, NULL, action);
1201  xaccAccountInsertSplit (acct, split);
1202  xaccTransAppendSplit (ll_txn, split);
1203  /* To offset the lot balance, the split must be of the opposite sign */
1204  xaccSplitSetBaseValue (split, gnc_numeric_neg (to_lot_bal), xaccAccountGetCommodity(acct));
1205  gnc_lot_add_split (to_lot, split);
1206 
1207  xaccTransCommitEdit (ll_txn);
1208 
1209 
1210  /* Do some post-cleaning on the lots
1211  * The above actions may have created splits that are
1212  * in the same transaction and lot. These can be merged.
1213  */
1214  xaccScrubMergeLotSubSplits (to_lot, FALSE);
1215  xaccScrubMergeLotSubSplits (from_lot, FALSE);
1216  /* And finally set the same memo for all remaining splits
1217  * It's a convenience for the users to identify all documents
1218  * involved in the link.
1219  */
1220  gncOwnerSetLotLinkMemo (ll_txn);
1221  xaccAccountCommitEdit (acct);
1222 }
1223 
1224 static void gncOwnerOffsetLots (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
1225 {
1226  gnc_numeric target_offset;
1227  Split *split;
1228 
1229  /* from lot should not be a document lot because we're removing a split from there ! */
1230  if (gncInvoiceGetInvoiceFromLot (from_lot))
1231  {
1232  PWARN ("from_lot %p is a document lot. That is not allowed in gncOwnerOffsetLots", from_lot);
1233  return;
1234  }
1235 
1236  /* Get best matching split from from_lot to offset to_lot */
1237  target_offset = gnc_lot_get_balance (to_lot);
1238  if (gnc_numeric_zero_p (target_offset))
1239  return; // to_lot is already balanced, nothing more to do
1240 
1241  split = gncOwnerFindOffsettingSplit (from_lot, target_offset);
1242  if (!split)
1243  return; // No suitable offsetting split found, nothing more to do
1244 
1245  /* If the offsetting split is bigger than the amount needed to balance
1246  * to_lot, reduce the split so its reduced value closes to_lot exactly.
1247  * Note the negation in the reduction function. The split must be of
1248  * opposite sign of to_lot's balance in order to be able to close it.
1249  */
1251  gnc_numeric_abs (target_offset)) > 0)
1252  gncOwnerReduceSplitTo (split, gnc_numeric_neg (target_offset));
1253 
1254  /* Move the reduced split from from_lot to to_lot */
1255  gnc_lot_add_split (to_lot, split);
1256 
1257 }
1258 
1259 void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
1260 {
1261  GList *left_iter;
1262 
1263  /* General note: in the code below the term "payment" can
1264  * both mean a true payment or a document of
1265  * the opposite sign (invoice vs credit note) relative to
1266  * the lot being processed. In general this function will
1267  * perform a balancing action on a set of lots, so you
1268  * will also find frequent references to balancing instead. */
1269 
1270  /* Payments can only be applied when at least an owner
1271  * and a list of lots to use are given */
1272  if (!owner) return;
1273  if (!lots) return;
1274 
1275  for (left_iter = lots; left_iter; left_iter = left_iter->next)
1276  {
1277  GNCLot *left_lot = left_iter->data;
1278  gnc_numeric left_lot_bal;
1279  gboolean left_lot_has_doc;
1280  gboolean left_modified = FALSE;
1281  Account *acct;
1282  GList *right_iter;
1283 
1284  /* Only attempt to apply payments to open lots.
1285  * Note that due to the iterative nature of this function lots
1286  * in the list may become empty/closed before they are evaluated as
1287  * base lot, so we should check this for each lot. */
1288  if (!left_lot)
1289  continue;
1290  if (gnc_lot_count_splits (left_lot) == 0)
1291  {
1292  gnc_lot_destroy (left_lot);
1293  left_iter->data = NULL;
1294  continue;
1295  }
1296  if (gnc_lot_is_closed (left_lot))
1297  continue;
1298 
1299  acct = gnc_lot_get_account (left_lot);
1300  xaccAccountBeginEdit (acct);
1301 
1302  left_lot_bal = gnc_lot_get_balance (left_lot);
1303  left_lot_has_doc = (gncInvoiceGetInvoiceFromLot (left_lot) != NULL);
1304 
1305  /* Attempt to offset left_lot with any of the remaining lots. To do so
1306  * iterate over the remaining lots adding lot links or moving payments
1307  * around.
1308  */
1309  for (right_iter = left_iter->next; right_iter; right_iter = right_iter->next)
1310  {
1311  GNCLot *right_lot = right_iter->data;
1312  gnc_numeric right_lot_bal;
1313  gboolean right_lot_has_doc;
1314 
1315  /* Only attempt to use open lots to balance the base lot.
1316  * Note that due to the iterative nature of this function lots
1317  * in the list may become empty/closed before they are evaluated as
1318  * base lot, so we should check this for each lot. */
1319  if (!right_lot)
1320  continue;
1321  if (gnc_lot_count_splits (right_lot) == 0)
1322  {
1323  gnc_lot_destroy (right_lot);
1324  right_iter->data = NULL;
1325  continue;
1326  }
1327  if (gnc_lot_is_closed (right_lot))
1328  continue;
1329 
1330  /* Balancing transactions for invoice/payments can only happen
1331  * in the same account. */
1332  if (acct != gnc_lot_get_account (right_lot))
1333  continue;
1334 
1335 
1336  /* Only attempt to balance if the base lot and balancing lot are
1337  * of the opposite sign. (Otherwise we would increase the balance
1338  * of the lot - Duh */
1339  right_lot_bal = gnc_lot_get_balance (right_lot);
1340  if (gnc_numeric_positive_p (left_lot_bal) == gnc_numeric_positive_p (right_lot_bal))
1341  continue;
1342 
1343  /* Ok we found two lots than can (partly) offset each other.
1344  * Depending on the lot types, a different action is needed to accomplish this.
1345  * 1. Both lots are document lots (invoices/credit notes)
1346  * -> Create a lot linking transaction between the lots
1347  * 2. Both lots are payment lots (lots without a document attached)
1348  * -> Use part of the bigger lot to the close the smaller lot
1349  * 3. One document lot with one payment lot
1350  * -> Use (part of) the payment to offset (part of) the document lot,
1351  * Which one will be closed depends on which is the bigger one
1352  */
1353  right_lot_has_doc = (gncInvoiceGetInvoiceFromLot (right_lot) != NULL);
1354  if (left_lot_has_doc && right_lot_has_doc)
1355  gncOwnerCreateLotLink (left_lot, right_lot, owner);
1356  else if (!left_lot_has_doc && !right_lot_has_doc)
1357  {
1358  gint cmp = gnc_numeric_compare (gnc_numeric_abs (left_lot_bal),
1359  gnc_numeric_abs (right_lot_bal));
1360  if (cmp >= 0)
1361  gncOwnerOffsetLots (left_lot, right_lot, owner);
1362  else
1363  gncOwnerOffsetLots (right_lot, left_lot, owner);
1364  }
1365  else
1366  {
1367  GNCLot *doc_lot = left_lot_has_doc ? left_lot : right_lot;
1368  GNCLot *pay_lot = left_lot_has_doc ? right_lot : left_lot;
1369  // Ok, let's try to move a payment from pay_lot to doc_lot
1370  gncOwnerOffsetLots (pay_lot, doc_lot, owner);
1371  }
1372 
1373  /* If we get here, then right_lot was modified
1374  * If the lot has a document, send an event for send an event for it as well
1375  * so it gets potentially updated as paid */
1376 
1377  {
1378  GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(right_lot);
1379  if (this_invoice)
1380  qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
1381  }
1382  left_modified = TRUE;
1383  }
1384 
1385  /* If left_lot was modified and the lot has a document,
1386  * send an event for send an event for it as well
1387  * so it gets potentially updated as paid */
1388  if (left_modified)
1389  {
1390  GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(left_lot);
1391  if (this_invoice)
1392  qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
1393  }
1394  xaccAccountCommitEdit (acct);
1395 
1396  }
1397 }
1398 
1399 /*
1400  * Create a payment of "amount" for the owner and match it with
1401  * the set of lots passed in.
1402  * If
1403  * - no lots were given
1404  * - auto_pay is true
1405  * then all open lots for the owner are considered.
1406  */
1407 void
1408 gncOwnerApplyPaymentSecs (const GncOwner *owner, Transaction **preset_txn,
1409  GList *lots, Account *posted_acc, Account *xfer_acc,
1410  gnc_numeric amount, gnc_numeric exch, time64 date,
1411  const char *memo, const char *num, gboolean auto_pay)
1412 {
1413  GNCLot *payment_lot = NULL;
1414  GList *selected_lots = NULL;
1415 
1416  /* Verify our arguments */
1417  if (!owner || !posted_acc
1418  || (!xfer_acc && !gnc_numeric_zero_p (amount)) ) return;
1419  g_return_if_fail (owner->owner.undefined);
1420 
1421  /* If there's a real amount to transfer create a lot for this payment */
1422  if (!gnc_numeric_zero_p (amount))
1423  payment_lot = gncOwnerCreatePaymentLotSecs (owner, preset_txn,
1424  posted_acc, xfer_acc,
1425  amount, exch, date, memo,
1426  num);
1427 
1428  if (lots)
1429  selected_lots = lots;
1430  else if (auto_pay)
1431  selected_lots = xaccAccountFindOpenLots (posted_acc, gncOwnerLotMatchOwnerFunc,
1432  (gpointer)owner, NULL);
1433 
1434  /* And link the selected lots and the payment lot together as well as possible.
1435  * If the payment was bigger than the selected documents/overpayments, only
1436  * part of the payment will be used. Similarly if more documents were selected
1437  * than the payment value set, not all documents will be marked as paid. */
1438  if (payment_lot)
1439  selected_lots = g_list_prepend (selected_lots, payment_lot);
1440  gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots);
1441  g_list_free (selected_lots);
1442 }
1443 
1444 GList *
1446 {
1447  g_return_val_if_fail (owner, NULL);
1448 
1449  switch (gncOwnerGetType (owner))
1450  {
1451  case GNC_OWNER_CUSTOMER:
1452  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_RECEIVABLE));
1453  case GNC_OWNER_VENDOR:
1454  case GNC_OWNER_EMPLOYEE:
1455  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_PAYABLE));
1456  break;
1457  default:
1458  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_NONE));
1459  }
1460 }
1461 
1462 GList *
1464 {
1465  g_return_val_if_fail (owner, NULL);
1466  g_return_val_if_fail (gncOwnerGetCurrency(owner), NULL);
1467 
1468  return (g_list_prepend (NULL, gncOwnerGetCurrency(owner)));
1469 }
1470 
1471 /*********************************************************************/
1472 /* Owner balance calculation routines */
1473 
1474 /*
1475  * Given an owner, extract the open balance from the owner and then
1476  * convert it to the desired currency.
1477  */
1478 gnc_numeric
1480  const gnc_commodity *report_currency)
1481 {
1482  gnc_numeric balance = gnc_numeric_zero ();
1483  QofBook *book;
1484  gnc_commodity *owner_currency;
1485  GNCPriceDB *pdb;
1486  const gnc_numeric *cached_balance = NULL;
1487 
1488  g_return_val_if_fail (owner, gnc_numeric_zero ());
1489 
1490  book = qof_instance_get_book (qofOwnerGetOwner (owner));
1491  owner_currency = gncOwnerGetCurrency (owner);
1492 
1493  cached_balance = gncOwnerGetCachedBalance (owner);
1494  if (cached_balance)
1495  balance = *cached_balance;
1496  else
1497  {
1498  /* No valid cache value found for balance. Let's recalculate */
1499  GList *acct_list = gnc_account_get_descendants (gnc_book_get_root_account (book));
1500  GList *acct_types = gncOwnerGetAccountTypesList (owner);
1501  GList *acct_node;
1502 
1503  /* For each account */
1504  for (acct_node = acct_list; acct_node; acct_node = acct_node->next)
1505  {
1506  Account *account = acct_node->data;
1507  GList *lot_list = NULL, *lot_node;
1508 
1509  /* Check if this account can have lots for the owner, otherwise skip to next */
1510  if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account))
1511  == -1)
1512  continue;
1513 
1514 
1515  if (!gnc_commodity_equal (owner_currency, xaccAccountGetCommodity (account)))
1516  continue;
1517 
1518  /* Get a list of open lots for this owner and account */
1520  (gpointer)owner, NULL);
1521  /* For each lot */
1522  for (lot_node = lot_list; lot_node; lot_node = lot_node->next)
1523  {
1524  GNCLot *lot = lot_node->data;
1525  gnc_numeric lot_balance = gnc_lot_get_balance (lot);
1526  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot(lot);
1527  if (invoice)
1528  balance = gnc_numeric_add (balance, lot_balance,
1530  }
1531  g_list_free (lot_list);
1532  }
1533  g_list_free (acct_list);
1534  g_list_free (acct_types);
1535 
1536  gncOwnerSetCachedBalance (owner, &balance);
1537  }
1538 
1539  pdb = gnc_pricedb_get_db (book);
1540 
1541  if (report_currency)
1543  pdb, balance, owner_currency, report_currency);
1544 
1545  return balance;
1546 }
1547 
1548 
1549 /* XXX: Yea, this is broken, but it should work fine for Queries.
1550  * We're single-threaded, right?
1551  */
1552 static GncOwner *
1553 owner_from_lot (GNCLot *lot)
1554 {
1555  static GncOwner owner;
1556 
1557  if (!lot) return NULL;
1558  if (gncOwnerGetOwnerFromLot (lot, &owner))
1559  return &owner;
1560 
1561  return NULL;
1562 }
1563 
1564 static void
1565 reg_lot (void)
1566 {
1567  static QofParam params[] =
1568  {
1569  { OWNER_FROM_LOT, _GNC_MOD_NAME, (QofAccessFunc)owner_from_lot, NULL },
1570  { NULL },
1571  };
1572 
1573  qof_class_register (GNC_ID_LOT, NULL, params);
1574 }
1575 
1576 gboolean gncOwnerGetOwnerFromTypeGuid (QofBook *book, GncOwner *owner, QofIdType type, GncGUID *guid)
1577 {
1578  if (!book || !owner || !type || !guid) return FALSE;
1579 
1580  if (0 == g_strcmp0(type, GNC_ID_CUSTOMER))
1581  {
1582  GncCustomer *customer = gncCustomerLookup(book, guid);
1583  gncOwnerInitCustomer(owner, customer);
1584  return (NULL != customer);
1585  }
1586  else if (0 == g_strcmp0(type, GNC_ID_JOB))
1587  {
1588  GncJob *job = gncJobLookup(book, guid);
1589  gncOwnerInitJob(owner, job);
1590  return (NULL != job);
1591  }
1592  else if (0 == g_strcmp0(type, GNC_ID_VENDOR))
1593  {
1594  GncVendor *vendor = gncVendorLookup(book, guid);
1595  gncOwnerInitVendor(owner, vendor);
1596  return (NULL != vendor);
1597  }
1598  else if (0 == g_strcmp0(type, GNC_ID_EMPLOYEE))
1599  {
1600  GncEmployee *employee = gncEmployeeLookup(book, guid);
1601  gncOwnerInitEmployee(owner, employee);
1602  return (NULL != employee);
1603  }
1604  return 0;
1605 }
1606 
1607 gboolean gncOwnerRegister (void)
1608 {
1609  static QofParam params[] =
1610  {
1611  { OWNER_TYPE, QOF_TYPE_INT64, (QofAccessFunc)gncOwnerGetType, NULL },
1612  { OWNER_CUSTOMER, GNC_ID_CUSTOMER, (QofAccessFunc)gncOwnerGetCustomer, NULL },
1613  { OWNER_JOB, GNC_ID_JOB, (QofAccessFunc)gncOwnerGetJob, NULL },
1614  { OWNER_VENDOR, GNC_ID_VENDOR, (QofAccessFunc)gncOwnerGetVendor, NULL },
1615  { OWNER_EMPLOYEE, GNC_ID_EMPLOYEE, (QofAccessFunc)gncOwnerGetEmployee, NULL },
1616  { OWNER_PARENT, GNC_ID_OWNER, (QofAccessFunc)gncOwnerGetEndOwner, NULL },
1617  { OWNER_PARENTG, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetEndGUID, NULL },
1618  { OWNER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncOwnerGetName, NULL },
1619  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetGUID, NULL },
1620  { NULL },
1621  };
1622 
1623  qof_class_register (GNC_ID_OWNER, (QofSortFunc)gncOwnerCompare, params);
1624  reg_lot ();
1625 
1626  return TRUE;
1627 }
1628 
1629 const gnc_numeric*
1630 gncOwnerGetCachedBalance (const GncOwner *owner)
1631 {
1632  if (!owner) return NULL;
1633 
1634  if (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER)
1635  return gncCustomerGetCachedBalance (gncOwnerGetCustomer (owner));
1636  else if (gncOwnerGetType (owner) == GNC_OWNER_VENDOR)
1637  return gncVendorGetCachedBalance (gncOwnerGetVendor (owner));
1638  else if (gncOwnerGetType (owner) == GNC_OWNER_EMPLOYEE)
1639  return gncEmployeeGetCachedBalance (gncOwnerGetEmployee (owner));
1640 
1641  return NULL;
1642 }
1643 
1644 void gncOwnerSetCachedBalance (const GncOwner *owner, const gnc_numeric *new_bal)
1645 {
1646  if (!owner) return;
1647 
1648  if (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER)
1649  gncCustomerSetCachedBalance (gncOwnerGetCustomer (owner), new_bal);
1650  else if (gncOwnerGetType (owner) == GNC_OWNER_VENDOR)
1651  gncVendorSetCachedBalance (gncOwnerGetVendor (owner), new_bal);
1652  else if (gncOwnerGetType (owner) == GNC_OWNER_EMPLOYEE)
1653  gncEmployeeSetCachedBalance (gncOwnerGetEmployee (owner), new_bal);
1654 }
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:1463
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:362
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:510
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Depending on the base_currency, set either the value or the amount of this split or both: If the base...
Definition: Split.c:1319
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
char xaccTransGetTxnType(const Transaction *trans)
Returns the Transaction Type.
Definition: Transaction.c:2548
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
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:1445
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3236
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1470
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:639
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:622
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition: gncOwner.c:405
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
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.
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:966
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:701
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:2658
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1425
void gncOwnerAutoApplyPaymentsWithLots(const GncOwner *owner, GList *lots)
Given a list of lots, try to balance as many of them as possible by creating balancing transactions b...
Definition: gncOwner.c:1259
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:713
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#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:2396
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type.
Definition: Transaction.c:2109
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:124
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:1408
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:1728
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:979
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:1479
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
The gnc_lot_get_split_list() routine returns a GList of all the splits in this lot.
Definition: gnc-lot.c:436
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2484
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:127
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:792
#define TXN_TYPE_PAYMENT
Transaction is a payment.
Definition: Transaction.h:126
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:3017
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
Definition: gncInvoice.c:1301
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:2017
Split * xaccTransGetFirstAPARAcctSplit(const Transaction *trans, gboolean strict)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
Definition: Transaction.c:2372
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:1430
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3405
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:1366
#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:913
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:1013
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:3994
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2052
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:1471
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:530
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn&#39;t be...
Definition: Split.c:1881