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