GnuCash c935c2f+
Loading...
Searching...
No Matches
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
55static 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
66void 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
103void 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
134void 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
165void gncOwnerInitUndefined (GncOwner *owner, gpointer obj)
166{
167 if (!owner) return;
168 owner->type = GNC_OWNER_UNDEFINED;
169 owner->owner.undefined = obj;
170}
171
172void gncOwnerInitCustomer (GncOwner *owner, GncCustomer *customer)
173{
174 if (!owner) return;
175 owner->type = GNC_OWNER_CUSTOMER;
176 owner->owner.customer = customer;
177}
178
179void gncOwnerInitJob (GncOwner *owner, GncJob *job)
180{
181 if (!owner) return;
182 owner->type = GNC_OWNER_JOB;
183 owner->owner.job = job;
184}
185
186void gncOwnerInitVendor (GncOwner *owner, GncVendor *vendor)
187{
188 if (!owner) return;
189 owner->type = GNC_OWNER_VENDOR;
190 owner->owner.vendor = vendor;
191}
192
193void gncOwnerInitEmployee (GncOwner *owner, GncEmployee *employee)
194{
195 if (!owner) return;
196 owner->type = GNC_OWNER_EMPLOYEE;
197 owner->owner.employee = employee;
198}
199
200GncOwnerType gncOwnerGetType (const GncOwner *owner)
201{
202 if (!owner) return GNC_OWNER_NONE;
203 return owner->type;
204}
205
206const 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
318void
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
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}
362gpointer 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
376GncJob * 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
383GncVendor * 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
390GncEmployee * 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
397void gncOwnerCopy (const GncOwner *src, GncOwner *dest)
398{
399 if (!src || !dest) return;
400 if (src == dest) return;
401 *dest = *src;
402}
403
404gboolean 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
411int gncOwnerGCompareFunc (const GncOwner *a, const GncOwner *b)
412{
413 if (gncOwnerEqual (a, b))
414 return 0;
415 else
416 return 1;
417}
418
419const 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
439const 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
459GncAddress * 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
478gnc_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
498gboolean 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
518const 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
539void
540gncOwnerSetActive (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
564GncGUID gncOwnerRetGUID (GncOwner *owner)
565{
566 const GncGUID *guid = gncOwnerGetGUID (owner);
567 if (guid)
568 return *guid;
569 return *guid_null ();
570}
571
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
590int 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
616const GncGUID * gncOwnerGetEndGUID (const GncOwner *owner)
617{
618 if (!owner) return NULL;
619 return gncOwnerGetGUID (gncOwnerGetEndOwner (owner));
620}
621
622void 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
636gboolean 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
674gboolean gncOwnerGetOwnerFromTxn (Transaction *txn, GncOwner *owner)
675{
676 Split *apar_split = NULL;
677
678 if (!txn || !owner) return FALSE;
679
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
699gboolean gncOwnerIsValid (const GncOwner *owner)
700{
701 if (!owner) return FALSE;
702 return (owner->owner.undefined != NULL);
703}
704
705gboolean
706gncOwnerLotMatchOwnerFunc (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
727gint
728gncOwnerLotsSortFunc (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
749GNCLot *
750gncOwnerCreatePaymentLotSecs (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 */
882 if (preset_txn)
883 *preset_txn = txn;
884
885 return payment_lot;
886}
887
888typedef enum
889{
890 is_equal = 8,
891 is_more = 4,
892 is_less = 2,
893 is_pay_split = 1
894} split_flags;
895
896Split *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
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
958gboolean
959gncOwnerReduceSplitTo (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
1009void
1010gncOwnerSetLotLinkMemo (Transaction *ll_txn)
1011{
1012 gchar *memo_prefix = _("Offset between business items: ");
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 */
1080static Transaction *
1081get_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
1121static void
1122gncOwnerCreateLotLink (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 */
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
1221static 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
1256void 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 */
1404void
1405gncOwnerApplyPaymentSecs (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
1443GList *
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
1461GList *
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 */
1477gnc_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 */
1551static GncOwner *
1552owner_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
1563static void
1564reg_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
1575gboolean 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
1606gboolean 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
1628const gnc_numeric*
1629gncOwnerGetCachedBalance (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
1643void 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}
Utilities to Convert Stock Accounts to use Lots.
API for Transactions and Splits (journal entries)
API for Transactions and Splits (journal entries)
Commodity handling public routines.
Business Invoice Interface.
Business Interface: Object OWNERs.
void xaccAccountCommitEdit(Account *acc)
ThexaccAccountCommitEdit() subroutine is the second phase of a two-phase-commit wrapper for account u...
Definition Account.cpp:1516
void xaccAccountBeginEdit(Account *acc)
The xaccAccountBeginEdit() subroutine is the first phase of a two-phase-commit wrapper for account up...
Definition Account.cpp:1475
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
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:3044
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
@ ACCT_TYPE_PAYABLE
A/P account type.
Definition Account.h:151
@ ACCT_TYPE_RECEIVABLE
A/R account type.
Definition Account.h:149
@ ACCT_TYPE_NONE
Not a type.
Definition Account.h:105
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:123
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
int(* QofSortFunc)(gconstpointer, gconstpointer)
This function is the default sort function for a particular object type.
Definition qofclass.h:168
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits,...
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly,...
#define xaccTransAppendSplit(t, s)
Add a split to the 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...
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
#define TXN_TYPE_NONE
No transaction type
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:3982
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransSetDatePostedSecs(Transaction *trans, time64 secs)
The xaccTransSetDatePostedSecs() method will modify the posted date of the transaction,...
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account.
Definition Account.h:1069
Split * xaccTransGetFirstAPARAcctSplit(const Transaction *trans, gboolean strict)
The xaccTransGetFirstPaymentAcctSplit() method returns a pointer to the first split in this transacti...
GList SplitList
GList of Split.
Definition gnc-engine.h:207
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
#define TXN_TYPE_PAYMENT
Transaction is a payment
#define TXN_TYPE_LINK
Transaction is a link between (invoice and payment) lots
const gchar * QofIdType
QofIdType declaration.
Definition qofid.h:80
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition qofid.h:82
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
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition guid.cpp:165
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
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_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
QofIdType e_type
Entity type.
Definition qofinstance.h:75
GncInvoice * gncInvoiceGetInvoiceFromLot(GNCLot *lot)
Given a LOT, find and return the Invoice attached to the lot.
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
Split * gnc_lot_get_latest_split(GNCLot *lot)
Convenience routineto identify the date this lot was closed.
Definition gnc-lot.cpp:670
void gnc_lot_add_split(GNCLot *lot, Split *split)
Adds a split to this lot.
Definition gnc-lot.cpp:579
Account * gnc_lot_get_account(const GNCLot *lot)
Returns the account with which this lot is associated.
Definition gnc-lot.cpp:377
gnc_numeric gnc_lot_get_balance(GNCLot *lot)
Returns the lot balance.
Definition gnc-lot.cpp:487
SplitList * gnc_lot_get_split_list(const GNCLot *lot)
Returns a list of all the splits in this lot.
Definition gnc-lot.cpp:425
gboolean gnc_lot_is_closed(GNCLot *lot)
Returns closed status of the given lot.
Definition gnc-lot.cpp:367
Split * gnc_lot_get_earliest_split(GNCLot *lot)
Convenience routine to identify the earliest date in the lot.
Definition gnc-lot.cpp:658
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a-b.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
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.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
int gnc_numeric_compare(gnc_numeric a, gnc_numeric b)
Returns 1 if a>b, -1 if b>a, 0 if a == b
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Return a+b.
@ GNC_HOW_RND_ROUND_HALF_UP
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
@ GNC_HOW_DENOM_FIXED
All arguments are required to have the same denominator, that denominator is to be used in the output...
@ GNC_HOW_DENOM_LCD
Find the least common multiple of the arguments' denominators and use that as the denominator of the ...
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
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
gboolean GNC_IS_OWNER(QofInstance *ent)
Check if entity is an owner kind.
Definition gncOwner.c:352
gboolean gncOwnerIsValid(const GncOwner *owner)
Returns TRUE if the given owner is one of the valid objects.
Definition gncOwner.c:699
gboolean gncOwnerGetOwnerFromLot(GNCLot *lot, GncOwner *owner)
Get the owner from the lot.
Definition gncOwner.c:636
void gncOwnerAttachToLot(const GncOwner *owner, GNCLot *lot)
Attach an owner to a lot.
Definition gncOwner.c:622
GList * gncOwnerGetCommoditiesList(const GncOwner *owner)
Returns a GList of currencies associated with the owner.
Definition gncOwner.c:1462
void gncOwnerBeginEdit(GncOwner *owner)
These are convenience wrappers around gnc{Vendor,Customer,Job,Employee}* functions.
Definition gncOwner.c:72
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
QofIdTypeConst qofOwnerGetType(const GncOwner *owner)
return the type for the collection.
Definition gncOwner.c:230
GList * gncOwnerGetAccountTypesList(const GncOwner *owner)
Returns a GList of account-types based on the owner type.
Definition gncOwner.c:1444
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
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
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
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
gboolean gncOwnerReduceSplitTo(Split *split, gnc_numeric target_amount)
Helper function to reduce the amount of a split to target_amount.
Definition gncOwner.c:959
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
int gncOwnerCompare(const GncOwner *a, const GncOwner *b)
Sort on name.
Definition gncOwner.c:590
gint gncOwnerLotsSortFunc(GNCLot *lotA, GNCLot *lotB)
Helper function used to sort lots by date.
Definition gncOwner.c:728
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
const GncOwner * gncOwnerGetEndOwner(const GncOwner *owner)
Get the "parent" Owner or GncGUID thereof.
Definition gncOwner.c:572
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
gboolean gncOwnerEqual(const GncOwner *a, const GncOwner *b)
Assess equality by checking.
Definition gncOwner.c:404
gboolean gncOwnerLotMatchOwnerFunc(GNCLot *lot, gpointer user_data)
Helper function used to filter a list of lots by owner.
Definition gncOwner.c:706
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
const GncGUID * gncOwnerGetGUID(const GncOwner *owner)
Get the GncGUID of the immediate owner.
Definition gncOwner.c:518
GncOwner * gncOwnerNew(void)
These two functions are mainly for the convenience of scheme code.
Definition gncOwner.c:57
GncOwnerType gncOwnerGetType(const GncOwner *owner)
Returns the GncOwnerType of this owner.
Definition gncOwner.c:200
const char * gncOwnerGetTypeString(const GncOwner *owner)
return the type for the owner as an untranslated string.
Definition gncOwner.c:206
QofInstance * qofOwnerGetOwner(const GncOwner *owner)
return the owner itself as an entity.
Definition gncOwner.c:275
QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
Returns the QofIdType of the given GncOwnerType, or NULL if no suitable one exists.
Definition gncOwner.c:235
void qofOwnerSetEntity(GncOwner *owner, QofInstance *ent)
set the owner from the entity.
Definition gncOwner.c:319
gboolean gncOwnerGetOwnerFromTxn(Transaction *txn, GncOwner *owner)
Convenience function to get the owner from a transaction.
Definition gncOwner.c:674
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
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.
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
gboolean xaccScrubMergeLotSubSplits(GNCLot *lot, gboolean strict)
The xaccScrubMergeLotSubSplits() routine does the same as the xaccScrubMergSubSplits,...
Definition Scrub2.cpp:390
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1506
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction's commodity.
Split * xaccMallocSplit(QofBook *book)
Constructor.
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account's commodity that the split should have...
GNCLot * xaccSplitGetLot(const Split *split)
Returns the pointer to the debited/credited Lot where this split belongs to, or NULL if it doesn't be...
Definition Split.cpp:1920
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
This is really a helper for xaccTransCopyOnto.
Definition Split.cpp:648
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
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:1355
#define NREC
not reconciled or cleared
Definition Split.h:76
QofBook * xaccSplitGetBook(const Split *split)
Returns the book of this split, i.e.
void xaccSplitSetAction(Split *split, const char *actn)
The Action is an arbitrary user-assigned string.
Definition Split.cpp:1786
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
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
STRUCTS.
credit, discount and shipaddr are unique to GncCustomer id, name, notes, terms, addr,...
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47