GnuCash 2.4.99
gncOwner.c
00001 /********************************************************************\
00002  * gncOwner.c -- Business Interface:  Object OWNERs                 *
00003  *                                                                  *
00004  * This program is free software; you can redistribute it and/or    *
00005  * modify it under the terms of the GNU General Public License as   *
00006  * published by the Free Software Foundation; either version 2 of   *
00007  * the License, or (at your option) any later version.              *
00008  *                                                                  *
00009  * This program is distributed in the hope that it will be useful,  *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00012  * GNU General Public License for more details.                     *
00013  *                                                                  *
00014  * You should have received a copy of the GNU General Public License*
00015  * along with this program; if not, contact:                        *
00016  *                                                                  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942       *
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00020  *                                                                  *
00021 \********************************************************************/
00022 
00023 /*
00024  * Copyright (C) 2001, 2002 Derek Atkins
00025  * Copyright (C) 2003 Linas Vepstas <linas@linas.org>
00026  * Copyright (c) 2005 Neil Williams <linux@codehelp.co.uk>
00027  * Copyright (c) 2006 David Hampton <hampton@employees.org>
00028  * Copyright (c) 2011 Geert Janssens <geert@kobaltwit.be>
00029  * Author: Derek Atkins <warlord@MIT.EDU>
00030  */
00031 
00032 #include "config.h"
00033 
00034 #include <glib.h>
00035 #include <glib/gi18n.h>
00036 #include <string.h>             /* for memcpy() */
00037 
00038 #include "gncCustomerP.h"
00039 #include "gncEmployeeP.h"
00040 #include "gncJobP.h"
00041 #include "gncOwner.h"
00042 #include "gncOwnerP.h"
00043 #include "gncVendorP.h"
00044 #include "gncInvoice.h"
00045 #include "gnc-commodity.h"
00046 #include "Transaction.h"
00047 #include "Split.h"
00048 
00049 #define _GNC_MOD_NAME   GNC_ID_OWNER
00050 
00051 #define GNC_OWNER_ID    "gncOwner"
00052 #define GNC_OWNER_TYPE  "owner-type"
00053 #define GNC_OWNER_GUID  "owner-guid"
00054 
00055 GncOwner * gncOwnerNew (void)
00056 {
00057     GncOwner *o;
00058 
00059     o = g_new0 (GncOwner, 1);
00060     o->type = GNC_OWNER_NONE;
00061     return o;
00062 }
00063 
00064 void gncOwnerFree (GncOwner *owner)
00065 {
00066     if (!owner) return;
00067     g_free (owner);
00068 }
00069 
00070 void gncOwnerBeginEdit (GncOwner *owner)
00071 {
00072     if (!owner) return;
00073     switch (owner->type)
00074     {
00075     case GNC_OWNER_NONE :
00076     case GNC_OWNER_UNDEFINED :
00077         break;
00078     case GNC_OWNER_CUSTOMER :
00079     {
00080         gncCustomerBeginEdit(owner->owner.customer);
00081         break;
00082     }
00083     case GNC_OWNER_JOB :
00084     {
00085         gncJobBeginEdit(owner->owner.job);
00086         break;
00087     }
00088     case GNC_OWNER_VENDOR :
00089     {
00090         gncVendorBeginEdit(owner->owner.vendor);
00091         break;
00092     }
00093     case GNC_OWNER_EMPLOYEE :
00094     {
00095         gncEmployeeBeginEdit(owner->owner.employee);
00096         break;
00097     }
00098     }
00099 }
00100 
00101 
00102 void gncOwnerDestroy (GncOwner *owner)
00103 {
00104     if (!owner) return;
00105     switch (owner->type)
00106     {
00107     case GNC_OWNER_NONE :
00108     case GNC_OWNER_UNDEFINED :
00109         break;
00110     case GNC_OWNER_CUSTOMER :
00111     {
00112         gncCustomerDestroy(owner->owner.customer);
00113         break;
00114     }
00115     case GNC_OWNER_JOB :
00116     {
00117         gncJobDestroy(owner->owner.job);
00118         break;
00119     }
00120     case GNC_OWNER_VENDOR :
00121     {
00122         gncVendorDestroy(owner->owner.vendor);
00123         break;
00124     }
00125     case GNC_OWNER_EMPLOYEE :
00126     {
00127         gncEmployeeDestroy(owner->owner.employee);
00128         break;
00129     }
00130     }
00131 }
00132 
00133 void gncOwnerInitUndefined (GncOwner *owner, gpointer obj)
00134 {
00135     if (!owner) return;
00136     owner->type = GNC_OWNER_UNDEFINED;
00137     owner->owner.undefined = obj;
00138 }
00139 
00140 void gncOwnerInitCustomer (GncOwner *owner, GncCustomer *customer)
00141 {
00142     if (!owner) return;
00143     owner->type = GNC_OWNER_CUSTOMER;
00144     owner->owner.customer = customer;
00145 }
00146 
00147 void gncOwnerInitJob (GncOwner *owner, GncJob *job)
00148 {
00149     if (!owner) return;
00150     owner->type = GNC_OWNER_JOB;
00151     owner->owner.job = job;
00152 }
00153 
00154 void gncOwnerInitVendor (GncOwner *owner, GncVendor *vendor)
00155 {
00156     if (!owner) return;
00157     owner->type = GNC_OWNER_VENDOR;
00158     owner->owner.vendor = vendor;
00159 }
00160 
00161 void gncOwnerInitEmployee (GncOwner *owner, GncEmployee *employee)
00162 {
00163     if (!owner) return;
00164     owner->type = GNC_OWNER_EMPLOYEE;
00165     owner->owner.employee = employee;
00166 }
00167 
00168 GncOwnerType gncOwnerGetType (const GncOwner *owner)
00169 {
00170     if (!owner) return GNC_OWNER_NONE;
00171     return owner->type;
00172 }
00173 
00174 QofIdTypeConst
00175 qofOwnerGetType(const GncOwner *owner)
00176 {
00177     return gncOwnerTypeToQofIdType(owner->type);
00178 }
00179 
00180 QofIdTypeConst gncOwnerTypeToQofIdType(GncOwnerType t)
00181 {
00182     QofIdTypeConst type = NULL;
00183     switch (t)
00184     {
00185     case GNC_OWNER_NONE :
00186     {
00187         type = NULL;
00188         break;
00189     }
00190     case GNC_OWNER_UNDEFINED :
00191     {
00192         type = NULL;
00193         break;
00194     }
00195     case GNC_OWNER_CUSTOMER :
00196     {
00197         type = GNC_ID_CUSTOMER;
00198         break;
00199     }
00200     case GNC_OWNER_JOB :
00201     {
00202         type = GNC_ID_JOB;
00203         break;
00204     }
00205     case GNC_OWNER_VENDOR :
00206     {
00207         type = GNC_ID_VENDOR;
00208         break;
00209     }
00210     case GNC_OWNER_EMPLOYEE :
00211     {
00212         type = GNC_ID_EMPLOYEE;
00213         break;
00214     }
00215     }
00216     return type;
00217 }
00218 
00219 QofInstance*
00220 qofOwnerGetOwner (const GncOwner *owner)
00221 {
00222     QofInstance *ent;
00223 
00224     if (!owner)
00225     {
00226         return NULL;
00227     }
00228     ent = NULL;
00229     switch (owner->type)
00230     {
00231     case GNC_OWNER_NONE :
00232     {
00233         break;
00234     }
00235     case GNC_OWNER_UNDEFINED :
00236     {
00237         break;
00238     }
00239     case GNC_OWNER_CUSTOMER :
00240     {
00241         ent = QOF_INSTANCE(owner->owner.customer);
00242         break;
00243     }
00244     case GNC_OWNER_JOB :
00245     {
00246         ent = QOF_INSTANCE(owner->owner.job);
00247         break;
00248     }
00249     case GNC_OWNER_VENDOR :
00250     {
00251         ent = QOF_INSTANCE(owner->owner.vendor);
00252         break;
00253     }
00254     case GNC_OWNER_EMPLOYEE :
00255     {
00256         ent = QOF_INSTANCE(owner->owner.employee);
00257         break;
00258     }
00259     }
00260     return ent;
00261 }
00262 
00263 void
00264 qofOwnerSetEntity (GncOwner *owner, QofInstance *ent)
00265 {
00266     if (!owner || !ent)
00267     {
00268         return;
00269     }
00270     if (0 == safe_strcmp(ent->e_type, GNC_ID_CUSTOMER))
00271     {
00272         owner->type = GNC_OWNER_CUSTOMER;
00273         gncOwnerInitCustomer(owner, (GncCustomer*)ent);
00274     }
00275     else if (0 == safe_strcmp(ent->e_type, GNC_ID_JOB))
00276     {
00277         owner->type = GNC_OWNER_JOB;
00278         gncOwnerInitJob(owner, (GncJob*)ent);
00279     }
00280     else if (0 == safe_strcmp(ent->e_type, GNC_ID_VENDOR))
00281     {
00282         owner->type = GNC_OWNER_VENDOR;
00283         gncOwnerInitVendor(owner, (GncVendor*)ent);
00284     }
00285     else if (0 == safe_strcmp(ent->e_type, GNC_ID_EMPLOYEE))
00286     {
00287         owner->type = GNC_OWNER_EMPLOYEE;
00288         gncOwnerInitEmployee(owner, (GncEmployee*)ent);
00289     }
00290     else
00291     {
00292         owner->type = GNC_OWNER_NONE;
00293         owner->owner.undefined = NULL;
00294     }
00295 }
00296 
00297 gboolean GNC_IS_OWNER (QofInstance *ent)
00298 {
00299     if (!ent)
00300         return FALSE;
00301 
00302     return (GNC_IS_VENDOR(ent) ||
00303             GNC_IS_CUSTOMER(ent) ||
00304             GNC_IS_EMPLOYEE(ent) ||
00305             GNC_IS_JOB(ent));
00306 }
00307 gpointer gncOwnerGetUndefined (const GncOwner *owner)
00308 {
00309     if (!owner) return NULL;
00310     if (owner->type != GNC_OWNER_UNDEFINED) return NULL;
00311     return owner->owner.undefined;
00312 }
00313 
00314 GncCustomer * gncOwnerGetCustomer (const GncOwner *owner)
00315 {
00316     if (!owner) return NULL;
00317     if (owner->type != GNC_OWNER_CUSTOMER) return NULL;
00318     return owner->owner.customer;
00319 }
00320 
00321 GncJob * gncOwnerGetJob (const GncOwner *owner)
00322 {
00323     if (!owner) return NULL;
00324     if (owner->type != GNC_OWNER_JOB) return NULL;
00325     return owner->owner.job;
00326 }
00327 
00328 GncVendor * gncOwnerGetVendor (const GncOwner *owner)
00329 {
00330     if (!owner) return NULL;
00331     if (owner->type != GNC_OWNER_VENDOR) return NULL;
00332     return owner->owner.vendor;
00333 }
00334 
00335 GncEmployee * gncOwnerGetEmployee (const GncOwner *owner)
00336 {
00337     if (!owner) return NULL;
00338     if (owner->type != GNC_OWNER_EMPLOYEE) return NULL;
00339     return owner->owner.employee;
00340 }
00341 
00342 void gncOwnerCopy (const GncOwner *src, GncOwner *dest)
00343 {
00344     if (!src || !dest) return;
00345     if (src == dest) return;
00346     memcpy (dest, src, sizeof (*dest));
00347 }
00348 
00349 gboolean gncOwnerEqual (const GncOwner *a, const GncOwner *b)
00350 {
00351     if (!a || !b) return FALSE;
00352     if (gncOwnerGetType (a) != gncOwnerGetType (b)) return FALSE;
00353     return (a->owner.undefined == b->owner.undefined);
00354 }
00355 
00356 int gncOwnerGCompareFunc (const GncOwner *a, const GncOwner *b)
00357 {
00358     if (gncOwnerEqual (a, b))
00359         return 0;
00360     else
00361         return 1;
00362 }
00363 
00364 const char * gncOwnerGetID (const GncOwner *owner)
00365 {
00366     if (!owner) return NULL;
00367     switch (owner->type)
00368     {
00369     case GNC_OWNER_NONE:
00370     case GNC_OWNER_UNDEFINED:
00371     default:
00372         return NULL;
00373     case GNC_OWNER_CUSTOMER:
00374         return gncCustomerGetID (owner->owner.customer);
00375     case GNC_OWNER_JOB:
00376         return gncJobGetID (owner->owner.job);
00377     case GNC_OWNER_VENDOR:
00378         return gncVendorGetID (owner->owner.vendor);
00379     case GNC_OWNER_EMPLOYEE:
00380         return gncEmployeeGetID (owner->owner.employee);
00381     }
00382 }
00383 
00384 const char * gncOwnerGetName (const GncOwner *owner)
00385 {
00386     if (!owner) return NULL;
00387     switch (owner->type)
00388     {
00389     case GNC_OWNER_NONE:
00390     case GNC_OWNER_UNDEFINED:
00391     default:
00392         return NULL;
00393     case GNC_OWNER_CUSTOMER:
00394         return gncCustomerGetName (owner->owner.customer);
00395     case GNC_OWNER_JOB:
00396         return gncJobGetName (owner->owner.job);
00397     case GNC_OWNER_VENDOR:
00398         return gncVendorGetName (owner->owner.vendor);
00399     case GNC_OWNER_EMPLOYEE:
00400         return gncEmployeeGetName (owner->owner.employee);
00401     }
00402 }
00403 
00404 GncAddress * gncOwnerGetAddr (const GncOwner *owner)
00405 {
00406     if (!owner) return NULL;
00407     switch (owner->type)
00408     {
00409     case GNC_OWNER_NONE:
00410     case GNC_OWNER_UNDEFINED:
00411     case GNC_OWNER_JOB:
00412     default:
00413         return NULL;
00414     case GNC_OWNER_CUSTOMER:
00415         return gncCustomerGetAddr (owner->owner.customer);
00416     case GNC_OWNER_VENDOR:
00417         return gncVendorGetAddr (owner->owner.vendor);
00418     case GNC_OWNER_EMPLOYEE:
00419         return gncEmployeeGetAddr (owner->owner.employee);
00420     }
00421 }
00422 
00423 gnc_commodity * gncOwnerGetCurrency (const GncOwner *owner)
00424 {
00425     if (!owner) return NULL;
00426     switch (owner->type)
00427     {
00428     case GNC_OWNER_NONE:
00429     case GNC_OWNER_UNDEFINED:
00430     default:
00431         return NULL;
00432     case GNC_OWNER_CUSTOMER:
00433         return gncCustomerGetCurrency (owner->owner.customer);
00434     case GNC_OWNER_VENDOR:
00435         return gncVendorGetCurrency (owner->owner.vendor);
00436     case GNC_OWNER_EMPLOYEE:
00437         return gncEmployeeGetCurrency (owner->owner.employee);
00438     case GNC_OWNER_JOB:
00439         return gncOwnerGetCurrency (gncJobGetOwner (owner->owner.job));
00440     }
00441 }
00442 
00443 gboolean gncOwnerGetActive (const GncOwner *owner)
00444 {
00445     if (!owner) return FALSE;
00446     switch (owner->type)
00447     {
00448     case GNC_OWNER_NONE:
00449     case GNC_OWNER_UNDEFINED:
00450     default:
00451         return FALSE;
00452     case GNC_OWNER_CUSTOMER:
00453         return gncCustomerGetActive (owner->owner.customer);
00454     case GNC_OWNER_VENDOR:
00455         return gncVendorGetActive (owner->owner.vendor);
00456     case GNC_OWNER_EMPLOYEE:
00457         return gncEmployeeGetActive (owner->owner.employee);
00458     case GNC_OWNER_JOB:
00459         return gncJobGetActive (owner->owner.job);
00460     }
00461 }
00462 
00463 const GncGUID * gncOwnerGetGUID (const GncOwner *owner)
00464 {
00465     if (!owner) return NULL;
00466 
00467     switch (owner->type)
00468     {
00469     case GNC_OWNER_NONE:
00470     case GNC_OWNER_UNDEFINED:
00471     default:
00472         return NULL;
00473     case GNC_OWNER_CUSTOMER:
00474         return qof_instance_get_guid (QOF_INSTANCE(owner->owner.customer));
00475     case GNC_OWNER_JOB:
00476         return qof_instance_get_guid (QOF_INSTANCE(owner->owner.job));
00477     case GNC_OWNER_VENDOR:
00478         return qof_instance_get_guid (QOF_INSTANCE(owner->owner.vendor));
00479     case GNC_OWNER_EMPLOYEE:
00480         return qof_instance_get_guid (QOF_INSTANCE(owner->owner.employee));
00481     }
00482 }
00483 
00484 void
00485 gncOwnerSetActive (const GncOwner *owner, gboolean active)
00486 {
00487     if (!owner) return;
00488     switch (owner->type)
00489     {
00490     case GNC_OWNER_CUSTOMER:
00491         gncCustomerSetActive (owner->owner.customer, active);
00492         break;
00493     case GNC_OWNER_VENDOR:
00494         gncVendorSetActive (owner->owner.vendor, active);
00495         break;
00496     case GNC_OWNER_EMPLOYEE:
00497         gncEmployeeSetActive (owner->owner.employee, active);
00498         break;
00499     case GNC_OWNER_JOB:
00500         gncJobSetActive (owner->owner.job, active);
00501         break;
00502     case GNC_OWNER_NONE:
00503     case GNC_OWNER_UNDEFINED:
00504     default:
00505         break;
00506     }
00507 }
00508 
00509 GncGUID gncOwnerRetGUID (GncOwner *owner)
00510 {
00511     const GncGUID *guid = gncOwnerGetGUID (owner);
00512     if (guid)
00513         return *guid;
00514     return *guid_null ();
00515 }
00516 
00517 const GncOwner * gncOwnerGetEndOwner (const GncOwner *owner)
00518 {
00519     if (!owner) return NULL;
00520     switch (owner->type)
00521     {
00522     case GNC_OWNER_NONE:
00523     case GNC_OWNER_UNDEFINED:
00524     default:
00525         return NULL;
00526     case GNC_OWNER_CUSTOMER:
00527     case GNC_OWNER_VENDOR:
00528     case GNC_OWNER_EMPLOYEE:
00529         return owner;
00530     case GNC_OWNER_JOB:
00531         return gncJobGetOwner (owner->owner.job);
00532     }
00533 }
00534 
00535 int gncOwnerCompare (const GncOwner *a, const GncOwner *b)
00536 {
00537     if (!a && !b) return 0;
00538     if (!a && b) return 1;
00539     if (a && !b) return -1;
00540 
00541     if (a->type != b->type)
00542         return (a->type - b->type);
00543 
00544     switch (a->type)
00545     {
00546     case GNC_OWNER_NONE:
00547     case GNC_OWNER_UNDEFINED:
00548     default:
00549         return 0;
00550     case GNC_OWNER_CUSTOMER:
00551         return gncCustomerCompare (a->owner.customer, b->owner.customer);
00552     case GNC_OWNER_VENDOR:
00553         return gncVendorCompare (a->owner.vendor, b->owner.vendor);
00554     case GNC_OWNER_EMPLOYEE:
00555         return gncEmployeeCompare (a->owner.employee, b->owner.employee);
00556     case GNC_OWNER_JOB:
00557         return gncJobCompare (a->owner.job, b->owner.job);
00558     }
00559 }
00560 
00561 const GncGUID * gncOwnerGetEndGUID (const GncOwner *owner)
00562 {
00563     if (!owner) return NULL;
00564     return gncOwnerGetGUID (gncOwnerGetEndOwner (owner));
00565 }
00566 
00567 void gncOwnerAttachToLot (const GncOwner *owner, GNCLot *lot)
00568 {
00569     KvpFrame *kvp;
00570     KvpValue *value;
00571 
00572     if (!owner || !lot)
00573         return;
00574 
00575     kvp = gnc_lot_get_slots (lot);
00576     gnc_lot_begin_edit (lot);
00577 
00578     value = kvp_value_new_gint64 (gncOwnerGetType (owner));
00579     kvp_frame_set_slot_path (kvp, value, GNC_OWNER_ID, GNC_OWNER_TYPE, NULL);
00580     kvp_value_delete (value);
00581 
00582     value = kvp_value_new_guid (gncOwnerGetGUID (owner));
00583     kvp_frame_set_slot_path (kvp, value, GNC_OWNER_ID, GNC_OWNER_GUID, NULL);
00584     qof_instance_set_dirty (QOF_INSTANCE (lot));
00585     gnc_lot_commit_edit (lot);
00586     kvp_value_delete (value);
00587 
00588 }
00589 
00590 gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner)
00591 {
00592     KvpFrame *kvp;
00593     KvpValue *value;
00594     GncGUID *guid;
00595     QofBook *book;
00596     GncOwnerType type;
00597 
00598     if (!lot || !owner) return FALSE;
00599 
00600     book = gnc_lot_get_book (lot);
00601     kvp = gnc_lot_get_slots (lot);
00602 
00603     value = kvp_frame_get_slot_path (kvp, GNC_OWNER_ID, GNC_OWNER_TYPE, NULL);
00604     if (!value) return FALSE;
00605 
00606     type = kvp_value_get_gint64 (value);
00607 
00608     value = kvp_frame_get_slot_path (kvp, GNC_OWNER_ID, GNC_OWNER_GUID, NULL);
00609     if (!value) return FALSE;
00610 
00611     guid = kvp_value_get_guid (value);
00612     if (!guid)
00613         return FALSE;
00614 
00615     switch (type)
00616     {
00617     case GNC_OWNER_CUSTOMER:
00618         gncOwnerInitCustomer (owner, gncCustomerLookup (book, guid));
00619         break;
00620     case GNC_OWNER_VENDOR:
00621         gncOwnerInitVendor (owner, gncVendorLookup (book, guid));
00622         break;
00623     case GNC_OWNER_EMPLOYEE:
00624         gncOwnerInitEmployee (owner, gncEmployeeLookup (book, guid));
00625         break;
00626     case GNC_OWNER_JOB:
00627         gncOwnerInitJob (owner, gncJobLookup (book, guid));
00628         break;
00629     default:
00630         return FALSE;
00631     }
00632 
00633     return (owner->owner.undefined != NULL);
00634 }
00635 
00636 gboolean gncOwnerIsValid (const GncOwner *owner)
00637 {
00638     if (!owner) return FALSE;
00639     return (owner->owner.undefined != NULL);
00640 }
00641 
00642 KvpFrame* gncOwnerGetSlots(GncOwner* owner)
00643 {
00644     if (!owner) return NULL;
00645 
00646     switch (gncOwnerGetType(owner))
00647     {
00648     case GNC_OWNER_CUSTOMER:
00649     case GNC_OWNER_VENDOR:
00650     case GNC_OWNER_EMPLOYEE:
00651         return qof_instance_get_slots(QOF_INSTANCE(owner->owner.undefined));
00652     case GNC_OWNER_JOB:
00653         return gncOwnerGetSlots(gncJobGetOwner(gncOwnerGetJob(owner)));
00654     default:
00655         return NULL;
00656     }
00657 }
00658 
00659 gboolean
00660 gncOwnerLotMatchOwnerFunc (GNCLot *lot, gpointer user_data)
00661 {
00662     const GncOwner *req_owner = user_data;
00663     GncOwner lot_owner;
00664     const GncOwner *end_owner;
00665     GncInvoice *invoice = gncInvoiceGetInvoiceFromLot (lot);
00666 
00667     /* Determine the owner associated to the lot */
00668     if (invoice)
00669         /* Invoice lots */
00670         end_owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (invoice));
00671     else if (gncOwnerGetOwnerFromLot (lot, &lot_owner))
00672         /* Pre-payment lots */
00673         end_owner = gncOwnerGetEndOwner (&lot_owner);
00674     else
00675         return FALSE;
00676 
00677     /* Is this a lot for the requested owner ? */
00678     return gncOwnerEqual (end_owner, req_owner);
00679 }
00680 
00681 gint
00682 gncOwnerLotsSortFunc (GNCLot *lotA, GNCLot *lotB)
00683 {
00684     GncInvoice *ia, *ib;
00685     Timespec da, db;
00686 
00687     ia = gncInvoiceGetInvoiceFromLot (lotA);
00688     ib = gncInvoiceGetInvoiceFromLot (lotB);
00689 
00690     if (ia)
00691         da = gncInvoiceGetDateDue (ia);
00692     else
00693         da = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_earliest_split (lotA)));
00694 
00695     if (ib)
00696         db = gncInvoiceGetDateDue (ib);
00697     else
00698         db = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_earliest_split (lotB)));
00699 
00700     return timespec_cmp (&da, &db);
00701 }
00702 
00703 static gboolean use_reversed_payment_amounts(const GncOwner *owner)
00704 {
00705     g_assert(owner);
00706     return (gncOwnerGetType (owner) == GNC_OWNER_CUSTOMER);
00707 }
00708 
00709 
00710 /*
00711  * Create a payment of "amount" for the owner and return
00712  * the new lot associated with this payment.
00713  */
00714 GNCLot *
00715 gncOwnerCreatePaymentLot (const GncOwner *owner, Transaction *txn,
00716                           Account *posted_acc, Account *xfer_acc,
00717                           gnc_numeric amount, gnc_numeric exch, Timespec date,
00718                           const char *memo, const char *num)
00719 {
00720     QofBook *book;
00721     Split *split;
00722     const char *name;
00723     gnc_commodity *commodity;
00724     gboolean reverse;
00725     gnc_numeric payment_value = amount;
00726     Split *xfer_split = NULL;
00727     GNCLot *payment_lot;
00728 
00729     /* Verify our arguments */
00730     if (!owner || !posted_acc || !xfer_acc) return NULL;
00731     g_return_val_if_fail (owner->owner.undefined != NULL, NULL);
00732 
00733     /* Compute the ancillary data */
00734     book = gnc_account_get_book (posted_acc);
00735     name = gncOwnerGetName (gncOwnerGetEndOwner ((GncOwner*)owner));
00736     commodity = gncOwnerGetCurrency (owner);
00737     reverse = use_reversed_payment_amounts(owner);
00738 
00739     if (txn)
00740     {
00741         /* Pre-existing transaction was specified. We completely clear it,
00742          * except for the split in the transfer account, unless the
00743          * transaction can't be reused (wrong currency, wrong transfer account).
00744          * In that case, the transaction is simply removed and an new
00745          * one created. */
00746 
00747         xfer_split = xaccTransFindSplitByAccount(txn, xfer_acc);
00748 
00749         if (xaccTransGetCurrency(txn) != gncOwnerGetCurrency (owner))
00750         {
00751             g_message("Uh oh, mismatching currency/commodity between selected transaction and owner. We fall back to manual creation of a new transaction.");
00752             xfer_split = NULL;
00753         }
00754 
00755         if (!xfer_split)
00756         {
00757             g_message("Huh? Asset account not found anymore. Fully deleting old txn and now creating a new one.");
00758 
00759             xaccTransBeginEdit (txn);
00760             xaccTransDestroy (txn);
00761             xaccTransCommitEdit (txn);
00762 
00763             txn = NULL;
00764         }
00765         else
00766         {
00767             int i = 0;
00768             xaccTransBeginEdit (txn);
00769             while (i < xaccTransCountSplits(txn))
00770             {
00771                 Split *split = xaccTransGetSplit (txn, i);
00772                 if (split == xfer_split)
00773                 {
00774                     ++i;
00775                 }
00776                 else
00777                 {
00778                     xaccSplitDestroy(split);
00779                 }
00780             }
00781             xaccTransCommitEdit (txn);
00782         }
00783     }
00784 
00785     /* Create the transaction if we don't have one yet */
00786     if (!txn)
00787         txn = xaccMallocTransaction (book);
00788 
00789     /* Insert a split for the transfer account if we don't have one yet */
00790     if (!xfer_split)
00791     {
00792         xaccTransBeginEdit (txn);
00793 
00794         /* Set up the transaction */
00795         xaccTransSetDescription (txn, name ? name : "");
00796         xaccTransSetNum (txn, num);
00797         xaccTransSetCurrency (txn, commodity);
00798         xaccTransSetDateEnteredSecs (txn, time(NULL));
00799         xaccTransSetDatePostedTS (txn, &date);
00800         xaccTransSetTxnType (txn, TXN_TYPE_PAYMENT);
00801 
00802 
00803         /* The split for the transfer account */
00804         split = xaccMallocSplit (book);
00805         xaccSplitSetMemo (split, memo);
00806         xaccSplitSetAction (split, _("Payment"));
00807         xaccAccountBeginEdit (xfer_acc);
00808         xaccAccountInsertSplit (xfer_acc, split);
00809         xaccAccountCommitEdit (xfer_acc);
00810         xaccTransAppendSplit (txn, split);
00811 
00812         if (gnc_commodity_equal(xaccAccountGetCommodity(xfer_acc), commodity))
00813         {
00814             xaccSplitSetBaseValue (split, reverse ? amount :
00815                                    gnc_numeric_neg (amount), commodity);
00816         }
00817         else
00818         {
00819             /* Need to value the payment in terms of the owner commodity */
00820             xaccSplitSetAmount(split, reverse ? amount : gnc_numeric_neg (amount));
00821             payment_value = gnc_numeric_mul(amount, exch, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND_HALF_UP);
00822             xaccSplitSetValue(split, reverse ? payment_value : gnc_numeric_neg(payment_value));
00823         }
00824     }
00825 
00826     /* Add a split in the post account */
00827     split = xaccMallocSplit (book);
00828     xaccSplitSetMemo (split, memo);
00829     xaccSplitSetAction (split, _("Payment"));
00830     xaccAccountBeginEdit (posted_acc);
00831     xaccAccountInsertSplit (posted_acc, split);
00832     xaccAccountCommitEdit (posted_acc);
00833     xaccTransAppendSplit (txn, split);
00834     xaccSplitSetBaseValue (split, reverse ? gnc_numeric_neg (amount) : amount, commodity);
00835 
00836     /* Create a new lot for the payment */
00837     payment_lot = gnc_lot_new (book);
00838     gncOwnerAttachToLot (owner, payment_lot);
00839     gnc_lot_add_split (payment_lot, split);
00840 
00841 
00842     /* Commit this new transaction */
00843     xaccTransCommitEdit (txn);
00844 
00845     return payment_lot;
00846 }
00847 
00848 void gncOwnerAutoApplyPaymentsWithLots (const GncOwner *owner, GList *lots)
00849 {
00850     GList *base_iter;
00851 
00852     /* General note: in the code below the term "payment" can
00853      * both mean a true payment or a document of
00854      * the opposite sign (invoice vs credit note) relative to
00855      * the lot being processed. In general this function will
00856      * perform a balancing action on a set of lots, so you
00857      * will also find frequent references to balancing instead. */
00858 
00859     /* Payments can only be applied when at least an owner
00860      * and a list of lots to use are given */
00861     if (!owner) return;
00862     if (!lots) return;
00863 
00864     for (base_iter = lots; base_iter; base_iter = base_iter->next)
00865     {
00866         GNCLot *base_lot = base_iter->data;
00867         QofBook *book;
00868         Account *acct;
00869         const gchar *name;
00870         GList *lot_list, *lot_iter;
00871         Transaction *txn = NULL;
00872         gnc_numeric base_lot_bal, val_to_pay, val_paid = { 0, 1 };
00873         gboolean base_bal_is_pos;
00874         const gchar *action, *memo;
00875 
00876         /* Only attempt to apply payments to open lots.
00877          * Note that due to the iterative nature of this function lots
00878          * in the list may become closed before they are evaluated as
00879          * base lot, so we should check this for each lot. */
00880         base_lot_bal = gnc_lot_get_balance (base_lot);
00881         if (gnc_numeric_zero_p (base_lot_bal))
00882             continue;
00883 
00884         book = gnc_lot_get_book (base_lot);
00885         acct = gnc_lot_get_account (base_lot);
00886         name = gncOwnerGetName (gncOwnerGetEndOwner (owner));
00887         lot_list = base_iter->next;
00888 
00889         /* Strings used when creating splits later on. */
00890         action = _("Lot Link");
00891         memo   = _("Internal link between invoice and payment lots");
00892 
00893         /* Note: to balance the lot the payment to assign
00894          * must have the opposite sign of the existing lot balance */
00895         val_to_pay = gnc_numeric_neg (base_lot_bal);
00896         base_bal_is_pos = gnc_numeric_positive_p (base_lot_bal);
00897 
00898 
00899         /* Create splits in a linking transaction between lots until
00900          * - either the invoice lot is balanced
00901          * - or there are no more balancing lots.
00902          */
00903         for (lot_iter = lot_list; lot_iter; lot_iter = lot_iter->next)
00904         {
00905             gnc_numeric payment_lot_balance;
00906             Split *split;
00907             Account *bal_acct;
00908             gnc_numeric  split_amt;
00909 
00910             GNCLot *balancing_lot = lot_iter->data;
00911 
00912             /* Only attempt to use open lots to balance the base lot.
00913              * Note that due to the iterative nature of this function lots
00914              * in the list may become closed before they are evaluated as
00915              * base lot, so we should check this for each lot. */
00916             if (gnc_lot_is_closed (balancing_lot))
00917                 continue;
00918 
00919             /* Balancing transactions for invoice/payments can only happen
00920              * in the same account. */
00921             bal_acct = gnc_lot_get_account (balancing_lot);
00922             if (acct != bal_acct)
00923                 continue;
00924 
00925             payment_lot_balance = gnc_lot_get_balance (balancing_lot);
00926 
00927             /* Only attempt to balance if the base lot and balancing lot are
00928              * of the opposite sign. (Otherwise we would increase the balance
00929              * of the lot - Duh */
00930             if (base_bal_is_pos == gnc_numeric_positive_p (payment_lot_balance))
00931                 continue;
00932 
00933             /*
00934              * If there is less to pay than there's open in the lot; we're done -- apply the base_lot_vale.
00935              * Note that payment_value and balance are opposite in sign, so we have to compare absolute values here
00936              *
00937              * Otherwise, apply the balance, subtract that from the payment_value,
00938              * and move on to the next one.
00939              */
00940             if (gnc_numeric_compare (gnc_numeric_abs (val_to_pay), gnc_numeric_abs (payment_lot_balance)) <= 0)
00941             {
00942                 /* abs(val_to_pay) <= abs(balance) */
00943                 split_amt = val_to_pay;
00944             }
00945             else
00946             {
00947                 /* abs(val_to_pay) > abs(balance)
00948                  * Remember payment_value and balance are opposite in sign,
00949                  * and we want a payment to neutralize the current balance
00950                  * so we need to negate here */
00951                 split_amt = payment_lot_balance;
00952             }
00953 
00954             /* If not created yet, create a new transaction linking
00955              * the base lot and the balancing lot(s) */
00956             if (!txn)
00957             {
00958                 Timespec ts = xaccTransRetDatePostedTS (xaccSplitGetParent (gnc_lot_get_latest_split (base_lot)));
00959 
00960                 xaccAccountBeginEdit (acct);
00961 
00962                 txn = xaccMallocTransaction (book);
00963                 xaccTransBeginEdit (txn);
00964 
00965                 xaccTransSetDescription (txn, name ? name : "");
00966                 xaccTransSetCurrency (txn, xaccAccountGetCommodity(acct));
00967                 xaccTransSetDateEnteredSecs (txn, time(NULL));
00968                 xaccTransSetDatePostedTS (txn, &ts);
00969                 xaccTransSetTxnType (txn, TXN_TYPE_LINK);
00970             }
00971 
00972             /* Create the split for this link in current balancing lot */
00973             split = xaccMallocSplit (book);
00974             xaccSplitSetMemo (split, memo);
00975             xaccSplitSetAction (split, action);
00976             xaccAccountInsertSplit (acct, split);
00977             xaccTransAppendSplit (txn, split);
00978             xaccSplitSetBaseValue (split, gnc_numeric_neg (split_amt), xaccAccountGetCommodity(acct));
00979             gnc_lot_add_split (balancing_lot, split);
00980 
00981             /* If the balancing lot was linked to a document (invoice/credit note),
00982              * send an event for it as well so it gets potentially updated as paid */
00983             {
00984                 GncInvoice *this_invoice = gncInvoiceGetInvoiceFromLot(balancing_lot);
00985                 if (this_invoice)
00986                     qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
00987             }
00988 
00989             val_paid   = gnc_numeric_add (val_paid, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
00990             val_to_pay = gnc_numeric_sub (val_to_pay, split_amt, GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
00991             if (gnc_numeric_zero_p (val_to_pay))
00992                 break;
00993         }
00994 
00995 
00996         /* If the above loop managed to create a transaction and some balancing splits,
00997          * create the final split for the link transaction in the base lot */
00998         if (txn)
00999         {
01000             GncInvoice *this_invoice;
01001             Split *split = xaccMallocSplit (book);
01002 
01003             xaccSplitSetMemo (split, memo);
01004             xaccSplitSetAction (split, action);
01005             xaccAccountInsertSplit (acct, split);
01006             xaccTransAppendSplit (txn, split);
01007             xaccSplitSetBaseValue (split, val_paid, xaccAccountGetCommodity(acct));
01008             gnc_lot_add_split (base_lot, split);
01009 
01010             xaccTransCommitEdit (txn);
01011             xaccAccountCommitEdit (acct);
01012 
01013             /* If the base lot was linked to a document (invoice/credit note),
01014              * send an event for it as well so it gets potentially updated as paid */
01015             this_invoice = gncInvoiceGetInvoiceFromLot(base_lot);
01016             if (this_invoice)
01017                 qof_event_gen (QOF_INSTANCE(this_invoice), QOF_EVENT_MODIFY, NULL);
01018 
01019         }
01020 
01021     }
01022 }
01023 
01024 /*
01025  * Create a payment of "amount" for the owner and match it with
01026  * the set of lots passed in. If not lots were given all open
01027  * lots for the owner are considered.
01028  */
01029 void
01030 gncOwnerApplyPayment (const GncOwner *owner, Transaction *txn, GList *lots,
01031                       Account *posted_acc, Account *xfer_acc,
01032                       gnc_numeric amount, gnc_numeric exch, Timespec date,
01033                       const char *memo, const char *num)
01034 {
01035     GNCLot *payment_lot;
01036     GList *selected_lots;
01037 
01038     /* Verify our arguments */
01039     if (!owner || !posted_acc || !xfer_acc) return;
01040     g_return_if_fail (owner->owner.undefined);
01041 
01042     /* Create a lot for this payment */
01043     payment_lot = gncOwnerCreatePaymentLot (owner, txn, posted_acc, xfer_acc,
01044                                             amount, exch, date, memo, num);
01045 
01046     if (lots)
01047         selected_lots = lots;
01048     else
01049         selected_lots = xaccAccountFindOpenLots (posted_acc, gncOwnerLotMatchOwnerFunc,
01050                                                  (gpointer)owner, NULL);
01051 
01052     /* And link the selected lots and the payment lot together as well as possible.
01053      * If the payment was bigger than the selected documents/overpayments, only
01054      * part of the payment will be used. Similarly if more documents were selected
01055      * than the payment value set, not all documents will be marked as paid. */
01056     if (payment_lot)
01057         selected_lots = g_list_prepend (selected_lots, payment_lot);
01058     gncOwnerAutoApplyPaymentsWithLots (owner, selected_lots);
01059 }
01060 
01061 GList *
01062 gncOwnerGetAccountTypesList (const GncOwner *owner)
01063 {
01064     g_return_val_if_fail (owner, NULL);
01065 
01066     switch (gncOwnerGetType (owner))
01067     {
01068     case GNC_OWNER_CUSTOMER:
01069         return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_RECEIVABLE));
01070     case GNC_OWNER_VENDOR:
01071     case GNC_OWNER_EMPLOYEE:
01072         return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_PAYABLE));
01073         break;
01074     default:
01075         return (g_list_prepend (NULL, (gpointer)ACCT_TYPE_NONE));
01076     }
01077 }
01078 
01079 GList *
01080 gncOwnerGetCommoditiesList (const GncOwner *owner)
01081 {
01082     g_return_val_if_fail (owner, NULL);
01083     g_return_val_if_fail (gncOwnerGetCurrency(owner), NULL);
01084 
01085     return (g_list_prepend (NULL, gncOwnerGetCurrency(owner)));
01086 }
01087 
01088 /*********************************************************************/
01089 /* Owner balance calculation routines                                */
01090 
01091 /*
01092  * Given an owner, extract the open balance from the owner and then
01093  * convert it to the desired currency.
01094  */
01095 gnc_numeric
01096 gncOwnerGetBalanceInCurrency (const GncOwner *owner,
01097                               const gnc_commodity *report_currency)
01098 {
01099     gnc_numeric balance = gnc_numeric_zero ();
01100     GList *acct_list, *acct_node, *acct_types, *lot_list = NULL, *lot_node;
01101     QofBook *book;
01102     gnc_commodity *owner_currency;
01103     GNCPriceDB *pdb;
01104 
01105     g_return_val_if_fail (owner, gnc_numeric_zero ());
01106 
01107     /* Get account list */
01108     book       = qof_instance_get_book (qofOwnerGetOwner (owner));
01109     acct_list  = gnc_account_get_descendants (gnc_book_get_root_account (book));
01110     acct_types = gncOwnerGetAccountTypesList (owner);
01111     owner_currency = gncOwnerGetCurrency (owner);
01112 
01113     /* For each account */
01114     for (acct_node = acct_list; acct_node; acct_node = acct_node->next)
01115     {
01116         Account *account = acct_node->data;
01117 
01118         /* Check if this account can have lots for the owner, otherwise skip to next */
01119         if (g_list_index (acct_types, (gpointer)xaccAccountGetType (account))
01120                 == -1)
01121             continue;
01122 
01123 
01124         if (!gnc_commodity_equal (owner_currency, xaccAccountGetCommodity (account)))
01125             continue;
01126 
01127         /* Get a list of open lots for this owner and account */
01128         lot_list = xaccAccountFindOpenLots (account, gncOwnerLotMatchOwnerFunc,
01129                                             (gpointer)owner, NULL);
01130         /* For each lot */
01131         for (lot_node = lot_list; lot_node; lot_node = lot_node->next)
01132         {
01133             GNCLot *lot = lot_node->data;
01134             gnc_numeric lot_balance = gnc_lot_get_balance (lot);
01135             balance = gnc_numeric_add (balance, lot_balance,
01136                                        gnc_commodity_get_fraction (owner_currency), GNC_HOW_RND_ROUND_HALF_UP);
01137         }
01138     }
01139 
01140     pdb = gnc_pricedb_get_db (book);
01141 
01142     if (report_currency)
01143         balance = gnc_pricedb_convert_balance_latest_price (
01144                       pdb, balance, owner_currency, report_currency);
01145 
01146     return balance;
01147 }
01148 
01149 
01150 /* XXX: Yea, this is broken, but it should work fine for Queries.
01151  * We're single-threaded, right?
01152  */
01153 static GncOwner *
01154 owner_from_lot (GNCLot *lot)
01155 {
01156     static GncOwner owner;
01157 
01158     if (!lot) return NULL;
01159     if (gncOwnerGetOwnerFromLot (lot, &owner))
01160         return &owner;
01161 
01162     return NULL;
01163 }
01164 
01165 static void
01166 reg_lot (void)
01167 {
01168     static QofParam params[] =
01169     {
01170         { OWNER_FROM_LOT, _GNC_MOD_NAME, (QofAccessFunc)owner_from_lot, NULL },
01171         { NULL },
01172     };
01173 
01174     qof_class_register (GNC_ID_LOT, NULL, params);
01175 }
01176 
01177 gboolean gncOwnerGetOwnerFromTypeGuid (QofBook *book, GncOwner *owner, QofIdType type, GncGUID *guid)
01178 {
01179     if (!book || !owner || !type || !guid) return FALSE;
01180 
01181     if (0 == safe_strcmp(type, GNC_ID_CUSTOMER))
01182     {
01183         GncCustomer *customer = gncCustomerLookup(book, guid);
01184         gncOwnerInitCustomer(owner, customer);
01185         return (NULL != customer);
01186     }
01187     else if (0 == safe_strcmp(type, GNC_ID_JOB))
01188     {
01189         GncJob *job = gncJobLookup(book, guid);
01190         gncOwnerInitJob(owner, job);
01191         return (NULL != job);
01192     }
01193     else if (0 == safe_strcmp(type, GNC_ID_VENDOR))
01194     {
01195         GncVendor *vendor = gncVendorLookup(book, guid);
01196         gncOwnerInitVendor(owner, vendor);
01197         return (NULL != vendor);
01198     }
01199     else if (0 == safe_strcmp(type, GNC_ID_EMPLOYEE))
01200     {
01201         GncEmployee *employee = gncEmployeeLookup(book, guid);
01202         gncOwnerInitEmployee(owner, employee);
01203         return (NULL != employee);
01204     }
01205     return 0;
01206 }
01207 
01208 gboolean gncOwnerRegister (void)
01209 {
01210     static QofParam params[] =
01211     {
01212         { OWNER_TYPE, QOF_TYPE_INT64,      (QofAccessFunc)gncOwnerGetType,          NULL },
01213         { OWNER_CUSTOMER, GNC_ID_CUSTOMER, (QofAccessFunc)gncOwnerGetCustomer,      NULL },
01214         { OWNER_JOB, GNC_ID_JOB,           (QofAccessFunc)gncOwnerGetJob,           NULL },
01215         { OWNER_VENDOR, GNC_ID_VENDOR,     (QofAccessFunc)gncOwnerGetVendor,        NULL },
01216         { OWNER_EMPLOYEE, GNC_ID_EMPLOYEE, (QofAccessFunc)gncOwnerGetEmployee,      NULL },
01217         { OWNER_PARENT, GNC_ID_OWNER,      (QofAccessFunc)gncOwnerGetEndOwner,      NULL },
01218         { OWNER_PARENTG, QOF_TYPE_GUID,    (QofAccessFunc)gncOwnerGetEndGUID,       NULL },
01219         { OWNER_NAME, QOF_TYPE_STRING,     (QofAccessFunc)gncOwnerGetName, NULL },
01220         { QOF_PARAM_GUID, QOF_TYPE_GUID,   (QofAccessFunc)gncOwnerGetGUID, NULL },
01221         { NULL },
01222     };
01223 
01224     qof_class_register (GNC_ID_OWNER, (QofSortFunc)gncOwnerCompare, params);
01225     reg_lot ();
01226 
01227     return TRUE;
01228 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines