GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 [email protected] *
20  * *
21 \********************************************************************/
22 
23 /*
24  * Copyright (C) 2001, 2002 Derek Atkins
25  * Copyright (C) 2003 Linas Vepstas <[email protected]>
26  * Copyright (c) 2005 Neil Williams <[email protected]>
27  * Copyright (c) 2006 David Hampton <[email protected]>
28  * Copyright (c) 2011 Geert Janssens <[email protected]>
29  * Author: Derek Atkins <[email protected]>
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 
209 {
210  return gncOwnerTypeToQofIdType(owner->type);
211 }
212 
214 {
215  QofIdTypeConst type = NULL;
216  switch (t)
217  {
218  case GNC_OWNER_NONE :
219  {
220  type = NULL;
221  break;
222  }
223  case GNC_OWNER_UNDEFINED :
224  {
225  type = NULL;
226  break;
227  }
228  case GNC_OWNER_CUSTOMER :
229  {
230  type = GNC_ID_CUSTOMER;
231  break;
232  }
233  case GNC_OWNER_JOB :
234  {
235  type = GNC_ID_JOB;
236  break;
237  }
238  case GNC_OWNER_VENDOR :
239  {
240  type = GNC_ID_VENDOR;
241  break;
242  }
243  case GNC_OWNER_EMPLOYEE :
244  {
245  type = GNC_ID_EMPLOYEE;
246  break;
247  }
248  }
249  return type;
250 }
251 
254 {
255  QofInstance *ent;
256 
257  if (!owner)
258  {
259  return NULL;
260  }
261  ent = NULL;
262  switch (owner->type)
263  {
264  case GNC_OWNER_NONE :
265  {
266  break;
267  }
268  case GNC_OWNER_UNDEFINED :
269  {
270  break;
271  }
272  case GNC_OWNER_CUSTOMER :
273  {
274  ent = QOF_INSTANCE(owner->owner.customer);
275  break;
276  }
277  case GNC_OWNER_JOB :
278  {
279  ent = QOF_INSTANCE(owner->owner.job);
280  break;
281  }
282  case GNC_OWNER_VENDOR :
283  {
284  ent = QOF_INSTANCE(owner->owner.vendor);
285  break;
286  }
287  case GNC_OWNER_EMPLOYEE :
288  {
289  ent = QOF_INSTANCE(owner->owner.employee);
290  break;
291  }
292  }
293  return ent;
294 }
295 
296 void
298 {
299  if (!owner || !ent)
300  {
301  return;
302  }
303  if (0 == g_strcmp0(ent->e_type, GNC_ID_CUSTOMER))
304  {
305  owner->type = GNC_OWNER_CUSTOMER;
306  gncOwnerInitCustomer(owner, (GncCustomer*)ent);
307  }
308  else if (0 == g_strcmp0(ent->e_type, GNC_ID_JOB))
309  {
310  owner->type = GNC_OWNER_JOB;
311  gncOwnerInitJob(owner, (GncJob*)ent);
312  }
313  else if (0 == g_strcmp0(ent->e_type, GNC_ID_VENDOR))
314  {
315  owner->type = GNC_OWNER_VENDOR;
316  gncOwnerInitVendor(owner, (GncVendor*)ent);
317  }
318  else if (0 == g_strcmp0(ent->e_type, GNC_ID_EMPLOYEE))
319  {
320  owner->type = GNC_OWNER_EMPLOYEE;
321  gncOwnerInitEmployee(owner, (GncEmployee*)ent);
322  }
323  else
324  {
325  owner->type = GNC_OWNER_NONE;
326  owner->owner.undefined = NULL;
327  }
328 }
329 
330 gboolean GNC_IS_OWNER (QofInstance *ent)
331 {
332  if (!ent)
333  return FALSE;
334 
335  return (GNC_IS_VENDOR(ent) ||
336  GNC_IS_CUSTOMER(ent) ||
337  GNC_IS_EMPLOYEE(ent) ||
338  GNC_IS_JOB(ent));
339 }
340 gpointer gncOwnerGetUndefined (const GncOwner *owner)
341 {
342  if (!owner) return NULL;
343  if (owner->type != GNC_OWNER_UNDEFINED) return NULL;
344  return owner->owner.undefined;
345 }
346 
348 {
349  if (!owner) return NULL;
350  if (owner->type != GNC_OWNER_CUSTOMER) return NULL;
351  return owner->owner.customer;
352 }
353 
355 {
356  if (!owner) return NULL;
357  if (owner->type != GNC_OWNER_JOB) return NULL;
358  return owner->owner.job;
359 }
360 
362 {
363  if (!owner) return NULL;
364  if (owner->type != GNC_OWNER_VENDOR) return NULL;
365  return owner->owner.vendor;
366 }
367 
369 {
370  if (!owner) return NULL;
371  if (owner->type != GNC_OWNER_EMPLOYEE) return NULL;
372  return owner->owner.employee;
373 }
374 
375 void gncOwnerCopy (const GncOwner *src, GncOwner *dest)
376 {
377  if (!src || !dest) return;
378  if (src == dest) return;
379  memcpy (dest, src, sizeof (*dest));
380 }
381 
382 gboolean gncOwnerEqual (const GncOwner *a, const GncOwner *b)
383 {
384  if (!a || !b) return FALSE;
385  if (gncOwnerGetType (a) != gncOwnerGetType (b)) return FALSE;
386  return (a->owner.undefined == b->owner.undefined);
387 }
388 
389 int gncOwnerGCompareFunc (const GncOwner *a, const GncOwner *b)
390 {
391  if (gncOwnerEqual (a, b))
392  return 0;
393  else
394  return 1;
395 }
396 
397 const char * gncOwnerGetID (const GncOwner *owner)
398 {
399  if (!owner) return NULL;
400  switch (owner->type)
401  {
402  case GNC_OWNER_NONE:
403  case GNC_OWNER_UNDEFINED:
404  default:
405  return NULL;
406  case GNC_OWNER_CUSTOMER:
407  return gncCustomerGetID (owner->owner.customer);
408  case GNC_OWNER_JOB:
409  return gncJobGetID (owner->owner.job);
410  case GNC_OWNER_VENDOR:
411  return gncVendorGetID (owner->owner.vendor);
412  case GNC_OWNER_EMPLOYEE:
413  return gncEmployeeGetID (owner->owner.employee);
414  }
415 }
416 
417 const char * gncOwnerGetName (const GncOwner *owner)
418 {
419  if (!owner) return NULL;
420  switch (owner->type)
421  {
422  case GNC_OWNER_NONE:
423  case GNC_OWNER_UNDEFINED:
424  default:
425  return NULL;
426  case GNC_OWNER_CUSTOMER:
427  return gncCustomerGetName (owner->owner.customer);
428  case GNC_OWNER_JOB:
429  return gncJobGetName (owner->owner.job);
430  case GNC_OWNER_VENDOR:
431  return gncVendorGetName (owner->owner.vendor);
432  case GNC_OWNER_EMPLOYEE:
433  return gncEmployeeGetName (owner->owner.employee);
434  }
435 }
436 
437 GncAddress * gncOwnerGetAddr (const GncOwner *owner)
438 {
439  if (!owner) return NULL;
440  switch (owner->type)
441  {
442  case GNC_OWNER_NONE:
443  case GNC_OWNER_UNDEFINED:
444  case GNC_OWNER_JOB:
445  default:
446  return NULL;
447  case GNC_OWNER_CUSTOMER:
448  return gncCustomerGetAddr (owner->owner.customer);
449  case GNC_OWNER_VENDOR:
450  return gncVendorGetAddr (owner->owner.vendor);
451  case GNC_OWNER_EMPLOYEE:
452  return gncEmployeeGetAddr (owner->owner.employee);
453  }
454 }
455 
456 gnc_commodity * gncOwnerGetCurrency (const GncOwner *owner)
457 {
458  if (!owner) return NULL;
459  switch (owner->type)
460  {
461  case GNC_OWNER_NONE:
462  case GNC_OWNER_UNDEFINED:
463  default:
464  return NULL;
465  case GNC_OWNER_CUSTOMER:
466  return gncCustomerGetCurrency (owner->owner.customer);
467  case GNC_OWNER_VENDOR:
468  return gncVendorGetCurrency (owner->owner.vendor);
469  case GNC_OWNER_EMPLOYEE:
470  return gncEmployeeGetCurrency (owner->owner.employee);
471  case GNC_OWNER_JOB:
472  return gncOwnerGetCurrency (gncJobGetOwner (owner->owner.job));
473  }
474 }
475 
476 gboolean gncOwnerGetActive (const GncOwner *owner)
477 {
478  if (!owner) return FALSE;
479  switch (owner->type)
480  {
481  case GNC_OWNER_NONE:
482  case GNC_OWNER_UNDEFINED:
483  default:
484  return FALSE;
485  case GNC_OWNER_CUSTOMER:
486  return gncCustomerGetActive (owner->owner.customer);
487  case GNC_OWNER_VENDOR:
488  return gncVendorGetActive (owner->owner.vendor);
489  case GNC_OWNER_EMPLOYEE:
490  return gncEmployeeGetActive (owner->owner.employee);
491  case GNC_OWNER_JOB:
492  return gncJobGetActive (owner->owner.job);
493  }
494 }
495 
496 const GncGUID * gncOwnerGetGUID (const GncOwner *owner)
497 {
498  if (!owner) return NULL;
499 
500  switch (owner->type)
501  {
502  case GNC_OWNER_NONE:
503  case GNC_OWNER_UNDEFINED:
504  default:
505  return NULL;
506  case GNC_OWNER_CUSTOMER:
507  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.customer));
508  case GNC_OWNER_JOB:
509  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.job));
510  case GNC_OWNER_VENDOR:
511  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.vendor));
512  case GNC_OWNER_EMPLOYEE:
513  return qof_instance_get_guid (QOF_INSTANCE(owner->owner.employee));
514  }
515 }
516 
517 void
518 gncOwnerSetActive (const GncOwner *owner, gboolean active)
519 {
520  if (!owner) return;
521  switch (owner->type)
522  {
523  case GNC_OWNER_CUSTOMER:
524  gncCustomerSetActive (owner->owner.customer, active);
525  break;
526  case GNC_OWNER_VENDOR:
527  gncVendorSetActive (owner->owner.vendor, active);
528  break;
529  case GNC_OWNER_EMPLOYEE:
530  gncEmployeeSetActive (owner->owner.employee, active);
531  break;
532  case GNC_OWNER_JOB:
533  gncJobSetActive (owner->owner.job, active);
534  break;
535  case GNC_OWNER_NONE:
536  case GNC_OWNER_UNDEFINED:
537  default:
538  break;
539  }
540 }
541 
542 GncGUID gncOwnerRetGUID (GncOwner *owner)
543 {
544  const GncGUID *guid = gncOwnerGetGUID (owner);
545  if (guid)
546  return *guid;
547  return *guid_null ();
548 }
549 
550 const GncOwner * gncOwnerGetEndOwner (const GncOwner *owner)
551 {
552  if (!owner) return NULL;
553  switch (owner->type)
554  {
555  case GNC_OWNER_NONE:
556  case GNC_OWNER_UNDEFINED:
557  default:
558  return NULL;
559  case GNC_OWNER_CUSTOMER:
560  case GNC_OWNER_VENDOR:
561  case GNC_OWNER_EMPLOYEE:
562  return owner;
563  case GNC_OWNER_JOB:
564  return gncJobGetOwner (owner->owner.job);
565  }
566 }
567 
568 int gncOwnerCompare (const GncOwner *a, const GncOwner *b)
569 {
570  if (!a && !b) return 0;
571  if (!a && b) return 1;
572  if (a && !b) return -1;
573 
574  if (a->type != b->type)
575  return (a->type - b->type);
576 
577  switch (a->type)
578  {
579  case GNC_OWNER_NONE:
580  case GNC_OWNER_UNDEFINED:
581  default:
582  return 0;
583  case GNC_OWNER_CUSTOMER:
584  return gncCustomerCompare (a->owner.customer, b->owner.customer);
585  case GNC_OWNER_VENDOR:
586  return gncVendorCompare (a->owner.vendor, b->owner.vendor);
587  case GNC_OWNER_EMPLOYEE:
588  return gncEmployeeCompare (a->owner.employee, b->owner.employee);
589  case GNC_OWNER_JOB:
590  return gncJobCompare (a->owner.job, b->owner.job);
591  }
592 }
593 
594 const GncGUID * gncOwnerGetEndGUID (const GncOwner *owner)
595 {
596  if (!owner) return NULL;
597  return gncOwnerGetGUID (gncOwnerGetEndOwner (owner));
598 }
599 
600 void gncOwnerAttachToLot (const GncOwner *owner, GNCLot *lot)
601 {
602  if (!owner || !lot)
603  return;
604 
605  gnc_lot_begin_edit (lot);
606 
607  qof_instance_set (QOF_INSTANCE (lot),
608  GNC_OWNER_TYPE, (gint64)gncOwnerGetType (owner),
609  GNC_OWNER_GUID, gncOwnerGetGUID (owner),
610  NULL);
611  gnc_lot_commit_edit (lot);
612 }
613 
614 gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner)
615 {
616  GncGUID *guid = NULL;
617  QofBook *book;
618  GncOwnerType type = GNC_OWNER_NONE;
619  guint64 type64 = 0;
620 
621  if (!lot || !owner) return FALSE;
622 
623  book = gnc_lot_get_book (lot);
624  qof_instance_get (QOF_INSTANCE (lot),
625  GNC_OWNER_TYPE, &type64,
626  GNC_OWNER_GUID, &guid,
627  NULL);
628  type = (GncOwnerType) type64;
629  switch (type)
630  {
631  case GNC_OWNER_CUSTOMER:
632  gncOwnerInitCustomer (owner, gncCustomerLookup (book, guid));
633  break;
634  case GNC_OWNER_VENDOR:
635  gncOwnerInitVendor (owner, gncVendorLookup (book, guid));
636  break;
637  case GNC_OWNER_EMPLOYEE:
638  gncOwnerInitEmployee (owner, gncEmployeeLookup (book, guid));
639  break;
640  case GNC_OWNER_JOB:
641  gncOwnerInitJob (owner, gncJobLookup (book, guid));
642  break;
643  default:
644  return FALSE;
645  }
646 
647  return (owner->owner.undefined != NULL);
648 }
649 
650 gboolean gncOwnerIsValid (const GncOwner *owner)
651 {
652  if (!owner) return FALSE;
653  return (owner->owner.undefined != NULL);
654 }
655 
656 gboolean
657 gncOwnerLotMatchOwnerFunc (GNCLot *lot, gpointer user_data)
658 {
659  const GncOwner *req_owner = user_data;
660  GncOwner lot_owner;
661  const GncOwner *end_owner;
662  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
663 
664  /* Determine the owner associated to the lot */
665  if (invoice)
666  /* Invoice lots */
667  end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
668  else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
669  /* Pre-payment lots */
670  end_owner = gncOwnerGetEndOwner (&lot_owner);
671  else
672  return FALSE;
673 
674  /* Is this a lot for the requested owner ? */
675  return gncOwnerEqual (end_owner, req_owner);
676 }
677 
678 gint
680 {
681  GncInvoice *ia, *ib;
682  Timespec da, db;
683 
684  ia = gncInvoiceGetInvoiceFromLot (lotA);
685  ib = gncInvoiceGetInvoiceFromLot (lotB);
686 
687  if (ia)
688  da = gncInvoiceGetDateDue (ia);
689  else
691 
692  if (ib)
693  db = gncInvoiceGetDateDue (ib);
694  else
696 
697  return timespec_cmp (&da, &db);
698 }
699 
700 GNCLot *
702  Account *posted_acc, Account *xfer_acc,
703  gnc_numeric amount, gnc_numeric exch, Timespec date,
704  const char *memo, const char *num)
705 {
706  QofBook *book;
707  Split *split;
708  const char *name;
709  gnc_commodity *commodity;
710  Split *xfer_split = NULL;
711  GNCLot *payment_lot;
712 
713  /* Verify our arguments */
714  if (!owner || !posted_acc || !xfer_acc) return NULL;
715  g_return_val_if_fail (owner->owner.undefined != NULL, NULL);
716 
717  /* Compute the ancillary data */
718  book = gnc_account_get_book (posted_acc);
719  name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
720  commodity = gncOwnerGetCurrency (owner);
721 // reverse = use_reversed_payment_amounts(owner);
722 
723  if (txn)
724  {
725  /* Pre-existing transaction was specified. We completely clear it,
726  * except for the split in the transfer account, unless the
727  * transaction can't be reused (wrong currency, wrong transfer account).
728  * In that case, the transaction is simply removed and an new
729  * one created. */
730 
731  xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
732 
733  if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
734  {
735  g_message("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
736  xfer_split = NULL;
737  }
738 
739  if (!xfer_split)
740  {
741  g_message("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");
742 
743  xaccTransBeginEdit (txn);
744  xaccTransDestroy (txn);
745  xaccTransCommitEdit (txn);
746 
747  txn = NULL;
748  }
749  else
750  {
751  int i = 0;
752  xaccTransBeginEdit (txn);
753  while (i < xaccTransCountSplits(txn))
754  {
755  Split *split = xaccTransGetSplit (txn, i);
756  if (split == xfer_split)
757  {
758  gnc_set_num_action (NULL, split, num, _("Payment"));
759  ++i;
760  }
761  else
762  {
763  xaccSplitDestroy(split);
764  }
765  }
766  /* Note: don't commit transaction now - that would insert an imbalance split.*/
767  }
768  }
769 
770  /* Create the transaction if we don't have one yet */
771  if (!txn)
772  {
773  txn = xaccMallocTransaction (book);
774  xaccTransBeginEdit (txn);
775  }
776 
777  /* Insert a split for the transfer account if we don't have one yet */
778  if (!xfer_split)
779  {
780 
781  /* Set up the transaction */
782  xaccTransSetDescription (txn, name ? name : "");
783  /* set per book option */
784  xaccTransSetCurrency (txn, commodity);
786  xaccTransSetDatePostedTS (txn, &date);
787 
788 
789  /* The split for the transfer account */
790  split = xaccMallocSplit (book);
791  xaccSplitSetMemo (split, memo);
792  /* set per book option */
793  gnc_set_num_action (NULL, split, num, _("Payment"));
794  xaccAccountBeginEdit (xfer_acc);
795  xaccAccountInsertSplit (xfer_acc, split);
796  xaccAccountCommitEdit (xfer_acc);
797  xaccTransAppendSplit (txn, split);
798 
799  if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
800  {
801  xaccSplitSetBaseValue (split, amount, commodity);
802  }
803  else
804  {
805  /* Need to value the payment in terms of the owner commodity */
806  gnc_numeric payment_value = gnc_numeric_mul(amount,
808 
809  xaccSplitSetAmount(split, amount);
810  xaccSplitSetValue(split, payment_value);
811  }
812  }
813 
814  /* Add a split in the post account */
815  split = xaccMallocSplit (book);
816  xaccSplitSetMemo (split, memo);
817  /* set per book option */
818  gnc_set_num_action (NULL, split, num, _("Payment"));
819  xaccAccountBeginEdit (posted_acc);
820  xaccAccountInsertSplit (posted_acc, split);
821  xaccAccountCommitEdit (posted_acc);
822  xaccTransAppendSplit (txn, split);
823  xaccSplitSetBaseValue (split, gnc_numeric_neg (amount), commodity);
824 
825  /* Create a new lot for the payment */
826  payment_lot = gnc_lot_new (book);
827  gncOwnerAttachToLot (owner, payment_lot);
828  gnc_lot_add_split (payment_lot, split);
829 
830  /* Mark the transaction as a payment */
831  gnc_set_num_action (txn, NULL, num, _("Payment"));
833 
834  /* Commit this new transaction */
835  xaccTransCommitEdit (txn);
836 
837  return payment_lot;
838 }
839 
840 typedef enum
841 {
842  is_equal = 8,
843  is_more = 4,
844  is_less = 2,
845  is_pay_split = 1
846 } split_flags;
847 
849 {
850  SplitList *ls_iter = NULL;
851  Split *best_split = NULL;
852  gnc_numeric best_val = { 0, 1};
853  gint best_flags = 0;
854 
855  if (!lot)
856  return NULL;
857 
858  for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
859  {
860  Split *split = ls_iter->data;
861  Transaction *txn;
862  gnc_numeric split_value;
863  gint new_flags = 0;
864  gint val_cmp = 0;
865 
866  if (!split)
867  continue;
868 
869 
870  txn = xaccSplitGetParent (split);
871  if (!txn)
872  {
873  // Ooops - the split doesn't belong to any transaction !
874  // This is not expected so issue a warning and continue with next split
875  PWARN("Encountered a split in a payment lot that's not part of any transaction. "
876  "This is unexpected! Skipping split %p.", split);
877  continue;
878  }
879 
880  // Check if this split has the opposite sign of the target value we want to offset
881  split_value = xaccSplitGetValue (split);
882  if (gnc_numeric_positive_p (target_value) == gnc_numeric_positive_p (split_value))
883  continue;
884 
885  // Ok we have found a split that potentially can offset the target value
886  // Let's see if it's better than what we have found already.
887  val_cmp = gnc_numeric_compare (gnc_numeric_abs (split_value),
888  gnc_numeric_abs (target_value));
889  if (val_cmp == 0)
890  new_flags += is_equal;
891  else if (val_cmp > 0)
892  new_flags += is_more;
893  else
894  new_flags += is_less;
895 
896  if (xaccTransGetTxnType (txn) != TXN_TYPE_LINK)
897  new_flags += is_pay_split;
898 
899  if ((new_flags >= best_flags) &&
900  (gnc_numeric_compare (gnc_numeric_abs (split_value),
901  gnc_numeric_abs (best_val)) > 0))
902  {
903  // The new split is a better match than what we found so far
904  best_split = split;
905  best_flags = new_flags;
906  best_val = split_value;
907  }
908  }
909 
910  return best_split;
911 }
912 
913 gboolean
915 {
916  gnc_numeric split_val = xaccSplitGetValue (split);
917  gnc_numeric rem_val;
918  Split *rem_split;
919  Transaction *txn;
920  GNCLot *lot;
921 
922  if (gnc_numeric_positive_p (split_val) != gnc_numeric_positive_p (target_value))
923  return FALSE; // Split and target value have to be of the same sign
924 
925  if (gnc_numeric_equal (split_val, target_value))
926  return FALSE; // Split already has the target value
927 
928  rem_val = gnc_numeric_sub (split_val, target_value, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD); // note: values are of opposite sign
929  rem_split = xaccMallocSplit (xaccSplitGetBook (split));
930  xaccSplitCopyOnto (split, rem_split);
931  xaccSplitSetValue (rem_split, rem_val);
932 
933  txn = xaccSplitGetParent (split);
934  xaccTransBeginEdit (txn);
935  xaccSplitSetValue (split, target_value);
936  xaccSplitSetParent (rem_split, txn);
937  xaccTransCommitEdit (txn);
938 
939  lot = xaccSplitGetLot (split);
940  gnc_lot_add_split (lot, rem_split);
941 
942  return TRUE;
943 }
944 
945 void
947 {
948  gchar *memo_prefix = _("Offset between documents: ");
949  gchar *new_memo;
950  SplitList *lts_iter;
951  SplitList *splits = NULL, *siter;
952  GList *titles = NULL, *titer;
953 
954  if (!ll_txn)
955  return;
956 
957  if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
958  return;
959 
960  // Find all splits in the lot link transaction that are also in a document lot
961  for (lts_iter = xaccTransGetSplitList (ll_txn); lts_iter; lts_iter = lts_iter->next)
962  {
963  Split *split = lts_iter->data;
964  GNCLot *lot;
965  GncInvoice *invoice;
966  gchar *title;
967 
968  if (!split)
969  continue;
970 
971  lot = xaccSplitGetLot (split);
972  if (!lot)
973  continue;
974 
975  invoice = gncInvoiceGetInvoiceFromLot (lot);
976  if (!invoice)
977  continue;
978 
979  title = g_strdup_printf ("%s %s", gncInvoiceGetTypeString (invoice), gncInvoiceGetID (invoice));
980 
981  titles = g_list_insert_sorted (titles, title, (GCompareFunc)g_strcmp0);
982  splits = g_list_prepend (splits, split); // splits don't need to be sorted
983  }
984 
985  if (!titles)
986  return; // We didn't find document lots
987 
988  // Create the memo as we'd want it to be
989  new_memo = g_strconcat (memo_prefix, titles->data, NULL);
990  for (titer = titles->next; titer; titer = titer->next)
991  {
992  gchar *tmp_memo = g_strconcat (new_memo, " - ", titer->data, NULL);
993  g_free (new_memo);
994  new_memo = tmp_memo;
995  }
996  g_list_free_full (titles, g_free);
997 
998  // Update the memos of all the splits we found previously (if needed)
999  for (siter = splits; siter; siter = siter->next)
1000  {
1001  if (g_strcmp0 (xaccSplitGetMemo (siter->data), new_memo) != 0)
1002  xaccSplitSetMemo (siter->data, new_memo);
1003  }
1004 
1005  g_list_free (splits);
1006  g_free (new_memo);
1007 }
1008 
1009 /* Find an existing lot link transaction in the given lot
1010  * Only use a lot link that already links at least two
1011  * documents (to avoid perpetuating the lot link proliferation
1012  * that happened in 2.6.0-2.6.3).
1013  */
1014 static Transaction *
1015 get_ll_transaction_from_lot (GNCLot *lot)
1016 {
1017  SplitList *ls_iter;
1018 
1019  /* This should really only be called on a document lot */
1020  if (!gncInvoiceGetInvoiceFromLot (lot))
1021  return NULL;
1022 
1023  /* The given lot is a valid document lot. Now iterate over all
1024  * other lot links in this lot to find one more document lot.
1025  */
1026  for (ls_iter = gnc_lot_get_split_list (lot); ls_iter; ls_iter = ls_iter->next)
1027  {
1028  Split *ls = ls_iter->data;
1029  Transaction *ll_txn = xaccSplitGetParent (ls);
1030  SplitList *ts_iter;
1031 
1032  if (xaccTransGetTxnType (ll_txn) != TXN_TYPE_LINK)
1033  continue;
1034 
1035  for (ts_iter = xaccTransGetSplitList (ll_txn); ts_iter; ts_iter = ts_iter->next)
1036  {
1037  Split *ts = ts_iter->data;
1038  GNCLot *tslot = xaccSplitGetLot (ts);
1039 
1040  if (!tslot)
1041  continue;
1042 
1043  if (tslot == lot)
1044  continue;
1045 
1046  if (gncInvoiceGetInvoiceFromLot (lot))
1047  return ll_txn; /* Got one more document lot - mission accomplished */
1048  }
1049  }
1050 
1051  /* The lot doesn't have an ll_txn with the requested criteria... */
1052  return NULL;
1053 }
1054 
1055 static void
1056 gncOwnerCreateLotLink (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
1057 {
1058  const gchar *action = _("Lot Link");
1059  Account *acct = gnc_lot_get_account (from_lot);
1060  const gchar *name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
1061  Transaction *ll_txn = NULL;
1062  gnc_numeric from_lot_bal, to_lot_bal;
1063  Timespec from_ts, to_ts;
1064  time64 time_posted;
1065  Split *split;
1066 
1067  /* Sanity check */
1068  if (!gncInvoiceGetInvoiceFromLot (from_lot) ||
1069  !gncInvoiceGetInvoiceFromLot (to_lot))
1070  return;
1071 
1072  /* Determine transaction date based on lot splits */
1075  if (timespecToTime64 (from_ts) >= timespecToTime64 (to_ts))
1076  time_posted = timespecToTime64 (from_ts);
1077  else
1078  time_posted = timespecToTime64 (to_ts);
1079 
1080  /* Figure out how much we can offset between the lots */
1081  from_lot_bal = gnc_lot_get_balance (from_lot);
1082  to_lot_bal = gnc_lot_get_balance (to_lot);
1083  if (gnc_numeric_compare (gnc_numeric_abs (from_lot_bal),
1084  gnc_numeric_abs (to_lot_bal)) > 0)
1085  from_lot_bal = gnc_numeric_neg (to_lot_bal);
1086  else
1087  to_lot_bal = gnc_numeric_neg (from_lot_bal);
1088 
1089  xaccAccountBeginEdit (acct);
1090 
1091  /* Look for a pre-existing lot link we can extend */
1092  ll_txn = get_ll_transaction_from_lot (from_lot);
1093 
1094  if (!ll_txn)
1095  ll_txn = get_ll_transaction_from_lot (to_lot);
1096 
1097  if (!ll_txn)
1098  {
1099  /* No pre-existing lot link. Create one. */
1100  Timespec ts;
1101 
1102  timespecFromTime64 (&ts, time_posted);
1103 
1104  ll_txn = xaccMallocTransaction (gnc_lot_get_book (from_lot));
1105  xaccTransBeginEdit (ll_txn);
1106 
1107  xaccTransSetDescription (ll_txn, name ? name : "(Unknown)");
1109  xaccTransSetDateEnteredSecs (ll_txn, gnc_time (NULL));
1110  xaccTransSetDatePostedTS (ll_txn, &ts);
1112  }
1113  else
1114  {
1115  Timespec ts = xaccTransRetDatePostedTS (ll_txn);
1116  xaccTransBeginEdit (ll_txn);
1117 
1118  /* Maybe we need to update the post date of the transaction ? */
1119  if (time_posted > timespecToTime64 (ts))
1120  {
1121  timespecFromTime64 (&ts, time_posted);
1122  xaccTransSetDatePostedTS (ll_txn, &ts);
1123 
1124  }
1125  }
1126 
1127  /* Create a split for the from_lot */
1128  split = xaccMallocSplit (gnc_lot_get_book (from_lot));
1129  /* set Action using utility function */
1130  gnc_set_num_action (NULL, split, NULL, action);
1131  xaccAccountInsertSplit (acct, split);
1132  xaccTransAppendSplit (ll_txn, split);
1133  /* To offset the lot balance, the split must be of the opposite sign */
1134  xaccSplitSetBaseValue (split, gnc_numeric_neg (from_lot_bal), xaccAccountGetCommodity(acct));
1135  gnc_lot_add_split (from_lot, split);
1136 
1137  /* Create a split for the to_lot */
1138  split = xaccMallocSplit (gnc_lot_get_book (to_lot));
1139  /* set Action using utility function */
1140  gnc_set_num_action (NULL, split, NULL, action);
1141  xaccAccountInsertSplit (acct, split);
1142  xaccTransAppendSplit (ll_txn, split);
1143  /* To offset the lot balance, the split must be of the opposite sign */
1144  xaccSplitSetBaseValue (split, gnc_numeric_neg (to_lot_bal), xaccAccountGetCommodity(acct));
1145  gnc_lot_add_split (to_lot, split);
1146 
1147  xaccTransCommitEdit (ll_txn);
1148 
1149 
1150  /* Do some post-cleaning on the lots
1151  * The above actions may have created splits that are
1152  * in the same transaction and lot. These can be merged.
1153  */
1154  xaccScrubMergeLotSubSplits (to_lot, FALSE);
1155  xaccScrubMergeLotSubSplits (from_lot, FALSE);
1156  /* And finally set the same memo for all remaining splits
1157  * It's a convenience for the users to identify all documents
1158  * involved in the link.
1159  */
1160  gncOwnerSetLotLinkMemo (ll_txn);
1161  xaccAccountCommitEdit (acct);
1162 }
1163 
1164 static void gncOwnerOffsetLots (GNCLot *from_lot, GNCLot *to_lot, const GncOwner *owner)
1165 {
1166  gnc_numeric target_offset;
1167  Split *split;
1168 
1169  /* from lot should not be a document lot because we're removing a split from there ! */
1170  if (gncInvoiceGetInvoiceFromLot (from_lot))
1171  {
1172  PWARN ("from_lot %p is a document lot. That is not allowed in gncOwnerOffsetLots", from_lot);
1173  return;
1174  }
1175 
1176  /* Get best matching split from from_lot to offset to_lot */
1177  target_offset = gnc_lot_get_balance (to_lot);
1178  if (gnc_numeric_zero_p (target_offset))
1179  return; // to_lot is already balanced, nothing more to do
1180 
1181  split = gncOwnerFindOffsettingSplit (from_lot, target_offset);
1182  if (!split)
1183  return; // No suitable offsetting split found, nothing more to do
1184 
1185  /* If the offsetting split is bigger than the amount needed to balance
1186  * to_lot, reduce the split so its reduced value closes to_lot exactly.
1187  * Note the negation in the reduction function. The split must be of
1188  * opposite sign of to_lot's balance in order to be able to close it.
1189  */
1191  gnc_numeric_abs (target_offset)) > 0)
1192  gncOwnerReduceSplitTo (split, gnc_numeric_neg (target_offset));
1193 
1194  /* Move the reduced split from from_lot to to_lot */
1195  gnc_lot_add_split (to_lot, split);
1196 
1197 }
1198 
1199 void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
1200 {
1201  GList *left_iter;
1202 
1203  /* General note: in the code below the term "payment" can
1204  * both mean a true payment or a document of
1205  * the opposite sign (invoice vs credit note) relative to
1206  * the lot being processed. In general this function will
1207  * perform a balancing action on a set of lots, so you
1208  * will also find frequent references to balancing instead. */
1209 
1210  /* Payments can only be applied when at least an owner
1211  * and a list of lots to use are given */
1212  if (!owner) return;
1213  if (!lots) return;
1214 
1215  for (left_iter = lots; left_iter; left_iter = left_iter->next)
1216  {
1217  GNCLot *left_lot = left_iter->data;
1218  gnc_numeric left_lot_bal;
1219  gboolean left_lot_has_doc;
1220  gboolean left_modified = FALSE;
1221  Account *acct;
1222  GList *right_iter;
1223 
1224  /* Only attempt to apply payments to open lots.
1225  * Note that due to the iterative nature of this function lots
1226  * in the list may become empty/closed before they are evaluated as
1227  * base lot, so we should check this for each lot. */
1228  if (!left_lot)
1229  continue;
1230  if (gnc_lot_count_splits (left_lot) == 0)
1231  {
1232  gnc_lot_destroy (left_lot);
1233  left_iter->data = NULL;
1234  continue;
1235  }
1236  if (gnc_lot_is_closed (left_lot))
1237  continue;
1238 
1239  acct = gnc_lot_get_account (left_lot);
1240  xaccAccountBeginEdit (acct);
1241 
1242  left_lot_bal = gnc_lot_get_balance (left_lot);
1243  left_lot_has_doc = (gncInvoiceGetInvoiceFromLot (left_lot) != NULL);
1244 
1245  /* Attempt to offset left_lot with any of the remaining lots. To do so
1246  * iterate over the remaining lots adding lot links or moving payments
1247  * around.
1248  */
1249  for (right_iter = left_iter->next; right_iter; right_iter = right_iter->next)
1250  {
1251  GNCLot *right_lot = right_iter->data;
1252  gnc_numeric right_lot_bal;
1253  gboolean right_lot_has_doc;
1254 
1255  /* Only attempt to use open lots to balance the base lot.
1256  * Note that due to the iterative nature of this function lots
1257  * in the list may become empty/closed before they are evaluated as
1258  * base lot, so we should check this for each lot. */
1259  if (!right_lot)
1260  continue;
1261  if (gnc_lot_count_splits (right_lot) == 0)
1262  {
1263  gnc_lot_destroy (right_lot);
1264  right_iter->data = NULL;
1265  continue;
1266  }
1267  if (gnc_lot_is_closed (right_lot))
1268  continue;
1269 
1270  /* Balancing transactions for invoice/payments can only happen
1271  * in the same account. */
1272  if (acct != gnc_lot_get_account (right_lot))
1273  continue;
1274 
1275 
1276  /* Only attempt to balance if the base lot and balancing lot are
1277  * of the opposite sign. (Otherwise we would increase the balance
1278  * of the lot - Duh */
1279  right_lot_bal = gnc_lot_get_balance (right_lot);
1280  if (gnc_numeric_positive_p (left_lot_bal) == gnc_numeric_positive_p (right_lot_bal))
1281  continue;
1282 
1283  /* Ok we found two lots than can (partly) offset each other.
1284  * Depending on the lot types, a different action is needed to accomplish this.
1285  * 1. Both lots are document lots (invoices/credit notes)
1286  * -> Create a lot linking transaction between the lots
1287  * 2. Both lots are payment lots (lots without a document attached)
1288  * -> Use part of the bigger lot to the close the smaller lot
1289  * 3. One document lot with one payment lot
1290  * -> Use (part of) the payment to offset (part of) the document lot,
1291  * Which one will be closed depends on which is the bigger one
1292  */
1293  right_lot_has_doc = (gncInvoiceGetInvoiceFromLot (right_lot) != NULL);
1294  if (left_lot_has_doc && right_lot_has_doc)
1295  gncOwnerCreateLotLink (left_lot, right_lot, owner);
1296  else if (!left_lot_has_doc && !right_lot_has_doc)
1297  {
1298  gint cmp = gnc_numeric_compare (gnc_numeric_abs (left_lot_bal),
1299  gnc_numeric_abs (right_lot_bal));
1300  if (cmp >= 0)
1301  gncOwnerOffsetLots (left_lot, right_lot, owner);
1302  else
1303  gncOwnerOffsetLots (right_lot, left_lot, owner);
1304  }
1305  else
1306  {
1307  GNCLot *doc_lot = left_lot_has_doc ? left_lot : right_lot;
1308  GNCLot *pay_lot = left_lot_has_doc ? right_lot : left_lot;
1309  // Ok, let's try to move a payment from pay_lot to doc_lot
1310  gncOwnerOffsetLots (pay_lot, doc_lot, owner);
1311  }
1312 
1313  /* If we get here, then right_lot was modified
1314  * If the lot has a document, send an event for send an event for it as well
1315  * so it gets potentially updated as paid */
1316 
1317  {
1318  GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(right_lot);
1319  if (this_invoice)
1320  qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
1321  }
1322  left_modified = TRUE;
1323  }
1324 
1325  /* If left_lot was modified and the lot has a document,
1326  * send an event for send an event for it as well
1327  * so it gets potentially updated as paid */
1328  if (left_modified)
1329  {
1330  GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(left_lot);
1331  if (this_invoice)
1332  qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
1333  }
1334  xaccAccountCommitEdit (acct);
1335 
1336  }
1337 }
1338 
1339 /*
1340  * Create a payment of "amount" for the owner and match it with
1341  * the set of lots passed in.
1342  * If
1343  * - no lots were given
1344  * - auto_pay is true
1345  * then all open lots for the owner are considered.
1346  */
1347 void
1348 gncOwnerApplyPayment (const GncOwner *owner, Transaction *txn, GList *lots,
1349  Account *posted_acc, Account *xfer_acc,
1350  gnc_numeric amount, gnc_numeric exch, Timespec date,
1351  const char *memo, const char *num, gboolean auto_pay)
1352 {
1353  GNCLot *payment_lot = NULL;
1354  GList *selected_lots = NULL;
1355 
1356  /* Verify our arguments */
1357  if (!owner || !posted_acc
1358  || (!xfer_acc && !gnc_numeric_zero_p (amount)) ) return;
1359  g_return_if_fail (owner->owner.undefined);
1360 
1361  /* If there's a real amount to transfer create a lot for this payment */
1362  if (!gnc_numeric_zero_p (amount))
1363  payment_lot = gncOwnerCreatePaymentLot (owner, txn, posted_acc, xfer_acc,
1364  amount, exch, date, memo, num);
1365 
1366  if (lots)
1367  selected_lots = lots;
1368  else if (auto_pay)
1369  selected_lots = xaccAccountFindOpenLots (posted_acc, gncOwnerLotMatchOwnerFunc,
1370  (gpointer)owner, NULL);
1371 
1372  /* And link the selected lots and the payment lot together as well as possible.
1373  * If the payment was bigger than the selected documents/overpayments, only
1374  * part of the payment will be used. Similarly if more documents were selected
1375  * than the payment value set, not all documents will be marked as paid. */
1376  if (payment_lot)
1377  selected_lots = g_list_prepend (selected_lots, payment_lot);
1378  gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots);
1379  g_list_free (selected_lots);
1380 }
1381 
1382 GList *
1384 {
1385  g_return_val_if_fail (owner, NULL);
1386 
1387  switch (gncOwnerGetType (owner))
1388  {
1389  case GNC_OWNER_CUSTOMER:
1390  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_RECEIVABLE));
1391  case GNC_OWNER_VENDOR:
1392  case GNC_OWNER_EMPLOYEE:
1393  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_PAYABLE));
1394  break;
1395  default:
1396  return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_NONE));
1397  }
1398 }
1399 
1400 GList *
1402 {
1403  g_return_val_if_fail (owner, NULL);
1404  g_return_val_if_fail (gncOwnerGetCurrency(owner), NULL);
1405 
1406  return (g_list_prepend (NULL, gncOwnerGetCurrency(owner)));
1407 }
1408 
1409 /*********************************************************************/
1410 /* Owner balance calculation routines */
1411 
1412 /*
1413  * Given an owner, extract the open balance from the owner and then
1414  * convert it to the desired currency.
1415  */
1418  const gnc_commodity *report_currency)
1419 {
1420  gnc_numeric balance = gnc_numeric_zero ();
1421  GList *acct_list, *acct_node, *acct_types, *lot_list = NULL, *lot_node;
1422  QofBook *book;
1423  gnc_commodity *owner_currency;
1424  GNCPriceDB *pdb;
1425 
1426  g_return_val_if_fail (owner, gnc_numeric_zero ());
1427 
1428  /* Get account list */
1429  book = qof_instance_get_book (qofOwnerGetOwner (owner));
1430  acct_list = gnc_account_get_descendants (gnc_book_get_root_account (book));
1431  acct_types = gncOwnerGetAccountTypesList (owner);
1432  owner_currency = gncOwnerGetCurrency (owner);
1433 
1434  /* For each account */
1435  for (acct_node = acct_list; acct_node; acct_node = acct_node->next)
1436  {
1437  Account *account = acct_node->data;
1438 
1439  /* Check if this account can have lots for the owner, otherwise skip to next */
1440  if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account))
1441  == -1)
1442  continue;
1443 
1444 
1445  if (!gnc_commodity_equal (owner_currency, xaccAccountGetCommodity (account)))
1446  continue;
1447 
1448  /* Get a list of open lots for this owner and account */
1450  (gpointer)owner, NULL);
1451  /* For each lot */
1452  for (lot_node = lot_list; lot_node; lot_node = lot_node->next)
1453  {
1454  GNCLot *lot = lot_node->data;
1455  gnc_numeric lot_balance = gnc_lot_get_balance (lot);
1456  GncInvoice *invoice = gncInvoiceGetInvoiceFromLot(lot);
1457  if (invoice)
1458  balance = gnc_numeric_add (balance, lot_balance,
1460  }
1461  }
1462 
1463  pdb = gnc_pricedb_get_db (book);
1464 
1465  if (report_currency)
1467  pdb, balance, owner_currency, report_currency);
1468 
1469  return balance;
1470 }
1471 
1472 
1473 /* XXX: Yea, this is broken, but it should work fine for Queries.
1474  * We're single-threaded, right?
1475  */
1476 static GncOwner *
1477 owner_from_lot (GNCLot *lot)
1478 {
1479  static GncOwner owner;
1480 
1481  if (!lot) return NULL;
1482  if (gncOwnerGetOwnerFromLot (lot, &owner))
1483  return &owner;
1484 
1485  return NULL;
1486 }
1487 
1488 static void
1489 reg_lot (void)
1490 {
1491  static QofParam params[] =
1492  {
1493  { OWNER_FROM_LOT, _GNC_MOD_NAME, (QofAccessFunc)owner_from_lot, NULL },
1494  { NULL },
1495  };
1496 
1497  qof_class_register (GNC_ID_LOT, NULL, params);
1498 }
1499 
1500 gboolean gncOwnerGetOwnerFromTypeGuid (QofBook *book, GncOwner *owner, QofIdType type, GncGUID *guid)
1501 {
1502  if (!book || !owner || !type || !guid) return FALSE;
1503 
1504  if (0 == g_strcmp0(type, GNC_ID_CUSTOMER))
1505  {
1506  GncCustomer *customer = gncCustomerLookup(book, guid);
1507  gncOwnerInitCustomer(owner, customer);
1508  return (NULL != customer);
1509  }
1510  else if (0 == g_strcmp0(type, GNC_ID_JOB))
1511  {
1512  GncJob *job = gncJobLookup(book, guid);
1513  gncOwnerInitJob(owner, job);
1514  return (NULL != job);
1515  }
1516  else if (0 == g_strcmp0(type, GNC_ID_VENDOR))
1517  {
1518  GncVendor *vendor = gncVendorLookup(book, guid);
1519  gncOwnerInitVendor(owner, vendor);
1520  return (NULL != vendor);
1521  }
1522  else if (0 == g_strcmp0(type, GNC_ID_EMPLOYEE))
1523  {
1524  GncEmployee *employee = gncEmployeeLookup(book, guid);
1525  gncOwnerInitEmployee(owner, employee);
1526  return (NULL != employee);
1527  }
1528  return 0;
1529 }
1530 
1531 gboolean gncOwnerRegister (void)
1532 {
1533  static QofParam params[] =
1534  {
1535  { OWNER_TYPE, QOF_TYPE_INT64, (QofAccessFunc)gncOwnerGetType, NULL },
1536  { OWNER_CUSTOMER, GNC_ID_CUSTOMER, (QofAccessFunc)gncOwnerGetCustomer, NULL },
1537  { OWNER_JOB, GNC_ID_JOB, (QofAccessFunc)gncOwnerGetJob, NULL },
1538  { OWNER_VENDOR, GNC_ID_VENDOR, (QofAccessFunc)gncOwnerGetVendor, NULL },
1539  { OWNER_EMPLOYEE, GNC_ID_EMPLOYEE, (QofAccessFunc)gncOwnerGetEmployee, NULL },
1540  { OWNER_PARENT, GNC_ID_OWNER, (QofAccessFunc)gncOwnerGetEndOwner, NULL },
1541  { OWNER_PARENTG, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetEndGUID, NULL },
1542  { OWNER_NAME, QOF_TYPE_STRING, (QofAccessFunc)gncOwnerGetName, NULL },
1543  { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)gncOwnerGetGUID, NULL },
1544  { NULL },
1545  };
1546 
1547  qof_class_register (GNC_ID_OWNER, (QofSortFunc)gncOwnerCompare, params);
1548  reg_lot ();
1549 
1550  return TRUE;
1551 }
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
GList * gncOwnerGetCommoditiesList(const GncOwner *owner)
Definition: gncOwner.c:1401
QofIdType e_type
Definition: qofinstance.h:69
#define xaccTransAppendSplit(t, s)
Definition: Transaction.h:357
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
void xaccSplitSetBaseValue(Split *s, gnc_numeric value, const gnc_commodity *base_currency)
Definition: Split.c:1341
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
Definition: Scrub2.c:398
const GncGUID * gncOwnerGetGUID(const GncOwner *owner)
Definition: gncOwner.c:496
char xaccTransGetTxnType(const Transaction *trans)
Definition: Transaction.c:2302
int gnc_commodity_get_fraction(const gnc_commodity *cm)
time64 timespecToTime64(Timespec ts)
Business Interface: Object OWNERs.
const GncGUID * qof_instance_get_guid(gconstpointer)
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Definition: Transaction.c:2144
GList * gncOwnerGetAccountTypesList(const GncOwner *owner)
Definition: gncOwner.c:1383
QofBook * qof_instance_get_book(gconstpointer)
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
gboolean xaccSplitDestroy(Split *split)
Definition: Split.c:1492
Utilities to Convert Stock Accounts to use Lots.
const gchar * QofIdTypeConst
Definition: qofid.h:87
gnc_numeric gnc_numeric_neg(gnc_numeric a)
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
Definition: Split.c:686
void qof_instance_set(QofInstance *inst, const gchar *first_param,...)
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_fcn, const QofParam *params)
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
void gnc_lot_add_split(GNCLot *lot, Split *split)
Definition: gnc-lot.c:569
void xaccTransSetDescription(Transaction *trans, const char *desc)
Definition: Transaction.c:2085
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Definition: gncOwner.c:382
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gboolean gnc_numeric_zero_p(gnc_numeric a)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
API for Transactions and Splits (journal entries)
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
Definition: qofclass.h:177
gint gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
QofBook * xaccSplitGetBook(const Split *split)
Definition: Split.c:2042
void gncOwnerBeginEdit(GncOwner *owner)
Definition: gncOwner.c:73
gboolean gncOwnerIsValid(const GncOwner *owner)
Definition: gncOwner.c:650
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Definition: gnc-pricedb.c:872
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Definition: gnc-lot.c:648
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
Definition: gncOwner.c:253
Definition: guid.h:65
gnc_numeric gnc_pricedb_convert_balance_latest_price(GNCPriceDB *pdb, gnc_numeric balance, const gnc_commodity *balance_currency, const gnc_commodity *new_currency)
Definition: gnc-pricedb.c:2013
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
void gncOwnerAutoApplyPaymentsWithLots(const GncOwner *owner, GList *lots)
Definition: gncOwner.c:1199
Split * gnc_lot_get_latest_split(GNCLot *lot)
Definition: gnc-lot.c:660
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1402
#define PWARN(format, args...)
Definition: qoflog.h:243
const gchar * QofIdType
Definition: qofid.h:85
gint timespec_cmp(const Timespec *ta, const Timespec *tb)
int xaccTransCountSplits(const Transaction *trans)
Definition: Transaction.c:2170
void xaccTransSetTxnType(Transaction *trans, char type)
Definition: Transaction.c:2016
int gncOwnerGCompareFunc(const GncOwner *a, const GncOwner *b)
Definition: gncOwner.c:389
GList SplitList
Definition: gnc-engine.h:203
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
void gncOwnerApplyPayment(const GncOwner *owner, Transaction *txn, GList *lots, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, Timespec date, const char *memo, const char *num, gboolean auto_pay)
Definition: gncOwner.c:1348
Definition: gncJob.c:41
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
void xaccSplitSetMemo(Split *split, const char *memo)
Definition: Split.c:1774
gint gncOwnerLotsSortFunc(GNCLot *lotA, GNCLot *lotB)
Definition: gncOwner.c:679
gboolean gncOwnerReduceSplitTo(Split *split, gnc_numeric target_value)
Definition: gncOwner.c:914
gnc_numeric gncOwnerGetBalanceInCurrency(const GncOwner *owner, const gnc_commodity *report_currency)
Definition: gncOwner.c:1417
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Definition: gnc-lot.c:417
QofIdTypeConst qofOwnerGetType(const GncOwner *owner)
Definition: gncOwner.c:208
int gncOwnerCompare(const GncOwner *a, const GncOwner *b)
Definition: gncOwner.c:568
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
Definition: gncOwner.c:297
int(* QofSortFunc)(gconstpointer, gconstpointer)
Definition: qofclass.h:222
void gncOwnerAttachToLot(const GncOwner *owner, GNCLot *lot)
Definition: gncOwner.c:600
QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
Definition: gncOwner.c:213
gpointer gncOwnerGetUndefined(const GncOwner *owner)
Definition: gncOwner.c:340
gboolean gncOwnerGetOwnerFromLot(GNCLot *lot, GncOwner *owner)
Definition: gncOwner.c:614
gnc_numeric gnc_numeric_abs(gnc_numeric a)
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
#define TXN_TYPE_LINK
Definition: Transaction.h:122
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
int gncVendorCompare(const GncVendor *a, const GncVendor *b)
Definition: gncVendor.c:801
#define TXN_TYPE_PAYMENT
Definition: Transaction.h:121
gboolean gnc_numeric_positive_p(gnc_numeric a)
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
gboolean GNC_IS_OWNER(QofInstance *ent)
Definition: gncOwner.c:330
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Definition: gncOwner.c:201
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Definition: gncOwner.c:550
GList * gnc_account_get_descendants(const Account *account)
Definition: Account.c:2755
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Definition: gncInvoice.c:1174
Business Invoice Interface.
GncJob * gncOwnerGetJob(const GncOwner *owner)
Definition: gncOwner.c:354
GNCLot * gncOwnerCreatePaymentLot(const GncOwner *owner, Transaction *txn, Account *posted_acc, Account *xfer_acc, gnc_numeric amount, gnc_numeric exch, Timespec date, const char *memo, const char *num)
Definition: gncOwner.c:701
gboolean gncOwnerLotMatchOwnerFunc(GNCLot *lot, gpointer user_data)
Definition: gncOwner.c:657
gboolean gnc_lot_is_closed(GNCLot *lot)
Definition: gnc-lot.c:376
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
const GncGUID * guid_null(void)
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
#define xaccAccountInsertSplit(acc, s)
Definition: Account.h:972
Timespec xaccTransRetDatePostedTS(const Transaction *trans)
Definition: Transaction.c:2243
Split * gncOwnerFindOffsettingSplit(GNCLot *lot, gnc_numeric target_value)
Definition: gncOwner.c:848
GncVendor * gncOwnerGetVendor(const GncOwner *owner)
Definition: gncOwner.c:361
GncCustomer * gncOwnerGetCustomer(const GncOwner *owner)
Definition: gncOwner.c:347
time64 gnc_time(time64 *tbuf)
get the current local time
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
void gncOwnerSetLotLinkMemo(Transaction *ll_txn)
Definition: gncOwner.c:946
gint64 time64
Definition: gnc-date.h:83
Account * gnc_lot_get_account(const GNCLot *lot)
Definition: gnc-lot.c:386
LotList * xaccAccountFindOpenLots(const Account *acc, gboolean(*match_func)(GNCLot *lot, gpointer user_data), gpointer user_data, GCompareFunc sort_func)
Definition: Account.c:3751
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Definition: Transaction.c:1951
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
GncEmployee * gncOwnerGetEmployee(const GncOwner *owner)
Definition: gncOwner.c:368
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
GncOwner * gncOwnerNew(void)
Definition: gncOwner.c:58
SplitList * xaccTransGetSplitList(const Transaction *trans)
Definition: Transaction.c:2164
Commodity handling public routines.
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Definition: gnc-lot.c:477
GNCLot * xaccSplitGetLot(const Split *split)
Definition: Split.c:1953
const gchar * QofLogModule
Definition: qofid.h:89
void xaccTransSetDatePostedTS(Transaction *trans, const Timespec *ts)
Definition: Transaction.c:1970
void timespecFromTime64(Timespec *ts, time64 t)